Commit 6e9f0396eec87d6d793579da151bbfb885e0d21e
1 parent
7adb99f0
全域督察员
Showing
4 changed files
with
859 additions
and
5 deletions
api/regional-order-manage/regional-order-manage.js
| ... | ... | @@ -129,6 +129,27 @@ export const dcyUniversalApproval = (data) => { |
| 129 | 129 | }; |
| 130 | 130 | |
| 131 | 131 | |
| 132 | +/** | |
| 133 | + * AI工单派发人员创建工单 | |
| 134 | + * @returns {Promise} | |
| 135 | + */ | |
| 136 | +export const aiWorkorderCreate = (data) => { | |
| 137 | + return post('/app-api/bpm/ai/workorder/create',data); | |
| 138 | +}; | |
| 139 | + | |
| 140 | + | |
| 141 | +/** | |
| 142 | + * -- app端统一AI工单派发人员发起审批入口 | |
| 143 | + * @returns {Promise} | |
| 144 | + */ | |
| 145 | +export const aiUniversalApproval = (data) => { | |
| 146 | + return post('/app-api/bpm/ai/workorder/universalApproval',data); | |
| 147 | +}; | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 132 | 153 | |
| 133 | 154 | |
| 134 | 155 | ... | ... |
pages-sub/problem/ai-manage/index.vue
0 → 100644
| 1 | +<template> | |
| 2 | + <view class="page-container"> | |
| 3 | + <!-- 顶部固定区域 --> | |
| 4 | + <up-sticky> | |
| 5 | + <view class="header-wrap"> | |
| 6 | + <!-- 第一行:u-tabs 待办/已办切换 :scrollable="false"--> | |
| 7 | + <up-tabs | |
| 8 | + v-model="activeTab" | |
| 9 | + :list="tabList" | |
| 10 | + active-color="#1989fa" | |
| 11 | + inactive-color="#666" | |
| 12 | + font-size="30rpx" | |
| 13 | + @click="handleTabChange" | |
| 14 | + /> | |
| 15 | + | |
| 16 | + <!-- 第二行:下拉框 + 搜索框 --> | |
| 17 | + <view class="search-header"> | |
| 18 | + <!-- 左侧下拉框 --> | |
| 19 | + <view class="select-wrap common-text-color"> | |
| 20 | + <up-select | |
| 21 | + v-model:current="selectedSortValue" | |
| 22 | + :options="sortOptions" | |
| 23 | + :showOptionsLabel="true" | |
| 24 | + @select="handleSortChange" | |
| 25 | + border="surround" | |
| 26 | + :style="{ flex: 1 }" | |
| 27 | + /> | |
| 28 | + </view> | |
| 29 | + | |
| 30 | + <!-- 右侧搜索框 --> | |
| 31 | + <view class="search-input-wrap"> | |
| 32 | + <up-search | |
| 33 | + v-model="searchValue" | |
| 34 | + placeholder="请输入关键字" | |
| 35 | + @search="handleSearch" | |
| 36 | + bg-color="#f5f5f5" | |
| 37 | + :clearabled="false" | |
| 38 | + :show-action="true" | |
| 39 | + actionText="搜索" | |
| 40 | + :animation="true" | |
| 41 | + @custom="handleSearch" | |
| 42 | + /> | |
| 43 | + </view> | |
| 44 | + </view> | |
| 45 | + </view> | |
| 46 | + </up-sticky> | |
| 47 | + | |
| 48 | + <!-- 列表容器 --> | |
| 49 | + <z-paging | |
| 50 | + ref="paging" | |
| 51 | + v-model="orderList" | |
| 52 | + @query="queryList" | |
| 53 | + :auto-show-system-loading="true" | |
| 54 | + | |
| 55 | + > | |
| 56 | + <template #empty> | |
| 57 | + <empty-view/> | |
| 58 | + </template> | |
| 59 | + | |
| 60 | + <view class="common-card-list" style="padding-top: 200rpx;padding-bottom: 30rpx"> | |
| 61 | + <!-- 待办工单卡片 --> | |
| 62 | + <up-card | |
| 63 | + v-if="activeTab == 0" | |
| 64 | + :border="false" | |
| 65 | + :foot-border-top="false" | |
| 66 | + v-for="(item, index) in orderList" | |
| 67 | + :key="`todo_${item.orderNo}_${index}`" | |
| 68 | + :show-head="false" | |
| 69 | + class="order-card" | |
| 70 | + > | |
| 71 | + <template #body> | |
| 72 | + <view class="card-body"> | |
| 73 | + <view class="u-body-item u-flex"> | |
| 74 | + <view class="u-body-item-title">工单编号:</view> | |
| 75 | + <view class="u-line-1 u-body-value">{{ item.orderNo || '-' }}</view> | |
| 76 | + </view> | |
| 77 | + <view class="u-body-item u-flex"> | |
| 78 | + <view class="u-body-item-title">工单位置:</view> | |
| 79 | + <view class="u-line-1 u-body-value">{{ item.lonLatAddress || '-' }}</view> | |
| 80 | + </view> | |
| 81 | + <view class="u-body-item u-flex"> | |
| 82 | + <view class="u-body-item-title">工单名称:</view> | |
| 83 | + <view class="u-line-1 u-body-value">{{ item.orderName || '未填写' }}</view> | |
| 84 | + </view> | |
| 85 | + <view class="u-body-item u-flex"> | |
| 86 | + <view class="u-body-item-title">情况描述:</view> | |
| 87 | + <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> | |
| 88 | + </view> | |
| 89 | + <view class="u-body-item u-flex common-item-center common-justify-between"> | |
| 90 | + <view class="u-body-item-title">紧急程度:</view> | |
| 91 | + <view class="u-line-1 u-body-value"> | |
| 92 | + {{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} | |
| 93 | + </view> | |
| 94 | + </view> | |
| 95 | + <view class="u-body-item u-flex"> | |
| 96 | + <view class="u-body-item-title">工单状态:</view> | |
| 97 | + <view class="u-line-1 u-body-value">{{ buzStatusMap[item.buzStatus] }}</view> | |
| 98 | + </view> | |
| 99 | + <view class="u-body-item u-flex"> | |
| 100 | + <view class="u-body-item-title">提交时间:</view> | |
| 101 | + <view class="u-line-1 u-body-value">{{ timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}</view> | |
| 102 | + </view> | |
| 103 | + <!-- 操作按钮行 --> | |
| 104 | + | |
| 105 | + <view class="u-body-item u-flex common-justify-between common-item-center mt-20"> | |
| 106 | + <up-button type="warning" size="mini" @click="handleReject(item)" | |
| 107 | + v-show="nextStepMap[item.taskKey].backShow">回退 | |
| 108 | + </up-button> | |
| 109 | + | |
| 110 | + <up-button type="success" size="mini" @click="handleRenew(item)" | |
| 111 | + v-show="nextStepMap[item.taskKey].renewShow">重新提交 | |
| 112 | + </up-button> | |
| 113 | + | |
| 114 | + <up-button type="primary" size="mini" @click="handleProcess(item)">{{ | |
| 115 | + nextStepMap[item.taskKey].btnText | |
| 116 | + }} | |
| 117 | + </up-button> | |
| 118 | + <up-button type="info" size="mini" @click="handleDetail(item)">详情</up-button> | |
| 119 | + </view> | |
| 120 | + </view> | |
| 121 | + </template> | |
| 122 | + </up-card> | |
| 123 | + | |
| 124 | + <!-- 已办工单卡片和我发起的 --> | |
| 125 | + <up-card | |
| 126 | + v-if="activeTab == 2||activeTab == 1" | |
| 127 | + :border="false" | |
| 128 | + :foot-border-top="false" | |
| 129 | + v-for="(item, index) in orderList" | |
| 130 | + :key="`done_${item.orderNo}_${index}`" | |
| 131 | + :show-head="false" | |
| 132 | + class="order-card" | |
| 133 | + > | |
| 134 | + <template #body> | |
| 135 | + <view class="card-body"> | |
| 136 | + <view class="u-body-item u-flex"> | |
| 137 | + <view class="u-body-item-title">工单编号:</view> | |
| 138 | + <view class="u-line-1 u-body-value">{{ item.orderNo || '-' }}</view> | |
| 139 | + </view> | |
| 140 | + <view class="u-body-item u-flex"> | |
| 141 | + <view class="u-body-item-title">工单位置:</view> | |
| 142 | + <view class="u-line-1 u-body-value">{{ item.lonLatAddress || '-' }}</view> | |
| 143 | + </view> | |
| 144 | + <view class="u-body-item u-flex"> | |
| 145 | + <view class="u-body-item-title">工单名称:</view> | |
| 146 | + <view class="u-line-1 u-body-value">{{ item.orderName || '未填写' }}</view> | |
| 147 | + </view> | |
| 148 | + <view class="u-body-item u-flex"> | |
| 149 | + <view class="u-body-item-title">情况描述:</view> | |
| 150 | + <view class="u-line-1 u-body-value">{{ item.remark || '无' }}</view> | |
| 151 | + </view> | |
| 152 | + | |
| 153 | + <view class="u-body-item u-flex common-justify-between common-item-center"> | |
| 154 | + <view class="u-body-item-title"> | |
| 155 | + 紧急程度:{{ uni.$dict.getDictLabel('workorder_pressing_type', item.pressingType) }} | |
| 156 | + </view> | |
| 157 | + <view class=" "> | |
| 158 | + <up-button type="primary" size="mini" @click="handleDetail(item)">工单详情</up-button> | |
| 159 | + </view> | |
| 160 | + </view> | |
| 161 | + <view class="u-body-item u-flex"> | |
| 162 | + <view class="u-body-item-title">工单状态:</view> | |
| 163 | + <view class="u-line-1 u-body-value">{{ buzStatusMap[item.buzStatus] }}</view> | |
| 164 | + </view> | |
| 165 | + <view class="u-body-item u-flex"> | |
| 166 | + <view class="u-body-item-title">提交时间:</view> | |
| 167 | + <view class="u-line-1 u-body-value">{{ timeFormat(item.createTime, 'yyyy-mm-dd hh:MM:ss') }}</view> | |
| 168 | + </view> | |
| 169 | + </view> | |
| 170 | + </template> | |
| 171 | + </up-card> | |
| 172 | + </view> | |
| 173 | + </z-paging> | |
| 174 | + | |
| 175 | + <!-- 底部新增工单按钮(仅巡查员显示) --> | |
| 176 | + <!-- <view v-if="isInspector" class="fixed-bottom-btn-wrap">--> | |
| 177 | + <!-- <up-button type="primary" size="large" @click="handleAddOrder">--> | |
| 178 | + <!-- 新增工单--> | |
| 179 | + <!-- </up-button>--> | |
| 180 | + <!-- </view>--> | |
| 181 | + | |
| 182 | + <view class="fixed-bottom-btn-wrap" v-if="isAi"> | |
| 183 | + <up-button type="primary" size="large" @click="handleAddOrder"> | |
| 184 | + 新增工单 | |
| 185 | + </up-button> | |
| 186 | + </view> | |
| 187 | + | |
| 188 | + | |
| 189 | + <!-- 回退原因弹窗:替换为up-modal(核心修改) --> | |
| 190 | + <up-modal | |
| 191 | + :show="rejectModalShow" | |
| 192 | + title="回退原因" | |
| 193 | + :closeOnClickOverlay="false" | |
| 194 | + :showConfirmButton="true" | |
| 195 | + :showCancelButton="true" | |
| 196 | + @cancel="handleRejectModalCancel" | |
| 197 | + @confirm="confirmReject" | |
| 198 | + > | |
| 199 | + <view class="reject-modal-content"> | |
| 200 | + <!-- 回退原因 必填textarea --> | |
| 201 | + <up-textarea | |
| 202 | + v-model.trim="rejectReason" | |
| 203 | + placeholder="请输入回退原因(必填)" | |
| 204 | + rows="6" | |
| 205 | + :count="200" | |
| 206 | + maxlength="200" | |
| 207 | + class="reject-textarea" | |
| 208 | + /> | |
| 209 | + <!-- 上传图片(选填)- 按照参考页面改造 --> | |
| 210 | + <view class="upload-wrap mt-20"> | |
| 211 | + <view class="upload-title">上传图片(选填)</view> | |
| 212 | + <up-upload | |
| 213 | + :file-list="rejectImgs.rawImgList.value|| []" | |
| 214 | + @after-read="rejectImgs.uploadImgs" | |
| 215 | + @delete="rejectImgs.deleteImg" | |
| 216 | + multiple | |
| 217 | + width="70" | |
| 218 | + height="70" | |
| 219 | + :max-count="rejectImgs.uploadConfig.maxCount" | |
| 220 | + :upload-text="rejectImgs.uploadConfig.uploadText" | |
| 221 | + :size-type="rejectImgs.uploadConfig.sizeType" | |
| 222 | + /> | |
| 223 | + </view> | |
| 224 | + </view> | |
| 225 | + </up-modal> | |
| 226 | + | |
| 227 | + <!-- 验收弹窗 up-modal(含图片上传) --> | |
| 228 | + <up-modal | |
| 229 | + :show="acceptModalShow" | |
| 230 | + title="验收" | |
| 231 | + :closeOnClickOverlay="false" | |
| 232 | + :showConfirmButton="true" | |
| 233 | + :showCancelButton="true" | |
| 234 | + @cancel="handleAcceptModalCancel" | |
| 235 | + @confirm="handleAcceptModalConfirm" | |
| 236 | + > | |
| 237 | + <view class="accept-modal-content"> | |
| 238 | + <!-- 第一行:单选框(通过/不通过,默认通过) --> | |
| 239 | + <view class="radio-group-wrap"> | |
| 240 | + <up-radio-group v-model="acceptRadioValue"> | |
| 241 | + <up-radio name="0" label="通过"></up-radio> | |
| 242 | + <up-radio name="1" label="不通过"></up-radio> | |
| 243 | + </up-radio-group> | |
| 244 | + </view> | |
| 245 | + | |
| 246 | + <!-- 第二行:必填textarea,最多200字 --> | |
| 247 | + <view class="textarea-wrap mt-30"> | |
| 248 | + <up-textarea | |
| 249 | + v-model.trim="acceptReason" | |
| 250 | + placeholder="请输入验收原因(必填,最多200字)" | |
| 251 | + :required="true" | |
| 252 | + maxlength="200" | |
| 253 | + rows="5" | |
| 254 | + count | |
| 255 | + /> | |
| 256 | + </view> | |
| 257 | + | |
| 258 | + <!-- 验收图片上传(选填,参考回退弹窗样式) --> | |
| 259 | + <view class="upload-wrap mt-20"> | |
| 260 | + <view class="upload-title">上传验收图片(选填)</view> | |
| 261 | + <up-upload | |
| 262 | + :file-list="acceptImgs.rawImgList.value || []" | |
| 263 | + @after-read="acceptImgs.uploadImgs" | |
| 264 | + @delete="acceptImgs.deleteImg" | |
| 265 | + | |
| 266 | + multiple | |
| 267 | + width="70" | |
| 268 | + height="70" | |
| 269 | + :max-count="acceptImgs.uploadConfig.maxCount" | |
| 270 | + :upload-text="acceptImgs.uploadConfig.uploadText" | |
| 271 | + :size-type="acceptImgs.uploadConfig.sizeType" | |
| 272 | + /> | |
| 273 | + </view> | |
| 274 | + </view> | |
| 275 | + </up-modal> | |
| 276 | + </view> | |
| 277 | +</template> | |
| 278 | + | |
| 279 | +<script setup> | |
| 280 | +import { ref, computed } from 'vue'; | |
| 281 | +import { onShow, onLoad } from '@dcloudio/uni-app'; | |
| 282 | +import { timeFormat } from '@/uni_modules/uview-plus'; | |
| 283 | +import { | |
| 284 | + myBuzSimplePage, | |
| 285 | + todoBuzSimplePage, | |
| 286 | + doneBuzSimplePage, | |
| 287 | + qyWorkorderCreate, | |
| 288 | + qyUniversalApproval, | |
| 289 | + daquUniversalApproval, | |
| 290 | + dcyUniversalApproval | |
| 291 | +} from '@/api/regional-order-manage/regional-order-manage' | |
| 292 | +// 从用户store获取角色信息 | |
| 293 | +import { useUserStore } from '@/pinia/user'; | |
| 294 | +import { nextStepMap, buzStatusMap } from '@/common/utils/common' | |
| 295 | +// 引入图片上传组合式函数(与参考页面一致) | |
| 296 | +import { useUploadImgs } from '@/common/utils/useUploadImgs' | |
| 297 | +// ========== 状态管理 ========== | |
| 298 | +const userStore = useUserStore(); | |
| 299 | +// 标签页切换 | |
| 300 | +const activeTab = ref(0); // 0-待办 1-我发起的 2-已办 | |
| 301 | +const tabList = ref([ | |
| 302 | + {name: '待办'}, | |
| 303 | + {name: '我发起的任务'}, | |
| 304 | + {name: '已办'} | |
| 305 | +]); | |
| 306 | +// 排序下拉框 | |
| 307 | +const selectedSortValue = ref(1); | |
| 308 | +const sortOptions = ref([ | |
| 309 | + {name: '位置', id: 1}, | |
| 310 | + {name: '名称', id: 2}, | |
| 311 | + {name: '描述', id: 3}, | |
| 312 | + {name: '编号', id: 4}, | |
| 313 | +]); | |
| 314 | +// 搜索 | |
| 315 | +const searchValue = ref(''); | |
| 316 | +// 分页 | |
| 317 | +const paging = ref(null); | |
| 318 | +const orderList = ref([]); | |
| 319 | +// 角色控制(巡查员显示新增按钮) | |
| 320 | +const isAi = computed(() => { | |
| 321 | + // patrol_global 全域巡查员 | |
| 322 | + // regional_manager 大区经理 | |
| 323 | + // AI_dispatcher AI工单派发人员 | |
| 324 | + // 增加可选链,避免用户信息不存在报错 | |
| 325 | + console.log('123') | |
| 326 | + console.log(!userStore.userInfo?.roles?.includes('AI_dispatcher')) | |
| 327 | + return !userStore.userInfo?.roles?.includes('AI_dispatcher') ; | |
| 328 | + // return true | |
| 329 | +}); | |
| 330 | +// 回退弹窗相关 | |
| 331 | +const rejectModalShow = ref(false); // 回退modal显示开关 | |
| 332 | +const rejectReason = ref(''); // 回退原因 | |
| 333 | +const currentRejectItem = ref(null); // 当前回退工单 | |
| 334 | +// 回退图片上传配置(与参考页面风格一致) | |
| 335 | +const rejectImgs = useUploadImgs({ | |
| 336 | + maxCount: 3, // 最多上传3张 | |
| 337 | + uploadText: '选择回退图片', // 自定义上传提示文字 | |
| 338 | + sizeType: ['compressed'], // 仅上传压缩图 | |
| 339 | + formRef: null, // 该弹窗无表单校验 | |
| 340 | + fieldName: 'rejectImgs' // 自定义字段名 | |
| 341 | +}) | |
| 342 | +// ========== 验收弹窗相关状态(含图片上传) ========== | |
| 343 | +const acceptModalShow = ref(false); // 验收弹窗显示开关 | |
| 344 | +const acceptRadioValue = ref('0'); // 单选框值,默认0(通过) | |
| 345 | +const acceptReason = ref(''); // 验收原因 | |
| 346 | +const currentAcceptItem = ref(null); // 当前验收的工单项 | |
| 347 | +// 验收图片上传配置(独立实例,参考回退弹窗) | |
| 348 | +const acceptImgs = useUploadImgs({ | |
| 349 | + maxCount: 3, // 最多上传3张,与回退弹窗一致 | |
| 350 | + uploadText: '选择验收图片', // 自定义上传提示文字 | |
| 351 | + sizeType: ['compressed'], // 仅上传压缩图,优化性能 | |
| 352 | + formRef: null, // 验收弹窗无表单校验 | |
| 353 | + fieldName: 'acceptImgs' // 自定义字段名,区分回退图片 | |
| 354 | +}) | |
| 355 | +// 分页查询列表 | |
| 356 | +const queryList = async (pageNo, pageSize) => { | |
| 357 | + try { | |
| 358 | + const apiParams = { | |
| 359 | + searchContent: searchValue.value.trim() || '', | |
| 360 | + pageNo, | |
| 361 | + pageSize, | |
| 362 | + type: selectedSortValue.value // 1-位置 2-工单名称 3-情况描述 4-工单编号 | |
| 363 | + }; | |
| 364 | + let res; | |
| 365 | + if (activeTab.value == 0) { | |
| 366 | + // 待办工单 | |
| 367 | + res = await todoBuzSimplePage(apiParams); | |
| 368 | + } else if (activeTab.value == 1) { | |
| 369 | + // 我发起的任务 | |
| 370 | + res = await myBuzSimplePage(apiParams); | |
| 371 | + } else { | |
| 372 | + // 已办工单 | |
| 373 | + res = await doneBuzSimplePage(apiParams); | |
| 374 | + } | |
| 375 | + // 适配z-paging分页 | |
| 376 | + paging.value.complete(res.list, res.total); | |
| 377 | + } catch (error) { | |
| 378 | + console.error('加载工单失败:', error); | |
| 379 | + paging.value?.complete(false); | |
| 380 | + uni.showToast({title: '加载失败,请重试', icon: 'none'}); | |
| 381 | + } | |
| 382 | +}; | |
| 383 | +// ========== 事件处理 ========== | |
| 384 | +// 标签页切换 | |
| 385 | +const handleTabChange = (item) => { | |
| 386 | + orderList.value = []; | |
| 387 | + console.log(item) | |
| 388 | + activeTab.value = item.index; | |
| 389 | + paging.value?.reload(); // 切换标签页刷新列表 | |
| 390 | +}; | |
| 391 | +// 排序变更 | |
| 392 | +const handleSortChange = (val) => { | |
| 393 | + selectedSortValue.value = val.id; | |
| 394 | + searchValue.value = ''; | |
| 395 | + paging.value?.reload(); // 排序变更刷新列表 | |
| 396 | +}; | |
| 397 | +// 搜索 | |
| 398 | +const handleSearch = (val) => { | |
| 399 | + searchValue.value = val; | |
| 400 | + paging.value?.reload(); // 搜索刷新列表 | |
| 401 | +}; | |
| 402 | +// 工单详情 | |
| 403 | +const handleDetail = (item) => { | |
| 404 | + // 0-待办 1我发起的- 2-已办 | |
| 405 | + uni.navigateTo({ | |
| 406 | + url: `/pages-sub/problem/regional-order-manage/order-detail?taskId=${item.taskId}&activeTab=${activeTab.value}&processInstanceId=${item.processInstanceId}`, | |
| 407 | + events: { | |
| 408 | + // 自定义事件名:needRefresh(与详情页保持一致) | |
| 409 | + needRefresh: () => { | |
| 410 | + console.log('详情页返回,触发工单列表刷新'); | |
| 411 | + if (paging.value) { | |
| 412 | + paging.value.reload(); // 刷新z-paging列表 | |
| 413 | + } | |
| 414 | + } | |
| 415 | + } | |
| 416 | + }); | |
| 417 | +}; | |
| 418 | +// 生成临时key | |
| 419 | +const generateTempKey = () => { | |
| 420 | + return 'renew_order_' + Date.now() + '_' + Math.floor(Math.random() * 10000); | |
| 421 | +}; | |
| 422 | +// 待办-重新提交工单(改造后:大数据存本地,仅传唯一标识) | |
| 423 | +const handleRenew = (item) => { | |
| 424 | + | |
| 425 | + // 1. 生成唯一临时标识 | |
| 426 | + const tempKey = generateTempKey(); | |
| 427 | + // 2. 将完整工单数据存入本地临时存储(同步存储,确保数据立即生效) | |
| 428 | + try { | |
| 429 | + console.log(item) | |
| 430 | + console.log('123') | |
| 431 | + uni.setStorageSync(tempKey, item); | |
| 432 | + } catch (error) { | |
| 433 | + console.error('存储工单数据失败:', error); | |
| 434 | + uni.showToast({title: '数据存储异常,无法重新提交', icon: 'none'}); | |
| 435 | + return; | |
| 436 | + } | |
| 437 | + | |
| 438 | + if (userStore.userInfo?.roles.includes('patrol_global')) { // 全域巡查员 | |
| 439 | + uni.navigateTo({ | |
| 440 | + url: `/pages-sub/problem/regional-order-manage/add-patrol-order?isRenew=1&tempKey=${tempKey}` | |
| 441 | + }); | |
| 442 | + } | |
| 443 | + if (userStore.userInfo?.roles.includes('regional_manager')) { // 大区经理 | |
| 444 | + uni.navigateTo({ | |
| 445 | + url: `/pages-sub/problem/regional-order-manage/add-order?isRenew=1&tempKey=${tempKey}` | |
| 446 | + }); | |
| 447 | + } | |
| 448 | + if (userStore.userInfo?.roles.includes('Inspector_global')) { // 督察员 | |
| 449 | + uni.navigateTo({ | |
| 450 | + url: `/pages-sub/problem/regional-order-manage/add-order?isRenew=1&tempKey=${tempKey}` | |
| 451 | + }); | |
| 452 | + } | |
| 453 | + // // 3. URL 仅传递「唯一标识」和「重新提交标记」(数据量极小,无长度问题) | |
| 454 | + // uni.navigateTo({ | |
| 455 | + // url: `/pages-sub/problem/regional-order-manage/add-patrol-order?isRenew=1&tempKey=${tempKey}` | |
| 456 | + // }); | |
| 457 | +}; | |
| 458 | +// 待办-处理工单 | |
| 459 | +const handleProcess = async (item) => { | |
| 460 | + console.log(nextStepMap[item.taskKey].name) | |
| 461 | + try { | |
| 462 | + if (nextStepMap[item.taskKey]?.name == '大区经理分配') { | |
| 463 | + // ① 生成唯一临时key(统一规则,避免冲突) | |
| 464 | + const tempKey = `distribute_order_${Date.now()}_${Math.floor(Math.random() * 10000)}`; | |
| 465 | + // ② 存储完整item到本地缓存(同步存储,确保立即生效) | |
| 466 | + try { | |
| 467 | + uni.setStorageSync(tempKey, item); | |
| 468 | + } catch (error) { | |
| 469 | + console.error('存储分配工单数据失败:', error); | |
| 470 | + uni.showToast({title: '数据存储异常,无法跳转', icon: 'none'}); | |
| 471 | + return; | |
| 472 | + } | |
| 473 | + // ③ URL仅传递临时key,无其他冗余参数 | |
| 474 | + uni.navigateTo({ | |
| 475 | + url: `/pages-sub/problem/regional-order-manage/distribution-order?tempKey=${tempKey}` | |
| 476 | + }) | |
| 477 | + } | |
| 478 | + if (nextStepMap[item.taskKey]?.name == '督察员单子大区经理分配') { | |
| 479 | + let postData = { | |
| 480 | + "taskKey":item.taskKey, | |
| 481 | + "taskId": item.taskId, | |
| 482 | + "operateType":60, | |
| 483 | + "workerDataId":item.id, | |
| 484 | + "agree":0, | |
| 485 | + "reason":item.remark, | |
| 486 | + "roadId":item.roadId, | |
| 487 | + "roadName":item.roadName, | |
| 488 | + "pressingType":item.pressingType, | |
| 489 | + "orderName":item.orderName, | |
| 490 | + "expectedFinishDate": item.expectedFinishDate, | |
| 491 | + "busiLine":item.busiLine, | |
| 492 | + } | |
| 493 | + const res = await dcyUniversalApproval(postData); | |
| 494 | + uni.showToast({title: '分配成功', icon: 'success', duration: 1000}); | |
| 495 | + paging.value?.reload(); // 刷新列表 | |
| 496 | + } | |
| 497 | + | |
| 498 | + | |
| 499 | + // 验收 - 打开弹窗 | |
| 500 | + if (nextStepMap[item.taskKey]?.name == '巡查员验收' || nextStepMap[item.taskKey]?.name == '养护组长验收') { | |
| 501 | + currentAcceptItem.value = item; // 存储当前工单信息 | |
| 502 | + acceptReason.value = ''; // 清空上次的验收原因 | |
| 503 | + acceptRadioValue.value = '0'; // 重置默认选中“通过” | |
| 504 | + acceptModalShow.value = true; // 显示验收弹窗 | |
| 505 | + } | |
| 506 | + | |
| 507 | + // 发起人确认 | |
| 508 | + if (nextStepMap[item.taskKey]?.name == '发起人确认') { | |
| 509 | + console.log(item) | |
| 510 | + uni.showModal({ | |
| 511 | + title: "结束工单", | |
| 512 | + content: "请确定是否结束工单?", | |
| 513 | + success: async function (res) { | |
| 514 | + if (res.confirm) { | |
| 515 | + // 构建请求参数 | |
| 516 | + const requestData = { | |
| 517 | + | |
| 518 | + "workerDataId": item.id, | |
| 519 | + "taskKey": 'ylInspectorStart', | |
| 520 | + "taskId": item.taskId, | |
| 521 | + "operateType": 200, | |
| 522 | + "agree": 1, | |
| 523 | + "reason": '结束工单' | |
| 524 | + }; | |
| 525 | + // 调用回退工单接口 daquUniversalApproval | |
| 526 | + | |
| 527 | + if( userStore.userInfo.roles.includes('regional_manager')){ // 大区经理 | |
| 528 | + await daquUniversalApproval(requestData) | |
| 529 | + } | |
| 530 | + if( userStore.userInfo.roles.includes('Inspector_global')){ // 督察员 | |
| 531 | + await dcyUniversalApproval(requestData); | |
| 532 | + } | |
| 533 | + if( userStore.userInfo.roles.includes('patrol_global')){ // 全域巡查员 | |
| 534 | + await qyUniversalApproval(requestData); | |
| 535 | + } | |
| 536 | + | |
| 537 | + uni.showToast({title: '结束成功', icon: 'success', duration: 1000}); | |
| 538 | + rejectModalShow.value = false; | |
| 539 | + paging.value?.reload(); // 刷新列表 | |
| 540 | + } else if (res.cancel) { | |
| 541 | + console.log("用户点击取消"); | |
| 542 | + } | |
| 543 | + }, | |
| 544 | + }); | |
| 545 | + } | |
| 546 | + } catch (error) { | |
| 547 | + console.error('处理工单失败:', error); | |
| 548 | + uni.showToast({title: '处理失败,请重试', icon: 'none'}); | |
| 549 | + } | |
| 550 | +}; | |
| 551 | +// 待办-回退工单(打开回退modal) | |
| 552 | +const handleReject = (item) => { | |
| 553 | + console.log('123213') | |
| 554 | + // 校验工单有效性 | |
| 555 | + if (!item || !item.id) { | |
| 556 | + uni.showToast({title: '工单信息异常,无法回退', icon: 'none'}); | |
| 557 | + return; | |
| 558 | + } | |
| 559 | + currentRejectItem.value = item; | |
| 560 | + rejectReason.value = ''; // 清空上次输入 | |
| 561 | + rejectImgs.clearImgs(); // 改造后:使用组合式函数的清空方法 | |
| 562 | + rejectModalShow.value = true; // 显示回退modal | |
| 563 | +}; | |
| 564 | +// 回退modal - 取消按钮 | |
| 565 | +const handleRejectModalCancel = () => { | |
| 566 | + rejectModalShow.value = false; | |
| 567 | + rejectReason.value = ''; | |
| 568 | + rejectImgs.clearImgs(); // 改造后:使用组合式函数的清空方法 | |
| 569 | +}; | |
| 570 | +// 确认回退工单 | |
| 571 | +const confirmReject = async () => { | |
| 572 | + // 严格校验回退原因(去除首尾空格) | |
| 573 | + const rejectReasonTrim = rejectReason.value.trim(); | |
| 574 | + if (!rejectReasonTrim) { | |
| 575 | + uni.showToast({title: '请填写回退原因', icon: 'none', duration: 1000}); | |
| 576 | + return; | |
| 577 | + } | |
| 578 | + // 校验当前工单有效性 | |
| 579 | + if (!currentRejectItem.value || !currentRejectItem.value.id) { | |
| 580 | + uni.showToast({title: '工单信息异常,无法提交', icon: 'none', duration: 1000}); | |
| 581 | + rejectModalShow.value = false; | |
| 582 | + return; | |
| 583 | + } | |
| 584 | + try { | |
| 585 | + // 显示加载中,防止重复提交 | |
| 586 | + uni.showLoading({title: '提交中...', mask: true}); | |
| 587 | + // 构建请求参数 | |
| 588 | + const requestData = { | |
| 589 | + "returnImgs": rejectImgs.getSuccessImgUrls(), // 改造后:获取上传成功的图片URL数组 | |
| 590 | + "workerDataId": currentRejectItem.value.id, | |
| 591 | + "taskKey": currentRejectItem.value.taskKey, | |
| 592 | + "taskId": currentRejectItem.value.taskId, | |
| 593 | + | |
| 594 | + "operateType": nextStepMap[currentRejectItem.value.taskKey].operateTypeNoPass, | |
| 595 | + "agree": 1, | |
| 596 | + "reason": rejectReasonTrim | |
| 597 | + }; | |
| 598 | + // 调用回退工单接口 | |
| 599 | + if(currentRejectItem.value.taskKey=='shRegionManager'){ // 对督察员单子 回退 | |
| 600 | + const res = await dcyUniversalApproval(requestData); | |
| 601 | + } | |
| 602 | + if(currentRejectItem.value.taskKey=='regionManager'){ // 对全域巡查员单子 回退 | |
| 603 | + const res = await qyUniversalApproval(requestData); | |
| 604 | + } | |
| 605 | + // 对大区经理单子 回退 | |
| 606 | + uni.showToast({title: '回退成功', icon: 'success', duration: 1000}); | |
| 607 | + rejectModalShow.value = false; | |
| 608 | + paging.value?.reload(); // 刷新列表 | |
| 609 | + } catch (error) { | |
| 610 | + console.error('回退工单失败:', error); | |
| 611 | + uni.showToast({title: '网络异常,回退失败', icon: 'none', duration: 1000}); | |
| 612 | + } finally { | |
| 613 | + // 隐藏加载中 | |
| 614 | + uni.hideLoading(); | |
| 615 | + } | |
| 616 | +}; | |
| 617 | +// 新增工单 | |
| 618 | +const handleAddOrder = () => { | |
| 619 | + if (userStore.userInfo?.roles.includes('patrol_global')) { // 全域巡查员 | |
| 620 | + uni.navigateTo({ | |
| 621 | + url: '/pages-sub/problem/regional-order-manage/add-patrol-order' | |
| 622 | + }); | |
| 623 | + } | |
| 624 | + if (userStore.userInfo?.roles.includes('regional_manager')) { // 大区经理 | |
| 625 | + uni.navigateTo({ | |
| 626 | + url: '/pages-sub/problem/regional-order-manage/add-order' | |
| 627 | + }); | |
| 628 | + } | |
| 629 | + if (userStore.userInfo?.roles.includes('Inspector_global')) { // 督察员 | |
| 630 | + uni.navigateTo({ | |
| 631 | + url: '/pages-sub/problem/regional-order-manage/add-order' | |
| 632 | + }); | |
| 633 | + } | |
| 634 | +}; | |
| 635 | +// 验收弹窗 - 取消按钮(清空状态) | |
| 636 | +const handleAcceptModalCancel = () => { | |
| 637 | + acceptModalShow.value = false; | |
| 638 | + acceptReason.value = ''; // 清空验收原因 | |
| 639 | + acceptRadioValue.value = '0'; // 重置单选框为“通过” | |
| 640 | + acceptImgs.clearImgs(); // 清空验收图片 | |
| 641 | +}; | |
| 642 | +// 验收弹窗 - 确定按钮(含returnImgs传参) | |
| 643 | +const handleAcceptModalConfirm = async () => { | |
| 644 | + // 1. 校验验收原因是否为空 | |
| 645 | + if (!acceptReason.value.trim()) { | |
| 646 | + uni.showToast({title: '请填写验收原因', icon: 'none', duration: 1000}); | |
| 647 | + return; | |
| 648 | + } | |
| 649 | + // 2. 校验验收原因长度 | |
| 650 | + if (acceptReason.value.length > 200) { | |
| 651 | + uni.showToast({title: '验收原因最多200字', icon: 'none', duration: 1000}); | |
| 652 | + return; | |
| 653 | + } | |
| 654 | + try { | |
| 655 | + // 3. 构建请求参数(含returnImgs) | |
| 656 | + console.log(currentAcceptItem.value) | |
| 657 | + console.log( userStore.userInfo.roles) | |
| 658 | + console.log( userStore.userInfo.roles.includes('Inspector_global')) | |
| 659 | + // | |
| 660 | + if( userStore.userInfo.roles.includes('regional_manager')){ // 大区经理验收 | |
| 661 | + let postData = { | |
| 662 | + "returnImgs": acceptImgs.getSuccessImgUrls(), // 验收图片URL数组 | |
| 663 | + "taskKey": currentAcceptItem.value.taskKey, | |
| 664 | + "workerDataId": currentAcceptItem.value.id, | |
| 665 | + "taskId": currentAcceptItem.value.taskId, | |
| 666 | + "operateType": acceptRadioValue.value == 0 ? nextStepMap[currentAcceptItem.value.taskKey].operateTypePass : nextStepMap[currentAcceptItem.value.taskKey].operateTypeNoPass, | |
| 667 | + "reason": acceptReason.value.trim(), | |
| 668 | + "agree":acceptRadioValue.value, | |
| 669 | + } | |
| 670 | + await daquUniversalApproval(postData); | |
| 671 | + } | |
| 672 | + // | |
| 673 | + if( userStore.userInfo.roles.includes('patrol_global')){ // 全域巡查员验收 | |
| 674 | + let postData = { | |
| 675 | + "returnImgs": acceptImgs.getSuccessImgUrls(), // 验收图片URL数组 | |
| 676 | + "taskKey": currentAcceptItem.value.taskKey, | |
| 677 | + "taskId": currentAcceptItem.value.taskId, | |
| 678 | + "workerDataId": currentAcceptItem.value.id, | |
| 679 | + "operateType": acceptRadioValue.value == 0 ? nextStepMap[currentAcceptItem.value.taskKey].operateTypePass : nextStepMap[currentAcceptItem.value.taskKey].operateTypeNoPass, | |
| 680 | + "reason": acceptReason.value.trim(), | |
| 681 | + "agree": acceptRadioValue.value | |
| 682 | + } | |
| 683 | + await qyUniversalApproval(postData); | |
| 684 | + } | |
| 685 | + // | |
| 686 | + if( userStore.userInfo.roles.includes('Inspector_global')){ // 督察员验收 | |
| 687 | + let postData = { | |
| 688 | + "returnImgs": acceptImgs.getSuccessImgUrls(), // 验收图片URL数组 | |
| 689 | + "taskKey": currentAcceptItem.value.taskKey, | |
| 690 | + "taskId": currentAcceptItem.value.taskId, | |
| 691 | + "workerDataId": currentAcceptItem.value.id, | |
| 692 | + "operateType": acceptRadioValue.value == 0 ? nextStepMap[currentAcceptItem.value.taskKey].operateTypePass : nextStepMap[currentAcceptItem.value.taskKey].operateTypeNoPass, | |
| 693 | + "reason": acceptReason.value.trim(), | |
| 694 | + "agree": acceptRadioValue.value | |
| 695 | + } | |
| 696 | + await dcyUniversalApproval(postData); | |
| 697 | + } | |
| 698 | + | |
| 699 | + // 4. 操作成功处理 | |
| 700 | + uni.showToast({title: '提交成功', icon: 'success', duration: 1000}); | |
| 701 | + handleAcceptModalCancel(); // 清空状态 | |
| 702 | + paging.value?.reload(); // 刷新工单列表 | |
| 703 | + } catch (error) { | |
| 704 | + // 5. 操作失败处理 | |
| 705 | + console.error('验收失败:', error); | |
| 706 | + uni.showToast({title: '验收提交失败,请重试', icon: 'none', duration: 1000}); | |
| 707 | + } | |
| 708 | +}; | |
| 709 | +// 页面初始化 | |
| 710 | +onLoad(() => { | |
| 711 | + // 初始化加载列表 | |
| 712 | + paging.value?.reload(); | |
| 713 | +}); | |
| 714 | +</script> | |
| 715 | + | |
| 716 | +<style scoped lang="scss"> | |
| 717 | +.page-container { | |
| 718 | + min-height: 100vh; | |
| 719 | + background-color: #fafafa; | |
| 720 | +} | |
| 721 | + | |
| 722 | +// 顶部固定区域 | |
| 723 | +.header-wrap { | |
| 724 | + background-color: #fff; | |
| 725 | +} | |
| 726 | + | |
| 727 | +// 搜索栏样式 | |
| 728 | +.search-header { | |
| 729 | + display: flex; | |
| 730 | + align-items: center; | |
| 731 | + padding: 20rpx; | |
| 732 | + box-sizing: border-box; | |
| 733 | + | |
| 734 | + .select-wrap { | |
| 735 | + width: 120rpx; | |
| 736 | + margin-right: 20rpx; | |
| 737 | + | |
| 738 | + :deep(.u-select) { | |
| 739 | + width: 100%; | |
| 740 | + font-size: 28rpx; | |
| 741 | + } | |
| 742 | + | |
| 743 | + :deep(.u-input__placeholder) { | |
| 744 | + font-size: 28rpx; | |
| 745 | + } | |
| 746 | + } | |
| 747 | + | |
| 748 | + .search-input-wrap { | |
| 749 | + flex: 1; | |
| 750 | + } | |
| 751 | +} | |
| 752 | + | |
| 753 | +// 工单卡片样式 | |
| 754 | +.order-card { | |
| 755 | + margin: 0 20rpx 20rpx; | |
| 756 | + background: #fff; | |
| 757 | + border-radius: 12rpx; | |
| 758 | + box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04); | |
| 759 | +} | |
| 760 | + | |
| 761 | +.card-body { | |
| 762 | + | |
| 763 | +} | |
| 764 | + | |
| 765 | +// 回退modal样式 | |
| 766 | +.reject-modal-content { | |
| 767 | + width: 100%; | |
| 768 | + box-sizing: border-box; | |
| 769 | + padding: 10rpx 0; | |
| 770 | +} | |
| 771 | + | |
| 772 | +.textarea-label { | |
| 773 | + font-size: 28rpx; | |
| 774 | + color: #333; | |
| 775 | + margin-bottom: 10rpx; | |
| 776 | + | |
| 777 | + .required-mark { | |
| 778 | + color: #f56c6c; | |
| 779 | + margin-left: 4rpx; | |
| 780 | + } | |
| 781 | +} | |
| 782 | + | |
| 783 | +.upload-wrap { | |
| 784 | + margin-top: 20rpx; | |
| 785 | + | |
| 786 | + .upload-title { | |
| 787 | + font-size: 28rpx; | |
| 788 | + color: #333; | |
| 789 | + margin-bottom: 10rpx; | |
| 790 | + } | |
| 791 | +} | |
| 792 | + | |
| 793 | +.mt-20 { | |
| 794 | + margin-top: 20rpx; | |
| 795 | +} | |
| 796 | + | |
| 797 | +.mt-30 { | |
| 798 | + margin-top: 30rpx; | |
| 799 | +} | |
| 800 | + | |
| 801 | +// 养护组长验收弹窗样式 | |
| 802 | +.accept-modal-content { | |
| 803 | + width: 100%; | |
| 804 | + box-sizing: border-box; | |
| 805 | +} | |
| 806 | + | |
| 807 | +.radio-group-wrap { | |
| 808 | + display: flex; | |
| 809 | + align-items: center; | |
| 810 | + gap: 40rpx; // 单选框之间的间距 | |
| 811 | + font-size: 28rpx; | |
| 812 | + margin-bottom: 20rpx; | |
| 813 | +} | |
| 814 | + | |
| 815 | +.textarea-wrap { | |
| 816 | + width: 100%; | |
| 817 | + margin-top: 30rpx; | |
| 818 | +} | |
| 819 | + | |
| 820 | +.modal-btn-wrap { | |
| 821 | + display: flex; | |
| 822 | + align-items: center; | |
| 823 | + justify-content: flex-end; | |
| 824 | + padding-right: 10rpx; | |
| 825 | +} | |
| 826 | +</style> | |
| 0 | 827 | \ No newline at end of file | ... | ... |
pages-sub/problem/regional-order-manage/index.vue
| ... | ... | @@ -179,7 +179,7 @@ |
| 179 | 179 | <!-- </up-button>--> |
| 180 | 180 | <!-- </view>--> |
| 181 | 181 | |
| 182 | - <view class="fixed-bottom-btn-wrap" v-if="isInspector"> | |
| 182 | + <view class="fixed-bottom-btn-wrap" v-if="isAi"> | |
| 183 | 183 | <up-button type="primary" size="large" @click="handleAddOrder"> |
| 184 | 184 | 新增工单 |
| 185 | 185 | </up-button> |
| ... | ... | @@ -277,7 +277,7 @@ |
| 277 | 277 | </template> |
| 278 | 278 | |
| 279 | 279 | <script setup> |
| 280 | -import { ref, computed, watch } from 'vue'; | |
| 280 | +import { ref, computed } from 'vue'; | |
| 281 | 281 | import { onShow, onLoad } from '@dcloudio/uni-app'; |
| 282 | 282 | import { timeFormat } from '@/uni_modules/uview-plus'; |
| 283 | 283 | import { |
| ... | ... | @@ -317,12 +317,15 @@ const searchValue = ref(''); |
| 317 | 317 | const paging = ref(null); |
| 318 | 318 | const orderList = ref([]); |
| 319 | 319 | // 角色控制(巡查员显示新增按钮) |
| 320 | -const isInspector = computed(() => { | |
| 320 | +const isAi = computed(() => { | |
| 321 | 321 | // patrol_global 全域巡查员 |
| 322 | 322 | // regional_manager 大区经理 |
| 323 | + // AI_dispatcher AI工单派发人员 | |
| 323 | 324 | // 增加可选链,避免用户信息不存在报错 |
| 324 | - // return userStore.userInfo?.roles?.includes('yl_inspector') || false; | |
| 325 | - return true | |
| 325 | + console.log('123') | |
| 326 | + console.log(!userStore.userInfo?.roles?.includes('AI_dispatcher')) | |
| 327 | + return !userStore.userInfo?.roles?.includes('AI_dispatcher') ; | |
| 328 | + // return true | |
| 326 | 329 | }); |
| 327 | 330 | // 回退弹窗相关 |
| 328 | 331 | const rejectModalShow = ref(false); // 回退modal显示开关 | ... | ... |
pages.json