Commit 6e9f0396eec87d6d793579da151bbfb885e0d21e

Authored by 刘淇
1 parent 7adb99f0

全域督察员

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(&#39;&#39;);
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
... ... @@ -172,6 +172,10 @@
172 172 {
173 173 "path": "regional-order-manage/order-detail",
174 174 "style": { "navigationBarTitleText": "工单详情" }
  175 + },
  176 + {
  177 + "path": "ai-manage/index",
  178 + "style": { "navigationBarTitleText": "ai工单" }
175 179 }
176 180 ]
177 181 },
... ...