| src/views/equipmentManagement/inspectionManagement/components/formDia.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/equipmentManagement/inspectionManagement/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/equipmentManagement/upkeep/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/views/equipmentManagement/inspectionManagement/components/formDia.vue
@@ -1,90 +1,185 @@ <template> <div> <el-dialog :title="operationType === 'add' ? '新增巡检任务' : '编辑巡检任务'" v-model="dialogVisitable" width="800px" @close="cancel"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> v-model="dialogVisitable" width="900px" @close="cancel"> <el-form ref="formRef" :model="form" :rules="rules" label-width="180px"> <el-row> <el-col :span="12"> <el-form-item label="设备名称" prop="taskId"> <el-select v-model="form.taskId" @change="setDeviceModel"> <el-option v-for="(item, index) in deviceOptions" :key="index" :label="item.deviceName" :value="item.id" ></el-option> </el-select> <el-form-item label="巡检任务名称" prop="taskName"> <el-input v-model="form.taskName" placeholder="请输入巡检任务名称" type="textarea" /> <!-- <el-select v-model="form.taskId" @change="setDeviceModel"> <el-option v-for="(item, index) in deviceOptions" :key="index" :label="item.deviceName" :value="item.id"></el-option> </el-select> --> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="巡检人" prop="inspector"> <el-select v-model="form.inspector" placeholder="请选择" multiple clearable> <el-option v-for="item in userList" :label="item.nickName" :value="item.userId" :key="item.userId"/> <el-form-item label="巡检人" prop="inspector"> <el-select v-model="form.inspector" placeholder="请选择" multiple clearable> <el-option v-for="item in userList" :label="item.nickName" :value="item.userId" :key="item.userId" /> </el-select> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="备注" prop="remarks"> <el-input v-model="form.remarks" placeholder="请输入备注" type="textarea" /> <el-form-item label="必须拍照视为巡检成功" prop="takePhone"> <el-radio-group v-model="form.takePhone"> <el-radio :label="true">是</el-radio> <el-radio :label="false">否</el-radio> </el-radio-group> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="上传相册照片" prop="takeAlbum"> <el-radio-group v-model="form.takeAlbum"> <el-radio :label="false">不可</el-radio> <el-radio :label="true">可</el-radio> </el-radio-group> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="任务频率" prop="frequencyType"> <el-select v-model="form.frequencyType" placeholder="请选择" clearable> <el-option label="每日" value="DAILY"/> <el-option label="每周" value="WEEKLY"/> <el-option label="每月" value="MONTHLY"/> <el-form-item label="备注" prop="remarks"> <el-input v-model="form.remarks" placeholder="请输入备注" type="textarea" /> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="任务频率" prop="frequencyType"> <el-select v-model="form.frequencyType" placeholder="请选择" clearable> <el-option label="每日" value="DAILY" /> <el-option label="每周" value="WEEKLY" /> <el-option label="每月" value="MONTHLY" /> <!-- <el-option label="季度" value="QUARTERLY"/> --> </el-select> </el-form-item> </el-col> <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType"> <el-form-item label="日期" prop="frequencyDetail"> <el-time-picker v-model="form.frequencyDetail" placeholder="选择时间" format="HH:mm" <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType"> <el-form-item label="日期" prop="frequencyDetail"> <el-time-picker v-model="form.frequencyDetail" placeholder="选择时间" format="HH:mm" value-format="HH:mm" /> </el-form-item> </el-col> <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType"> <el-form-item label="日期" prop="frequencyDetail"> <el-select v-model="form.week" placeholder="请选择" clearable style="width: 50%"> <el-option label="周一" value="MON"/> <el-option label="周二" value="TUE"/> <el-option label="周三" value="WED"/> <el-option label="周四" value="THU"/> <el-option label="周五" value="FRI"/> <el-option label="周六" value="SAT"/> <el-option label="周日" value="SUN"/> <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType"> <el-form-item label="日期" prop="frequencyDetail"> <el-select v-model="form.week" placeholder="请选择" clearable style="width: 50%"> <el-option label="周一" value="MON" /> <el-option label="周二" value="TUE" /> <el-option label="周三" value="WED" /> <el-option label="周四" value="THU" /> <el-option label="周五" value="FRI" /> <el-option label="周六" value="SAT" /> <el-option label="周日" value="SUN" /> </el-select> <el-time-picker v-model="form.time" placeholder="选择时间" format="HH:mm" value-format="HH:mm" style="width: 50%"/> <el-time-picker v-model="form.time" placeholder="选择时间" format="HH:mm" value-format="HH:mm" style="width: 50%" /> </el-form-item> </el-col> <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType"> <el-form-item label="日期" prop="frequencyDetail"> <el-date-picker v-model="form.frequencyDetail" type="datetime" clearable placeholder="选择开始日期" format="DD,HH:mm" value-format="DD,HH:mm" /> <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType"> <el-form-item label="日期" prop="frequencyDetail"> <el-date-picker v-model="form.frequencyDetail" type="datetime" clearable placeholder="选择开始日期" format="DD,HH:mm" value-format="DD,HH:mm" /> </el-form-item> </el-col> <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType"> <el-form-item label="日期" prop="frequencyDetail"> <el-date-picker v-model="form.frequencyDetail" type="datetime" clearable placeholder="选择开始日期" format="MM,DD,HH:mm" value-format="MM,DD,HH:mm" /> <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType"> <el-form-item label="日期" prop="frequencyDetail"> <el-date-picker v-model="form.frequencyDetail" type="datetime" clearable placeholder="选择开始日期" format="MM,DD,HH:mm" value-format="MM,DD,HH:mm" /> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType"> <el-form-item label="时限(小时)" prop="inspectionDeadline"> <el-input v-model="form.inspectionDeadline" type="number" placeholder="请输入备注"> </el-input> </el-form-item> </el-col> <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType"> <el-form-item label="时限(天)" prop="inspectionDeadline"> <el-input v-model="form.inspectionDeadline" placeholder="请输入备注" type="number"> </el-input> </el-form-item> </el-col> <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType"> <el-form-item label="时限(天)" prop="inspectionDeadline"> <el-input v-model="form.inspectionDeadline" placeholder="请输入备注" type="number"> </el-input> </el-form-item> </el-col> </el-row> @@ -92,7 +187,8 @@ <template #footer> <div class="dialog-footer"> <el-button @click="cancel">取消</el-button> <el-button type="primary" @click="submitForm">保存</el-button> <el-button type="primary" @click="submitForm">保存</el-button> </div> </template> </el-dialog> @@ -100,188 +196,205 @@ </template> <script setup> import {reactive, ref, getCurrentInstance, toRefs} from "vue"; import useUserStore from '@/store/modules/user' import {addOrEditTimingTask} from "@/api/inspectionManagement/index.js"; import {userListNoPageByTenantId} from "@/api/system/user.js"; import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; import { reactive, ref, getCurrentInstance, toRefs } from "vue"; import useUserStore from "@/store/modules/user"; import { addOrEditTimingTask } from "@/api/inspectionManagement/index.js"; import { userListNoPageByTenantId } from "@/api/system/user.js"; import { getDeviceLedger } from "@/api/equipmentManagement/ledger"; const { proxy } = getCurrentInstance() const emit = defineEmits() const userStore = useUserStore() const dialogVisitable = ref(false); const operationType = ref('add'); const deviceOptions = ref([]); const data = reactive({ form: { taskId: undefined, taskName: undefined, inspector: '', inspectorIds: '', remarks: '', frequencyType: '', frequencyDetail: '', week: '', time: '' }, rules: { taskId: [{ required: true, message: "请选择设备", trigger: "change" },], inspector: [{ required: true, message: "请输入巡检人", trigger: "blur" },], dateStr: [{ required: true, message: "请选择登记时间", trigger: "change" }], frequencyType: [{ required: true, message: "请选择任务频率", trigger: "change" }], frequencyDetail: [ { required: true, message: "请选择日期", trigger: "change", validator: (rule, value, callback) => { if (!form.value.frequencyType) { callback() return } if (form.value.frequencyType === 'WEEKLY') { if (!form.value.week || !form.value.time) { callback(new Error("请选择日期和时间")) } else { callback() } } else { if (!value) { callback(new Error("请选择日期")) } else { callback() } } } } ], week: [ { required: true, message: "请选择星期", trigger: "change", validator: (rule, value, callback) => { if (form.value.frequencyType === 'WEEKLY' && !value) { callback(new Error("请选择星期")) } else { callback() } } } ], time: [ { required: true, message: "请选择时间", trigger: "change", validator: (rule, value, callback) => { if (form.value.frequencyType === 'WEEKLY' && !value) { callback(new Error("请选择时间")) } else { callback() } } } ] } }) const { form, rules } = toRefs(data) const userList = ref([]) const loadDeviceName = async () => { const { data } = await getDeviceLedger(); deviceOptions.value = data; }; const setDeviceModel = (id) => { const option = deviceOptions.value.find((item) => item.id === id); if (option) { form.value.taskName = option.deviceName; } } // 打开弹框 const openDialog = async (type, row) => { dialogVisitable.value = true operationType.value = type // 重置表单 resetForm(); // 加载用户列表 userListNoPageByTenantId().then((res) => { userList.value = res.data; const { proxy } = getCurrentInstance(); const emit = defineEmits(); const userStore = useUserStore(); const dialogVisitable = ref(false); const operationType = ref("add"); const deviceOptions = ref([]); const data = reactive({ form: { taskId: undefined, taskName: undefined, inspector: "", inspectorIds: "", remarks: "", frequencyType: "", frequencyDetail: "", week: "", time: "", takePhone: true, takeAlbum: false, inspectionDeadline: "", }, rules: { // taskId: [{ required: true, message: "请选择设备", trigger: "change" }], taskName: [ { required: true, message: "请输入巡检任务名称", trigger: "blur" }, ], inspector: [{ required: true, message: "请输入巡检人", trigger: "blur" }], dateStr: [{ required: true, message: "请选择登记时间", trigger: "change" }], frequencyType: [ { required: true, message: "请选择任务频率", trigger: "change" }, ], frequencyDetail: [ { required: true, message: "请选择日期", trigger: "change", validator: (rule, value, callback) => { if (!form.value.frequencyType) { callback(); return; } if (form.value.frequencyType === "WEEKLY") { if (!form.value.week || !form.value.time) { callback(new Error("请选择日期和时间")); } else { callback(); } } else { if (!value) { callback(new Error("请选择日期")); } else { callback(); } } }, }, ], inspectionDeadline: [ { required: true, message: "请输入时限", trigger: "blur", }, ], week: [ { required: true, message: "请选择星期", trigger: "change", validator: (rule, value, callback) => { if (form.value.frequencyType === "WEEKLY" && !value) { callback(new Error("请选择星期")); } else { callback(); } }, }, ], time: [ { required: true, message: "请选择时间", trigger: "change", validator: (rule, value, callback) => { if (form.value.frequencyType === "WEEKLY" && !value) { callback(new Error("请选择时间")); } else { callback(); } }, }, ], }, }); // 加载设备列表 await loadDeviceName(); if (type === 'edit' && row) { form.value = {...row} form.value.inspector = form.value.inspectorIds.split(',').map(Number) // 如果有设备ID,自动设置设备信息 if (form.value.taskId) { setDeviceModel(form.value.taskId); const { form, rules } = toRefs(data); const userList = ref([]); const loadDeviceName = async () => { const { data } = await getDeviceLedger(); deviceOptions.value = data; }; const setDeviceModel = id => { const option = deviceOptions.value.find(item => item.id === id); if (option) { form.value.taskName = option.deviceName; } } } }; // 关闭对话框 const cancel = () => { resetForm() dialogVisitable.value = false emit('closeDia') } // 打开弹框 const openDialog = async (type, row) => { dialogVisitable.value = true; operationType.value = type; // 重置表单函数 const resetForm = () => { if (proxy.$refs.formRef) { proxy.$refs.formRef.resetFields() } // 重置表单数据确保设备信息正确重置 form.value = { taskId: undefined, taskName: undefined, inspector: '', inspectorIds: '', remarks: '', frequencyType: '', frequencyDetail: '', week: '', time: '' } } // 重置表单 resetForm(); // 提交表单 const submitForm = () => { proxy.$refs["formRef"].validate(async valid => { if (valid) { try { form.value.inspectorIds = form.value.inspector.join(',') delete form.value.inspector if (form.value.frequencyType === 'WEEKLY') { let frequencyDetail = '' frequencyDetail = form.value.week + ',' + form.value.time form.value.frequencyDetail = frequencyDetail // 加载用户列表 userListNoPageByTenantId().then(res => { userList.value = res.data; }); // 加载设备列表 await loadDeviceName(); if (type === "edit" && row) { form.value = { ...row }; form.value.inspector = form.value.inspectorIds.split(",").map(Number); // 如果有设备ID,自动设置设备信息 // if (form.value.taskId) { // setDeviceModel(form.value.taskId); // } } }; // 关闭对话框 const cancel = () => { resetForm(); dialogVisitable.value = false; emit("closeDia"); }; // 重置表单函数 const resetForm = () => { if (proxy.$refs.formRef) { proxy.$refs.formRef.resetFields(); } // 重置表单数据确保设备信息正确重置 form.value = { taskId: undefined, taskName: undefined, inspector: "", inspectorIds: "", remarks: "", frequencyType: "", frequencyDetail: "", week: "", time: "", takePhone: true, takeAlbum: false, inspectionDeadline: "", }; }; // 提交表单 const submitForm = () => { proxy.$refs["formRef"].validate(async valid => { if (valid) { try { form.value.inspectorIds = form.value.inspector.join(","); delete form.value.inspector; if (form.value.frequencyType === "WEEKLY") { let frequencyDetail = ""; frequencyDetail = form.value.week + "," + form.value.time; form.value.frequencyDetail = frequencyDetail; } let res = await userStore.getInfo(); form.value.registrantId = res.user.userId; await addOrEditTimingTask(form.value); cancel(); proxy.$modal.msgSuccess("提交成功"); } catch (error) { proxy.$modal.msgError("提交失败,请重试"); } let res = await userStore.getInfo() form.value.registrantId = res.user.userId await addOrEditTimingTask(form.value) cancel() proxy.$modal.msgSuccess('提交成功') } catch (error) { proxy.$modal.msgError('提交失败,请重试') } } }) } defineExpose({ openDialog }) }); }; defineExpose({ openDialog }); </script> <style scoped> </style> src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue
@@ -1,83 +1,32 @@ <template> <div> <el-dialog title="查看附件" v-model="dialogVisitable" width="800px" @close="cancel"> v-model="dialogVisitable" width="800px" @close="cancel"> <div class="upload-container"> <!-- 生产前 --> <div class="form-container"> <div class="title">生产前</div> <div class="title">附件列表</div> <!-- 图片列表 --> <div style="display: flex; flex-wrap: wrap;"> <img v-for="(item, index) in beforeProductionImgs" :key="index" <img v-for="(item, index) in beforeProductionImgs" :key="index" @click="showMedia(beforeProductionImgs, index, 'image')" :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt=""> :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt=""> </div> <!-- 视频列表 --> <div style="display: flex; flex-wrap: wrap;"> <div v-for="(videoUrl, index) in beforeProductionVideos" :key="index" @click="showMedia(beforeProductionVideos, index, 'video')" style="position: relative; margin: 10px; cursor: pointer;" > <div v-for="(videoUrl, index) in beforeProductionVideos" :key="index" @click="showMedia(beforeProductionVideos, index, 'video')" style="position: relative; margin: 10px; cursor: pointer;"> <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;"> <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" /> </div> <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div> </div> </div> </div> <!-- 生产后 --> <div class="form-container"> <div class="title">生产后</div> <!-- 图片列表 --> <div style="display: flex; flex-wrap: wrap;"> <img v-for="(item, index) in afterProductionImgs" :key="index" @click="showMedia(afterProductionImgs, index, 'image')" :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt=""> </div> <!-- 视频列表 --> <div style="display: flex; flex-wrap: wrap;"> <div v-for="(videoUrl, index) in afterProductionVideos" :key="index" @click="showMedia(afterProductionVideos, index, 'video')" style="position: relative; margin: 10px; cursor: pointer;" > <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;"> <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" /> </div> <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div> </div> </div> </div> <!-- 生产问题 --> <div class="form-container"> <div class="title">生产问题</div> <!-- 图片列表 --> <div style="display: flex; flex-wrap: wrap;"> <img v-for="(item, index) in productionIssuesImgs" :key="index" @click="showMedia(productionIssuesImgs, index, 'image')" :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt=""> </div> <!-- 视频列表 --> <div style="display: flex; flex-wrap: wrap;"> <div v-for="(videoUrl, index) in productionIssuesVideos" :key="index" @click="showMedia(productionIssuesVideos, index, 'video')" style="position: relative; margin: 10px; cursor: pointer;" > <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;"> <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" /> <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" /> </div> <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div> </div> @@ -85,220 +34,225 @@ </div> </div> </el-dialog> <!-- 统一媒体查看器 --> <div v-if="isMediaViewerVisible" class="media-viewer-overlay" @click.self="closeMediaViewer"> <div class="media-viewer-content" @click.stop> <div v-if="isMediaViewerVisible" class="media-viewer-overlay" @click.self="closeMediaViewer"> <div class="media-viewer-content" @click.stop> <!-- 图片 --> <vue-easy-lightbox v-if="mediaType === 'image'" :visible="isMediaViewerVisible" :imgs="mediaList" :index="currentMediaIndex" @hide="closeMediaViewer" ></vue-easy-lightbox> <vue-easy-lightbox v-if="mediaType === 'image'" :visible="isMediaViewerVisible" :imgs="mediaList" :index="currentMediaIndex" @hide="closeMediaViewer"></vue-easy-lightbox> <!-- 视频 --> <div v-else-if="mediaType === 'video'" style="position: relative;"> <video :src="mediaList[currentMediaIndex]" autoplay controls style="max-width: 90vw; max-height: 80vh;" /> <div v-else-if="mediaType === 'video'" style="position: relative;"> <video :src="mediaList[currentMediaIndex]" autoplay controls style="max-width: 90vw; max-height: 80vh;" /> </div> </div> </div> </div> </template> <script setup> import { ref } from 'vue'; import VueEasyLightbox from 'vue-easy-lightbox'; const { proxy } = getCurrentInstance(); import { ref } from "vue"; import VueEasyLightbox from "vue-easy-lightbox"; const { proxy } = getCurrentInstance(); // 控制弹窗显示 const dialogVisitable = ref(false); // 控制弹窗显示 const dialogVisitable = ref(false); // 图片数组 const beforeProductionImgs = ref([]); const afterProductionImgs = ref([]); const productionIssuesImgs = ref([]); // 图片数组 const beforeProductionImgs = ref([]); const afterProductionImgs = ref([]); const productionIssuesImgs = ref([]); // 视频数组 const beforeProductionVideos = ref([]); const afterProductionVideos = ref([]); const productionIssuesVideos = ref([]); // 视频数组 const beforeProductionVideos = ref([]); const afterProductionVideos = ref([]); const productionIssuesVideos = ref([]); // 媒体查看器状态 const isMediaViewerVisible = ref(false); const currentMediaIndex = ref(0); const mediaList = ref([]); // 存储当前要查看的媒体列表(含图片和视频对象) const mediaType = ref('image'); // image | video const javaApi = proxy.javaApi; // 媒体查看器状态 const isMediaViewerVisible = ref(false); const currentMediaIndex = ref(0); const mediaList = ref([]); // 存储当前要查看的媒体列表(含图片和视频对象) const mediaType = ref("image"); // image | video const javaApi = proxy.javaApi; // 处理 URL:将 Windows 路径转换为可访问的 URL function processFileUrl(fileUrl) { if (!fileUrl) return ''; // 如果 URL 是 Windows 路径格式(包含反斜杠),需要转换 if (fileUrl && fileUrl.indexOf('\\') > -1) { // 查找 uploads 关键字的位置,从那里开始提取相对路径 const uploadsIndex = fileUrl.toLowerCase().indexOf('uploads'); if (uploadsIndex > -1) { // 从 uploads 开始提取路径,并将反斜杠替换为正斜杠 const relativePath = fileUrl.substring(uploadsIndex).replace(/\\/g, '/'); fileUrl = '/' + relativePath; } else { // 如果没有找到 uploads,提取最后一个目录和文件名 const parts = fileUrl.split('\\'); const fileName = parts[parts.length - 1]; fileUrl = '/uploads/' + fileName; } } // 确保所有非 http 开头的 URL 都拼接 baseUrl if (fileUrl && !fileUrl.startsWith('http')) { // 确保路径以 / 开头 if (!fileUrl.startsWith('/')) { fileUrl = '/' + fileUrl; } // 拼接 baseUrl fileUrl = javaApi + fileUrl; } return fileUrl; } // 处理 URL:将 Windows 路径转换为可访问的 URL function processFileUrl(fileUrl) { if (!fileUrl) return ""; // 处理每一类数据:分离图片和视频 function processItems(items) { const images = []; const videos = []; // 检查 items 是否存在且为数组 if (!items || !Array.isArray(items)) { return { images, videos }; } items.forEach(item => { if (!item || !item.url) return; // 处理文件 URL const fileUrl = processFileUrl(item.url); // 根据文件扩展名判断是图片还是视频 const urlLower = fileUrl.toLowerCase(); if (urlLower.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/)) { images.push(fileUrl); } else if (urlLower.match(/\.(mp4|avi|mov|wmv|flv|mkv|webm)$/)) { videos.push(fileUrl); } else if (item.contentType) { // 如果有 contentType,使用 contentType 判断 if (item.contentType.startsWith('image/')) { images.push(fileUrl); } else if (item.contentType.startsWith('video/')) { videos.push(fileUrl); // 如果 URL 是 Windows 路径格式(包含反斜杠),需要转换 if (fileUrl && fileUrl.indexOf("\\") > -1) { // 查找 uploads 关键字的位置,从那里开始提取相对路径 const uploadsIndex = fileUrl.toLowerCase().indexOf("uploads"); if (uploadsIndex > -1) { // 从 uploads 开始提取路径,并将反斜杠替换为正斜杠 const relativePath = fileUrl.substring(uploadsIndex).replace(/\\/g, "/"); fileUrl = "/" + relativePath; } else { // 如果没有找到 uploads,提取最后一个目录和文件名 const parts = fileUrl.split("\\"); const fileName = parts[parts.length - 1]; fileUrl = "/uploads/" + fileName; } } }); return { images, videos }; } // 打开弹窗并加载数据 const openDialog = async (row) => { // 使用正确的字段名:commonFileListBefore, commonFileListAfter // productionIssues 可能不存在,使用空数组 const { images: beforeImgs, videos: beforeVids } = processItems(row.commonFileListBefore || []); const { images: afterImgs, videos: afterVids } = processItems(row.commonFileListAfter || []); const { images: issueImgs, videos: issueVids } = processItems(row.productionIssues || []); beforeProductionImgs.value = beforeImgs; beforeProductionVideos.value = beforeVids; afterProductionImgs.value = afterImgs; afterProductionVideos.value = afterVids; productionIssuesImgs.value = issueImgs; productionIssuesVideos.value = issueVids; dialogVisitable.value = true; }; // 确保所有非 http 开头的 URL 都拼接 baseUrl if (fileUrl && !fileUrl.startsWith("http")) { // 确保路径以 / 开头 if (!fileUrl.startsWith("/")) { fileUrl = "/" + fileUrl; } // 拼接 baseUrl fileUrl = javaApi + fileUrl; } // 显示媒体(图片 or 视频) function showMedia(mediaArray, index, type) { mediaList.value = mediaArray; currentMediaIndex.value = index; mediaType.value = type; isMediaViewerVisible.value = true; } return fileUrl; } // 关闭媒体查看器 function closeMediaViewer() { isMediaViewerVisible.value = false; mediaList.value = []; mediaType.value = 'image'; } // 处理每一类数据:分离图片和视频 function processItems(items) { const images = []; const videos = []; // 表单关闭方法 const cancel = () => { dialogVisitable.value = false; }; // 检查 items 是否存在且为数组 if (!items || !Array.isArray(items)) { return { images, videos }; } defineExpose({ openDialog }); items.forEach(item => { if (!item || !item.url) return; // 处理文件 URL const fileUrl = processFileUrl(item.url); // 根据文件扩展名判断是图片还是视频 const urlLower = fileUrl.toLowerCase(); if (urlLower.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/)) { images.push(fileUrl); } else if (urlLower.match(/\.(mp4|avi|mov|wmv|flv|mkv|webm)$/)) { videos.push(fileUrl); } else if (item.contentType) { // 如果有 contentType,使用 contentType 判断 if (item.contentType.startsWith("image/")) { images.push(fileUrl); } else if (item.contentType.startsWith("video/")) { videos.push(fileUrl); } } }); return { images, videos }; } // 打开弹窗并加载数据 const openDialog = async row => { // 使用正确的字段名:commonFileListBefore, commonFileListAfter // productionIssues 可能不存在,使用空数组 const { images: beforeImgs, videos: beforeVids } = processItems( row.commonFileListBefore || [] ); const { images: afterImgs, videos: afterVids } = processItems( row.commonFileListAfter || [] ); const { images: issueImgs, videos: issueVids } = processItems( row.productionIssues || [] ); beforeProductionImgs.value = beforeImgs; beforeProductionVideos.value = beforeVids; afterProductionImgs.value = afterImgs; afterProductionVideos.value = afterVids; productionIssuesImgs.value = issueImgs; productionIssuesVideos.value = issueVids; dialogVisitable.value = true; }; // 显示媒体(图片 or 视频) function showMedia(mediaArray, index, type) { mediaList.value = mediaArray; currentMediaIndex.value = index; mediaType.value = type; isMediaViewerVisible.value = true; } // 关闭媒体查看器 function closeMediaViewer() { isMediaViewerVisible.value = false; mediaList.value = []; mediaType.value = "image"; } // 表单关闭方法 const cancel = () => { dialogVisitable.value = false; }; defineExpose({ openDialog }); </script> <style scoped lang="scss"> .upload-container { display: flex; flex-direction: column; align-items: center; padding: 20px; border: 1px solid #dcdfe6; box-sizing: border-box; .form-container { flex: 1; width: 100%; .upload-container { display: flex; flex-direction: column; align-items: center; padding: 20px; border: 1px solid #dcdfe6; box-sizing: border-box; margin-bottom: 20px; } } .title { font-size: 14px; color: #165dff; line-height: 20px; font-weight: 600; padding-left: 10px; position: relative; margin: 6px 0; &::before { content: ""; position: absolute; .form-container { flex: 1; width: 100%; margin-bottom: 20px; } } .title { font-size: 14px; color: #165dff; line-height: 20px; font-weight: 600; padding-left: 10px; position: relative; margin: 6px 0; &::before { content: ""; position: absolute; left: 0; top: 3px; width: 4px; height: 14px; background-color: #165dff; } } .media-viewer-overlay { position: fixed; top: 0; left: 0; top: 3px; width: 4px; height: 14px; background-color: #165dff; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.8); z-index: 9999; display: flex; align-items: center; justify-content: center; } } .media-viewer-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.8); z-index: 9999; display: flex; align-items: center; justify-content: center; } .media-viewer-content { position: relative; max-width: 90vw; max-height: 90vh; overflow: hidden; } .media-viewer-content { position: relative; max-width: 90vw; max-height: 90vh; overflow: hidden; } </style> src/views/equipmentManagement/inspectionManagement/index.vue
@@ -151,6 +151,78 @@ }, }, { prop: "inspectionDeadlinetxt", label: "期限", minWidth: 150, }, { prop: "inspectionStatus", label: "巡检状态", minWidth: 150, dataType: "tag", formatType: params => { const typeMap = { 已完成: "info", 未巡检: "warning", 超期: "danger", }; return typeMap[params] || "info"; }, }, { prop: "frequencyDetail", label: "开始日期与时间", minWidth: 150, formatter: (row, column, cellValue) => { // 先判断是否是字符串 if (typeof cellValue !== "string") return ""; let val = cellValue; const replacements = { MON: "周一", TUE: "周二", WED: "周三", THU: "周四", FRI: "周五", SAT: "周六", SUN: "周日", }; // 使用正则一次性替换所有匹配项 return val.replace( /MON|TUE|WED|THU|FRI|SAT|SUN/g, match => replacements[match] ); }, }, { prop: "registrant", label: "登记人", minWidth: 100 }, { prop: "createTime", label: "登记日期", minWidth: 100 }, ]); const columns1 = ref([ { prop: "taskName", label: "巡检任务名称", minWidth: 160 }, { prop: "remarks", label: "备注", minWidth: 150 }, { prop: "inspector", label: "执行巡检人", minWidth: 150, slot: "inspector" }, { prop: "frequencyType", label: "频次", minWidth: 150, // formatter: (_, __, val) => ({ // DAILY: "每日", // WEEKLY: "每周", // MONTHLY: "每月", // QUARTERLY: "季度" // }[val] || "") formatData: params => { return params === "DAILY" ? "每日" : params === "WEEKLY" ? "每周" : params === "MONTHLY" ? "每月" : params === "QUARTERLY" ? "季度" : ""; }, }, { prop: "frequencyDetail", label: "开始日期与时间", minWidth: 150, @@ -221,7 +293,7 @@ if (value === "taskManage") { const operationColumn = getOperationColumn(["edit"]); tableColumns.value = [ ...columns.value, ...columns1.value, ...(operationColumn ? [operationColumn] : []), ]; operationsArr.value = ["edit"]; @@ -293,6 +365,13 @@ return processedItem; }); tableData.value.forEach(item => { item.inspectionStatus = getFileStatus(item); item.inspectionDeadlinetxt = item.frequencyType === "DAILY" ? item.inspectionDeadline + "小时" : item.inspectionDeadline + "天"; }); total.value = res.data.total || 0; }) .finally(() => { @@ -345,7 +424,61 @@ }) .catch(() => {}); }; const getFileStatus = record => { console.log(record); if (record.takePhone) { if (record.commonFileListBefore && record.commonFileListBefore.length) { return "已完成"; } if (record.frequencyType == "DAILY") { if (Number(record.inspectionDeadline) && record.createTime) { // 计算时间差(小时) const now = new Date().getTime(); const createTime = new Date(record.createTime).getTime(); const hoursDiff = (now - createTime) / (1000 * 60 * 60); if (hoursDiff > Number(record.inspectionDeadline)) { return "超期"; } } } else { if (Number(record.inspectionDeadline) && record.createTime) { // 计算时间差(天) const now = new Date().getTime(); const createTime = new Date(record.createTime).getTime(); const daysDiff = (now - createTime) / (1000 * 60 * 60 * 24); if (daysDiff > Number(record.inspectionDeadline)) { return "超期"; } } } return "未巡检"; } else if (record.inspectionSubmitted) { return "已完成"; } else { if (record.frequencyType == "DAILY") { if (Number(record.inspectionDeadline) && record.createTime) { // 计算时间差(小时) const now = new Date().getTime(); const createTime = new Date(record.createTime).getTime(); const hoursDiff = (now - createTime) / (1000 * 60 * 60); if (hoursDiff > Number(record.inspectionDeadline)) { return "超期"; } } } else { if (Number(record.inspectionDeadline) && record.createTime) { // 计算时间差(天) const now = new Date().getTime(); const createTime = new Date(record.createTime).getTime(); const daysDiff = (now - createTime) / (1000 * 60 * 60 * 24); if (daysDiff > Number(record.inspectionDeadline)) { return "超期"; } } } return "未巡检"; } }; // 多选变更 const handleSelectionChange = selection => { selectedRows.value = selection; src/views/equipmentManagement/upkeep/index.vue
@@ -1,694 +1,704 @@ <template> <div class="app-container"> <el-tabs v-model="activeTab" @tab-change="handleTabChange"> <el-tabs v-model="activeTab" @tab-change="handleTabChange"> <!-- 定时任务管理tab --> <el-tab-pane label="定时任务管理" name="scheduled"> <el-tab-pane label="定时任务管理" name="scheduled"> <div class="search_form"> <el-form :model="scheduledFilters" :inline="true"> <el-form :model="scheduledFilters" :inline="true"> <el-form-item label="任务名称"> <el-input v-model="scheduledFilters.taskName" style="width: 240px" placeholder="请输入任务名称" clearable :prefix-icon="Search" @change="getScheduledTableData" /> <el-input v-model="scheduledFilters.taskName" style="width: 240px" placeholder="请输入任务名称" clearable :prefix-icon="Search" @change="getScheduledTableData" /> </el-form-item> <el-form-item label="任务状态"> <el-select v-model="scheduledFilters.status" placeholder="请选择任务状态" clearable style="width: 200px"> <el-option label="启用" value="1" /> <el-option label="停用" value="0" /> <el-select v-model="scheduledFilters.status" placeholder="请选择任务状态" clearable style="width: 200px"> <el-option label="启用" value="1" /> <el-option label="停用" value="0" /> </el-select> </el-form-item> <el-form-item> <el-button type="primary" @click="getScheduledTableData">搜索</el-button> <el-button type="primary" @click="getScheduledTableData">搜索</el-button> <el-button @click="resetScheduledFilters">重置</el-button> </el-form-item> </el-form> </div> <div class="table_list"> <div class="actions"> <el-text class="mx-1" size="large">定时任务管理</el-text> <el-text class="mx-1" size="large">定时任务管理</el-text> <div> <el-button type="primary" icon="Plus" @click="addScheduledTask"> <el-button type="primary" icon="Plus" @click="addScheduledTask"> 新增任务 </el-button> <el-button type="danger" icon="Delete" :disabled="scheduledMultipleList.length <= 0" @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))" > <el-button type="danger" icon="Delete" :disabled="scheduledMultipleList.length <= 0" @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))"> 批量删除 </el-button> </div> </div> <PIMTable rowKey="id" isSelection :column="scheduledColumns" :tableData="scheduledDataList" :page="{ <PIMTable rowKey="id" isSelection :column="scheduledColumns" :tableData="scheduledDataList" :page="{ current: scheduledPagination.currentPage, size: scheduledPagination.pageSize, total: scheduledPagination.total, }" @selection-change="handleScheduledSelectionChange" @pagination="changeScheduledPage" > @selection-change="handleScheduledSelectionChange" @pagination="changeScheduledPage"> <template #statusRef="{ row }"> <el-tag v-if="row.status === 1" type="success">启用</el-tag> <el-tag v-if="row.status === 0" type="danger">停用</el-tag> <el-tag v-if="row.status === 1" type="success">启用</el-tag> <el-tag v-if="row.status === 0" type="danger">停用</el-tag> </template> <template #operation="{ row }"> <el-button type="primary" link @click="editScheduledTask(row)" > <el-button type="primary" link @click="editScheduledTask(row)"> 编辑 </el-button> <el-button type="danger" link @click="delScheduledTaskByIds(row.id)" > <el-button type="danger" link @click="delScheduledTaskByIds(row.id)"> 删除 </el-button> </template> </PIMTable> </div> </el-tab-pane> <!-- 任务记录tab(原设备保养页面) --> <el-tab-pane label="任务记录" name="record"> <el-tab-pane label="任务记录" name="record"> <div class="search_form"> <el-form :model="filters" :inline="true"> <el-form :model="filters" :inline="true"> <el-form-item label="设备名称"> <el-input v-model="filters.deviceName" style="width: 240px" placeholder="请输入设备名称" clearable :prefix-icon="Search" @change="getTableData" /> <el-input v-model="filters.deviceName" style="width: 240px" placeholder="请输入设备名称" clearable :prefix-icon="Search" @change="getTableData" /> </el-form-item> <el-form-item label="计划保养日期"> <el-date-picker v-model="filters.maintenancePlanTime" type="date" placeholder="请选择计划保养日期" size="default" @change="(date) => handleDateChange(date,2)" /> <el-date-picker v-model="filters.maintenancePlanTime" type="date" placeholder="请选择计划保养日期" size="default" @change="(date) => handleDateChange(date,2)" /> </el-form-item> <el-form-item label="实际保养日期"> <el-date-picker v-model="filters.maintenanceActuallyTime" type="date" placeholder="请选择实际保养日期" size="default" @change="(date) => handleDateChange(date,1)" /> <el-date-picker v-model="filters.maintenanceActuallyTime" type="date" placeholder="请选择实际保养日期" size="default" @change="(date) => handleDateChange(date,1)" /> </el-form-item> <el-form-item label="实际保养人"> <el-input v-model="filters.maintenanceActuallyName" style="width: 240px" placeholder="请输入实际保养人" clearable :prefix-icon="Search" @change="getTableData" /> <el-input v-model="filters.maintenanceActuallyName" style="width: 240px" placeholder="请输入实际保养人" clearable :prefix-icon="Search" @change="getTableData" /> </el-form-item> <el-form-item> <el-button type="primary" @click="getTableData">搜索</el-button> <el-button type="primary" @click="getTableData">搜索</el-button> <el-button @click="resetFilters">重置</el-button> </el-form-item> </el-form> </div> <div class="table_list"> <div class="actions"> <el-text class="mx-1" size="large">任务记录</el-text> <el-text class="mx-1" size="large">任务记录</el-text> <div> <el-button type="success" icon="Van" @click="addPlan"> <el-button type="success" icon="Van" @click="addPlan"> 新增计划 </el-button> <el-button @click="handleOut"> 导出 </el-button> <el-button type="danger" icon="Delete" :disabled="multipleList.length <= 0 || hasFinishedStatus" @click="delRepairByIds(multipleList.map((item) => item.id))" > <el-button type="danger" icon="Delete" :disabled="multipleList.length <= 0 || hasFinishedStatus" @click="delRepairByIds(multipleList.map((item) => item.id))"> 批量删除 </el-button> </div> </div> <PIMTable rowKey="id" isSelection :column="columns" :tableData="dataList" :page="{ <PIMTable rowKey="id" isSelection :column="columns" :tableData="dataList" :page="{ current: pagination.currentPage, size: pagination.pageSize, total: pagination.total, }" @selection-change="handleSelectionChange" @pagination="changePage" > <template #maintenanceResultRef="{ row }"> <div>{{ row.maintenanceResult || '-' }}</div> </template> <template #statusRef="{ row }"> <el-tag v-if="row.status === 2" type="danger">失败</el-tag> <el-tag v-if="row.status === 1" type="success">完结</el-tag> <el-tag v-if="row.status === 0" type="warning">待保养</el-tag> </template> <template #operation="{ row }"> <!-- 这个功能跟新增保养功能一模一样,有啥意义? --> <!-- <el-button @selection-change="handleSelectionChange" @pagination="changePage"> <template #maintenanceResultRef="{ row }"> <div>{{ row.maintenanceResult || '-' }}</div> </template> <template #statusRef="{ row }"> <el-tag v-if="row.status === 2" type="danger">失败</el-tag> <el-tag v-if="row.status === 1" type="success">完结</el-tag> <el-tag v-if="row.status === 0" type="warning">待保养</el-tag> </template> <template #operation="{ row }"> <!-- 这个功能跟新增保养功能一模一样,有啥意义? --> <!-- <el-button type="primary" text @click="addMaintain(row)" > 新增保养 </el-button> --> <el-button type="primary" link :disabled="row.status === 1" @click="editPlan(row.id)" > 编辑 </el-button> <el-button type="success" link :disabled="row.status === 1" @click="addMaintain(row)" > 保养 </el-button> <el-button type="danger" link :disabled="row.status === 1" @click="delRepairByIds(row.id)" > 删除 </el-button> <el-button type="primary" link @click="openFileDialog(row)" > 附件 </el-button> </template> </PIMTable> <el-button type="primary" link :disabled="row.status === 1" @click="editPlan(row.id)"> 编辑 </el-button> <el-button type="success" link :disabled="row.status === 1" @click="addMaintain(row)"> 保养 </el-button> <el-button type="danger" link :disabled="row.status === 1" @click="delRepairByIds(row.id)"> 删除 </el-button> <el-button type="primary" link @click="openFileDialog(row)"> 附件 </el-button> </template> </PIMTable> </div> </el-tab-pane> </el-tabs> <PlanModal ref="planModalRef" @ok="getTableData" /> <MaintenanceModal ref="maintainModalRef" @ok="getTableData" /> <FormDia ref="formDiaRef" @closeDia="getScheduledTableData" /> <FileListDialog ref="fileListDialogRef" v-model="fileDialogVisible" :show-upload-button="true" :show-delete-button="true" :delete-method="handleAttachmentDelete" :name-column-label="'附件名称'" :rulesRegulationsManagementId="currentMaintenanceTaskId" @upload="handleAttachmentUpload" /> <PlanModal ref="planModalRef" @ok="getTableData" /> <MaintenanceModal ref="maintainModalRef" @ok="getTableData" /> <FormDia ref="formDiaRef" @closeDia="getScheduledTableData" /> <FileListDialog ref="fileListDialogRef" v-model="fileDialogVisible" :show-upload-button="true" :show-delete-button="true" :delete-method="handleAttachmentDelete" :name-column-label="'附件名称'" :rulesRegulationsManagementId="currentMaintenanceTaskId" @upload="handleAttachmentUpload" /> </div> </template> <script setup> import { ref, onMounted, reactive, getCurrentInstance, nextTick, computed } from 'vue' import { Search } from '@element-plus/icons-vue' import { ElMessage, ElMessageBox } from 'element-plus' import PlanModal from './Form/PlanModal.vue' import MaintenanceModal from './Form/MaintenanceModal.vue' import FormDia from './Form/formDia.vue' import FileListDialog from '@/components/Dialog/FileListDialog.vue' import { getUpkeepPage, delUpkeep, deviceMaintenanceTaskList, deviceMaintenanceTaskDel, } from '@/api/equipmentManagement/upkeep' import { listMaintenanceTaskFiles, addMaintenanceTaskFile, delMaintenanceTaskFile, } from '@/api/equipmentManagement/maintenanceTaskFile' import dayjs from 'dayjs' import { ref, onMounted, reactive, getCurrentInstance, nextTick, computed, } from "vue"; import { Search } from "@element-plus/icons-vue"; import { ElMessage, ElMessageBox } from "element-plus"; import PlanModal from "./Form/PlanModal.vue"; import MaintenanceModal from "./Form/MaintenanceModal.vue"; import FormDia from "./Form/formDia.vue"; import FileListDialog from "@/components/Dialog/FileListDialog.vue"; import { getUpkeepPage, delUpkeep, deviceMaintenanceTaskList, deviceMaintenanceTaskDel, } from "@/api/equipmentManagement/upkeep"; import { listMaintenanceTaskFiles, addMaintenanceTaskFile, delMaintenanceTaskFile, } from "@/api/equipmentManagement/maintenanceTaskFile"; import dayjs from "dayjs"; const { proxy } = getCurrentInstance() const { proxy } = getCurrentInstance(); // Tab相关 const activeTab = ref('scheduled') // Tab相关 const activeTab = ref("scheduled"); // 计划弹窗控制器 const planModalRef = ref() // 保养弹窗控制器 const maintainModalRef = ref() // 定时任务弹窗控制器 const formDiaRef = ref() // 附件弹窗 const fileListDialogRef = ref(null) const fileDialogVisible = ref(false) const currentMaintenanceTaskId = ref(null) // 计划弹窗控制器 const planModalRef = ref(); // 保养弹窗控制器 const maintainModalRef = ref(); // 定时任务弹窗控制器 const formDiaRef = ref(); // 附件弹窗 const fileListDialogRef = ref(null); const fileDialogVisible = ref(false); const currentMaintenanceTaskId = ref(null); // 任务记录tab(原设备保养页面)相关变量 const filters = reactive({ deviceName: '', maintenancePlanTime: '', maintenanceActuallyTime: '', maintenanceActuallyName: '', }) // 任务记录tab(原设备保养页面)相关变量 const filters = reactive({ deviceName: "", maintenancePlanTime: "", maintenanceActuallyTime: "", maintenanceActuallyName: "", }); const dataList = ref([]) const pagination = ref({ currentPage: 1, pageSize: 10, total: 0, }) const multipleList = ref([]) const dataList = ref([]); const pagination = ref({ currentPage: 1, pageSize: 10, total: 0, }); const multipleList = ref([]); // 定时任务管理tab相关变量 const scheduledFilters = reactive({ taskName: '', status: '', }) // 定时任务管理tab相关变量 const scheduledFilters = reactive({ taskName: "", status: "", }); const scheduledDataList = ref([]) const scheduledPagination = reactive({ currentPage: 1, pageSize: 10, total: 0, }) const scheduledMultipleList = ref([]) const scheduledDataList = ref([]); const scheduledPagination = reactive({ currentPage: 1, pageSize: 10, total: 0, }); const scheduledMultipleList = ref([]); // 定时任务管理表格列配置 const scheduledColumns = ref([ { prop: "taskName", label: "设备名称"}, { label: "规格型号", prop: "deviceModel", }, { prop: "frequencyType", label: "频次", minWidth: 150, // PIMTable 使用的是 formatData,而不是 Element-Plus 的 formatter formatData: (cell) => ({ DAILY: "每日", WEEKLY: "每周", MONTHLY: "每月", QUARTERLY: "季度" }[cell] || "") }, { prop: "frequencyDetail", label: "开始日期与时间", minWidth: 150, // 同样改用 formatData,PIMTable 内部会把单元格值传进来 formatData: (cell) => { if (typeof cell !== 'string') return ''; let val = cell; const replacements = { MON: '周一', TUE: '周二', WED: '周三', THU: '周四', FRI: '周五', SAT: '周六', SUN: '周日' }; // 使用正则一次性替换所有匹配项 return val.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, match => replacements[match]); } }, { prop: "registrant", label: "登记人", minWidth: 100 }, { prop: "registrationDate", label: "登记日期", minWidth: 100 }, { fixed: "right", label: "操作", dataType: "slot", slot: "operation", align: "center", width: "200px", }, ]) // 定时任务管理表格列配置 const scheduledColumns = ref([ { prop: "taskName", label: "设备名称" }, { label: "规格型号", prop: "deviceModel", }, { prop: "frequencyType", label: "频次", minWidth: 150, // PIMTable 使用的是 formatData,而不是 Element-Plus 的 formatter formatData: cell => ({ DAILY: "每日", WEEKLY: "每周", MONTHLY: "每月", QUARTERLY: "季度", }[cell] || ""), }, { prop: "frequencyDetail", label: "开始日期与时间", minWidth: 150, // 同样改用 formatData,PIMTable 内部会把单元格值传进来 formatData: cell => { if (typeof cell !== "string") return ""; let val = cell; const replacements = { MON: "周一", TUE: "周二", WED: "周三", THU: "周四", FRI: "周五", SAT: "周六", SUN: "周日", }; // 使用正则一次性替换所有匹配项 return val.replace( /MON|TUE|WED|THU|FRI|SAT|SUN/g, match => replacements[match] ); }, }, { prop: "registrant", label: "登记人", minWidth: 100 }, { prop: "registrationDate", label: "登记日期", minWidth: 100 }, { fixed: "right", label: "操作", dataType: "slot", slot: "operation", align: "center", width: "200px", }, ]); // 任务记录表格列配置(原设备保养表格列) const columns = ref([ { label: "设备名称", align: "center", prop: "deviceName", }, { label: "规格型号", align: "center", prop: "deviceModel", }, { label: "计划保养日期", align: "center", prop: "maintenancePlanTime", formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"), }, { label: "录入人", align: "center", prop: "createUserName", }, // { // label: "录入日期", // align: "center", // prop: "createTime", // formatData: (cell) => dayjs(cell).format("YYYY-MM-DD HH:mm:ss"), // width: 200, // }, { label: "实际保养人", align: "center", prop: "maintenanceActuallyName", }, { label: "实际保养日期", align: "center", prop: "maintenanceActuallyTime", formatData: (cell) => cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : "-", }, { label: "保养结果", align: "center", prop: "maintenanceResult", dataType: "slot", slot: "maintenanceResultRef", }, { label: "状态", align: "center", prop: "status", dataType: "slot", slot: "statusRef", }, { fixed: "right", label: "操作", dataType: "slot", slot: "operation", align: "center", width: "350px", }, ]) // 任务记录表格列配置(原设备保养表格列) const columns = ref([ { label: "设备名称", align: "center", prop: "deviceName", }, { label: "规格型号", align: "center", prop: "deviceModel", }, { label: "计划保养日期", align: "center", prop: "maintenancePlanTime", formatData: cell => dayjs(cell).format("YYYY-MM-DD"), }, { label: "录入人", align: "center", prop: "createUserName", }, // { // label: "录入日期", // align: "center", // prop: "createTime", // formatData: (cell) => dayjs(cell).format("YYYY-MM-DD HH:mm:ss"), // width: 200, // }, { label: "实际保养人", align: "center", prop: "maintenanceActuallyName", }, { label: "实际保养日期", align: "center", prop: "maintenanceActuallyTime", formatData: cell => cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : "-", }, { label: "保养结果", align: "center", prop: "maintenanceResult", dataType: "slot", slot: "maintenanceResultRef", }, { label: "状态", align: "center", prop: "status", dataType: "slot", slot: "statusRef", }, { fixed: "right", label: "操作", dataType: "slot", slot: "operation", align: "center", width: "350px", }, ]); // Tab切换处理 const handleTabChange = (tabName) => { if (tabName === 'record') { getTableData() } else if (tabName === 'scheduled') { getScheduledTableData() } } // 定时任务管理相关方法 const getScheduledTableData = async () => { try { const params = { current: scheduledPagination.currentPage, size: scheduledPagination.pageSize, taskName: scheduledFilters.taskName || undefined, status: scheduledFilters.status || undefined, // Tab切换处理 const handleTabChange = tabName => { if (tabName === "record") { getTableData(); } else if (tabName === "scheduled") { getScheduledTableData(); } const { code, data } = await deviceMaintenanceTaskList(params) if (code === 200) { scheduledDataList.value = data?.records || [] scheduledPagination.total = data?.total || 0 }; // 定时任务管理相关方法 const getScheduledTableData = async () => { try { const params = { current: scheduledPagination.currentPage, size: scheduledPagination.pageSize, taskName: scheduledFilters.taskName || undefined, status: scheduledFilters.status || undefined, }; const { code, data } = await deviceMaintenanceTaskList(params); if (code === 200) { scheduledDataList.value = data?.records || []; scheduledPagination.total = data?.total || 0; } } catch (error) { ElMessage.error("获取定时任务列表失败"); } } catch (error) { ElMessage.error('获取定时任务列表失败') } } }; const resetScheduledFilters = () => { scheduledFilters.taskName = '' scheduledFilters.status = '' getScheduledTableData() } const resetScheduledFilters = () => { scheduledFilters.taskName = ""; scheduledFilters.status = ""; getScheduledTableData(); }; const handleScheduledSelectionChange = (selection) => { scheduledMultipleList.value = selection } const handleScheduledSelectionChange = selection => { scheduledMultipleList.value = selection; }; const changeScheduledPage = (page) => { scheduledPagination.currentPage = page.page scheduledPagination.pageSize = page.limit getScheduledTableData() } const changeScheduledPage = page => { scheduledPagination.currentPage = page.page; scheduledPagination.pageSize = page.limit; getScheduledTableData(); }; const addScheduledTask = () => { nextTick(() => { formDiaRef.value?.openDialog('add'); }); } const addScheduledTask = () => { nextTick(() => { formDiaRef.value?.openDialog("add"); }); }; const editScheduledTask = (row) => { if (row) { nextTick(() => { formDiaRef.value?.openDialog('edit', row); }); } } const editScheduledTask = row => { if (row) { nextTick(() => { formDiaRef.value?.openDialog("edit", row); }); } }; const delScheduledTaskByIds = async (ids) => { try { await ElMessageBox.confirm('确定删除选中的定时任务吗?', '提示', { type: 'warning', const delScheduledTaskByIds = async ids => { try { await ElMessageBox.confirm("确定删除选中的定时任务吗?", "提示", { type: "warning", }); const payload = Array.isArray(ids) ? ids : [ids]; await deviceMaintenanceTaskDel(payload); ElMessage.success("删除定时任务成功"); getScheduledTableData(); } catch (error) { // 用户取消删除 } }; const handleScheduledOut = () => { ElMessage.info("导出定时任务功能待实现"); }; // 任务记录相关方法(原设备保养页面方法) const getTableData = async () => { try { const params = { current: pagination.value.currentPage, size: pagination.value.pageSize, deviceName: filters.deviceName || undefined, maintenancePlanTime: filters.maintenancePlanTime ? dayjs(filters.maintenancePlanTime).format("YYYY-MM-DD") : undefined, maintenanceActuallyTime: filters.maintenanceActuallyTime ? dayjs(filters.maintenanceActuallyTime).format("YYYY-MM-DD") : undefined, maintenanceActuallyName: filters.maintenanceActuallyName || undefined, }; const { code, data } = await getUpkeepPage(params); if (code === 200) { dataList.value = data.records; pagination.value.total = data.total; } } catch (error) { console.log(error); } }; const resetFilters = () => { filters.deviceName = ""; filters.maintenancePlanTime = ""; filters.maintenanceActuallyTime = ""; filters.maintenanceActuallyName = ""; getTableData(); }; const handleSelectionChange = selection => { multipleList.value = selection; }; // 检查选中的记录中是否有完结状态的 const hasFinishedStatus = computed(() => { return multipleList.value.some(item => item.status === 1); }); const changePage = page => { pagination.value.currentPage = page.page; pagination.value.pageSize = page.limit; getTableData(); }; const addMaintain = row => { maintainModalRef.value.open(row.id, row); }; const addPlan = () => { planModalRef.value.openModal(); }; const editPlan = id => { planModalRef.value.openEdit(id); }; const delRepairByIds = async ids => { // 检查是否有完结状态的记录 const hasFinished = multipleList.value.some(item => item.status === 1); if (hasFinished) { ElMessage.warning("不能删除状态为完结的记录"); return; } try { await ElMessageBox.confirm("确认删除保养数据, 此操作不可逆?", "警告", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning", }); const { code } = await delUpkeep(ids); if (code === 200) { ElMessage.success("删除成功"); getTableData(); } } catch (error) { // 用户取消删除 } }; const handleOut = () => { ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) const payload = Array.isArray(ids) ? ids : [ids] await deviceMaintenanceTaskDel(payload) ElMessage.success('删除定时任务成功') getScheduledTableData() } catch (error) { // 用户取消删除 } } .then(() => { proxy.download("/device/maintenance/export", {}, "设备保养.xlsx"); }) .catch(() => { ElMessage.info("已取消"); }); }; const handleScheduledOut = () => { ElMessage.info('导出定时任务功能待实现') } // 任务记录相关方法(原设备保养页面方法) const getTableData = async () => { try { const params = { current: pagination.value.currentPage, size: pagination.value.pageSize, deviceName: filters.deviceName || undefined, maintenancePlanTime: filters.maintenancePlanTime ? dayjs(filters.maintenancePlanTime).format('YYYY-MM-DD') : undefined, maintenanceActuallyTime: filters.maintenanceActuallyTime ? dayjs(filters.maintenanceActuallyTime).format('YYYY-MM-DD') : undefined, maintenanceActuallyName: filters.maintenanceActuallyName || undefined, const handleDateChange = (date, type) => { if (type === 1) { filters.maintenanceActuallyTime = date ? dayjs(date).format("YYYY-MM-DD") : ""; } else { filters.maintenancePlanTime = date ? dayjs(date).format("YYYY-MM-DD") : ""; } getTableData(); }; const { code, data } = await getUpkeepPage(params) if (code === 200) { dataList.value = data.records pagination.value.total = data.total // 附件相关方法 // 查询附件列表 const fetchMaintenanceTaskFiles = async deviceMaintenanceId => { try { const params = { current: 1, size: 100, deviceMaintenanceId, rulesRegulationsManagementId: deviceMaintenanceId, }; const res = await listMaintenanceTaskFiles(params); const records = res?.data?.records || []; const mapped = records.map(item => ({ id: item.id, name: item.fileName || item.name, url: item.fileUrl || item.url, raw: item, })); fileListDialogRef.value?.setList(mapped); } catch (error) { ElMessage.error("获取附件列表失败"); } } catch (error) { console.log(error); } } }; const resetFilters = () => { filters.deviceName = '' filters.maintenancePlanTime = '' filters.maintenanceActuallyTime = '' filters.maintenanceActuallyName = '' getTableData() } // 打开附件弹窗 const openFileDialog = async row => { currentMaintenanceTaskId.value = row.id; fileDialogVisible.value = true; await fetchMaintenanceTaskFiles(row.id); }; const handleSelectionChange = (selection) => { multipleList.value = selection } // 刷新附件列表 const refreshFileList = async () => { if (!currentMaintenanceTaskId.value) return; await fetchMaintenanceTaskFiles(currentMaintenanceTaskId.value); }; // 检查选中的记录中是否有完结状态的 const hasFinishedStatus = computed(() => { return multipleList.value.some(item => item.status === 1) }) const changePage = (page) => { pagination.value.currentPage = page.page pagination.value.pageSize = page.limit getTableData() } const addMaintain = (row) => { maintainModalRef.value.open(row.id, row) } const addPlan = () => { planModalRef.value.openModal() } const editPlan = (id) => { planModalRef.value.openEdit(id) } const delRepairByIds = async (ids) => { // 检查是否有完结状态的记录 const hasFinished = multipleList.value.some(item => item.status === 1) if (hasFinished) { ElMessage.warning('不能删除状态为完结的记录') return } try { await ElMessageBox.confirm('确认删除保养数据, 此操作不可逆?', '警告', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', }) const { code } = await delUpkeep(ids) if (code === 200) { ElMessage.success('删除成功') getTableData() // 上传附件 const handleAttachmentUpload = async filePayload => { if (!currentMaintenanceTaskId.value) return; try { const payload = { name: filePayload?.fileName || filePayload?.name, url: filePayload?.fileUrl || filePayload?.url, deviceMaintenanceId: currentMaintenanceTaskId.value, }; await addMaintenanceTaskFile(payload); ElMessage.success("文件上传成功"); await refreshFileList(); } catch (error) { ElMessage.error("文件上传失败"); } } catch (error) { // 用户取消删除 } } }; const handleOut = () => { ElMessageBox.confirm('选中的内容将被导出,是否确认导出?', '导出', { confirmButtonText: '确认', cancelButtonText: '取消', type: 'warning', }) .then(() => { proxy.download('/device/maintenance/export', {}, '设备保养.xlsx') }) .catch(() => { ElMessage.info('已取消') }) } const handleDateChange = (date, type) => { if (type === 1) { filters.maintenanceActuallyTime = date ? dayjs(date).format('YYYY-MM-DD') : '' } else { filters.maintenancePlanTime = date ? dayjs(date).format('YYYY-MM-DD') : '' } getTableData() } // 附件相关方法 // 查询附件列表 const fetchMaintenanceTaskFiles = async (deviceMaintenanceId) => { try { const params = { current: 1, size: 100, deviceMaintenanceId, rulesRegulationsManagementId:deviceMaintenanceId // 删除附件 const handleAttachmentDelete = async row => { if (!row?.id) return false; try { await ElMessageBox.confirm("确认删除该附件?", "提示", { type: "warning" }); } catch { return false; } const res = await listMaintenanceTaskFiles(params) const records = res?.data?.records || [] const mapped = records.map(item => ({ id: item.id, name: item.fileName || item.name, url: item.fileUrl || item.url, raw: item, })) fileListDialogRef.value?.setList(mapped) } catch (error) { ElMessage.error('获取附件列表失败') } } // 打开附件弹窗 const openFileDialog = async (row) => { currentMaintenanceTaskId.value = row.id fileDialogVisible.value = true await fetchMaintenanceTaskFiles(row.id) } // 刷新附件列表 const refreshFileList = async () => { if (!currentMaintenanceTaskId.value) return await fetchMaintenanceTaskFiles(currentMaintenanceTaskId.value) } // 上传附件 const handleAttachmentUpload = async (filePayload) => { if (!currentMaintenanceTaskId.value) return try { const payload = { name: filePayload?.fileName || filePayload?.name, url: filePayload?.fileUrl || filePayload?.url, deviceMaintenanceId: currentMaintenanceTaskId.value, try { await delMaintenanceTaskFile(row.id); ElMessage.success("删除成功"); await refreshFileList(); return true; } catch (error) { ElMessage.error("删除失败"); return false; } await addMaintenanceTaskFile(payload) ElMessage.success('文件上传成功') await refreshFileList() } catch (error) { ElMessage.error('文件上传失败') } } }; // 删除附件 const handleAttachmentDelete = async (row) => { if (!row?.id) return false try { await ElMessageBox.confirm('确认删除该附件?', '提示', { type: 'warning' }) } catch { return false } try { await delMaintenanceTaskFile(row.id) ElMessage.success('删除成功') await refreshFileList() return true } catch (error) { ElMessage.error('删除失败') return false } } onMounted(() => { // 根据默认激活的 Tab 调用对应的查询接口 if (activeTab.value === 'scheduled') { getScheduledTableData() } else { getTableData() } }) onMounted(() => { // 根据默认激活的 Tab 调用对应的查询接口 if (activeTab.value === "scheduled") { getScheduledTableData(); } else { getTableData(); } }); </script> <style lang="scss" scoped> .table_list { margin-top: unset; } .actions { display: flex; justify-content: space-between; margin-bottom: 10px; } .table_list { margin-top: unset; } .actions { display: flex; justify-content: space-between; margin-bottom: 10px; } </style>