Commit fa775c6bedce7b56103ee2175632f2c5f1a15abd

Authored by 刘淇
1 parent 2764b83e

养护计划调整

api/work-order-manage/work-order-manage.js 0 → 100644
  1 +import { post, get, put } from '@/common/utils/request';
  2 +
  3 +// /app-api/bpm/garden/workorder/getApprovalDetail 获得审批详情
  4 +
  5 +
  6 +// /app-api/bpm/garden/workorder/approve 验收通过调用此接口、巡查员结束工单也调用此接口
  7 +// /app-api/bpm/garden/workorder/returnPreviousNode 不通过和退回都使用此接口
  8 +
  9 +
  10 +/**
  11 + * 养护员工单实施页面提交接口
  12 + * @returns {Promise}
  13 + */
  14 +export const ylWorkerExcuteWOrder = (params) => {
  15 + return put('/app-api/bpm/garden/workorder/ylWorkerExcuteWOrder',params);
  16 +};
  17 +
  18 +/**
  19 + * 获得园林养护员列表、共同处理人也调用此接口
  20 + * @returns {Promise}
  21 + */
  22 +export const getYlWorkersPage = (params) => {
  23 + return get('/app-api/bpm/garden/workorder/getYlWorkersPage',params);
  24 +};
  25 +
  26 +/**
  27 + * 养护组长分配工单调用此接口
  28 + * @returns {Promise}
  29 + */
  30 +export const ylTeamLeaderAssignWOrder = (params) => {
  31 + return put('/app-api/bpm/garden/workorder/ylTeamLeaderAssignWOrder',params);
  32 +};
  33 +
  34 +
  35 +/**
  36 + * 我发起的列表-工单详情
  37 + * @returns {Promise}
  38 + */
  39 +export const getMyTaskDetail = (params) => {
  40 + return get('/app-api/bpm/garden/workorder/getMyTaskDetail',params);
  41 +};
  42 +
  43 +
  44 +/**
  45 + * 已办列表-工单详情
  46 + * @returns {Promise}
  47 + */
  48 +export const getDoneTaskDetail = (params) => {
  49 + return get('/app-api/bpm/garden/workorder/getDoneTaskDetail',params);
  50 +};
  51 +
  52 +/**
  53 + * 待办列表-工单详情
  54 + * @returns {Promise}
  55 + */
  56 +export const getTodoTaskDetail = (params) => {
  57 + return get('/app-api/bpm/garden/workorder/getTodoTaskDetail',params);
  58 +};
  59 +
  60 +
  61 +/**
  62 + * 我发起的列表
  63 + * @returns {Promise}
  64 + */
  65 +export const myBuzSimplePage = (params) => {
  66 + return get('/app-api/bpm/garden/workorder/myBuzSimplePage',params);
  67 +};
  68 +
  69 +/**
  70 + * 已办汇总
  71 + * @returns {Promise}
  72 + */
  73 +export const doneBuzSimplePage = (params) => {
  74 + return get('/app-api/bpm/garden/workorder/doneBuzSimplePage',params);
  75 +};
  76 +
  77 +
  78 +
  79 +/**
  80 + * 待办汇总
  81 + * @returns {Promise}
  82 + */
  83 +export const todoBuzSimplePage = (params) => {
  84 + return get('/app-api/bpm/garden/workorder/todoBuzSimplePage',params);
  85 +};
  86 +
  87 +/**
  88 + * 问题工单创建
  89 + * @returns {Promise}
  90 + */
  91 +export const workorderCreate = (data) => {
  92 + return post('/app-api/bpm/garden/workorder/create',data);
  93 +};
... ...
pages-sub/daily/maintain-manage/add-record.vue
... ... @@ -7,9 +7,9 @@
7 7 ref="inspectFormRef"
8 8 labelWidth="140rpx"
9 9 >
10   - <!-- 1. 巡查描述(文本域) -->
  10 + <!-- 1. 养护描述(文本域) -->
11 11 <up-form-item
12   - prop="content"
  12 + prop="remark"
