From dacff5e32b70abcb4b7942d919ba291d058c3439 Mon Sep 17 00:00:00 2001 From: liugongyu <290219706@qq.com> Date: Mon, 22 Dec 2025 14:56:46 +0800 Subject: [PATCH] 养护员退回 --- common/utils/common.js | 1 + common/utils/useUploadImgs.js | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----------- pages-sub/daily/patrol-manage/add-patrol-record.vue | 1 + pages-sub/problem/work-order-manage/add-maintain-order.vue | 383 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------- pages-sub/problem/work-order-manage/distribution-order.vue | 4 +++- pages-sub/problem/work-order-manage/index.vue | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------- pages-sub/problem/work-order-manage/order-detail.vue | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------- 7 files changed, 517 insertions(+), 155 deletions(-) diff --git a/common/utils/common.js b/common/utils/common.js index f7e8658..62c134e 100644 --- a/common/utils/common.js +++ b/common/utils/common.js @@ -11,6 +11,7 @@ export const nextStepMap = { name: '养护员待实施', btnText: '实施', operateTypePass: 120, + operateTypeNoPass: 220, backShow: true, renewShow: false }, diff --git a/common/utils/useUploadImgs.js b/common/utils/useUploadImgs.js index 9e470f6..638881c 100644 --- a/common/utils/useUploadImgs.js +++ b/common/utils/useUploadImgs.js @@ -19,18 +19,32 @@ export function useUploadImgs(config) { const imgList = ref([]) /** + * 新增:清空所有图片 + * 功能:重置图片列表为空,并触发表单字段校验(如果有表单Ref) + */ + const clearImgs = () => { + imgList.value = []; + // 优化:先判断 formRef 存在,再判断 formRef.value 存在 + if (defaultConfig.formRef && defaultConfig.formRef.value && defaultConfig.fieldName) { + defaultConfig.formRef.value.validateField(defaultConfig.fieldName); + } + }; + + + /** * 删除图片 */ const deleteImg = (event) => { - // 确保index是有效数字 - const index = Number(event.index) - if (isNaN(index) || index < 0 || index >= imgList.value.length) return - - imgList.value.splice(index, 1) - // 删除后重新校验 - defaultConfig.formRef.value?.validateField(defaultConfig.fieldName) - uni.showToast({ title: '图片删除成功', icon: 'success' }) - } + const index = Number(event.index); + if (isNaN(index) || index < 0 || index >= imgList.value.length) return; + + imgList.value.splice(index, 1); + // 修复:先判断 formRef 存在,再访问 value + if (defaultConfig.formRef && defaultConfig.formRef.value && defaultConfig.fieldName) { + defaultConfig.formRef.value.validateField(defaultConfig.fieldName); + } + uni.showToast({ title: '图片删除成功', icon: 'success' }); + }; /** * 上传图片(适配u-upload的file格式) @@ -106,7 +120,9 @@ export function useUploadImgs(config) { } // 上传完成后校验 - defaultConfig.formRef.value?.validateField(defaultConfig.fieldName) + if (defaultConfig.formRef && defaultConfig.formRef.value && defaultConfig.fieldName) { + defaultConfig.formRef.value.validateField(defaultConfig.fieldName); + } } catch (err) { console.error(`【${defaultConfig.fieldName}】图片上传失败:`, err) // 标记所有上传失败 @@ -147,11 +163,39 @@ export function useUploadImgs(config) { } } + /** + * 新增:批量设置图片列表(图片回显核心方法,替代业务页面的setUploadImgsList) + * @param imgUrls 图片URL数组(如:['https://xxx.jpg', 'https://yyy.png']) + * 功能:将纯URL数组转换为u-upload兼容格式,实现静默回显,无数据时不提示 + */ + const setImgList = (imgUrls = []) => { + // 容错处理:校验参数有效性,非数组/空数组直接重置 + if (!Array.isArray(imgUrls) || imgUrls.length === 0) { + imgList.value = [] + return + } + + // 转换为u-upload兼容的格式(status: success 标记为已成功上传,可正常显示/删除) + const formatImgList = imgUrls.map(url => ({ + url: url, + status: 'success', // 关键:标记为成功状态,兼容后续删除/校验逻辑 + message: '', + name: url.substring(url.lastIndexOf('/') + 1), // 从URL截取文件名,优化显示 + size: 0 // 历史图片无大小信息,默认0不影响使用 + })) + + // 额外优化:限制回显数量不超过maxCount,避免异常 + const finalImgList = formatImgList.slice(0, defaultConfig.maxCount) + imgList.value = finalImgList + } + return { - imgList: imgList.value, // 核心修复:返回纯数组(解除响应式代理) + imgList: imgList, // 核心修复:返回纯数组(解除响应式代理) rawImgList: imgList, // 保留响应式引用(内部使用) uploadImgs, deleteImg, + clearImgs, + setImgList, getSuccessImgUrls, imgValidateRule, uploadConfig: defaultConfig diff --git a/pages-sub/daily/patrol-manage/add-patrol-record.vue b/pages-sub/daily/patrol-manage/add-patrol-record.vue index 79e1aa2..5a184d9 100644 --- a/pages-sub/daily/patrol-manage/add-patrol-record.vue +++ b/pages-sub/daily/patrol-manage/add-patrol-record.vue @@ -10,6 +10,7 @@ > - + { + try { + // 1. 校验tempKey是否缺失 + if (!options || !options.tempKey) { + uni.showToast({ + title: '缺失工单缓存Key,无法加载数据', + icon: 'none', + duration: 3000 + }); + console.error('onLoad异常:options或tempKey缺失'); + return; + } + const { tempKey } = options; + let orderItem = {}; + // 2. 读取缓存并校验缓存数据是否有效 + orderItem = uni.getStorageSync(tempKey) || {}; + if (JSON.stringify(orderItem) === '{}') { + uni.showToast({ + title: '工单缓存数据为空,请重新进入', + icon: 'none', + duration: 3000 + }); + console.error('onLoad异常:工单缓存数据为空'); + // 可选:返回上一页 + // setTimeout(() => uni.navigateBack(), 1500); + return; + } - workOrderForm.workerDataId = options.id - workOrderForm.taskId = options.taskId - workOrderForm.orderNo = options.orderNo + // 可选:读取后移除缓存,避免冗余数据 + uni.removeStorageSync(tempKey); - console.log('从URL获取工单编号:', workOrderForm.taskId) + // 3. 填充基础表单数据(存在则赋值,不存在则提示) + if (!orderItem.id) { + uni.showToast({ + title: '缺失工单ID,数据异常', + icon: 'none', + duration: 2000 + }); + console.warn('工单数据缺失:id'); + } + if (!orderItem.taskId) { + uni.showToast({ + title: '缺失任务ID,提交可能失败', + icon: 'none', + duration: 2000 + }); + console.warn('工单数据缺失:taskId'); + } + if (!orderItem.orderNo) { + uni.showToast({ + title: '缺失工单编号,数据异常', + icon: 'none', + duration: 2000 + }); + console.warn('工单数据缺失:orderNo'); + } + + workOrderForm.workerDataId = orderItem.id || ''; + workOrderForm.taskId = orderItem.taskId || ''; + workOrderForm.orderNo = orderItem.orderNo || ''; + workOrderForm.reason = orderItem.handleResult || ''; // 处理情况回显 + + // 共同处理人(如有数据则回显) + if (orderItem.coHandlers && orderItem.coHandlersName) { + workOrderForm.coProcessorId = orderItem.coHandlers; + workOrderForm.coProcessorName = orderItem.coHandlersName; + } else { + console.warn('工单数据提示:无共同处理人信息'); + } + + // 4. 回显各类图片:使用 useUploadImgs 内置 setImgList 方法(自动添加 status: 'success') + // 校验图片字段是否存在,不存在则赋值空数组,避免报错 + const startImgsArr = orderItem.startImgs || []; + const processingImgsArr = orderItem.processingImgs || []; + const endImgsArr = orderItem.endImgs || []; + const personImgsArr = orderItem.personImgs || []; + const materialImgsArr = orderItem.materialImgs || []; + + // 图片回显前校验数组有效性 + if (!Array.isArray(startImgsArr)) { + uni.showToast({ + title: '开始图片数据格式异常', + icon: 'none', + duration: 2000 + }); + console.error('开始图片异常:非数组格式'); + } + if (!Array.isArray(endImgsArr)) { + uni.showToast({ + title: '结束图片数据格式异常', + icon: 'none', + duration: 2000 + }); + console.error('结束图片异常:非数组格式'); + } + + startImgs.setImgList(startImgsArr); + processingImgs.setImgList(processingImgsArr); + endImgs.setImgList(endImgsArr); + personImgs.setImgList(personImgsArr); + materialImgs.setImgList(materialImgsArr); + + // 5. 校验必填图片(开始/结束)是否为空,提前提示 + if (startImgsArr.length === 0) { + uni.showToast({ + title: '开始图片为空,请补充上传', + icon: 'none', + duration: 2000 + }); + console.warn('工单提示:开始图片数组为空'); + } + if (endImgsArr.length === 0) { + uni.showToast({ + title: '结束图片为空,请补充上传', + icon: 'none', + duration: 2000 + }); + console.warn('工单提示:结束图片数组为空'); + } + + console.log('工单数据初始化完成:', workOrderForm); + } catch (error) { + uni.showToast({ + title: '工单数据加载失败,请重试', + icon: 'none', + duration: 3000 + }); + console.error('获取工单缓存数据失败:', error); + // 可选:返回上一页 + // setTimeout(() => uni.navigateBack(), 1500); + } }) // 生命周期 - 初始化表单规则 onReady(() => { - if (workOrderFormRef.value) { - workOrderFormRef.value.setRules(workOrderFormRules) + // 校验表单实例是否存在 + if (!workOrderFormRef.value) { + uni.showToast({ + title: '表单实例初始化失败', + icon: 'none', + duration: 2000 + }); + console.error('onReady异常:workOrderFormRef.value 为空'); + return; } - console.log('工单表单规则初始化完成') + workOrderFormRef.value.setRules(workOrderFormRules) }) // 生命周期 - 加载共同处理人列表 @@ -329,32 +454,77 @@ const loadCoProcessorList = async () => { pageSize: 100 } const res = await getYlWorkersPage(queryData) + + // 校验接口返回数据是否有效 + if (!res || !res.list) { + uni.showToast({ + title: '获取处理人列表失败(无数据)', + icon: 'none', + duration: 2000 + }); + console.error('loadCoProcessorList异常:接口返回无有效数据'); + coProcessorList.value = []; + uni.hideLoading(); + return; + } + uni.hideLoading() if (res.list && res.list.length > 0) { - coProcessorList.value = res.list.map(item => ({ - name: item.nickname, - value: item.id, - id: item.id - })) - console.log('共同处理人列表:', coProcessorList.value) + coProcessorList.value = res.list.map(item => { + // 校验列表项是否含必填字段 + if (!item.id || !item.nickname) { + console.warn('处理人列表项异常:缺失id或nickname', item); + return null; + } + return { + name: item.nickname, + value: item.id, + id: item.id + } + }).filter(Boolean); // 过滤null项 } else { coProcessorList.value = [] - uni.showToast({ title: '未查询到处理人数据', icon: 'none' }) + uni.showToast({ + title: '暂无共同处理人数据', + icon: 'none', + duration: 2000 + }); + console.warn('loadCoProcessorList提示:处理人列表为空'); } } catch (err) { uni.hideLoading() + uni.showToast({ + title: '获取处理人列表失败,请重试', + icon: 'none', + duration: 3000 + }); console.error('获取共同处理人列表失败:', err) - uni.showToast({ title: '获取处理人失败,请重试', icon: 'none' }) coProcessorList.value = [] } } // 打开通用下拉弹窗(仅共同处理人) const handleActionSheetOpen = (type) => { - // 共同处理人列表为空提示 + // 校验弹窗类型是否为支持的类型 + if (type !== 'coProcessor') { + uni.showToast({ + title: '不支持该弹窗类型', + icon: 'none', + duration: 2000 + }); + console.error('handleActionSheetOpen异常:不支持的弹窗类型', type); + return; + } + + // 共同处理人列表为空时,提示并返回 if (type === 'coProcessor' && coProcessorList.value.length === 0) { - uni.showToast({ title: '暂无处理人数据可选', icon: 'none' }) + uni.showToast({ + title: '暂无共同处理人可选', + icon: 'none', + duration: 2000 + }); + console.warn('handleActionSheetOpen提示:共同处理人列表为空'); return } @@ -375,6 +545,7 @@ const handleActionSheetOpen = (type) => { // 关闭通用下拉弹窗 const handleActionSheetClose = () => { showActionSheet.value = false + // 重置弹窗数据,避免残留 currentActionSheetData.type = '' currentActionSheetData.list = [] currentActionSheetData.title = '' @@ -382,20 +553,45 @@ const handleActionSheetClose = () => { // 下拉弹窗选择事件(仅处理共同处理人多选) const handleActionSheetSelect = (e) => { - console.log(e) + // 校验事件参数是否有效 + if (!e || !e.name || !e.id) { + uni.showToast({ + title: '选择处理人失败(参数异常)', + icon: 'none', + duration: 2000 + }); + console.error('handleActionSheetSelect异常:e参数缺失name或id', e); + showActionSheet.value = false; + return; + } + const { type } = currentActionSheetData // 多选场景(仅共同处理人) if (type === 'coProcessor') { workOrderForm.coProcessorName = e.name workOrderForm.coProcessorId = e.id - workOrderFormRef.value?.validateField('coProcessorName') + // 校验表单实例是否存在,再执行字段校验 + if (workOrderFormRef.value) { + workOrderFormRef.value?.validateField('coProcessorName') + } else { + console.warn('handleActionSheetSelect提示:表单实例不存在,跳过字段校验'); + } } showActionSheet.value = false } // 图片切换选择 const imgTabChange = (item)=> { - console.log(item) + // 校验切换参数是否有效 + if (!item || item.index === undefined || item.index === null) { + uni.showToast({ + title: '图片标签切换失败(参数异常)', + icon: 'none', + duration: 2000 + }); + console.error('imgTabChange异常:item参数缺失index', item); + return; + } activeTab.value = item.index } @@ -407,66 +603,141 @@ const hideKeyboard = () => { // 提交工单(整合所有图片URL,增加开始/结束图片必填校验) const submitWorkOrder = async () => { try { - // ========== 新增:校验开始和结束阶段图片至少各1张 ========== + // ========== 前置校验:表单实例是否存在 ========== + if (!workOrderFormRef.value) { + uni.showToast({ + title: '表单实例异常,无法提交', + icon: 'none', + duration: 2000 + }); + console.error('submitWorkOrder异常:workOrderFormRef.value 为空'); + return; + } + + // ========== 开始/结束图片必填校验 ========== const startImgUrls = startImgs.getSuccessImgUrls(); // 开始阶段图片URL数组 const endImgUrls = endImgs.getSuccessImgUrls(); // 结束阶段图片URL数组 + // 打印日志验证(可选,用于排查) + console.log('开始图片有效URL:', startImgUrls); + console.log('结束图片有效URL:', endImgUrls); + // 判断开始图片是否为空 - if (startImgUrls.length === 0) { + if (!Array.isArray(startImgUrls) || startImgUrls.length === 0) { uni.showToast({ title: '请至少上传1张开始阶段图片', icon: 'none', duration: 2000 }); + console.warn('submitWorkOrder校验失败:开始图片为空'); return; // 终止提交流程 } // 判断结束图片是否为空 - if (endImgUrls.length === 0) { + if (!Array.isArray(endImgUrls) || endImgUrls.length === 0) { uni.showToast({ title: '请至少上传1张结束阶段图片', icon: 'none', duration: 2000 }); + console.warn('submitWorkOrder校验失败:结束图片为空'); return; // 终止提交流程 } - // ========== 图片校验结束 ========== - // 原有表单校验 + // ========== 处理情况必填校验(兜底,防止表单校验失效) ========== + if (!workOrderForm.reason || workOrderForm.reason.trim().length === 0) { + uni.showToast({ + title: '请输入处理情况描述', + icon: 'none', + duration: 2000 + }); + console.warn('submitWorkOrder校验失败:处理情况为空'); + return; + } + if (workOrderForm.reason.trim().length > 200) { + uni.showToast({ + title: '处理情况描述不能超过200字', + icon: 'none', + duration: 2000 + }); + console.warn('submitWorkOrder校验失败:处理情况超过200字'); + return; + } + + // ========== 原有表单校验 ========== await workOrderFormRef.value.validate() + // ========== 校验核心提交参数 ========== + if (!workOrderForm.taskId) { + uni.showToast({ + title: '缺失任务ID,无法提交', + icon: 'none', + duration: 2000 + }); + console.error('submitWorkOrder异常:taskId 为空'); + return; + } + if (!workOrderForm.workerDataId) { + uni.showToast({ + title: '缺失工单ID,无法提交', + icon: 'none', + duration: 2000 + }); + console.error('submitWorkOrder异常:workerDataId 为空'); + return; + } + // 构造所有图片URL(原有代码不变) const allImgs = { - startImgs: startImgUrls, // 直接使用已获取的开始图片URL - processingImgs: processingImgs.getSuccessImgUrls(), - endImgs: endImgUrls, // 直接使用已获取的结束图片URL - personImgs: personImgs.getSuccessImgUrls(), - materialImgs: materialImgs.getSuccessImgUrls() + startImgs: startImgUrls, + processingImgs: processingImgs.getSuccessImgUrls() || [], + endImgs: endImgUrls, + personImgs: personImgs.getSuccessImgUrls() || [], + materialImgs: materialImgs.getSuccessImgUrls() || [] } - // 构造提交参数(可按需调整图片字段格式,此处既保留分类也提供合并数组) + // 构造提交参数 const submitData = { taskId: workOrderForm.taskId, taskKey:'ylWorker', - operateType:nextStepMap['ylWorker'].operateTypePass, - workerDataId:Number(workOrderForm.workerDataId), - // nextStepMap + operateType: nextStepMap['ylWorker']?.operateTypePass || '', // 兜底:防止nextStepMap缺失属性 + workerDataId: Number(workOrderForm.workerDataId) || '', handleResult: workOrderForm.reason.trim(), - coHandlers: [String(workOrderForm.coProcessorId)], // 数组格式提交,如需字符串可.join(',') - // busiLine: 'yl', - // // 分类图片URL + coHandlers: workOrderForm.coProcessorId ? [String(workOrderForm.coProcessorId)] : [], startImgs: allImgs.startImgs, processingImgs: allImgs.processingImgs, endImgs: allImgs.endImgs, personImgs: allImgs.personImgs, materialImgs: allImgs.materialImgs, - problemsImgs:[] } - console.log(submitData) + + // 校验operateType是否有效 + if (!submitData.operateType) { + uni.showToast({ + title: '提交类型异常,无法提交', + icon: 'none', + duration: 2000 + }); + console.error('submitWorkOrder异常:operateType 为空'); + return; + } uni.showLoading({ title: '提交中...' }) const res = await universalApproval(submitData) + + // 校验接口返回结果 + if (!res) { + uni.hideLoading(); + uni.showToast({ + title: '工单提交失败(接口无返回)', + icon: 'none', + duration: 3000 + }); + console.error('submitWorkOrder异常:universalApproval接口无有效返回'); + return; + } + uni.hideLoading() uni.showToast({ @@ -484,14 +755,16 @@ const submitWorkOrder = async () => { } catch (error) { uni.hideLoading() - // 区分校验失败和接口失败 + // 区分校验失败和接口失败,仅接口失败时提示(校验失败已有内置提示) if (!Array.isArray(error)) { - console.error('工单提交失败:', error) uni.showToast({ title: '提交失败,请重试', icon: 'none', duration: 2000 - }) + }); + console.error('工单提交失败:', error) + } else { + console.warn('工单提交校验失败:', error); } } } @@ -501,7 +774,7 @@ const submitWorkOrder = async () => { // 页面容器样式 .page-container { min-height: 100vh; - padding-bottom: 100rpx; // 给底部按钮留空间,与参考示例一致 + padding-bottom: 100rpx; // 给底部按钮留空间 } // 表单内容容器 @@ -515,7 +788,7 @@ const submitWorkOrder = async () => { background: #fff; } -// 新增:Tab自定义内容样式(红色*号) +// Tab自定义内容样式(红色*号) .tab-item-content { display: flex; align-items: center; @@ -528,8 +801,6 @@ const submitWorkOrder = async () => { } .tab-text { - font-size: 28rpx; // 与原有Tab文字大小一致 + font-size: 28rpx; } - - \ No newline at end of file diff --git a/pages-sub/problem/work-order-manage/distribution-order.vue b/pages-sub/problem/work-order-manage/distribution-order.vue index e79f8c1..3448223 100644 --- a/pages-sub/problem/work-order-manage/distribution-order.vue +++ b/pages-sub/problem/work-order-manage/distribution-order.vue @@ -96,6 +96,7 @@ const currentActionSheetData = reactive({ const assigneeList = ref([]) // 养护员列表 // ========== 工单表单数据(仅保留所需字段) ========== const workOrderForm = reactive({ + id:'', taskId:'', orderNo: '', // 工单编号(对应接口参数id) assigneeId: '', // 养护员ID(对应接口参数nextAssignee) @@ -118,7 +119,7 @@ onLoad((options) => { if (options && options.orderNo) { workOrderForm.orderNo = options.orderNo workOrderForm.taskId = options.taskId - + workOrderForm.id = options.id } console.log('从URL获取工单编号:', workOrderForm.orderNo) }) @@ -229,6 +230,7 @@ const submitWorkOrder = async () => { } // 3. 构造接口所需参数 const submitData = { + workerDataId:workOrderForm.id, operateType: nextStepMap['ylTeamLeader'].operateTypePass, taskKey:'ylTeamLeader', agree:0, diff --git a/pages-sub/problem/work-order-manage/index.vue b/pages-sub/problem/work-order-manage/index.vue index 94cf804..df913ca 100644 --- a/pages-sub/problem/work-order-manage/index.vue +++ b/pages-sub/problem/work-order-manage/index.vue @@ -181,28 +181,25 @@ > - - - - + 上传图片(选填) @@ -244,7 +241,7 @@ @@ -327,7 +348,7 @@ onShow(() => { // Tab内容区 .tab-content { - padding: 16rpx; + //padding: 16rpx; } // 工单详情内容 -- libgit2 0.21.4