Commit 6853427faf5613784424d515aed2f036cbec1084
1 parent
5f7ce1e4
业务线 小程序不用写死,从后端接口获取
Showing
9 changed files
with
560 additions
and
122 deletions
common/utils/common.js
| ... | ... | @@ -102,6 +102,28 @@ export const buzStatusMap = { |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | 104 | /** |
| 105 | + * 工作流节点动作按钮颜色(与统一动作弹窗保持一致) | |
| 106 | + * @param {string} code - 动作编码,如 ASSIGN/REJECT/RETURN_PREV | |
| 107 | + */ | |
| 108 | +export const getActionButtonType = (code) => { | |
| 109 | + switch (code) { | |
| 110 | + case 'APPROVE': | |
| 111 | + case 'HANDLE': | |
| 112 | + case 'COMPLETE': | |
| 113 | + return 'success' | |
| 114 | + case 'REJECT': | |
| 115 | + return 'error' | |
| 116 | + case 'RETURN': | |
| 117 | + case 'RETURN_PREV': | |
| 118 | + return 'warning' | |
| 119 | + case 'WITHDRAW': | |
| 120 | + return 'info' | |
| 121 | + default: | |
| 122 | + return 'primary' | |
| 123 | + } | |
| 124 | +} | |
| 125 | + | |
| 126 | +/** | |
| 105 | 127 | * 计算两个时间的时间差,返回格式化字符串(天/小时/分钟/秒,按需显示,无无效单位) |
| 106 | 128 | * @param {string | Date | number} startTime - 开始时间(时间字符串/Date对象/10位/13位时间戳) |
| 107 | 129 | * @param {string | Date | number} endTime - 结束时间(时间字符串/Date对象/10位/13位时间戳) | ... | ... |
components/unified-task-actions/unified-task-actions.vue
pages-sub/daily/maintain-manage/type-list-page.vue
| ... | ... | @@ -33,8 +33,8 @@ |
| 33 | 33 | <view class="info-text u-line-1">有效期:{{ timeFormat(item.beginTime, 'yyyy-mm-dd') }}—{{ |
| 34 | 34 | timeFormat(item.endTime, 'yyyy-mm-dd') }} |
| 35 | 35 | </view> |
| 36 | - <!-- 仅待完成且存在进行中的本次养护时才显示结束任务(draftCommitId 由后端按 commit_state=1 回填) --> | |
| 37 | - <view v-if="activeStatus === '1' && item.draftCommitId" class="mini-btn" | |
| 36 | + <!-- 仅待完成且存在进行中的本次养护时才显示结束任务(commitId 由后端按 commit_state=1 回填) --> | |
| 37 | + <view v-if="activeStatus === '1' && item.commitId" class="mini-btn" | |
| 38 | 38 | @click.stop="handleEndTask(item)">结束任务</view> |
| 39 | 39 | </view> |
| 40 | 40 | </view> |
| ... | ... | @@ -255,18 +255,18 @@ const handleEndTaskModalCancel = () => { |
| 255 | 255 | // 确认结束任务,真正调用接口【新增】 |
| 256 | 256 | const confirmEndTask = async () => { |
| 257 | 257 | const item = currentEndTaskItem.value |
| 258 | - // draftCommitId 由明细列表接口回填(commit_state=1),按钮只在有值时渲染 | |
| 259 | - if (!item || !item.draftCommitId) return | |
| 258 | + // commitId 由明细列表接口回填(commit_state=1),按钮只在有值时渲染 | |
| 259 | + if (!item || !item.commitId) return | |
| 260 | 260 | endTaskModalShow.value = false |
| 261 | 261 | |
| 262 | 262 | uni.showLoading({ title: '提交中...', mask: true }) |
| 263 | 263 | try { |
| 264 | 264 | // 后端 /finish 只认 commitId,且要求本次养护至少有一条有效子上报 |
| 265 | - await finishPlan({ commitId: item.draftCommitId }) | |
| 265 | + await finishPlan({ commitId: item.commitId }) | |
| 266 | 266 | // 先关 loading 再弹提示:微信端 showLoading/showToast 共用同一个 toast,顺序反了会把成功提示顶掉 |
| 267 | 267 | uni.hideLoading() |
| 268 | 268 | uni.showToast({ title: '结束任务成功', icon: 'success' }) |
| 269 | - // 操作成功,重新加载数据,刷新列表(draftCommitId 随之清空,按钮消失) | |
| 269 | + // 操作成功,重新加载数据,刷新列表(commitId 随之清空,按钮消失) | |
| 270 | 270 | await loadData() |
| 271 | 271 | pagingRef.value?.reload() |
| 272 | 272 | } catch (err) { | ... | ... |
pages-sub/problem/ai-manage/index.vue
| ... | ... | @@ -94,16 +94,25 @@ |
| 94 | 94 | <view class="u-body-item-title">提交时间:</view> |
| 95 | 95 | <view class="u-line-1 u-body-value">{{ timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}</view> |
| 96 | 96 | </view> |
| 97 | - <!-- 操作按钮行 --> | |
| 98 | - <view class="u-body-item u-flex u-body-item-btn-wrap common-justify-between common-item-center mt-20"> | |
| 99 | -<!-- <up-button type="success" size="mini" @click="handleRenew(item)" v-show="nextStepMap[item.taskKey].renewShow">重新提交</up-button>--> | |
| 100 | - <up-button type="warning" size="large" @click="handleUnifiedReject(item)" | |
| 101 | - v-show="showRejectButton(item)">回退 | |
| 102 | - </up-button> | |
| 103 | - <up-button type="primary" size="large" @click="handleUnifiedProcess(item)">{{ getProcessButtonText(item) }}</up-button> | |
| 104 | -<!-- <up-button type="primary" size="large" @click="handleProcess(item)" v-show="nextStepMap[item.taskKey].ysShow">验收</up-button>--> | |
| 105 | - | |
| 106 | - <up-button type="info" size="large" @click="handleDetail(item)">详情</up-button> | |
| 97 | + <!-- 操作按钮行:已配置工作流动作时按配置逐个渲染按钮,点击直接执行对应动作 --> | |
| 98 | + <view class="u-body-item task-btn-row mt-20"> | |
| 99 | + <template v-if="hasConfiguredActions(item)"> | |
| 100 | + <view | |
| 101 | + v-for="action in item.configuredActions" | |
| 102 | + :key="action.code" | |
| 103 | + :class="['task-btn', 'task-btn--' + getActionButtonType(action.code)]" | |
| 104 | + @click.stop="handleUnifiedProcess(item, action)" | |
| 105 | + >{{ action.name }}</view> | |
| 106 | + <view class="task-btn task-btn--info" @click.stop="handleDetail(item)">详情</view> | |
| 107 | + </template> | |
| 108 | + <!-- 未配置:沿用原有节点按钮 --> | |
| 109 | + <template v-else> | |
| 110 | + <view v-if="showRejectButton(item)" class="task-btn task-btn--warning" | |
| 111 | + @click.stop="handleUnifiedReject(item)">回退</view> | |
| 112 | + <view class="task-btn task-btn--primary" | |
| 113 | + @click.stop="handleUnifiedProcess(item)">{{ getProcessButtonText(item) }}</view> | |
| 114 | + <view class="task-btn task-btn--info" @click.stop="handleDetail(item)">详情</view> | |
| 115 | + </template> | |
| 107 | 116 | </view> |
| 108 | 117 | </view> |
| 109 | 118 | </template> |
| ... | ... | @@ -267,7 +276,7 @@ import { |
| 267 | 276 | } from '@/api/regional-order-manage/regional-order-manage' |
| 268 | 277 | import { getTaskActions } from '@/api/work-order-manage/work-order-manage' |
| 269 | 278 | import { useUserStore } from '@/pinia/user'; |
| 270 | -import { nextStepMap, buzStatusMap } from '@/common/utils/common' | |
| 279 | +import { nextStepMap, buzStatusMap, getActionButtonType } from '@/common/utils/common' | |
| 271 | 280 | import { useUploadImgs } from '@/common/utils/useUploadImgs' |
| 272 | 281 | |
| 273 | 282 | // ========== 全局实例 & 常量 ========== |
| ... | ... | @@ -497,14 +506,18 @@ const getProcessButtonText = (item) => { |
| 497 | 506 | return nextStepMap[item.taskKey]?.btnText || '处理' |
| 498 | 507 | } |
| 499 | 508 | |
| 500 | -/** 待办-处理工单:已配置统一动作时走新逻辑,否则回退原有处理 */ | |
| 501 | -const handleUnifiedProcess = async (item) => { | |
| 509 | +/** 是否已配置统一动作(配置后按配置逐个渲染动作按钮) */ | |
| 510 | +const hasConfiguredActions = (item) => | |
| 511 | + Array.isArray(item?.configuredActions) && item.configuredActions.length > 0 | |
| 512 | + | |
| 513 | +/** 待办-处理工单:已配置统一动作时直接执行点击的配置动作,否则回退原有处理 */ | |
| 514 | +const handleUnifiedProcess = async (item, action = null) => { | |
| 502 | 515 | const actions = Array.isArray(item?.configuredActions) |
| 503 | 516 | ? item.configuredActions |
| 504 | 517 | : await queryUnifiedActions(item) |
| 505 | 518 | if (actions) { |
| 506 | - // 主按钮文案就是第一个动作,直接执行该动作,不再弹「请选择操作」让用户二次选择 | |
| 507 | - unifiedActionsRef.value?.open(item, actions.slice(0, 1)) | |
| 519 | + // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 | |
| 520 | + unifiedActionsRef.value?.open(item, [action || actions[0]]) | |
| 508 | 521 | return |
| 509 | 522 | } |
| 510 | 523 | handleProcess(item) |
| ... | ... | @@ -730,8 +743,44 @@ onShow(() => { |
| 730 | 743 | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); |
| 731 | 744 | } |
| 732 | 745 | |
| 733 | -.u-body-item-btn-wrap :deep(.u-button--large){ | |
| 734 | - height: 28px; | |
| 746 | +// 卡片操作按钮:自动换行、右对齐,动作多时每行 3~4 个,不再整行铺满 | |
| 747 | +.task-btn-row { | |
| 748 | + display: flex; | |
| 749 | + flex-wrap: wrap; | |
| 750 | + justify-content: flex-end; | |
| 751 | + margin-bottom: -10rpx; | |
| 752 | +} | |
| 753 | + | |
| 754 | +.task-btn { | |
| 755 | + box-sizing: border-box; | |
| 756 | + height: 56rpx; | |
| 757 | + line-height: 56rpx; | |
| 758 | + padding: 0 24rpx; | |
| 759 | + margin: 0 0 10rpx 12rpx; | |
| 760 | + border-radius: 8rpx; | |
| 761 | + font-size: 24rpx; | |
| 762 | + color: #fff; | |
| 763 | + white-space: nowrap; | |
| 764 | +} | |
| 765 | + | |
| 766 | +.task-btn--primary { | |
| 767 | + background-color: #3c9cff; | |
| 768 | +} | |
| 769 | + | |
| 770 | +.task-btn--success { | |
| 771 | + background-color: #5ac725; | |
| 772 | +} | |
| 773 | + | |
| 774 | +.task-btn--warning { | |
| 775 | + background-color: #f9ae3d; | |
| 776 | +} | |
| 777 | + | |
| 778 | +.task-btn--error { | |
| 779 | + background-color: #f56c6c; | |
| 780 | +} | |
| 781 | + | |
| 782 | +.task-btn--info { | |
| 783 | + background-color: #909399; | |
| 735 | 784 | } |
| 736 | 785 | |
| 737 | 786 | ... | ... |
pages-sub/problem/regional-order-manage/index.vue
| ... | ... | @@ -106,12 +106,27 @@ |
| 106 | 106 | <view class="u-line-1 u-body-value">{{ item.createTime ? timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') : '-' }}</view> |
| 107 | 107 | </view> |
| 108 | 108 | |
| 109 | - <!-- 待办工单(0) 保留原来的操作按钮区 不变 --> | |
| 110 | - <view v-if="activeTab === 0" class="u-body-item u-body-item-btn-wrap u-flex common-justify-between common-item-center mt-20"> | |
| 111 | - <up-button type="warning" size="large" @click="handleUnifiedReject(item)" v-show="showRejectButton(item)">回退</up-button> | |
| 112 | - <up-button type="success" size="large" @click="handleRenew(item)" v-show="nextStepMap[item.taskKey]?.renewShow">重新提交</up-button> | |
| 113 | - <up-button type="primary" size="large" @click="handleUnifiedProcess(item)">{{ getProcessButtonText(item) }}</up-button> | |
| 114 | - <up-button type="info" size="large" @click="handleDetail(item)">详情</up-button> | |
| 109 | + <!-- 待办工单(0):已配置工作流动作时按配置逐个渲染按钮,点击直接执行对应动作 --> | |
| 110 | + <view v-if="activeTab === 0" class="u-body-item task-btn-row mt-20"> | |
| 111 | + <template v-if="hasConfiguredActions(item)"> | |
| 112 | + <view | |
| 113 | + v-for="action in item.configuredActions" | |
| 114 | + :key="action.code" | |
| 115 | + :class="['task-btn', 'task-btn--' + getActionButtonType(action.code)]" | |
| 116 | + @click.stop="handleUnifiedProcess(item, action)" | |
| 117 | + >{{ action.name }}</view> | |
| 118 | + <view class="task-btn task-btn--info" @click.stop="handleDetail(item)">详情</view> | |
| 119 | + </template> | |
| 120 | + <!-- 未配置:沿用原有节点按钮 --> | |
| 121 | + <template v-else> | |
| 122 | + <view v-if="showRejectButton(item)" class="task-btn task-btn--warning" | |
| 123 | + @click.stop="handleUnifiedReject(item)">回退</view> | |
| 124 | + <view v-if="nextStepMap[item.taskKey]?.renewShow" class="task-btn task-btn--success" | |
| 125 | + @click.stop="handleRenew(item)">重新提交</view> | |
| 126 | + <view class="task-btn task-btn--primary" | |
| 127 | + @click.stop="handleUnifiedProcess(item)">{{ getProcessButtonText(item) }}</view> | |
| 128 | + <view class="task-btn task-btn--info" @click.stop="handleDetail(item)">详情</view> | |
| 129 | + </template> | |
| 115 | 130 | </view> |
| 116 | 131 | |
| 117 | 132 | <!-- 已删除:原来单独的【我发起的/已办】按钮区,不需要了 --> |
| ... | ... | @@ -226,7 +241,7 @@ import { |
| 226 | 241 | } from '@/api/regional-order-manage/regional-order-manage' |
| 227 | 242 | import { getTaskActions } from '@/api/work-order-manage/work-order-manage' |
| 228 | 243 | import { useUserStore } from '@/pinia/user'; |
| 229 | -import { nextStepMap, buzStatusMap } from '@/common/utils/common' | |
| 244 | +import { nextStepMap, buzStatusMap, getActionButtonType } from '@/common/utils/common' | |
| 230 | 245 | import { useUploadImgs } from '@/common/utils/useUploadImgs' |
| 231 | 246 | |
| 232 | 247 | // ========== 全局实例 & 常量 ========== |
| ... | ... | @@ -472,14 +487,18 @@ const getProcessButtonText = (item) => { |
| 472 | 487 | return nextStepMap[item.taskKey]?.btnText |
| 473 | 488 | } |
| 474 | 489 | |
| 475 | -/** 待办-处理工单:已配置统一动作时走新逻辑,否则回退原有处理 */ | |
| 476 | -const handleUnifiedProcess = async (item) => { | |
| 490 | +/** 是否已配置统一动作(配置后按配置逐个渲染动作按钮) */ | |
| 491 | +const hasConfiguredActions = (item) => | |
| 492 | + Array.isArray(item?.configuredActions) && item.configuredActions.length > 0 | |
| 493 | + | |
| 494 | +/** 待办-处理工单:已配置统一动作时直接执行点击的配置动作,否则回退原有处理 */ | |
| 495 | +const handleUnifiedProcess = async (item, action = null) => { | |
| 477 | 496 | const actions = Array.isArray(item?.configuredActions) |
| 478 | 497 | ? item.configuredActions |
| 479 | 498 | : await queryUnifiedActions(item) |
| 480 | 499 | if (actions) { |
| 481 | - // 主按钮文案就是第一个动作,直接执行该动作,不再弹「请选择操作」让用户二次选择 | |
| 482 | - unifiedActionsRef.value?.open(item, actions.slice(0, 1)) | |
| 500 | + // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 | |
| 501 | + unifiedActionsRef.value?.open(item, [action || actions[0]]) | |
| 483 | 502 | return |
| 484 | 503 | } |
| 485 | 504 | handleProcess(item) |
| ... | ... | @@ -720,8 +739,44 @@ onLoad(() => { |
| 720 | 739 | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); |
| 721 | 740 | } |
| 722 | 741 | |
| 723 | -.u-body-item-btn-wrap :deep(.u-button--large){ | |
| 724 | - height: 28px; | |
| 742 | +// 卡片操作按钮:自动换行、右对齐,动作多时每行 3~4 个,不再整行铺满 | |
| 743 | +.task-btn-row { | |
| 744 | + display: flex; | |
| 745 | + flex-wrap: wrap; | |
| 746 | + justify-content: flex-end; | |
| 747 | + margin-bottom: -10rpx; | |
| 748 | +} | |
| 749 | + | |
| 750 | +.task-btn { | |
| 751 | + box-sizing: border-box; | |
| 752 | + height: 56rpx; | |
| 753 | + line-height: 56rpx; | |
| 754 | + padding: 0 24rpx; | |
| 755 | + margin: 0 0 10rpx 12rpx; | |
| 756 | + border-radius: 8rpx; | |
| 757 | + font-size: 24rpx; | |
| 758 | + color: #fff; | |
| 759 | + white-space: nowrap; | |
| 760 | +} | |
| 761 | + | |
| 762 | +.task-btn--primary { | |
| 763 | + background-color: #3c9cff; | |
| 764 | +} | |
| 765 | + | |
| 766 | +.task-btn--success { | |
| 767 | + background-color: #5ac725; | |
| 768 | +} | |
| 769 | + | |
| 770 | +.task-btn--warning { | |
| 771 | + background-color: #f9ae3d; | |
| 772 | +} | |
| 773 | + | |
| 774 | +.task-btn--error { | |
| 775 | + background-color: #f56c6c; | |
| 776 | +} | |
| 777 | + | |
| 778 | +.task-btn--info { | |
| 779 | + background-color: #909399; | |
| 725 | 780 | } |
| 726 | 781 | |
| 727 | 782 | ... | ... |
pages-sub/problem/regional-order-manage/list-detail.vue
| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | color="#3c9cff" |
| 9 | 9 | ></up-loading-page> |
| 10 | 10 | |
| 11 | - <view v-else class="main-content"> | |
| 11 | + <view v-else class="main-content" :class="'pb-rows-' + actionBarRows"> | |
| 12 | 12 | <!-- 顶部标签栏 --> |
| 13 | 13 | <up-sticky :bgColor="'#fff'"> |
| 14 | 14 | <up-tabs |
| ... | ... | @@ -223,23 +223,25 @@ |
| 223 | 223 | </view> |
| 224 | 224 | |
| 225 | 225 | <!-- 底部操作按钮 --> |
| 226 | - <view v-if="activeTab === '0' && (configuredActions || nextStepMap[orderDetail.taskKey])" class="fixed-bottom-btn-wrap"> | |
| 227 | - <view class="u-body-item u-flex common-justify-between common-item-center"> | |
| 228 | - <up-button | |
| 229 | - type="warning" | |
| 230 | - size="normal" | |
| 231 | - @click="handleUnifiedReject(orderDetail)" | |
| 232 | - v-show="showRejectButton" | |
| 233 | - >回退</up-button> | |
| 234 | - <up-button | |
| 235 | - type="success" | |
| 236 | - size="normal" | |
| 237 | - @click="handleRenew(orderDetail)" | |
| 238 | - v-show="nextStepMap[orderDetail.taskKey]?.renewShow" | |
| 239 | - >重新提交</up-button> | |
| 240 | - <up-button type="primary" size="normal" @click="handleUnifiedProcess(orderDetail)"> | |
| 241 | - {{ processButtonText }} | |
| 242 | - </up-button> | |
| 226 | + <view v-if="activeTab === '0' && (configuredActions || nextStepMap[orderDetail.taskKey])" | |
| 227 | + class="fixed-bottom-btn-wrap order-action-bar"> | |
| 228 | + <!-- 已配置工作流动作:每行最多 3 个、超出自动换行,点击直接执行对应动作,不再弹「请选择操作」 --> | |
| 229 | + <view v-if="hasConfiguredActions" class="order-action-row"> | |
| 230 | + <view | |
| 231 | + v-for="action in configuredActions" | |
| 232 | + :key="action.code" | |
| 233 | + :class="['order-action-btn', 'order-action-btn--' + getActionButtonType(action.code)]" | |
| 234 | + @click.stop="handleUnifiedProcess(orderDetail, action)" | |
| 235 | + >{{ action.name }}</view> | |
| 236 | + </view> | |
| 237 | + <!-- 未配置:沿用原有节点按钮(整行展示) --> | |
| 238 | + <view v-else class="order-action-row order-action-row--single"> | |
| 239 | + <view v-if="showRejectButton" class="order-action-btn order-action-btn--warning" | |
| 240 | + @click.stop="handleUnifiedReject(orderDetail)">回退</view> | |
| 241 | + <view v-if="nextStepMap[orderDetail.taskKey]?.renewShow" class="order-action-btn order-action-btn--success" | |
| 242 | + @click.stop="handleRenew(orderDetail)">重新提交</view> | |
| 243 | + <view class="order-action-btn order-action-btn--primary" | |
| 244 | + @click.stop="handleUnifiedProcess(orderDetail)">{{ processButtonText }}</view> | |
| 243 | 245 | </view> |
| 244 | 246 | </view> |
| 245 | 247 | |
| ... | ... | @@ -335,7 +337,7 @@ import { timeFormat } from '@/uni_modules/uview-plus' |
| 335 | 337 | import { getApprovalDetail,workOrderDetailByID } from '@/api/regional-order-manage/regional-order-manage' |
| 336 | 338 | import { getTaskActions } from '@/api/work-order-manage/work-order-manage' |
| 337 | 339 | |
| 338 | -import { nextStepMap, calculateFormatTimeDiff } from '@/common/utils/common' | |
| 340 | +import { nextStepMap, calculateFormatTimeDiff, getActionButtonType } from '@/common/utils/common' | |
| 339 | 341 | import { useUploadImgs } from '@/common/utils/useUploadImgs' |
| 340 | 342 | import { useUserStore } from '@/pinia/user' |
| 341 | 343 | |
| ... | ... | @@ -517,6 +519,21 @@ const showRejectButton = computed(() => { |
| 517 | 519 | return !!nextStepMap[orderDetail.value.taskKey]?.backShow |
| 518 | 520 | }) |
| 519 | 521 | |
| 522 | +/** 是否已配置统一动作(配置后按配置逐个渲染动作按钮) */ | |
| 523 | +const hasConfiguredActions = computed(() => | |
| 524 | + Array.isArray(configuredActions.value) && configuredActions.value.length > 0) | |
| 525 | + | |
| 526 | +/** 底部操作栏行数:详情内容据此预留底部间距,避免按钮遮挡内容 */ | |
| 527 | +const actionBarRows = computed(() => { | |
| 528 | + if (hasConfiguredActions.value) { | |
| 529 | + return Math.ceil(configuredActions.value.length / 3) | |
| 530 | + } | |
| 531 | + let rows = 1 | |
| 532 | + if (showRejectButton.value) rows++ | |
| 533 | + if (nextStepMap[orderDetail.value.taskKey]?.renewShow) rows++ | |
| 534 | + return rows | |
| 535 | +}) | |
| 536 | + | |
| 520 | 537 | /** 主按钮文案:已配置统一动作时取配置的动作名称,未配置时沿用原有节点规则 */ |
| 521 | 538 | const processButtonText = computed(() => { |
| 522 | 539 | const actions = configuredActions.value |
| ... | ... | @@ -529,14 +546,14 @@ const processButtonText = computed(() => { |
| 529 | 546 | /** 统一动作弹窗 */ |
| 530 | 547 | const unifiedActionsRef = ref<any>(null) |
| 531 | 548 | |
| 532 | -/** 处理:已配置统一动作时走统一接口,否则回退原有处理 */ | |
| 533 | -const handleUnifiedProcess = async (item: any) => { | |
| 549 | +/** 处理:已配置统一动作时直接执行点击的配置动作,否则回退原有处理 */ | |
| 550 | +const handleUnifiedProcess = async (item: any, action: any = null) => { | |
| 534 | 551 | const actions = Array.isArray(configuredActions.value) |
| 535 | 552 | ? configuredActions.value |
| 536 | 553 | : await queryUnifiedActions(item?.taskId) |
| 537 | 554 | if (actions) { |
| 538 | - // 主按钮文案就是第一个动作,直接执行该动作,不再弹「请选择操作」让用户二次选择 | |
| 539 | - unifiedActionsRef.value?.open(item, actions.slice(0, 1)) | |
| 555 | + // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 | |
| 556 | + unifiedActionsRef.value?.open(item, [action || actions[0]]) | |
| 540 | 557 | return |
| 541 | 558 | } |
| 542 | 559 | handleProcess(item) |
| ... | ... | @@ -1001,4 +1018,74 @@ onLoad((options: any) => { |
| 1001 | 1018 | width: 70px !important; |
| 1002 | 1019 | height: 70px !important; |
| 1003 | 1020 | } |
| 1021 | + | |
| 1022 | +// 底部动作按钮:动作多时自动换行 | |
| 1023 | +// 底部操作栏:白底 + 顶部投影,按钮每行最多 3 个,避免多动作时整屏遮挡工单详情 | |
| 1024 | +.order-action-bar { | |
| 1025 | + background-color: #fff; | |
| 1026 | + box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06); | |
| 1027 | + padding: 10rpx 14rpx; | |
| 1028 | + padding-bottom: calc(10rpx + constant(safe-area-inset-bottom)); | |
| 1029 | + padding-bottom: calc(10rpx + env(safe-area-inset-bottom)); | |
| 1030 | +} | |
| 1031 | + | |
| 1032 | +.order-action-row { | |
| 1033 | + display: flex; | |
| 1034 | + flex-wrap: wrap; | |
| 1035 | + margin: -6rpx; | |
| 1036 | +} | |
| 1037 | + | |
| 1038 | +.order-action-btn { | |
| 1039 | + box-sizing: border-box; | |
| 1040 | + width: calc((100% - 36rpx) / 3); | |
| 1041 | + height: 68rpx; | |
| 1042 | + line-height: 68rpx; | |
| 1043 | + margin: 6rpx; | |
| 1044 | + padding: 0 8rpx; | |
| 1045 | + border-radius: 8rpx; | |
| 1046 | + font-size: 26rpx; | |
| 1047 | + text-align: center; | |
| 1048 | + color: #fff; | |
| 1049 | + white-space: nowrap; | |
| 1050 | + overflow: hidden; | |
| 1051 | + text-overflow: ellipsis; | |
| 1052 | +} | |
| 1053 | + | |
| 1054 | +// 未配置统一动作时按钮整行展示,保持原有观感 | |
| 1055 | +.order-action-row--single .order-action-btn { | |
| 1056 | + width: 100%; | |
| 1057 | +} | |
| 1058 | + | |
| 1059 | +.order-action-btn--primary { | |
| 1060 | + background-color: #3c9cff; | |
| 1061 | +} | |
| 1062 | + | |
| 1063 | +.order-action-btn--success { | |
| 1064 | + background-color: #5ac725; | |
| 1065 | +} | |
| 1066 | + | |
| 1067 | +.order-action-btn--warning { | |
| 1068 | + background-color: #f9ae3d; | |
| 1069 | +} | |
| 1070 | + | |
| 1071 | +.order-action-btn--error { | |
| 1072 | + background-color: #f56c6c; | |
| 1073 | +} | |
| 1074 | + | |
| 1075 | +.order-action-btn--info { | |
| 1076 | + background-color: #909399; | |
| 1077 | +} | |
| 1078 | + | |
| 1079 | +// 按操作栏行数给内容预留底部间距 | |
| 1080 | +.main-content.pb-rows-1 { | |
| 1081 | + padding-bottom: 190rpx; | |
| 1082 | +} | |
| 1083 | + | |
| 1084 | +.main-content.pb-rows-2 { | |
| 1085 | + padding-bottom: 290rpx; | |
| 1086 | +} | |
| 1087 | + | |
| 1088 | +.main-content.pb-rows-3 { | |
| 1089 | + padding-bottom: 390rpx; | |
| 1090 | +} | |
| 1004 | 1091 | </style> |
| 1005 | 1092 | \ No newline at end of file | ... | ... |
pages-sub/problem/regional-order-manage/order-detail.vue
| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | ></up-loading-page> |
| 10 | 10 | |
| 11 | 11 | <!-- 主内容容器 --> |
| 12 | - <view v-else class="main-content"> | |
| 12 | + <view v-else class="main-content" :class="'pb-rows-' + actionBarRows"> | |
| 13 | 13 | <!-- 顶部固定Tabs --> |
| 14 | 14 | <up-sticky :bgColor="'#fff'"> |
| 15 | 15 | <up-tabs |
| ... | ... | @@ -253,21 +253,25 @@ |
| 253 | 253 | </view> |
| 254 | 254 | |
| 255 | 255 | <!-- activeTab==0的时候才出现, 也就是待办 --> |
| 256 | - <view v-if="activeTab==0&&(configuredActions||nextStepMap[orderDetail.taskKey])" class="fixed-bottom-btn-wrap"> | |
| 257 | - <view class="u-body-item u-flex common-justify-between common-item-center "> | |
| 258 | - <up-button type="warning" size="normal" @click="handleUnifiedReject(orderDetail)" | |
| 259 | - v-show="showRejectButton">回退 | |
| 260 | - </up-button> | |
| 261 | - | |
| 262 | - <up-button type="success" size="normal" @click="handleRenew(orderDetail)" | |
| 263 | - v-show="nextStepMap[orderDetail.taskKey]?.renewShow">重新提交 | |
| 264 | - </up-button> | |
| 265 | - | |
| 266 | - <up-button type="primary" size="normal" @click="handleUnifiedProcess(orderDetail)">{{ | |
| 267 | - processButtonText | |
| 268 | - }} | |
| 269 | - </up-button> | |
| 270 | - | |
| 256 | + <view v-if="activeTab==0&&(configuredActions||nextStepMap[orderDetail.taskKey])" | |
| 257 | + class="fixed-bottom-btn-wrap order-action-bar"> | |
| 258 | + <!-- 已配置工作流动作:每行最多 3 个、超出自动换行,点击直接执行对应动作,不再弹「请选择操作」 --> | |
| 259 | + <view v-if="hasConfiguredActions" class="order-action-row"> | |
| 260 | + <view | |
| 261 | + v-for="action in configuredActions" | |
| 262 | + :key="action.code" | |
| 263 | + :class="['order-action-btn', 'order-action-btn--' + getActionButtonType(action.code)]" | |
| 264 | + @click.stop="handleUnifiedProcess(orderDetail, action)" | |
| 265 | + >{{ action.name }}</view> | |
| 266 | + </view> | |
| 267 | + <!-- 未配置:沿用原有节点按钮(整行展示) --> | |
| 268 | + <view v-else class="order-action-row order-action-row--single"> | |
| 269 | + <view v-if="showRejectButton" class="order-action-btn order-action-btn--warning" | |
| 270 | + @click.stop="handleUnifiedReject(orderDetail)">回退</view> | |
| 271 | + <view v-if="nextStepMap[orderDetail.taskKey]?.renewShow" class="order-action-btn order-action-btn--success" | |
| 272 | + @click.stop="handleRenew(orderDetail)">重新提交</view> | |
| 273 | + <view class="order-action-btn order-action-btn--primary" | |
| 274 | + @click.stop="handleUnifiedProcess(orderDetail)">{{ processButtonText }}</view> | |
| 271 | 275 | </view> |
| 272 | 276 | </view> |
| 273 | 277 | |
| ... | ... | @@ -377,7 +381,7 @@ import { |
| 377 | 381 | dcyUniversalApproval, |
| 378 | 382 | aiUniversalApproval |
| 379 | 383 | } from '@/api/regional-order-manage/regional-order-manage'; |
| 380 | -import {nextStepMap, buzStatusMap, calculateFormatTimeDiff} from '@/common/utils/common' | |
| 384 | +import {nextStepMap, buzStatusMap, calculateFormatTimeDiff, getActionButtonType} from '@/common/utils/common' | |
| 381 | 385 | import {getTaskActions} from '@/api/work-order-manage/work-order-manage'; |
| 382 | 386 | import {useUploadImgs} from '@/common/utils/useUploadImgs' |
| 383 | 387 | import { useUserStore } from '@/pinia/user'; |
| ... | ... | @@ -585,6 +589,21 @@ const showRejectButton = computed(() => { |
| 585 | 589 | return !!nextStepMap[orderDetail.value.taskKey]?.backShow |
| 586 | 590 | }) |
| 587 | 591 | |
| 592 | +/** 是否已配置统一动作(配置后按配置逐个渲染动作按钮) */ | |
| 593 | +const hasConfiguredActions = computed(() => | |
| 594 | + Array.isArray(configuredActions.value) && configuredActions.value.length > 0) | |
| 595 | + | |
| 596 | +/** 底部操作栏行数:详情内容据此预留底部间距,避免按钮遮挡内容 */ | |
| 597 | +const actionBarRows = computed(() => { | |
| 598 | + if (hasConfiguredActions.value) { | |
| 599 | + return Math.ceil(configuredActions.value.length / 3) | |
| 600 | + } | |
| 601 | + let rows = 1 | |
| 602 | + if (showRejectButton.value) rows++ | |
| 603 | + if (nextStepMap[orderDetail.value.taskKey]?.renewShow) rows++ | |
| 604 | + return rows | |
| 605 | +}) | |
| 606 | + | |
| 588 | 607 | /** 主按钮文案:已配置统一动作时取配置的动作名称,未配置时沿用原有节点规则 */ |
| 589 | 608 | const processButtonText = computed(() => { |
| 590 | 609 | const actions = configuredActions.value |
| ... | ... | @@ -597,14 +616,14 @@ const processButtonText = computed(() => { |
| 597 | 616 | /** 统一动作弹窗 */ |
| 598 | 617 | const unifiedActionsRef = ref<any>(null) |
| 599 | 618 | |
| 600 | -/** 处理:已配置统一动作时走统一接口,否则回退原有处理 */ | |
| 601 | -const handleUnifiedProcess = async (item: any) => { | |
| 619 | +/** 处理:已配置统一动作时直接执行点击的配置动作,否则回退原有处理 */ | |
| 620 | +const handleUnifiedProcess = async (item: any, action: any = null) => { | |
| 602 | 621 | const actions = Array.isArray(configuredActions.value) |
| 603 | 622 | ? configuredActions.value |
| 604 | 623 | : await queryUnifiedActions(item?.taskId) |
| 605 | 624 | if (actions) { |
| 606 | - // 主按钮文案就是第一个动作,直接执行该动作,不再弹「请选择操作」让用户二次选择 | |
| 607 | - unifiedActionsRef.value?.open(item, actions.slice(0, 1)) | |
| 625 | + // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 | |
| 626 | + unifiedActionsRef.value?.open(item, [action || actions[0]]) | |
| 608 | 627 | return |
| 609 | 628 | } |
| 610 | 629 | handleProcess(item) |
| ... | ... | @@ -1146,4 +1165,74 @@ onShow(() => {}); |
| 1146 | 1165 | width: 70px !important; |
| 1147 | 1166 | height: 70px !important; |
| 1148 | 1167 | } |
| 1168 | + | |
| 1169 | +// 底部动作按钮:动作多时自动换行 | |
| 1170 | +// 底部操作栏:白底 + 顶部投影,按钮每行最多 3 个,避免多动作时整屏遮挡工单详情 | |
| 1171 | +.order-action-bar { | |
| 1172 | + background-color: #fff; | |
| 1173 | + box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06); | |
| 1174 | + padding: 10rpx 14rpx; | |
| 1175 | + padding-bottom: calc(10rpx + constant(safe-area-inset-bottom)); | |
| 1176 | + padding-bottom: calc(10rpx + env(safe-area-inset-bottom)); | |
| 1177 | +} | |
| 1178 | + | |
| 1179 | +.order-action-row { | |
| 1180 | + display: flex; | |
| 1181 | + flex-wrap: wrap; | |
| 1182 | + margin: -6rpx; | |
| 1183 | +} | |
| 1184 | + | |
| 1185 | +.order-action-btn { | |
| 1186 | + box-sizing: border-box; | |
| 1187 | + width: calc((100% - 36rpx) / 3); | |
| 1188 | + height: 68rpx; | |
| 1189 | + line-height: 68rpx; | |
| 1190 | + margin: 6rpx; | |
| 1191 | + padding: 0 8rpx; | |
| 1192 | + border-radius: 8rpx; | |
| 1193 | + font-size: 26rpx; | |
| 1194 | + text-align: center; | |
| 1195 | + color: #fff; | |
| 1196 | + white-space: nowrap; | |
| 1197 | + overflow: hidden; | |
| 1198 | + text-overflow: ellipsis; | |
| 1199 | +} | |
| 1200 | + | |
| 1201 | +// 未配置统一动作时按钮整行展示,保持原有观感 | |
| 1202 | +.order-action-row--single .order-action-btn { | |
| 1203 | + width: 100%; | |
| 1204 | +} | |
| 1205 | + | |
| 1206 | +.order-action-btn--primary { | |
| 1207 | + background-color: #3c9cff; | |
| 1208 | +} | |
| 1209 | + | |
| 1210 | +.order-action-btn--success { | |
| 1211 | + background-color: #5ac725; | |
| 1212 | +} | |
| 1213 | + | |
| 1214 | +.order-action-btn--warning { | |
| 1215 | + background-color: #f9ae3d; | |
| 1216 | +} | |
| 1217 | + | |
| 1218 | +.order-action-btn--error { | |
| 1219 | + background-color: #f56c6c; | |
| 1220 | +} | |
| 1221 | + | |
| 1222 | +.order-action-btn--info { | |
| 1223 | + background-color: #909399; | |
| 1224 | +} | |
| 1225 | + | |
| 1226 | +// 按操作栏行数给内容预留底部间距 | |
| 1227 | +.main-content.pb-rows-1 { | |
| 1228 | + padding-bottom: 190rpx; | |
| 1229 | +} | |
| 1230 | + | |
| 1231 | +.main-content.pb-rows-2 { | |
| 1232 | + padding-bottom: 290rpx; | |
| 1233 | +} | |
| 1234 | + | |
| 1235 | +.main-content.pb-rows-3 { | |
| 1236 | + padding-bottom: 390rpx; | |
| 1237 | +} | |
| 1149 | 1238 | </style> |
| 1150 | 1239 | \ No newline at end of file | ... | ... |
pages-sub/problem/work-order-manage/index.vue
| ... | ... | @@ -101,20 +101,27 @@ |
| 101 | 101 | <view class="u-line-1 u-body-value">{{ timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}</view> |
| 102 | 102 | </view> |
| 103 | 103 | <!-- 操作按钮行 --> |
| 104 | - <view class="u-body-item u-body-item-btn-wrap u-flex common-justify-between common-item-center mt-20"> | |
| 105 | - <up-button type="warning" size="large" @click="handleUnifiedReject(item)" | |
| 106 | - v-show="showRejectButton(item)">回退 | |
| 107 | - </up-button> | |
| 108 | - | |
| 109 | - <up-button type="success" size="large" @click="handleRenew(item)" | |
| 110 | - v-show="nextStepMap[item.taskKey]?.renewShow">重新提交 | |
| 111 | - </up-button> | |
| 112 | - | |
| 113 | - <up-button type="primary" size="large" @click="handleUnifiedProcess(item)">{{ | |
| 114 | - getProcessButtonText(item) | |
| 115 | - }} | |
| 116 | - </up-button> | |
| 117 | - <up-button type="info" size="large" @click="handleDetail(item)">详情</up-button> | |
| 104 | + <view class="u-body-item task-btn-row mt-20"> | |
| 105 | + <!-- 已配置工作流动作:按配置逐个渲染按钮,点击直接执行对应动作,不再弹「请选择操作」 --> | |
| 106 | + <template v-if="hasConfiguredActions(item)"> | |
| 107 | + <view | |
| 108 | + v-for="action in item.configuredActions" | |
| 109 | + :key="action.code" | |
| 110 | + :class="['task-btn', 'task-btn--' + getActionButtonType(action.code)]" | |
| 111 | + @click.stop="handleUnifiedProcess(item, action)" | |
| 112 | + >{{ action.name }}</view> | |
| 113 | + <view class="task-btn task-btn--info" @click.stop="handleDetail(item)">详情</view> | |
| 114 | + </template> | |
| 115 | + <!-- 未配置:沿用原有节点按钮 --> | |
| 116 | + <template v-else> | |
| 117 | + <view v-if="showRejectButton(item)" class="task-btn task-btn--warning" | |
| 118 | + @click.stop="handleUnifiedReject(item)">回退</view> | |
| 119 | + <view v-if="nextStepMap[item.taskKey]?.renewShow" class="task-btn task-btn--success" | |
| 120 | + @click.stop="handleRenew(item)">重新提交</view> | |
| 121 | + <view class="task-btn task-btn--primary" | |
| 122 | + @click.stop="handleUnifiedProcess(item)">{{ getProcessButtonText(item) }}</view> | |
| 123 | + <view class="task-btn task-btn--info" @click.stop="handleDetail(item)">详情</view> | |
| 124 | + </template> | |
| 118 | 125 | </view> |
| 119 | 126 | </view> |
| 120 | 127 | </template> |
| ... | ... | @@ -291,7 +298,7 @@ import { |
| 291 | 298 | } from '@/api/work-order-manage/work-order-manage' |
| 292 | 299 | // 从用户store获取角色信息 |
| 293 | 300 | import { useUserStore } from '@/pinia/user'; |
| 294 | -import { nextStepMap, buzStatusMap } from '@/common/utils/common' | |
| 301 | +import { nextStepMap, buzStatusMap, getActionButtonType } from '@/common/utils/common' | |
| 295 | 302 | // 引入图片上传组合式函数(与参考页面一致) |
| 296 | 303 | import { useUploadImgs } from '@/common/utils/useUploadImgs' |
| 297 | 304 | |
| ... | ... | @@ -539,14 +546,18 @@ const getProcessButtonText = (item) => { |
| 539 | 546 | return nextStepMap[item.taskKey]?.btnText |
| 540 | 547 | } |
| 541 | 548 | |
| 542 | -/** 待办-处理工单:已配置统一动作时走新逻辑,否则回退原有处理 */ | |
| 543 | -const handleUnifiedProcess = async (item) => { | |
| 549 | +/** 是否已配置统一动作(配置后按配置逐个渲染动作按钮) */ | |
| 550 | +const hasConfiguredActions = (item) => | |
| 551 | + Array.isArray(item?.configuredActions) && item.configuredActions.length > 0 | |
| 552 | + | |
| 553 | +/** 待办-处理工单:已配置统一动作时直接执行点击的配置动作,否则回退原有处理 */ | |
| 554 | +const handleUnifiedProcess = async (item, action = null) => { | |
| 544 | 555 | const actions = Array.isArray(item?.configuredActions) |
| 545 | 556 | ? item.configuredActions |
| 546 | 557 | : await queryUnifiedActions(item) |
| 547 | 558 | if (actions) { |
| 548 | - // 主按钮文案就是第一个动作,直接执行该动作,不再弹「请选择操作」让用户二次选择 | |
| 549 | - unifiedActionsRef.value?.open(item, actions.slice(0, 1)) | |
| 559 | + // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 | |
| 560 | + unifiedActionsRef.value?.open(item, [action || actions[0]]) | |
| 550 | 561 | return |
| 551 | 562 | } |
| 552 | 563 | handleProcess(item) |
| ... | ... | @@ -842,9 +853,44 @@ onUnload(() => { |
| 842 | 853 | border-radius: 12rpx; |
| 843 | 854 | box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); |
| 844 | 855 | } |
| 845 | -.u-body-item-btn-wrap :deep(.u-button--large){ | |
| 856 | +// 卡片操作按钮:自动换行、右对齐,动作多时每行 3~4 个,不再整行铺满 | |
| 857 | +.task-btn-row { | |
| 858 | + display: flex; | |
| 859 | + flex-wrap: wrap; | |
| 860 | + justify-content: flex-end; | |
| 861 | + margin-bottom: -10rpx; | |
| 862 | +} | |
| 863 | + | |
| 864 | +.task-btn { | |
| 865 | + box-sizing: border-box; | |
| 866 | + height: 56rpx; | |
| 867 | + line-height: 56rpx; | |
| 868 | + padding: 0 24rpx; | |
| 869 | + margin: 0 0 10rpx 12rpx; | |
| 870 | + border-radius: 8rpx; | |
| 871 | + font-size: 24rpx; | |
| 872 | + color: #fff; | |
| 873 | + white-space: nowrap; | |
| 874 | +} | |
| 875 | + | |
| 876 | +.task-btn--primary { | |
| 877 | + background-color: #3c9cff; | |
| 878 | +} | |
| 879 | + | |
| 880 | +.task-btn--success { | |
| 881 | + background-color: #5ac725; | |
| 882 | +} | |
| 883 | + | |
| 884 | +.task-btn--warning { | |
| 885 | + background-color: #f9ae3d; | |
| 886 | +} | |
| 887 | + | |
| 888 | +.task-btn--error { | |
| 889 | + background-color: #f56c6c; | |
| 890 | +} | |
| 846 | 891 | |
| 847 | - height: 28px; | |
| 892 | +.task-btn--info { | |
| 893 | + background-color: #909399; | |
| 848 | 894 | } |
| 849 | 895 | |
| 850 | 896 | ... | ... |
pages-sub/problem/work-order-manage/order-detail.vue
| ... | ... | @@ -9,7 +9,7 @@ |
| 9 | 9 | ></up-loading-page> |
| 10 | 10 | |
| 11 | 11 | <!-- 主内容容器 --> |
| 12 | - <view v-else class="main-content"> | |
| 12 | + <view v-else class="main-content" :class="'pb-rows-' + actionBarRows"> | |
| 13 | 13 | <!-- 顶部固定Tabs --> |
| 14 | 14 | <up-sticky :bgColor="'#fff'"> |
| 15 | 15 | <up-tabs |
| ... | ... | @@ -256,20 +256,25 @@ |
| 256 | 256 | </view> |
| 257 | 257 | |
| 258 | 258 | <!-- activeTab==0的时候才出现, 也就是待办 --> |
| 259 | - <view v-if="activeTab==0&&(configuredActions||nextStepMap[orderDetail.taskKey])" class="fixed-bottom-btn-wrap"> | |
| 260 | - <view class="u-body-item u-flex common-justify-between common-item-center "> | |
| 261 | - <up-button type="warning" size="normal" @click="handleUnifiedReject(orderDetail)" | |
| 262 | - v-show="showRejectButton">回退 | |
| 263 | - </up-button> | |
| 264 | - | |
| 265 | - <up-button type="success" size="normal" @click="handleRenew(orderDetail)" | |
| 266 | - v-show="nextStepMap[orderDetail.taskKey]?.renewShow">重新提交 | |
| 267 | - </up-button> | |
| 268 | - | |
| 269 | - <up-button type="primary" size="normal" @click="handleUnifiedProcess(orderDetail)">{{ | |
| 270 | - processButtonText | |
| 271 | - }} | |
| 272 | - </up-button> | |
| 259 | + <view v-if="activeTab==0&&(configuredActions||nextStepMap[orderDetail.taskKey])" | |
| 260 | + class="fixed-bottom-btn-wrap order-action-bar"> | |
| 261 | + <!-- 已配置工作流动作:每行最多 3 个、超出自动换行,点击直接执行对应动作,不再弹「请选择操作」 --> | |
| 262 | + <view v-if="hasConfiguredActions" class="order-action-row"> | |
| 263 | + <view | |
| 264 | + v-for="action in configuredActions" | |
| 265 | + :key="action.code" | |
| 266 | + :class="['order-action-btn', 'order-action-btn--' + getActionButtonType(action.code)]" | |
| 267 | + @click.stop="handleUnifiedProcess(orderDetail, action)" | |
| 268 | + >{{ action.name }}</view> | |
| 269 | + </view> | |
| 270 | + <!-- 未配置:沿用原有节点按钮(整行展示) --> | |
| 271 | + <view v-else class="order-action-row order-action-row--single"> | |
| 272 | + <view v-if="showRejectButton" class="order-action-btn order-action-btn--warning" | |
| 273 | + @click.stop="handleUnifiedReject(orderDetail)">回退</view> | |
| 274 | + <view v-if="nextStepMap[orderDetail.taskKey]?.renewShow" class="order-action-btn order-action-btn--success" | |
| 275 | + @click.stop="handleRenew(orderDetail)">重新提交</view> | |
| 276 | + <view class="order-action-btn order-action-btn--primary" | |
| 277 | + @click.stop="handleUnifiedProcess(orderDetail)">{{ processButtonText }}</view> | |
| 273 | 278 | </view> |
| 274 | 279 | </view> |
| 275 | 280 | |
| ... | ... | @@ -376,7 +381,7 @@ import { |
| 376 | 381 | universalApproval, |
| 377 | 382 | getTaskActions |
| 378 | 383 | } from '@/api/work-order-manage/work-order-manage'; |
| 379 | -import {nextStepMap, buzStatusMap, calculateFormatTimeDiff} from '@/common/utils/common' | |
| 384 | +import {nextStepMap, buzStatusMap, calculateFormatTimeDiff, getActionButtonType} from '@/common/utils/common' | |
| 380 | 385 | // 引入图片上传组合式函数 |
| 381 | 386 | import {useUploadImgs} from '@/common/utils/useUploadImgs' |
| 382 | 387 | |
| ... | ... | @@ -722,6 +727,21 @@ const showRejectButton = computed(() => { |
| 722 | 727 | return !!nextStepMap[orderDetail.value.taskKey]?.backShow |
| 723 | 728 | }) |
| 724 | 729 | |
| 730 | +/** 是否已配置统一动作(配置后按配置逐个渲染动作按钮) */ | |
| 731 | +const hasConfiguredActions = computed(() => | |
| 732 | + Array.isArray(configuredActions.value) && configuredActions.value.length > 0) | |
| 733 | + | |
| 734 | +/** 底部操作栏行数:详情内容据此预留底部间距,避免按钮遮挡内容 */ | |
| 735 | +const actionBarRows = computed(() => { | |
| 736 | + if (hasConfiguredActions.value) { | |
| 737 | + return Math.ceil(configuredActions.value.length / 3) | |
| 738 | + } | |
| 739 | + let rows = 1 | |
| 740 | + if (showRejectButton.value) rows++ | |
| 741 | + if (nextStepMap[orderDetail.value.taskKey]?.renewShow) rows++ | |
| 742 | + return rows | |
| 743 | +}) | |
| 744 | + | |
| 725 | 745 | /** 主按钮文案:已配置统一动作时取配置的动作名称,未配置时沿用原有节点规则 */ |
| 726 | 746 | const processButtonText = computed(() => { |
| 727 | 747 | const actions = configuredActions.value |
| ... | ... | @@ -745,14 +765,14 @@ const queryUnifiedActions = async (item: any) => { |
| 745 | 765 | return null |
| 746 | 766 | } |
| 747 | 767 | |
| 748 | -/** 处理工单:已配置统一动作时走新逻辑,否则回退原有处理 */ | |
| 749 | -const handleUnifiedProcess = async (item: any) => { | |
| 768 | +/** 处理工单:已配置统一动作时直接执行点击的配置动作,否则回退原有处理 */ | |
| 769 | +const handleUnifiedProcess = async (item: any, action: any = null) => { | |
| 750 | 770 | const actions = Array.isArray(configuredActions.value) |
| 751 | 771 | ? configuredActions.value |
| 752 | 772 | : await queryUnifiedActions(item) |
| 753 | 773 | if (actions) { |
| 754 | - // 主按钮文案就是第一个动作,直接执行该动作,不再弹「请选择操作」让用户二次选择 | |
| 755 | - unifiedActionsRef.value?.open(item, actions.slice(0, 1)) | |
| 774 | + // 传入的动作即用户点击的配置按钮,直接执行该动作,不再弹「请选择操作」二次选择 | |
| 775 | + unifiedActionsRef.value?.open(item, [action || actions[0]]) | |
| 756 | 776 | return |
| 757 | 777 | } |
| 758 | 778 | handleProcess(item) |
| ... | ... | @@ -1151,4 +1171,74 @@ onShow(() => { |
| 1151 | 1171 | width: 70px !important; // 与多图保持一致 |
| 1152 | 1172 | height: 70px !important; |
| 1153 | 1173 | } |
| 1174 | + | |
| 1175 | +// 底部动作按钮:动作多时自动换行 | |
| 1176 | +// 底部操作栏:白底 + 顶部投影,按钮每行最多 3 个,避免多动作时整屏遮挡工单详情 | |
| 1177 | +.order-action-bar { | |
| 1178 | + background-color: #fff; | |
| 1179 | + box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.06); | |
| 1180 | + padding: 10rpx 14rpx; | |
| 1181 | + padding-bottom: calc(10rpx + constant(safe-area-inset-bottom)); | |
| 1182 | + padding-bottom: calc(10rpx + env(safe-area-inset-bottom)); | |
| 1183 | +} | |
| 1184 | + | |
| 1185 | +.order-action-row { | |
| 1186 | + display: flex; | |
| 1187 | + flex-wrap: wrap; | |
| 1188 | + margin: -6rpx; | |
| 1189 | +} | |
| 1190 | + | |
| 1191 | +.order-action-btn { | |
| 1192 | + box-sizing: border-box; | |
| 1193 | + width: calc((100% - 36rpx) / 3); | |
| 1194 | + height: 68rpx; | |
| 1195 | + line-height: 68rpx; | |
| 1196 | + margin: 6rpx; | |
| 1197 | + padding: 0 8rpx; | |
| 1198 | + border-radius: 8rpx; | |
| 1199 | + font-size: 26rpx; | |
| 1200 | + text-align: center; | |
| 1201 | + color: #fff; | |
| 1202 | + white-space: nowrap; | |
| 1203 | + overflow: hidden; | |
| 1204 | + text-overflow: ellipsis; | |
| 1205 | +} | |
| 1206 | + | |
| 1207 | +// 未配置统一动作时按钮整行展示,保持原有观感 | |
| 1208 | +.order-action-row--single .order-action-btn { | |
| 1209 | + width: 100%; | |
| 1210 | +} | |
| 1211 | + | |
| 1212 | +.order-action-btn--primary { | |
| 1213 | + background-color: #3c9cff; | |
| 1214 | +} | |
| 1215 | + | |
| 1216 | +.order-action-btn--success { | |
| 1217 | + background-color: #5ac725; | |
| 1218 | +} | |
| 1219 | + | |
| 1220 | +.order-action-btn--warning { | |
| 1221 | + background-color: #f9ae3d; | |
| 1222 | +} | |
| 1223 | + | |
| 1224 | +.order-action-btn--error { | |
| 1225 | + background-color: #f56c6c; | |
| 1226 | +} | |
| 1227 | + | |
| 1228 | +.order-action-btn--info { | |
| 1229 | + background-color: #909399; | |
| 1230 | +} | |
| 1231 | + | |
| 1232 | +// 按操作栏行数给内容预留底部间距 | |
| 1233 | +.main-content.pb-rows-1 { | |
| 1234 | + padding-bottom: 190rpx; | |
| 1235 | +} | |
| 1236 | + | |
| 1237 | +.main-content.pb-rows-2 { | |
| 1238 | + padding-bottom: 290rpx; | |
| 1239 | +} | |
| 1240 | + | |
| 1241 | +.main-content.pb-rows-3 { | |
| 1242 | + padding-bottom: 390rpx; | |
| 1243 | +} | |
| 1154 | 1244 | </style> |
| 1155 | 1245 | \ No newline at end of file | ... | ... |