Commit 371cf0ebe66a054cdf898be8706fe122dde4ccc3
1 parent
dacff5e3
流程节点
Showing
2 changed files
with
236 additions
and
53 deletions
pages-sub/problem/work-order-manage/add-maintain-order.vue
| ... | ... | @@ -28,7 +28,7 @@ |
| 28 | 28 | @click="handleActionSheetOpen('coProcessor'); hideKeyboard()" |
| 29 | 29 | > |
| 30 | 30 | <up-input |
| 31 | - v-model="workOrderForm.coProcessorName" | |
| 31 | + v-model="workOrderForm.coProcessorNameStr" | |
| 32 | 32 | disabled |
| 33 | 33 | disabled-color="#ffffff" |
| 34 | 34 | placeholder="请选择共同处理人" |
| ... | ... | @@ -203,13 +203,14 @@ const tabList = ref([ |
| 203 | 203 | // 共同处理人列表 |
| 204 | 204 | const coProcessorList = ref([]) |
| 205 | 205 | |
| 206 | -// 工单表单数据(仅保留需要的字段) | |
| 206 | +// 工单表单数据(修改:新增coProcessorName数组,coProcessorNameStr用于页面展示) | |
| 207 | 207 | const workOrderForm = reactive({ |
| 208 | 208 | workerDataId:'', |
| 209 | 209 | taskId:'', // 任务id |
| 210 | 210 | orderNo: '', // 工单编号 |
| 211 | - coProcessorId: '', // 共同处理人ID数组(多选) | |
| 212 | - coProcessorName: '', // 共同处理人名称数组(多选) | |
| 211 | + coProcessorId: [], // 共同处理人ID数组(多选,改为数组格式) | |
| 212 | + coProcessorName: [], // 共同处理人名称数组(多选,数组格式,用于提交) | |
| 213 | + coProcessorNameStr: '', // 共同处理人名称字符串(用于页面输入框展示) | |
| 213 | 214 | reason: '', // 处理情况描述 |
| 214 | 215 | }) |
| 215 | 216 | |
| ... | ... | @@ -313,8 +314,6 @@ onLoad((options) => { |
| 313 | 314 | duration: 3000 |
| 314 | 315 | }); |
| 315 | 316 | console.error('onLoad异常:工单缓存数据为空'); |
| 316 | - // 可选:返回上一页 | |
| 317 | - // setTimeout(() => uni.navigateBack(), 1500); | |
| 318 | 317 | return; |
| 319 | 318 | } |
| 320 | 319 | |
| ... | ... | @@ -352,10 +351,18 @@ onLoad((options) => { |
| 352 | 351 | workOrderForm.orderNo = orderItem.orderNo || ''; |
| 353 | 352 | workOrderForm.reason = orderItem.handleResult || ''; // 处理情况回显 |
| 354 | 353 | |
| 355 | - // 共同处理人(如有数据则回显) | |
| 354 | + // 共同处理人(如有数据则回显,转换为数组格式) | |
| 356 | 355 | if (orderItem.coHandlers && orderItem.coHandlersName) { |
| 357 | - workOrderForm.coProcessorId = orderItem.coHandlers; | |
| 358 | - workOrderForm.coProcessorName = orderItem.coHandlersName; | |
| 356 | + // 处理ID:如果是字符串(逗号分隔),转为数组;本身是数组则直接赋值 | |
| 357 | + workOrderForm.coProcessorId = Array.isArray(orderItem.coHandlers) | |
| 358 | + ? orderItem.coHandlers | |
| 359 | + : (orderItem.coHandlers.split(',').filter(Boolean) || []); | |
| 360 | + // 处理名称:同理,转为数组格式(用于提交),并拼接为字符串(用于展示) | |
| 361 | + workOrderForm.coProcessorName = Array.isArray(orderItem.coHandlersName) | |
| 362 | + ? orderItem.coHandlersName | |
| 363 | + : (orderItem.coHandlersName.split(',').filter(Boolean) || []); | |
| 364 | + // 拼接名称为字符串,用于输入框展示 | |
| 365 | + workOrderForm.coProcessorNameStr = workOrderForm.coProcessorName.join(','); | |
| 359 | 366 | } else { |
| 360 | 367 | console.warn('工单数据提示:无共同处理人信息'); |
| 361 | 368 | } |
| ... | ... | @@ -418,8 +425,6 @@ onLoad((options) => { |
| 418 | 425 | duration: 3000 |
| 419 | 426 | }); |
| 420 | 427 | console.error('获取工单缓存数据失败:', error); |
| 421 | - // 可选:返回上一页 | |
| 422 | - // setTimeout(() => uni.navigateBack(), 1500); | |
| 423 | 428 | } |
| 424 | 429 | }) |
| 425 | 430 | |
| ... | ... | @@ -551,7 +556,7 @@ const handleActionSheetClose = () => { |
| 551 | 556 | currentActionSheetData.title = '' |
| 552 | 557 | } |
| 553 | 558 | |
| 554 | -// 下拉弹窗选择事件(仅处理共同处理人多选) | |
| 559 | +// 下拉弹窗选择事件(修改:支持多选,存储名称和ID为数组) | |
| 555 | 560 | const handleActionSheetSelect = (e) => { |
| 556 | 561 | // 校验事件参数是否有效 |
| 557 | 562 | if (!e || !e.name || !e.id) { |
| ... | ... | @@ -566,10 +571,23 @@ const handleActionSheetSelect = (e) => { |
| 566 | 571 | } |
| 567 | 572 | |
| 568 | 573 | const { type } = currentActionSheetData |
| 569 | - // 多选场景(仅共同处理人) | |
| 574 | + // 多选场景(仅共同处理人,存储数组格式) | |
| 570 | 575 | if (type === 'coProcessor') { |
| 571 | - workOrderForm.coProcessorName = e.name | |
| 572 | - workOrderForm.coProcessorId = e.id | |
| 576 | + // 若已选中该处理人,移除(实现切换选择);未选中则添加 | |
| 577 | + const idIndex = workOrderForm.coProcessorId.findIndex(id => id === e.id); | |
| 578 | + if (idIndex > -1) { | |
| 579 | + // 移除已选中的ID和名称 | |
| 580 | + workOrderForm.coProcessorId.splice(idIndex, 1); | |
| 581 | + workOrderForm.coProcessorName.splice(idIndex, 1); | |
| 582 | + } else { | |
| 583 | + // 添加新选中的ID和名称(数组格式) | |
| 584 | + workOrderForm.coProcessorId.push(e.id); | |
| 585 | + workOrderForm.coProcessorName.push(e.name); | |
| 586 | + } | |
| 587 | + | |
| 588 | + // 拼接名称数组为字符串,用于输入框展示 | |
| 589 | + workOrderForm.coProcessorNameStr = workOrderForm.coProcessorName.join(','); | |
| 590 | + | |
| 573 | 591 | // 校验表单实例是否存在,再执行字段校验 |
| 574 | 592 | if (workOrderFormRef.value) { |
| 575 | 593 | workOrderFormRef.value?.validateField('coProcessorName') |
| ... | ... | @@ -600,7 +618,7 @@ const hideKeyboard = () => { |
| 600 | 618 | uni.hideKeyboard() |
| 601 | 619 | } |
| 602 | 620 | |
| 603 | -// 提交工单(整合所有图片URL,增加开始/结束图片必填校验) | |
| 621 | +// 提交工单(修改:将coProcessorName数组一并传入提交参数) | |
| 604 | 622 | const submitWorkOrder = async () => { |
| 605 | 623 | try { |
| 606 | 624 | // ========== 前置校验:表单实例是否存在 ========== |
| ... | ... | @@ -696,14 +714,15 @@ const submitWorkOrder = async () => { |
| 696 | 714 | materialImgs: materialImgs.getSuccessImgUrls() || [] |
| 697 | 715 | } |
| 698 | 716 | |
| 699 | - // 构造提交参数 | |
| 717 | + // 构造提交参数(修改:添加coProcessorName数组一并提交) | |
| 700 | 718 | const submitData = { |
| 701 | 719 | taskId: workOrderForm.taskId, |
| 702 | 720 | taskKey:'ylWorker', |
| 703 | 721 | operateType: nextStepMap['ylWorker']?.operateTypePass || '', // 兜底:防止nextStepMap缺失属性 |
| 704 | 722 | workerDataId: Number(workOrderForm.workerDataId) || '', |
| 705 | 723 | handleResult: workOrderForm.reason.trim(), |
| 706 | - coHandlers: workOrderForm.coProcessorId ? [String(workOrderForm.coProcessorId)] : [], | |
| 724 | + coHandlers: workOrderForm.coProcessorId || [], // ID数组 | |
| 725 | + coHandlersName: workOrderForm.coProcessorName || [], // 名称数组(一并提交) | |
| 707 | 726 | startImgs: allImgs.startImgs, |
| 708 | 727 | processingImgs: allImgs.processingImgs, |
| 709 | 728 | endImgs: allImgs.endImgs, |
| ... | ... | @@ -712,6 +731,9 @@ const submitWorkOrder = async () => { |
| 712 | 731 | problemsImgs:[] |
| 713 | 732 | } |
| 714 | 733 | |
| 734 | + // 打印提交参数,验证coProcessorName是否为数组 | |
| 735 | + console.log('提交参数(含名称数组):', submitData); | |
| 736 | + | |
| 715 | 737 | // 校验operateType是否有效 |
| 716 | 738 | if (!submitData.operateType) { |
| 717 | 739 | uni.showToast({ | ... | ... |
pages-sub/problem/work-order-manage/order-detail.vue
| ... | ... | @@ -24,7 +24,6 @@ |
| 24 | 24 | ></up-tabs> |
| 25 | 25 | </up-sticky> |
| 26 | 26 | |
| 27 | - | |
| 28 | 27 | <!-- 顶部Tab内容区 --> |
| 29 | 28 | <view class="tab-content"> |
| 30 | 29 | <!-- 1. 工单详情Tab --> |
| ... | ... | @@ -110,20 +109,18 @@ |
| 110 | 109 | ></up-cell> |
| 111 | 110 | </up-cell-group> |
| 112 | 111 | |
| 113 | - | |
| 114 | 112 | <!-- 图片分类Tabs区块 --> |
| 115 | 113 | <view class="img-tabs-block" v-if="orderDetail.startImgs.length>0"> |
| 116 | 114 | <up-cell-group :border="false"> |
| 117 | 115 | <up-cell> |
| 118 | - <template #title> | |
| 119 | - <view style="min-width: 200rpx">共同处理人</view> | |
| 120 | - </template> | |
| 121 | - <template #value> | |
| 122 | - <view class="common-text-color up-line-1">{{ orderDetail.coHandlersName || '--' }}</view> | |
| 123 | - </template> | |
| 116 | + <template #title> | |
| 117 | + <view style="min-width: 200rpx">共同处理人</view> | |
| 118 | + </template> | |
| 119 | + <template #value> | |
| 120 | + <view class="common-text-color up-line-1">{{ orderDetail.coHandlersName || '--' }}</view> | |
| 121 | + </template> | |
| 124 | 122 | </up-cell> |
| 125 | 123 | </up-cell-group> |
| 126 | - <!-- coHandlersName--> | |
| 127 | 124 | <up-tabs |
| 128 | 125 | @change='imgTabChange' |
| 129 | 126 | v-model="activeImgTab" |
| ... | ... | @@ -151,10 +148,68 @@ |
| 151 | 148 | |
| 152 | 149 | <!-- 2. 流程节点Tab --> |
| 153 | 150 | <view v-show="activeTopTab == 1" class="process-content"> |
| 154 | - <!-- <up-empty--> | |
| 155 | - <!-- mode="data"--> | |
| 156 | - <!-- ></up-empty>--> | |
| 157 | - <!-- <!– 可根据实际需求补充流程节点展示逻辑 –>--> | |
| 151 | + <!-- 竖向步骤条:动态绑定current属性 --> | |
| 152 | + <up-steps | |
| 153 | + v-if="processData.activityNodes && processData.activityNodes.length" | |
| 154 | + :list="processData.activityNodes" | |
| 155 | + :current="getCurrentStepIndex()" | |
| 156 | + direction="column" | |
| 157 | + active-color="#3c9cff" | |
| 158 | + inactive-color="#999" | |
| 159 | + class="vertical-steps" | |
| 160 | + > | |
| 161 | + <up-steps-item | |
| 162 | + v-for="(item, index) in processData.activityNodes" | |
| 163 | + :key="`${item.id}_${index}`" | |
| 164 | + > | |
| 165 | + <!-- 唯一自定义模板:content,包含标题、描述、相册所有内容 --> | |
| 166 | + <template #content> | |
| 167 | + <view class="step-content-wrap"> | |
| 168 | + <!-- 1. 原标题内容:节点名称 + 操作人 --> | |
| 169 | + <view class="step-title"> | |
| 170 | + {{ item.name }} | |
| 171 | + <text class="operator-name"> | |
| 172 | + {{ item.tasks && item.tasks[0]?.assigneeUser?.nickname ? '(' + item.tasks[0].assigneeUser.nickname + ')' : '(未知操作人)' }} | |
| 173 | + </text> | |
| 174 | + </view> | |
| 175 | + | |
| 176 | + <!-- 2. 原描述内容:时间 + 处理说明(最多200字) --> | |
| 177 | + <view class="step-desc"> | |
| 178 | + <!-- 时间行 --> | |
| 179 | + <view class="time-line"> | |
| 180 | + 处理时间:{{ timeFormat(item.startTime, 'yyyy-mm-dd hh:MM:ss') }} | |
| 181 | + <text v-if="item.endTime"> - {{ timeFormat(item.endTime, 'yyyy-mm-dd hh:MM:ss') }}</text> | |
| 182 | + <text v-else class="processing-tag">(处理中)</text> | |
| 183 | + </view> | |
| 184 | + <!-- 原因行 --> | |
| 185 | + <view class="reason-line up-line-2" v-if="item.tasks && item.tasks[0]?.reason"> | |
| 186 | + 描述:{{ getLimitReason(item.tasks && item.tasks[0]?.reason) }} | |
| 187 | + </view> | |
| 188 | + </view> | |
| 189 | + | |
| 190 | + <!-- 3. 原相册内容:预留up-album --> | |
| 191 | + <view class="step-album-wrap"> | |
| 192 | + <up-album | |
| 193 | + v-if="item.tasks && item.tasks[0]?.signPicUrl && item.tasks[0].signPicUrl.length" | |
| 194 | + :urls="item.tasks[0].signPicUrl.slice(0, 3)" | |
| 195 | + singleSize="60" | |
| 196 | + multipleSize="60" | |
| 197 | + :preview-full-image="true" | |
| 198 | + class="step-album" | |
| 199 | + ></up-album> | |
| 200 | + </view> | |
| 201 | + </view> | |
| 202 | + </template> | |
| 203 | + </up-steps-item> | |
| 204 | + </up-steps> | |
| 205 | + | |
| 206 | + <!-- 流程节点为空时的提示 --> | |
| 207 | + <up-empty | |
| 208 | + v-else | |
| 209 | + mode="data" | |
| 210 | + title="暂无流程节点数据" | |
| 211 | + class="empty-process" | |
| 212 | + ></up-empty> | |
| 158 | 213 | </view> |
| 159 | 214 | </view> |
| 160 | 215 | </view> |
| ... | ... | @@ -183,6 +238,14 @@ const topTabList = ref([ |
| 183 | 238 | {name: '流程节点'} |
| 184 | 239 | ]); |
| 185 | 240 | |
| 241 | +// 流程节点数据(初始化适配接口格式) | |
| 242 | +const processData = ref<any>({ | |
| 243 | + status: 2, | |
| 244 | + activityNodes: [], | |
| 245 | + formFieldsPermission: null, | |
| 246 | + todoTask: null | |
| 247 | +}); | |
| 248 | + | |
| 186 | 249 | const activeTopTabClick = async (item: any) => { |
| 187 | 250 | console.log(item) |
| 188 | 251 | activeTopTab.value = item.index |
| ... | ... | @@ -192,6 +255,19 @@ const activeTopTabClick = async (item: any) => { |
| 192 | 255 | } |
| 193 | 256 | const res = await getApprovalDetail(getData) |
| 194 | 257 | console.log(res) |
| 258 | + // 关键:格式化数据,补充up-steps要求的title字段 | |
| 259 | + if (res && res.activityNodes && res.activityNodes.length) { | |
| 260 | + const formatActivityNodes = res.activityNodes.map(node => ({ | |
| 261 | + ...node, | |
| 262 | + title: node.name // 补充强制字段,满足3.3.48版本组件要求 | |
| 263 | + })); | |
| 264 | + processData.value = { | |
| 265 | + ...res, | |
| 266 | + activityNodes: formatActivityNodes | |
| 267 | + }; | |
| 268 | + } else { | |
| 269 | + processData.value = res; | |
| 270 | + } | |
| 195 | 271 | } |
| 196 | 272 | } |
| 197 | 273 | |
| ... | ... | @@ -270,6 +346,36 @@ const imgTabChange = (({index}) => { |
| 270 | 346 | currentImgList.value = orderDetail.value[currentKey] |
| 271 | 347 | }) |
| 272 | 348 | |
| 349 | +/** | |
| 350 | + * 截取reason最多200字 | |
| 351 | + * @param reason 处理说明 | |
| 352 | + * @returns 截取后的字符串 | |
| 353 | + */ | |
| 354 | +const getLimitReason = (reason: string | null | undefined) => { | |
| 355 | + if (!reason) return '无处理说明'; | |
| 356 | + if (reason.length <= 200) return reason; | |
| 357 | + return reason.substring(0, 200) + '...'; | |
| 358 | +} | |
| 359 | + | |
| 360 | +/** | |
| 361 | + * 动态获取当前步骤索引(核心:根据接口数据的status字段判断) | |
| 362 | + * status=1:当前步骤(处理中) | |
| 363 | + * status=2:已完成步骤 | |
| 364 | + * @returns {number} 当前激活的步骤索引(从0开始) | |
| 365 | + */ | |
| 366 | +const getCurrentStepIndex = () => { | |
| 367 | + const { activityNodes } = processData.value; | |
| 368 | + if (!activityNodes || !activityNodes.length) return 0; | |
| 369 | + | |
| 370 | + // 1. 查找第一个状态为1(处理中)的节点,即为当前步骤 | |
| 371 | + const processingNodeIndex = activityNodes.findIndex(node => node.status === 1); | |
| 372 | + if (processingNodeIndex !== -1) { | |
| 373 | + return processingNodeIndex; | |
| 374 | + } | |
| 375 | + | |
| 376 | + // 2. 若没有处理中的节点(全部已完成),则激活最后一个节点 | |
| 377 | + return activityNodes.length - 1; | |
| 378 | +} | |
| 273 | 379 | |
| 274 | 380 | /** |
| 275 | 381 | * 获取工单详情 |
| ... | ... | @@ -321,12 +427,7 @@ onLoad((options: any) => { |
| 321 | 427 | }); |
| 322 | 428 | |
| 323 | 429 | onShow(() => { |
| 324 | - // if (taskId.value) { | |
| 325 | - // DetailQuery(taskId.value); | |
| 326 | - // } else { | |
| 327 | - // loading.value = false; | |
| 328 | - // uni.showToast({title: '缺少工单ID参数', icon: 'none'}); | |
| 329 | - // } | |
| 430 | + // 注释原有逻辑,避免重复加载 | |
| 330 | 431 | }); |
| 331 | 432 | </script> |
| 332 | 433 | |
| ... | ... | @@ -371,20 +472,12 @@ onShow(() => { |
| 371 | 472 | // 图片分类Tabs区块 |
| 372 | 473 | .img-tabs-block { |
| 373 | 474 | background-color: #fff; |
| 374 | - border-radius: 12rpx; | |
| 375 | - padding: 16rpx; | |
| 376 | - | |
| 377 | - //// 图片Tabs样式(平均分配空间) | |
| 378 | - //.img-tabs { | |
| 379 | - // --u-tabs-item-flex: 1; // 平均分配空间 | |
| 380 | - // --u-tabs-item-font-size: 26rpx; | |
| 381 | - // --u-tabs-item-height: 72rpx; | |
| 382 | - // margin-bottom: 16rpx; | |
| 383 | - //} | |
| 475 | + //border-radius: 12rpx; | |
| 476 | + //padding: 16rpx; | |
| 384 | 477 | |
| 385 | 478 | // 图片内容区 |
| 386 | 479 | .img-tab-content { |
| 387 | - padding: 10rpx 0; | |
| 480 | + padding: 20rpx 15px ; | |
| 388 | 481 | min-height: 120rpx; |
| 389 | 482 | display: flex; |
| 390 | 483 | align-items: center; |
| ... | ... | @@ -403,15 +496,83 @@ onShow(() => { |
| 403 | 496 | } |
| 404 | 497 | } |
| 405 | 498 | |
| 406 | -// 流程节点空状态 | |
| 499 | +// 流程节点区域(完整样式,确保内容可见) | |
| 407 | 500 | .process-content { |
| 408 | - display: flex; | |
| 409 | - justify-content: center; | |
| 410 | - align-items: center; | |
| 411 | - min-height: 400rpx; | |
| 501 | + //padding: 16rpx; | |
| 502 | + //min-height: 400rpx; | |
| 412 | 503 | |
| 413 | 504 | .empty-process { |
| 414 | 505 | margin-top: 100rpx; |
| 415 | 506 | } |
| 507 | + | |
| 508 | + // 竖向步骤条容器样式 | |
| 509 | + .vertical-steps { | |
| 510 | + //width: 100%; | |
| 511 | + background-color: #fff; | |
| 512 | + padding: 20rpx; | |
| 513 | + border-radius: 12rpx; | |
| 514 | + display: flex; | |
| 515 | + flex-direction: column; | |
| 516 | + gap: 20rpx; // 步骤项间距 | |
| 517 | + } | |
| 518 | + | |
| 519 | + // 自定义内容容器样式 | |
| 520 | + .step-content-wrap { | |
| 521 | + width: 100%; | |
| 522 | + //padding: 10rpx 0; | |
| 523 | + box-sizing: border-box; | |
| 524 | + | |
| 525 | + // 节点标题 + 操作人样式 | |
| 526 | + .step-title { | |
| 527 | + font-size: 30rpx; | |
| 528 | + font-weight: 600; | |
| 529 | + color: #333; | |
| 530 | + margin-bottom: 12rpx; | |
| 531 | + | |
| 532 | + .operator-name { | |
| 533 | + font-size: 30rpx; | |
| 534 | + font-weight: 600; | |
| 535 | + color: #333; | |
| 536 | + margin-left: 20rpx; | |
| 537 | + } | |
| 538 | + } | |
| 539 | + | |
| 540 | + // 描述(时间 + 处理说明)样式 | |
| 541 | + .step-desc { | |
| 542 | + font-size: 24rpx; | |
| 543 | + color: #666; | |
| 544 | + line-height: 1.6; | |
| 545 | + margin-bottom: 12rpx; | |
| 546 | + | |
| 547 | + .time-line { | |
| 548 | + margin-bottom: 8rpx; | |
| 549 | + | |
| 550 | + .processing-tag { | |
| 551 | + color: #f59e0b; | |
| 552 | + margin-left: 10rpx; | |
| 553 | + } | |
| 554 | + } | |
| 555 | + | |
| 556 | + .reason-line { | |
| 557 | + word-break: break-all; // 长文本自动换行 | |
| 558 | + } | |
| 559 | + } | |
| 560 | + | |
| 561 | + // 相册容器样式 | |
| 562 | + .step-album-wrap { | |
| 563 | + padding: 10rpx 0; | |
| 564 | + | |
| 565 | + .step-album { | |
| 566 | + width: 100%; | |
| 567 | + max-width: 300rpx; | |
| 568 | + } | |
| 569 | + | |
| 570 | + .no-img-tip { | |
| 571 | + font-size: 24rpx; | |
| 572 | + color: #999; | |
| 573 | + margin-top: 10rpx; | |
| 574 | + } | |
| 575 | + } | |
| 576 | + } | |
| 416 | 577 | } |
| 417 | 578 | </style> |
| 418 | 579 | \ No newline at end of file | ... | ... |