13 13 class="form-item"
14 14 >
15 15 <up-textarea
... ... @@ -148,7 +148,7 @@ export default {
148 148 // this.initProgress = option.finishPercent ? Number(option.finishPercent)+1 : 0
149 149 // // 关键修复:初始进度值设为 初始进度+1,避免刚进入就触发校验失败
150 150 // this.inspectForm.progress = this.initProgress
151   - console.log('初始进度值:', this.initProgress)
  151 +
152 152 },
153 153 onReady() {
154 154 this.$refs.inspectFormRef.setRules(this.inspectFormRules)
... ... @@ -284,7 +284,6 @@ export default {
284 284 console.log('图片列表:', this.imagesList)
285 285  
286 286 const submitData = {
287   - totalFinishPercent: 100,
288 287 "planNo": this.paramsOptins.planNo,
289 288 "imgHost": "1",
290 289 "beginImg": this.getImgUrlList(this.imagesList),
... ...
pages-sub/daily/maintain-manage/index.vue
... ... @@ -151,8 +151,8 @@
151 151 </view>
152 152  
153 153 <view class="u-body-item u-flex">
154   - <view class="u-body-item-title">已完成比例:</view>
155   - <view class="u-line-1 u-body-value">{{ item.finishPercent || 0 }}%</view>
  154 + <view class="u-body-item-title">已完成次数:</view>
  155 + <view class="u-line-1 u-body-value">{{ item.planFinishNum || 0 }}</view>
156 156 </view>
157 157  
158 158 <view class="u-body-item u-flex">
... ... @@ -181,7 +181,8 @@ const typeTabs = ref([])
181 181 const statusTabs = ref([
182 182 { name: '待完成', id: '1' },
183 183 { name: '已失效', id: '3' },
184   - { name: '已完成', id: '2' }
  184 + { name: '已完成', id: '2' },
  185 + { name: '已终止', id: '4' }
185 186 ])
186 187  
187 188 // 核心响应式数据
... ... @@ -303,13 +304,13 @@ const goToDetail = (item) =&gt; {
303 304 // 提交记录
304 305 const submitRecord = (item) => {
305 306 console.log('提交记录:', item)
306   - if (item.finishPercent == 0) { // 去新增
  307 + if (item.planFinishNum == 0) { // 去新增
307 308 uni.navigateTo({
308   - url: `/pages-sub/daily/maintain-manage/add-record?finishState=${item.finishState}&planNo=${item.planNo}&finishPercent=${item.finishPercent}`
  309 + url: `/pages-sub/daily/maintain-manage/add-record?finishState=${item.finishState}&planNo=${item.planNo}`
309 310 })
310 311 } else {
311 312 uni.navigateTo({
312   - url: `/pages-sub/daily/maintain-manage/pending-plan-detail?finishState=${item.finishState}&planNo=${item.planNo}&finishPercent=${item.finishPercent}&planTypeId=${item.planTypeId}`
  313 + url: `/pages-sub/daily/maintain-manage/pending-plan-detail?finishState=${item.finishState}&planNo=${item.planNo}&planTypeId=${item.planTypeId}`
313 314 })
314 315 }
315 316  
... ...
pages-sub/daily/maintain-manage/pending-plan-detail.vue
... ... @@ -93,14 +93,12 @@ const batchNo = ref(&#39;&#39;)
93 93 const planNo = ref('')
94 94 const finishState = ref('')
95 95 const planTypeId = ref('')
96   -const finishPercent = ref('')
97 96  
98 97 // 页面加载接收参数(逻辑完全保留)
99 98 onLoad((options) => {
100 99 planNo.value = options.planNo;
101 100 finishState.value = options.finishState
102 101 planTypeId.value = options.planTypeId
103   - finishPercent.value = options.finishPercent
104 102 });
105 103  
106 104 // 页面显示时请求数据(逻辑完全保留)
... ... @@ -138,7 +136,7 @@ const gotoFinishPlanDetail = (i) =&gt; {
138 136 // 新增记录(逻辑完全保留)
139 137 const addNewRecord = () => {
140 138 uni.navigateTo({
141   - url: `/pages-sub/daily/maintain-manage/add-record?planNo=${planNo.value}&finishPercent=${finishPercent.value}`,
  139 + url: `/pages-sub/daily/maintain-manage/add-record?planNo=${planNo.value}`,
142 140 });
143 141 };
144 142 </script>
... ...
pages-sub/daily/maintain-manage/road-detail-list.vue
... ... @@ -114,10 +114,10 @@
114 114 </view>
115 115 </view>
116 116  
117   -<!-- <view class="u-body-item u-flex">-->
118   -<!-- <view class="u-body-item-title">已完成比例:</view>-->
119   -<!-- <view class="u-line-1 u-body-value">{{ item.finishPercent || 0 }}%</view>-->
120   -<!-- </view>-->
  117 + <view class="u-body-item u-flex">
  118 + <view class="u-body-item-title">完成次数:</view>
  119 + <view class="u-line-1 u-body-value">{{ item.planFinishNum || 0 }}</view>
  120 + </view>
121 121  
122 122 <view class="u-body-item u-flex">
123 123 <view class="u-body-item-title">计划有效期:</view>
... ... @@ -142,7 +142,8 @@ import { getRoadDetails } from &quot;@/api/maintain-manage/maintain-manage&quot;;
142 142 const statusTabs = ref([
143 143 {name: '待完成', id: '1'},
144 144 {name: '已失效', id: '3'},
145   - {name: '已完成', id: '2'}
  145 + {name: '已完成', id: '2'},
  146 + { name: '已终止', id: '4' }
146 147 ])
147 148 const activeStatus = ref('1')
148 149 const searchValue = ref('')
... ... @@ -179,14 +180,14 @@ const submitRecord = (item) =&gt; {
179 180 if (item.finishState === '3') {
180 181 return
181 182 }
182   - console.log('提交记录:', item.finishPercent)
183   - if (item.finishPercent == 0) {
  183 + console.log('提交记录:', item.planFinishNum)
  184 + if (item.planFinishNum == 0) {
184 185 uni.navigateTo({
185   - url: `/pages-sub/daily/maintain-manage/add-record?finishState=${item.finishState}&planNo=${item.planNo}&finishPercent=${item.finishPercent}`
  186 + url: `/pages-sub/daily/maintain-manage/add-record?finishState=${item.finishState}&planNo=${item.planNo}`
186 187 })
187 188 } else {
188 189 uni.navigateTo({
189   - url: `/pages-sub/daily/maintain-manage/pending-plan-detail?finishState=${item.finishState}&planNo=${item.planNo}&finishPercent=${item.finishPercent}&planTypeId=${item.planTypeId}`
  190 + url: `/pages-sub/daily/maintain-manage/pending-plan-detail?finishState=${item.finishState}&planNo=${item.planNo}&planTypeId=${item.planTypeId}`
190 191 })
191 192 }
192 193 }
... ...
pages-sub/daily/patrol-manage/add-patrol-record.vue
... ... @@ -12,9 +12,10 @@
12 12 <up-form-item
13 13 prop="content"
14 14 class="form-item"
  15 + required
15 16 >
16 17 <up-textarea
17   - v-model="inspectForm.content"
  18 + v-model.trim="inspectForm.content"
18 19 placeholder="请输入巡查描述"
19 20 maxlength="200"
20 21 count
... ... @@ -102,13 +103,13 @@ export default {
102 103 imagesList: [],
103 104 // 单选列表
104 105 radioList: [
105   - { label: '是', value: '2' },
106   - { label: '否', value: '1' }
  106 + { label: '否', value: '1' },
  107 + { label: '是', value: '2' }
107 108 ],
108 109 // 巡查表单数据
109 110 inspectForm: {
110 111 content: '', // 巡查描述
111   - isWorkOrder: '2' // 是否转为工单 1:否(默认) 2:是
  112 + isWorkOrder: '1' // 是否转为工单 1:否(默认) 2:是
112 113 },
113 114 paramsOptins:{},//接受参数
114 115 // 表单校验规则
... ... @@ -133,6 +134,10 @@ export default {
133 134 }
134 135 }
135 136 ],
  137 +
  138 + content: [
  139 + { type: 'string', required: true, message: '请输入工单描述', trigger: ['change'] }
  140 + ],
136 141 isWorkOrder: [
137 142 { type: 'string', required: true, message: '请选择是否转为工单', trigger: ['change'] }
138 143 ]
... ... @@ -268,7 +273,7 @@ export default {
268 273 "inspectionState": this.inspectForm.isWorkOrder,
269 274 "transState": this.inspectForm.isWorkOrder==1?'1':'2',
270 275 "transWorkNo": "default'",
271   - "remark": this.inspectForm.content
  276 + "remark": this.inspectForm.content.trim()
272 277 }
273 278  
274 279 // 显示加载中
... ...
pages-sub/daily/patrol-manage/finish-plan-detail.vue
... ... @@ -9,91 +9,98 @@
9 9 ></up-loading-page>
10 10  
11 11 <!-- 内容容器 -->
12   - <view v-else class="content-wrap" v-for="(i, index) in orderDetail" :key="index">
13   - <template >
14   - <!-- 工单详情内容 -->
15   - <up-cell-group :border="false" inset >
16   - <!-- 1. 工单名称 -->
17   - <up-cell
18   - align="middle"
19   - >
20   - <template #title>
21   - <view class="up-line-1">{{i.planName || '--'}}</view>
22   - </template>
23   -<!-- <template #value>-->
24   -<!-- <view class="up-line-1">{{orderDetail.planName || '&#45;&#45;'}}</view>-->
25   -<!-- </template>-->
26   - </up-cell>
27   -
28   - <!-- 2. 工单位置 -->
29   - <up-cell
30   - title="计划编码"
31   - :value="i.planNo || '--'"
32   - align="middle"
33   - ></up-cell>
34   -
35   - <!-- 3. 工单名称 -->
36   - <up-cell
37   - title="养护周期"
38   - :value="`${i.rate}${uni.$dict.getDictLabel('cycle_id_type', i.cycleId)}`"
39   - align="middle"
40   - ></up-cell>
41   -
42   - <!-- 4. 情况描述 -->
43   - <up-cell
44   - title="计划有效期"
45   - :value="`${timeFormat(i.beginTime,'yyyy-mm-dd')} 至 ${timeFormat(i. endTime,'yyyy-mm-dd')}`"
46   - align="middle"
47   - ></up-cell>
48   -
49   - <!-- 5. 问题照片(核心修复:判断条件+空值处理) -->
50   - <up-cell title="照片">
51   - <template #value>
52   - <view class="cell-content-wrap">
53   -
54   - <!-- 修复1:正确判断problemImgsList,补充空数组默认值 -->
55   - <up-album
56   - v-if="!!i.imgList?.length"
57   - :urls="i.imgList || []"
58   - singleSize="70"
59   - :preview-full-image="true"
60   -
61   - ></up-album>
62   - <text v-else class="empty-text">暂无问题照片</text>
63   - </view>
64   - </template>
65   - </up-cell>
66   -
67   - <!-- 7. 处理结果 -->
68   - <up-cell
69   - align="middle"
70   - >
71   - <template #title>
72   - <view style="min-width: 200rpx">巡查描述</view>
73   - </template>
74   - <template #value>
75   - <view class="up-line-1 common-text-color">{{i.remark || '--'}}</view>
76   - </template>
77   - </up-cell>
78   -
79   - <up-cell
80   - title="提交时间"
81   - :value="timeFormat(i.finishTime,'yyyy-mm-dd hh:MM:ss') || '--'"
82   - align="middle"
83   -
84   - ></up-cell>
85   -
86   - <up-cell
87   - title="提交人"
88   - :value="i.userName || '--'"
89   - align="middle"
90   - :border="false"
91   - ></up-cell>
92   - </up-cell-group>
93   - </template>
94   -
95   -
96   - </view>
  12 + <template v-else>
  13 + <view v-if="orderDetail.length>0">
  14 + <view class="content-wrap" v-for="(i, index) in orderDetail" :key="index">
  15 + <!-- 工单详情内容 -->
  16 + <up-cell-group :border="false" inset >
  17 + <!-- 1. 工单名称 -->
  18 + <up-cell
  19 + align="middle"
  20 + >
  21 + <template #title>
  22 + <view class="up-line-1">{{i.planName || '--'}}</view>
  23 + </template>
  24 + <!-- <template #value>-->
  25 + <!-- <view class="up-line-1">{{orderDetail.planName || '&#45;&#45;'}}</view>-->
  26 + <!-- </template>-->
  27 + </up-cell>
  28 +
  29 + <!-- 2. 工单位置 -->
  30 + <up-cell
  31 + title="计划编码"
  32 + :value="i.planNo || '--'"
  33 + align="middle"
  34 + ></up-cell>
  35 +
  36 + <!-- 3. 工单名称 -->
  37 + <up-cell
  38 + title="养护周期"
  39 + :value="`${i.rate}${uni.$dict.getDictLabel('cycle_id_type', i.cycleId)}`"
  40 + align="middle"
  41 + ></up-cell>
  42 +
  43 + <!-- 4. 情况描述 -->
  44 + <up-cell
  45 + title="计划有效期"
  46 + :value="`${timeFormat(i.beginTime,'yyyy-mm-dd')} 至 ${timeFormat(i. endTime,'yyyy-mm-dd')}`"
  47 + align="middle"
  48 + ></up-cell>
  49 +
  50 + <!-- 5. 问题照片(核心修复:判断条件+空值处理) -->
  51 + <up-cell title="照片">
  52 + <template #value>
  53 + <view class="cell-content-wrap">
  54 +
  55 + <!-- 修复1:正确判断problemImgsList,补充空数组默认值 -->
  56 + <up-album
  57 + v-if="!!i.imgList?.length"
  58 + :urls="i.imgList || []"
  59 + singleSize="70"
  60 + :preview-full-image="true"
  61 +
  62 + ></up-album>
  63 + <text v-else class="empty-text">暂无问题照片</text>
  64 + </view>
  65 + </template>
  66 + </up-cell>
  67 +
  68 + <!-- 7. 处理结果 -->
  69 + <up-cell
  70 + align="middle"
  71 + >
  72 + <template #title>
  73 + <view style="min-width: 200rpx">巡查描述</view>
  74 + </template>
  75 + <template #value>
  76 + <view class="up-line-1 common-text-color">{{i.remark || '--'}}</view>
  77 + </template>
  78 + </up-cell>
  79 +
  80 + <up-cell
  81 + title="提交时间"
  82 + :value="timeFormat(i.finishTime,'yyyy-mm-dd hh:MM:ss') || '--'"
  83 + align="middle"
  84 +
  85 + ></up-cell>
  86 +
  87 + <up-cell
  88 + title="提交人"
  89 + :value="i.userName || '--'"
  90 + align="middle"
  91 + :border="false"
  92 + ></up-cell>
  93 + </up-cell-group>
  94 +
  95 + </view>
  96 + </view>
  97 + <view v-else>
  98 + <up-empty
  99 + mode="history">
  100 + </up-empty>
  101 + </view>
  102 +
  103 + </template>
97 104 </view>
98 105 </template>
99 106  
... ...
pages-sub/daily/patrol-manage/index.vue
... ... @@ -112,7 +112,8 @@ import { inspectionPlanPage } from &quot;@/api/patrol-manage/patrol-plan&quot;;
112 112 const tabList = ref([
113 113 {name: '待完成', id: '1'},
114 114 {name: '已失效', id: '3'},
115   - {name: '已完成', id: '2'}
  115 + {name: '已完成', id: '2'},
  116 + { name: '已终止', id: '4' }
116 117 ]);
117 118 const pagingRef = ref(null)
118 119 const activeTab = ref('1');
... ...
pages-sub/problem/work-order-manage/add-maintain-order.vue
... ... @@ -7,7 +7,7 @@
7 7 ref="workOrderFormRef"
8 8 labelWidth="190rpx"
9 9 >
10   - <!-- 1. 工单编号(新增:从URL获取,只读展示) -->
  10 + <!-- 1. 工单编号(只读展示,从URL获取) -->
11 11 <up-form-item
12 12 label="工单编号"
13 13 border-bottom
... ... @@ -20,7 +20,7 @@
20 20 ></up-input>
21 21 </up-form-item>
22 22  
23   - <!-- 2. 共同处理人(新增:非必选,下拉框) -->
  23 + <!-- 2. 共同处理人(支持多选) -->
24 24 <up-form-item
25 25 label="共同处理人"
26 26 prop="coProcessorName"
... ... @@ -31,7 +31,7 @@
31 31 v-model="workOrderForm.coProcessorName"
32 32 disabled
33 33 disabled-color="#ffffff"
34   - placeholder="请选择共同处理人(选)"
  34 + placeholder="请选择共同处理人(支持多选)"
35 35 border="none"
36 36 ></up-input>
37 37 <template #right>
... ... @@ -39,14 +39,14 @@
39 39 </template>
40 40 </up-form-item>
41 41  
42   - <!-- 3. 处理建议(新增:必传,文本域) -->
  42 + <!-- 3. 处理建议(处理情况描述,必填) -->
43 43 <up-form-item
44   - label="处理建议"
  44 + label="处理情况描述"
45 45 prop="reason"
46 46 required
47 47 >
48 48 <up-textarea
49   - placeholder="请输入处理建议(必填,最多200字)"
  49 + placeholder="请输入处理情况描述(必填,最多200字)"
50 50 v-model.trim="workOrderForm.reason"
51 51 count
52 52 maxlength="200"
... ... @@ -56,131 +56,8 @@
56 56 ></up-textarea>
57 57 </up-form-item>
58 58  
59   - <!-- 原有:工单位置(地图选择) -->
60   - <up-form-item
61   - label="工单位置"
62   - prop="workLocation"
63   - border-bottom
64   - required
65   - @click="chooseWorkLocation(); hideKeyboard()"
66   - >
67   - <up-input
68   - v-model="workOrderForm.workLocation"
69   - border="none"
70   - readonly
71   - suffix-icon="map-fill"
72   - placeholder="点击选择工单位置"
73   - ></up-input>
74   - </up-form-item>
75   -
76   - <!-- 原有:道路名称(下拉框) -->
77   - <up-form-item
78   - label="道路名称"
79   - prop="roadName"
80   - border-bottom
81   - required
82   - @click="handleActionSheetOpen('roadName'); hideKeyboard()"
83   - >
84   - <up-input
85   - v-model="workOrderForm.roadName"
86   - readonly
87   - disabled-color="#ffffff"
88   - placeholder="请先选择工单位置"
89   - border="none"
90   - ></up-input>
91   - <template #right>
92   - <up-icon name="arrow-right" size="16"></up-icon>
93   - </template>
94   - </up-form-item>
95   -
96   - <!-- 原有:工单名称(下拉框) -->
97   - <up-form-item
98   - label="工单名称"
99   - prop="orderName"
100   - border-bottom
101   - required
102   - @click="handleActionSheetOpen('orderName'); hideKeyboard()"
103   - >
104   - <up-input
105   - v-model="workOrderForm.orderName"
106   - disabled
107   - disabled-color="#ffffff"
108   - placeholder="请选择工单名称"
109   - border="none"
110   - ></up-input>
111   - <template #right>
112   - <up-icon name="arrow-right" size="16"></up-icon>
113   - </template>
114   - </up-form-item>
115   -
116   - <!-- 原有:紧急程度选择 -->
117   - <up-form-item
118   - label="紧急程度"
119   - prop="pressingTypeName"
120   - border-bottom
121   - required
122   - @click="handleActionSheetOpen('pressingType'); hideKeyboard()"
123   - >
124   - <up-input
125   - v-model="workOrderForm.pressingTypeName"
126   - disabled
127   - disabled-color="#ffffff"
128   - placeholder="请选择紧急程度"
129   - border="none"
130   - ></up-input>
131   - <template #right>
132   - <up-icon name="arrow-right" size="16"></up-icon>
133   - </template>
134   - </up-form-item>
135   -
136   - <!-- 原有:情况描述(文本域) -->
137   - <up-form-item
138   - label="情况描述"
139   - prop="problemDesc"
140   - required
141   - >
142   - <up-textarea
143   - placeholder="请输入情况描述(最多200字)"
144   - v-model.trim="workOrderForm.problemDesc"
145   - count
146   - maxlength="200"
147   - rows="4"
148   - @blur="() => workOrderFormRef.validateField('problemDesc')"
149   - ></up-textarea>
150   - </up-form-item>
151   -
152   - <!-- 原有:问题照片 -->
153   - <up-form-item label="问题照片" prop="problemImgs" required>
154   - <up-upload
155   - :file-list="problemImgs.imgList"
156   - @after-read="problemImgs.uploadImgs"
157   - @delete="problemImgs.deleteImg"
158   - multiple
159   - :max-count="problemImgs.uploadConfig.maxCount"
160   - :upload-text="problemImgs.uploadConfig.uploadText"
161   - :size-type="problemImgs.uploadConfig.sizeType"
162   - ></up-upload>
163   - </up-form-item>
164   -
165   - <!-- 原有:完成时间 -->
166   - <up-form-item
167   - label="希望完成时间"
168   - prop="finishDate"
169   - @click="show=true;hideKeyboard()"
170   - >
171   - <up-input
172   - v-model="workOrderForm.finishDate"
173   - border="none"
174   - readonly
175   - placeholder="点击选择时间"
176   - ></up-input>
177   - <template #right>
178   - <up-icon name="arrow-right" size="16"></up-icon>
179   - </template>
180   - </up-form-item>
181   - </up-form>
182 59  
183   - <!-- 4. Tabs标签栏(新增:开始、进行中、结束、人员、材料) -->
  60 + <!-- Tabs标签栏(图片切换:开始、进行中、结束、人员、材料) -->
184 61 <view class="tabs-wrap commonPageLRpadding" style="margin-top: 30rpx;">
185 62 <up-tabs
186 63 v-model="activeTab"
... ... @@ -188,19 +65,86 @@
188 65 line-width="40rpx"
189 66 active-color="#1989fa"
190 67 inactive-color="#666666"
  68 +
  69 + @change = "imgTabChange"
191 70 ></up-tabs>
192   - <!-- Tab对应内容容器(可根据需求填充具体内容) -->
193   - <view class="tab-content" style="padding-top: 20rpx;">
194   - <view v-if="activeTab === 0">开始阶段相关内容</view>
195   - <view v-if="activeTab === 1">进行中阶段相关内容</view>
196   - <view v-if="activeTab === 2">结束阶段相关内容</view>
197   - <view v-if="activeTab === 3">人员配置相关内容</view>
198   - <view v-if="activeTab === 4">材料使用相关内容</view>
  71 + <view class="tab-content" style="padding-top: 20rpx; background: #fff; padding-bottom: 20rpx;">
  72 + <!-- 开始阶段图片上传 -->
  73 + <view v-if="activeTab == 0">
  74 + <up-form-item prop="startImgs">
  75 + <up-upload
  76 + :file-list="startImgs.imgList"
  77 + @after-read="startImgs.uploadImgs"
  78 + @delete="startImgs.deleteImg"
  79 + multiple
  80 + :max-count="startImgs.uploadConfig.maxCount"
  81 + :upload-text="startImgs.uploadConfig.uploadText"
  82 + :size-type="startImgs.uploadConfig.sizeType"
  83 + ></up-upload>
  84 + </up-form-item>
  85 + </view>
  86 + <!-- 进行中阶段图片上传 -->
  87 + <view v-if="activeTab == 1">
  88 + <up-form-item prop="processingImgs">
  89 + <up-upload
  90 + :file-list="processingImgs.imgList"
  91 + @after-read="processingImgs.uploadImgs"
  92 + @delete="processingImgs.deleteImg"
  93 + multiple
  94 + :max-count="processingImgs.uploadConfig.maxCount"
  95 + :upload-text="processingImgs.uploadConfig.uploadText"
  96 + :size-type="processingImgs.uploadConfig.sizeType"
  97 + ></up-upload>
  98 + </up-form-item>
  99 + </view>
  100 + <!-- 结束阶段图片上传 -->
  101 + <view v-if="activeTab == 2">
  102 + <up-form-item prop="endImgs">
  103 + <up-upload
  104 + :file-list="endImgs.imgList"
  105 + @after-read="endImgs.uploadImgs"
  106 + @delete="endImgs.deleteImg"
  107 + multiple
  108 + :max-count="endImgs.uploadConfig.maxCount"
  109 + :upload-text="endImgs.uploadConfig.uploadText"
  110 + :size-type="endImgs.uploadConfig.sizeType"
  111 + ></up-upload>
  112 + </up-form-item>
  113 + </view>
  114 + <!-- 人员配置图片上传 -->
  115 + <view v-if="activeTab == 3">
  116 + <up-form-item prop="personImgs">
  117 + <up-upload
  118 + :file-list="personImgs.imgList"
  119 + @after-read="personImgs.uploadImgs"
  120 + @delete="personImgs.deleteImg"
  121 + multiple
  122 + :max-count="personImgs.uploadConfig.maxCount"
  123 + :upload-text="personImgs.uploadConfig.uploadText"
  124 + :size-type="personImgs.uploadConfig.sizeType"
  125 + ></up-upload>
  126 + </up-form-item>
  127 + </view>
  128 + <!-- 材料使用图片上传 -->
  129 + <view v-if="activeTab == 4">
  130 + <up-form-item prop="materialImgs">
  131 + <up-upload
  132 + :file-list="materialImgs.imgList"
  133 + @after-read="materialImgs.uploadImgs"
  134 + @delete="materialImgs.deleteImg"
  135 + multiple
  136 + :max-count="materialImgs.uploadConfig.maxCount"
  137 + :upload-text="materialImgs.uploadConfig.uploadText"
  138 + :size-type="materialImgs.uploadConfig.sizeType"
  139 + ></up-upload>
  140 + </up-form-item>
  141 + </view>
199 142 </view>
200 143 </view>
  144 + </up-form>
201 145 </view>
202 146  
203   - <!-- 底部提交按钮 -->
  147 + <!-- 底部提交按钮(保留,按需可移除) -->
204 148 <view class="fixed-bottom-btn-wrap">
205 149 <up-button
206 150 type="primary"
... ... @@ -209,7 +153,7 @@
209 153 ></up-button>
210 154 </view>
211 155  
212   - <!-- 合并后的通用下拉弹窗(新增共同处理人配置) -->
  156 + <!-- 通用下拉弹窗(仅用于共同处理人多选) -->
213 157 <up-action-sheet
214 158 :show="showActionSheet"
215 159 :actions="currentActionSheetData.list"
... ... @@ -217,56 +161,31 @@
217 161 @close="handleActionSheetClose"
218 162 @select="handleActionSheetSelect"
219 163 ></up-action-sheet>
220   -
221   - <!-- 完成时间选择器 -->
222   - <up-datetime-picker
223   - :show="show"
224   - v-model="finishDate"
225   - mode="datetime"
226   - :min-date="new Date()"
227   - @cancel="show = false"
228   - @confirm="finishDateConfirm"
229   - ></up-datetime-picker>
230 164 </view>
231 165 </template>
232 166  
233 167 <script setup>
234   -import { ref, reactive, watch, onLoad } from 'vue'
235   -import { onReady, onShow } from '@dcloudio/uni-app';
  168 +import { ref, reactive, watch } from 'vue'
  169 +import { onLoad, onReady, onShow } from '@dcloudio/uni-app';
236 170 import { useUploadImgs } from '@/common/utils/useUploadImgs'
237   -import { getRoadListByLatLng } from '@/api/common'
238   -import { workorderCreate, getYlWorkersPage, ylTeamLeaderAssignWOrder, ylWorkerExcuteWOrder } from '@/api/work-order-manage/work-order-manage'
239   -import { timeFormat } from '@/uni_modules/uview-plus'
240   -
241   -// ========== 表单Ref ==========
242   -const workOrderFormRef = ref(null)
  171 +import { getYlWorkersPage, ylWorkerExcuteWOrder } from '@/api/work-order-manage/work-order-manage'
  172 +import { useUserStore } from '@/pinia/user';
243 173  
244   -// ========== 公共上传逻辑复用 ==========
245   -const problemImgs = useUploadImgs({
246   - maxCount: 3,
247   - uploadText: '选择问题照片',
248   - sizeType: ['compressed'],
249   - formRef: workOrderFormRef,
250   - fieldName: 'problemImgs'
251   -})
  174 +const userStore = useUserStore();
252 175  
253   -// 核心修复:监听响应式数组变化,同步更新纯数组
254   -watch(() => problemImgs.rawImgList.value, (newVal) => {
255   - problemImgs.imgList = newVal
256   -}, { deep: true })
  176 +// 表单Ref
  177 +const workOrderFormRef = ref(null)
257 178  
258   -// ========== 页面状态 ==========
  179 +// 页面状态
259 180 const showActionSheet = ref(false)
260 181 const currentActionSheetData = reactive({
261 182 type: '',
262 183 list: [],
263   - title: ''
  184 + title: '',
264 185 })
265   -const show = ref(false)
266   -const finishDate = ref(Date.now())
267 186  
268   -// 新增:Tabs配置
269   -const activeTab = ref(0) // 默认选中第一个标签
  187 +// Tabs配置(图片切换用)
  188 +const activeTab = ref(0)
270 189 const tabList = ref([
271 190 { name: '开始' },
272 191 { name: '进行中' },
... ... @@ -275,63 +194,99 @@ const tabList = ref([
275 194 { name: '材料' }
276 195 ])
277 196  
278   -// ========== 下拉列表数据 ==========
279   -const roadNameList = ref([])
280   -const orderNameList = ref([])
281   -const pressingTypeList = ref([])
282   -const coProcessorList = ref([]) // 新增:共同处理人列表(来自getYlWorkersPage)
  197 +// 共同处理人列表
  198 +const coProcessorList = ref([])
283 199  
284   -// ========== 工单表单数据(新增字段) ==========
  200 +// 工单表单数据(仅保留需要的字段)
285 201 const workOrderForm = reactive({
286   - orderNo: '', // 新增:工单编号(URL获取)
287   - coProcessorId: '', // 新增:共同处理人ID(非必选,提交接口用)
288   - coProcessorName: '', // 新增:共同处理人名称(显示用)
289   - reason: '', // 新增:处理建议(必填)
290   - roadId: 0,
291   - roadName: '',
292   - workLocation: '',
293   - orderName: '',
294   - pressingType: '',
295   - pressingTypeName: '',
296   - problemDesc: '',
297   - lat: 0,
298   - lon: 0,
299   - finishDate: '',
  202 + orderNo: '', // 工单编号
  203 + coProcessorId: '', // 共同处理人ID数组(多选)
  204 + coProcessorName: '', // 共同处理人名称数组(多选)
  205 + reason: '', // 处理情况描述
  206 +})
  207 +
  208 +// ========== 图片上传配置(5个Tab分别配置,均限制3张,与参考示例一致) ==========
  209 +// 开始阶段图片
  210 +const startImgs = useUploadImgs({
  211 + maxCount: 3,
  212 + uploadText: '选择开始阶段照片',
  213 + sizeType: ['compressed'],
  214 + formRef: workOrderFormRef,
  215 + fieldName: 'startImgs'
  216 +})
  217 +// 进行中阶段图片
  218 +const processingImgs = useUploadImgs({
  219 + maxCount: 3,
  220 + uploadText: '选择进行中阶段照片',
  221 + sizeType: ['compressed'],
  222 + formRef: workOrderFormRef,
  223 + fieldName: 'processingImgs'
  224 +})
  225 +// 结束阶段图片
  226 +const endImgs = useUploadImgs({
  227 + maxCount: 3,
  228 + uploadText: '选择结束阶段照片',
  229 + sizeType: ['compressed'],
  230 + formRef: workOrderFormRef,
  231 + fieldName: 'endImgs'
300 232 })
  233 +// 人员配置图片
  234 +const personImgs = useUploadImgs({
  235 + maxCount: 3,
  236 + uploadText: '选择人员配置照片',
  237 + sizeType: ['compressed'],
  238 + formRef: workOrderFormRef,
  239 + fieldName: 'personImgs'
  240 +})
  241 +// 材料使用图片
  242 +const materialImgs = useUploadImgs({
  243 + maxCount: 3,
  244 + uploadText: '选择材料使用照片',
  245 + sizeType: ['compressed'],
  246 + formRef: workOrderFormRef,
  247 + fieldName: 'materialImgs'
  248 +})
  249 +
  250 +// ========== 核心修复:监听每个上传实例的响应式数组变化,解决u-upload不刷新问题 ==========
  251 +watch(() => startImgs.rawImgList.value, (newVal) => {
  252 + startImgs.imgList = newVal
  253 +}, { deep: true })
  254 +
  255 +watch(() => processingImgs.rawImgList.value, (newVal) => {
  256 + processingImgs.imgList = newVal
  257 +}, { deep: true })
  258 +
  259 +watch(() => endImgs.rawImgList.value, (newVal) => {
  260 + endImgs.imgList = newVal
  261 +}, { deep: true })
  262 +
  263 +watch(() => personImgs.rawImgList.value, (newVal) => {
  264 + personImgs.imgList = newVal
  265 +}, { deep: true })
  266 +
  267 +watch(() => materialImgs.rawImgList.value, (newVal) => {
  268 + materialImgs.imgList = newVal
  269 +}, { deep: true })
301 270  
302   -// ========== 表单校验规则(更新:新增处理建议必填、共同处理人非必填) ==========
  271 +// 表单校验规则(新增5个图片字段校验,复用上传校验规则)
303 272 const workOrderFormRules = reactive({
304   - orderNo: [ // 工单编号仅展示,无校验
  273 + orderNo: [
305 274 { type: 'string', trigger: ['change'] }
306 275 ],
307   - coProcessorName: [ // 共同处理人非必填,仅长度兜底
308   - { type: 'string', max: 50, message: '共同处理人名称过长', trigger: ['change'] }
309   - ],
310   - reason: [ // 处理建议必填+长度限制
311   - { type: 'string', required: true, message: '请输入处理建议', trigger: ['change', 'blur'] },
312   - { type: 'string', max: 200, message: '处理建议最多200字', trigger: ['change', 'blur'] }
313   - ],
314   - workLocation: [
315   - { type: 'string', required: true, message: '请选择工单位置', trigger: ['change', 'blur'] }
316   - ],
317   - roadName: [
318   - { type: 'string', required: true, message: '请选择道路名称', trigger: ['change', 'blur'] }
319   - ],
320   - orderName: [
321   - { type: 'string', required: true, message: '请选择工单名称', trigger: ['change', 'blur'] }
322   - ],
323   - pressingTypeName: [
324   - { type: 'string', required: true, message: '请选择紧急程度', trigger: ['change'] }
325   - ],
326   - problemDesc: [
327   - { type: 'string', required: true, message: '请输入情况描述', trigger: ['change', 'blur'] },
328   - { type: 'string', min: 3, max: 200, message: '情况描述需3-200字', trigger: ['change', 'blur'] }
  276 +
  277 + reason: [
  278 + { type: 'string', required: true, message: '请输入处理情况描述', trigger: ['change', 'blur'] },
  279 + { type: 'string', max: 200, message: '处理情况描述最多200字', trigger: ['change', 'blur'] }
329 280 ],
330   - problemImgs: [problemImgs.imgValidateRule]
  281 + // 新增5个图片字段校验
  282 + startImgs: [startImgs.imgValidateRule],
  283 + processingImgs: [processingImgs.imgValidateRule],
  284 + endImgs: [endImgs.imgValidateRule],
  285 + personImgs: [personImgs.imgValidateRule],
  286 + materialImgs: [materialImgs.imgValidateRule]
331 287 })
332 288  
333   -// ========== 生命周期 ==========
334   -// 新增:onLoad - 从URL获取工单编号
  289 +// 生命周期 - 从URL获取工单编号
335 290 onLoad((options) => {
336 291 if (options && options.orderNo) {
337 292 workOrderForm.orderNo = options.orderNo
... ... @@ -339,6 +294,7 @@ onLoad((options) =&gt; {
339 294 console.log('从URL获取工单编号:', workOrderForm.orderNo)
340 295 })
341 296  
  297 +// 生命周期 - 初始化表单规则
342 298 onReady(() => {
343 299 if (workOrderFormRef.value) {
344 300 workOrderFormRef.value.setRules(workOrderFormRules)
... ... @@ -346,29 +302,17 @@ onReady(() =&gt; {
346 302 console.log('工单表单规则初始化完成')
347 303 })
348 304  
  305 +// 生命周期 - 加载共同处理人列表
349 306 onShow(async () => {
350   - console.log(uni.$dict.getDictLabel('ai_image_status', 20))
351   - console.log(uni.$dict.getDictSimpleList('work_name'))
352   -
353   - // 初始化工单名称列表
354   - orderNameList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('work_name'))
355   - console.log('工单名称列表:', orderNameList.value)
356   -
357   - // 初始化紧急程度列表
358   - pressingTypeList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('workorder_pressing_type'))
359   - console.log('紧急程度列表:', pressingTypeList.value)
360   -
361   - // 新增:加载共同处理人列表(来自getYlWorkersPage)
362 307 await loadCoProcessorList()
363 308 })
364 309  
365   -// ========== 新增:加载共同处理人列表 ==========
  310 +// 加载共同处理人列表
366 311 const loadCoProcessorList = async () => {
367 312 try {
368 313 uni.showLoading({ title: '获取处理人列表中...' })
369   - // 构造查询参数(可根据接口需求调整)
370 314 const queryData = {
371   - roleCode: 'team_leader_yl',
  315 + roleCode: 'yl_worker',
372 316 busiLine: 'yl',
373 317 pageNo: 1,
374 318 pageSize: 100
... ... @@ -376,21 +320,13 @@ const loadCoProcessorList = async () =&gt; {
376 320 const res = await getYlWorkersPage(queryData)
377 321 uni.hideLoading()
378 322  
379   - // 适配接口返回格式(兼容res.data.list或res.records)
380   - let listData = []
381   - if (res && res.code === 0 && res.data && res.data.list) {
382   - listData = res.data.list
383   - } else if (res && res.records) {
384   - listData = res.records
385   - }
386   -
387   - if (Array.isArray(listData) && listData.length > 0) {
388   - // 格式化共同处理人列表(映射name和value)
389   - coProcessorList.value = listData.map(item => ({
390   - name: item.nickname || item.realName || item.userName || '未知处理人',
391   - value: item.id || item.workerId || '',
392   - id: item.id || item.workerId || ''
  323 + if (res.list && res.list.length > 0) {
  324 + coProcessorList.value = res.list.map(item => ({
  325 + name: item.nickname,
  326 + value: item.id,
  327 + id: item.id
393 328 }))
  329 + console.log('共同处理人列表:', coProcessorList.value)
394 330 } else {
395 331 coProcessorList.value = []
396 332 uni.showToast({ title: '未查询到处理人数据', icon: 'none' })
... ... @@ -403,40 +339,19 @@ const loadCoProcessorList = async () =&gt; {
403 339 }
404 340 }
405 341  
406   -// ========== 方法定义 ==========
407   -/**
408   - * 打开通用下拉弹窗(新增共同处理人配置)
409   - */
  342 +// 打开通用下拉弹窗(仅共同处理人)
410 343 const handleActionSheetOpen = (type) => {
411   - // 道路名称需先校验工单位置是否选择
412   - if (type === 'roadName' && !workOrderForm.workLocation) {
413   - uni.showToast({ title: '请先选择工单位置', icon: 'none' })
414   - return
415   - }
416   -
417 344 // 共同处理人列表为空提示
418 345 if (type === 'coProcessor' && coProcessorList.value.length === 0) {
419 346 uni.showToast({ title: '暂无处理人数据可选', icon: 'none' })
420 347 return
421 348 }
422 349  
423   - // 配置当前弹窗参数(新增coProcessor
  350 + // 弹窗配置映射(仅保留共同处理人
424 351 const configMap = {
425 352 coProcessor: {
426 353 title: '请选择共同处理人',
427   - list: coProcessorList.value
428   - },
429   - roadName: {
430   - title: '请选择道路名称',
431   - list: roadNameList.value
432   - },
433   - orderName: {
434   - title: '请选择工单名称',
435   - list: orderNameList.value
436   - },
437   - pressingType: {
438   - title: '请选择紧急程度',
439   - list: pressingTypeList.value
  354 + list: coProcessorList.value,
440 355 }
441 356 }
442 357  
... ... @@ -446,9 +361,7 @@ const handleActionSheetOpen = (type) =&gt; {
446 361 showActionSheet.value = true
447 362 }
448 363  
449   -/**
450   - * 关闭通用下拉弹窗
451   - */
  364 +// 关闭通用下拉弹窗
452 365 const handleActionSheetClose = () => {
453 366 showActionSheet.value = false
454 367 currentActionSheetData.type = ''
... ... @@ -456,144 +369,71 @@ const handleActionSheetClose = () =&gt; {
456 369 currentActionSheetData.title = ''
457 370 }
458 371  
459   -/**
460   - * 通用下拉弹窗选择事件(新增共同处理人逻辑)
461   - */
  372 +// 下拉弹窗选择事件(仅处理共同处理人多选)
462 373 const handleActionSheetSelect = (e) => {
  374 + console.log(e)
463 375 const { type } = currentActionSheetData
464   - switch (type) {
465   - case 'coProcessor': // 新增:共同处理人选择
466   - workOrderForm.coProcessorName = e.name
467   - workOrderForm.coProcessorId = e.value
468   - workOrderFormRef.value?.validateField('coProcessorName')
469   - break
470   - case 'roadName':
471   - workOrderForm.roadName = e.name
472   - workOrderForm.roadId = e.code
473   - workOrderFormRef.value?.validateField('roadName')
474   - break
475   - case 'orderName':
476   - workOrderForm.orderName = e.name
477   - workOrderFormRef.value?.validateField('orderName')
478   - break
479   - case 'pressingType':
480   - workOrderForm.pressingType = e.value
481   - workOrderForm.pressingTypeName = e.name
482   - workOrderFormRef.value?.validateField('pressingType')
483   - break
  376 + // 多选场景(仅共同处理人)
  377 + if (type === 'coProcessor') {
  378 + workOrderForm.coProcessorName = e.name
  379 + workOrderForm.coProcessorId = e.id
  380 + workOrderFormRef.value?.validateField('coProcessorName')
484 381 }
485 382 showActionSheet.value = false
486 383 }
487 384  
488   -/**
489   - * 返回上一页
490   - */
491   -const navigateBack = () => {
492   - uni.navigateBack()
493   -}
494   -
495   -/**
496   - * 选择工单位置
497   - */
498   -const chooseWorkLocation = () => {
499   - uni.chooseLocation({
500   - success: async (res) => {
501   - workOrderForm.roadName = ''
502   - workOrderForm.roadId = 0
503   - roadNameList.value = []
504   -
505   - workOrderForm.workLocation = res.name
506   - workOrderForm.lat = res.latitude
507   - workOrderForm.lon = res.longitude
508   -
509   - workOrderFormRef.value?.validateField('workLocation')
510   - workOrderFormRef.value?.validateField('roadName')
511   -
512   - try {
513   - uni.showLoading({ title: '获取道路名称中...' })
514   - const roadRes = await getRoadListByLatLng({
515   - companyCode: 'sls',
516   - latitude: res.latitude,
517   - longitude: res.longitude
518   - })
519   - uni.hideLoading()
520   -
521   - if (Array.isArray(roadRes)) {
522   - roadNameList.value = roadRes.map((item) => ({
523   - name: item.roadName || '',
524   - code: item.roadCode || '',
525   - id: item.roadId || 0
526   - }))
527   - } else {
528   - roadNameList.value = [{ name: '未查询到道路名称', code: '', id: 0 }]
529   - uni.showToast({ title: '未查询到该位置的道路信息', icon: 'none' })
530   - }
531   - } catch (err) {
532   - uni.hideLoading()
533   - console.error('获取道路名称失败:', err)
534   - uni.showToast({ title: '获取道路名称失败,请重试', icon: 'none' })
535   - roadNameList.value = [{ name: '获取失败,请重新选择位置', code: '', id: 0 }]
536   - }
537   - },
538   - fail: (err) => {
539   - console.error('选择位置失败:', err)
540   - uni.showToast({ title: '选择位置失败:' + err.errMsg, icon: 'none' })
541   - }
542   - })
543   -}
544   -
545   -/**
546   - * 完成时间确认
547   - */
548   -const finishDateConfirm = (e) => {
549   - console.log('选择的完成时间:', e)
550   - workOrderForm.finishDate = timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss')
551   - show.value = false
  385 +// 图片切换选择
  386 +const imgTabChange = (item)=> {
  387 + console.log(item)
  388 + activeTab.value = item.index
552 389 }
553 390  
554   -/**
555   - * 隐藏键盘
556   - */
  391 +// 隐藏键盘
557 392 const hideKeyboard = () => {
558 393 uni.hideKeyboard()
559 394 }
560 395  
561   -/**
562   - * 提交工单(改造:使用ylWorkerExcuteWOrder接口,传递新增参数)
563   - */
  396 +// 提交工单(整合所有图片URL,与参考示例一致)
564 397 const submitWorkOrder = async () => {
565 398 try {
566 399 // 表单校验
567 400 await workOrderFormRef.value.validate()
568 401  
569   - // 构造提交参数(包含原有参数+新增字段)
  402 + // 构造所有图片URL(按Tab分类,或合并为一个数组,可按需调整)
  403 + const allImgs = {
  404 + startImgs: startImgs.getSuccessImgUrls(),
  405 + processingImgs: processingImgs.getSuccessImgUrls(),
  406 + endImgs: endImgs.getSuccessImgUrls(),
  407 + personImgs: personImgs.getSuccessImgUrls(),
  408 + materialImgs: materialImgs.getSuccessImgUrls()
  409 + }
  410 +
  411 + // 构造提交参数(可按需调整图片字段格式,此处既保留分类也提供合并数组)
570 412 const submitData = {
571   - id: workOrderForm.orderNo, // 工单编号(对应接口id)
572   - reason: workOrderForm.reason.trim(), // 处理建议(必填)
573   - coProcessorId: workOrderForm.coProcessorId, // 共同处理人ID(非必选)
574   - roadId: workOrderForm.roadId,
575   - roadName: workOrderForm.roadName,
576   - imgs: problemImgs.getSuccessImgUrls(),
577   - remark: workOrderForm.problemDesc.trim(),
578   - latLonType: 2,
579   - lat: workOrderForm.lat,
580   - lon: workOrderForm.lon,
581   - lonLatAddress: workOrderForm.workLocation,
582   - pressingType: workOrderForm.pressingType,
583   - orderName: workOrderForm.orderName,
584   - finishDate: workOrderForm.finishDate,
585   - sourceId: 1,
586   - sourceName: '园林',
587   - busiLine: 'yl'
  413 + id: workOrderForm.orderNo,
  414 + reason: workOrderForm.reason.trim(),
  415 + coProcessorId: workOrderForm.coProcessorId, // 数组格式提交,如需字符串可.join(',')
  416 + busiLine: 'yl',
  417 + // 分类图片URL
  418 + startImgs: allImgs.startImgs,
  419 + processingImgs: allImgs.processingImgs,
  420 + endImgs: allImgs.endImgs,
  421 + personImgs: allImgs.personImgs,
  422 + materialImgs: allImgs.materialImgs,
  423 + // 合并所有图片为一个数组(若接口需要)
  424 + imgs: [
  425 + ...allImgs.startImgs,
  426 + ...allImgs.processingImgs,
  427 + ...allImgs.endImgs,
  428 + ...allImgs.personImgs,
  429 + ...allImgs.materialImgs
  430 + ]
588 431 }
589 432  
590   - // 显示加载中
591 433 uni.showLoading({ title: '提交中...' })
592   -
593   - // 替换为指定接口:ylWorkerExcuteWOrder
594 434 const res = await ylWorkerExcuteWOrder(submitData)
595   -
596 435 uni.hideLoading()
  436 +
597 437 uni.showToast({
598 438 title: '工单提交成功',
599 439 icon: 'success',
... ... @@ -609,7 +449,7 @@ const submitWorkOrder = async () =&gt; {
609 449 } catch (error) {
610 450 uni.hideLoading()
611 451  
612   - // 区分表单校验失败和接口调用失败
  452 + // 区分校验失败和接口失败
613 453 if (!Array.isArray(error)) {
614 454 console.error('工单提交失败:', error)
615 455 uni.showToast({
... ... @@ -623,14 +463,13 @@ const submitWorkOrder = async () =&gt; {
623 463 </script>
624 464  
625 465 <style lang="scss" scoped>
626   -// 全局页面样式
  466 +// 页面容器样式
627 467 .page-container {
628 468 min-height: 100vh;
629   - padding-bottom: 100rpx; // 给底部按钮留空间
630   - background-color: #f5f5f5;
  469 + padding-bottom: 100rpx; // 给底部按钮留空间,与参考示例一致
631 470 }
632 471  
633   -// 工单表单内容容器
  472 +// 表单内容容器
634 473 .work-order-form-content {
635 474 background: #fff;
636 475 padding-bottom: 30rpx;
... ... @@ -641,5 +480,4 @@ const submitWorkOrder = async () =&gt; {
641 480 background: #fff;
642 481 }
643 482  
644   -
645 483 </style>
646 484 \ No newline at end of file
... ...
pages-sub/problem/work-order-manage/add-order.vue
... ... @@ -7,32 +7,77 @@
7 7 ref="workOrderFormRef"
8 8 labelWidth="190rpx"
9 9 >
10   - <!-- 1. 工单编号(从URL获取展示) -->
  10 + <!-- 1. 工单位置(地图选择) -->
11 11 <up-form-item
12   - label="工单编号"
  12 + label="工单位置"
  13 + prop="workLocation"
13 14 border-bottom
  15 + required
  16 + @click="chooseWorkLocation(); hideKeyboard()"
14 17 >
15 18 <up-input
16   - v-model="workOrderForm.orderNo"
  19 + v-model="workOrderForm.workLocation"
17 20 border="none"
18 21 readonly
19   - placeholder="暂无工单编号"
  22 + suffix-icon="map-fill"
  23 + placeholder="点击选择工单位置"
  24 + ></up-input>
  25 + </up-form-item>
  26 +
  27 + <!-- 2. 道路名称(下拉框) -->
  28 + <up-form-item
  29 + label="道路名称"
  30 + prop="roadName"
  31 + border-bottom
  32 + required
  33 + @click="handleActionSheetOpen('roadName'); hideKeyboard()"
  34 + >
  35 + <up-input
  36 + v-model="workOrderForm.roadName"
  37 + readonly
  38 + disabled-color="#ffffff"
  39 + placeholder="请先选择工单位置"
  40 + border="none"
  41 +
  42 + ></up-input>
  43 + <template #right>
  44 + <up-icon name="arrow-right" size="16" ></up-icon>
  45 + </template>
  46 + </up-form-item>
  47 +
  48 + <!-- 3. 工单名称(下拉框) -->
  49 + <up-form-item
  50 + label="工单名称"
  51 + prop="orderName"
  52 + border-bottom
  53 + required
  54 + @click="handleActionSheetOpen('orderName'); hideKeyboard()"
  55 + >
  56 + <up-input
  57 + v-model="workOrderForm.orderName"
  58 + disabled
  59 + disabled-color="#ffffff"
  60 + placeholder="请选择工单名称"
  61 + border="none"
20 62 ></up-input>
  63 + <template #right>
  64 + <up-icon name="arrow-right" size="16"></up-icon>
  65 + </template>
21 66 </up-form-item>
22 67  
23   - <!-- 2. 养护员选择(必选,下拉框) -->
  68 + <!-- 新增:紧急程度选择 -->
24 69 <up-form-item
25   - label="养护员"
26   - prop="assigneeName"
  70 + label="紧急程度"
  71 + prop="pressingTypeName"
27 72 border-bottom
28 73 required
29   - @click="handleActionSheetOpen('assignee'); hideKeyboard()"
  74 + @click="handleActionSheetOpen('pressingType'); hideKeyboard()"
30 75 >
31 76 <up-input
32   - v-model="workOrderForm.assigneeName"
  77 + v-model="workOrderForm.pressingTypeName"
33 78 disabled
34 79 disabled-color="#ffffff"
35   - placeholder="请选择养护员"
  80 + placeholder="请选择紧急程度"
36 81 border="none"
37 82 ></up-input>
38 83 <template #right>
... ... @@ -40,19 +85,51 @@
40 85 </template>
41 86 </up-form-item>
42 87  
43   - <!-- 3. 处理意见(非必填,文本域) -->
  88 + <!-- 4. 情况描述(文本域) -->
44 89 <up-form-item
45   - label="处理意见"
46   - prop="reason"
  90 + label="情况描述"
  91 + prop="problemDesc"
  92 + required
47 93 >
48 94 <up-textarea
49   - placeholder="请输入处理意见(可选,最多200字)"
50   - v-model.trim="workOrderForm.reason"
  95 + placeholder="请输入情况描述(最多200字)"
  96 + v-model.trim="workOrderForm.problemDesc"
51 97 count
52 98 maxlength="200"
53 99 rows="4"
  100 + @blur="() => workOrderFormRef.validateField('problemDesc')"
54 101 ></up-textarea>
55 102 </up-form-item>
  103 +
  104 + <!-- 问题照片(核心修复:绑定纯数组) -->
  105 + <up-form-item label="问题照片" prop="problemImgs" required>
  106 + <up-upload
  107 + :file-list="problemImgs.imgList"
  108 + @after-read="problemImgs.uploadImgs"
  109 + @delete="problemImgs.deleteImg"
  110 + multiple
  111 + :max-count="problemImgs.uploadConfig.maxCount"
  112 + :upload-text="problemImgs.uploadConfig.uploadText"
  113 + :size-type="problemImgs.uploadConfig.sizeType"
  114 + ></up-upload>
  115 + </up-form-item>
  116 +
  117 + <!-- 完成时间 -->
  118 + <up-form-item
  119 + label="希望完成时间"
  120 + prop="finishDate"
  121 + @click="show=true;hideKeyboard()"
  122 + >
  123 + <up-input
  124 + v-model="workOrderForm.finishDate"
  125 + border="none"
  126 + readonly
  127 + placeholder="点击选择时间"
  128 + ></up-input>
  129 + <template #right>
  130 + <up-icon name="arrow-right" size="16"></up-icon>
  131 + </template>
  132 + </up-form-item>
56 133 </up-form>
57 134 </view>
58 135  
... ... @@ -60,12 +137,12 @@
60 137 <view class="fixed-bottom-btn-wrap">
61 138 <up-button
62 139 type="primary"
63   - text="提交"
  140 + text="提交工单"
64 141 @click="submitWorkOrder"
65 142 ></up-button>
66 143 </view>
67 144  
68   - <!-- 养护员下拉弹窗 -->
  145 + <!-- 合并后的通用下拉弹窗 -->
69 146 <up-action-sheet
70 147 :show="showActionSheet"
71 148 :actions="currentActionSheetData.list"
... ... @@ -73,188 +150,315 @@
73 150 @close="handleActionSheetClose"
74 151 @select="handleActionSheetSelect"
75 152 ></up-action-sheet>
  153 +
  154 + <!-- 完成时间选择器 -->
  155 + <up-datetime-picker
  156 + :show="show"
  157 + v-model="finishDate"
  158 + mode="datetime"
  159 + :min-date="new Date()"
  160 + @cancel="show = false"
  161 + @confirm="finishDateConfirm"
  162 + ></up-datetime-picker>
76 163 </view>
77 164 </template>
78 165  
79 166 <script setup>
80   -import { ref, reactive } from 'vue'
81   -import { onLoad, onReady, onShow } from '@dcloudio/uni-app';
82   -import { getYlWorkersPage, ylTeamLeaderAssignWOrder } from '@/api/work-order-manage/work-order-manage'
83   -import { useUserStore } from '@/pinia/user';
84   -const userStore = useUserStore();
  167 +import { ref, reactive, watch } from 'vue'
  168 +import { onReady, onShow } from '@dcloudio/uni-app';
  169 +import { useUploadImgs } from '@/common/utils/useUploadImgs' // 引入改造后的上传逻辑
  170 +import { getRoadListByLatLng } from '@/api/common'
  171 +import { workorderCreate } from '@/api/work-order-manage/work-order-manage'
  172 +import { timeFormat } from '@/uni_modules/uview-plus'
  173 +
85 174 // ========== 表单Ref ==========
86 175 const workOrderFormRef = ref(null)
  176 +
  177 +// ========== 公共上传逻辑复用 ==========
  178 +const problemImgs = useUploadImgs({
  179 + maxCount: 3,
  180 + uploadText: '选择问题照片',
  181 + sizeType: ['compressed'],
  182 + formRef: workOrderFormRef,
  183 + fieldName: 'problemImgs'
  184 +})
  185 +
  186 +// 核心修复:监听响应式数组变化,同步更新纯数组(解决u-upload不刷新问题)
  187 +watch(() => problemImgs.rawImgList.value, (newVal) => {
  188 + problemImgs.imgList = newVal
  189 +}, { deep: true })
  190 +
87 191 // ========== 页面状态 ==========
  192 +// 通用弹窗控制
88 193 const showActionSheet = ref(false)
  194 +// 当前弹窗配置
89 195 const currentActionSheetData = reactive({
90 196 type: '',
91 197 list: [],
92 198 title: ''
93 199 })
  200 +// 完成时间选择器控制
  201 +const show = ref(false)
  202 +const finishDate = ref(Date.now())
  203 +
94 204 // ========== 下拉列表数据 ==========
95   -const assigneeList = ref([]) // 养护员列表
96   -// ========== 工单表单数据(仅保留所需字段) ==========
  205 +const roadNameList = ref([])
  206 +const orderNameList = ref([])
  207 +const pressingTypeList = ref([])
  208 +
  209 +// ========== 工单表单数据 ==========
97 210 const workOrderForm = reactive({
98   - taskId:'',
99   - orderNo: '', // 工单编号(对应接口参数id)
100   - assigneeId: '', // 养护员ID(对应接口参数nextAssignee)
101   - assigneeName: '', // 养护员名称(显示用)
102   - reason: '' // 处理意见(对应接口参数reason)
  211 + roadId: 0, // 道路ID
  212 + roadName: '', // 道路名称
  213 + workLocation: '', // 工单位置
  214 + orderName: '', // 工单名称
  215 + pressingType: '', // 紧急程度值(提交接口用)
  216 + pressingTypeName: '', // 紧急程度名称(显示用)
  217 + problemDesc: '', // 情况描述
  218 + lat: 0, // 纬度
  219 + lon: 0, // 经度
  220 + finishDate: '', // 完成时间
103 221 })
104   -// ========== 表单校验规则(仅保留养护员必选校验) ==========
  222 +
  223 +// ========== 表单校验规则 ==========
105 224 const workOrderFormRules = reactive({
106   - assigneeName: [
107   - {type: 'string', required: true, message: '请选择养护员', trigger: ['change']}
  225 + workLocation: [
  226 + { type: 'string', required: true, message: '请选择工单位置', trigger: ['change', 'blur'] }
108 227 ],
109   - reason: [
110   - {type: 'string', max: 200, message: '处理意见最多200字', trigger: ['change', 'blur']}
111   - ]
  228 + roadName: [
  229 + { type: 'string', required: true, message: '请选择道路名称', trigger: ['change', 'blur'] }
  230 + ],
  231 + orderName: [
  232 + { type: 'string', required: true, message: '请选择工单名称', trigger: ['change', 'blur'] }
  233 + ],
  234 + pressingTypeName: [
  235 + { type: 'string', required: true, message: '请选择紧急程度', trigger: ['change'] }
  236 + ],
  237 + problemDesc: [
  238 + { type: 'string', required: true, message: '请输入情况描述', trigger: ['change', 'blur'] },
  239 + { type: 'string', min: 3, max: 200, message: '情况描述需3-200字', trigger: ['change', 'blur'] }
  240 + ],
  241 + problemImgs: [problemImgs.imgValidateRule] // 复用上传校验规则
112 242 })
113   -// ========== 生命周期 ==========
114   -// onLoad - 获取URL中的工单编号
115   -onLoad((options) => {
116   - // 从URL参数中获取工单编号(参数名orderNo可根据实际修改)
117   - if (options && options.orderNo) {
118   - workOrderForm.orderNo = options.orderNo
119   - workOrderForm.taskId = options.taskId
120 243  
121   - }
122   - console.log('从URL获取工单编号:', workOrderForm.orderNo)
123   -})
  244 +// ========== 生命周期 ==========
124 245 onReady(() => {
125 246 // 设置表单校验规则
126 247 if (workOrderFormRef.value) {
127 248 workOrderFormRef.value.setRules(workOrderFormRules)
128 249 }
  250 + console.log('工单表单规则初始化完成')
129 251 })
  252 +
130 253 onShow(() => {
131   - // 加载养护员列表
132   - loadAssigneeList()
  254 + console.log(uni.$dict.getDictLabel('ai_image_status', 20))
  255 + console.log(uni.$dict.getDictSimpleList('work_name'))
  256 +
  257 + // 初始化工单名称列表
  258 + orderNameList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('work_name'))
  259 + console.log('工单名称列表:', orderNameList.value)
  260 +
  261 + // 初始化紧急程度列表
  262 + pressingTypeList.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('workorder_pressing_type'))
  263 + console.log('紧急程度列表:', pressingTypeList.value)
133 264 })
134   -// ========== 加载养护员列表 ==========
135   -const loadAssigneeList = async () => {
136   - try {
137   - uni.showLoading({title: '获取养护员中...'})
138   - // 调用getYlWorkersPage接口(可根据接口要求传递参数,此处默认空对象)
139   - console.log(userStore.userInfo.user.busiLine)
140   - let queryData = {
141   - // roleCode:userStore.userInfo.roles,
142   - roleCode: 'yl_worker',
143   - busiLine: userStore.userInfo.user.busiLine,
144   - pageNo: 1,
145   - pageSize: 100
146   - }
147   - const res = await getYlWorkersPage(queryData)
148   - uni.hideLoading()
149   - if (res.list.length > 0) {
150   - assigneeList.value = res.list.map(item => ({
151   - name: item.nickname,
152   - value: item.id,
153   - id: item.id
154   - }))
155   - console.log(currentActionSheetData.list)
156   - } else {
157   - uni.showToast({title: '所在班组暂无养护员,请先配置养护员', icon: 'none'})
158   - }
159   - console.log(currentActionSheetData.list)
160   - } catch (err) {
161   - uni.hideLoading()
162   - console.error('获取养护员列表失败:', err)
163   - uni.showToast({title: '获取养护员失败,请重试', icon: 'none'})
164   - assigneeList.value = []
165   - }
166   -}
  265 +
167 266 // ========== 方法定义 ==========
168 267 /**
169   - * 打开养护员下拉弹窗
  268 + * 打开通用下拉弹窗
170 269 */
171 270 const handleActionSheetOpen = (type) => {
172   - // 判断养护员列表是否为空
173   - if (type === 'assignee' && assigneeList.value.length === 0) {
174   - uni.showToast({title: '暂无养护员数据可选', icon: 'none'})
  271 + // 道路名称需先校验工单位置是否选择
  272 + if (type === 'roadName' && !workOrderForm.workLocation) {
  273 + uni.showToast({ title: '请先选择工单位置', icon: 'none' })
175 274 return
176 275 }
177   - // 配置弹窗参数
  276 +
  277 + // 配置当前弹窗参数
178 278 const configMap = {
179   - assignee: {
180   - title: '请选择养护员',
181   - list: assigneeList.value
  279 + roadName: {
  280 + title: '请选择道路名称',
  281 + list: roadNameList.value
  282 + },
  283 + orderName: {
  284 + title: '请选择工单名称',
  285 + list: orderNameList.value
  286 + },
  287 + pressingType: {
  288 + title: '请选择紧急程度',
  289 + list: pressingTypeList.value
182 290 }
183 291 }
  292 +
184 293 currentActionSheetData.type = type
185 294 currentActionSheetData.title = configMap[type].title
186 295 currentActionSheetData.list = configMap[type].list
187 296 showActionSheet.value = true
188 297 }
  298 +
189 299 /**
190   - * 关闭下拉弹窗
  300 + * 关闭通用下拉弹窗
191 301 */
192 302 const handleActionSheetClose = () => {
193 303 showActionSheet.value = false
  304 + // 重置当前弹窗配置
194 305 currentActionSheetData.type = ''
195 306 currentActionSheetData.list = []
196 307 currentActionSheetData.title = ''
197 308 }
  309 +
198 310 /**
199   - * 养护员选择事件
  311 + * 通用下拉弹窗选择事件
200 312 */
201 313 const handleActionSheetSelect = (e) => {
202   - const {type} = currentActionSheetData
203   - if (type === 'assignee') {
204   - workOrderForm.assigneeName = e.name
205   - workOrderForm.assigneeId = e.value // 绑定养护员ID
206   - workOrderFormRef.value?.validateField('assigneeName')
  314 + const { type } = currentActionSheetData
  315 + // 根据类型处理不同的选择逻辑
  316 + switch (type) {
  317 + case 'roadName':
  318 + workOrderForm.roadName = e.name
  319 + workOrderForm.roadId = e.code
  320 + workOrderFormRef.value?.validateField('roadName')
  321 + break
  322 + case 'orderName':
  323 + workOrderForm.orderName = e.name
  324 + workOrderFormRef.value?.validateField('orderName')
  325 + break
  326 + case 'pressingType':
  327 + console.log(e)
  328 + workOrderForm.pressingType =e.value
  329 + workOrderForm.pressingTypeName = e.name
  330 + workOrderFormRef.value?.validateField('pressingType')
  331 + break
207 332 }
  333 + // 关闭弹窗
208 334 showActionSheet.value = false
209 335 }
  336 +
  337 +/**
  338 + * 返回上一页
  339 + */
  340 +const navigateBack = () => {
  341 + uni.navigateBack()
  342 +}
  343 +
  344 +/**
  345 + * 选择工单位置
  346 + */
  347 +const chooseWorkLocation = () => {
  348 + uni.chooseLocation({
  349 + success: async (res) => {
  350 + workOrderForm.roadName = ''
  351 + workOrderForm.roadId = 0
  352 + roadNameList.value = []
  353 +
  354 + workOrderForm.workLocation = res.name
  355 + workOrderForm.lat = res.latitude
  356 + workOrderForm.lon = res.longitude
  357 +
  358 + workOrderFormRef.value?.validateField('workLocation')
  359 + workOrderFormRef.value?.validateField('roadName')
  360 +
  361 + try {
  362 + uni.showLoading({ title: '获取道路名称中...' })
  363 + const roadRes = await getRoadListByLatLng({
  364 + companyCode: 'sls',
  365 + latitude: res.latitude,
  366 + longitude: res.longitude
  367 + })
  368 + uni.hideLoading()
  369 +
  370 + if (Array.isArray(roadRes)) {
  371 + roadNameList.value = roadRes.map((item) => ({
  372 + name: item.roadName || '',
  373 + code: item.roadCode || '',
  374 + id: item.roadId || 0
  375 + }))
  376 + } else {
  377 + roadNameList.value = [{ name: '未查询到道路名称', code: '', id: 0 }]
  378 + uni.showToast({ title: '未查询到该位置的道路信息', icon: 'none' })
  379 + }
  380 + } catch (err) {
  381 + uni.hideLoading()
  382 + console.error('获取道路名称失败:', err)
  383 + uni.showToast({ title: '获取道路名称失败,请重试', icon: 'none' })
  384 + roadNameList.value = [{ name: '获取失败,请重新选择位置', code: '', id: 0 }]
  385 + }
  386 + },
  387 + fail: (err) => {
  388 + console.error('选择位置失败:', err)
  389 + uni.showToast({ title: '选择位置失败:' + err.errMsg, icon: 'none' })
  390 + }
  391 + })
  392 +}
  393 +
  394 +/**
  395 + * 完成时间确认
  396 + */
  397 +const finishDateConfirm = (e) => {
  398 + console.log('选择的完成时间:', e)
  399 + workOrderForm.finishDate = timeFormat(e.value, 'yyyy-mm-dd hh:MM:ss')
  400 + show.value = false
  401 +}
  402 +
210 403 /**
211 404 * 隐藏键盘
212 405 */
213 406 const hideKeyboard = () => {
214 407 uni.hideKeyboard()
215 408 }
  409 +
216 410 /**
217   - * 提交数据(使用ylTeamLeaderAssignWOrder接口,传递指定参数)
  411 + * 提交工单
218 412 */
219 413 const submitWorkOrder = async () => {
220 414 try {
221   - // 1. 表单校验(先校验养护员必选项)
  415 + // 先执行表单校验
222 416 await workOrderFormRef.value.validate()
223   - // 2. 校验工单编号是否存在(避免无工单编号提交)
224   - if (!workOrderForm.orderNo) {
225   - uni.showToast({title: '工单编号不能为空', icon: 'none'})
226   - return
227   - }
228   - // 3. 构造接口所需参数
  417 +
229 418 const submitData = {
230   - id: workOrderForm.taskId, // 工单编码(对应接口参数id)
231   - reason: workOrderForm.reason.trim(), // 处理建议(对应接口参数reason)
232   - nextAssignee: workOrderForm.assigneeId // 养护员ID(对应接口参数nextAssignee)
  419 + roadId: workOrderForm.roadId,
  420 + roadName: workOrderForm.roadName,
  421 + imgs: problemImgs.getSuccessImgUrls(), // 复用上传逻辑的URL获取方法
  422 + remark: workOrderForm.problemDesc.trim(),
  423 + latLonType: 2,
  424 + lat: workOrderForm.lat,
  425 + lon: workOrderForm.lon,
  426 + lonLatAddress: workOrderForm.workLocation,
  427 + pressingType: workOrderForm.pressingType,
  428 + orderName: workOrderForm.orderName,
  429 + finishDate: workOrderForm.finishDate,
  430 + sourceId: 1,
  431 + sourceName: '园林',
  432 + busiLine: 'yl'
233 433 }
234   - console.log('提交参数:', submitData)
235   - // 4. 显示加载提示
236   - uni.showLoading({title: '提交中...'})
237   - // 5. 调用指定接口 ylTeamLeaderAssignWOrder
238   - const res = await ylTeamLeaderAssignWOrder(submitData)
239   - // 6. 隐藏加载提示并给出成功反馈
  434 +
  435 + // 显示加载中
  436 + uni.showLoading({ title: '提交中...' })
  437 +
  438 + // 调用提交接口
  439 + const res = await workorderCreate(submitData)
  440 +
240 441 uni.hideLoading()
241 442 uni.showToast({
242   - title: '提交成功',
  443 + title: '工单提交成功',
243 444 icon: 'success',
244 445 duration: 1000
245 446 })
246   - // 7. 提交成功后返回上一页
  447 +
  448 + // 延迟跳转
247 449 setTimeout(() => {
248   - uni.navigateTo({
249   - url: `/pages-sub/problem/work-order-manage/index`
  450 + uni.redirectTo({
  451 + url: '/pages-sub/problem/work-order-manage/index'
250 452 })
251 453 }, 1000)
252 454 } catch (error) {
253   - // 隐藏加载提示
  455 + // 隐藏加载
254 456 uni.hideLoading()
255   - // 区分表单校验失败和接口调用失败
  457 +
  458 + // 区分是表单校验失败还是接口调用失败
256 459 if (!Array.isArray(error)) {
257   - console.error('提交失败:', error)
  460 + // 接口调用失败
  461 + console.error('工单提交失败:', error)
258 462 uni.showToast({
259 463 title: '提交失败,请重试',
260 464 icon: 'none',
... ... @@ -268,14 +472,13 @@ const submitWorkOrder = async () =&gt; {
268 472 <style lang="scss" scoped>
269 473 // 全局页面样式
270 474 .page-container {
271   -
  475 + min-height: 100vh;
  476 + padding-bottom: 100rpx; // 给底部按钮留空间
272 477 }
273 478  
274   -// 表单内容容器
  479 +// 工单表单内容容器
275 480 .work-order-form-content {
276 481 background: #fff;
277   - margin-top: 10rpx;
278 482 }
279 483  
280   -
281 484 </style>
282 485 \ No newline at end of file
... ...
pages-sub/problem/work-order-manage/distribution-order.vue 0 → 100644
  1 +<template>
  2 + <view class="page-container">
  3 + <view class="work-order-form-content commonPageLRpadding">
  4 + <up-form
  5 + label-position="left"
  6 + :model="workOrderForm"
  7 + ref="workOrderFormRef"
  8 + labelWidth="190rpx"
  9 + >
  10 + <!-- 1. 工单编号(从URL获取展示) -->
  11 + <up-form-item
  12 + label="工单编号"
  13 + border-bottom
  14 + >
  15 + <up-input
  16 + v-model="workOrderForm.orderNo"
  17 + border="none"
  18 + readonly
  19 + placeholder="暂无工单编号"
  20 + ></up-input>
  21 + </up-form-item>
  22 +
  23 + <!-- 2. 养护员选择(必选,下拉框) -->
  24 + <up-form-item
  25 + label="养护员"
  26 + prop="assigneeName"
  27 + border-bottom
  28 + required
  29 + @click="handleActionSheetOpen('assignee'); hideKeyboard()"
  30 + >
  31 + <up-input
  32 + v-model="workOrderForm.assigneeName"
  33 + disabled
  34 + disabled-color="#ffffff"
  35 + placeholder="请选择养护员"
  36 + border="none"
  37 + ></up-input>
  38 + <template #right>
  39 + <up-icon name="arrow-right" size="16"></up-icon>
  40 + </template>
  41 + </up-form-item>
  42 +
  43 + <!-- 3. 处理意见(非必填,文本域) -->
  44 + <up-form-item
  45 + label="处理意见"
  46 + prop="reason"
  47 + >
  48 + <up-textarea
  49 + placeholder="请输入处理意见(可选,最多200字)"
  50 + v-model.trim="workOrderForm.reason"
  51 + count
  52 + maxlength="200"
  53 + rows="4"
  54 + ></up-textarea>
  55 + </up-form-item>
  56 + </up-form>
  57 + </view>
  58 +
  59 + <!-- 底部提交按钮 -->
  60 + <view class="fixed-bottom-btn-wrap">
  61 + <up-button
  62 + type="primary"
  63 + text="提交"
  64 + @click="submitWorkOrder"
  65 + ></up-button>
  66 + </view>
  67 +
  68 + <!-- 养护员下拉弹窗 -->
  69 + <up-action-sheet
  70 + :show="showActionSheet"
  71 + :actions="currentActionSheetData.list"
  72 + :title="currentActionSheetData.title"
  73 + @close="handleActionSheetClose"
  74 + @select="handleActionSheetSelect"
  75 + ></up-action-sheet>
  76 + </view>
  77 +</template>
  78 +
  79 +<script setup>
  80 +import { ref, reactive } from 'vue'
  81 +import { onLoad, onReady, onShow } from '@dcloudio/uni-app';
  82 +import { getYlWorkersPage, ylTeamLeaderAssignWOrder } from '@/api/work-order-manage/work-order-manage'
  83 +import { useUserStore } from '@/pinia/user';
  84 +const userStore = useUserStore();
  85 +// ========== 表单Ref ==========
  86 +const workOrderFormRef = ref(null)
  87 +// ========== 页面状态 ==========
  88 +const showActionSheet = ref(false)
  89 +const currentActionSheetData = reactive({
  90 + type: '',
  91 + list: [],
  92 + title: ''
  93 +})
  94 +// ========== 下拉列表数据 ==========
  95 +const assigneeList = ref([]) // 养护员列表
  96 +// ========== 工单表单数据(仅保留所需字段) ==========
  97 +const workOrderForm = reactive({
  98 + taskId:'',
  99 + orderNo: '', // 工单编号(对应接口参数id)
  100 + assigneeId: '', // 养护员ID(对应接口参数nextAssignee)
  101 + assigneeName: '', // 养护员名称(显示用)
  102 + reason: '' // 处理意见(对应接口参数reason)
  103 +})
  104 +// ========== 表单校验规则(仅保留养护员必选校验) ==========
  105 +const workOrderFormRules = reactive({
  106 + assigneeName: [
  107 + {type: 'string', required: true, message: '请选择养护员', trigger: ['change']}
  108 + ],
  109 + reason: [
  110 + {type: 'string', max: 200, message: '处理意见最多200字', trigger: ['change', 'blur']}
  111 + ]
  112 +})
  113 +// ========== 生命周期 ==========
  114 +// onLoad - 获取URL中的工单编号
  115 +onLoad((options) => {
  116 + // 从URL参数中获取工单编号(参数名orderNo可根据实际修改)
  117 + if (options && options.orderNo) {
  118 + workOrderForm.orderNo = options.orderNo
  119 + workOrderForm.taskId = options.taskId
  120 +
  121 + }
  122 + console.log('从URL获取工单编号:', workOrderForm.orderNo)
  123 +})
  124 +onReady(() => {
  125 + // 设置表单校验规则
  126 + if (workOrderFormRef.value) {
  127 + workOrderFormRef.value.setRules(workOrderFormRules)
  128 + }
  129 +})
  130 +onShow(() => {
  131 + // 加载养护员列表
  132 + loadAssigneeList()
  133 +})
  134 +// ========== 加载养护员列表 ==========
  135 +const loadAssigneeList = async () => {
  136 + try {
  137 + uni.showLoading({title: '获取养护员中...'})
  138 + // 调用getYlWorkersPage接口(可根据接口要求传递参数,此处默认空对象)
  139 + console.log(userStore.userInfo.user.busiLine)
  140 + let queryData = {
  141 + // roleCode:userStore.userInfo.roles,
  142 + roleCode: 'yl_worker',
  143 + busiLine: 'yl',
  144 + // busiLine: userStore.userInfo.user.busiLine,
  145 + pageNo: 1,
  146 + pageSize: 100
  147 + }
  148 + const res = await getYlWorkersPage(queryData)
  149 + uni.hideLoading()
  150 + if (res.list.length > 0) {
  151 + assigneeList.value = res.list.map(item => ({
  152 + name: item.nickname,
  153 + value: item.id,
  154 + id: item.id
  155 + }))
  156 + console.log(currentActionSheetData.list)
  157 + } else {
  158 + uni.showToast({title: '所在班组暂无养护员,请先配置养护员', icon: 'none'})
  159 + }
  160 + console.log(currentActionSheetData.list)
  161 + } catch (err) {
  162 + uni.hideLoading()
  163 + console.error('获取养护员列表失败:', err)
  164 + uni.showToast({title: '获取养护员失败,请重试', icon: 'none'})
  165 + assigneeList.value = []
  166 + }
  167 +}
  168 +// ========== 方法定义 ==========
  169 +/**
  170 + * 打开养护员下拉弹窗
  171 + */
  172 +const handleActionSheetOpen = (type) => {
  173 + // 判断养护员列表是否为空
  174 + if (type === 'assignee' && assigneeList.value.length === 0) {
  175 + uni.showToast({title: '暂无养护员数据可选', icon: 'none'})
  176 + return
  177 + }
  178 + // 配置弹窗参数
  179 + const configMap = {
  180 + assignee: {
  181 + title: '请选择养护员',
  182 + list: assigneeList.value
  183 + }
  184 + }
  185 + currentActionSheetData.type = type
  186 + currentActionSheetData.title = configMap[type].title
  187 + currentActionSheetData.list = configMap[type].list
  188 + showActionSheet.value = true
  189 +}
  190 +/**
  191 + * 关闭下拉弹窗
  192 + */
  193 +const handleActionSheetClose = () => {
  194 + showActionSheet.value = false
  195 + currentActionSheetData.type = ''
  196 + currentActionSheetData.list = []
  197 + currentActionSheetData.title = ''
  198 +}
  199 +/**
  200 + * 养护员选择事件
  201 + */
  202 +const handleActionSheetSelect = (e) => {
  203 + const {type} = currentActionSheetData
  204 + if (type === 'assignee') {
  205 + workOrderForm.assigneeName = e.name
  206 + workOrderForm.assigneeId = e.value // 绑定养护员ID
  207 + workOrderFormRef.value?.validateField('assigneeName')
  208 + }
  209 + showActionSheet.value = false
  210 +}
  211 +/**
  212 + * 隐藏键盘
  213 + */
  214 +const hideKeyboard = () => {
  215 + uni.hideKeyboard()
  216 +}
  217 +/**
  218 + * 提交数据(使用ylTeamLeaderAssignWOrder接口,传递指定参数)
  219 + */
  220 +const submitWorkOrder = async () => {
  221 + try {
  222 + // 1. 表单校验(先校验养护员必选项)
  223 + await workOrderFormRef.value.validate()
  224 + // 2. 校验工单编号是否存在(避免无工单编号提交)
  225 + if (!workOrderForm.orderNo) {
  226 + uni.showToast({title: '工单编号不能为空', icon: 'none'})
  227 + return
  228 + }
  229 + // 3. 构造接口所需参数
  230 + const submitData = {
  231 + id: workOrderForm.taskId, // 工单编码(对应接口参数id)
  232 + reason: workOrderForm.reason.trim(), // 处理建议(对应接口参数reason)
  233 + nextAssignee: workOrderForm.assigneeId // 养护员ID(对应接口参数nextAssignee)
  234 + }
  235 + console.log('提交参数:', submitData)
  236 + // 4. 显示加载提示
  237 + uni.showLoading({title: '提交中...'})
  238 + // 5. 调用指定接口 ylTeamLeaderAssignWOrder
  239 + const res = await ylTeamLeaderAssignWOrder(submitData)
  240 + // 6. 隐藏加载提示并给出成功反馈
  241 + uni.hideLoading()
  242 + uni.showToast({
  243 + title: '提交成功',
  244 + icon: 'success',
  245 + duration: 1000
  246 + })
  247 + // 7. 提交成功后返回上一页
  248 + setTimeout(() => {
  249 + uni.navigateTo({
  250 + url: `/pages-sub/problem/work-order-manage/index`
  251 + })
  252 + }, 1000)
  253 + } catch (error) {
  254 + // 隐藏加载提示
  255 + uni.hideLoading()
  256 + // 区分表单校验失败和接口调用失败
  257 + if (!Array.isArray(error)) {
  258 + console.error('提交失败:', error)
  259 + uni.showToast({
  260 + title: '提交失败,请重试',
  261 + icon: 'none',
  262 + duration: 2000
  263 + })
  264 + }
  265 + }
  266 +}
  267 +</script>
  268 +
  269 +<style lang="scss" scoped>
  270 +// 全局页面样式
  271 +.page-container {
  272 +
  273 +}
  274 +
  275 +// 表单内容容器
  276 +.work-order-form-content {
  277 + background: #fff;
  278 + margin-top: 10rpx;
  279 +}
  280 +
  281 +
  282 +</style>
0 283 \ No newline at end of file
... ...
pages-sub/problem/work-order-manage/index.vue
... ... @@ -307,7 +307,7 @@ const handleProcess = async (item) =&gt; {
307 307  
308 308 if(nextStepMap[item.taskKey] == '养护组长分配'){
309 309 uni.navigateTo({
310   - url: `/pages-sub/problem/work-order-manage/add-order?taskId=${item.taskId}&orderNo=${item.orderNo}`
  310 + url: `/pages-sub/problem/work-order-manage/distribution-order?taskId=${item.taskId}&orderNo=${item.orderNo}`
311 311 })
312 312 }
313 313  
... ...
pages-sub/problem/work-order-manage/order-detail.vue
... ... @@ -121,8 +121,8 @@
121 121 </template>
122 122  
123 123 <script setup lang="ts">
124   -import { ref, reactive, computed } from 'vue';
125   -import { onLoad } from '@dcloudio/uni-app';
  124 +import { ref, computed } from 'vue';
  125 +import { onLoad, onShow } from '@dcloudio/uni-app';
126 126 import { timeFormat } from '@/uni_modules/uview-plus';
127 127 import { getMyTaskDetail, getDoneTaskDetail, getTodoTaskDetail } from '@/api/work-order-manage/work-order-manage';
128 128  
... ... @@ -165,12 +165,27 @@ const getCurrentImgList = computed(() =&gt; {
165 165 /**
166 166 * 获取工单详情
167 167 */
168   -const getMyTaskDetailQuery = async (taskId) => {
  168 +const DetailQuery = async (taskIdStr) => {
  169 + console.log(taskIdStr)
169 170 try {
170 171 loading.value = true;
171   - const res = await getMyTaskDetail({ taskId });
172   - console.log('工单详情接口返回:', res);
173   - orderDetail.value = res
  172 + if(activeTab.value==0){
  173 +
  174 + const res = await getTodoTaskDetail({ taskId:taskIdStr });
  175 + orderDetail.value = res
  176 + }
  177 + if(activeTab.value==1){
  178 +
  179 + const res = await getMyTaskDetail({ taskId: taskIdStr });
  180 + orderDetail.value = res
  181 +
  182 + }
  183 + if(activeTab.value==2){
  184 +
  185 + const res = await getDoneTaskDetail({ taskId: taskIdStr });
  186 + orderDetail.value = res
  187 + }
  188 +
174 189  
175 190 } catch (error) {
176 191 console.error('获取工单详情失败:', error);
... ... @@ -181,22 +196,20 @@ const getMyTaskDetailQuery = async (taskId) =&gt; {
181 196 };
182 197  
183 198 // 页面加载
  199 +const taskId = ref('')
  200 +const activeTab = ref('')
184 201 onLoad((options) => {
185 202 console.log(options)
186   - const { taskId, activeTab } = options;
  203 + const { taskId: taskIdOpt, activeTab: activeTabOpt } = options;
187 204 // 0-待办 1我发起的- 2-已办
188   - console.log(taskId)
189   - if(activeTab==0){
190   - getTodoTaskDetail(taskId);
191   - }
192   - if(activeTab==1){
193   - getMyTaskDetailQuery(taskId);
  205 + console.log(taskIdOpt)
  206 + taskId.value = taskIdOpt
  207 + activeTab.value = activeTabOpt
194 208  
195   - }
196   - if(activeTab==2){
197   - getDoneTaskDetail(taskId);
198   - }
199 209 });
  210 +onShow(()=>{
  211 + DetailQuery(taskId.value)
  212 +})
200 213 </script>
201 214  
202 215 <style scoped lang="scss">
... ...
pages.json
... ... @@ -126,10 +126,17 @@
126 126 },
127 127 {
128 128 "path": "work-order-manage/add-order",
129   - "style": { "navigationBarTitleText": "工单提交" }
  129 + "style": { "navigationBarTitleText": "工单任务" }
130 130 },
131 131  
132 132 {
  133 + "path": "work-order-manage/distribution-order",
  134 + "style": { "navigationBarTitleText": "分配工单" }
  135 + },
  136 +
  137 +
  138 +
  139 + {
133 140 "path": "work-order-manage/order-detail",
134 141 "style": { "navigationBarTitleText": "工单详情" }
135 142 },
... ...