first commit

This commit is contained in:
2025-12-29 14:59:44 +08:00
commit 10c3fbb0d7
5315 changed files with 795443 additions and 0 deletions

View File

@@ -0,0 +1,366 @@
<template>
<view class="page padding">
<view class="text-gray text-center" v-if="!hasData">暂无证件照记录</view>
<button class="cuIcon-add bg-blue round margin-top-xl" @click="showAddPopup = true">新增</button>
<!-- 新增证件照弹窗 -->
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title text-bold">新增证照</view>
<view class="popup-close" @click="showAddPopup = false">×</view>
</view>
<view class="popup-body">
<!-- 部门 -->
<view class="form-item">
<view class="form-label">部门<text class="text-red">*</text></view>
<view class="form-input form-select" @click="showDeptPopup = true">
<text :class="formData.dept ? '' : 'text-gray'">
{{ formData.dept || '请选择部门' }}
</text>
</view>
</view>
<!-- 证件类型 -->
<view class="form-item">
<view class="form-label">证件类型</view>
<input class="form-input" v-model="formData.idType" placeholder="请输入证件类型" />
</view>
<!-- 证件编号 -->
<view class="form-item">
<view class="form-label">证件编号</view>
<input class="form-input" v-model="formData.number" placeholder="请输入证件编号" />
</view>
<!-- 开始日期 -->
<view class="form-item">
<view class="form-label">开始日期</view>
<view class="form-input form-select" @click="showDatePicker = true">
<text :class="formData.expireDate ? '' : 'text-gray'">
{{ formData.expireDate || '请选择开始时间' }}
</text>
</view>
</view>
<!-- 结束日期 -->
<view class="form-item">
<view class="form-label">结束日期</view>
<view class="form-input form-select" @click="showDatePicker = true">
<text :class="formData.expireDate ? '' : 'text-gray'">
{{ formData.expireDate || '请选择结束时间' }}
</text>
</view>
</view>
<!-- 上传证件照 -->
<view class="form-item">
<view class="form-label">封面图片</view>
<view class="upload-box" @click="chooseImage">
<view class="upload-add" v-if="!formData.image">
<text class="upload-icon">+</text>
<text class="upload-text">上传照片</text>
</view>
<image v-else :src="formData.image" mode="aspectFill" class="upload-img"></image>
</view>
</view>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="handleSubmit">确定</button>
</view>
</view>
</u-popup>
<!-- 日期选择器 -->
<u-datetime-picker
:show="showDatePicker"
mode="date"
@confirm="onDateConfirm"
@cancel="showDatePicker = false"
></u-datetime-picker>
<!-- 选择部门弹窗 -->
<u-popup :show="showDeptPopup" mode="center" round="20" @close="showDeptPopup = false">
<view class="dept-popup">
<view class="popup-header">
<view class="popup-title text-bold">选择部门</view>
<view class="popup-close" @click="showDeptPopup = false">×</view>
</view>
<view class="dept-list">
<view
class="dept-item"
v-for="(item, index) in deptList"
:key="index"
@click="selectedDept = item"
>
<view class="dept-checkbox" :class="{ 'dept-checkbox-active': selectedDept === item }">
<text v-if="selectedDept === item"></text>
</view>
<text class="dept-name">{{ item }}</text>
</view>
</view>
<button class="btn-dept-confirm bg-blue" @click="confirmDept">确定</button>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
const hasData = ref(false);
const showAddPopup = ref(false);
const showDatePicker = ref(false);
const showDeptPopup = ref(false);
// 部门列表
const deptList = ref([
'湘西自治州和谐网络科技有限公司',
'湘西自治州和谐云大数据科技有限公司',
'湘西网络有限公司'
]);
const selectedDept = ref('');
const formData = reactive({
dept: '',
type: '',
idType: '',
number: '',
startDate: '',
expireDate: '',
image: ''
});
// 确认选择部门
const confirmDept = () => {
if (selectedDept.value) {
formData.dept = selectedDept.value;
}
showDeptPopup.value = false;
};
// 选择图片
const chooseImage = () => {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
formData.image = res.tempFilePaths[0];
}
});
};
// 日期选择确认
const onDateConfirm = (e) => {
const date = new Date(e.value);
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
formData.expireDate = `${year}-${month}-${day}`;
showDatePicker.value = false;
};
// 提交表单
const handleSubmit = () => {
if (!formData.dept) {
uni.showToast({ title: '请选择部门', icon: 'none' });
return;
}
console.log('提交数据:', formData);
uni.showToast({ title: '新增成功', icon: 'success' });
showAddPopup.value = false;
// 重置表单
formData.dept = '';
formData.type = '';
formData.number = '';
formData.startDate = '';
formData.expireDate = '';
formData.image = '';
selectedDept.value = '';
};
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
// 弹出框样式
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.popup-title {
font-size: 34rpx;
color: #333;
}
.popup-close {
font-size: 48rpx;
color: #999;
line-height: 1;
}
.popup-body {
max-height: 700rpx;
overflow-y: auto;
}
.form-item {
margin-bottom: 24rpx;
}
.form-label {
font-size: 28rpx;
color: #333;
margin-bottom: 12rpx;
}
.form-input {
width: 100%;
height: 80rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.form-select {
display: flex;
align-items: center;
line-height: 80rpx;
}
.upload-box {
width: 200rpx;
height: 200rpx;
border: 2rpx dashed #ccc;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
}
.upload-add {
display: flex;
flex-direction: column;
align-items: center;
}
.upload-icon {
font-size: 60rpx;
color: #999;
}
.upload-text {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.upload-img {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.popup-footer {
display: flex;
justify-content: center;
gap: 30rpx;
margin-top: 40rpx;
}
.btn-cancel {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border: 2rpx solid #E5E5E5;
border-radius: 40rpx;
background: #fff;
color: #333;
font-size: 30rpx;
}
.btn-confirm {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: #fff;
font-size: 30rpx;
}
// 部门选择弹窗
.dept-popup {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
}
.dept-list {
max-height: 400rpx;
overflow-y: auto;
margin-bottom: 30rpx;
}
.dept-item {
display: flex;
align-items: center;
padding: 24rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
margin-bottom: 16rpx;
}
.dept-checkbox {
width: 36rpx;
height: 36rpx;
border: 2rpx solid #ccc;
border-radius: 6rpx;
margin-right: 20rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.dept-checkbox-active {
background: #2667E9;
border-color: #2667E9;
color: #fff;
}
.dept-name {
font-size: 28rpx;
color: #333;
}
.btn-dept-confirm {
width: 100%;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: #fff;
font-size: 30rpx;
}
</style>

View File

@@ -0,0 +1,52 @@
<template>
<view class="padding">
<view class="text-bold text-black">检查清单预览</view>
<view class="flex margin-bottom">
<view class="text-gray">计划名称</view>
<view>和谐矿业每日巡检</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">检查时间</view>
<view>2025-11-19 10:18:40</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">检查人员</view>
<view>18174379303</view>
</view>
<image></image>
<view class="flex margin-bottom">
<view>被检查单位</view>
<view></view>
</view>
<view class="flex margin-bottom">
<view>检查人员</view>
<view></view>
</view>
<view class="flex margin-bottom">
<view>上次检查情况</view>
<view></view>
</view>
<view class="flex margin-bottom">
<view>本次检查情况</view>
<view></view>
</view>
<view class="flex margin-bottom">
<view>检查日期</view>
<view>2025-11-19 10:18:40</view>
</view>
<view class=" flex justify-between">
<view class="flex text-center align-center">
<button class="bg-blue">缩小</button>
<view >50%</view>
<button class="bg-blue">放大</button>
</view>
<button class="lg cu-btn">重置</button>
</view>
</view>
</template>
<script>
</script>
<style>
</style>

View File

@@ -0,0 +1,52 @@
<template>
<view class="page padding">
<view class="padding bg-white radius list">
<view class="text-bold margin-bottom text-black">和谐矿业每日巡检</view>
<view class="flex margin-bottom">
<view class="text-gray">检查时间</view>
<view>2025-11-19 10:18:40</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">检查人员</view>
<view>18174379303</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">隐患数量</view>
<view>1</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">备注</view>
<view>可以</view>
</view>
<view class="flex justify-between">
<view></view>
<button class="bg-blue round cu-btn lg " @click="Checklist()">预览清单</button>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const Checklist = () => {
uni.navigateTo({
url: '/pages/Inspectionchecklist/Inspectionchecklist'
})
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.list {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 6rpx 2rpx rgba(0, 0, 0, 0.08);
border-left: 5px solid #2667E9;
border-radius: 20rpx;
padding: 20rpx;
}
</style>

View File

@@ -0,0 +1,147 @@
<template>
<view class="page padding">
<view class="padding bg-white radius">
<view class="text-bold">{{ checkData?.name || '加载中...' }}</view>
<view class="margin-top">
<rich-text :nodes="checkData?.point || ''"></rich-text>
</view>
<view class="margin-top">
<u-radio-group
v-model="radiovalue1"
placement="row"
@change="groupChange"
>
<u-radio
:customStyle="{marginBottom: '8px'}"
v-for="(item, index) in radiolist1"
:key="index"
:label="item.name"
:name="item.name"
@change="radioChange"
>
</u-radio>
</u-radio-group>
</view>
<view>
<up-textarea v-model="value1" placeholder="请输入备注信息" ></up-textarea>
</view>
</view>
<button class="bg-blue round margin-top-xl" @click="handleSubmit">提交</button>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { enterCheckPlan,submitCheckResult } from '@/request/api.js';
// 页面参数
const oneTableId = ref('');
// 检查项数据
const checkData = ref(null);
// 单选框 result: 1.正常 2.异常 3.不涉及
const radiolist1 = reactive([
{
name: '正常',
value: 1,
disabled: false,
},
{
name: '异常',
value: 2,
disabled: false,
},
{
name: '不涉及',
value: 3,
disabled: false,
},
]);
// 选中的结果值
const radiovalue1 = ref('');
const groupChange = (n) => {
console.log('groupChange', n);
};
const radioChange = (n) => {
console.log('radioChange', n);
};
// 备注
const value1 = ref('');
// 提交检查结果
const handleSubmit = async () => {
// 验证是否选择了检查结果
if (!radiovalue1.value) {
uni.showToast({ title: '请选择检查结果', icon: 'none' });
return;
}
// 获取选中项对应的 value 值
const selectedItem = radiolist1.find(item => item.name === radiovalue1.value);
const resultValue = selectedItem ? selectedItem.value : null;
if (!resultValue) {
uni.showToast({ title: '请选择检查结果', icon: 'none' });
return;
}
try {
const params = {
taskId: checkData.value?.taskId,
result: resultValue,
remark: value1.value
};
console.log('提交参数:', params);
const res = await submitCheckResult(params);
console.log('提交结果:', res);
if (res.code === 0) {
uni.showToast({ title: '提交成功', icon: 'success' });
// 提交成功后可以返回上一页或刷新数据
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.showToast({ title: res.msg || '提交失败', icon: 'none' });
}
} catch (error) {
console.error('提交失败:', error);
uni.showToast({ title: '提交失败', icon: 'none' });
}
};
// 获取检查项数据
const getCheckData = async () => {
try {
const res = await enterCheckPlan(oneTableId.value);
console.log('检查项数据:', res);
if (res.code === 0) {
checkData.value = res.data;
}
} catch (error) {
console.error(error);
}
};
// 页面加载时获取参数并调用接口
onLoad((options) => {
console.log('接收到的参数:', options);
if (options.id) {
oneTableId.value = options.id;
getCheckData();
}
});
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
</style>

View File

@@ -0,0 +1,181 @@
<template>
<view class="padding page">
<scroll-view scroll-x class="tab-scroll">
<view class="tab-list">
<view class="tab-item" :class="{ 'tab-active': activeIndex === index }"
v-for="(item, index) in warningList" :key="index" @click="switchTab(index)">
{{ item.name }}
</view>
</view>
</scroll-view>
<!-- 查询条件 -->
<view class="bg-white radius padding margin-top">
<view class="flex">
<!-- <view class="lg cuIcon-search bg-blue radius text-center align-center"></view> -->
<view class="text-black text-bold">查询条件</view>
</view>
<view class="margin-top margin-bottom">开始日期</view>
<up-datetime-picker hasInput :show="show" v-model="value1" mode="date"></up-datetime-picker>
<view class="margin-top margin-bottom">结束日期</view>
<up-datetime-picker hasInput :show="show" v-model="value1" mode="date"></up-datetime-picker>
<view class="margin-top margin-bottom">公司名称</view>
<up-input placeholder="请输入公司名称"></up-input>
<button class="bg-blue round margin-top">查询</button>
</view>
<!-- 统计概览 -->
<view class="padding bg-white radius margin-top">
<view class="flex">
<view></view>
<view class="text-bold text-black">统计概览</view>
</view>
<view class="flex col-4 grid margin-top " style="gap:20rpx">
<view class="text-center padding-top-sm " style="width: 142rpx;height: 124rpx;background:#628EFB; border-radius: 8rpx;color: #fff;">
<view>80</view>
<view>总计</view>
</view>
<view class="text-center padding-top-sm " style="width: 142rpx;height: 124rpx;background:#32DCC7; border-radius: 8rpx;color: #fff;">
<view>70</view>
<view>逾期</view>
</view>
<view class="text-center padding-top-sm " style="width: 142rpx;height: 124rpx;background:#32D1E9; border-radius: 8rpx;color: #fff;">
<view>20</view>
<view>已完成</view>
</view>
<view class="text-center padding-top-sm " style="width: 142rpx;height: 124rpx;background:#A190F5; border-radius: 8rpx;color: #fff;">
<view>20</view>
<view>待处理</view>
</view>
</view>
</view>
<!-- 数据列表 -->
<view class="bg-white radius padding margin-top margin-bottom flex">
<view class="list-title"></view>
<view class="text-bold text-black">日常安全检查预警数据列表</view>
</view>
<view class="bg-white radius padding list-list">
<view class=" flex justify-between">
<view class="text-bold text-black">#1</view>
<view>严重逾期</view>
</view>
<view class="flex margin-top">
<view class="text-gray" style="white-space: nowrap;">企业名称</view>
<view>湘西和谐云大数据产业发展有限公司</view>
</view>
<view class="flex margin-top">
<view class="text-gray">计划名称</view>
<view>检查计划</view>
</view>
<view class="flex margin-top">
<view class="text-gray">计划周期</view>
<view>每天一次</view>
</view>
<view class="flex margin-top">
<view class="text-gray">预约检查日期</view>
<view>2025-11-20</view>
</view>
<view class="flex margin-top">
<view class="text-gray">实际完成时间</view>
<view>未完成</view>
</view>
<view class="flex margin-top">
<view class="text-gray">负责人</view>
<view>符友成</view>
</view>
<view class="flex margin-top">
<view class="text-gray">逾期天数</view>
<view>17 </view>
</view>
</view>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
const activeIndex = ref(0)
const warningList = ref([{
id: 1,
name: '全部状态80',
},
{
id: 2,
name: '逾期未检16',
},
{
id: 3,
name: '严重逾期50',
},
{
id: 4,
name: '期限内待检4',
},
{
id: 5,
name: '逾期已完成8',
},
{
id: 6,
name: '按期已完成2',
}
])
const switchTab = (index) => {
activeIndex.value = index
}
// 日期
const value1 = ref(Date.now());
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.tab-scroll {
white-space: nowrap;
}
.tab-list {
display: inline-flex;
gap: 20rpx;
}
.tab-item {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 16rpx 28rpx;
border-radius: 8rpx;
font-size: 28rpx;
background: #fff;
border: 1rpx solid #ddd;
color: #333;
flex-shrink: 0;
&.tab-active {
background: #2979ff;
border-color: #2979ff;
color: #fff;
}
}
.list-title {
width: 10rpx;
height: 32rpx;
background: #2667E9;
border-radius: 10rpx;
line-height: 32rpx;
margin-right: 10rpx;
}
.list-list {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 6rpx 2rpx rgba(0, 0, 0, 0.08);
border-left: 5px solid #2667E9;
border-radius: 20rpx;
padding: 20rpx;
}
</style>

226
pages/area/management.vue Normal file
View File

@@ -0,0 +1,226 @@
<template>
<view class="padding page">
<view class="padding bg-white radius">
<view class="flex justify-between">
<view>
<view class="text-bold text-black">{{ areaData.name || '区域名称' }}</view>
<view class="margin-top flex align-center">
<text>颜色</text>
<view class="color-dot" :style="{ backgroundColor: areaData.color }"></view>
<text class="margin-left-xs">{{ areaData.color }}</text>
</view>
</view>
<view>
<button class="bg-blue cu-btn" @click="openEditPopup" >编辑</button>
<button class="bg-red cu-btn margin-left">删除</button>
</view>
</view>
</view>
<button class="cuIcon-add bg-blue round margin-top-xl">新增公司区域</button>
<!-- 编辑区域弹出框 -->
<u-popup :show="showEditPopup" mode="center" round="20" @close="showEditPopup = false">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title text-bold">编辑区域</view>
<view class="popup-close" @click="showEditPopup = false">×</view>
</view>
<view class="popup-body">
<!-- 区域名称 -->
<view class="flex margin-bottom-sm">
<view>区域名称</view>
<view class="text-red">*</view>
</view>
<up-input v-model="formData.name" placeholder="请输入区域名称"></up-input>
<!-- 区域颜色 -->
<view class="flex margin-bottom-sm margin-top">
<view>区域颜色</view>
<view class="text-red">*</view>
</view>
<view class="flex align-center">
<up-input v-model="formData.color" placeholder="#ef4444" class="flex-sub"></up-input>
<view class="color-preview" :style="{ backgroundColor: formData.color }"></view>
</view>
<!-- 预设颜色 -->
<view class="margin-top margin-bottom-sm text-gray">预设颜色</view>
<view class="color-grid">
<view
v-for="(color, index) in presetColors"
:key="index"
class="color-item"
:style="{ backgroundColor: color }"
@click="selectColor(color)"
></view>
</view>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="showEditPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="handleEdit">确定</button>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
// 弹出框显示状态
const showEditPopup = ref(false);
// 当前区域数据(用于列表显示)
const areaData = reactive({
name: '区域名称',
color: '#ef4444'
});
// 表单数据
const formData = reactive({
name: '',
color: '#ef4444'
});
// 预设颜色
const presetColors = [
'#2563eb', '#ef4444', '#10b981', '#f59e0b', '#6366f1', '#ec4899', '#06b6d4',
'#84cc16', '#f97316', '#4f46e5', '#dc2626', '#f59e0b', '#d97706', '#8b5cf6',
'#db2777'
];
// 打开编辑弹出框
const openEditPopup = () => {
// 初始化表单数据为当前区域数据
formData.name = areaData.name;
formData.color = areaData.color;
showEditPopup.value = true;
};
// 选择预设颜色
const selectColor = (color) => {
formData.color = color;
};
// 确定编辑
const handleEdit = () => {
if (!formData.name) {
uni.showToast({ title: '请输入区域名称', icon: 'none' });
return;
}
if (!formData.color) {
uni.showToast({ title: '请选择区域颜色', icon: 'none' });
return;
}
// 更新区域数据
areaData.name = formData.name;
areaData.color = formData.color;
showEditPopup.value = false;
uni.showToast({
title: '编辑成功',
icon: 'success'
});
};
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
}
.popup-title {
font-size: 32rpx;
}
.popup-close {
font-size: 40rpx;
color: #999;
cursor: pointer;
}
.popup-body {
padding: 30rpx;
}
.popup-footer {
display: flex;
padding: 20rpx 30rpx 30rpx;
button {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
font-size: 30rpx;
margin: 0 10rpx;
&::after {
border: none;
}
}
.btn-cancel {
background: #f5f5f5;
color: #666;
}
.btn-confirm {
color: #fff;
}
}
// 颜色预览
.color-preview {
width: 80rpx;
height: 80rpx;
border-radius: 8rpx;
margin-left: 20rpx;
flex-shrink: 0;
}
// 预设颜色网格
.color-grid {
display: flex;
flex-wrap: wrap;
gap: 16rpx;
}
.color-item {
width: 70rpx;
height: 70rpx;
border-radius: 12rpx;
cursor: pointer;
transition: transform 0.2s;
&:active {
transform: scale(0.9);
}
}
// 颜色圆点
.color-dot {
width: 30rpx;
height: 30rpx;
border-radius: 6rpx;
flex-shrink: 0;
margin-left: 10rpx;
}
</style>

View File

@@ -0,0 +1,31 @@
<template>
<view class="page padding">
<view class="padding bg-white radius flex justify-between">
<view>危化品使用安全专题检查</view>
<view>
<button class="bg-blue cu-btn margin-right-xs" @click="edit()">编辑</button>
<button class="bg-red cu-btn">删除</button>
</view>
</view>
<button class="lg cuIcon-add bg-blue round margin-top-xl">新增检查表</button>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { useRouter } from 'vue-router'
const router = useRouter()
const edit = () => {
uni.navigateTo({
url: '/pages/editchecklist/editchecklist'
})
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
</style>

View File

@@ -0,0 +1,159 @@
<template>
<view class="padding page">
<view class="padding bg-white radius">
<view class="flex justify-between margin-bottom">
<view class="text-bold text-black">发现火苗</view>
<view>已审核</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">隐患日期</view>
<view class="text-black">2025-11-11</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">责任单位</view>
<view class="text-black">吉首网络有限公司</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">判定人员</view>
<view class="text-black">张起</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">创建时间</view>
<view class="text-black">2025-11-14 06:33:49</view>
</view>
<view class="flex justify-between">
<view></view>
<view><button class="bg-blue round cu-btn lg" @click="editor()">查看详情</button></view>
</view>
</view>
<button class="cuIcon-add bg-blue round margin-top" @click="showAddPopup = true">新增</button>
<!-- 弹出框 -->
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title text-bold">新增销号申请</view>
<view class="popup-close" @click="showAddPopup = false">×</view>
</view>
<view class="popup-body">
<view class="flex margin-bottom">
<view>隐患</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请选择隐患"></up-input>
<view class="flex margin-bottom margin-top">
<view>整改时限</view>
<view class="text-red">*</view>
</view>
<view>
<up-datetime-picker hasInput :show="show" v-model="value1" mode="date"></up-datetime-picker>
</view>
<view class="margin-bottom margin-top">隐患治理责任单位</view>
<up-input placeholder="请输入隐患治理责任单位"></up-input>
<view class="margin-bottom margin-top">主要负责人</view>
<up-input placeholder="请输入主要负责人"></up-input>
<view class="margin-bottom margin-top">主要治理内容</view>
<up-textarea v-model="value" placeholder="请输入主要治理内容" ></up-textarea>
<view class="margin-bottom margin-top">隐患治理完成内容</view>
<up-textarea v-model="value" placeholder="请输入隐患治理完成情况" ></up-textarea>
<view class="margin-bottom margin-top">隐患治理责任单位自行验收的情况</view>
<up-textarea v-model="value" placeholder="请输入隐患治理责任单位自行验收的情况" ></up-textarea>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="handleAdd">确定</button>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import {
ref
} from 'vue'
// 弹窗控制
const showAddPopup = ref(false);
// 确定新增
const handleAdd = () => {
// 在这里处理新增逻辑
showAddPopup.value = false;
uni.showToast({
title: '新增成功',
icon: 'success'
});
};
// 整改时限
const value1 = ref(Date.now());
const editor = () => {
uni.navigateTo({
url: '/pages/closeout/editor'
})
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
.popup-title {
font-size: 32rpx;
color: #333;
}
.popup-close {
font-size: 40rpx;
color: #999;
line-height: 1;
}
}
.popup-body {
padding: 30rpx;
max-height: 800rpx;
overflow-y: auto;
}
.popup-footer {
display: flex;
border-top: 1rpx solid #eee;
button {
flex: 1;
height: 90rpx;
line-height: 90rpx;
border-radius: 0;
font-size: 30rpx;
&::after {
border: none;
}
}
.btn-cancel {
background: #fff;
color: #666;
}
.btn-confirm {
color: #fff;
}
}
</style>

41
pages/closeout/editor.vue Normal file
View File

@@ -0,0 +1,41 @@
<template>
<view class="padding page">
<view class="padding bg-white radius">
<view class="flex margin-bottom">
<view class="text-gray">隐患</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入内容"></up-input>
<view class="flex margin-bottom margin-top">
<view class="text-gray">整改时限</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入内容"></up-input>
<view class="text-gray margin-bottom margin-top">隐患治理责任单位</view>
<up-input placeholder="请输入内容"></up-input>
<view class="text-gray margin-bottom margin-top">主要负责人</view>
<up-input placeholder="请输入内容"></up-input>
<view class="margin-bottom text-gray margin-top">主要治理内容</view>
<up-textarea v-model="value1" placeholder="请输入内容" ></up-textarea>
<view class="margin-bottom text-gray margin-top">隐患治理完成情况</view>
<up-textarea v-model="value1" placeholder="请输入内容" ></up-textarea>
<view class="margin-bottom text-gray margin-top">隐患治理责任单位自行验收的情况</view>
<up-textarea v-model="value1" placeholder="请输入内容" ></up-textarea>
<view class="flex justify-center margin-top-xl">
<button class="lg round cu-btn lg margin-right">取消</button>
<button class="bg-blue round cu-btn lg ">确定</button>
</view>
</view>
</view>
</template>
<script>
</script>
<style l>
.page {
min-height: 100vh;
background: #EBF2FC;
}
</style>

View File

@@ -0,0 +1,49 @@
<template>
<view class="page padding">
<view class="padding bg-white radius list">
<view class="flex justify-between">
<view class="text-bold">湘西自治州和谐网络科技有限公司</view>
<view class="lg text-blue cuIcon-edit over" @click="edit()">编辑</view>
</view>
<view class="flex margin-top">
<view class="text-gray">所属部门</view>
<view>湘西自治州和谐网络科技有限公司</view>
</view>
<view class="flex margin-top">
<view class="text-gray">企业代码</view>
<view>91433126MA4P8WWG20</view>
</view>
<view class="flex margin-top">
<view class="text-gray">联系电话</view>
<view>13974356210</view>
</view>
<view class="flex margin-top">
<view class="text-gray">企业地址</view>
<view>湘西州文学艺术界联合会6楼</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const edit = () => {
uni.navigateTo({
url: '/pages/editcompanInformation/editcompanInformation'
})
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.list {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 6rpx 2rpx rgba(0, 0, 0, 0.08);
border-left: 5px solid #2667E9;
border-radius: 20rpx;
padding: 20rpx;
}
</style>

View File

@@ -0,0 +1,606 @@
<template>
<view class="page padding">
<view class="padding radius bg-white">
<view class="flex margin-bottom ">
<view class="text-gray">检查表名称</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入检查表名称" border="surround"></up-input>
<view class="flex margin-bottom margin-top">
<view class="text-gray">分派单位</view>
<view class="text-red">*</view>
</view>
<up-select placeholder="请选择分派单位" v-model:current="cateId" label="湘西自治州和谐网络科技有限公司" :options="cateList" @select="selectItem" ></up-select>
<view class="margin-bottom margin-top">补充说明</view>
<up-textarea v-model="value1" placeholder="请输入内容" ></up-textarea>
<view class="margin-bottom margin-top" >运行模式</view>
<up-select placeholder="请选择分派单位" v-model:current="cateId" label="全员" :options="cateList" @select="selectItem" ></up-select>
<view class="margin-bottom margin-top" >部门</view>
<up-select placeholder="请选择分派单位" v-model:current="cateId" label="选择部门" :options="cateList" @select="selectItem" ></up-select>
<view class="margin-bottom margin-top" >周期</view>
<up-select placeholder="请选择分派单位" v-model:current="cateId" label="每天一次" :options="cateList" @select="selectItem" ></up-select>
<view class="margin-bottom margin-top" >工作日</view>
<view class="flex">
<up-switch v-model="value" @change="change" activeColor="#07C160 " class="margin-right"></up-switch>
<up-switch v-model="value" @change="change" activeColor="#07C160 "></up-switch>
</view>
<view class="margin-bottom margin-top" @click="show = true">开始日期</view>
<up-calendar :show="show" :mode="mode" @confirm="confirm"></up-calendar>
<view class="margin-bottom margin-top" @click="show = true">结束日期</view>
<up-calendar :show="show" :mode="mode" @confirm="confirm"></up-calendar>
<view class="margin-bottom margin-top">已添加的检查项31</view>
<view>
<view class="flex margin-bottom">
<view style="white-space: nowrap;">检查库</view>
<view>应急管理部门非煤地下矿山领域标准化检查表</view>
</view>
<view class="flex margin-bottom">
<view style="white-space: nowrap;">关联表名</view>
<view>应急管理部门非煤地下矿山领域标准化检查表</view>
</view>
<view class="flex margin-bottom">
<view>检查项数量</view>
<view>31</view>
</view>
<view class="btn-right">
<button class="bg-red cu-btn ">删除</button>
</view>
<view class="margin-bottom margin-top">添加检查项</view>
<view class="flex justify-between">
<view class="but" @click="showAddPopup = true">手动添加</view>
<view class="but" @click="showLibraryPopup = true">从检查库添加</view>
</view>
</view>
</view>
<button class="bg-blue round margin-top-xl margin-bottom-xl">保存</button>
<!-- 手动添加检查项弹出框 -->
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title text-bold">手动添加检查项</view>
<view class="popup-close" @click="showAddPopup = false">×</view>
</view>
<view class="popup-body">
<!-- 项目名称 -->
<view class="form-item">
<view class="form-label">项目名称<text class="text-red">*</text></view>
<input class="form-input" v-model="checkForm.projectName" placeholder="请输入项目名称" />
</view>
<!-- 检查内容 -->
<view class="form-item">
<view class="form-label">检查内容<text class="text-red">*</text></view>
<input class="form-input" v-model="checkForm.checkContent" placeholder="请输入检查内容" />
</view>
<!-- 参考法规 -->
<view class="form-item">
<view class="form-label">参考法规</view>
<view class="form-btn" @click="showLawPopup = true">
<text class="text-blue">{{ checkForm.law || '选择法规' }}</text>
</view>
</view>
<!-- 参考图片 -->
<view class="form-item">
<view class="form-label">参考图片</view>
<view class="upload-box" @click="chooseImage">
<view class="upload-add" v-if="!checkForm.image">
<text class="upload-icon">+</text>
<text class="upload-text">上传图片</text>
</view>
<image v-else :src="checkForm.image" mode="aspectFill" class="upload-img"></image>
</view>
</view>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="handleAddCheck">确定</button>
</view>
</view>
</u-popup>
<!-- 选择法规弹出框 -->
<u-popup :show="showLawPopup" mode="center" round="20" @close="showLawPopup = false">
<view class="law-popup">
<view class="popup-header">
<view class="popup-title text-bold">选择参考法规</view>
<view class="popup-close" @click="showLawPopup = false">×</view>
</view>
<!-- 搜索框 -->
<view class="search-box">
<text class="search-icon">🔍</text>
<input class="search-input" v-model="lawKeyword" placeholder="请输入关键词搜索" />
</view>
<!-- 法规列表 -->
<view class="law-list">
<view
class="law-item"
:class="{ 'law-item-active': selectedLaw === item }"
v-for="(item, index) in filteredLawList"
:key="index"
@click="selectedLaw = item"
>
{{ item }}
</view>
</view>
<!-- 加载更多 -->
<view class="load-more" @click="loadMoreLaw">
<text class="text-blue">加载更多</text>
</view>
<!-- 确认按钮 -->
<view class="law-footer">
<button class="btn-cancel" @click="showLawPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="confirmLaw">确定</button>
</view>
</view>
</u-popup>
<!-- 从检查库添加弹出框 -->
<u-popup :show="showLibraryPopup" mode="center" round="20" @close="showLibraryPopup = false">
<view class="library-popup">
<view class="popup-header">
<view class="popup-title text-bold">选择检查库</view>
<view class="popup-close" @click="showLibraryPopup = false">×</view>
</view>
<!-- 搜索框 -->
<view class="search-box">
<text class="search-icon">🔍</text>
<input class="search-input" v-model="libraryKeyword" placeholder="请输入关键词搜索" />
</view>
<!-- 检查库列表 -->
<view class="library-list">
<view
class="library-item"
v-for="(item, index) in filteredLibraryList"
:key="index"
@click="toggleLibrarySelect(item)"
>
<view class="library-checkbox" :class="{ 'library-checkbox-active': selectedLibraries.includes(item.id) }">
<text v-if="selectedLibraries.includes(item.id)"></text>
</view>
<view class="library-info">
<view class="library-name">关联表名{{ item.name }}</view>
<view class="library-count text-gray">{{ item.count }}</view>
</view>
</view>
</view>
<!-- 添加选中项按钮 -->
<button class="btn-add-library bg-blue" @click="addSelectedLibrary">添加选中项</button>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, reactive, computed } from 'vue'
// 响应式数据
const cateId = ref('')
const cateList = ref([
{
id: '1',
name: '湘西自治州和谐网络科技有限公司'
},
{
id: '2',
name: '湘西自治州和谐云大数据科技有限公司'
},
{
id: '3',
name: '湘西网络有限公司'
},
])
// 方法
const selectItem = (item) => {
console.log(item);
};
// 工作日开关
const value = ref(false)
// 日期
const show = ref(false);
const mode = ref('single');
const confirm = (e) => {
console.log(e);
};
// 手动添加检查项弹窗
const showAddPopup = ref(false);
const checkForm = reactive({
projectName: '',
checkContent: '',
law: '',
image: ''
});
// 选择法规弹窗
const showLawPopup = ref(false);
const lawKeyword = ref('');
const selectedLaw = ref('');
const lawList = ref([
'中华人民共和国安全生产法 第三十二条',
'建设项目安全设施"三同时"监督管理办法 第二十条',
'中华人民共和国职业病防治法 第十七条',
'中华人民共和国职业病防治法 第十八条',
'中华人民共和国消防法2021版第十一条',
'建设工程消防监督管理规定 第二十条'
]);
// 过滤法规列表
const filteredLawList = computed(() => {
if (!lawKeyword.value) return lawList.value;
return lawList.value.filter(item => item.includes(lawKeyword.value));
});
// 加载更多法规
const loadMoreLaw = () => {
uni.showToast({ title: '加载更多...', icon: 'none' });
};
// 确认选择法规
const confirmLaw = () => {
if (selectedLaw.value) {
checkForm.law = selectedLaw.value;
}
showLawPopup.value = false;
};
// 从检查库添加弹窗
const showLibraryPopup = ref(false);
const libraryKeyword = ref('');
const selectedLibraries = ref([]);
const libraryList = ref([
{ id: 1, name: '安全生产隐患"常见病"检查诊断表(个性部分)公路养护工程', count: 18 },
{ id: 2, name: '安全生产隐患"常见病"检查诊断表(个性部分)出租汽车企业', count: 12 },
{ id: 3, name: '安全生产隐患"常见病"检查诊断表(个性部分)城镇燃气', count: 12 }
]);
// 过滤检查库列表
const filteredLibraryList = computed(() => {
if (!libraryKeyword.value) return libraryList.value;
return libraryList.value.filter(item => item.name.includes(libraryKeyword.value));
});
// 切换选择检查库
const toggleLibrarySelect = (item) => {
const index = selectedLibraries.value.indexOf(item.id);
if (index > -1) {
selectedLibraries.value.splice(index, 1);
} else {
selectedLibraries.value.push(item.id);
}
};
// 添加选中的检查库
const addSelectedLibrary = () => {
if (selectedLibraries.value.length === 0) {
uni.showToast({ title: '请选择检查库', icon: 'none' });
return;
}
console.log('添加检查库:', selectedLibraries.value);
uni.showToast({ title: '添加成功', icon: 'success' });
showLibraryPopup.value = false;
selectedLibraries.value = [];
};
// 选择图片
const chooseImage = () => {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
checkForm.image = res.tempFilePaths[0];
}
});
};
// 提交检查项
const handleAddCheck = () => {
if (!checkForm.projectName) {
uni.showToast({ title: '请输入项目名称', icon: 'none' });
return;
}
if (!checkForm.checkContent) {
uni.showToast({ title: '请输入检查内容', icon: 'none' });
return;
}
console.log('提交检查项:', checkForm);
uni.showToast({ title: '添加成功', icon: 'success' });
showAddPopup.value = false;
// 重置表单
checkForm.projectName = '';
checkForm.checkContent = '';
checkForm.law = '';
checkForm.image = '';
};
</script>
<style scoped lang="scss">
.page {
min-height: 100vh;
background: #EBF2FC;
}
.btn-right {
display: flex;
justify-content: flex-end;
}
.but {
width: 304rpx;
height: 72rpx;
border-radius: 6rpx 6rpx 6rpx 6rpx;
border: 2rpx solid #108FFF;
color: #108FFF;
text-align: center;
line-height: 72rpx;
}
// 弹出框样式
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.popup-title {
font-size: 34rpx;
color: #333;
}
.popup-close {
font-size: 48rpx;
color: #999;
line-height: 1;
}
.popup-body {
max-height: 700rpx;
overflow-y: auto;
}
.form-item {
margin-bottom: 24rpx;
}
.form-label {
font-size: 28rpx;
color: #333;
margin-bottom: 12rpx;
}
.form-input {
width: 100%;
height: 80rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.form-btn {
width: 100%;
height: 80rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
}
.upload-box {
width: 160rpx;
height: 160rpx;
border: 2rpx dashed #ccc;
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
}
.upload-add {
display: flex;
flex-direction: column;
align-items: center;
}
.upload-icon {
font-size: 48rpx;
color: #999;
}
.upload-text {
font-size: 24rpx;
color: #999;
margin-top: 8rpx;
}
.upload-img {
width: 100%;
height: 100%;
border-radius: 12rpx;
}
.popup-footer {
display: flex;
justify-content: center;
gap: 30rpx;
margin-top: 40rpx;
}
.btn-cancel {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border: 2rpx solid #E5E5E5;
border-radius: 40rpx;
background: #fff;
color: #333;
font-size: 30rpx;
}
.btn-confirm {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: #fff;
font-size: 30rpx;
}
// 选择法规弹窗
.law-popup {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
max-height: 80vh;
}
.search-box {
display: flex;
align-items: center;
background: #F5F5F5;
border-radius: 40rpx;
padding: 16rpx 24rpx;
margin-bottom: 24rpx;
}
.search-icon {
font-size: 28rpx;
margin-right: 12rpx;
}
.search-input {
flex: 1;
font-size: 28rpx;
background: transparent;
}
.law-list {
max-height: 500rpx;
overflow-y: auto;
}
.law-item {
padding: 24rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
margin-bottom: 16rpx;
font-size: 28rpx;
color: #333;
}
.law-item-active {
border-color: #2667E9;
background: #F0F6FF;
}
.load-more {
text-align: center;
padding: 24rpx;
border: 2rpx solid #2667E9;
border-radius: 40rpx;
margin-top: 16rpx;
}
.law-footer {
display: flex;
justify-content: center;
gap: 30rpx;
margin-top: 30rpx;
}
// 检查库弹窗样式
.library-popup {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
max-height: 80vh;
}
.library-list {
max-height: 500rpx;
overflow-y: auto;
}
.library-item {
display: flex;
align-items: flex-start;
padding: 24rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
margin-bottom: 16rpx;
}
.library-checkbox {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #ccc;
border-radius: 8rpx;
margin-right: 20rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-top: 4rpx;
}
.library-checkbox-active {
background: #2667E9;
border-color: #2667E9;
color: #fff;
}
.library-info {
flex: 1;
}
.library-name {
font-size: 28rpx;
color: #333;
line-height: 1.5;
}
.library-count {
font-size: 24rpx;
margin-top: 8rpx;
}
.btn-add-library {
width: 100%;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: #fff;
font-size: 30rpx;
margin-top: 30rpx;
}
</style>

View File

@@ -0,0 +1,108 @@
<template>
<view class="padding page">
<view class="padding bg-white radius">
<view class="flex margin-bottom margin-top">
<view>用户名</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">企业代码</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="flex margin-bottom margin-top">
<view>企业类型</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">注册资金万元</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">建设日期</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">员工人数</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">所属行业</view>
<up-radio-group v-model="radiovalue1" placement="row" shape="square" @change="groupChange">
<up-radio :customStyle="{marginBottom: '8px'}" v-for="(item, index) in radiolist1" :key="index"
:label="item.name" :name="item.name" @change="radioChange">
</up-radio>
</up-radio-group>
<view class="margin-bottom margin-top">主营业务</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">年收入万元</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">所在城市</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">企业地址</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">联系电话</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">邮箱</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">法人代表</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">法人手机</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">安全负责人</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">安全负责人手机</view>
<up-input placeholder="请输入内容" border="surround" v-model="value" @change="change"></up-input>
<view class="margin-bottom margin-top">证书图片</view>
<up-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple
:maxCount="10"></up-upload>
<view class="margin-bottom margin-top">企业简介</view>
<up-textarea v-model="value1" placeholder="请输入内容"></up-textarea>
</view>
</view>
</template>
<script setup>
import {
ref,
reactive
} from 'vue';
// 基本案列数据
const radiolist1 = reactive([{
name: '矿山开采',
disabled: false,
},
{
name: '化工生产',
disabled: false,
},
{
name: '冶金工业',
disabled: false,
},
{
name: '建筑施工',
disabled: false,
},
]);
// up-radio-group的v-model绑定的值如果设置为某个radio的name就会被默认选中
const radiovalue1 = ref('矿山开采');
const groupChange = (n) => {
console.log('groupChange', n);
};
const radioChange = (n) => {
console.log('radioChange', n);
};
// 图片上传
const fileList1 = ref([]);
const afterRead = (event) => {
console.log(event);
};
const deletePic = (event) => {
console.log(event);
};
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
</style>

View File

@@ -0,0 +1,271 @@
<template>
<view class="padding">
<view class="padding">
<view class="text-gray text-center margin-top-xl margin-bottom-xl">暂无设备</view>
<button class="cuIcon-add round bg-blue" @click="toAdd">新增</button>
</view>
<!-- 新增弹出框 -->
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title text-bold">新增设备</view>
<view class="popup-close" @click="showAddPopup = false">×</view>
</view>
<view class="popup-body">
<!-- 在这里填写表单内容 -->
<view class="flex">
<view class=" margin-bottom">型号</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入型号"></up-input>
<view class="flex margin-bottom margin-top">
<view >名称</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入名称"></up-input>
<view class=" margin-bottom margin-top">参数</view>
<up-input placeholder="请输入参数"></up-input>
<view class="flex margin-bottom margin-top">
<view>数量(单位)</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入数量"></up-input>
<view class="flex margin-bottom margin-top">
<view >购买时间</view>
<view class="text-red">*</view>
</view>
<up-datetime-picker hasInput :show="show" v-model="value1" mode="date"></up-datetime-picker>
<view class="flex margin-bottom margin-top">
<view >设备预警时间</view>
<view class="text-red">*</view>
</view>
<up-datetime-picker hasInput :show="show" v-model="value1" mode="date"></up-datetime-picker>
<view class="flex margin-bottom margin-top">
<view >区域</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入区域"></up-input>
<view class="margin-top-sm margin-bottom-sm margin-bottom margin-top">上传资料</view>
<view class="upload-area" @click="chooseFile">
<view class="upload-icon">
<text class="cuIcon-upload" style="font-size: 60rpx; color: #999;"></text>
</view>
<view class="upload-text">点击选择文件</view>
<view class="upload-tip">支持WordExcelPDF图片等格式</view>
<button class="cu-but bg-blue">选择文件</button>
</view>
<!-- 已上传文件列表 -->
<view class="file-list" v-if="fileList.length > 0">
<view class="file-item" v-for="(file, index) in fileList" :key="index">
<text class="file-name">{{ file.name }}</text>
<text class="file-delete text-red" @click.stop="removeFile(index)">×</text>
</view>
</view>
<view class="margin-top-sm margin-bottom margin-top">备注</view>
<up-textarea v-model="value1" placeholder="请输入备注"></up-textarea>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="handleAdd">确定</button>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import {
ref,
reactive
} from 'vue';
// 弹出框显示状态
const showAddPopup = ref(false);
// 文件列表
const fileList = ref([]);
// 打开新增弹出框
const toAdd = () => {
showAddPopup.value = true;
};
// 选择文件
const chooseFile = () => {
uni.chooseMessageFile({
count: 10,
type: 'all',
success: (res) => {
const files = res.tempFiles.map(file => ({
name: file.name,
path: file.path,
size: file.size
}));
fileList.value = [...fileList.value, ...files];
},
fail: () => {
// 如果不支持chooseMessageFile使用chooseImage
uni.chooseImage({
count: 9,
success: (res) => {
const files = res.tempFilePaths.map((path, index) => ({
name: `文件${fileList.value.length + index + 1}`,
path: path,
size: 0
}));
fileList.value = [...fileList.value, ...files];
}
});
}
});
};
// 移除文件
const removeFile = (index) => {
fileList.value.splice(index, 1);
};
// 确定新增
const handleAdd = () => {
// 在这里处理新增逻辑
showAddPopup.value = false;
uni.showToast({
title: '新增成功',
icon: 'success'
});
};
// 选择时间
const show = ref(false);
const value1 = ref(Date.now());
</script>
<style lang="scss" scoped>
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
}
.popup-title {
font-size: 32rpx;
}
.popup-close {
font-size: 40rpx;
color: #999;
cursor: pointer;
}
.popup-body {
padding: 30rpx;
max-height: 60vh;
overflow-y: auto;
}
.popup-footer {
display: flex;
border-top: 1rpx solid #eee;
button {
flex: 1;
height: 90rpx;
line-height: 90rpx;
border-radius: 0;
font-size: 30rpx;
&::after {
border: none;
}
}
.btn-cancel {
background: #f5f5f5;
color: #666;
}
.btn-confirm {
color: #fff;
}
}
// 上传区域样式
.upload-area {
background: #F8F8F;
border: 2rpx dashed #C5D4F5;
border-radius: 16rpx;
padding: 40rpx 30rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 16rpx;
}
.upload-icon {
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 16rpx;
}
.upload-text {
font-size: 28rpx;
color: #333;
margin-bottom: 8rpx;
}
.upload-tip {
font-size: 24rpx;
color: #999;
margin-bottom: 24rpx;
}
.upload-btn {
padding: 16rpx 48rpx;
font-size: 28rpx;
color: #fff;
border-radius: 40rpx;
}
// 文件列表样式
.file-list {
margin-top: 20rpx;
}
.file-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16rpx 20rpx;
background: #f5f5f5;
border-radius: 8rpx;
margin-bottom: 12rpx;
}
.file-name {
font-size: 26rpx;
color: #333;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.file-delete {
font-size: 36rpx;
padding-left: 20rpx;
}
</style>

View File

@@ -0,0 +1,540 @@
<template>
<view class=" page padding">
<view class="padding radius bg-white list-list margin-bottom" v-for="item in hiddenDangerList" :key="item.hazardId">
<view class="flex justify-between margin-bottom">
<view class="text-bold text-black">{{item.title}}</view>
<view class="text-blue">{{item.statusName}}</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">隐患等级</view>
<view>{{item.levelName}}</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray" style="white-space: nowrap;">隐患位置</view>
<view class="text-black">{{item.address}}</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">创建时间</view>
<view class="text-black">{{item.createdAt}}</view>
</view>
<view class="flex col-3" style="gap: 10rpx;">
<button class="round cu-btn lg light bg-blue" @click="details(item)">查看详情</button>
<button class="round cu-btn lg light bg-blue" @click="Rectification(item)">立即整改</button>
<button class="round cu-btn lg bg-blue" @click="acceptance()">立即验收</button>
</view>
</view>
<button class="cuIcon-add round bg-blue margin-top-xl" @click="showAddPopup = true">新增</button>
<!-- 新增弹窗 -->
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title text-bold">新增隐患排查</view>
<view class="popup-close" @click="showAddPopup = false">×</view>
</view>
<view class="popup-body">
<view class="flex margin-bottom">
<view class="text-gray">隐患图片/视频</view>
<view class="text-red">*</view>
</view>
<up-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple
:maxCount="10"></up-upload>
<view class="text-gray text-sm">必填请上传现场照片或者视频作为隐患证据</view>
<view class="flex margin-bottom margin-top">
<view class="text-gray">隐患标题</view>
<view class="text-red">*</view>
</view>
<up-input placeholder="请输入内容" border="surround" v-model="formData.title"></up-input>
<view class="text-sm text-gray margin-top-xs">请用简洁的语言概括隐患要点</view>
<view class="flex margin-bottom margin-top">
<view class="text-gray">隐患等级</view>
<view class="text-red">*</view>
</view>
<up-choose v-model="formData.level" :options="levelOptions" :wrap="false" item-width="183rpx" item-height="72rpx"></up-choose>
<view class="flex margin-bottom margin-top">
<view class="text-gray">隐患位置</view>
<view class="text-red">*</view>
</view>
<view class="address-box">
<view class="address-input" @click="showAddressPopup = true">
<text :class="selectedAddress ? '' : 'text-gray'">{{ selectedAddress || '请选择地址' }}</text>
</view>
<button class="btn-address bg-blue" @click="showAddressPopup = true">选择地址</button>
</view>
<!-- 地址选择弹窗 -->
<u-popup :show="showAddressPopup" mode="center" round="20" @close="showAddressPopup = false">
<view class="address-popup">
<view class="popup-header">
<view class="popup-title text-bold">选择地址</view>
<view class="popup-close" @click="showAddressPopup = false">×</view>
</view>
<view class="address-popup-body">
<view class="search-box">
<input class="search-input" v-model="addressKeyword" placeholder="请输入关键词搜索" />
</view>
<view class="address-list">
<view class="address-item" v-for="(item, index) in filteredAddressList" :key="index"
@click="tempSelectedAddress = item" :class="{'address-item-active': tempSelectedAddress === item}">
<text>{{ item }}</text>
</view>
</view>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="showAddressPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="confirmAddress">定位</button>
</view>
</view>
</u-popup>
<view class="text-gray text-sm margin-top-xs">办公楼3层东侧消防通道生产车间A区设备旁等或点击"选择地址"按钮在地图上选择</view>
<view class="flex margin-bottom margin-top">
<view class="text-gray">隐患描述</view>
<view class="text-red">*</view>
</view>
<up-textarea v-model="formData.description" placeholder="请输入内容" ></up-textarea>
<view class="text-gray text-sm margin-top-xs">请详细说明隐患现状潜在风险及影响范围</view>
<view class="text-gray margin-bottom margin-top">隐患标签</view>
<up-choose v-model="formData.tagIndex" :options="tagOptions"></up-choose>
<view class="text-gray text-sm">可选择多个相关标签对隐患进行分类</view>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="handleAdd">确定</button>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, computed, reactive } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { addHiddenDanger, enterCheckPlan, getCheckTaskDetail,getMyHiddenDangerList,getHiddenDangerLabelList} from '@/request/api.js'
import { baseUrl,AUTH_TOKEN } from '@/request/request.js'
// 弹窗控制
const showAddPopup = ref(false);
// 任务相关ID从接口获取
const taskId = ref('');
const checkPointId = ref('');
// 获取任务详情
const fetchTaskInfo = async (oneTableId) => {
try {
// 第一步:调用 start 接口获取 taskId
const startRes = await enterCheckPlan(oneTableId);
if (startRes.code === 0 && startRes.data) {
const tid = startRes.data.taskId;
// 第二步:用 taskId 获取任务详情
const detailRes = await getCheckTaskDetail(tid);
if (detailRes.code === 0 && detailRes.data) {
taskId.value = detailRes.data.taskId;
checkPointId.value = detailRes.data.checkPointId;
}
}
} catch (error) {
console.error('获取任务信息失败:', error);
}
};
onLoad((options) => {
if (options.id) {
fetchTaskInfo(options.id);
}
});
// 表单数据
const formData = reactive({
title: '', // 隐患标题
level: 0, // 隐患等级索引
description: '', // 隐患描述
tagIndex: 0, // 隐患标签索引
});
// 经纬度
const lng = ref(0);
const lat = ref(0);
// 地址选择
const showAddressPopup = ref(false);
const addressKeyword = ref('');
const selectedAddress = ref('');
const tempSelectedAddress = ref('');
const addressList = ref([
'湖南省湘西土家族苗族自治州吉首市人民北路105号',
'湖南省湘西土家族苗族自治州吉首市人民南路100号',
'湖南省湘西土家族苗族自治州吉首市团结广场',
'湖南省湘西土家族苗族自治州吉首市火车站'
]);
const filteredAddressList = computed(() => {
if (!addressKeyword.value) return addressList.value;
return addressList.value.filter(item => item.includes(addressKeyword.value));
});
const confirmAddress = () => {
if (tempSelectedAddress.value) {
selectedAddress.value = tempSelectedAddress.value;
}
showAddressPopup.value = false;
};
// 确定新增
const handleAdd = async () => {
// 表单验证
if (!formData.title) {
uni.showToast({ title: '请输入隐患标题', icon: 'none' });
return;
}
if (fileList1.value.length === 0) {
uni.showToast({ title: '请上传隐患图片/视频', icon: 'none' });
return;
}
// 构建附件列表 - 从上传返回的url中提取文件名
const attachments = fileList1.value.map(file => {
// 确保 url 是字符串
let url = '';
if (typeof file.url === 'string') {
url = file.url;
} else if (file.url && typeof file.url === 'object') {
url = file.url.url || file.url.path || '';
}
// 从url中提取文件名
const fileName = (typeof url === 'string' && url) ? url.split('/').pop() : (file.name || '');
return {
fileName: fileName || '',
filePath: url || '',
fileType: file.type || 'image/png',
fileSize: file.size || 0
};
});
// 获取隐患标签ID
const selectedTag = tagOptions.value[formData.tagIndex];
const tagId = selectedTag ? selectedTag.id : null;
// 构建请求参数
const params = {
title: formData.title,//标题
level: formData.level + 1, // 1.轻微隐患 2.一般隐患 3.重大隐患
lng: lng.value || 0,//经度
lat: lat.value || 0,//纬度
address: selectedAddress.value || '',//详细地址
description: formData.description || '',//隐患描述
tagId: tagId,//隐患标签ID
taskId: taskId.value, //关联任务ID
checkPointId: checkPointId.value,//关联检查点ID
source:'cillum labore veniam',//隐患来源
};
//
try {
const res = await addHiddenDanger(params);
if (res.code === 0) {
uni.showToast({
title: '新增成功',
icon: 'success'
});
showAddPopup.value = false;
// 重置表单
formData.title = '';
formData.level = 0;
formData.description = '';
formData.tagIndex = 0;
selectedAddress.value = '';
fileList1.value = [];
} else {
uni.showToast({ title: res.msg || '新增失败', icon: 'none' });
}
} catch (error) {
console.error(error);
uni.showToast({ title: '请求失败', icon: 'none' });
}
};
//获取隐患列表
const hiddenDangerList = ref([]);
const fetchHiddenDangerList = async () => {
try {
const res = await getMyHiddenDangerList();
if (res.code === 0) {
hiddenDangerList.value = res.data;
} else {
uni.showToast({ title: res.msg || '获取隐患列表失败', icon: 'none' });
}
} catch (error) {
console.error(error);
uni.showToast({ title: '请求失败', icon: 'none' });
}
};
fetchHiddenDangerList();
const details = (item) => {
uni.navigateTo({
url: `/pages/hiddendanger/view?hazardId=${item.hazardId}&assignId=${item.assignId}`
})
}
const Rectification = (item) => {
uni.navigateTo({
url: `/pages/hiddendanger/rectification?hazardId=${item.hazardId}&assignId=${item.assignId}`
})
}
const acceptance = () => {
uni.navigateTo({
url: '/pages/hiddendanger/acceptance'
})
}
const fileList1 = ref([]);
// 删除图片
const deletePic = (event) => {
fileList1.value.splice(event.index, 1);
};
// 新增图片
const afterRead = async (event) => {
// 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file);
let fileListLen = fileList1.value.length;
lists.map((item) => {
fileList1.value.push({
...item,
status: 'uploading',
message: '上传中',
});
});
for (let i = 0; i < lists.length; i++) {
const result = await uploadFilePromise(lists[i].url);
let item = fileList1.value[fileListLen];
fileList1.value.splice(fileListLen, 1, {
...item,
status: 'success',
message: '',
url: result,
});
fileListLen++;
}
};
const uploadFilePromise = (filePath) => {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: baseUrl + '/frontend/attachment/upload',
filePath: filePath,
name: 'file',
header: {
'Authorization': AUTH_TOKEN
},
success: (res) => {
const data = JSON.parse(res.data);
if (data.code === 0) {
resolve(data.data);
} else {
reject(data.msg || '上传失败');
}
},
fail: (err) => {
console.error('上传失败:', err);
reject(err);
}
});
});
};
// 隐患标签选项
// const tagOptions = ref([
// {id: 1, title: '安全'},
// {id: 2, title: '人机工程'},
// {id: 3, title: '其他'},
// {id: 4, title: '职业健康'},
// {id: 5, title: '电气隐患'},
// {id: 6, title: '环保'}
// ])
const tagOptions = ref([]);
const fetchTagOptions = async () => {
try {
const res = await getHiddenDangerLabelList();
if (res.code === 0) {
// 将接口返回的 name 字段映射为 title 字段,供 up-choose 组件使用
tagOptions.value = res.data.map(item => ({
id: item.id,
title: item.name
}));
} else {
uni.showToast({ title: res.msg || '获取标签列表失败', icon: 'none' });
}
} catch (error) {
console.error(error);
uni.showToast({ title: '请求失败', icon: 'none' });
}
};
fetchTagOptions();
//
// 隐患等级选项
const levelOptions = ref([
{id: 1, title: '轻微隐患'},
{id: 2, title: '一般隐患'},
{id: 3, title: '重大隐患'}
])
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.list-list {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 6rpx 2rpx rgba(0, 0, 0, 0.08);
border-left: 5px solid #2667E9;
border-radius: 20rpx;
padding: 20rpx;
}
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
border-bottom: 1rpx solid #eee;
.popup-title {
font-size: 32rpx;
color: #333;
}
.popup-close {
font-size: 40rpx;
color: #999;
line-height: 1;
}
}
.popup-body {
padding: 30rpx;
max-height: 900rpx;
overflow-y: auto;
}
.popup-footer {
display: flex;
border-top: 1rpx solid #eee;
button {
flex: 1;
height: 90rpx;
line-height: 90rpx;
border-radius: 0;
font-size: 30rpx;
&::after {
border: none;
}
}
.btn-cancel {
background: #fff;
color: #666;
}
.btn-confirm {
color: #fff;
}
}
.address-box {
display: flex;
align-items: center;
gap: 20rpx;
.address-input {
flex: 1;
background: #fff;
border: 1rpx solid #F6F6F6;;
border-radius: 8rpx;
padding: 20rpx;
font-size: 26rpx;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.btn-address {
flex-shrink: 0;
height: 70rpx;
line-height: 70rpx;
padding: 0 30rpx;
font-size: 26rpx;
border-radius: 8rpx;
color: #fff;
&::after {
border: none;
}
}
}
.address-popup {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
overflow: hidden;
}
.address-popup-body {
padding: 30rpx;
max-height: 500rpx;
.search-box {
margin-bottom: 20rpx;
.search-input {
width: 100%;
background: #f5f5f5;
border-radius: 8rpx;
padding: 16rpx 20rpx;
font-size: 28rpx;
}
}
.address-list {
max-height: 350rpx;
overflow-y: auto;
}
.address-item {
padding: 24rpx 20rpx;
border-bottom: 1rpx solid #eee;
font-size: 26rpx;
color: #333;
&:last-child {
border-bottom: none;
}
&.address-item-active {
background: #EBF2FC;
color: #2667E9;
}
}
}
</style>
<style lang="scss">
/* 全局样式覆盖 up-tag 文字居中 */
.u-tag {
justify-content: center !important;
}
</style>

View File

@@ -0,0 +1,80 @@
<template>
<view class="page padding">
<view class="padding bg-white radius">
<view class="text-gray margin-bottom">整改记录</view>
<up-textarea v-model="value1" placeholder="请输入内容"></up-textarea>
<view class="flex margin-bottom margin-top">
<view class="text-gray">验收内容</view>
<view class="text-red">*</view>
</view>
<up-textarea v-model="value1" placeholder="请输入内容"></up-textarea>
<view class="flex margin-bottom margin-top">
<view class="text-gray">验收图片/视频</view>
<view class="text-red">*</view>
</view>
<up-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple :maxCount="10"></up-upload>
<button class="bg-blue round margin-top-xl"> 提交验收</button>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const fileList1 = ref([]);
// 删除图片
const deletePic = (event) => {
fileList1.value.splice(event.index, 1);
};
// 新增图片
const afterRead = async (event) => {
// 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file);
let fileListLen = fileList1.value.length;
lists.map((item) => {
fileList1.value.push({
...item,
status: 'uploading',
message: '上传中',
});
});
for (let i = 0; i < lists.length; i++) {
const result = await uploadFilePromise(lists[i].url);
let item = fileList1.value[fileListLen];
fileList1.value.splice(fileListLen, 1, {
...item,
status: 'success',
message: '',
url: result,
});
fileListLen++;
}
};
const uploadFilePromise = (url) => {
return new Promise((resolve, reject) => {
let a = uni.uploadFile({
url: 'http://192.168.2.21:7001/upload', // 仅为示例,非真实的接口地址
filePath: url,
name: 'file',
formData: {
user: 'test',
},
success: (res) => {
setTimeout(() => {
resolve(res.data.data);
}, 1000);
},
});
});
};
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
</style>

View File

@@ -0,0 +1,237 @@
<template>
<view class="page padding">
<view class="padding bg-white radius">
<view class="flex margin-bottom">
<view class="text-gray">整改方案</view>
<view class="text-red">*</view>
</view>
<up-textarea v-model="formData.rectifyPlan" placeholder="请输入内容"></up-textarea>
<view class="flex margin-bottom margin-top">
<view class="text-gray">整改完成情况</view>
<view class="text-red">*</view>
</view>
<up-textarea v-model="formData.rectifyResult" placeholder="请输入内容"></up-textarea>
<view class="flex margin-bottom">
<view class="text-gray margin-top">投资资金(计划)</view>
<view class="text-red">*</view>
</view>
<up-input v-model="formData.planCost" placeholder="请输入内容" type="number"></up-input>
<view class="flex margin-bottom">
<view class="text-gray margin-top">投资资金(实际)</view>
<view class="text-red">*</view>
</view>
<up-input v-model="formData.actualCost" placeholder="请输入内容" type="number"></up-input>
<view class="flex margin-bottom">
<view class="text-gray margin-top">限定整改时间</view>
<view class="text-red">*</view>
</view>
<view class="date-input" @click="show = true">
<text :class="selectedDate ? '' : 'text-gray'">{{ selectedDate || '请选择日期' }}</text>
</view>
<up-calendar :show="show" :mode="mode" @confirm="confirmDate" @close="show = false"></up-calendar>
<view class="flex margin-bottom">
<view class="text-gray">整改人员</view>
<view class="text-red">*</view>
</view>
<up-radio-group v-model="radiovalue1" placement="column" @change="groupChange">
<up-radio shape="square" :customStyle="{marginBottom: '8px'}" v-for="(item, index) in radiolist1"
:key="index" :label="item.name" :name="item.name" @change="radioChange"></up-radio>
</up-radio-group>
<view class="flex margin-bottom">
<view class="text-gray">整改图片/视频</view>
<view class="text-red">*</view>
</view>
<up-upload :fileList="fileList1" @afterRead="afterRead" @delete="deletePic" name="1" multiple :maxCount="10"></up-upload>
<button class="bg-blue round margin-top-xl" @click="handleSubmit">提交整改</button>
</view>
</view>
</template>
<script setup>
import {ref,reactive} from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import {submitRectification} from '@/request/api.js'
import { baseUrl, AUTH_TOKEN } from '@/request/request.js'
// 从页面参数获取的ID
const hazardId = ref('');
const assignId = ref('');
// 表单数据
const formData = reactive({
rectifyPlan: '', // 整改方案
rectifyResult: '', // 整改完成情况
planCost: '', // 投资资金(计划)
actualCost: '' // 投资资金(实际)
});
const show = ref(false);
const mode = ref('single');
const selectedDate = ref('');
const radiovalue1 = ref('');
// 基本案列数据
const radiolist1 = reactive([{
name: '孙致远',
disabled: false,
},
{
name: '符友成',
disabled: false,
},
{
name: '向彪',
disabled: false,
},
{
name: '向纪荣',
disabled: false,
},
]);
// 上传图片
const fileList1 = ref([]);
// 删除图片
const deletePic = (event) => {
fileList1.value.splice(event.index, 1);
};
// 新增图片
const afterRead = async (event) => {
// 当设置 mutiple 为 true 时, file 为数组格式,否则为对象格式
let lists = [].concat(event.file);
let fileListLen = fileList1.value.length;
lists.map((item) => {
fileList1.value.push({
...item,
status: 'uploading',
message: '上传中',
});
});
for (let i = 0; i < lists.length; i++) {
const result = await uploadFilePromise(lists[i].url);
let item = fileList1.value[fileListLen];
fileList1.value.splice(fileListLen, 1, {
...item,
status: 'success',
message: '',
url: result,
});
fileListLen++;
}
};
// 日期选择确认
const confirmDate = (e) => {
selectedDate.value = e[0];
show.value = false;
};
const uploadFilePromise = (filePath) => {
return new Promise((resolve, reject) => {
uni.uploadFile({
url: baseUrl + '/frontend/attachment/upload',
filePath: filePath,
name: 'file',
header: {
'Authorization': AUTH_TOKEN
},
success: (res) => {
const data = JSON.parse(res.data);
if (data.code === 0) {
resolve(data.data);
} else {
reject(data.msg || '上传失败');
}
},
fail: (err) => {
console.error('上传失败:', err);
reject(err);
}
});
});
};
// 提交整改
const handleSubmit = async () => {
if (!formData.rectifyPlan) {
uni.showToast({ title: '请输入整改方案', icon: 'none' });
return;
}
if (!formData.rectifyResult) {
uni.showToast({ title: '请输入整改完成情况', icon: 'none' });
return;
}
// 构建附件列表
const attachments = fileList1.value.map(file => {
let url = '';
if (typeof file.url === 'string') {
url = file.url;
} else if (file.url && typeof file.url === 'object') {
url = file.url.url || file.url.path || '';
}
const fileName = (typeof url === 'string' && url) ? url.split('/').pop() : (file.name || '');
return {
fileName: fileName || '',
filePath: url || '',
fileType: file.type || 'image/png',
fileSize: file.size || 0
};
});
const params = {
hazardId: hazardId.value,
assignId: assignId.value,
rectifyPlan: formData.rectifyPlan,
rectifyResult: formData.rectifyResult,
planCost: Number(formData.planCost) || 0,
actualCost: Number(formData.actualCost) || 0,
attachments: attachments
};
try {
const res = await submitRectification(params);
if (res.code === 0) {
uni.showToast({ title: '提交成功', icon: 'success' });
setTimeout(() => {
uni.navigateBack();
}, 1500);
} else {
uni.showToast({ title: res.msg || '提交失败', icon: 'none' });
}
} catch (error) {
console.error('提交整改失败:', error);
uni.showToast({ title: '请求失败', icon: 'none' });
}
};
onLoad((options) => {
if (options.hazardId) {
hazardId.value = options.hazardId;
}
if (options.assignId) {
assignId.value = options.assignId;
}
});
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.date-input {
background: #fff;
border-radius: 8rpx;
padding: 24rpx 20rpx;
margin-bottom: 20rpx;
border: 1rpx solid #F6F6F6 ;
text {
font-size: 28rpx;
color: #333;
}
}
</style>

131
pages/hiddendanger/view.vue Normal file
View File

@@ -0,0 +1,131 @@
<template>
<view class="padding page">
<view class="padding bg-white radius">
<view class="flex">
<view class="text-gray">隐患图片/视频</view>
<view class="text-red">*</view>
</view>
<view class="margin-bottom">
<view class="flex" style="flex-wrap: wrap; gap: 10rpx;" v-if="detailData?.attachments && detailData.attachments.length > 0">
<image v-for="(img, idx) in detailData.attachments" :key="idx" :src="img.filePath" style="width: 136rpx;height: 136rpx;border-radius: 16rpx;" mode="aspectFill"></image>
</view>
<view v-else class="text-gray text-sm">暂无图片</view>
<view class="text-gray text-sm margin-top-xs">必填请上传现场照片或者视频作为隐患证据</view>
</view>
<view class="flex margin-bottom">
<view class="text-gray">隐患标题</view>
<view class="text-red">*</view>
</view>
<up-input v-model="detailData.title" disabled="true" disabledColor="#F6F6F6" border="surround"/>
<view class="margin-bottom text-gray text-sm margin-top-xs" >请用简洁的语言概括隐患要点</view>
<view class="flex margin-bottom">
<view class="text-gray">隐患等级</view>
<view class="text-red">*</view>
</view>
<view class="flex col-3" style="gap: 10rpx;">
<view :class="detailData.level === 1 ? 'bg-blue light' : 'bg-gray'" style="padding: 16rpx 40rpx;">轻微隐患</view>
<view :class="detailData.level === 2 ? 'bg-blue light' : 'bg-gray'" style="padding: 16rpx 40rpx;">一般隐患</view>
<view :class="detailData.level === 3 ? 'bg-blue light' : 'bg-gray'" style="padding: 16rpx 40rpx;">重大隐患</view>
</view>
<view class="text-gray text-sm margin-top-xs margin-bottom">请用隐患可能造成的危害程度选择等级</view>
<view class="flex">
<view class="text-gray">隐患位置</view>
<view class="text-red">*</view>
</view>
<view class="address-box margin-top-sm margin-bottom-sm">
<input
class="address-input"
v-model="detailData.address"
placeholder="暂无地址"
disabled
/>
<button class="address-btn bg-blue">选择地址</button>
</view>
<view class="text-gray text-sm">办公楼3层东侧消防通道生产车间A区设备旁等或点击"选择地址"按钮在地图上选择</view>
<view class="flex margin-bottom ">
<view class="text-gray">隐患描述</view>
<view class="text-red">*</view>
</view>
<up-textarea v-model="detailData.description" placeholder="暂无描述" disabled></up-textarea>
<view class="text-gray text-sm margin-top-xs margin-bottom">请详细说明隐患现状潜在风险及影响范围</view>
<view class="text-gray margin-bottom">隐患来源</view>
<view class="bg-gray padding radius">{{ detailData.source || '暂无' }}</view>
<view class="text-gray margin-top margin-bottom">创建时间</view>
<view class="bg-gray padding radius">{{ detailData.createdAt || '暂无' }}</view>
</view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import { getHiddenDangerDetail } from '@/request/api.js'
// 详情数据
const detailData = reactive({
hazardId: '',
assignId: '',
title: '',
level: 0,
levelName: '',
source: '',
description: '',
address: '',
createdAt: '',
attachments: []
});
// 获取隐患详情
const fetchDetail = async (hazardId, assignId) => {
try {
const res = await getHiddenDangerDetail({ hazardId, assignId });
if (res.code === 0 && res.data) {
Object.assign(detailData, res.data);
} else {
uni.showToast({ title: res.msg || '获取详情失败', icon: 'none' });
}
} catch (error) {
console.error('获取隐患详情失败:', error);
uni.showToast({ title: '请求失败', icon: 'none' });
}
};
onLoad((options) => {
if (options.hazardId && options.assignId) {
fetchDetail(options.hazardId, options.assignId);
}
});
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.address-box {
display: flex;
align-items: center;
gap: 20rpx;
}
.address-input {
flex: 1;
height: 80rpx;
background: #F6F6F6;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #333;
}
.address-btn {
flex-shrink: 0;
height: 80rpx;
line-height: 80rpx;
padding: 0 32rpx;
border-radius: 12rpx;
font-size: 28rpx;
color: #fff;
}
</style>

346
pages/index/index.vue Normal file
View File

@@ -0,0 +1,346 @@
<template>
<view class="content">
<view class="flex padding-top-xl padding-bottom-xl text-white " style="background-color:#007aff ;">
<view class="cu-avatar xl round margin-left">
<image></image>
</view>
<view class="padding-left">
<view class="text-bold">湘西和谐云大数据产业发展有限公司</view>
<view class="flex padding-top-xs">
<view>手机号</view>
<view>17374339800</view>
</view>
<view class="flex justify-between">
<view></view>
<view class="cu-btn text-blue margin-top text-bold">切换</view>
</view>
</view>
</view>
<view class="padding" style="background: #EBF2FC;">
<view class="bg-white padding radius">
<view class>
<view></view>
<view>功能菜单</view>
</view>
<view class=" grid col-3 grid-list">
<view class="list " v-for="(item, index) in infoList" :key="index" @click="handleMenuClick(item)">
<image style="width: 102rpx;height: 102rpx;" :src="item.src"></image>
<view>{{ item.name}}</view>
</view>
</view>
</view>
<!-- 我的检查计划 -->
<view class="padding bg-white margin-top radius">
<view class="flex margin-bottom-xl">
<view class="border-tite"></view>
<view class="text-bold margin-left-xs">我的检查计划</view>
</view>
<!-- 无数据提示 -->
<view v-if="checkPlanData.length === 0" class="text-center text-gray padding">
暂无检查计划
</view>
<!-- 列表渲染 -->
<view class="list-list padding margin-bottom" v-for="(item, index) in checkPlanData" :key="item.id">
<view class="flex">
<image src="/static/蒙版组 273.png" style="width: 40rpx;height: 40rpx;"></image>
<view class="text-bold margin-left">{{ item.name }}</view>
</view>
<view class="flex margin-top">
<view class="border-border margin-right-xs">{{ item.runModeName }}完成</view>
<view class="border-border">{{ item.cycle }}</view>
</view>
<view class="flex text-gray margin-top">
<view>计划时间</view>
<view>{{ formatDate(item.planStartTime) }}{{ formatDate(item.planEndTime) }}</view>
</view>
<view class="flex margin-top align-center">
<view>完成进度</view>
<view class="flex align-center margin-left-sm">
<view class="cu-progress round">
<view class="bg-green" :style="{ width: item.progress + '%' }"></view>
</view>
<text class="margin-left-sm">{{ item.progress }}%</text>
</view>
</view>
<view class="grid col-4 bg-gray margin padding text-center radius">
<view>
<view class="text-orange">{{ item.totalCount }}</view>
<view>总数</view>
</view>
<view>
<view class="text-yellow">{{ item.totalCount - item.finishedCount }}</view>
<view>待完成</view>
</view>
<view>
<view class="text-olive">0</view>
<view>待验收</view>
</view>
<view>
<view class="text-blue">{{ item.finishedCount }}</view>
<view>已完成</view>
</view>
</view>
<view class="margin-top margin-bottom flex justify-end">
<button class="cu-btn round lg light bg-blue margin-right" @click.stop="ViewDetails(item)">查看详情</button>
<button class="cu-btn round lg bg-blue" @click.stop="goDetails(item)">开始检查</button>
</view>
</view>
</view>
<!-- 我的隐患 -->
<view class="padding bg-white margin-top radius">
<view class="flex margin-bottom-xl ">
<view class="border-tite"></view>
<view class="text-bold margin-left-xs">我的隐患排查</view>
</view>
<view class="list-list padding">
<view class="flex text-bold">
<view>隐患</view>
<view class="text-bold margin-left">#15</view>
</view>
<view class="flex margin-top">
<view class="text-gray">标题</view>
<view>有隐患</view>
</view>
<view class="flex margin-top">
<view class="text-gray">隐患来源</view>
<view>企业自查</view>
</view>
<view class="flex margin-top">
<view class="text-gray" style="white-space: nowrap;">隐患位置</view>
<view>湖南省湘西土家族苗族自治州吉首市人民北路105号</view>
</view>
<view class="flex margin-top">
<view class="text-gray">隐患等级</view>
<view>一般隐患</view>
</view>
<view class="flex margin-top">
<view class="text-gray">隐患状态</view>
<view>待验收</view>
</view>
<view class="flex margin-top">
<view class="text-gray">发现时间</view>
<view>2025-11-11 17:08:09</view>
</view>
<view class="margin-top margin-bottom flex">
<button class="cu-btn round lg light bg-blue " style="white-space: nowrap;">查看详情</button>
<button class="cu-btn round lg light bg-blue " style="white-space: nowrap;">立即整改</button>
<button class="cu-btn round lg bg-blue " style="white-space: nowrap;">立即验收</button>
</view>
</view>
</view>
</view>
<view class="cu-bar tabbar bg-white">
<view class="action">
<view class="cuIcon-cu-image">
<image src="/static/tabbar/组 20264.png"></image>
</view>
<view class="text-blue">首页</view>
</view>
<view class="action">
<view class="cuIcon-cu-image">
<image src="/static/tabbar/组 20261.png"></image>
</view>
<view class="text-gray">一张图</view>
</view>
<view class="action" @click="Inspectionwarning()">
<view class="cuIcon-cu-image">
<image src="/static/tabbar/组 20262.png"></image>
</view>
<view class="text-gray" >预警</view>
</view>
<view class="action" @click="my()">
<view class="cuIcon-cu-image">
<image src="/static/tabbar/组 20263.png"></image>
</view>
<view class="text-gray">我的</view>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import {getCheckPlanList} from '@/request/api.js'
const loading = ref(true);
const infoList = ref([{
name: '成员管理',
src: '../../static/组 19378.png'
},
{
name: '企业信息填报',
src: '../../static/组 19387.png'
},
{
name: '区域设置',
src: '../../static/组 20253.png'
},
{
name: '检查表',
src: '../../static/组 20254.png'
},
{
name: '检查记录',
src: '../../static/组 20255.png'
},
{
name: '证照管理',
src: '../../static/组 20256.png'
},
{
name: '隐患排查',
src: '../../static/组 20257.png'
},
{
name: '隐患销号申请',
src: '../../static/组 20258.png'
},
{
name: '设备登记',
src: '../../static/组 20259.png'
}
]);
const ViewDetails = (item) => {
uni.navigateTo({
url: `/pages/plandetail/plandetail?id=${item.id}`
})
}
const goDetails = (item) => {
uni.navigateTo({
url: `/pages/Inspectionresult/Inspectionresult?id=${item.id}`
})
}
// 预警
const Inspectionwarning = () => {
uni.navigateTo({
url: '/pages/Inspectionwarning/Inspectionwarning'
})
}
// 我的
const my = () => {
uni.navigateTo({
url: '/pages/personalcenter/my'
})
}
// 菜单点击跳转
const handleMenuClick = (item) => {
const menuRoutes = {
'成员管理': '/pages/membermanagemen/membermanagemen',
'企业信息填报': '/pages/corporateInformation/corporateInformation',
'区域设置':'/pages/area/management',
'检查表' :'/pages/checklist/checklist',
'检查记录': '/pages/Inspectionlog/Inspectionlog',
'证照管理': '/pages/Idphotomanagement/Idphotomanagement',
'隐患排查':'/pages/hiddendanger/Inspection',
'隐患销号申请':'/pages/closeout/application',
'设备登记':'/pages/equipmentregistration/equipmentregistration',
// 可以在这里添加其他菜单的跳转路径
};
const url = menuRoutes[item.name];
if (url) {
uni.navigateTo({ url });
} else {
uni.showToast({ title: '功能开发中', icon: 'none' });
}
}
//我的检查计划
const checkPlanParams = ref({
pageNum: 1,
pageSize: 10,
name: ''
});
const checkPlanData = ref([]);
const getCheckPlanLists = async () => {
try {
const res = await getCheckPlanList(checkPlanParams.value);
console.log(res);
if (res.code === 0) {
checkPlanData.value = res.data.records;
}
} catch (error) {
console.error(error);
} finally {
loading.value = false;
}
};
// 格式化日期 (2025-12-18 00:00:00 -> 2025-12-18)
const formatDate = (dateStr) => {
if (!dateStr) return '';
return dateStr.split(' ')[0];
};
// 页面加载时调用接口
onLoad(() => {
getCheckPlanLists();
});
</script>
<style lang="scss" scoped>
.content {}
.grid-list {
// gap: 5px 5px;
}
.list {
background: #F2F6FF;
box-shadow: 0rpx 4rpx 8rpx 2rpx #CADDFC;
border-radius: 10rpx;
text-align: center;
padding: 20rpx 0;
}
.list-list {
background: #FFFFFF;
box-shadow: 0rpx 2rpx 6rpx 2rpx rgba(0, 0, 0, 0.08);
border-left: 5px solid #2667E9;
border-radius: 20rpx;
padding: 20rpx;
}
.border-tite {
width: 10rpx;
height: 32rpx;
background: #2667E9;
border-radius: 10rpx 10rpx 10rpx 10rpx;
}
.cu-progress {
width: 300rpx;
height: 20rpx;
background: #ebeef5;
border-radius: 100rpx;
overflow: hidden;
view {
height: 100%;
border-radius: 100rpx;
transition: width 0.3s ease;
}
}
.bg-green {
background: #2667E9;
}
.border-border {
padding: 10rpx;
background: #EEF3FF;
border-radius: 4rpx 4rpx 4rpx 4rpx;
border: 2rpx solid #AAC5FC;
text-align: center;
justify-content: center;
align-items: center;
display: flex;
font-size: 28rpx;
color: #2667E9;
}
</style>

View File

@@ -0,0 +1,266 @@
<template>
<view class=" page padding ">
<view class=" padding bg-white radius">
<view class="flex justify-between align-center">
<view class="flex align-center">
<view class="border-tite"></view>
<view class="text-bold margin-left-xs" @click="show = true">湘西自治州和谐网络科技有限公司</view>
<up-picker :show="show" :columns="columns"></up-picker>
</view>
<view class="tag-outline">负责人</view>
</view>
<view class="flex margin-top">
<view class="cu-avatar radius lg" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big81005.jpg);"></view>
<view class="margin-left">
<view class="flex">
<view>罗燚</view>
<view class="margin-left-xs light bg-olive padding-left-xs padding-right-xs">正常</view>
</view>
<view class="flex text-gray">
<view>手机设置</view>
<view>未设置</view>
</view>
<view class="flex text-gray">
<view>登录IP</view>
<view>45.135.228.172</view>
</view>
</view>
<button class="bg-blue btn-lock" @click="Lock()">锁定</button>
</view>
</view>
<button class="lg cuIcon-add bg-blue round margin-top-xl" @click="showPopup = true">添加成员</button>
<!-- 添加成员弹出框 -->
<u-popup :show="showPopup" mode="center" round="20" @close="showPopup = false">
<view class="popup-content">
<view class="popup-header">
<view class="popup-title text-bold">添加成员</view>
<view class="popup-close" @click="showPopup = false">×</view>
</view>
<view class="popup-body">
<!-- 用户名 -->
<view class="form-item">
<view class="form-label">用户名<text class="text-red">*</text></view>
<input class="form-input" v-model="formData.username" placeholder="请输入用户名" />
</view>
<!-- 昵称 -->
<view class="form-item">
<view class="form-label">昵称</view>
<input class="form-input" v-model="formData.nickname" placeholder="请输入昵称" />
</view>
<!-- 手机号 -->
<view class="form-item">
<view class="form-label">手机号</view>
<input class="form-input" v-model="formData.phone" placeholder="请输入手机号" type="number" />
</view>
<!-- 密码 -->
<view class="form-item">
<view class="form-label">密码<text class="text-red">*</text></view>
<input class="form-input" v-model="formData.password" placeholder="请输入密码6-16位" password />
</view>
<!-- 主部门 -->
<view class="form-item">
<view class="form-label">主部门<text class="text-red">*</text></view>
<view class="form-input form-select" @click="showDeptPicker = true">
<text :class="formData.department ? '' : 'text-gray'">
{{ formData.department || '请选择主部门' }}
</text>
</view>
</view>
</view>
<view class="popup-footer">
<button class="btn-cancel" @click="showPopup = false">取消</button>
<button class="btn-confirm bg-blue" @click="handleSubmit">确定</button>
</view>
</view>
</u-popup>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue';
const showPopup = ref(false);
const showDeptPicker = ref(false);
const formData = reactive({
username: '',
nickname: '',
phone: '',
password: '',
department: ''
});
const handleSubmit = () => {
// 表单验证
if (!formData.username) {
uni.showToast({ title: '请输入用户名', icon: 'none' });
return;
}
if (!formData.password || formData.password.length < 6 || formData.password.length > 16) {
uni.showToast({ title: '请输入6-16位密码', icon: 'none' });
return;
}
if (!formData.department) {
uni.showToast({ title: '请选择主部门', icon: 'none' });
return;
}
// 提交逻辑
console.log('提交数据:', formData);
uni.showToast({ title: '添加成功', icon: 'success' });
showPopup.value = false;
};
// 锁定成员
const Lock = () => {
uni.showModal({
title: '提示',
content: '确定要锁定该成员吗?',
confirmColor: '#2667E9',
success: (res) => {
if (res.confirm) {
// 确认锁定
console.log('用户点击确定');
uni.showToast({ title: '锁定成功', icon: 'success' });
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
};
//选择部门
const show = ref(false);
const columns = reactive([
['湘西自治州和谐网络科技有限公司', '湘西自治州和谐云科技有限公司']
]);
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.border-tite {
width: 8rpx;
height: 32rpx;
background: #2667E9;
border-radius: 8rpx;
}
.tag-outline {
padding: 4rpx 16rpx;
border-radius: 8rpx;
background:#EEF3FF;
color: #2E7CF3 ;
font-size: 24rpx;
flex-shrink: 0;
margin-right: -30rpx;
border-radius: 24rpx 0rpx 0rpx 24rpx;
}
.btn-lock {
width: 112rpx;
height: 52rpx;
line-height: 52rpx;
padding: 0;
font-size: 26rpx;
display: flex;
align-items: center;
justify-content: center;
}
// 弹出框样式
.popup-content {
width: 600rpx;
background: #fff;
border-radius: 20rpx;
padding: 30rpx;
}
.popup-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
}
.popup-title {
font-size: 34rpx;
color: #333;
}
.popup-close {
font-size: 48rpx;
color: #999;
line-height: 1;
}
.popup-body {
max-height: 700rpx;
overflow-y: auto;
}
.form-item {
margin-bottom: 24rpx;
}
.form-label {
font-size: 28rpx;
color: #333;
margin-bottom: 12rpx;
}
.form-input {
width: 100%;
height: 80rpx;
border: 2rpx solid #E5E5E5;
border-radius: 12rpx;
padding: 0 24rpx;
font-size: 28rpx;
box-sizing: border-box;
}
.form-select {
display: flex;
align-items: center;
line-height: 80rpx;
}
.popup-footer {
display: flex;
justify-content: center;
gap: 30rpx;
margin-top: 40rpx;
}
.btn-cancel {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border: 2rpx solid #2667E9;
border-radius: 40rpx;
background: #fff;
color: #2667E9;
font-size: 30rpx;
}
.btn-confirm {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
color: #fff;
font-size: 30rpx;
}
</style>

View File

@@ -0,0 +1,24 @@
<template>
<view class="padding page">
<view class="padding bg-white">
<view class="flex justify-between padding-bottom solid-bottom">
<view>修改登录密码</view>
<view class="lg text-gray cuIcon-right"></view>
</view>
<view class="flex justify-between padding-top padding-bottom solid-bottom">
<view>注销账户</view>
<view class="lg text-gray cuIcon-right"></view>
</view>
</view>
</view>
</template>
<script setup>
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
</style>

View File

@@ -0,0 +1,200 @@
<template>
<view class="page">
<view class="padding bg-white">
<!-- 头像 -->
<view class="flex justify-between align-center padding-tb solid-bottom" @click="chooseAvatar">
<view class="text-black">头像</view>
<view class="flex align-center">
<image class="avatar" :src="userInfo.avatar" mode="aspectFill"></image>
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
</view>
</view>
<!-- 昵称 -->
<view class="flex justify-between align-center padding-tb solid-bottom">
<view class="text-black label-text">昵称</view>
<view class="flex align-center flex-sub justify-end">
<input class="input-right" v-model="userInfo.nickname" placeholder="请输入昵称" />
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
</view>
</view>
<!-- 用户名 -->
<view class="flex justify-between align-center padding-tb solid-bottom">
<view class="text-black label-text">用户名</view>
<view class="flex align-center">
<text class="text-black">{{ userInfo.username }}</text>
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
</view>
</view>
<!-- 个性签名 -->
<view class="flex justify-between align-center padding-tb solid-bottom">
<view class="text-black label-text">个性签名</view>
<view class="flex align-center flex-sub justify-end">
<input class="input-right" v-model="userInfo.signature" placeholder="请输入个性签名" />
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
</view>
</view>
<!-- 性别 -->
<view class="flex justify-between align-center padding-tb solid-bottom">
<view class="text-black">性别</view>
<view class="flex align-center">
<view class="gender-switch">
<view
class="gender-item"
:class="{ 'gender-active': userInfo.gender === 1, 'gender-male': userInfo.gender === 1 }"
@click="userInfo.gender = 1"
>
<text class="cuIcon-male"></text>
</view>
<view
class="gender-item"
:class="{ 'gender-active': userInfo.gender === 2, 'gender-female': userInfo.gender === 2 }"
@click="userInfo.gender = 2"
>
<text class="cuIcon-female"></text>
</view>
</view>
</view>
</view>
<!-- 日期选择 -->
<view class="flex justify-between align-center padding-tb solid-bottom" @click="showDatePicker = true">
<view class="text-black">日期选择</view>
<view class="flex align-center">
<text class="text-black">{{ userInfo.birthday || '请选择日期' }}</text>
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
</view>
</view>
<up-calendar
:show="showDatePicker"
mode="single"
@confirm="confirmDate"
@close="showDatePicker = false"
></up-calendar>
<button class="bg-blue round margin-top-xl" @click="handleSave">保存</button>
<button class="round line-blue margin-top" @click="handleLogout">退出登录</button>
</view>
</view>
</template>
<script setup>
import { ref, reactive } from 'vue'
const showDatePicker = ref(false);
const userInfo = reactive({
avatar: 'https://ossweb-img.qq.com/images/lol/web201310/skin/big81005.jpg',
nickname: '希缝弗斯',
username: '17374339800',
signature: '',
gender: 1, // 1-男 2-女
birthday: '2025-10-09'
});
// 选择头像
const chooseAvatar = () => {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: (res) => {
userInfo.avatar = res.tempFilePaths[0];
}
});
};
// 日期选择确认
const confirmDate = (e) => {
userInfo.birthday = e[0];
showDatePicker.value = false;
};
// 保存
const handleSave = () => {
uni.showToast({ title: '保存成功', icon: 'success' });
};
// 退出登录
const handleLogout = () => {
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
uni.reLaunch({ url: '/pages/login/login' });
}
}
});
};
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #f5f5f5;
}
.avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
}
.label-text {
flex-shrink: 0;
margin-right: 20rpx;
}
.input-right {
text-align: right;
font-size: 28rpx;
color: #333;
}
.padding-tb {
padding: 30rpx 0;
}
.gender-switch {
display: flex;
align-items: center;
background: #f0f0f0;
border-radius: 40rpx;
padding: 4rpx;
}
.gender-item {
width: 60rpx;
height: 60rpx;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #999;
transition: all 0.3s;
}
.gender-active {
color: #fff;
}
.gender-male {
background: #2667E9;
}
.gender-female {
background: #ff6b81;
}
.line-blue {
border: 1rpx solid #2667E9;
color: #2667E9;
background: #fff;
}
</style>

