基本功能都已完成
This commit is contained in:
@@ -1,23 +1,60 @@
|
||||
<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>
|
||||
<!-- 证照列表 -->
|
||||
<view class="license-list" v-if="licenseList.length > 0">
|
||||
<view class="license-item" v-for="(item, index) in licenseList" :key="item.id">
|
||||
<view class="license-info">
|
||||
<view class="license-header">
|
||||
<text class="license-type">{{ item.type || '未知类型' }}</text>
|
||||
<view class="license-actions">
|
||||
<text class="action-btn text-blue" @click="handleEdit(item)">编辑</text>
|
||||
<text class="action-btn text-red" @click="handleDelete(item)">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="license-detail">
|
||||
<view class="detail-row">
|
||||
<text class="label">证件编号:</text>
|
||||
<text class="value">{{ item.code || '-' }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="label">有效期:</text>
|
||||
<text class="value">{{ item.startDate || '-' }} 至 {{ item.endDate || '-' }}</text>
|
||||
</view>
|
||||
<view class="detail-row">
|
||||
<text class="label">法人:</text>
|
||||
<text class="value">{{ item.legalPerson || '-' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="license-photo" v-if="item.photo">
|
||||
<image :src="getImageUrl(item.photo)" mode="aspectFill" @click="previewImage(item.photo)"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 新增证件照弹窗 -->
|
||||
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" v-else>
|
||||
<text class="text-gray text-center">暂无证照记录</text>
|
||||
</view>
|
||||
|
||||
<!-- 新增按钮 -->
|
||||
<button class="add-btn cuIcon-add bg-blue round" @click="openAddPopup">+ 新增</button>
|
||||
|
||||
<!-- 新增/编辑证照弹窗 -->
|
||||
<u-popup :show="showAddPopup" mode="center" round="20" @close="closePopup">
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<view class="popup-title text-bold">新增证照</view>
|
||||
<view class="popup-close" @click="showAddPopup = false">×</view>
|
||||
<view class="popup-title text-bold">{{ isEdit ? '编辑证照' : '新增证照' }}</view>
|
||||
<view class="popup-close" @click="closePopup">×</view>
|
||||
</view>
|
||||
|
||||
<view class="popup-body">
|
||||
<scroll-view class="popup-body" scroll-y>
|
||||
<!-- 部门 -->
|
||||
<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 :class="formData.enterpriseName ? '' : 'text-gray'">
|
||||
{{ formData.enterpriseName || '请选择部门' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -25,49 +62,60 @@
|
||||
<!-- 证件类型 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">证件类型</view>
|
||||
<input class="form-input" v-model="formData.idType" placeholder="请输入证件类型" />
|
||||
<input class="form-input" v-model="formData.type" placeholder="请输入证件类型" />
|
||||
</view>
|
||||
|
||||
<!-- 证件编号 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">证件编号</view>
|
||||
<input class="form-input" v-model="formData.number" placeholder="请输入证件编号" />
|
||||
<input class="form-input" v-model="formData.code" 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 || '请选择结束时间' }}
|
||||
<view class="form-input form-select" @click="openDatePicker('start')">
|
||||
<text :class="formData.startDate ? '' : 'text-gray'">
|
||||
{{ formData.startDate || '请选择开始日期' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 上传证件照 -->
|
||||
<!-- 结束日期 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">结束日期</view>
|
||||
<view class="form-input form-select" @click="openDatePicker('end')">
|
||||
<text :class="formData.endDate ? '' : 'text-gray'">
|
||||
{{ formData.endDate || '请选择结束日期' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 法人 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">法人</view>
|
||||
<input class="form-input" v-model="formData.legalPerson" placeholder="请输入法人" />
|
||||
</view>
|
||||
|
||||
<!-- 封面图片 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">封面图片</view>
|
||||
<view class="upload-box" @click="chooseImage">
|
||||
<view class="upload-add" v-if="!formData.image">
|
||||
<view class="upload-add" v-if="!formData.photoPreview">
|
||||
<text class="upload-icon">+</text>
|
||||
<text class="upload-text">上传照片</text>
|
||||
</view>
|
||||
<image v-else :src="formData.image" mode="aspectFill" class="upload-img"></image>
|
||||
<view class="upload-preview" v-else>
|
||||
<image :src="formData.photoPreview" mode="aspectFill" class="upload-img"></image>
|
||||
<view class="upload-delete" @click.stop="removeImage">×</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="popup-footer">
|
||||
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
|
||||
<button class="btn-confirm bg-blue" @click="handleSubmit">确定</button>
|
||||
<button class="btn-cancel" @click="closePopup">取消</button>
|
||||
<button class="btn-confirm bg-blue" @click="handleSubmit" :loading="submitting">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
@@ -75,9 +123,11 @@
|
||||
<!-- 日期选择器 -->
|
||||
<u-datetime-picker
|
||||
:show="showDatePicker"
|
||||
v-model="datePickerValue"
|
||||
mode="date"
|
||||
@confirm="onDateConfirm"
|
||||
@cancel="showDatePicker = false"
|
||||
@cancel="onDateCancel"
|
||||
@close="onDateCancel"
|
||||
></u-datetime-picker>
|
||||
|
||||
<!-- 选择部门弹窗 -->
|
||||
@@ -88,60 +138,289 @@
|
||||
<view class="popup-close" @click="showDeptPopup = false">×</view>
|
||||
</view>
|
||||
|
||||
<view class="dept-list">
|
||||
<scroll-view class="dept-list" scroll-y v-if="deptList.length > 0">
|
||||
<view
|
||||
class="dept-item"
|
||||
v-for="(item, index) in deptList"
|
||||
:key="index"
|
||||
v-for="item in deptList"
|
||||
:key="item.id"
|
||||
@click="selectedDept = item"
|
||||
>
|
||||
<view class="dept-checkbox" :class="{ 'dept-checkbox-active': selectedDept === item }">
|
||||
<text v-if="selectedDept === item">✓</text>
|
||||
<view class="dept-checkbox" :class="{ 'dept-checkbox-active': selectedDept && selectedDept.id === item.id }">
|
||||
<text v-if="selectedDept && selectedDept.id === item.id">✓</text>
|
||||
</view>
|
||||
<text class="dept-name">{{ item }}</text>
|
||||
<text class="dept-name">{{ item.name }}</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="text-gray text-center padding" v-else>
|
||||
暂无部门数据
|
||||
</view>
|
||||
|
||||
<button class="btn-dept-confirm bg-blue" @click="confirmDept">确定</button>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
<!-- 删除确认弹窗 -->
|
||||
<u-modal
|
||||
:show="showDeleteModal"
|
||||
title="确认删除"
|
||||
content="确定要删除这条证照记录吗?"
|
||||
showCancelButton
|
||||
@confirm="confirmDelete"
|
||||
@cancel="showDeleteModal = false"
|
||||
></u-modal>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import {
|
||||
getLicenseEnterpriseSelect,
|
||||
getLicenseList,
|
||||
getLicenseDetail,
|
||||
addLicense,
|
||||
updateLicense,
|
||||
deleteLicense
|
||||
} from '@/request/three_one_api/license.js';
|
||||
import { baseUrl, getToken } from '@/request/request.js';
|
||||
|
||||
const hasData = ref(false);
|
||||
// 证照列表
|
||||
const licenseList = ref([]);
|
||||
// 部门列表
|
||||
const deptList = ref([]);
|
||||
const selectedDept = ref(null);
|
||||
|
||||
// 弹窗控制
|
||||
const showAddPopup = ref(false);
|
||||
const showDatePicker = ref(false);
|
||||
const showDeptPopup = ref(false);
|
||||
const showDeleteModal = ref(false);
|
||||
|
||||
// 部门列表
|
||||
const deptList = ref([
|
||||
'湘西自治州和谐网络科技有限公司',
|
||||
'湘西自治州和谐云大数据科技有限公司',
|
||||
'湘西网络有限公司'
|
||||
]);
|
||||
const selectedDept = ref('');
|
||||
// 编辑状态
|
||||
const isEdit = ref(false);
|
||||
const currentEditId = ref(null);
|
||||
const currentDeleteItem = ref(null);
|
||||
const submitting = ref(false);
|
||||
|
||||
// 日期选择类型
|
||||
const datePickerType = ref('start');
|
||||
// 日期选择器的值(时间戳)
|
||||
const datePickerValue = ref(Date.now());
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
dept: '',
|
||||
enterpriseId: '',
|
||||
enterpriseName: '',
|
||||
type: '',
|
||||
idType: '',
|
||||
number: '',
|
||||
code: '',
|
||||
startDate: '',
|
||||
expireDate: '',
|
||||
image: ''
|
||||
endDate: '',
|
||||
legalPerson: '',
|
||||
photo: '',
|
||||
photoPreview: ''
|
||||
});
|
||||
|
||||
// 页面加载
|
||||
onMounted(() => {
|
||||
loadLicenseList();
|
||||
loadDeptList();
|
||||
});
|
||||
|
||||
// 获取图片完整URL
|
||||
const getImageUrl = (path) => {
|
||||
if (!path) return '';
|
||||
if (path.startsWith('http')) return path;
|
||||
return baseUrl + path;
|
||||
};
|
||||
|
||||
// 预览图片
|
||||
const previewImage = (path) => {
|
||||
uni.previewImage({
|
||||
urls: [getImageUrl(path)]
|
||||
});
|
||||
};
|
||||
|
||||
// 加载证照列表
|
||||
const loadLicenseList = async () => {
|
||||
try {
|
||||
const res = await getLicenseList();
|
||||
if (res.code === 0) {
|
||||
licenseList.value = res.data.records || [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取证照列表失败:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// 加载部门列表
|
||||
const loadDeptList = async () => {
|
||||
try {
|
||||
const res = await getLicenseEnterpriseSelect();
|
||||
if (res.code === 0) {
|
||||
deptList.value = res.data || [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取部门列表失败:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// 打开新增弹窗
|
||||
const openAddPopup = () => {
|
||||
resetForm();
|
||||
isEdit.value = false;
|
||||
currentEditId.value = null;
|
||||
showAddPopup.value = true;
|
||||
};
|
||||
|
||||
// 编辑证照
|
||||
const handleEdit = async (item) => {
|
||||
try {
|
||||
// 先获取详情
|
||||
const res = await getLicenseDetail({ id: item.id });
|
||||
if (res.code === 0) {
|
||||
const detail = res.data;
|
||||
isEdit.value = true;
|
||||
currentEditId.value = item.id;
|
||||
|
||||
// 填充表单数据
|
||||
formData.enterpriseId = detail.enterpriseId || '';
|
||||
formData.type = detail.type || '';
|
||||
formData.code = detail.code || '';
|
||||
formData.startDate = detail.startDate || '';
|
||||
formData.endDate = detail.endDate || '';
|
||||
formData.legalPerson = detail.legalPerson || '';
|
||||
formData.photo = detail.photo || '';
|
||||
formData.photoPreview = detail.photo ? getImageUrl(detail.photo) : '';
|
||||
|
||||
// 设置部门名称
|
||||
const dept = deptList.value.find(d => d.id === detail.enterpriseId);
|
||||
formData.enterpriseName = dept ? dept.name : '';
|
||||
selectedDept.value = dept || null;
|
||||
|
||||
showAddPopup.value = true;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取证照详情失败:', err);
|
||||
uni.showToast({ title: '获取详情失败', icon: 'none' });
|
||||
}
|
||||
};
|
||||
|
||||
// 删除证照
|
||||
const handleDelete = (item) => {
|
||||
currentDeleteItem.value = item;
|
||||
showDeleteModal.value = true;
|
||||
};
|
||||
|
||||
// 确认删除
|
||||
const confirmDelete = async () => {
|
||||
if (!currentDeleteItem.value) return;
|
||||
|
||||
try {
|
||||
const res = await deleteLicense({ id: currentDeleteItem.value.id });
|
||||
if (res.code === 0) {
|
||||
uni.showToast({ title: '删除成功', icon: 'success' });
|
||||
loadLicenseList();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('删除失败:', err);
|
||||
uni.showToast({ title: '删除失败', icon: 'none' });
|
||||
} finally {
|
||||
showDeleteModal.value = false;
|
||||
currentDeleteItem.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
// 关闭弹窗
|
||||
const closePopup = () => {
|
||||
showAddPopup.value = false;
|
||||
resetForm();
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
formData.enterpriseId = '';
|
||||
formData.enterpriseName = '';
|
||||
formData.type = '';
|
||||
formData.code = '';
|
||||
formData.startDate = '';
|
||||
formData.endDate = '';
|
||||
formData.legalPerson = '';
|
||||
formData.photo = '';
|
||||
formData.photoPreview = '';
|
||||
selectedDept.value = null;
|
||||
isEdit.value = false;
|
||||
currentEditId.value = null;
|
||||
};
|
||||
|
||||
// 确认选择部门
|
||||
const confirmDept = () => {
|
||||
if (selectedDept.value) {
|
||||
formData.dept = selectedDept.value;
|
||||
formData.enterpriseId = selectedDept.value.id;
|
||||
formData.enterpriseName = selectedDept.value.name;
|
||||
}
|
||||
showDeptPopup.value = false;
|
||||
};
|
||||
|
||||
// 打开日期选择器
|
||||
const openDatePicker = (type) => {
|
||||
datePickerType.value = type;
|
||||
|
||||
// 根据已有的日期设置选择器初始值
|
||||
let currentDate = '';
|
||||
if (type === 'start' && formData.startDate) {
|
||||
currentDate = formData.startDate;
|
||||
} else if (type === 'end' && formData.endDate) {
|
||||
currentDate = formData.endDate;
|
||||
}
|
||||
|
||||
// 如果有已选择的日期,转换为时间戳
|
||||
if (currentDate) {
|
||||
datePickerValue.value = new Date(currentDate).getTime();
|
||||
} else {
|
||||
datePickerValue.value = Date.now();
|
||||
}
|
||||
|
||||
showDatePicker.value = true;
|
||||
};
|
||||
|
||||
// 日期选择取消/关闭
|
||||
const onDateCancel = () => {
|
||||
showDatePicker.value = false;
|
||||
};
|
||||
|
||||
// 日期选择确认
|
||||
const onDateConfirm = (e) => {
|
||||
// 使用 v-model 绑定的 datePickerValue
|
||||
const timestamp = datePickerValue.value;
|
||||
|
||||
// 验证时间戳
|
||||
if (!timestamp || isNaN(timestamp)) {
|
||||
console.error('无效的日期值:', timestamp);
|
||||
showDatePicker.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const date = new Date(timestamp);
|
||||
|
||||
// 验证日期是否有效
|
||||
if (isNaN(date.getTime())) {
|
||||
console.error('无效的日期:', date);
|
||||
showDatePicker.value = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const dateStr = `${year}-${month}-${day}`;
|
||||
|
||||
if (datePickerType.value === 'start') {
|
||||
formData.startDate = dateStr;
|
||||
} else {
|
||||
formData.endDate = dateStr;
|
||||
}
|
||||
showDatePicker.value = false;
|
||||
};
|
||||
|
||||
// 选择图片
|
||||
const chooseImage = () => {
|
||||
uni.chooseImage({
|
||||
@@ -149,40 +428,102 @@ const chooseImage = () => {
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
formData.image = res.tempFilePaths[0];
|
||||
const tempFilePath = res.tempFilePaths[0];
|
||||
formData.photoPreview = tempFilePath;
|
||||
// 上传图片
|
||||
uploadImage(tempFilePath);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 日期选择确认
|
||||
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 uploadImage = (filePath) => {
|
||||
uni.showLoading({ title: '上传中...' });
|
||||
|
||||
uni.uploadFile({
|
||||
url: baseUrl + '/frontend/attachment/upload',
|
||||
filePath: filePath,
|
||||
name: 'file',
|
||||
header: {
|
||||
'Authorization': getToken()
|
||||
},
|
||||
success: (uploadRes) => {
|
||||
uni.hideLoading();
|
||||
try {
|
||||
const data = JSON.parse(uploadRes.data);
|
||||
if (data.code === 0 && data.data) {
|
||||
formData.photo = data.data.url || data.data;
|
||||
uni.showToast({ title: '上传成功', icon: 'success' });
|
||||
} else {
|
||||
uni.showToast({ title: data.msg || '上传失败', icon: 'none' });
|
||||
formData.photoPreview = '';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('解析上传结果失败:', e);
|
||||
uni.showToast({ title: '上传失败', icon: 'none' });
|
||||
formData.photoPreview = '';
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
console.error('上传失败:', err);
|
||||
uni.showToast({ title: '上传失败', icon: 'none' });
|
||||
formData.photoPreview = '';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 移除图片
|
||||
const removeImage = () => {
|
||||
formData.photo = '';
|
||||
formData.photoPreview = '';
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = () => {
|
||||
if (!formData.dept) {
|
||||
const handleSubmit = async () => {
|
||||
// 表单验证
|
||||
if (!formData.enterpriseId) {
|
||||
uni.showToast({ title: '请选择部门', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('提交数据:', formData);
|
||||
uni.showToast({ title: '新增成功', icon: 'success' });
|
||||
showAddPopup.value = false;
|
||||
submitting.value = true;
|
||||
|
||||
// 重置表单
|
||||
formData.dept = '';
|
||||
formData.type = '';
|
||||
formData.number = '';
|
||||
formData.startDate = '';
|
||||
formData.expireDate = '';
|
||||
formData.image = '';
|
||||
selectedDept.value = '';
|
||||
try {
|
||||
const submitData = {
|
||||
enterpriseId: formData.enterpriseId,
|
||||
type: formData.type,
|
||||
code: formData.code,
|
||||
startDate: formData.startDate,
|
||||
endDate: formData.endDate,
|
||||
legalPerson: formData.legalPerson,
|
||||
photo: formData.photo
|
||||
};
|
||||
|
||||
let res;
|
||||
if (isEdit.value) {
|
||||
// 编辑
|
||||
submitData.id = currentEditId.value;
|
||||
res = await updateLicense(submitData);
|
||||
} else {
|
||||
// 新增
|
||||
res = await addLicense(submitData);
|
||||
}
|
||||
|
||||
if (res.code === 0) {
|
||||
uni.showToast({
|
||||
title: isEdit.value ? '修改成功' : '新增成功',
|
||||
icon: 'success'
|
||||
});
|
||||
closePopup();
|
||||
loadLicenseList();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('提交失败:', err);
|
||||
uni.showToast({ title: '操作失败', icon: 'none' });
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -190,6 +531,96 @@ const handleSubmit = () => {
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
// 证照列表样式
|
||||
.license-list {
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.license-item {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.license-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.license-type {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.license-actions {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
font-size: 28rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
}
|
||||
|
||||
.license-detail {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.detail-row {
|
||||
display: flex;
|
||||
margin-bottom: 12rpx;
|
||||
font-size: 28rpx;
|
||||
|
||||
.label {
|
||||
color: #999;
|
||||
width: 160rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.license-photo {
|
||||
width: 200rpx;
|
||||
height: 150rpx;
|
||||
border-radius: 8rpx;
|
||||
overflow: hidden;
|
||||
|
||||
image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// 空状态
|
||||
.empty-state {
|
||||
padding: 200rpx 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// 新增按钮
|
||||
.add-btn {
|
||||
position: fixed;
|
||||
bottom: 40rpx;
|
||||
left: 30rpx;
|
||||
right: 30rpx;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
// 弹出框样式
|
||||
@@ -257,6 +688,7 @@ const handleSubmit = () => {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.upload-add {
|
||||
@@ -276,12 +708,33 @@ const handleSubmit = () => {
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.upload-preview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.upload-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.upload-delete {
|
||||
position: absolute;
|
||||
top: -16rpx;
|
||||
right: -16rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background: #ff4d4f;
|
||||
color: #fff;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
<template>
|
||||
<view class="page padding">
|
||||
<!-- 进度显示 -->
|
||||
<view class="progress-bar" v-if="checkData">
|
||||
<view class="progress-text">
|
||||
<text class="current-index">第 {{ checkData.currentIndex || 1 }} 个问题</text>
|
||||
<text class="total-count"> / 共 {{ checkData.totalCount || 1 }} 个</text>
|
||||
</view>
|
||||
<view class="progress-line">
|
||||
<view class="progress-inner" :style="{ width: progressPercent + '%' }"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="padding bg-white radius">
|
||||
<view class="text-bold">{{ checkData?.name || '加载中...' }}</view>
|
||||
<view class="margin-top">
|
||||
@@ -22,18 +33,169 @@
|
||||
</u-radio>
|
||||
</u-radio-group>
|
||||
</view>
|
||||
<view>
|
||||
|
||||
<!-- 异常时显示隐患信息区域 -->
|
||||
<view v-if="radiovalue1 === '异常'" class="hazard-section margin-top">
|
||||
<view class="hazard-tip">
|
||||
<text class="cuIcon-warn text-yellow margin-right-xs"></text>
|
||||
<text class="text-orange">检查结果为异常,需填写隐患信息</text>
|
||||
</view>
|
||||
|
||||
<!-- 未填写时显示按钮 -->
|
||||
<view v-if="!hasHazardData" class="hazard-btn" @click="openHazardPopup">
|
||||
<text class="text-blue">填写隐患信息</text>
|
||||
</view>
|
||||
|
||||
<!-- 已填写时显示卡片 -->
|
||||
<view v-else class="hazard-card">
|
||||
<view class="card-header">
|
||||
<view class="text-bold text-black">{{ hazardFormData.title }}</view>
|
||||
<view class="level-tag" :class="{
|
||||
'level-minor': hazardFormData.level === 0,
|
||||
'level-normal': hazardFormData.level === 1,
|
||||
'level-major': hazardFormData.level === 2
|
||||
}">{{ levelOptions[hazardFormData.level]?.title }}</view>
|
||||
</view>
|
||||
<view class="card-body">
|
||||
<view class="info-row">
|
||||
<text class="text-gray">隐患来源:</text>
|
||||
<text>{{ sourceOptions[hazardFormData.source]?.title || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="text-gray">隐患位置:</text>
|
||||
<text>{{ hazardAddress || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-row">
|
||||
<text class="text-gray">隐患描述:</text>
|
||||
<text class="description-text">{{ hazardFormData.description || '-' }}</text>
|
||||
</view>
|
||||
<view class="info-row" v-if="hazardFileList.length > 0">
|
||||
<text class="text-gray">附件:</text>
|
||||
<text>{{ hazardFileList.length }}个文件</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="card-footer">
|
||||
<button class="btn-edit" @click="editHazard">修改</button>
|
||||
<button class="btn-clear" @click="clearHazard">清除</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="margin-top">
|
||||
<up-textarea v-model="value1" placeholder="请输入备注信息" ></up-textarea>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<button class="bg-blue round margin-top-xl" @click="handleSubmit">提交</button>
|
||||
|
||||
<!-- 新增隐患弹窗 -->
|
||||
<u-popup :show="showHazardPopup" mode="center" round="20" @close="showHazardPopup = false">
|
||||
<view class="popup-content">
|
||||
<view class="popup-header">
|
||||
<view class="popup-title text-bold">填写隐患信息</view>
|
||||
<view class="popup-close" @click="showHazardPopup = false">×</view>
|
||||
</view>
|
||||
<scroll-view class="popup-body" scroll-y :style="{ height: '60vh' }">
|
||||
<view class="flex margin-bottom">
|
||||
<view class="text-gray">隐患图片/视频</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<up-upload :fileList="hazardFileList" @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="hazardFormData.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="hazardFormData.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>
|
||||
<up-choose v-model="hazardFormData.source" :options="sourceOptions" :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">
|
||||
<up-input class="address-input-wrapper" v-model="hazardAddress" placeholder="请输入地址" border="surround"></up-input>
|
||||
<button class="btn-address bg-blue" @tap.stop="chooseLocation">选择地址</button>
|
||||
</view>
|
||||
<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>
|
||||
<view class="select-trigger" @click="showAreaPicker = true">
|
||||
<view class="select-value" :class="{ 'placeholder': !selectedAreaName }">
|
||||
{{ selectedAreaName || '请选择隐患区域' }}
|
||||
</view>
|
||||
<text class="cuIcon-unfold"></text>
|
||||
</view>
|
||||
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">隐患描述</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<up-textarea v-model="hazardFormData.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="hazardFormData.tagIndex" :options="tagOptions"></up-choose>
|
||||
<view class="text-gray text-sm">可选择多个相关标签对隐患进行分类</view>
|
||||
</scroll-view>
|
||||
<view class="popup-footer">
|
||||
<button class="btn-cancel" @click="showHazardPopup = false">取消</button>
|
||||
<button class="btn-confirm bg-blue" @click="confirmHazard">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
<!-- 区域选择弹窗 -->
|
||||
<u-popup :show="showAreaPicker" mode="bottom" round="20" @close="showAreaPicker = false">
|
||||
<view class="picker-popup">
|
||||
<view class="picker-header">
|
||||
<view class="picker-cancel" @click="showAreaPicker = false">取消</view>
|
||||
<view class="picker-title">选择隐患区域</view>
|
||||
<view class="picker-confirm" @click="confirmAreaSelect">确定</view>
|
||||
</view>
|
||||
<scroll-view class="picker-body" scroll-y>
|
||||
<view
|
||||
v-for="item in areaList"
|
||||
:key="item.id"
|
||||
class="picker-item"
|
||||
:class="{ 'picker-item-active': tempAreaId === item.id }"
|
||||
@click="tempAreaId = item.id"
|
||||
>
|
||||
<view class="flex align-center">
|
||||
<view class="area-color-dot" :style="{ backgroundColor: item.color }"></view>
|
||||
<text>{{ item.name }}</text>
|
||||
</view>
|
||||
<text v-if="tempAreaId === item.id" class="cuIcon-check text-blue"></text>
|
||||
</view>
|
||||
<view v-if="areaList.length === 0" class="text-gray text-center padding">
|
||||
暂无区域数据
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { enterCheckPlan,submitCheckResult } from '@/request/api.js';
|
||||
import { enterCheckPlan, submitCheckResult, addHiddenDanger, getHiddenDangerLabelList } from '@/request/api.js';
|
||||
import { baseUrl, getToken } from '@/request/request.js';
|
||||
import { getAreaList } from '@/request/three_one_api/area.js';
|
||||
|
||||
// 页面参数
|
||||
const oneTableId = ref('');
|
||||
@@ -63,16 +225,246 @@
|
||||
const radiovalue1 = ref('');
|
||||
|
||||
const groupChange = (n) => {
|
||||
console.log('groupChange', n);
|
||||
console.log('groupChange', n);
|
||||
// 切换到非异常时清除隐患数据
|
||||
if (n !== '异常') {
|
||||
clearHazard();
|
||||
}
|
||||
};
|
||||
|
||||
const radioChange = (n) => {
|
||||
console.log('radioChange', n);
|
||||
console.log('radioChange', n);
|
||||
};
|
||||
|
||||
// 备注
|
||||
const value1 = ref('');
|
||||
|
||||
// ==================== 隐患信息相关 ====================
|
||||
|
||||
// 弹窗控制
|
||||
const showHazardPopup = ref(false);
|
||||
|
||||
// 隐患表单数据(暂存)
|
||||
const hazardFormData = reactive({
|
||||
title: '',
|
||||
level: 0,
|
||||
source: 0,
|
||||
description: '',
|
||||
tagIndex: 0
|
||||
});
|
||||
|
||||
// 隐患地址和经纬度
|
||||
const hazardAddress = ref('');
|
||||
const hazardLng = ref(0);
|
||||
const hazardLat = ref(0);
|
||||
|
||||
// 区域选择相关
|
||||
const showAreaPicker = ref(false);
|
||||
const areaList = ref([]);
|
||||
const selectedAreaId = ref('');
|
||||
const selectedAreaName = ref('');
|
||||
const tempAreaId = ref('');
|
||||
|
||||
// 获取区域列表
|
||||
const fetchAreaList = async () => {
|
||||
try {
|
||||
const res = await getAreaList();
|
||||
if (res.code === 0 && res.data && res.data.records) {
|
||||
areaList.value = res.data.records;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取区域列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 确认区域选择
|
||||
const confirmAreaSelect = () => {
|
||||
if (tempAreaId.value) {
|
||||
selectedAreaId.value = tempAreaId.value;
|
||||
const selected = areaList.value.find(item => item.id === tempAreaId.value);
|
||||
selectedAreaName.value = selected ? selected.name : '';
|
||||
}
|
||||
showAreaPicker.value = false;
|
||||
};
|
||||
|
||||
// 隐患附件列表
|
||||
const hazardFileList = ref([]);
|
||||
|
||||
// 是否已填写隐患数据
|
||||
const hasHazardData = computed(() => {
|
||||
return hazardFormData.title && hazardFileList.value.length > 0;
|
||||
});
|
||||
|
||||
// 进度百分比
|
||||
const progressPercent = computed(() => {
|
||||
if (!checkData.value) return 0;
|
||||
const current = checkData.value.currentIndex || 1;
|
||||
const total = checkData.value.totalCount || 1;
|
||||
return Math.round((current / total) * 100);
|
||||
});
|
||||
|
||||
// 隐患等级选项
|
||||
const levelOptions = ref([
|
||||
{ id: 1, title: '轻微隐患' },
|
||||
{ id: 2, title: '一般隐患' },
|
||||
{ id: 3, title: '重大隐患' }
|
||||
]);
|
||||
|
||||
// 隐患来源选项
|
||||
const sourceOptions = ref([
|
||||
{ id: 1, title: '随手拍' },
|
||||
{ id: 2, title: '企业自查' },
|
||||
{ id: 3, title: '行业互查' },
|
||||
{ id: 4, title: '专家诊查' }
|
||||
]);
|
||||
|
||||
// 隐患标签选项
|
||||
const tagOptions = ref([]);
|
||||
|
||||
// 获取隐患标签列表
|
||||
const fetchTagOptions = async () => {
|
||||
try {
|
||||
const res = await getHiddenDangerLabelList();
|
||||
if (res.code === 0) {
|
||||
tagOptions.value = res.data.map(item => ({
|
||||
id: item.id,
|
||||
title: item.name
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取标签列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 打开隐患信息弹窗
|
||||
const openHazardPopup = () => {
|
||||
showHazardPopup.value = true;
|
||||
};
|
||||
|
||||
// 编辑隐患信息(回显数据)
|
||||
const editHazard = () => {
|
||||
showHazardPopup.value = true;
|
||||
};
|
||||
|
||||
// 清除隐患信息
|
||||
const clearHazard = () => {
|
||||
hazardFormData.title = '';
|
||||
hazardFormData.level = 0;
|
||||
hazardFormData.source = 0;
|
||||
hazardFormData.description = '';
|
||||
hazardFormData.tagIndex = 0;
|
||||
hazardAddress.value = '';
|
||||
hazardLng.value = 0;
|
||||
hazardLat.value = 0;
|
||||
hazardFileList.value = [];
|
||||
selectedAreaId.value = '';
|
||||
selectedAreaName.value = '';
|
||||
};
|
||||
|
||||
// 确认隐患信息(只暂存,不调接口)
|
||||
const confirmHazard = () => {
|
||||
// 表单验证
|
||||
if (hazardFileList.value.length === 0) {
|
||||
uni.showToast({ title: '请上传隐患图片/视频', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!hazardFormData.title) {
|
||||
uni.showToast({ title: '请输入隐患标题', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!hazardAddress.value) {
|
||||
uni.showToast({ title: '请输入隐患位置', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!hazardFormData.description) {
|
||||
uni.showToast({ title: '请输入隐患描述', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证通过,关闭弹窗(数据已在 reactive 中暂存)
|
||||
showHazardPopup.value = false;
|
||||
uni.showToast({ title: '隐患信息已暂存', icon: 'success' });
|
||||
};
|
||||
|
||||
// 选择地址
|
||||
const chooseLocation = () => {
|
||||
showHazardPopup.value = false;
|
||||
|
||||
setTimeout(() => {
|
||||
uni.chooseLocation({
|
||||
success: (res) => {
|
||||
hazardAddress.value = res.address + (res.name ? `(${res.name})` : '');
|
||||
hazardLng.value = res.longitude;
|
||||
hazardLat.value = res.latitude;
|
||||
showHazardPopup.value = true;
|
||||
},
|
||||
fail: (err) => {
|
||||
showHazardPopup.value = true;
|
||||
if (err.errMsg && err.errMsg.indexOf('cancel') === -1) {
|
||||
uni.showToast({ title: '选择位置失败', icon: 'none' });
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
};
|
||||
|
||||
// 删除图片
|
||||
const deletePic = (event) => {
|
||||
hazardFileList.value.splice(event.index, 1);
|
||||
};
|
||||
|
||||
// 新增图片
|
||||
const afterRead = async (event) => {
|
||||
let lists = [].concat(event.file);
|
||||
let fileListLen = hazardFileList.value.length;
|
||||
lists.map((item) => {
|
||||
hazardFileList.value.push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中',
|
||||
});
|
||||
});
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url);
|
||||
let item = hazardFileList.value[fileListLen];
|
||||
hazardFileList.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': getToken()
|
||||
},
|
||||
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 () => {
|
||||
// 验证是否选择了检查结果
|
||||
@@ -90,32 +482,121 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果选择异常,验证是否填写了隐患信息
|
||||
if (radiovalue1.value === '异常' && !hasHazardData.value) {
|
||||
uni.showToast({ title: '请填写隐患信息', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const params = {
|
||||
uni.showLoading({ title: '提交中...' });
|
||||
|
||||
// 如果选择异常,先调用新增隐患接口
|
||||
if (radiovalue1.value === '异常' && hasHazardData.value) {
|
||||
// 构建附件列表
|
||||
const attachments = hazardFileList.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
|
||||
};
|
||||
});
|
||||
|
||||
// 获取隐患标签ID
|
||||
const selectedTag = tagOptions.value[hazardFormData.tagIndex];
|
||||
const tagId = selectedTag ? selectedTag.id : null;
|
||||
|
||||
// 构建隐患参数
|
||||
const hazardParams = {
|
||||
taskId: checkData.value?.taskId,
|
||||
checkPointId: checkData.value?.checkPointId,
|
||||
title: hazardFormData.title,
|
||||
level: hazardFormData.level + 1,
|
||||
lng: hazardLng.value || 0,
|
||||
lat: hazardLat.value || 0,
|
||||
address: hazardAddress.value || '',
|
||||
areaId: selectedAreaId.value || null, // 隐患区域ID
|
||||
description: hazardFormData.description || '',
|
||||
source: sourceOptions.value[hazardFormData.source]?.title || '',
|
||||
tagId: tagId,
|
||||
attachments: attachments
|
||||
};
|
||||
|
||||
console.log('隐患参数:', hazardParams);
|
||||
|
||||
// 调用新增隐患接口
|
||||
const hazardRes = await addHiddenDanger(hazardParams);
|
||||
if (hazardRes.code !== 0) {
|
||||
uni.hideLoading();
|
||||
uni.showToast({ title: hazardRes.msg || '新增隐患失败', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
console.log('新增隐患成功');
|
||||
}
|
||||
|
||||
// 调用提交巡检结果接口
|
||||
const submitParams = {
|
||||
taskId: checkData.value?.taskId,
|
||||
result: resultValue,
|
||||
remark: value1.value
|
||||
};
|
||||
console.log('提交参数:', params);
|
||||
console.log('提交参数:', submitParams);
|
||||
|
||||
const res = await submitCheckResult(params);
|
||||
console.log('提交结果:', res);
|
||||
const res = await submitCheckResult(submitParams);
|
||||
uni.hideLoading();
|
||||
|
||||
if (res.code === 0) {
|
||||
uni.showToast({ title: '提交成功', icon: 'success' });
|
||||
// 提交成功后可以返回上一页或刷新数据
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
// 判断是否全部完成
|
||||
if (res.data && res.data.allFinished === true) {
|
||||
// 全部完成,退出页面
|
||||
uni.showToast({ title: '全部检查已完成', icon: 'success' });
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
} else if (res.data && res.data.nextTask) {
|
||||
// 还有下一个问题,更新数据继续
|
||||
uni.showToast({ title: '提交成功,进入下一题', icon: 'success' });
|
||||
|
||||
// 重置表单状态
|
||||
resetFormState();
|
||||
|
||||
// 更新为下一个检查项的数据
|
||||
checkData.value = res.data.nextTask;
|
||||
} else {
|
||||
// 兜底处理:没有 allFinished 也没有 nextTask,直接返回
|
||||
uni.showToast({ title: '提交成功', icon: 'success' });
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '提交失败', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
console.error('提交失败:', error);
|
||||
uni.showToast({ title: '提交失败', icon: 'none' });
|
||||
}
|
||||
};
|
||||
|
||||
// 重置表单状态(进入下一题时调用)
|
||||
const resetFormState = () => {
|
||||
// 重置检查结果选择
|
||||
radiovalue1.value = '';
|
||||
// 重置备注
|
||||
value1.value = '';
|
||||
// 清除隐患信息
|
||||
clearHazard();
|
||||
};
|
||||
|
||||
// 获取检查项数据
|
||||
const getCheckData = async () => {
|
||||
try {
|
||||
@@ -136,6 +617,10 @@
|
||||
oneTableId.value = options.id;
|
||||
getCheckData();
|
||||
}
|
||||
// 获取隐患标签列表
|
||||
fetchTagOptions();
|
||||
// 获取区域列表
|
||||
fetchAreaList();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -144,4 +629,342 @@
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
}
|
||||
</style>
|
||||
|
||||
// 进度显示
|
||||
.progress-bar {
|
||||
background: #fff;
|
||||
border-radius: 12rpx;
|
||||
padding: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.current-index {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #2667E9;
|
||||
}
|
||||
|
||||
.total-count {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-line {
|
||||
height: 12rpx;
|
||||
background: #E5E5E5;
|
||||
border-radius: 6rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-inner {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #2667E9, #5B9BFF);
|
||||
border-radius: 6rpx;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
// 隐患信息区域
|
||||
.hazard-section {
|
||||
border-top: 1rpx solid #eee;
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
// 提示文字
|
||||
.hazard-tip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 20rpx;
|
||||
background: #FFF7E6;
|
||||
border: 1rpx solid #FFE7BA;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.text-orange {
|
||||
color: #FA8C16;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 填写隐患信息按钮
|
||||
.hazard-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 88rpx;
|
||||
border: 2rpx dashed #2667E9;
|
||||
border-radius: 12rpx;
|
||||
background: #F5F9FF;
|
||||
|
||||
.text-blue {
|
||||
color: #2667E9;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 隐患信息卡片
|
||||
.hazard-card {
|
||||
background: #F5F9FF;
|
||||
border: 1rpx solid #D6E4FF;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
border-bottom: 1rpx solid #E8E8E8;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
padding: 20rpx;
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 12rpx;
|
||||
font-size: 26rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.text-gray {
|
||||
flex-shrink: 0;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.description-text {
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.card-footer {
|
||||
display: flex;
|
||||
border-top: 1rpx solid #E8E8E8;
|
||||
background: #fff;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
border-radius: 0;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background: #fff;
|
||||
color: #2667E9;
|
||||
border-right: 1rpx solid #E8E8E8;
|
||||
}
|
||||
|
||||
.btn-clear {
|
||||
background: #fff;
|
||||
color: #F56C6C;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 隐患等级标签
|
||||
.level-tag {
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 8rpx;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.level-minor {
|
||||
background: #F6FFED;
|
||||
border: 2rpx solid #B7EB8F;
|
||||
color: #52C41A;
|
||||
}
|
||||
|
||||
.level-normal {
|
||||
background: #FFF7E6;
|
||||
border: 2rpx solid #FFD591;
|
||||
color: #FA8C16;
|
||||
}
|
||||
|
||||
.level-major {
|
||||
background: #FFF1F0;
|
||||
border: 2rpx solid #FFA39E;
|
||||
color: #F5222D;
|
||||
}
|
||||
|
||||
// 弹窗样式
|
||||
.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;
|
||||
}
|
||||
|
||||
.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-wrapper {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.btn-address {
|
||||
flex-shrink: 0;
|
||||
height: 70rpx;
|
||||
line-height: 70rpx;
|
||||
padding: 0 30rpx;
|
||||
font-size: 26rpx;
|
||||
border-radius: 8rpx;
|
||||
color: #fff;
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 选择器触发器样式
|
||||
.select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #fff;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
|
||||
.select-value {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
|
||||
&.placeholder {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 选择弹窗样式
|
||||
.picker-popup {
|
||||
background: #fff;
|
||||
|
||||
.picker-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
|
||||
.picker-cancel {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.picker-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.picker-confirm {
|
||||
font-size: 28rpx;
|
||||
color: #2667E9;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-body {
|
||||
max-height: 600rpx;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.picker-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.picker-item-active {
|
||||
color: #2667E9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 区域颜色圆点
|
||||
.area-color-dot {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -9,173 +9,462 @@
|
||||
</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="bg-white radius padding margin-top search-card">
|
||||
<view class="section-header">
|
||||
<image class="section-icon" src="/static/yujin/yujin_sousuo.png" mode="aspectFit"></image>
|
||||
<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 class="date-row margin-top">
|
||||
<view class="date-item">
|
||||
<view class="date-label">开始日期</view>
|
||||
<view class="date-picker" @click="showStartDatePicker = true">
|
||||
<text :class="searchForm.startDate ? 'date-value' : 'date-placeholder'">
|
||||
{{ searchForm.startDate || '请选择' }}
|
||||
</text>
|
||||
<text class="cuIcon-unfold"></text>
|
||||
</view>
|
||||
<up-datetime-picker
|
||||
:show="showStartDatePicker"
|
||||
v-model="startDateValue"
|
||||
mode="date"
|
||||
@confirm="onStartDateConfirm"
|
||||
@cancel="showStartDatePicker = false"
|
||||
@close="showStartDatePicker = false"
|
||||
></up-datetime-picker>
|
||||
</view>
|
||||
<view class="date-item">
|
||||
<view class="date-label">结束日期</view>
|
||||
<view class="date-picker" @click="showEndDatePicker = true">
|
||||
<text :class="searchForm.endDate ? 'date-value' : 'date-placeholder'">
|
||||
{{ searchForm.endDate || '请选择' }}
|
||||
</text>
|
||||
<text class="cuIcon-unfold"></text>
|
||||
</view>
|
||||
<up-datetime-picker
|
||||
:show="showEndDatePicker"
|
||||
v-model="endDateValue"
|
||||
mode="date"
|
||||
@confirm="onEndDateConfirm"
|
||||
@cancel="showEndDatePicker = false"
|
||||
@close="showEndDatePicker = false"
|
||||
></up-datetime-picker>
|
||||
</view>
|
||||
</view>
|
||||
<view class="margin-top">
|
||||
<view class="date-label">公司名称</view>
|
||||
<up-input v-model="searchForm.deptName" placeholder="请输入公司名称" border="surround"></up-input>
|
||||
</view>
|
||||
<button class="search-btn" @click="handleSearch">查询</button>
|
||||
</view>
|
||||
|
||||
<!-- 统计概览 -->
|
||||
<view class="padding bg-white radius margin-top">
|
||||
<view class="flex">
|
||||
<view></view>
|
||||
<view class="section-header">
|
||||
<image class="section-icon" src="/static/yujin/yujin_tongji.png" mode="aspectFit"></image>
|
||||
<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 class="stat-grid margin-top">
|
||||
<view class="stat-item stat-total">
|
||||
<view class="stat-num">{{ statistics.total }}</view>
|
||||
<view class="stat-label">总计</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 class="stat-item stat-overdue">
|
||||
<view class="stat-num">{{ statistics.overdue }}</view>
|
||||
<view class="stat-label">逾期</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 class="stat-item stat-completed">
|
||||
<view class="stat-num">{{ statistics.completed }}</view>
|
||||
<view class="stat-label">已完成</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 class="stat-item stat-pending">
|
||||
<view class="stat-num">{{ statistics.pending }}</view>
|
||||
<view class="stat-label">待处理</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 数据列表 -->
|
||||
<view class="bg-white radius padding margin-top margin-bottom flex">
|
||||
<view class="list-title"></view>
|
||||
|
||||
<!-- 数据列表标题 -->
|
||||
<view class="bg-white radius padding margin-top margin-bottom flex align-center">
|
||||
<view class="list-title-bar"></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 v-for="(item, index) in dataList" :key="item.id" class="list-card">
|
||||
<!-- 状态标签(斜角) -->
|
||||
<view class="status-tag" :class="getStatusClass(item.overdueDays)">
|
||||
<text class="status-text">{{ getStatusText(item.overdueDays, item.statusName) }}</text>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray" style="white-space: nowrap;">企业名称:</view>
|
||||
<view>湘西和谐云大数据产业发展有限公司</view>
|
||||
|
||||
<view class="card-header">
|
||||
<view class="text-bold text-black">#{{ index + 1 }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">计划名称:</view>
|
||||
<view>检查计划</view>
|
||||
<view class="card-row">
|
||||
<view class="row-label">企业名称:</view>
|
||||
<view class="row-value">{{ item.deptName || '-' }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">计划周期:</view>
|
||||
<view>每天一次</view>
|
||||
<view class="card-row">
|
||||
<view class="row-label">计划名称:</view>
|
||||
<view class="row-value">{{ item.planName || '-' }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">预约检查日期:</view>
|
||||
<view>2025-11-20</view>
|
||||
<view class="card-row">
|
||||
<view class="row-label">计划周期:</view>
|
||||
<view class="row-value">{{ item.cycleName || '-' }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">实际完成时间:</view>
|
||||
<view>未完成</view>
|
||||
<view class="card-row">
|
||||
<view class="row-label">预约检查日期:</view>
|
||||
<view class="row-value">{{ item.taskDate || '-' }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">负责人:</view>
|
||||
<view>符友成</view>
|
||||
<view class="card-row">
|
||||
<view class="row-label">实际完成时间:</view>
|
||||
<view class="row-value">{{ item.finishTime || '未完成' }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">逾期天数:</view>
|
||||
<view>17天 </view>
|
||||
<view class="card-row">
|
||||
<view class="row-label">负责人:</view>
|
||||
<view class="row-value">{{ item.executorName || '-' }}</view>
|
||||
</view>
|
||||
<view class="card-row">
|
||||
<view class="row-label">逾期天数:</view>
|
||||
<view class="row-value">{{ item.overdueDays || '-' }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view v-if="dataList.length === 0" class="empty-tip">
|
||||
<text>暂无数据</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
ref
|
||||
} from 'vue'
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { getInspectionWarningList } from '@/request/api.js'
|
||||
|
||||
const activeIndex = ref(0)
|
||||
// 搜索表单
|
||||
const searchForm = reactive({
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
deptName: ''
|
||||
})
|
||||
|
||||
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 showStartDatePicker = ref(false)
|
||||
const showEndDatePicker = ref(false)
|
||||
const startDateValue = ref(Number(new Date()))
|
||||
const endDateValue = ref(Number(new Date()))
|
||||
|
||||
const switchTab = (index) => {
|
||||
activeIndex.value = index
|
||||
// 统计数据
|
||||
const statistics = reactive({
|
||||
total: 0,
|
||||
overdue: 0,
|
||||
completed: 0,
|
||||
pending: 0
|
||||
})
|
||||
|
||||
// 列表数据
|
||||
const dataList = ref([])
|
||||
const pageNum = ref(1)
|
||||
const pageSize = ref(20)
|
||||
|
||||
// 日期格式化
|
||||
const formatDate = (timestamp) => {
|
||||
const date = new Date(timestamp)
|
||||
const year = date.getFullYear()
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(date.getDate()).padStart(2, '0')
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
// 日期选择确认
|
||||
const onStartDateConfirm = (e) => {
|
||||
searchForm.startDate = formatDate(e.value)
|
||||
showStartDatePicker.value = false
|
||||
}
|
||||
|
||||
const onEndDateConfirm = (e) => {
|
||||
searchForm.endDate = formatDate(e.value)
|
||||
showEndDatePicker.value = false
|
||||
}
|
||||
|
||||
// 获取状态样式类
|
||||
const getStatusClass = (overdueDays) => {
|
||||
if (!overdueDays || overdueDays === '按期') {
|
||||
return 'status-normal' // 按期/期限内
|
||||
}
|
||||
// 日期
|
||||
const value1 = ref(Date.now());
|
||||
const days = parseInt(overdueDays)
|
||||
if (days >= 7) {
|
||||
return 'status-serious' // 严重逾期(红色)
|
||||
} else if (days >= 1) {
|
||||
return 'status-overdue' // 逾期(橙色)
|
||||
}
|
||||
return 'status-normal'
|
||||
}
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (overdueDays, statusName) => {
|
||||
if (!overdueDays || overdueDays === '按期') {
|
||||
return statusName === '已完成' ? '按期已完成' : '期限内待检'
|
||||
}
|
||||
const days = parseInt(overdueDays)
|
||||
if (days >= 7) {
|
||||
return '严重逾期'
|
||||
} else if (days >= 1) {
|
||||
return statusName === '已完成' ? '逾期已完成' : '逾期未检'
|
||||
}
|
||||
return '期限内待检'
|
||||
}
|
||||
|
||||
// 获取数据
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const params = {
|
||||
pageNum: pageNum.value,
|
||||
pageSize: pageSize.value
|
||||
}
|
||||
// 添加查询条件
|
||||
if (searchForm.startDate) {
|
||||
params.startDate = searchForm.startDate
|
||||
}
|
||||
if (searchForm.endDate) {
|
||||
params.endDate = searchForm.endDate
|
||||
}
|
||||
if (searchForm.deptName && searchForm.deptName.trim()) {
|
||||
params.deptName = searchForm.deptName.trim()
|
||||
}
|
||||
|
||||
const res = await getInspectionWarningList(params)
|
||||
if (res.code === 0) {
|
||||
// 更新统计数据
|
||||
if (res.data.statistics) {
|
||||
statistics.total = res.data.statistics.total || 0
|
||||
statistics.overdue = res.data.statistics.overdue || 0
|
||||
statistics.completed = res.data.statistics.completed || 0
|
||||
statistics.pending = res.data.statistics.pending || 0
|
||||
}
|
||||
// 更新列表数据
|
||||
if (res.data.page && res.data.page.records) {
|
||||
dataList.value = res.data.page.records
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取预警列表失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索
|
||||
const handleSearch = () => {
|
||||
pageNum.value = 1
|
||||
fetchData()
|
||||
}
|
||||
|
||||
// 页面加载
|
||||
onShow(() => {
|
||||
fetchData()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
}
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.tab-scroll {
|
||||
white-space: nowrap;
|
||||
// 区块标题
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.section-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-list {
|
||||
display: inline-flex;
|
||||
// 搜索卡片
|
||||
.search-card {
|
||||
.date-row {
|
||||
display: 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;
|
||||
|
||||
.date-item {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
.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;
|
||||
|
||||
.date-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.date-picker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 72rpx;
|
||||
padding: 0 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
border: 1rpx solid #eee;
|
||||
|
||||
.date-value {
|
||||
color: #333;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.date-placeholder {
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
margin-top: 30rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #2667E9 100%);
|
||||
color: #fff;
|
||||
border-radius: 40rpx;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 统计卡片
|
||||
.stat-grid {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16rpx;
|
||||
|
||||
.stat-item {
|
||||
flex: 1;
|
||||
height: 124rpx;
|
||||
border-radius: 12rpx;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.stat-num {
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.stat-total {
|
||||
background: linear-gradient(135deg, #628EFB 0%, #4A7CF7 100%);
|
||||
}
|
||||
|
||||
.stat-overdue {
|
||||
background: linear-gradient(135deg, #32DCC7 0%, #20C5B0 100%);
|
||||
}
|
||||
|
||||
.stat-completed {
|
||||
background: linear-gradient(135deg, #32D1E9 0%, #20B8D0 100%);
|
||||
}
|
||||
|
||||
.stat-pending {
|
||||
background: linear-gradient(135deg, #A190F5 0%, #8B78E8 100%);
|
||||
}
|
||||
}
|
||||
|
||||
// 列表标题
|
||||
.list-title-bar {
|
||||
width: 8rpx;
|
||||
height: 32rpx;
|
||||
background: #2667E9;
|
||||
border-radius: 4rpx;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
// 数据卡片
|
||||
.list-card {
|
||||
position: relative;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0rpx 2rpx 10rpx rgba(0, 0, 0, 0.08);
|
||||
border-left: 8rpx solid #2667E9;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.card-header {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.card-row {
|
||||
display: flex;
|
||||
margin-top: 16rpx;
|
||||
font-size: 28rpx;
|
||||
line-height: 1.5;
|
||||
|
||||
.row-label {
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.row-value {
|
||||
color: #333;
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 状态标签(斜角样式)
|
||||
.status-tag {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
width: 160rpx;
|
||||
height: 50rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transform: rotate(0deg);
|
||||
border-radius: 0 16rpx 0 16rpx;
|
||||
|
||||
.status-text {
|
||||
font-size: 22rpx;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
// 严重逾期 - 红色
|
||||
.status-serious {
|
||||
background: linear-gradient(135deg, #FF6B6B 0%, #EE5A5A 100%);
|
||||
}
|
||||
|
||||
// 逾期 - 橙色
|
||||
.status-overdue {
|
||||
background: linear-gradient(135deg, #FFA726 0%, #FF9800 100%);
|
||||
}
|
||||
|
||||
// 按期/正常 - 绿色
|
||||
.status-normal {
|
||||
background: linear-gradient(135deg, #66BB6A 0%, #4CAF50 100%);
|
||||
}
|
||||
|
||||
// 逾期已完成 - 蓝色
|
||||
.status-completed {
|
||||
background: linear-gradient(135deg, #42A5F5 0%, #2196F3 100%);
|
||||
}
|
||||
|
||||
// 空状态
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
padding: 100rpx 0;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -1,226 +1,213 @@
|
||||
<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 class="area-list" v-if="areaList.length > 0">
|
||||
<view class="padding bg-white radius margin-bottom" v-for="item in areaList" :key="item.id">
|
||||
<view class="flex justify-between">
|
||||
<view>
|
||||
<view class="text-bold text-black">{{ item.name || '区域名称' }}</view>
|
||||
<view class="margin-top flex align-center">
|
||||
<text>颜色:</text>
|
||||
<view class="color-dot" :style="{ backgroundColor: item.color }"></view>
|
||||
<text class="margin-left-xs">{{ item.color }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view>
|
||||
<button class="bg-blue cu-btn" @click="openEditPopup(item)">编辑</button>
|
||||
<button class="bg-red cu-btn margin-left" @click="handleDelete(item)">删除</button>
|
||||
</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 class="empty-state" v-else>
|
||||
<text class="text-gray">暂无区域数据</text>
|
||||
</view>
|
||||
|
||||
<!-- 新增按钮 -->
|
||||
<button class="add-btn cuIcon-add bg-blue round" @click="openAddPopup">新增公司区域</button>
|
||||
|
||||
<!-- 新增/编辑弹窗组件 -->
|
||||
<AreaFormPopup
|
||||
v-model:visible="showPopup"
|
||||
:isEdit="isEdit"
|
||||
:editData="editData"
|
||||
:loading="submitting"
|
||||
@submit="handleSubmit"
|
||||
@close="handlePopupClose"
|
||||
/>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import AreaFormPopup from '@/components/AreaFormPopup.vue';
|
||||
import {
|
||||
getAreaList,
|
||||
getAreaDetail,
|
||||
addArea,
|
||||
updateArea,
|
||||
deleteArea
|
||||
} from '@/request/three_one_api/area.js';
|
||||
|
||||
// 弹出框显示状态
|
||||
const showEditPopup = ref(false);
|
||||
// 区域列表
|
||||
const areaList = ref([]);
|
||||
|
||||
// 当前区域数据(用于列表显示)
|
||||
const areaData = reactive({
|
||||
name: '区域名称',
|
||||
color: '#ef4444'
|
||||
// 弹窗控制
|
||||
const showPopup = ref(false);
|
||||
const isEdit = ref(false);
|
||||
const currentEditId = ref(null);
|
||||
const submitting = ref(false);
|
||||
|
||||
// 编辑时的数据
|
||||
const editData = ref({});
|
||||
|
||||
// 页面加载
|
||||
onMounted(() => {
|
||||
loadAreaList();
|
||||
});
|
||||
|
||||
// 表单数据
|
||||
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 loadAreaList = async () => {
|
||||
try {
|
||||
const res = await getAreaList();
|
||||
if (res.code === 0) {
|
||||
areaList.value = res.data.records || [];
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取区域列表失败:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// 选择预设颜色
|
||||
const selectColor = (color) => {
|
||||
formData.color = color;
|
||||
// 打开新增弹窗
|
||||
const openAddPopup = () => {
|
||||
isEdit.value = false;
|
||||
currentEditId.value = null;
|
||||
editData.value = {};
|
||||
showPopup.value = true;
|
||||
};
|
||||
|
||||
// 确定编辑
|
||||
const handleEdit = () => {
|
||||
if (!formData.name) {
|
||||
uni.showToast({ title: '请输入区域名称', icon: 'none' });
|
||||
return;
|
||||
// 打开编辑弹窗
|
||||
const openEditPopup = async (item) => {
|
||||
try {
|
||||
const res = await getAreaDetail({ id: item.id });
|
||||
if (res.code === 0) {
|
||||
isEdit.value = true;
|
||||
currentEditId.value = item.id;
|
||||
editData.value = {
|
||||
name: res.data.name || '',
|
||||
color: res.data.color || '#FF5733'
|
||||
};
|
||||
showPopup.value = true;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('获取区域详情失败:', err);
|
||||
uni.showToast({ title: '获取详情失败', icon: 'none' });
|
||||
}
|
||||
if (!formData.color) {
|
||||
uni.showToast({ title: '请选择区域颜色', icon: 'none' });
|
||||
return;
|
||||
};
|
||||
|
||||
// 弹窗关闭
|
||||
const handlePopupClose = () => {
|
||||
isEdit.value = false;
|
||||
currentEditId.value = null;
|
||||
editData.value = {};
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async (formData) => {
|
||||
submitting.value = true;
|
||||
|
||||
try {
|
||||
const submitData = {
|
||||
name: formData.name,
|
||||
color: formData.color
|
||||
};
|
||||
|
||||
let res;
|
||||
if (isEdit.value) {
|
||||
submitData.id = currentEditId.value;
|
||||
res = await updateArea(submitData);
|
||||
} else {
|
||||
res = await addArea(submitData);
|
||||
}
|
||||
|
||||
if (res.code === 0) {
|
||||
showPopup.value = false;
|
||||
uni.showToast({
|
||||
title: isEdit.value ? '修改成功' : '新增成功',
|
||||
icon: 'success'
|
||||
});
|
||||
loadAreaList();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('提交失败:', err);
|
||||
uni.showToast({ title: '操作失败', icon: 'none' });
|
||||
} finally {
|
||||
submitting.value = false;
|
||||
}
|
||||
|
||||
// 更新区域数据
|
||||
areaData.name = formData.name;
|
||||
areaData.color = formData.color;
|
||||
|
||||
showEditPopup.value = false;
|
||||
uni.showToast({
|
||||
title: '编辑成功',
|
||||
icon: 'success'
|
||||
};
|
||||
|
||||
// 删除区域
|
||||
const handleDelete = (item) => {
|
||||
uni.showModal({
|
||||
title: '确认删除',
|
||||
content: '确定要删除该区域吗?',
|
||||
confirmColor: '#e54d42',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
const result = await deleteArea({ id: item.id });
|
||||
if (result.code === 0) {
|
||||
uni.showToast({ title: '删除成功', icon: 'success' });
|
||||
loadAreaList();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('删除失败:', err);
|
||||
uni.showToast({ title: '删除失败', icon: 'none' });
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
}
|
||||
|
||||
.popup-content {
|
||||
width: 600rpx;
|
||||
background: #fff;
|
||||
border-radius: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.popup-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
// 区域列表
|
||||
.area-list {
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.popup-title {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
// 空状态
|
||||
.empty-state {
|
||||
padding: 200rpx 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.popup-close {
|
||||
font-size: 40rpx;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
}
|
||||
// 新增按钮
|
||||
.add-btn {
|
||||
position: fixed;
|
||||
bottom: 40rpx;
|
||||
left: 30rpx;
|
||||
right: 30rpx;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
border-radius: 44rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.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>
|
||||
// 颜色圆点
|
||||
.color-dot {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
border-radius: 6rpx;
|
||||
flex-shrink: 0;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,41 +1,101 @@
|
||||
<template>
|
||||
<view class="page padding">
|
||||
<view class="padding bg-white radius flex justify-between margin-bottom" v-for="item in list" :key="item.id">
|
||||
<view>{{ item.name }}</view>
|
||||
<view>
|
||||
<button class="bg-blue cu-btn margin-right-xs" @click="edit()">编辑</button>
|
||||
<button class="bg-red cu-btn">删除</button>
|
||||
</view>
|
||||
<!-- 检查表列表 -->
|
||||
<view class="checklist-card" v-for="item in list" :key="item.id">
|
||||
<view class="card-name">{{ item.name }}</view>
|
||||
</view>
|
||||
<button class="lg cuIcon-add bg-blue round margin-top-xl" @click="edit()">新增检查表</button>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view v-if="list.length === 0" class="empty-tip">
|
||||
<text>暂无检查表</text>
|
||||
</view>
|
||||
|
||||
<!-- 新增按钮 -->
|
||||
<button class="add-btn" @click="goToAdd">
|
||||
<text class="cuIcon-add"></text>
|
||||
<text>新增检查表</text>
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { getCheckTableList } from '@/request/api.js'
|
||||
const router = useRouter()
|
||||
const list = ref([])
|
||||
const edit = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/editchecklist/editchecklist'
|
||||
})
|
||||
import { ref } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { getCheckTableList } from '@/request/api.js'
|
||||
|
||||
const list = ref([])
|
||||
|
||||
// 获取检查表列表
|
||||
const fetchList = async () => {
|
||||
try {
|
||||
const res = await getCheckTableList({ pageNum: 1, pageSize: 100 });
|
||||
if (res.code === 0) {
|
||||
list.value = res.data.records || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取检查表列表失败:', error);
|
||||
}
|
||||
onLoad(() => {
|
||||
getCheckTableList().then(res => {
|
||||
if (res.code === 0) {
|
||||
list.value = res.data.records
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 跳转到新增页面
|
||||
const goToAdd = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/editchecklist/editchecklist'
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// 每次显示页面时刷新数据
|
||||
onShow(() => {
|
||||
fetchList();
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.checklist-card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.card-name {
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.empty-tip {
|
||||
text-align: center;
|
||||
padding: 100rpx 0;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
position: fixed;
|
||||
bottom: 40rpx;
|
||||
left: 30rpx;
|
||||
right: 30rpx;
|
||||
height: 90rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #2668EA 100%);
|
||||
border-radius: 45rpx;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
box-shadow: 0 8rpx 20rpx rgba(102, 126, 234, 0.4);
|
||||
|
||||
.cuIcon-add {
|
||||
margin-right: 10rpx;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -27,7 +27,7 @@
|
||||
<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>
|
||||
<button class="cuIcon-add bg-blue round margin-top" @click="openAddPopup">新增</button>
|
||||
<!-- 弹出框 -->
|
||||
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
|
||||
<view class="popup-content">
|
||||
@@ -35,7 +35,7 @@
|
||||
<view class="popup-title text-bold">新增销号申请</view>
|
||||
<view class="popup-close" @click="showAddPopup = false">×</view>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<scroll-view class="popup-body" scroll-y :style="{ height: '60vh' }">
|
||||
<view class="flex margin-bottom">
|
||||
<view>隐患</view>
|
||||
<view class="text-red">*</view>
|
||||
@@ -66,7 +66,16 @@
|
||||
@close="showDatePicker = false"
|
||||
></up-datetime-picker>
|
||||
<view class="margin-bottom margin-top">隐患治理责任单位</view>
|
||||
<up-input v-model="formData.responsibleDeptName" placeholder="请输入隐患治理责任单位"></up-input>
|
||||
<view class="picker-input" @click="showDeptPicker = true">
|
||||
<text :class="selectedDeptName ? '' : 'text-gray'">{{ selectedDeptName || '请选择隐患治理责任单位' }}</text>
|
||||
</view>
|
||||
<up-picker
|
||||
:show="showDeptPicker"
|
||||
:columns="deptColumns"
|
||||
@confirm="onDeptConfirm"
|
||||
@cancel="showDeptPicker = false"
|
||||
@close="showDeptPicker = false"
|
||||
></up-picker>
|
||||
<view class="margin-bottom margin-top">主要负责人</view>
|
||||
<up-input v-model="formData.responsiblePerson" placeholder="请输入主要负责人"></up-input>
|
||||
<view class="margin-bottom margin-top">主要治理内容</view>
|
||||
@@ -75,7 +84,7 @@
|
||||
<up-textarea v-model="formData.treatmentResult" placeholder="请输入隐患治理完成情况"></up-textarea>
|
||||
<view class="margin-bottom margin-top">隐患治理责任单位自行验收的情况</view>
|
||||
<up-textarea v-model="formData.selfVerifyContent" placeholder="请输入隐患治理责任单位自行验收的情况"></up-textarea>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="popup-footer">
|
||||
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
|
||||
<button class="btn-confirm bg-blue" @click="handleAdd">确定</button>
|
||||
@@ -87,18 +96,26 @@
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import {getMyWriteOffList, applyDelete } from '@/request/api.js';
|
||||
import { getMyWriteOffList, applyDelete, getAcceptanceList, getDepartmentPersonUsers } from '@/request/api.js';
|
||||
|
||||
// 弹窗控制
|
||||
const showAddPopup = ref(false);
|
||||
const showHazardPicker = ref(false);
|
||||
const showDatePicker = ref(false);
|
||||
const showDeptPicker = ref(false);
|
||||
|
||||
// 隐患选择
|
||||
const selectedHazard = ref('');
|
||||
const selectedHazardId = ref('');
|
||||
const hazardColumns = ref([['暂无数据']]);
|
||||
const hazardList = ref([]); // 存储完整隐患数据
|
||||
const acceptanceHazardList = ref([]); // 存储可申请销号的隐患数据
|
||||
const hazardList = ref([]); // 存储销号申请列表
|
||||
|
||||
// 部门选择
|
||||
const selectedDeptName = ref('');
|
||||
const selectedDeptId = ref('');
|
||||
const deptColumns = ref([['暂无数据']]);
|
||||
const deptList = ref([]); // 存储部门列表
|
||||
|
||||
// 日期选择
|
||||
const dateValue = ref(Date.now());
|
||||
@@ -106,31 +123,100 @@
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
rectifyDeadline: '', // 整改时限
|
||||
responsibleDeptName: '', // 隐患治理责任单位
|
||||
responsibleDeptId: '', // 隐患治理责任单位ID
|
||||
responsiblePerson: '', // 主要负责人
|
||||
mainTreatmentContent: '', // 主要治理内容
|
||||
treatmentResult: '', // 隐患治理完成内容
|
||||
selfVerifyContent: '' // 责任单位自行验收情况
|
||||
});
|
||||
|
||||
// 获取验收完成的隐患列表
|
||||
const fetchHazardList = async () => {
|
||||
// 获取销号申请列表(页面显示用)
|
||||
const fetchWriteOffList = async () => {
|
||||
try {
|
||||
const res = await getMyWriteOffList();
|
||||
if (res.code === 0 && res.data) {
|
||||
const list = res.data;
|
||||
hazardList.value = list;
|
||||
// 转换为 picker 需要的格式
|
||||
if (list.length > 0) {
|
||||
hazardColumns.value = [list.map(item => item.hazardTitle || `隐患${item.hazardId}`)];
|
||||
}
|
||||
console.log('隐患列表:', list);
|
||||
hazardList.value = res.data;
|
||||
console.log('销号申请列表:', res.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取隐患列表失败:', error);
|
||||
console.error('获取销号申请列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取可申请销号的隐患列表(弹窗选择用)
|
||||
const fetchAcceptanceList = async () => {
|
||||
try {
|
||||
const res = await getAcceptanceList();
|
||||
if (res.code === 0 && res.data) {
|
||||
const list = res.data.records || res.data || [];
|
||||
acceptanceHazardList.value = list;
|
||||
// 转换为 picker 需要的格式
|
||||
if (list.length > 0) {
|
||||
hazardColumns.value = [list.map(item => item.title || item.hazardTitle || `隐患${item.hazardId}`)];
|
||||
} else {
|
||||
hazardColumns.value = [['暂无可申请销号的隐患']];
|
||||
}
|
||||
console.log('可申请销号的隐患列表:', list);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取可申请销号隐患列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取部门列表
|
||||
const fetchDeptList = async () => {
|
||||
try {
|
||||
const res = await getDepartmentPersonUsers();
|
||||
if (res.code === 0 && res.data) {
|
||||
const users = [];
|
||||
res.data.forEach(dept => {
|
||||
if (dept.users && dept.users.length > 0) {
|
||||
dept.users.forEach(user => {
|
||||
users.push({
|
||||
userId: user.userId,
|
||||
deptId: dept.deptId,
|
||||
name: `${user.nickName}(${dept.deptName})`
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
deptList.value = users;
|
||||
// 转换为 picker 需要的格式
|
||||
if (users.length > 0) {
|
||||
deptColumns.value = [users.map(item => item.name)];
|
||||
} else {
|
||||
deptColumns.value = [['暂无人员数据']];
|
||||
}
|
||||
console.log('部门人员列表:', users);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取部门人员列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 部门选择确认
|
||||
const onDeptConfirm = (e) => {
|
||||
console.log('选择的人员:', e);
|
||||
if (e.value && e.value.length > 0) {
|
||||
selectedDeptName.value = e.value[0];
|
||||
// 找到对应的用户ID和部门ID
|
||||
const index = e.indexs[0];
|
||||
if (deptList.value[index]) {
|
||||
selectedDeptId.value = deptList.value[index].deptId;
|
||||
formData.responsibleDeptId = deptList.value[index].deptId;
|
||||
}
|
||||
}
|
||||
showDeptPicker.value = false;
|
||||
};
|
||||
|
||||
// 打开新增弹窗
|
||||
const openAddPopup = () => {
|
||||
resetForm();
|
||||
fetchAcceptanceList(); // 获取可申请销号的隐患列表
|
||||
fetchDeptList(); // 获取部门列表
|
||||
showAddPopup.value = true;
|
||||
};
|
||||
|
||||
// 隐患选择确认
|
||||
const onHazardConfirm = (e) => {
|
||||
console.log('选择的隐患:', e);
|
||||
@@ -138,8 +224,8 @@
|
||||
selectedHazard.value = e.value[0];
|
||||
// 找到对应的隐患ID
|
||||
const index = e.indexs[0];
|
||||
if (hazardList.value[index]) {
|
||||
selectedHazardId.value = hazardList.value[index].hazardId;
|
||||
if (acceptanceHazardList.value[index]) {
|
||||
selectedHazardId.value = acceptanceHazardList.value[index].hazardId;
|
||||
}
|
||||
}
|
||||
showHazardPicker.value = false;
|
||||
@@ -163,8 +249,10 @@
|
||||
const resetForm = () => {
|
||||
selectedHazard.value = '';
|
||||
selectedHazardId.value = '';
|
||||
selectedDeptName.value = '';
|
||||
selectedDeptId.value = '';
|
||||
formData.rectifyDeadline = '';
|
||||
formData.responsibleDeptName = '';
|
||||
formData.responsibleDeptId = '';
|
||||
formData.responsiblePerson = '';
|
||||
formData.mainTreatmentContent = '';
|
||||
formData.treatmentResult = '';
|
||||
@@ -178,10 +266,11 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建请求参数
|
||||
// 构建请求参数(与接口文档对应)
|
||||
const params = {
|
||||
hazardId: Number(selectedHazardId.value), // 隐患ID(必需)
|
||||
rectifyDeadline: formData.rectifyDeadline || '', // 整改时限
|
||||
responsibleDeptId: Number(formData.responsibleDeptId) || 0, // 隐患治理责任单位ID
|
||||
responsiblePerson: formData.responsiblePerson || '', // 主要负责人
|
||||
mainTreatmentContent: formData.mainTreatmentContent || '', // 主要治理内容
|
||||
treatmentResult: formData.treatmentResult || '', // 隐患治理完成内容
|
||||
@@ -196,6 +285,8 @@
|
||||
uni.showToast({ title: '申请成功', icon: 'success' });
|
||||
showAddPopup.value = false;
|
||||
resetForm();
|
||||
// 刷新销号申请列表
|
||||
fetchWriteOffList();
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '申请失败', icon: 'none' });
|
||||
}
|
||||
@@ -211,9 +302,9 @@
|
||||
})
|
||||
};
|
||||
|
||||
// 页面加载时获取数据
|
||||
// 页面加载时获取销号申请列表
|
||||
onMounted(() => {
|
||||
fetchHazardList();
|
||||
fetchWriteOffList();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -251,8 +342,6 @@
|
||||
|
||||
.popup-body {
|
||||
padding: 30rpx;
|
||||
max-height: 800rpx;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<up-input v-model="formData.statusName" placeholder="" disabled></up-input>
|
||||
<view class="flex justify-center margin-top-xl" style="gap: 30rpx;">
|
||||
<button class="round cu-btn lg" @click="handleCancel">返回</button>
|
||||
<button v-if="canEdit" class="bg-blue round cu-btn lg" @click="handleSubmit">保存</button>
|
||||
<!-- <button v-if="canEdit" class="bg-blue round cu-btn lg" @click="handleSubmit">保存</button> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,49 +1,825 @@
|
||||
<template>
|
||||
<view class="page padding">
|
||||
<view class="padding bg-white radius list">
|
||||
<!-- 有企业信息时显示详情 -->
|
||||
<view v-if="hasEnterpriseInfo" 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 class="text-bold text-lg">{{ enterpriseInfo.name }}</view>
|
||||
<view class="lg text-blue cuIcon-edit over" @click="openEditPopup">编辑</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">所属部门:</view>
|
||||
<view>湘西自治州和谐网络科技有限公司</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.enterpriseTypeName">
|
||||
<view class="text-gray">企业类型:</view>
|
||||
<view>{{ enterpriseInfo.enterpriseTypeName }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">企业代码:</view>
|
||||
<view>91433126MA4P8WWG20</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.industryName">
|
||||
<view class="text-gray">行业类型:</view>
|
||||
<view>{{ enterpriseInfo.industryName }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="info-item" v-if="enterpriseInfo.creditCode">
|
||||
<view class="text-gray">统一社会信用代码:</view>
|
||||
<view>{{ enterpriseInfo.creditCode }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.registeredCapital">
|
||||
<view class="text-gray">注册资本:</view>
|
||||
<view>{{ enterpriseInfo.registeredCapital }}万元</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.establishDate">
|
||||
<view class="text-gray">成立时间:</view>
|
||||
<view>{{ enterpriseInfo.establishDate }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.employeeCount">
|
||||
<view class="text-gray">员工总数:</view>
|
||||
<view>{{ enterpriseInfo.employeeCount }}人</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.mainBusiness">
|
||||
<view class="text-gray">主营行业:</view>
|
||||
<view>{{ enterpriseInfo.mainBusiness }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.mainProducts">
|
||||
<view class="text-gray">主要产品/服务:</view>
|
||||
<view>{{ enterpriseInfo.mainProducts }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.annualOutput">
|
||||
<view class="text-gray">年产值:</view>
|
||||
<view>{{ enterpriseInfo.annualOutput }}万元</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.province || enterpriseInfo.city">
|
||||
<view class="text-gray">所在地区:</view>
|
||||
<view>{{ enterpriseInfo.province }}{{ enterpriseInfo.city }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.address">
|
||||
<view class="text-gray">详细地址:</view>
|
||||
<view>{{ enterpriseInfo.address }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.phone">
|
||||
<view class="text-gray">联系电话:</view>
|
||||
<view>13974356210</view>
|
||||
<view>{{ enterpriseInfo.phone }}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">企业地址:</view>
|
||||
<view>湘西州文学艺术界联合会6楼</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.email">
|
||||
<view class="text-gray">电子邮箱:</view>
|
||||
<view>{{ enterpriseInfo.email }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.legalPerson">
|
||||
<view class="text-gray">法定代表人:</view>
|
||||
<view>{{ enterpriseInfo.legalPerson }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.legalPersonPhone">
|
||||
<view class="text-gray">法人联系电话:</view>
|
||||
<view>{{ enterpriseInfo.legalPersonPhone }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.safetyManager">
|
||||
<view class="text-gray">安全负责人:</view>
|
||||
<view>{{ enterpriseInfo.safetyManager }}</view>
|
||||
</view>
|
||||
<view class="info-item" v-if="enterpriseInfo.safetyManagerPhone">
|
||||
<view class="text-gray">安全负责人电话:</view>
|
||||
<view>{{ enterpriseInfo.safetyManagerPhone }}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 没有企业信息时显示新增按钮 -->
|
||||
<view v-else class="empty-box">
|
||||
<view class="text-gray text-center margin-bottom">暂无企业信息</view>
|
||||
<button class="bg-blue round" @click="openAddPopup">新增企业信息</button>
|
||||
</view>
|
||||
|
||||
<!-- 新增/编辑弹窗 - 使用 up-modal -->
|
||||
<up-modal
|
||||
:show="showPopup"
|
||||
:title="isEdit ? '编辑企业信息' : '新增企业信息'"
|
||||
:showConfirmButton="true"
|
||||
:showCancelButton="true"
|
||||
confirmText="确定"
|
||||
cancelText="取消"
|
||||
@confirm="handleSubmit"
|
||||
@cancel="showPopup = false"
|
||||
@close="showPopup = false"
|
||||
:closeOnClickOverlay="false"
|
||||
>
|
||||
<scroll-view class="modal-scroll-body" scroll-y="true">
|
||||
<!-- 企业名称 -->
|
||||
<view class="form-label">
|
||||
<view class="text-gray">企业名称</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.name" placeholder="请输入企业名称" />
|
||||
|
||||
<!-- 企业类型 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">企业类型</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="select-trigger" @click="openEnterpriseTypePopup">
|
||||
<view class="select-value" :class="{ 'placeholder': !selectedEnterpriseTypeName }">
|
||||
{{ selectedEnterpriseTypeName || '请选择企业类型' }}
|
||||
</view>
|
||||
<text class="cuIcon-unfold"></text>
|
||||
</view>
|
||||
|
||||
<!-- 行业类型 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">行业类型</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="select-trigger" @click="openIndustryPopup">
|
||||
<view class="select-value" :class="{ 'placeholder': !selectedIndustryName }">
|
||||
{{ selectedIndustryName || '请选择行业类型' }}
|
||||
</view>
|
||||
<text class="cuIcon-unfold"></text>
|
||||
</view>
|
||||
|
||||
<!-- 统一社会信用代码 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">统一社会信用代码</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.creditCode" placeholder="请输入统一社会信用代码" />
|
||||
|
||||
<!-- 注册资本 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">注册资本(万元)</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.registeredCapital" placeholder="请输入注册资本" type="number" />
|
||||
|
||||
<!-- 成立时间 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">成立时间</view>
|
||||
</view>
|
||||
<view class="select-trigger" @click="showDatePicker = true">
|
||||
<view class="select-value" :class="{ 'placeholder': !formData.establishDate }">
|
||||
{{ formData.establishDate || '请选择成立时间' }}
|
||||
</view>
|
||||
<text class="cuIcon-calendar"></text>
|
||||
</view>
|
||||
|
||||
<!-- 员工总数 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">员工总数</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.employeeCount" placeholder="请输入员工总数" type="number" />
|
||||
|
||||
<!-- 主营行业 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">主营行业</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.mainBusiness" placeholder="请输入主营行业" />
|
||||
|
||||
<!-- 主要产品/服务 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">主要产品/服务</view>
|
||||
</view>
|
||||
<textarea class="form-textarea" v-model="formData.mainProducts" placeholder="请输入主要产品/服务"></textarea>
|
||||
|
||||
<!-- 年产值 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">年产值(万元)</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.annualOutput" placeholder="请输入年产值" type="number" />
|
||||
|
||||
<!-- 所在省份 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">所在省份</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.province" placeholder="请输入所在省份" />
|
||||
|
||||
<!-- 所在城市 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">所在城市</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.city" placeholder="请输入所在城市" />
|
||||
|
||||
<!-- 详细地址 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">详细地址</view>
|
||||
</view>
|
||||
<textarea class="form-textarea" v-model="formData.address" placeholder="请输入详细地址"></textarea>
|
||||
|
||||
<!-- 联系电话 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">联系电话</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.phone" placeholder="请输入联系电话" />
|
||||
|
||||
<!-- 电子邮箱 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">电子邮箱</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.email" placeholder="请输入电子邮箱" />
|
||||
|
||||
<!-- 法定代表人 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">法定代表人</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.legalPerson" placeholder="请输入法定代表人" />
|
||||
|
||||
<!-- 法人联系电话 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">法人联系电话</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.legalPersonPhone" placeholder="请输入法人联系电话" />
|
||||
|
||||
<!-- 安全负责人 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">安全负责人</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.safetyManager" placeholder="请输入安全负责人" />
|
||||
|
||||
<!-- 安全负责人电话 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">安全负责人电话</view>
|
||||
</view>
|
||||
<input class="form-input" v-model="formData.safetyManagerPhone" placeholder="请输入安全负责人电话" />
|
||||
|
||||
<!-- 资质证书 -->
|
||||
<view class="form-label margin-top">
|
||||
<view class="text-gray">资质证书</view>
|
||||
</view>
|
||||
<up-upload :fileList="certificateFiles" @afterRead="afterRead" @delete="deleteCertificate" name="certificate" multiple :maxCount="10" accept="all"></up-upload>
|
||||
<view class="text-gray text-sm margin-bottom">支持上传图片、PDF等文件</view>
|
||||
</scroll-view>
|
||||
</up-modal>
|
||||
|
||||
<!-- 日期选择器单独放在外面 -->
|
||||
<u-datetime-picker
|
||||
:show="showDatePicker"
|
||||
v-model="establishDateValue"
|
||||
mode="date"
|
||||
@confirm="onDateConfirm"
|
||||
@cancel="showDatePicker = false"
|
||||
@close="showDatePicker = false"
|
||||
></u-datetime-picker>
|
||||
|
||||
<!-- 企业类型选择弹窗 -->
|
||||
<u-popup :show="showEnterpriseTypePopup" mode="bottom" round="20" @close="showEnterpriseTypePopup = false">
|
||||
<view class="picker-popup">
|
||||
<view class="picker-header">
|
||||
<view class="picker-cancel" @click="showEnterpriseTypePopup = false">取消</view>
|
||||
<view class="picker-title">选择企业类型</view>
|
||||
<view class="picker-confirm" @click="confirmEnterpriseType">确定</view>
|
||||
</view>
|
||||
<scroll-view class="picker-body" scroll-y>
|
||||
<view
|
||||
class="picker-item"
|
||||
v-for="item in enterpriseTypeList"
|
||||
:key="item.id"
|
||||
:class="{ 'active': tempEnterpriseTypeId === item.id }"
|
||||
@click="tempEnterpriseTypeId = item.id"
|
||||
>
|
||||
<text>{{ item.name }}</text>
|
||||
<text v-if="tempEnterpriseTypeId === item.id" class="cuIcon-check text-blue"></text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
<!-- 行业类型选择弹窗 -->
|
||||
<u-popup :show="showIndustryPopup" mode="bottom" round="20" @close="showIndustryPopup = false">
|
||||
<view class="picker-popup">
|
||||
<view class="picker-header">
|
||||
<view class="picker-cancel" @click="showIndustryPopup = false">取消</view>
|
||||
<view class="picker-title">选择行业类型</view>
|
||||
<view class="picker-confirm" @click="confirmIndustry">确定</view>
|
||||
</view>
|
||||
<scroll-view class="picker-body" scroll-y>
|
||||
<view
|
||||
class="picker-item"
|
||||
v-for="item in industryList"
|
||||
:key="item.id"
|
||||
:class="{ 'active': tempIndustryId === item.id }"
|
||||
@click="tempIndustryId = item.id"
|
||||
>
|
||||
<text>{{ item.name }}</text>
|
||||
<text v-if="tempIndustryId === item.id" class="cuIcon-check text-blue"></text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
const edit = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/editcompanInformation/editcompanInformation'
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import { getEnterpriseinfo, addEnterprise, updateEnterprise, getEnterprisetype, getindustry } from '@/request/api.js'
|
||||
import { baseUrl, getToken } from '@/request/request.js'
|
||||
|
||||
// 企业信息
|
||||
const enterpriseInfo = ref({})
|
||||
const hasEnterpriseInfo = computed(() => {
|
||||
return enterpriseInfo.value && enterpriseInfo.value.name
|
||||
})
|
||||
|
||||
// 弹窗控制
|
||||
const showPopup = ref(false)
|
||||
const isEdit = ref(false)
|
||||
const showDatePicker = ref(false)
|
||||
const establishDateValue = ref(Date.now())
|
||||
|
||||
// 下拉选项
|
||||
const enterpriseTypeList = ref([])
|
||||
const industryList = ref([])
|
||||
|
||||
// 选择弹窗控制
|
||||
const showEnterpriseTypePopup = ref(false)
|
||||
const showIndustryPopup = ref(false)
|
||||
const tempEnterpriseTypeId = ref('')
|
||||
const tempIndustryId = ref('')
|
||||
const selectedEnterpriseTypeName = ref('')
|
||||
const selectedIndustryName = ref('')
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
deptId: '',
|
||||
enterpriseTypeId: '',
|
||||
industryId: '',
|
||||
name: '',
|
||||
creditCode: '',
|
||||
registeredCapital: '',
|
||||
establishDate: '',
|
||||
employeeCount: '',
|
||||
mainBusiness: '',
|
||||
mainProducts: '',
|
||||
annualOutput: '',
|
||||
province: '',
|
||||
city: '',
|
||||
address: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
legalPerson: '',
|
||||
legalPersonPhone: '',
|
||||
safetyManager: '',
|
||||
safetyManagerPhone: '',
|
||||
certificates: ''
|
||||
})
|
||||
|
||||
// 资质证书文件列表
|
||||
const certificateFiles = ref([])
|
||||
|
||||
// 获取用户部门ID
|
||||
const getDeptId = () => {
|
||||
try {
|
||||
const userInfoStr = uni.getStorageSync('userInfo')
|
||||
if (userInfoStr) {
|
||||
const userInfo = JSON.parse(userInfoStr)
|
||||
return userInfo.deptId || ''
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
// 获取企业信息
|
||||
const fetchEnterpriseInfo = async () => {
|
||||
try {
|
||||
const res = await getEnterpriseinfo()
|
||||
if (res.code === 0 && res.data) {
|
||||
enterpriseInfo.value = res.data
|
||||
console.log('企业信息:', res.data)
|
||||
} else {
|
||||
enterpriseInfo.value = {}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取企业信息失败:', error)
|
||||
enterpriseInfo.value = {}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取企业类型列表
|
||||
const fetchEnterpriseTypes = async () => {
|
||||
try {
|
||||
const res = await getEnterprisetype()
|
||||
if (res.code === 0 && res.data) {
|
||||
enterpriseTypeList.value = res.data.map(item => ({
|
||||
id: String(item.id),
|
||||
name: item.name
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取企业类型失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取行业类型列表
|
||||
const fetchIndustryTypes = async () => {
|
||||
try {
|
||||
const res = await getindustry({})
|
||||
if (res.code === 0 && res.data) {
|
||||
industryList.value = res.data.map(item => ({
|
||||
id: String(item.id),
|
||||
name: item.name
|
||||
}))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取行业类型失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 打开企业类型选择弹窗
|
||||
const openEnterpriseTypePopup = () => {
|
||||
tempEnterpriseTypeId.value = formData.enterpriseTypeId
|
||||
showEnterpriseTypePopup.value = true
|
||||
}
|
||||
|
||||
// 确认企业类型选择
|
||||
const confirmEnterpriseType = () => {
|
||||
if (tempEnterpriseTypeId.value) {
|
||||
formData.enterpriseTypeId = tempEnterpriseTypeId.value
|
||||
const selected = enterpriseTypeList.value.find(item => item.id === tempEnterpriseTypeId.value)
|
||||
selectedEnterpriseTypeName.value = selected ? selected.name : ''
|
||||
}
|
||||
showEnterpriseTypePopup.value = false
|
||||
}
|
||||
|
||||
// 打开行业类型选择弹窗
|
||||
const openIndustryPopup = () => {
|
||||
tempIndustryId.value = formData.industryId
|
||||
showIndustryPopup.value = true
|
||||
}
|
||||
|
||||
// 确认行业类型选择
|
||||
const confirmIndustry = () => {
|
||||
if (tempIndustryId.value) {
|
||||
formData.industryId = tempIndustryId.value
|
||||
const selected = industryList.value.find(item => item.id === tempIndustryId.value)
|
||||
selectedIndustryName.value = selected ? selected.name : ''
|
||||
}
|
||||
showIndustryPopup.value = false
|
||||
}
|
||||
|
||||
// 日期确认
|
||||
const onDateConfirm = (e) => {
|
||||
const date = new Date(e.value)
|
||||
formData.establishDate = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`
|
||||
showDatePicker.value = false
|
||||
}
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
formData.deptId = getDeptId()
|
||||
formData.enterpriseTypeId = ''
|
||||
formData.industryId = ''
|
||||
formData.name = ''
|
||||
formData.creditCode = ''
|
||||
formData.registeredCapital = ''
|
||||
formData.establishDate = ''
|
||||
formData.employeeCount = ''
|
||||
formData.mainBusiness = ''
|
||||
formData.mainProducts = ''
|
||||
formData.annualOutput = ''
|
||||
formData.province = ''
|
||||
formData.city = ''
|
||||
formData.address = ''
|
||||
formData.phone = ''
|
||||
formData.email = ''
|
||||
formData.legalPerson = ''
|
||||
formData.legalPersonPhone = ''
|
||||
formData.safetyManager = ''
|
||||
formData.safetyManagerPhone = ''
|
||||
formData.certificates = ''
|
||||
certificateFiles.value = []
|
||||
selectedEnterpriseTypeName.value = ''
|
||||
selectedIndustryName.value = ''
|
||||
}
|
||||
|
||||
// 打开新增弹窗
|
||||
const openAddPopup = () => {
|
||||
isEdit.value = false
|
||||
resetForm()
|
||||
showPopup.value = true
|
||||
}
|
||||
|
||||
// 打开编辑弹窗
|
||||
const openEditPopup = () => {
|
||||
isEdit.value = true
|
||||
// 填充表单数据
|
||||
formData.deptId = enterpriseInfo.value.deptId || getDeptId()
|
||||
formData.enterpriseTypeId = String(enterpriseInfo.value.enterpriseTypeId || '')
|
||||
formData.industryId = String(enterpriseInfo.value.industryId || '')
|
||||
formData.name = enterpriseInfo.value.name || ''
|
||||
formData.creditCode = enterpriseInfo.value.creditCode || ''
|
||||
formData.registeredCapital = enterpriseInfo.value.registeredCapital || ''
|
||||
formData.establishDate = enterpriseInfo.value.establishDate || ''
|
||||
formData.employeeCount = enterpriseInfo.value.employeeCount || ''
|
||||
formData.mainBusiness = enterpriseInfo.value.mainBusiness || ''
|
||||
formData.mainProducts = enterpriseInfo.value.mainProducts || ''
|
||||
formData.annualOutput = enterpriseInfo.value.annualOutput || ''
|
||||
formData.province = enterpriseInfo.value.province || ''
|
||||
formData.city = enterpriseInfo.value.city || ''
|
||||
formData.address = enterpriseInfo.value.address || ''
|
||||
formData.phone = enterpriseInfo.value.phone || ''
|
||||
formData.email = enterpriseInfo.value.email || ''
|
||||
formData.legalPerson = enterpriseInfo.value.legalPerson || ''
|
||||
formData.legalPersonPhone = enterpriseInfo.value.legalPersonPhone || ''
|
||||
formData.safetyManager = enterpriseInfo.value.safetyManager || ''
|
||||
formData.safetyManagerPhone = enterpriseInfo.value.safetyManagerPhone || ''
|
||||
|
||||
// 同步显示已选择的类型名称
|
||||
selectedEnterpriseTypeName.value = enterpriseInfo.value.enterpriseTypeName || ''
|
||||
selectedIndustryName.value = enterpriseInfo.value.industryName || ''
|
||||
|
||||
// 处理资质证书
|
||||
if (enterpriseInfo.value.certificates) {
|
||||
try {
|
||||
const certs = JSON.parse(enterpriseInfo.value.certificates)
|
||||
certificateFiles.value = certs.map(cert => ({
|
||||
url: cert.filePath || cert.url,
|
||||
name: cert.fileName || cert.name,
|
||||
status: 'success'
|
||||
}))
|
||||
} catch (e) {
|
||||
certificateFiles.value = []
|
||||
}
|
||||
} else {
|
||||
certificateFiles.value = []
|
||||
}
|
||||
|
||||
showPopup.value = true
|
||||
}
|
||||
|
||||
// 上传文件
|
||||
const afterRead = async (event) => {
|
||||
let lists = [].concat(event.file)
|
||||
let fileListLen = certificateFiles.value.length
|
||||
lists.forEach((item) => {
|
||||
certificateFiles.value.push({
|
||||
...item,
|
||||
status: 'uploading',
|
||||
message: '上传中'
|
||||
})
|
||||
})
|
||||
for (let i = 0; i < lists.length; i++) {
|
||||
const result = await uploadFilePromise(lists[i].url)
|
||||
let item = certificateFiles.value[fileListLen]
|
||||
certificateFiles.value.splice(fileListLen, 1, {
|
||||
...item,
|
||||
status: 'success',
|
||||
message: '',
|
||||
url: result
|
||||
})
|
||||
fileListLen++
|
||||
}
|
||||
}
|
||||
|
||||
// 删除文件
|
||||
const deleteCertificate = (event) => {
|
||||
certificateFiles.value.splice(event.index, 1)
|
||||
}
|
||||
|
||||
// 上传文件Promise
|
||||
const uploadFilePromise = (filePath) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: baseUrl + '/frontend/attachment/upload',
|
||||
filePath: filePath,
|
||||
name: 'file',
|
||||
header: {
|
||||
'Authorization': getToken()
|
||||
},
|
||||
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.name) {
|
||||
uni.showToast({ title: '请输入企业名称', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!formData.enterpriseTypeId) {
|
||||
uni.showToast({ title: '请选择企业类型', icon: 'none' })
|
||||
return
|
||||
}
|
||||
if (!formData.industryId) {
|
||||
uni.showToast({ title: '请选择行业类型', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 构建资质证书JSON
|
||||
const certificates = certificateFiles.value.map(file => ({
|
||||
fileName: file.name || file.url.split('/').pop(),
|
||||
filePath: file.url
|
||||
}))
|
||||
|
||||
const params = {
|
||||
deptId: Number(formData.deptId) || Number(getDeptId()),
|
||||
enterpriseTypeId: Number(formData.enterpriseTypeId),
|
||||
industryId: Number(formData.industryId),
|
||||
name: formData.name,
|
||||
creditCode: formData.creditCode || '',
|
||||
registeredCapital: Number(formData.registeredCapital) || 0,
|
||||
establishDate: formData.establishDate || '',
|
||||
employeeCount: Number(formData.employeeCount) || 0,
|
||||
mainBusiness: formData.mainBusiness || '',
|
||||
mainProducts: formData.mainProducts || '',
|
||||
annualOutput: Number(formData.annualOutput) || 0,
|
||||
province: formData.province || '',
|
||||
city: formData.city || '',
|
||||
address: formData.address || '',
|
||||
phone: formData.phone || '',
|
||||
email: formData.email || '',
|
||||
legalPerson: formData.legalPerson || '',
|
||||
legalPersonPhone: formData.legalPersonPhone || '',
|
||||
safetyManager: formData.safetyManager || '',
|
||||
safetyManagerPhone: formData.safetyManagerPhone || '',
|
||||
certificates: JSON.stringify(certificates)
|
||||
}
|
||||
|
||||
// 如果是编辑模式,添加 id 字段
|
||||
if (isEdit.value && enterpriseInfo.value.id) {
|
||||
params.id = enterpriseInfo.value.id
|
||||
}
|
||||
|
||||
try {
|
||||
let res
|
||||
if (isEdit.value) {
|
||||
res = await updateEnterprise(params)
|
||||
} else {
|
||||
res = await addEnterprise(params)
|
||||
}
|
||||
|
||||
if (res.code === 0) {
|
||||
uni.showToast({
|
||||
title: isEdit.value ? '修改成功' : '新增成功',
|
||||
icon: 'success'
|
||||
})
|
||||
showPopup.value = false
|
||||
// 刷新数据
|
||||
fetchEnterpriseInfo()
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg || '操作失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
uni.showToast({
|
||||
title: '操作失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 页面显示时获取数据
|
||||
onShow(() => {
|
||||
fetchEnterpriseInfo()
|
||||
fetchEnterpriseTypes()
|
||||
fetchIndustryTypes()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
.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;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
margin-top: 16rpx;
|
||||
font-size: 28rpx;
|
||||
|
||||
.text-gray {
|
||||
flex-shrink: 0;
|
||||
color: #999;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
|
||||
.empty-box {
|
||||
padding: 100rpx 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// up-modal 内的滚动区域
|
||||
.modal-scroll-body {
|
||||
height: 60vh;
|
||||
padding: 20rpx 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// 表单输入框样式
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
padding: 0 24rpx;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
min-height: 160rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
box-sizing: border-box;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
.text-red {
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
|
||||
// 选择触发器样式
|
||||
.select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #fff;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
|
||||
.select-value {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
|
||||
&.placeholder {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 选择弹窗样式
|
||||
.picker-popup {
|
||||
background: #fff;
|
||||
|
||||
.picker-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
|
||||
.picker-cancel {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.picker-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.picker-confirm {
|
||||
font-size: 28rpx;
|
||||
color: #2667E9;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-body {
|
||||
max-height: 600rpx;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.picker-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #2667E9;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@
|
||||
<view class="popup-title text-bold">新增设备</view>
|
||||
<view class="popup-close" @click="showAddPopup = false">×</view>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<scroll-view class="popup-body" scroll-y :style="{ height: '60vh' }">
|
||||
<!-- 在这里填写表单内容 -->
|
||||
<view class="flex">
|
||||
<view class=" margin-bottom">型号</view>
|
||||
@@ -64,7 +64,7 @@
|
||||
</view>
|
||||
<view class="margin-top-sm margin-bottom margin-top">备注</view>
|
||||
<up-textarea v-model="value1" placeholder="请输入备注"></up-textarea>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="popup-footer">
|
||||
<button class="btn-cancel" @click="showAddPopup = false">取消</button>
|
||||
<button class="btn-confirm bg-blue" @click="handleAdd">确定</button>
|
||||
@@ -169,8 +169,6 @@
|
||||
|
||||
.popup-body {
|
||||
padding: 30rpx;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.popup-footer {
|
||||
|
||||
@@ -25,18 +25,27 @@
|
||||
<view class="flex justify-end" style="gap: 10rpx;">
|
||||
<!-- 所有状态都显示查看详情 -->
|
||||
<button class="round cu-btn lg light bg-blue" @click="details(item)">查看详情</button>
|
||||
<!-- 待整改、待验收显示立即整改 -->
|
||||
<button v-if="item.statusName === '待整改' || item.statusName === '待验收'"
|
||||
class="round cu-btn lg light bg-blue" @click="Rectification(item)">立即整改</button>
|
||||
<!-- 待验收显示立即验收 -->
|
||||
<button v-if="item.statusName === '待验收'"
|
||||
<!-- 待整改状态:canEdit为true时显示隐患交办和立即整改,为false时不显示 -->
|
||||
<button v-if="item.statusName === '待整改' && item.canEdit"
|
||||
class="round cu-btn lg light bg-blue" @click="assignHazard(item)">隐患交办</button>
|
||||
<button v-if="item.statusName === '待整改' && item.canEdit"
|
||||
class="round cu-btn lg bg-blue" @click="Rectification(item)">立即整改</button>
|
||||
<!-- 待验收显示编辑整改信息和立即验收 -->
|
||||
<button v-if="item.statusName === '待验收' && item.canEdit"
|
||||
class="round cu-btn lg light bg-blue" @click="editRectification(item)">编辑整改信息</button>
|
||||
<button v-if="item.statusName === '待验收' && canAcceptance"
|
||||
class="round cu-btn lg bg-blue" @click="acceptance(item)">立即验收</button>
|
||||
<!-- 待交办显示隐患交办 -->
|
||||
<button v-if="item.statusName === '待交办'"
|
||||
class="round cu-btn lg bg-blue" @click="assignHazard(item)">隐患交办</button>
|
||||
</view>
|
||||
</view>
|
||||
<button class="cuIcon-add round bg-blue margin-top-xl" @click="showAddPopup = true">新增</button>
|
||||
|
||||
<!-- 固定在底部的悬浮新增按钮 -->
|
||||
<view class="fixed-add-btn" @click="showAddPopup = true">
|
||||
<text class="cuIcon-add"></text>
|
||||
<text>新增</text>
|
||||
</view>
|
||||
|
||||
<!-- 新增弹窗 -->
|
||||
<u-popup :show="showAddPopup" mode="center" round="20" @close="showAddPopup = false">
|
||||
@@ -45,7 +54,7 @@
|
||||
<view class="popup-title text-bold">新增隐患排查</view>
|
||||
<view class="popup-close" @click="showAddPopup = false">×</view>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<scroll-view class="popup-body" scroll-y>
|
||||
<view class="flex margin-bottom">
|
||||
<view class="text-gray">隐患图片/视频</view>
|
||||
<view class="text-red">*</view>
|
||||
@@ -77,12 +86,22 @@
|
||||
</view>
|
||||
|
||||
<view class="address-box">
|
||||
<view class="address-input" @tap.stop="chooseLocation">
|
||||
<text :class="selectedAddress ? '' : 'text-gray'">{{ selectedAddress || '请选择地址' }}</text>
|
||||
</view>
|
||||
<up-input class="address-input-wrapper" v-model="selectedAddress" placeholder="请输入地址" border="surround"></up-input>
|
||||
<button class="btn-address bg-blue" @tap.stop="chooseLocation">选择地址</button>
|
||||
</view>
|
||||
<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>
|
||||
<view class="select-trigger" @click="showAreaPicker = true">
|
||||
<view class="select-value" :class="{ 'placeholder': !selectedAreaName }">
|
||||
{{ selectedAreaName || '请选择隐患区域' }}
|
||||
</view>
|
||||
<text class="cuIcon-unfold"></text>
|
||||
</view>
|
||||
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">隐患描述</view>
|
||||
<view class="text-red">*</view>
|
||||
@@ -92,13 +111,42 @@
|
||||
<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>
|
||||
</scroll-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>
|
||||
|
||||
<!-- 区域选择弹窗 -->
|
||||
<u-popup :show="showAreaPicker" mode="bottom" round="20" @close="showAreaPicker = false">
|
||||
<view class="picker-popup">
|
||||
<view class="picker-header">
|
||||
<view class="picker-cancel" @click="showAreaPicker = false">取消</view>
|
||||
<view class="picker-title">选择隐患区域</view>
|
||||
<view class="picker-confirm" @click="confirmAreaSelect">确定</view>
|
||||
</view>
|
||||
<scroll-view class="picker-body" scroll-y>
|
||||
<view
|
||||
v-for="item in areaList"
|
||||
:key="item.id"
|
||||
class="picker-item"
|
||||
:class="{ 'picker-item-active': tempAreaId === item.id }"
|
||||
@click="tempAreaId = item.id"
|
||||
>
|
||||
<view class="flex align-center">
|
||||
<view class="area-color-dot" :style="{ backgroundColor: item.color }"></view>
|
||||
<text>{{ item.name }}</text>
|
||||
</view>
|
||||
<text v-if="tempAreaId === item.id" class="cuIcon-check text-blue"></text>
|
||||
</view>
|
||||
<view v-if="areaList.length === 0" class="text-gray text-center padding">
|
||||
暂无区域数据
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -120,6 +168,7 @@
|
||||
getMyHiddenDangerList,
|
||||
getHiddenDangerLabelList
|
||||
} from '@/request/api.js'
|
||||
import { getAreaList } from '@/request/three_one_api/area.js'
|
||||
import {
|
||||
baseUrl,
|
||||
getToken
|
||||
@@ -127,6 +176,27 @@
|
||||
|
||||
// 弹窗控制
|
||||
const showAddPopup = ref(false);
|
||||
|
||||
// 获取用户角色,判断是否有验收权限(admin或manage才能验收)
|
||||
const userRole = ref('');
|
||||
const canAcceptance = computed(() => {
|
||||
return userRole.value === 'admin' || userRole.value === 'manage';
|
||||
});
|
||||
|
||||
// 从storage获取用户信息
|
||||
const getUserRole = () => {
|
||||
try {
|
||||
const userInfoStr = uni.getStorageSync('userInfo');
|
||||
if (userInfoStr) {
|
||||
const userInfo = JSON.parse(userInfoStr);
|
||||
userRole.value = userInfo.role || '';
|
||||
console.log('当前用户角色:', userRole.value);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
}
|
||||
};
|
||||
getUserRole();
|
||||
|
||||
// 任务相关ID(从接口获取)
|
||||
const taskId = ref('');
|
||||
@@ -173,6 +243,36 @@
|
||||
|
||||
// 地址选择 - 调用腾讯地图
|
||||
const selectedAddress = ref('');
|
||||
|
||||
// 区域选择相关
|
||||
const showAreaPicker = ref(false);
|
||||
const areaList = ref([]);
|
||||
const selectedAreaId = ref('');
|
||||
const selectedAreaName = ref('');
|
||||
const tempAreaId = ref('');
|
||||
|
||||
// 获取区域列表
|
||||
const fetchAreaList = async () => {
|
||||
try {
|
||||
const res = await getAreaList();
|
||||
if (res.code === 0 && res.data && res.data.records) {
|
||||
areaList.value = res.data.records;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取区域列表失败:', error);
|
||||
}
|
||||
};
|
||||
fetchAreaList();
|
||||
|
||||
// 确认区域选择
|
||||
const confirmAreaSelect = () => {
|
||||
if (tempAreaId.value) {
|
||||
selectedAreaId.value = tempAreaId.value;
|
||||
const selected = areaList.value.find(item => item.id === tempAreaId.value);
|
||||
selectedAreaName.value = selected ? selected.name : '';
|
||||
}
|
||||
showAreaPicker.value = false;
|
||||
};
|
||||
|
||||
const chooseLocation = () => {
|
||||
console.log('chooseLocation called');
|
||||
@@ -180,27 +280,60 @@
|
||||
showAddPopup.value = false;
|
||||
|
||||
setTimeout(() => {
|
||||
uni.chooseLocation({
|
||||
success: (res) => {
|
||||
console.log('选择位置成功:', res);
|
||||
// 获取选择的位置信息
|
||||
selectedAddress.value = res.address + (res.name ? `(${res.name})` : '');
|
||||
lng.value = res.longitude;
|
||||
lat.value = res.latitude;
|
||||
// 重新打开弹窗
|
||||
showAddPopup.value = true;
|
||||
// 先获取当前位置,再打开地图选择
|
||||
uni.getLocation({
|
||||
type: 'gcj02', // 使用国测局坐标系(腾讯地图使用)
|
||||
success: (locationRes) => {
|
||||
console.log('获取当前位置成功:', locationRes);
|
||||
// 使用当前位置作为地图初始中心点
|
||||
uni.chooseLocation({
|
||||
latitude: locationRes.latitude,
|
||||
longitude: locationRes.longitude,
|
||||
success: (res) => {
|
||||
console.log('选择位置成功:', res);
|
||||
// 获取选择的位置信息
|
||||
selectedAddress.value = res.address + (res.name ? `(${res.name})` : '');
|
||||
lng.value = res.longitude;
|
||||
lat.value = res.latitude;
|
||||
// 重新打开弹窗
|
||||
showAddPopup.value = true;
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('选择位置失败:', err);
|
||||
// 重新打开弹窗
|
||||
showAddPopup.value = true;
|
||||
// 用户取消选择不提示
|
||||
if (err.errMsg && err.errMsg.indexOf('cancel') === -1) {
|
||||
uni.showToast({
|
||||
title: '选择位置失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('选择位置失败:', err);
|
||||
// 重新打开弹窗
|
||||
showAddPopup.value = true;
|
||||
// 用户取消选择不提示
|
||||
if (err.errMsg && err.errMsg.indexOf('cancel') === -1) {
|
||||
uni.showToast({
|
||||
title: '选择位置失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
console.error('获取当前位置失败:', err);
|
||||
// 即使获取位置失败,也打开地图选择(不带初始位置)
|
||||
uni.chooseLocation({
|
||||
success: (res) => {
|
||||
console.log('选择位置成功:', res);
|
||||
selectedAddress.value = res.address + (res.name ? `(${res.name})` : '');
|
||||
lng.value = res.longitude;
|
||||
lat.value = res.latitude;
|
||||
showAddPopup.value = true;
|
||||
},
|
||||
fail: (chooseErr) => {
|
||||
console.error('选择位置失败:', chooseErr);
|
||||
showAddPopup.value = true;
|
||||
if (chooseErr.errMsg && chooseErr.errMsg.indexOf('cancel') === -1) {
|
||||
uni.showToast({
|
||||
title: '选择位置失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}, 300);
|
||||
@@ -250,19 +383,21 @@
|
||||
|
||||
// 构建请求参数
|
||||
const params = {
|
||||
|
||||
title: formData.title, //标题
|
||||
level: formData.level + 1, // 1.轻微隐患 2.一般隐患 3.重大隐患
|
||||
lng: lng.value || 0, //经度
|
||||
lat: lat.value || 0, //纬度
|
||||
address: selectedAddress.value || '', //详细地址
|
||||
areaId: selectedAreaId.value || null, //隐患区域ID
|
||||
description: formData.description || '', //隐患描述
|
||||
tagId: tagId, //隐患标签ID
|
||||
taskId: taskId.value, //关联任务ID
|
||||
checkPointId: checkPointId.value, //关联检查点ID
|
||||
source: sourceOptions.value[formData.source]?.title || '', //隐患来源(随手拍、企业自查、行业互查、专家诊查)
|
||||
|
||||
attachments: attachments, //附件列表(图片/视频)
|
||||
};
|
||||
|
||||
console.log('提交的参数:', params);
|
||||
//
|
||||
try {
|
||||
const res = await addHiddenDanger(params);
|
||||
@@ -278,6 +413,8 @@
|
||||
formData.description = '';
|
||||
formData.tagIndex = 0;
|
||||
selectedAddress.value = '';
|
||||
selectedAreaId.value = '';
|
||||
selectedAreaName.value = '';
|
||||
fileList1.value = [];
|
||||
// 刷新隐患列表
|
||||
fetchHiddenDangerList();
|
||||
@@ -320,6 +457,7 @@
|
||||
// 页面显示时刷新列表(从交办、验收页面返回时自动刷新)
|
||||
onShow(() => {
|
||||
fetchHiddenDangerList();
|
||||
|
||||
});
|
||||
|
||||
const details = (item) => {
|
||||
@@ -332,6 +470,14 @@
|
||||
url: `/pages/hiddendanger/rectification?hazardId=${item.hazardId}&assignId=${item.assignId}`
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑整改信息(待验收状态)
|
||||
const editRectification = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/hiddendanger/rectification?rectifyId=${item.rectifyId}&isEdit=1`
|
||||
})
|
||||
}
|
||||
|
||||
const acceptance = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/hiddendanger/acceptance?hazardId=${item.hazardId}&assignId=${item.assignId}&rectifyId=${item.rectifyId}`
|
||||
@@ -476,6 +622,31 @@
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
padding-bottom: 120rpx; // 给底部按钮留出空间
|
||||
}
|
||||
|
||||
// 固定在底部的悬浮新增按钮
|
||||
.fixed-add-btn {
|
||||
position: fixed;
|
||||
bottom: 40rpx;
|
||||
left: 30rpx;
|
||||
right: 30rpx;
|
||||
height: 88rpx;
|
||||
background: linear-gradient(135deg, #667eea 0%, #2668EA 100%);
|
||||
border-radius: 44rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #fff;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 8rpx 24rpx rgba(38, 104, 234, 0.4);
|
||||
z-index: 100;
|
||||
|
||||
.cuIcon-add {
|
||||
margin-right: 10rpx;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.list-list {
|
||||
@@ -576,18 +747,8 @@
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
|
||||
.address-input {
|
||||
.address-input-wrapper {
|
||||
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 {
|
||||
@@ -605,6 +766,87 @@
|
||||
}
|
||||
}
|
||||
|
||||
// 选择器触发器样式
|
||||
.select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #fff;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
|
||||
.select-value {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
|
||||
&.placeholder {
|
||||
color: #c0c4cc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 选择弹窗样式
|
||||
.picker-popup {
|
||||
background: #fff;
|
||||
|
||||
.picker-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
|
||||
.picker-cancel {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.picker-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.picker-confirm {
|
||||
font-size: 28rpx;
|
||||
color: #2667E9;
|
||||
}
|
||||
}
|
||||
|
||||
.picker-body {
|
||||
max-height: 600rpx;
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
.picker-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.picker-item-active {
|
||||
color: #2667E9;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 区域颜色圆点
|
||||
.area-color-dot {
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
border-radius: 50%;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.address-popup {
|
||||
width: 600rpx;
|
||||
background: #fff;
|
||||
|
||||
@@ -1,58 +1,91 @@
|
||||
<template>
|
||||
<view class="page padding">
|
||||
<view class="padding bg-white radius">
|
||||
<view class="flex margin-bottom">
|
||||
<view class="form-label 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="form-label 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="form-label margin-bottom margin-top">
|
||||
<view class="text-gray">投资资金(计划)</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="form-label margin-bottom margin-top">
|
||||
<view class="text-gray">投资资金(实际)</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="form-label margin-bottom margin-top">
|
||||
<view class="text-gray">限定整改时间</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 class="form-label margin-bottom margin-top">
|
||||
<view class="text-gray">整改人员</view>
|
||||
<view class="text-red">*</view>
|
||||
<view class="margin-left-sm text-black" v-if="selectedUserName">{{ selectedUserName }}</view>
|
||||
</view>
|
||||
<up-select v-model:current="cateId" :options="cateList" @select="selectItem"></up-select>
|
||||
<!-- 点击打开人员选择弹窗 -->
|
||||
<view class="select-trigger" @click="showUserPopup = true">
|
||||
<view class="select-content" :class="{ 'text-gray': selectedUsers.length === 0 }">
|
||||
{{ selectedUsers.length > 0 ? selectedUsersText : '请选择整改人员(可多选)' }}
|
||||
</view>
|
||||
<text class="cuIcon-unfold"></text>
|
||||
</view>
|
||||
|
||||
<view class="flex margin-bottom">
|
||||
<!-- 人员多选弹窗 -->
|
||||
<u-popup :show="showUserPopup" mode="bottom" round="20" @close="showUserPopup = false">
|
||||
<view class="user-popup">
|
||||
<view class="popup-header">
|
||||
<view class="popup-title text-bold">选择整改人员</view>
|
||||
<view class="popup-close" @click="showUserPopup = false">×</view>
|
||||
</view>
|
||||
<view class="popup-body">
|
||||
<up-checkbox-group v-model="selectedUserIds" placement="column" @change="onUserChange">
|
||||
<view class="user-item" v-for="item in cateList" :key="item.id">
|
||||
<up-checkbox
|
||||
:label="item.name"
|
||||
:name="item.id"
|
||||
activeColor="#2667E9"
|
||||
shape="square"
|
||||
></up-checkbox>
|
||||
</view>
|
||||
</up-checkbox-group>
|
||||
</view>
|
||||
<view class="popup-footer">
|
||||
<button class="btn-cancel" @click="showUserPopup = false">取消</button>
|
||||
<button class="btn-confirm bg-blue" @click="confirmUserSelect">确定</button>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
<view class="form-label 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" @click="handleSubmit">提交整改</button>
|
||||
<button class="bg-blue round margin-top-xl" @click="handleSubmit">{{ isEdit ? '保存修改' : '提交整改' }}</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {ref,reactive,onMounted} from 'vue'
|
||||
import {ref,reactive,computed} from 'vue'
|
||||
import {onLoad} from '@dcloudio/uni-app'
|
||||
import {submitRectification,getDepartmentPersonUsers} from '@/request/api.js'
|
||||
import {submitRectification,getDepartmentPersonUsers,getRectifyDetail,getDeptUsersWithSubordinates} from '@/request/api.js'
|
||||
import {baseUrl,getToken} from '@/request/request.js'
|
||||
|
||||
// 从页面参数获取的ID
|
||||
const hazardId = ref('');
|
||||
const assignId = ref('');
|
||||
const rectifyId = ref(''); // 整改ID(编辑模式时使用)
|
||||
const isEdit = ref(false); // 是否为编辑模式
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
@@ -66,17 +99,42 @@
|
||||
const value1 = ref(Date.now());
|
||||
const radiovalue1 = ref('');
|
||||
|
||||
// 整改人员
|
||||
const cateId = ref('')
|
||||
// 整改人员(多选)
|
||||
const cateList = ref([])
|
||||
const selectedUserName = ref('') // 选中的人员名称
|
||||
const showUserPopup = ref(false) // 人员选择弹窗
|
||||
const selectedUserIds = ref([]) // 选中的用户ID数组
|
||||
const selectedUsers = ref([]) // 选中的用户对象数组
|
||||
|
||||
// 选中人员的显示文本
|
||||
const selectedUsersText = computed(() => {
|
||||
if (selectedUsers.value.length === 0) return '';
|
||||
if (selectedUsers.value.length <= 2) {
|
||||
return selectedUsers.value.map(u => u.name).join('、');
|
||||
}
|
||||
return `${selectedUsers.value[0].name}等${selectedUsers.value.length}人`;
|
||||
});
|
||||
|
||||
// checkbox变化事件
|
||||
const onUserChange = (ids) => {
|
||||
console.log('选中的ID:', ids);
|
||||
};
|
||||
|
||||
// 确认选择人员
|
||||
const confirmUserSelect = () => {
|
||||
// 根据选中的ID获取用户对象
|
||||
selectedUsers.value = cateList.value.filter(item => selectedUserIds.value.includes(item.id));
|
||||
showUserPopup.value = false;
|
||||
console.log('选中的整改人员:', selectedUsers.value);
|
||||
};
|
||||
|
||||
// 获取部门人员列表
|
||||
const fetchDeptUsers = async () => {
|
||||
console.log('当前hazardId:', hazardId.value);
|
||||
|
||||
try {
|
||||
const res = await getDepartmentPersonUsers();
|
||||
const res = await getDeptUsersWithSubordinates({hazardId:hazardId.value});
|
||||
if (res.code === 0 && res.data) {
|
||||
// 将部门下的用户数据扁平化为 up-select 需要的格式
|
||||
// 将部门下的用户数据扁平化
|
||||
const userList = [];
|
||||
res.data.forEach(dept => {
|
||||
if (dept.users && dept.users.length > 0) {
|
||||
@@ -95,9 +153,6 @@
|
||||
console.error('获取部门人员失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 页面加载时获取人员列表
|
||||
fetchDeptUsers();
|
||||
|
||||
// 上传图片
|
||||
const fileList1 = ref([]);
|
||||
@@ -173,6 +228,13 @@
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (selectedUsers.value.length === 0) {
|
||||
uni.showToast({
|
||||
title: '请选择整改人员',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 构建附件列表
|
||||
const attachments = fileList1.value.map(file => {
|
||||
@@ -198,14 +260,21 @@
|
||||
rectifyResult: formData.rectifyResult,
|
||||
planCost: Number(formData.planCost) || 0,
|
||||
actualCost: Number(formData.actualCost) || 0,
|
||||
attachments: attachments
|
||||
attachments: attachments,
|
||||
// 整改人员ID数组
|
||||
rectifyUserIds: selectedUserIds.value.map(id => Number(id))
|
||||
};
|
||||
|
||||
// 编辑模式需要传递rectifyId
|
||||
if (rectifyId.value) {
|
||||
params.rectifyId = rectifyId.value;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await submitRectification(params);
|
||||
if (res.code === 0) {
|
||||
uni.showToast({
|
||||
title: '提交成功',
|
||||
title: isEdit.value ? '保存成功' : '提交成功',
|
||||
icon: 'success'
|
||||
});
|
||||
setTimeout(() => {
|
||||
@@ -213,19 +282,76 @@
|
||||
}, 1500);
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg || '提交失败',
|
||||
title: res.msg || (isEdit.value ? '保存失败' : '提交失败'),
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交整改失败:', error);
|
||||
uni.showToast({
|
||||
title: '您不是整改人员',
|
||||
title: '操作失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 获取整改详情(编辑模式)
|
||||
const fetchRectifyDetail = async () => {
|
||||
try {
|
||||
uni.showLoading({ title: '加载中...' });
|
||||
const res = await getRectifyDetail({ rectifyId: rectifyId.value });
|
||||
uni.hideLoading();
|
||||
|
||||
if (res.code === 0 && res.data) {
|
||||
const data = res.data;
|
||||
// 回显表单数据
|
||||
formData.rectifyPlan = data.rectifyPlan || '';
|
||||
formData.rectifyResult = data.rectifyResult || '';
|
||||
formData.planCost = data.planCost ? String(data.planCost) : '';
|
||||
formData.actualCost = data.actualCost ? String(data.actualCost) : '';
|
||||
|
||||
// 保存hazardId和assignId
|
||||
hazardId.value = data.hazardId || '';
|
||||
assignId.value = data.assignId || '';
|
||||
|
||||
// 回显附件
|
||||
if (data.attachments && data.attachments.length > 0) {
|
||||
fileList1.value = data.attachments.map(att => ({
|
||||
url: att.filePath.startsWith('http') ? att.filePath : (baseUrl.replace('/api', '') + att.filePath),
|
||||
status: 'success',
|
||||
message: '',
|
||||
name: att.fileName,
|
||||
type: att.fileType,
|
||||
filePath: att.filePath // 保存原始路径用于提交
|
||||
}));
|
||||
}
|
||||
|
||||
// 回显整改人员(如果有)
|
||||
if (data.memberIds) {
|
||||
const memberIdArr = data.memberIds.split(',').map(id => String(id.trim()));
|
||||
selectedUserIds.value = memberIdArr;
|
||||
// 等人员列表加载完成后再匹配
|
||||
setTimeout(() => {
|
||||
selectedUsers.value = cateList.value.filter(item => memberIdArr.includes(item.id));
|
||||
}, 500);
|
||||
} else if (data.rectifierId) {
|
||||
// 如果没有memberIds,使用rectifierId
|
||||
selectedUserIds.value = [String(data.rectifierId)];
|
||||
setTimeout(() => {
|
||||
selectedUsers.value = cateList.value.filter(item => item.id === String(data.rectifierId));
|
||||
}, 500);
|
||||
}
|
||||
|
||||
// 设置页面标题
|
||||
uni.setNavigationBarTitle({ title: '编辑整改信息' });
|
||||
}
|
||||
} catch (error) {
|
||||
uni.hideLoading();
|
||||
console.error('获取整改详情失败:', error);
|
||||
uni.showToast({ title: '获取详情失败', icon: 'none' });
|
||||
}
|
||||
};
|
||||
|
||||
onLoad((options) => {
|
||||
if (options.hazardId) {
|
||||
hazardId.value = options.hazardId;
|
||||
@@ -233,13 +359,18 @@
|
||||
if (options.assignId) {
|
||||
assignId.value = options.assignId;
|
||||
}
|
||||
|
||||
// 在hazardId赋值后调用,确保有值
|
||||
fetchDeptUsers();
|
||||
|
||||
// 编辑模式
|
||||
if (options.rectifyId) {
|
||||
rectifyId.value = options.rectifyId;
|
||||
isEdit.value = options.isEdit === '1';
|
||||
// 获取整改详情
|
||||
fetchRectifyDetail();
|
||||
}
|
||||
});
|
||||
// 选择整改人员
|
||||
const selectItem = (item) => {
|
||||
console.log('选择的整改人员:', item);
|
||||
cateId.value = item.id;
|
||||
selectedUserName.value = item.name; // 显示选中的人员名称
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -247,6 +378,17 @@
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
}
|
||||
|
||||
// 表单标签样式 - 让*号和文字对齐
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.text-red {
|
||||
margin-left: 4rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.date-input {
|
||||
background: #fff;
|
||||
@@ -260,4 +402,87 @@
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
// 选择触发器样式
|
||||
.select-trigger {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: #fff;
|
||||
border: 1rpx solid #dcdfe6;
|
||||
border-radius: 8rpx;
|
||||
padding: 20rpx 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.select-content {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
// 人员选择弹窗
|
||||
.user-popup {
|
||||
background: #fff;
|
||||
|
||||
.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: 20rpx 30rpx;
|
||||
max-height: 600rpx;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.user-item {
|
||||
padding: 24rpx 0;
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.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>
|
||||
@@ -6,9 +6,9 @@
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
<view class="margin-bottom">
|
||||
<view v-if="rectifyAttachments.length > 0" class="margin-top">
|
||||
<view v-if="detailData.attachments && detailData.attachments.length > 0" class="margin-top">
|
||||
<view class="flex" style="flex-wrap: wrap; gap: 10rpx;">
|
||||
<image v-for="(img, idx) in rectifyAttachments" :key="idx" :src="getFullPath(img.filePath)" style="width: 136rpx;height: 136rpx;border-radius: 16rpx;" mode="aspectFill" @click="previewRectifyImage(idx)"></image>
|
||||
<image v-for="(img, idx) in detailData.attachments" :key="idx" :src="getFullPath(img.filePath)" style="width: 136rpx;height: 136rpx;border-radius: 16rpx;" mode="aspectFill" @click="previewHazardImage(idx)"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="text-gray text-sm">暂无图片</view>
|
||||
@@ -44,7 +44,12 @@
|
||||
<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 margin-top margin-bottom">隐患区域</view>
|
||||
<view class="bg-gray padding radius">{{ detailData.areaName || '暂无' }}</view>
|
||||
|
||||
<view class="flex margin-bottom margin-top">
|
||||
<view class="text-gray">隐患描述</view>
|
||||
<view class="text-red">*</view>
|
||||
</view>
|
||||
@@ -74,6 +79,7 @@
|
||||
source: '',
|
||||
description: '',
|
||||
address: '',
|
||||
areaName: '', // 隐患区域名称
|
||||
createdAt: '',
|
||||
attachments: []
|
||||
});
|
||||
@@ -93,8 +99,9 @@
|
||||
};
|
||||
|
||||
// 图片预览 - 隐患图片
|
||||
const previewImage = (attachments, index) => {
|
||||
const urls = attachments.map(item => getFullPath(item.filePath));
|
||||
const previewHazardImage = (index) => {
|
||||
if (!detailData.attachments || detailData.attachments.length === 0) return;
|
||||
const urls = detailData.attachments.map(item => getFullPath(item.filePath));
|
||||
uni.previewImage({
|
||||
current: index,
|
||||
urls: urls
|
||||
@@ -116,6 +123,8 @@
|
||||
const res = await getHiddenDangerDetail({ hazardId, assignId });
|
||||
if (res.code === 0 && res.data) {
|
||||
Object.assign(detailData, res.data);
|
||||
console.log('隐患详情数据:', res.data);
|
||||
console.log('隐患附件:', res.data.attachments);
|
||||
|
||||
// 提取整改附件:assigns[0].rectify.attachments
|
||||
if (res.data.assigns && res.data.assigns.length > 0) {
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<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>
|
||||
<image class="avatar-image" :src="getImageUrl(userInfo.avatar) || defaultAvatar" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="padding-left">
|
||||
<view class="padding-left" style="display: flex;flex-direction: column;gap: 10rpx;justify-content: center;align-items: center;">
|
||||
<view class="text-bold">{{ userInfo.deptName || '未知部门' }}</view>
|
||||
<view class="flex padding-top-xs">
|
||||
<view>用户:</view>
|
||||
@@ -82,7 +82,8 @@
|
||||
</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>
|
||||
<button v-if="item.finishedCount < item.totalCount" class="cu-btn round lg bg-blue" @click.stop="goDetails(item)">开始检查</button>
|
||||
<view v-else class="cu-btn round lg bg-green">已完成</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -92,10 +93,13 @@
|
||||
<view class="border-tite"></view>
|
||||
<view class="text-bold margin-left-xs">我的隐患排查</view>
|
||||
</view>
|
||||
<view class="list-list padding margin-bottom" v-for="(item,index) in hiddenDangerData" :key="item.id" @click="HazardList()">
|
||||
<view class="flex text-bold">
|
||||
<view>隐患</view>
|
||||
<view class="text-bold margin-left">#15</view>
|
||||
<view class="list-list padding margin-bottom" v-for="(item,index) in hiddenDangerData" :key="item.hazardId">
|
||||
<view class="flex text-bold justify-between">
|
||||
<view class="flex">
|
||||
<view>隐患</view>
|
||||
<view class="text-bold margin-left">#{{ index + 1 }}</view>
|
||||
</view>
|
||||
<view class="text-blue">{{item.statusName}}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">标题:</view>
|
||||
@@ -111,20 +115,32 @@
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">隐患等级:</view>
|
||||
<view>{{item.levelName}}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">隐患状态:</view>
|
||||
<view>{{item.statusName}}</view>
|
||||
<view class="level-tag" :class="{
|
||||
'level-minor': item.levelName === '轻微隐患',
|
||||
'level-normal': item.levelName === '一般隐患',
|
||||
'level-major': item.levelName === '重大隐患'
|
||||
}">{{item.levelName}}</view>
|
||||
</view>
|
||||
<view class="flex margin-top">
|
||||
<view class="text-gray">发现时间:</view>
|
||||
<view>{{item.createdAt}}</view>
|
||||
</view>
|
||||
<view class="margin-top margin-bottom flex" style="gap: 5rpx;">
|
||||
<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 class="margin-top margin-bottom flex justify-end" style="gap: 10rpx;">
|
||||
<!-- 所有状态都显示查看详情 -->
|
||||
<button class="cu-btn round lg light bg-blue" @click.stop="viewHazardDetail(item)">查看详情</button>
|
||||
<!-- 待整改状态:canEdit为true时显示隐患交办和立即整改 -->
|
||||
<button v-if="item.statusName === '待整改' && item.canEdit"
|
||||
class="cu-btn round lg light bg-blue" @click.stop="assignHazard(item)">隐患交办</button>
|
||||
<button v-if="item.statusName === '待整改' && item.canEdit"
|
||||
class="cu-btn round lg bg-blue" @click.stop="goRectification(item)">立即整改</button>
|
||||
<!-- 待验收显示编辑整改信息和立即验收 -->
|
||||
<button v-if="item.statusName === '待验收' && item.canEdit"
|
||||
class="cu-btn round lg light bg-blue" @click.stop="editRectification(item)">编辑整改信息</button>
|
||||
<button v-if="item.statusName === '待验收' && canAcceptance"
|
||||
class="cu-btn round lg bg-blue" @click.stop="goAcceptance(item)">立即验收</button>
|
||||
<!-- 待交办显示隐患交办 -->
|
||||
<button v-if="item.statusName === '待交办'"
|
||||
class="cu-btn round lg bg-blue" @click.stop="assignHazard(item)">隐患交办</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -133,35 +149,73 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { onLoad } from '@dcloudio/uni-app';
|
||||
import { ref, reactive, computed } from 'vue';
|
||||
// import { onLoad } from '@dcloudio/uni-app';
|
||||
import {getCheckPlanList,getHiddenDangerList} from '@/request/api.js'
|
||||
|
||||
import { getProfileDetail } from '@/request/three_one_api/info.js';
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import { baseUrl } from '@/request/request.js';
|
||||
const loading = ref(true);
|
||||
|
||||
const defaultAvatar = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg';
|
||||
|
||||
// 用户信息
|
||||
const userInfo = reactive({
|
||||
userId: '',
|
||||
username: '',
|
||||
nickName: '',
|
||||
deptId: '',
|
||||
deptName: ''
|
||||
deptName: '',
|
||||
role: '',
|
||||
avatar: ''
|
||||
});
|
||||
|
||||
// 获取用户信息
|
||||
const getUserInfo = () => {
|
||||
// 获取用户角色,判断是否有验收权限(admin或manage才能验收)
|
||||
const canAcceptance = computed(() => {
|
||||
return userInfo.role === 'admin' || userInfo.role === 'manage';
|
||||
});
|
||||
|
||||
// 获取图片完整URL(用于显示)
|
||||
const getImageUrl = (path) => {
|
||||
if (!path) return '';
|
||||
if (path.startsWith('http')) return path;
|
||||
return baseUrl + path;
|
||||
};
|
||||
|
||||
// 获取用户信息(从接口获取)
|
||||
const getUserInfo = async () => {
|
||||
try {
|
||||
const storedUserInfo = uni.getStorageSync('userInfo');
|
||||
if (storedUserInfo) {
|
||||
const info = JSON.parse(storedUserInfo);
|
||||
userInfo.userId = info.userId || '';
|
||||
userInfo.username = info.username || '';
|
||||
userInfo.nickName = info.nickName || '';
|
||||
userInfo.deptId = info.deptId || '';
|
||||
userInfo.deptName = info.deptName || '';
|
||||
const res = await getProfileDetail();
|
||||
if (res.code === 0 && res.data) {
|
||||
userInfo.userId = res.data.userId || '';
|
||||
userInfo.username = res.data.userName || '';
|
||||
userInfo.nickName = res.data.nickName || '';
|
||||
userInfo.deptId = res.data.deptId || '';
|
||||
userInfo.deptName = res.data.deptName || '';
|
||||
userInfo.avatar = res.data.avatar || '';
|
||||
// 获取角色信息
|
||||
if (res.data.roles && res.data.roles.length > 0) {
|
||||
userInfo.role = res.data.roles[0].roleKey || '';
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取用户信息失败:', e);
|
||||
// 如果接口失败,尝试从本地存储获取
|
||||
try {
|
||||
const storedUserInfo = uni.getStorageSync('userInfo');
|
||||
if (storedUserInfo) {
|
||||
const info = JSON.parse(storedUserInfo);
|
||||
userInfo.userId = info.userId || '';
|
||||
userInfo.username = info.username || '';
|
||||
userInfo.nickName = info.nickName || '';
|
||||
userInfo.deptId = info.deptId || '';
|
||||
userInfo.deptName = info.deptName || '';
|
||||
userInfo.role = info.role || '';
|
||||
userInfo.avatar = info.avatar || '';
|
||||
}
|
||||
} catch (storageError) {
|
||||
console.error('从本地存储获取用户信息失败:', storageError);
|
||||
}
|
||||
}
|
||||
};
|
||||
const infoList = ref([{
|
||||
@@ -264,9 +318,15 @@
|
||||
};
|
||||
|
||||
// 页面加载时调用接口
|
||||
onLoad(() => {
|
||||
// onLoad(() => {
|
||||
// getUserInfo();
|
||||
// getCheckPlanLists();
|
||||
// });
|
||||
// 页面每次显示时都会加载数据
|
||||
onShow(() => {
|
||||
getUserInfo();
|
||||
getCheckPlanLists();
|
||||
getHiddenDangerLists();
|
||||
});
|
||||
//我的隐患排查
|
||||
const hiddenDangerParams = ref({
|
||||
@@ -296,6 +356,42 @@
|
||||
getHiddenDangerLists();
|
||||
|
||||
});
|
||||
|
||||
// ========== 隐患排查相关跳转函数 ==========
|
||||
// 查看隐患详情
|
||||
const viewHazardDetail = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/hiddendanger/view?hazardId=${item.hazardId}&assignId=${item.assignId}`
|
||||
})
|
||||
}
|
||||
|
||||
// 立即整改(待整改状态)
|
||||
const goRectification = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/hiddendanger/rectification?hazardId=${item.hazardId}&assignId=${item.assignId}`
|
||||
})
|
||||
}
|
||||
|
||||
// 编辑整改信息(待验收状态)
|
||||
const editRectification = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/hiddendanger/rectification?rectifyId=${item.rectifyId}&isEdit=1`
|
||||
})
|
||||
}
|
||||
|
||||
// 立即验收
|
||||
const goAcceptance = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/hiddendanger/acceptance?hazardId=${item.hazardId}&assignId=${item.assignId}&rectifyId=${item.rectifyId}`
|
||||
})
|
||||
}
|
||||
|
||||
// 隐患交办
|
||||
const assignHazard = (item) => {
|
||||
uni.navigateTo({
|
||||
url: `/pages/hiddendanger/assignment?hazardId=${item.hazardId}&assignId=${item.assignId}`
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@@ -309,7 +405,13 @@
|
||||
z-index: 10;
|
||||
min-height: calc(100vh - 400rpx);
|
||||
}
|
||||
.content {}
|
||||
|
||||
// 头像图片样式
|
||||
.avatar-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.grid-list {
|
||||
gap: 30rpx;
|
||||
@@ -370,4 +472,31 @@
|
||||
font-size: 28rpx;
|
||||
color: #2667E9;
|
||||
}
|
||||
|
||||
// 隐患等级标签样式
|
||||
.level-tag {
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
// 轻微隐患
|
||||
.level-minor {
|
||||
background: #F6FFED;
|
||||
border: 2rpx solid #B7EB8F;
|
||||
color: #52C41A;
|
||||
}
|
||||
|
||||
// 一般隐患
|
||||
.level-normal {
|
||||
background: #FFF7E6;
|
||||
border: 2rpx solid #FFD591;
|
||||
color: #FA8C16;
|
||||
}
|
||||
|
||||
// 重大隐患
|
||||
.level-major {
|
||||
background: #FFF1F0;
|
||||
border: 2rpx solid #FFA39E;
|
||||
color: #F5222D;
|
||||
}
|
||||
</style>
|
||||
@@ -18,10 +18,10 @@
|
||||
<input class="sl-input" v-model="password" type="text" maxlength="32" placeholder="请输入密码" :password="showPassword"/>
|
||||
<image class="eye-img" :src="showPassword ? '/static/index/cl.png' : '/static/index/op.png'" @click="changePassword"></image>
|
||||
</view>
|
||||
<view class="agreement">
|
||||
<!-- <view class="agreement">
|
||||
<navigator url="reg" open-type="navigate" class="link">注册成员账号</navigator>
|
||||
<navigator url="forget" open-type="navigate" class="link">忘记密码?</navigator>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
|
||||
<view class="padding-lr">
|
||||
@@ -32,10 +32,10 @@
|
||||
<text>登录普通成员</text>
|
||||
</view> -->
|
||||
|
||||
<view class="button-report margin-top" hover-class="button-hover" @tap="goToReport">
|
||||
<!-- <view class="button-report margin-top" hover-class="button-hover" @tap="goToReport">
|
||||
<image src="/static/index/photos.png" class="icon-image"></image>
|
||||
<text>随手拍举报</text>
|
||||
</view>
|
||||
</view> -->
|
||||
|
||||
<!-- <view class="protocol-box">
|
||||
<navigator url="agreement" open-type="navigate" class="protocol-link">《用户协议》</navigator>
|
||||
@@ -112,7 +112,9 @@ const handleLogin = async () => {
|
||||
username: res.data.username,
|
||||
nickName: res.data.nickName,
|
||||
deptId: res.data.deptId,
|
||||
deptName: res.data.deptName
|
||||
deptName: res.data.deptName,
|
||||
role:res.data.role,
|
||||
isDept:res.data.isDept
|
||||
};
|
||||
uni.setStorageSync('userInfo', JSON.stringify(userInfo));
|
||||
|
||||
|
||||
@@ -1,38 +1,50 @@
|
||||
<template>
|
||||
<view class=" page padding ">
|
||||
<view class=" padding bg-white radius margin-bottom" v-for="(item,index) in list" :key="item.id">
|
||||
<view class="flex justify-between align-center">
|
||||
<view class="page padding">
|
||||
<!-- 成员管理卡片 -->
|
||||
<view class="member-card bg-white radius">
|
||||
<!-- 卡片头部:公司名称 + 角色标签 -->
|
||||
<view class="card-header">
|
||||
<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 class="border-line"></view>
|
||||
<view class="text-bold margin-left-sm">{{ userInfo.deptName || '未知部门' }}</view>
|
||||
</view>
|
||||
<view class="tag-outline">负责人</view>
|
||||
<view class="role-tag">{{ roleText }}</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 class="member-list">
|
||||
<view
|
||||
class="member-item"
|
||||
v-for="(item, index) in list"
|
||||
:key="item.userId"
|
||||
:class="{ 'border-bottom': index < list.length - 1 }"
|
||||
>
|
||||
<view class="cu-avatar radius lg bg-gray" style="background-image:url(https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png);"></view>
|
||||
<view class="member-info">
|
||||
<view class="flex align-center">
|
||||
<text class="member-name">{{ item.nickName }}</text>
|
||||
<view class="status-tag" :class="item.statusName === '正常' ? 'status-normal' : 'status-locked'">
|
||||
{{ item.statusName }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="member-phone text-gray">
|
||||
<text>手机:{{ item.phonenumber || '未设置' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<button class="btn-lock bg-blue" @click="Lock(item)">
|
||||
{{ item.status === '1' ? '解锁' : '锁定' }}
|
||||
</button>
|
||||
</view>
|
||||
<view class="margin-left">
|
||||
<view class="flex">
|
||||
<view>{{item.nickName}}</view>
|
||||
<view class="margin-left-xs light bg-olive padding-left-xs padding-right-xs">{{item.statusName}}</view>
|
||||
</view>
|
||||
<view class="flex text-gray">
|
||||
<view>手机设置:</view>
|
||||
<view>{{item.phonenumber}}</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(item)">{{ item.lockStatus === 1 ? '解锁' : '锁定' }}</button>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 添加成员按钮 -->
|
||||
<view class="add-btn-wrapper">
|
||||
<button class="add-btn" @click="showPopup = true">
|
||||
<text class="cuIcon-add"></text>
|
||||
<text>添加成员</text>
|
||||
</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">
|
||||
@@ -42,43 +54,49 @@
|
||||
<view class="popup-close" @click="showPopup = false">×</view>
|
||||
</view>
|
||||
|
||||
<view class="popup-body">
|
||||
<scroll-view class="popup-body" scroll-y>
|
||||
<!-- 用户名 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">用户名<text class="text-red">*</text></view>
|
||||
<input class="form-input" v-model="formData.username" placeholder="请输入用户名" />
|
||||
<up-input v-model="formData.username" placeholder="请输入用户名" border="surround"></up-input>
|
||||
</view>
|
||||
|
||||
<!-- 昵称 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">昵称</view>
|
||||
<input class="form-input" v-model="formData.nickname" placeholder="请输入昵称" />
|
||||
<up-input v-model="formData.nickname" placeholder="请输入昵称" border="surround"></up-input>
|
||||
</view>
|
||||
|
||||
<!-- 手机号 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">手机号</view>
|
||||
<input class="form-input" v-model="formData.phone" placeholder="请输入手机号" type="number" />
|
||||
<up-input v-model="formData.phone" placeholder="请输入手机号" type="number" border="surround"></up-input>
|
||||
</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 />
|
||||
<up-input v-model="formData.password" placeholder="请输入密码(6-16位)" password border="surround"></up-input>
|
||||
</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 || '请选择主部门' }}
|
||||
<view class="form-label">角色类型<text class="text-red">*</text></view>
|
||||
<view class="form-select" @click="showRolePicker = true">
|
||||
<text :class="selectedRoleName ? '' : 'text-gray'">
|
||||
{{ selectedRoleName || '请选择角色类型' }}
|
||||
</text>
|
||||
<text class="cuIcon-unfold"></text>
|
||||
</view>
|
||||
<up-picker :show="showDeptPicker" :columns="deptColumns" @confirm="onDeptConfirm"
|
||||
@cancel="showDeptPicker = false" @close="showDeptPicker = false"></up-picker>
|
||||
<up-picker
|
||||
:show="showRolePicker"
|
||||
:columns="roleColumns"
|
||||
@confirm="onRoleConfirm"
|
||||
@cancel="showRolePicker = false"
|
||||
@close="showRolePicker = false"
|
||||
></up-picker>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<view class="popup-footer">
|
||||
<button class="btn-cancel" @click="showPopup = false">取消</button>
|
||||
@@ -91,259 +109,396 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref,reactive } from 'vue';
|
||||
import { addMember,getMemberList,lockOrUnlockMember} from '@/request/api.js';
|
||||
//成员列表
|
||||
const list = ref([]);
|
||||
getMemberList().then(res => {
|
||||
list.value = res.data;
|
||||
});
|
||||
const showPopup = ref(false);
|
||||
const showDeptPicker = ref(false);
|
||||
import { ref, reactive, computed, onMounted } from 'vue';
|
||||
import { addMember, getMemberList, lockOrUnlockMember } from '@/request/api.js';
|
||||
|
||||
const formData = reactive({
|
||||
username: '',
|
||||
nickname: '',
|
||||
phone: '',
|
||||
password: '',
|
||||
department: ''
|
||||
});
|
||||
const handleSubmit = async () => {
|
||||
// 表单验证
|
||||
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;
|
||||
}
|
||||
// 用户信息(从storage获取)
|
||||
const userInfo = ref({
|
||||
deptId: '',
|
||||
deptName: '',
|
||||
nickName: '',
|
||||
role: '',
|
||||
userId: '',
|
||||
username: ''
|
||||
});
|
||||
|
||||
// 构建请求参数(根据接口要求的字段名)
|
||||
const params = {
|
||||
userName: formData.username,
|
||||
nickName: formData.nickname || '',
|
||||
phonenumber: formData.phone || '',
|
||||
password: formData.password,
|
||||
roleType: 'common'
|
||||
};
|
||||
// 角色显示文本
|
||||
const roleText = computed(() => {
|
||||
const role = userInfo.value.role;
|
||||
if (role === 'manage' || role === 'admin') {
|
||||
return '管理人员';
|
||||
} else if (role === 'common') {
|
||||
return '执行人员';
|
||||
}
|
||||
return '成员';
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await addMember(params);
|
||||
if (res.code === 0) {
|
||||
uni.showToast({
|
||||
title: '添加成功',
|
||||
icon: 'success'
|
||||
});
|
||||
showPopup.value = false;
|
||||
// 重置表单
|
||||
formData.username = '';
|
||||
formData.nickname = '';
|
||||
formData.phone = '';
|
||||
formData.password = '';
|
||||
formData.department = '';
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: res.msg || '添加失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('添加成员失败:', error);
|
||||
uni.showToast({
|
||||
title: '请求失败',
|
||||
icon: 'none'
|
||||
});
|
||||
// 获取用户信息
|
||||
const getUserInfo = () => {
|
||||
try {
|
||||
const userInfoStr = uni.getStorageSync('userInfo');
|
||||
if (userInfoStr) {
|
||||
userInfo.value = JSON.parse(userInfoStr);
|
||||
console.log('用户信息:', userInfo.value);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 成员列表
|
||||
const list = ref([]);
|
||||
|
||||
// 获取成员列表
|
||||
const fetchMemberList = async () => {
|
||||
try {
|
||||
const res = await getMemberList();
|
||||
if (res.code === 0 && res.data) {
|
||||
list.value = res.data;
|
||||
console.log('成员列表:', res.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取成员列表失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// 弹窗控制
|
||||
const showPopup = ref(false);
|
||||
const showRolePicker = ref(false);
|
||||
const selectedRoleName = ref('');
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
username: '',
|
||||
nickname: '',
|
||||
phone: '',
|
||||
password: '',
|
||||
roleType: ''
|
||||
});
|
||||
|
||||
// 角色类型选择器数据
|
||||
const roleColumns = reactive([
|
||||
['管理员', '普通成员']
|
||||
]);
|
||||
|
||||
// 角色名称与值的映射
|
||||
const roleMap = {
|
||||
'管理员': 'manage',
|
||||
'普通成员': 'common'
|
||||
};
|
||||
|
||||
// 角色类型选择确认
|
||||
const onRoleConfirm = (e) => {
|
||||
if (e.value && e.value.length > 0) {
|
||||
selectedRoleName.value = e.value[0];
|
||||
formData.roleType = roleMap[e.value[0]];
|
||||
}
|
||||
showRolePicker.value = false;
|
||||
};
|
||||
|
||||
// 重置表单
|
||||
const resetForm = () => {
|
||||
formData.username = '';
|
||||
formData.nickname = '';
|
||||
formData.phone = '';
|
||||
formData.password = '';
|
||||
formData.roleType = '';
|
||||
selectedRoleName.value = '';
|
||||
};
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
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.roleType) {
|
||||
uni.showToast({ title: '请选择角色类型', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
const params = {
|
||||
userName: formData.username,
|
||||
nickName: formData.nickname || '',
|
||||
phonenumber: formData.phone || '',
|
||||
password: formData.password,
|
||||
roleType: formData.roleType
|
||||
};
|
||||
|
||||
// 锁定/解锁成员
|
||||
const Lock = (item) => {
|
||||
// 当前是锁定状态则解锁,否则锁定
|
||||
const isLocked = item.lockStatus === 1;
|
||||
const actionText = isLocked ? '解锁' : '锁定';
|
||||
const newLockStatus = isLocked ? 0 : 1;
|
||||
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: `确定要${actionText}该成员吗?`,
|
||||
confirmColor: '#2667E9',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
const result = await lockOrUnlockMember({
|
||||
userId: item.userId,
|
||||
lockStatus: newLockStatus
|
||||
});
|
||||
if (result.code === 0) {
|
||||
uni.showToast({
|
||||
title: `${actionText}成功`,
|
||||
icon: 'success'
|
||||
});
|
||||
// 更新本地状态
|
||||
item.lockStatus = newLockStatus;
|
||||
item.statusName = newLockStatus === 1 ? '已锁定' : '正常';
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: result.msg || `${actionText}失败`,
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`${actionText}成员失败:`, error);
|
||||
uni.showToast({
|
||||
title: '请求失败',
|
||||
icon: 'none'
|
||||
});
|
||||
try {
|
||||
const res = await addMember(params);
|
||||
if (res.code === 0) {
|
||||
uni.showToast({ title: '添加成功', icon: 'success' });
|
||||
showPopup.value = false;
|
||||
resetForm();
|
||||
// 刷新成员列表
|
||||
fetchMemberList();
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '添加失败', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('添加成员失败:', error);
|
||||
uni.showToast({ title: '请求失败', icon: 'none' });
|
||||
}
|
||||
};
|
||||
|
||||
// 锁定/解锁成员
|
||||
const Lock = (item) => {
|
||||
const isLocked = item.status === '1';
|
||||
const actionText = isLocked ? '解锁' : '锁定';
|
||||
const newStatus = isLocked ? '0' : '1';
|
||||
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: `确定要${actionText}该成员吗?`,
|
||||
confirmColor: '#2667E9',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
const result = await lockOrUnlockMember({
|
||||
userId: item.userId,
|
||||
lockStatus: Number(newStatus)
|
||||
});
|
||||
if (result.code === 0) {
|
||||
uni.showToast({ title: `${actionText}成功`, icon: 'success' });
|
||||
// 更新本地状态
|
||||
item.status = newStatus;
|
||||
item.statusName = newStatus === '1' ? '已锁定' : '正常';
|
||||
} else {
|
||||
uni.showToast({ title: result.msg || `${actionText}失败`, icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`${actionText}成员失败:`, error);
|
||||
uni.showToast({ title: '请求失败', icon: 'none' });
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
//选择部门(顶部切换用)
|
||||
const show = ref(false);
|
||||
const columns = reactive([
|
||||
['湘西自治州和谐网络科技有限公司', '湘西自治州和谐云科技有限公司']
|
||||
]);
|
||||
|
||||
// 主部门选择器数据
|
||||
const deptColumns = reactive([
|
||||
['湘西自治州和谐网络科技有限公司', '湘西自治州和谐云科技有限公司', '研发部门', '深圳总公司', '若依科技']
|
||||
]);
|
||||
|
||||
// 主部门选择确认
|
||||
const onDeptConfirm = (e) => {
|
||||
console.log('选择的部门:', e);
|
||||
// e.value 是选中的值数组
|
||||
if (e.value && e.value.length > 0) {
|
||||
formData.department = e.value[0];
|
||||
}
|
||||
showDeptPicker.value = false;
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
// 页面加载
|
||||
onMounted(() => {
|
||||
getUserInfo();
|
||||
fetchMemberList();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
}
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
}
|
||||
|
||||
.border-tite {
|
||||
// 成员卡片
|
||||
.member-card {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// 卡片头部
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
|
||||
.border-line {
|
||||
width: 8rpx;
|
||||
height: 32rpx;
|
||||
background: #2667E9;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-outline {
|
||||
padding: 4rpx 16rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #EEF3FF;
|
||||
color: #2E7CF3;
|
||||
font-size: 24rpx;
|
||||
// 角色标签
|
||||
.role-tag {
|
||||
padding: 8rpx 24rpx;
|
||||
background: #EEF3FF;
|
||||
color: #2667E9;
|
||||
font-size: 24rpx;
|
||||
border-radius: 24rpx 0 0 24rpx;
|
||||
margin-right: -30rpx;
|
||||
}
|
||||
|
||||
// 成员列表
|
||||
.member-list {
|
||||
padding: 0 30rpx;
|
||||
}
|
||||
|
||||
// 成员项
|
||||
.member-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx 0;
|
||||
|
||||
&.border-bottom {
|
||||
border-bottom: 1rpx solid #f5f5f5;
|
||||
}
|
||||
|
||||
.cu-avatar {
|
||||
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;
|
||||
// 成员信息
|
||||
.member-info {
|
||||
flex: 1;
|
||||
margin-left: 20rpx;
|
||||
overflow: hidden;
|
||||
|
||||
.member-name {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.member-phone {
|
||||
font-size: 24rpx;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-confirm {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
color: #fff;
|
||||
font-size: 30rpx;
|
||||
// 状态标签
|
||||
.status-tag {
|
||||
margin-left: 12rpx;
|
||||
padding: 4rpx 12rpx;
|
||||
font-size: 22rpx;
|
||||
border-radius: 6rpx;
|
||||
|
||||
&.status-normal {
|
||||
background: #E8F5E9;
|
||||
color: #4CAF50;
|
||||
}
|
||||
</style>
|
||||
|
||||
&.status-locked {
|
||||
background: #FFEBEE;
|
||||
color: #F44336;
|
||||
}
|
||||
}
|
||||
|
||||
// 锁定按钮
|
||||
.btn-lock {
|
||||
width: 120rpx;
|
||||
height: 56rpx;
|
||||
line-height: 56rpx;
|
||||
padding: 0;
|
||||
font-size: 26rpx;
|
||||
border-radius: 28rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
// 添加成员按钮
|
||||
.add-btn-wrapper {
|
||||
padding: 30rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #fff;
|
||||
border: 2rpx dashed #2667E9;
|
||||
border-radius: 12rpx;
|
||||
color: #2667E9;
|
||||
font-size: 30rpx;
|
||||
|
||||
.cuIcon-add {
|
||||
margin-right: 10rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
// 弹出框样式
|
||||
.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: 34rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.popup-close {
|
||||
font-size: 48rpx;
|
||||
color: #999;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.popup-body {
|
||||
padding: 30rpx;
|
||||
max-height: 700rpx;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 80rpx;
|
||||
border: 2rpx solid #dadbde;
|
||||
border-radius: 8rpx;
|
||||
padding: 0 24rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.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>
|
||||
|
||||
@@ -1,24 +1,178 @@
|
||||
<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 class="page">
|
||||
<view class="padding bg-white margin-top">
|
||||
<!-- 旧密码 -->
|
||||
<view class="form-item solid-bottom">
|
||||
<view class="form-label">旧密码</view>
|
||||
<view class="form-input-wrap">
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.oldPassword"
|
||||
:type="showOldPwd ? 'text' : 'password'"
|
||||
placeholder="请输入旧密码"
|
||||
/>
|
||||
<view class="pwd-toggle" @click="showOldPwd = !showOldPwd">
|
||||
<text :class="showOldPwd ? 'cuIcon-attention' : 'cuIcon-attentionforbid'"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="flex justify-between padding-top padding-bottom solid-bottom">
|
||||
<view>注销账户</view>
|
||||
<view class="lg text-gray cuIcon-right"></view>
|
||||
|
||||
<!-- 新密码 -->
|
||||
<view class="form-item solid-bottom">
|
||||
<view class="form-label">新密码</view>
|
||||
<view class="form-input-wrap">
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.newPassword"
|
||||
:type="showNewPwd ? 'text' : 'password'"
|
||||
placeholder="请输入新密码"
|
||||
/>
|
||||
<view class="pwd-toggle" @click="showNewPwd = !showNewPwd">
|
||||
<text :class="showNewPwd ? 'cuIcon-attention' : 'cuIcon-attentionforbid'"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 确认密码 -->
|
||||
<view class="form-item">
|
||||
<view class="form-label">确认密码</view>
|
||||
<view class="form-input-wrap">
|
||||
<input
|
||||
class="form-input"
|
||||
v-model="formData.confirmPassword"
|
||||
:type="showConfirmPwd ? 'text' : 'password'"
|
||||
placeholder="请再次输入新密码"
|
||||
/>
|
||||
<view class="pwd-toggle" @click="showConfirmPwd = !showConfirmPwd">
|
||||
<text :class="showConfirmPwd ? 'cuIcon-attention' : 'cuIcon-attentionforbid'"></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提示信息 -->
|
||||
<view class="tips">
|
||||
<text class="text-gray text-sm">密码长度至少6位,建议包含字母和数字</text>
|
||||
</view>
|
||||
|
||||
<!-- 保存按钮 -->
|
||||
<view class="padding">
|
||||
<button class="bg-blue round" @click="handleSave" :loading="saving">保存</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { updatePassword } from '@/request/three_one_api/info.js';
|
||||
|
||||
const saving = ref(false);
|
||||
const showOldPwd = ref(false);
|
||||
const showNewPwd = ref(false);
|
||||
const showConfirmPwd = ref(false);
|
||||
|
||||
const formData = reactive({
|
||||
oldPassword: '',
|
||||
newPassword: '',
|
||||
confirmPassword: ''
|
||||
});
|
||||
|
||||
// 保存
|
||||
const handleSave = async () => {
|
||||
// 表单验证
|
||||
if (!formData.oldPassword) {
|
||||
uni.showToast({ title: '请输入旧密码', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!formData.newPassword) {
|
||||
uni.showToast({ title: '请输入新密码', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (formData.newPassword.length < 6) {
|
||||
uni.showToast({ title: '新密码长度至少6位', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (!formData.confirmPassword) {
|
||||
uni.showToast({ title: '请确认新密码', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (formData.newPassword !== formData.confirmPassword) {
|
||||
uni.showToast({ title: '两次输入的密码不一致', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
if (formData.oldPassword === formData.newPassword) {
|
||||
uni.showToast({ title: '新密码不能与旧密码相同', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
saving.value = true;
|
||||
try {
|
||||
const params = {
|
||||
oldPassword: formData.oldPassword,
|
||||
newPassword: formData.newPassword,
|
||||
confirmPassword: formData.confirmPassword
|
||||
};
|
||||
|
||||
const res = await updatePassword(params);
|
||||
if (res.code === 0) {
|
||||
uni.showToast({ title: '密码修改成功', icon: 'success' });
|
||||
// 清空表单
|
||||
formData.oldPassword = '';
|
||||
formData.newPassword = '';
|
||||
formData.confirmPassword = '';
|
||||
// 延迟返回
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '修改失败', icon: 'none' });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('修改密码失败:', err);
|
||||
uni.showToast({ title: '修改失败', icon: 'none' });
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
}
|
||||
</style>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
padding: 30rpx 0;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.form-input-wrap {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #f5f5f5;
|
||||
border-radius: 12rpx;
|
||||
padding: 0 20rpx;
|
||||
}
|
||||
|
||||
.form-input {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.pwd-toggle {
|
||||
padding: 10rpx;
|
||||
font-size: 36rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.tips {
|
||||
padding: 20rpx 30rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<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>
|
||||
<image class="avatar" :src="avatarPreview || getImageUrl(userInfo.avatar) || defaultAvatar" mode="aspectFill"></image>
|
||||
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -14,25 +14,25 @@
|
||||
<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="请输入昵称" />
|
||||
<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="text-black label-text">电话号码</view>
|
||||
<view class="flex align-center flex-sub justify-end">
|
||||
<input class="input-right" v-model="userInfo.signature" placeholder="请输入个性签名" />
|
||||
<input class="input-right" v-model="userInfo.phonenumber" placeholder="请输入电话号码" type="number" />
|
||||
<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.email" placeholder="请输入邮箱" />
|
||||
<view class="lg text-gray cuIcon-right margin-left-xs"></view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -44,15 +44,15 @@
|
||||
<view class="gender-switch">
|
||||
<view
|
||||
class="gender-item"
|
||||
:class="{ 'gender-active': userInfo.gender === 1, 'gender-male': userInfo.gender === 1 }"
|
||||
@click="userInfo.gender = 1"
|
||||
:class="{ 'gender-active': userInfo.sex === '0', 'gender-male': userInfo.sex === '0' }"
|
||||
@click="userInfo.sex = '0'"
|
||||
>
|
||||
<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"
|
||||
:class="{ 'gender-active': userInfo.sex === '1', 'gender-female': userInfo.sex === '1' }"
|
||||
@click="userInfo.sex = '1'"
|
||||
>
|
||||
<text class="cuIcon-female"></text>
|
||||
</view>
|
||||
@@ -60,42 +60,59 @@
|
||||
</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>
|
||||
<button class="bg-blue round margin-top-xl" @click="handleSave" :loading="saving">保存</button>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ref, reactive, onMounted } from 'vue';
|
||||
import { baseUrl, getToken } from '@/request/request.js';
|
||||
import { getProfileDetail, updateProfile } from '@/request/three_one_api/info.js';
|
||||
|
||||
const showDatePicker = ref(false);
|
||||
const saving = ref(false);
|
||||
const defaultAvatar = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big81005.jpg';
|
||||
const avatarPreview = ref(''); // 用于显示选择的图片临时预览
|
||||
|
||||
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'
|
||||
avatar: '', // 保存相对路径,用于提交
|
||||
nickName: '',
|
||||
phonenumber: '',
|
||||
email: '',
|
||||
sex: '0' // '0'-男 '1'-女
|
||||
});
|
||||
|
||||
// 获取图片完整URL(用于显示)
|
||||
const getImageUrl = (path) => {
|
||||
if (!path) return '';
|
||||
if (path.startsWith('http')) return path;
|
||||
return baseUrl + path;
|
||||
};
|
||||
|
||||
// 页面加载时获取个人信息
|
||||
onMounted(() => {
|
||||
loadProfileDetail();
|
||||
});
|
||||
|
||||
// 获取个人信息
|
||||
const loadProfileDetail = async () => {
|
||||
try {
|
||||
uni.showLoading({ title: '加载中...' });
|
||||
const res = await getProfileDetail();
|
||||
uni.hideLoading();
|
||||
if (res.code === 0 && res.data) {
|
||||
userInfo.avatar = res.data.avatar || '';
|
||||
userInfo.nickName = res.data.nickName || '';
|
||||
userInfo.phonenumber = res.data.phonenumber || '';
|
||||
userInfo.email = res.data.email || '';
|
||||
userInfo.sex = res.data.sex || '0';
|
||||
}
|
||||
} catch (err) {
|
||||
uni.hideLoading();
|
||||
console.error('获取个人信息失败:', err);
|
||||
}
|
||||
};
|
||||
|
||||
// 选择头像
|
||||
const chooseAvatar = () => {
|
||||
uni.chooseImage({
|
||||
@@ -103,33 +120,84 @@ const chooseAvatar = () => {
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
userInfo.avatar = res.tempFilePaths[0];
|
||||
const tempFilePath = res.tempFilePaths[0];
|
||||
// 显示临时预览
|
||||
avatarPreview.value = tempFilePath;
|
||||
// 上传获取链接
|
||||
uploadAvatar(tempFilePath);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 日期选择确认
|
||||
const confirmDate = (e) => {
|
||||
userInfo.birthday = e[0];
|
||||
showDatePicker.value = false;
|
||||
// 上传头像获取链接
|
||||
const uploadAvatar = (filePath) => {
|
||||
uni.showLoading({ title: '上传中...' });
|
||||
|
||||
uni.uploadFile({
|
||||
url: baseUrl + '/frontend/attachment/upload',
|
||||
filePath: filePath,
|
||||
name: 'file',
|
||||
header: {
|
||||
'Authorization': getToken()
|
||||
},
|
||||
success: (uploadRes) => {
|
||||
uni.hideLoading();
|
||||
try {
|
||||
const data = JSON.parse(uploadRes.data);
|
||||
if (data.code === 0 && data.data) {
|
||||
// 上传成功,保存相对路径(用于提交)
|
||||
userInfo.avatar = data.data.url || data.data;
|
||||
uni.showToast({ title: '上传成功', icon: 'success' });
|
||||
} else {
|
||||
avatarPreview.value = ''; // 上传失败,清除预览
|
||||
uni.showToast({ title: data.msg || '上传失败', icon: 'none' });
|
||||
}
|
||||
} catch (e) {
|
||||
avatarPreview.value = '';
|
||||
uni.showToast({ title: '上传失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
fail: () => {
|
||||
uni.hideLoading();
|
||||
avatarPreview.value = '';
|
||||
uni.showToast({ title: '上传失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 保存
|
||||
const handleSave = () => {
|
||||
uni.showToast({ title: '保存成功', icon: 'success' });
|
||||
};
|
||||
|
||||
// 退出登录
|
||||
const handleLogout = () => {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '确定要退出登录吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.reLaunch({ url: '/pages/login/login' });
|
||||
}
|
||||
const handleSave = async () => {
|
||||
// 表单验证
|
||||
if (!userInfo.nickName) {
|
||||
uni.showToast({ title: '请输入昵称', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
saving.value = true;
|
||||
try {
|
||||
const params = {
|
||||
nickName: userInfo.nickName,
|
||||
phonenumber: userInfo.phonenumber,
|
||||
email: userInfo.email,
|
||||
sex: userInfo.sex,
|
||||
avatar: userInfo.avatar // 提交相对路径
|
||||
};
|
||||
|
||||
const res = await updateProfile(params);
|
||||
if (res.code === 0) {
|
||||
uni.showToast({ title: '保存成功', icon: 'success' });
|
||||
setTimeout(() => {
|
||||
uni.navigateBack();
|
||||
}, 1500);
|
||||
} else {
|
||||
uni.showToast({ title: res.msg || '保存失败', icon: 'none' });
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('保存失败:', err);
|
||||
uni.showToast({ title: '保存失败', icon: 'none' });
|
||||
} finally {
|
||||
saving.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -197,4 +265,4 @@ const handleLogout = () => {
|
||||
color: #2667E9;
|
||||
background: #fff;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,101 +1,134 @@
|
||||
<template>
|
||||
<view class="title">
|
||||
<view class="padding">
|
||||
<view class="text-center margin-top-xl text-white text-bold">我的</view>
|
||||
<view class="flex justify-between align-center" style="padding-top:60rpx;" >
|
||||
<view class="flex align-center">
|
||||
<view class="cu-avatar xl round" style="background-image:url(https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg);"></view>
|
||||
<view class="margin-left">
|
||||
<view class="text-white text-lg text-bold">hhhrrrr</view>
|
||||
<view class="text-white" style="opacity: 0.8;">17374339800</view>
|
||||
<view class="page-wrapper">
|
||||
<!-- 顶部弥散渐变背景 -->
|
||||
<view class="header-bg">
|
||||
<!-- 弥散光斑效果 -->
|
||||
<view class="blur-circle circle-1"></view>
|
||||
<view class="blur-circle circle-2"></view>
|
||||
<view class="blur-circle circle-3"></view>
|
||||
|
||||
<!-- 标题 -->
|
||||
<!-- <view class="header-title">我的</view> -->
|
||||
|
||||
<!-- 用户信息区域 -->
|
||||
<view class="user-info-section">
|
||||
<view class="user-avatar">
|
||||
<image class="avatar-img" :src="getImageUrl(userInfo.avatar) || defaultAvatar" mode="aspectFill"></image>
|
||||
</view>
|
||||
<view class="user-details">
|
||||
<view class="user-name">{{ userInfo.nickName || '未设置昵称' }}</view>
|
||||
<view class="user-phone">{{ userInfo.phonenumber || '未绑定手机' }}</view>
|
||||
</view>
|
||||
<button class="edit-btn" @click="editinfo()">编辑资料</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容区域 -->
|
||||
<view class="content-area">
|
||||
<!-- 菜单卡片 -->
|
||||
<view class="menu-card">
|
||||
<!-- <view class="menu-item" @click="Helpcenter()">
|
||||
<view class="menu-left">
|
||||
<image src="/static/my/Helpcenter.png" class="menu-icon"></image>
|
||||
<text class="menu-text">帮助中心</text>
|
||||
</view>
|
||||
<text class="cuIcon-right menu-arrow"></text>
|
||||
</view> -->
|
||||
<!-- <view class="menu-item">
|
||||
<view class="menu-left">
|
||||
<image src="/static/my/CustomerService.png" class="menu-icon"></image>
|
||||
<text class="menu-text">智能客服</text>
|
||||
</view>
|
||||
<text class="cuIcon-right menu-arrow"></text>
|
||||
</view> -->
|
||||
<view class="menu-item" @click="editinfo()">
|
||||
<view class="menu-left">
|
||||
<image src="/static/my/Notification.png" class="menu-icon"></image>
|
||||
<text class="menu-text">编辑个人信息</text>
|
||||
</view>
|
||||
<text class="cuIcon-right menu-arrow"></text>
|
||||
</view>
|
||||
<view class="menu-item" @click="Account()">
|
||||
<view class="menu-left">
|
||||
<image src="/static/my/Account.png" class="menu-icon"></image>
|
||||
<text class="menu-text">修改登录密码</text>
|
||||
</view>
|
||||
<text class="cuIcon-right menu-arrow"></text>
|
||||
</view>
|
||||
<!-- <view class="menu-item">
|
||||
<view class="menu-left">
|
||||
<image src="/static/my/Delete.png" class="menu-icon"></image>
|
||||
<text class="menu-text">清除缓存</text>
|
||||
</view>
|
||||
<view class="menu-right">
|
||||
<text class="menu-value">0B</text>
|
||||
<text class="cuIcon-right menu-arrow"></text>
|
||||
</view>
|
||||
</view>
|
||||
<button class="cu-btn round edit-btn bg-blue text-white ">编辑资料</button>
|
||||
<view class="menu-item" @click="Settings()">
|
||||
<view class="menu-left">
|
||||
<image src="/static/my/Settings.png" class="menu-icon"></image>
|
||||
<text class="menu-text">通用设置</text>
|
||||
</view>
|
||||
<text class="cuIcon-right menu-arrow"></text>
|
||||
</view>
|
||||
<view class="menu-item">
|
||||
<view class="menu-left">
|
||||
<image src="/static/my/Helpcenter.png" class="menu-icon"></image>
|
||||
<text class="menu-text">关于</text>
|
||||
</view>
|
||||
<view class="menu-right">
|
||||
<text class="menu-value">1.0.0</text>
|
||||
<text class="cuIcon-right menu-arrow"></text>
|
||||
</view>
|
||||
</view> -->
|
||||
</view>
|
||||
|
||||
<!-- 退出登录按钮 -->
|
||||
<button class="logout-btn" @click="handleLogout()">退出登录</button>
|
||||
</view>
|
||||
</view>
|
||||
<view class="page-content">
|
||||
<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 " @click="handleLogout()">退出登录</button>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ref, reactive } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app';
|
||||
import { baseUrl } from '@/request/request.js';
|
||||
import { getProfileDetail } from '@/request/three_one_api/info.js';
|
||||
|
||||
const defaultAvatar = 'https://ossweb-img.qq.com/images/lol/web201310/skin/big99008.jpg';
|
||||
|
||||
// 用户信息
|
||||
const userInfo = reactive({
|
||||
avatar: '',
|
||||
nickName: '',
|
||||
phonenumber: ''
|
||||
});
|
||||
|
||||
// // 获取用户信息
|
||||
// const getUserInfo = () => {
|
||||
// try {
|
||||
// const storedUserInfo = uni.getStorageSync('userInfo');
|
||||
// if (storedUserInfo) {
|
||||
// const info = JSON.parse(storedUserInfo);
|
||||
// userInfo.nickName = info.nickName || '';
|
||||
// userInfo.phonenumber = info.phonenumber || info.username || '';
|
||||
// }
|
||||
// } catch (e) {
|
||||
// console.error('获取用户信息失败:', e);
|
||||
// }
|
||||
// };
|
||||
// 获取图片完整URL(用于显示)
|
||||
const getImageUrl = (path) => {
|
||||
if (!path) return '';
|
||||
if (path.startsWith('http')) return path;
|
||||
return baseUrl + path;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getUserInfo();
|
||||
// 获取用户信息
|
||||
const loadUserInfo = async () => {
|
||||
try {
|
||||
const res = await getProfileDetail();
|
||||
if (res.code === 0 && res.data) {
|
||||
userInfo.avatar = res.data.avatar || '';
|
||||
userInfo.nickName = res.data.nickName || '';
|
||||
userInfo.phonenumber = res.data.phonenumber || '';
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('获取用户信息失败:', e);
|
||||
}
|
||||
};
|
||||
|
||||
// 每次页面显示时获取最新数据(包括从编辑页返回)
|
||||
onShow(() => {
|
||||
loadUserInfo();
|
||||
});
|
||||
|
||||
//帮助中心
|
||||
@@ -110,6 +143,12 @@
|
||||
url:'/pages/personalcenter/notification'
|
||||
})
|
||||
}
|
||||
//编辑个人信息
|
||||
const editinfo = () => {
|
||||
uni.navigateTo({
|
||||
url:'/pages/personalcenter/edit'
|
||||
})
|
||||
}
|
||||
//通用设置
|
||||
const Settings = () => {
|
||||
uni.navigateTo({
|
||||
@@ -144,22 +183,190 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
page {
|
||||
background: #EBF2FC;
|
||||
.page-wrapper {
|
||||
min-height: 100vh;
|
||||
background: #EBF2FC;
|
||||
}
|
||||
|
||||
// 顶部弥散渐变背景
|
||||
.header-bg {
|
||||
position: relative;
|
||||
height: 400rpx;
|
||||
background: linear-gradient(180deg, #3B7FED 0%, #007AFF 50%, #8BB8F8 100%);
|
||||
padding-top: 60rpx;
|
||||
overflow: hidden;
|
||||
|
||||
// 弥散光斑效果
|
||||
.blur-circle {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
filter: blur(60rpx);
|
||||
opacity: 0.5;
|
||||
}
|
||||
.page-content {
|
||||
background: #EBF2FC;
|
||||
border-radius: 40rpx 40rpx 0rpx 0rpx;
|
||||
margin-top: -40rpx;
|
||||
padding: 30rpx;
|
||||
padding-bottom: 50rpx;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
min-height: calc(100vh - 400rpx);
|
||||
|
||||
.circle-1 {
|
||||
width: 300rpx;
|
||||
height: 300rpx;
|
||||
background: rgba(100, 180, 255, 0.6);
|
||||
top: -50rpx;
|
||||
left: -50rpx;
|
||||
}
|
||||
.title {
|
||||
height: 440rpx;
|
||||
background: linear-gradient(135deg, #2667E9 0%, #4A8AF4 50%, #719BF0 100%);
|
||||
padding-top: 60rpx;
|
||||
|
||||
.circle-2 {
|
||||
width: 250rpx;
|
||||
height: 250rpx;
|
||||
background: rgba(150, 200, 255, 0.5);
|
||||
top: 100rpx;
|
||||
right: -30rpx;
|
||||
}
|
||||
|
||||
.circle-3 {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
background: rgba(180, 220, 255, 0.4);
|
||||
bottom: 50rpx;
|
||||
left: 200rpx;
|
||||
}
|
||||
}
|
||||
|
||||
// 标题
|
||||
.header-title {
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
// 用户信息区域
|
||||
.user-info-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 60rpx 40rpx 0;
|
||||
position: relative;
|
||||
z-index: 5;
|
||||
|
||||
.user-avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.15);
|
||||
|
||||
.avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.user-details {
|
||||
flex: 1;
|
||||
margin-left: 24rpx;
|
||||
|
||||
.user-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.user-phone {
|
||||
font-size: 26rpx;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
// padding: 16rpx 32rpx;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border: 2rpx solid rgba(255, 255, 255, 0.5);
|
||||
border-radius: 32rpx;
|
||||
font-size: 26rpx;
|
||||
color: #fff;
|
||||
backdrop-filter: blur(10rpx);
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 内容区域
|
||||
.content-area {
|
||||
position: relative;
|
||||
margin-top: -60rpx;
|
||||
padding: 0 30rpx 50rpx;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
// 菜单卡片
|
||||
.menu-card {
|
||||
background: #fff;
|
||||
border-radius: 24rpx;
|
||||
padding: 10rpx 0;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 32rpx 36rpx;
|
||||
border-bottom: 1rpx solid #F5F5F5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.menu-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.menu-icon {
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.menu-value {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
font-size: 28rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
// 退出登录按钮
|
||||
.logout-btn {
|
||||
margin-top: 60rpx;
|
||||
height: 96rpx;
|
||||
line-height: 96rpx;
|
||||
background: linear-gradient(135deg, #3B7FED 0%, #5A9CF5 100%);
|
||||
border-radius: 48rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
box-shadow: 0 8rpx 24rpx rgba(59, 127, 237, 0.35);
|
||||
|
||||
&::after {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user