View File

@@ -0,0 +1,18 @@
<template>
<view>
<view class="justify-around flex margin-top-xl">
<view><image src="/static/my/Customer service.png" style="width: 100rpx;height: 100rpx;"></image></view>
<view><image src="/static/my/Phone.png" style="width: 100rpx;height: 100rpx;"></image></view>
</view>
<view class="margin-top-xl flex text-gray text-center justify-center">
<view>工作时间</view>
<view>09:00-22:00</view>
</view>
</view>
</template>
<script>
</script>
<style>
</style>

113
pages/personalcenter/my.vue Normal file
View File

@@ -0,0 +1,113 @@
<template>
<view class="title">
<view class="padding">
<view class="text-center">我的</view>
<view class="flex justify-around" style="padding-top:60rpx;" >
<view class="flex">
<view class="cu-avatar xl round margin-left" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg);"></view>
<view>
<view>测试</view>
<view>17374339800</view>
</view>
</view>
<button class="bg-blue round cu-btn">编辑资料</button>
</view>
</view>
</view>
<view class="padding page">
<view class="padding bg-white radius">
<view class="flex justify-between padding-bottom solid-bottom">
<view class="flex " @click="Helpcenter()">
<image src="/static/my/Helpcenter.png" style="width:40rpx;height: 40rpx;"></image>
<view class="margin-left">帮助中心</view>
</view>
<view class="lg text-gray cuIcon-right"></view>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view class="flex">
<image src="/static/my/CustomerService.png" style="width:40rpx;height: 40rpx;"></image>
<view class="margin-left">智能客服</view>
</view>
<view class="lg text-gray cuIcon-right"></view>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view class="flex" @click="Account()">
<image src="/static/my/Account.png" style="width:40rpx;height: 40rpx;"></image>
<view class="margin-left">账号安全</view>
</view>
<view class="lg text-gray cuIcon-right"></view>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view class="flex" @click="notification()">
<image src="/static/my/Notification.png" style="width:40rpx;height: 40rpx;"></image>
<view class="margin-left">新消息通知</view>
</view>
<view class="lg text-gray cuIcon-right"></view>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view class="flex">
<image src="/static/my/Delete.png" style="width:40rpx;height: 40rpx;"></image>
<view class="margin-left">清除缓存</view>
</view>
<view class="lg text-gray cuIcon-right"></view>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view class="flex" @click="Settings()">
<image src="/static/my/Settings.png" style="width:40rpx;height: 40rpx;"></image>
<view class="margin-left">通用设置</view>
</view>
<view class="lg text-gray cuIcon-right"></view>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view class="flex">
<image src="/static/my/Helpcenter.png" style="width:40rpx;height: 40rpx;"></image>
<view class="margin-left">关于</view>
</view>
<view class="lg text-gray cuIcon-right"></view>
</view>
</view>
<button class=" bg-blue round margin-top-xl ">退出登录</button>
</view>
</template>
<script setup>
import { ref } from 'vue'
//帮助中心
const Helpcenter = () => {
uni.navigateTo({
url:'/pages/personalcenter/helpcenter'
})
}
//新消息通知
const notification = () => {
uni.navigateTo({
url:'/pages/personalcenter/notification'
})
}
//通用设置
const Settings = () => {
uni.navigateTo({
url:'/pages/personalcenter/settings'
})
}
//账号安全
const Account = () => {
uni.navigateTo({
url:'/pages/personalcenter/account'
})
}
</script>
<style lang="scss" scoped>
.page {
// min-height: 100vh;
background: #EBF2FC;
}
.title {
height: 516rpx;
background: radial-gradient( 0% 0% at 78% 8%, #2667E9 0%, #FDFDFD 100%, #719BF0 100%);
}
</style>

View File

@@ -0,0 +1,35 @@
<template>
<view class="page padding">
<view class="padding bg-white radius">
<view class="flex justify-between padding-bottom solid-bottom">
<view>横幅消息通知</view>
<up-switch v-model="value" activeColor="#07C160" @change="change" ></up-switch>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view>系统声音</view>
<up-switch v-model="value" activeColor="#07C160" @change="change"></up-switch>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view>系统震动</view>
<up-switch v-model="value" activeColor="#07C160" @change="change"></up-switch>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const value = ref(false)
const change = (e) => {
console.log('change', e);
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
</style>

View File

@@ -0,0 +1,35 @@
<template>
<view class="page padding">
<view class="padding bg-white radius">
<view class="flex justify-between padding-bottom solid-bottom">
<view>截屏后提示</view>
<up-switch v-model="value" activeColor="#07C160" @change="change" ></up-switch>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view>开启屏幕旋转</view>
<up-switch v-model="value" activeColor="#07C160" @change="change"></up-switch>
</view>
<view class="flex justify-between padding-bottom padding-top solid-bottom">
<view>获取地理位置</view>
<up-switch v-model="value" activeColor="#07C160" @change="change"></up-switch>
</view>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
const value = ref(false)
const change = (e) => {
console.log('change', e);
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
</style>

View File

@@ -0,0 +1,125 @@
<template>
<view class="page padding">
<view class="padding bg-white radius">
<view class="text-bold">{{ planData?.name || '加载中...' }}</view>
<view class="flex margin-top">
<view class="border-border margin-right-xs">任务ID: {{ planData?.taskId }}</view>
<view class="border-border">检查点: {{ planData?.checkPointId }}</view>
</view>
<view class="flex text-gray margin-top">
<view>状态</view>
<view>{{ planData?.status === 1 ? '进行中' : '已完成' }}</view>
</view>
<view class="flex margin-top align-center">
<view>完成进度</view>
<view class="flex align-center margin-left-sm">
<view class="cu-progress round">
<view class="bg-green" :style="{ width: progressPercent + '%' }"></view>
</view>
<text class="margin-left-sm">{{ planData?.currentIndex || 0 }}/{{ planData?.totalCount || 0 }}</text>
</view>
</view>
</view>
<view class="padding bg-white radius margin-top" >
<view class="text-bold">检查内容</view>
<view class="bg-gray padding radius">
<rich-text :nodes="planData?.point || ''"></rich-text>
</view>
</view>
<view class="padding bg-white radius margin-top">
<view class="text-bold">检查结果</view>
<view class="bg-gray padding radius">
{{ planData?.result || '暂无结果' }}
</view>
</view>
<view class="padding bg-white radius margin-top">
<view class="text-bold">备注</view>
<view class="bg-gray padding radius">
{{ planData?.remark || '暂无备注' }}
</view>
</view>
<view class="padding bg-white radius margin-top" v-if="planData?.isLast === false">
<view class="text-gray text-sm text-center">还有更多检查项</view>
</view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import { onLoad } from '@dcloudio/uni-app';
import { enterCheckPlan, getCheckTaskDetail } from '@/request/api.js';
const loading = ref(true);
const planData = ref(null);
// 计算进度百分比
const progressPercent = computed(() => {
if (!planData.value || !planData.value.totalCount) return 0;
return Math.round((planData.value.currentIndex / planData.value.totalCount) * 100);
});
// 先调用 start 接口获取 taskId再获取详情
const fetchTaskDetail = async (oneTableId) => {
try {
// 第一步:调用 start 接口获取 taskId
const startRes = await enterCheckPlan(oneTableId);
if (startRes.code === 0 && startRes.data) {
const taskId = startRes.data.taskId;
// 第二步:用 taskId 获取任务详情
const detailRes = await getCheckTaskDetail(taskId);
if (detailRes.code === 0 && detailRes.data) {
planData.value = detailRes.data;
loading.value = false;
}
}
} catch (error) {
console.error('获取任务详情失败:', error);
} finally {
loading.value = false;
}
};
onLoad((options) => {
if (options.id) {
fetchTaskDetail(options.id);
}
});
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #EBF2FC;
}
.cu-progress {
width: 300rpx;
height: 20rpx;
background: #ebeef5;
border-radius: 100rpx;
overflow: hidden;
view {
height: 100%;
border-radius: 100rpx;
transition: width 0.3s ease;
}
}
.bg-green {
background: #2667E9;
}
.border-border {
padding: 10rpx;
background: #EEF3FF;
border-radius: 4rpx 4rpx 4rpx 4rpx;
border: 2rpx solid #AAC5FC;
text-align: center;
justify-content: center;
align-items: center;
display: flex;
font-size: 28rpx;
color: #2667E9;
}
</style>