miaofuhao 3 gün önce
ebeveyn
işleme
26e8039af0

+ 417 - 83
apps/web-ele/src/views/workflow/components/actions/flow-actions.vue

@@ -3,19 +3,21 @@ import type { ApprovalType } from '../type';
3 3
 
4 4
 import type { TaskInfo } from '#/api/workflow/task/model';
5 5
 
6
-import { computed, ref } from 'vue';
6
+import { computed, ref, reactive } from 'vue';
7 7
 
8 8
 import { cn } from '@vben/utils';
9 9
 
10
-import { ElButton, ElDrawer, ElMessageBox, ElSpace } from 'element-plus';
10
+import { UploadFilled } from '@element-plus/icons-vue';
11
+import { ElButton, ElDrawer, ElForm, ElFormItem, ElInput, ElMessage, ElUpload, ElMessageBox, ElSpace, ElTreeSelect, ElSelect, ElOption } from 'element-plus';
11 12
 
12 13
 import {
13 14
   backProcess,
14
-  completeTask,
15 15
   deleteOrder,
16 16
   submitOrder,
17 17
   taskOperation,
18 18
 } from '#/api/workflow/task';
19
+import { requestClient } from '#/api/request';
20
+import { getSingleImageUploadConfig } from '#/components/upload/config';
19 21
 import CreatOrder from '#/views/workflow/order/creatOrder.vue';
20 22
 
21 23
 interface Props {
@@ -24,6 +26,10 @@ interface Props {
24 26
    */
25 27
   task?: TaskInfo;
26 28
   /**
29
+   * 工单详情
30
+   */
31
+  workOrderDetail?: any;
32
+  /**
27 33
    * 审批类型 根据不同类型显示按钮
28 34
    */
29 35
   type: ApprovalType;
@@ -56,6 +62,36 @@ const editableAndRemoveable = computed(() => {
56 62
 const drawerVisible = ref(false);
57 63
 const drawerId = ref<string>('');
58 64
 
65
+// 处理工单的抽屉
66
+const handleDrawerVisible = ref(false);
67
+const handleFormData = reactive({
68
+  attachments: '',
69
+  processContent: '',
70
+  taskId: '',
71
+});
72
+const handleFileList = ref([]);
73
+
74
+// 延时申请的抽屉
75
+const delayDrawerVisible = ref(false);
76
+const delayFormData = reactive({
77
+  applyFile: '',
78
+  delayDuration: 0,
79
+  delayReason: '',
80
+  taskId: 0,
81
+});
82
+const delayFileList = ref([]);
83
+
84
+// 抄送的抽屉
85
+const ccDrawerVisible = ref(false);
86
+const ccFormData = reactive({
87
+  ccUserIds: '',
88
+  taskId: 0,
89
+});
90
+const deptTree = ref([]);
91
+const userList = ref([]);
92
+const selectedDeptId = ref('');
93
+const selectedUsers = ref([]);
94
+
59 95
 // 编辑
60 96
 const handleEdit = () => {
61 97
   drawerId.value = props.task!.id;
@@ -80,6 +116,72 @@ const handleDrawerClosed = () => {
80 116
   drawerId.value = '';
81 117
 };
82 118
 
119
+// 上传成功回调
120
+const handleUploadSuccess = (response, file, fileList) => {
121
+  if (response.code === 200) {
122
+    // 将文件路径添加到attachments字段
123
+    const paths = fileList.map((f) => f.response.data.fileName).join(',');
124
+    handleFormData.attachments = paths;
125
+  } else {
126
+    ElMessage.error('文件上传失败');
127
+  }
128
+};
129
+
130
+// 上传失败回调
131
+const handleUploadError = (error) => {
132
+  ElMessage.error('文件上传失败');
133
+  console.error('文件上传失败:', error);
134
+};
135
+
136
+// 移除文件回调
137
+const handleFileRemove = (file, fileList) => {
138
+  // 更新attachments字段(文件名)
139
+  const fileNames = fileList.map((f) => f.response.data.fileName).join(',');
140
+  handleFormData.attachments = fileNames;
141
+};
142
+
143
+// 延时申请上传成功回调
144
+const handleDelayUploadSuccess = (response, file, fileList) => {
145
+  if (response.code === 200) {
146
+    // 将文件路径添加到applyFile字段
147
+    const paths = fileList.map((f) => f.response.data.fileName).join(',');
148
+    delayFormData.applyFile = paths;
149
+  } else {
150
+    ElMessage.error('附件上传失败');
151
+  }
152
+};
153
+
154
+// 延时申请移除文件回调
155
+const handleDelayFileRemove = (file, fileList) => {
156
+  // 更新applyFile字段(文件名)
157
+  const fileNames = fileList.map((f) => f.response.data.fileName).join(',');
158
+  delayFormData.applyFile = fileNames;
159
+};
160
+
161
+// 处理工单提交
162
+async function handleSubmitForm() {
163
+  try {
164
+    // 验证处理内容
165
+    if (!handleFormData.processContent.trim()) {
166
+      ElMessage.error('请输入处理内容');
167
+      return;
168
+    }
169
+
170
+    // 调用处理接口
171
+    await requestClient.put('/workOrder/order/handle', handleFormData);
172
+    ElMessage.success('工单处理成功');
173
+
174
+    // 关闭抽屉
175
+    handleDrawerVisible.value = false;
176
+
177
+    // 重新加载数据
178
+    emit('reload');
179
+  } catch (error) {
180
+    ElMessage.error('工单处理失败');
181
+    console.error('工单处理失败:', error);
182
+  }
183
+}
184
+
83 185
 // 删除
84 186
 function handleRemove() {
85 187
   ElMessageBox.confirm('确定删除该工单吗?', '提示', {
@@ -87,8 +189,7 @@ function handleRemove() {
87 189
     cancelButtonText: '取消',
88 190
     type: 'warning',
89 191
     center: true,
90
-  })
91
-    .then(async () => {
192
+  }).then(async () => {
92 193
       await deleteOrder([props.task!.id]);
93 194
       emit('reload');
94 195
     })
@@ -116,71 +217,148 @@ async function handleSubmit() {
116 217
 }
117 218
 
118 219
 // 处理
119
-async function handleApprove() {
220
+function handleApprove() {
221
+  // 重置表单数据
222
+  handleFormData.attachments = '';
223
+  handleFormData.processContent = '';
224
+  handleFormData.taskId = props.task!.taskId;
225
+  handleFileList.value = [];
226
+  
227
+  // 打开抽屉
228
+  handleDrawerVisible.value = true;
229
+}
230
+
231
+// 延时
232
+function handleDelay() {
233
+  // 重置表单数据
234
+  delayFormData.taskId = props.task!.taskId;
235
+  delayFormData.applyFile = '';
236
+  delayFormData.delayDuration = 0;
237
+  delayFormData.delayReason = '';
238
+  delayFileList.value = [];
239
+  
240
+  // 打开抽屉
241
+  delayDrawerVisible.value = true;
242
+}
243
+
244
+// 抄送
245
+function handleCopy() {
246
+  // 重置表单数据
247
+  ccFormData.taskId = props.task!.taskId;
248
+  ccFormData.ccUserIds = '';
249
+  selectedDeptId.value = '';
250
+  selectedUsers.value = [];
251
+  userList.value = [];
252
+  
253
+  // 加载部门树
254
+  loadDeptTree();
255
+  
256
+  // 打开抽屉
257
+  ccDrawerVisible.value = true;
258
+}
259
+
260
+// 加载部门树
261
+async function loadDeptTree() {
120 262
   try {
121
-    await ElMessageBox.confirm('确定要处理该工单吗?', '提示', {
122
-      confirmButtonText: '确定',
123
-      cancelButtonText: '取消',
124
-      type: 'warning',
125
-      center: true,
126
-    });
127
-    await completeTask({
128
-      taskId: props.task!.taskId,
129
-      taskVariables: {},
130
-      variables: {},
131
-      assigneeMap: {},
132
-      messageType: [],
133
-      flowCopyList: [],
134
-    });
135
-    emit('reload');
136
-  } catch {
137
-    // 用户取消操作,不做任何处理
138
-    console.log('用户取消了处理操作');
263
+    const response = await requestClient.get('/system/user/deptTree');
264
+    if (response.code === 200) {
265
+      deptTree.value = response.data;
266
+    } else {
267
+      ElMessage.error('加载部门树失败');
268
+    }
269
+  } catch (error) {
270
+    ElMessage.error('加载部门树失败');
271
+    console.error('加载部门树失败:', error);
139 272
   }
140 273
 }
141 274
 
142
-// 延时
143
-async function handleDelay() {
275
+// 加载人员列表
276
+async function loadUserList(deptId) {
144 277
   try {
145
-    await ElMessageBox.confirm('确定要延时处理该工单吗?', '提示', {
146
-      confirmButtonText: '确定',
147
-      cancelButtonText: '取消',
148
-      type: 'warning',
149
-      center: true,
150
-    });
151
-    await taskOperation(
152
-      {
153
-        taskId: props.task!.taskId,
154
-      },
155
-      'delegateTask',
156
-    );
278
+    const response = await requestClient.get(`/system/user/list?deptId=${deptId}&pageNum=1&pageSize=20`);
279
+    if (response.code === 200) {
280
+      userList.value = response.data.list || [];
281
+    } else {
282
+      ElMessage.error('加载人员列表失败');
283
+    }
284
+  } catch (error) {
285
+    ElMessage.error('加载人员列表失败');
286
+    console.error('加载人员列表失败:', error);
287
+  }
288
+}
289
+
290
+// 部门选择变化回调
291
+async function handleDeptChange(deptId) {
292
+  if (deptId) {
293
+    // 加载该部门下的人员
294
+    await loadUserList(deptId);
295
+  } else {
296
+    // 清空人员列表和选择
297
+    userList.value = [];
298
+    selectedUsers.value = [];
299
+    ccFormData.ccUserIds = '';
300
+  }
301
+}
302
+
303
+// 人员选择变化回调
304
+function handleUserChange(users) {
305
+  // 更新ccUserIds字段(用逗号分隔)
306
+  ccFormData.ccUserIds = users.join(',');
307
+}
308
+
309
+// 延时申请提交
310
+async function handleDelaySubmit() {
311
+  try {
312
+    // 验证表单
313
+    if (!delayFormData.delayReason.trim()) {
314
+      ElMessage.error('请输入延时原因');
315
+      return;
316
+    }
317
+    if (!delayFormData.delayDuration || delayFormData.delayDuration < 1) {
318
+      ElMessage.error('请输入有效的延时时长(至少1小时)');
319
+      return;
320
+    }
321
+    
322
+    // 调用延时API
323
+    await requestClient.put('/workOrder/order/delay', delayFormData);
324
+    ElMessage.success('延时申请提交成功');
325
+    
326
+    // 关闭抽屉
327
+    delayDrawerVisible.value = false;
328
+    
329
+    // 重新加载数据
157 330
     emit('reload');
158
-  } catch {
159
-    // 用户取消操作,不做任何处理
160
-    console.log('用户取消了延时操作');
331
+  } catch (error) {
332
+    ElMessage.error('延时申请提交失败');
333
+    console.error('延时申请失败:', error);
161 334
   }
162 335
 }
163 336
 
164
-// 抄送
165
-async function handleCopy() {
337
+// 抄送提交
338
+async function handleCCSubmit() {
166 339
   try {
167
-    await ElMessageBox.confirm('确定要抄送该工单吗?', '提示', {
168
-      confirmButtonText: '确定',
169
-      cancelButtonText: '取消',
170
-      type: 'warning',
171
-      center: true,
172
-    });
173
-    await taskOperation(
174
-      {
175
-        taskId: props.task!.taskId,
176
-        userIds: [],
177
-      },
178
-      'addSignature',
179
-    );
340
+    // 验证表单
341
+    if (!selectedDeptId.value) {
342
+      ElMessage.error('请选择部门');
343
+      return;
344
+    }
345
+    if (!selectedUsers.value || selectedUsers.value.length === 0) {
346
+      ElMessage.error('请选择人员');
347
+      return;
348
+    }
349
+    
350
+    // 调用抄送API
351
+    await requestClient.put('/workOrder/order/cc', ccFormData);
352
+    ElMessage.success('抄送成功');
353
+    
354
+    // 关闭抽屉
355
+    ccDrawerVisible.value = false;
356
+    
357
+    // 重新加载数据
180 358
     emit('reload');
181
-  } catch {
182
-    // 用户取消操作,不做任何处理
183
-    console.log('用户取消了抄送操作');
359
+  } catch (error) {
360
+    ElMessage.error('抄送失败');
361
+    console.error('抄送失败:', error);
184 362
   }
185 363
 }
186 364
 
@@ -203,21 +381,9 @@ async function handleBack() {
203 381
   }
204 382
 }
205 383
 
206
-// 获取可用按钮
207
-const availableButtons = computed(() => {
208
-  if (!props.task || !props.task.button) {
209
-    return [];
210
-  }
211
-  return props.task.button.split(',');
212
-});
213 384
 
214
-// 检查按钮是否显示
215
-const showButton = (buttonType: string) => {
216
-  // 同时检查 availableButtons 和 buttonPermissions
217
-  const isInButtonList = availableButtons.value.includes(buttonType);
218
-  const hasPermission = !props.buttonPermissions || props.buttonPermissions[buttonType] !== false;
219
-  return isInButtonList && hasPermission;
220
-};
385
+
386
+
221 387
 </script>
222 388
 
223 389
 <template>
@@ -234,7 +400,6 @@ const showButton = (buttonType: string) => {
234 400
       <ElSpace v-if="type === 'myself'">
235 401
         <ElButton
236 402
           type="primary"
237
-          text
238 403
           v-if="buttonPermissions?.edit || editableAndRemoveable"
239 404
           @click="handleEdit"
240 405
         >
@@ -242,9 +407,7 @@ const showButton = (buttonType: string) => {
242 407
         </ElButton>
243 408
         <ElButton
244 409
           v-if="buttonPermissions?.delete || editableAndRemoveable"
245
-          danger
246
-          text
247
-          type="primary"
410
+          type="danger"
248 411
           @click="handleRemove"
249 412
         >
250 413
           删除
@@ -253,7 +416,6 @@ const showButton = (buttonType: string) => {
253 416
         <ElButton
254 417
           v-if="buttonPermissions?.submit"
255 418
           type="primary"
256
-          text
257 419
           @click="handleSubmit"
258 420
         >
259 421
           提交
@@ -263,23 +425,23 @@ const showButton = (buttonType: string) => {
263 425
       <!-- 审批操作按钮 -->
264 426
       <ElSpace v-if="type === 'waiting'">
265 427
         <ElButton
266
-          v-if="showButton('handle')"
428
+          v-if="buttonPermissions?.handle"
267 429
           type="primary"
268 430
           @click="handleApprove"
269 431
         >
270 432
           处理
271 433
         </ElButton>
272 434
         <ElButton
273
-          v-if="showButton('delay')"
435
+          v-if="buttonPermissions?.delay"
274 436
           type="warning"
275 437
           @click="handleDelay"
276 438
         >
277 439
           延时
278 440
         </ElButton>
279
-        <ElButton v-if="showButton('cc')" type="info" @click="handleCopy">
441
+        <ElButton v-if="buttonPermissions?.cc" type="info" @click="handleCopy">
280 442
           抄送
281 443
         </ElButton>
282
-        <ElButton v-if="showButton('back')" danger @click="handleBack">
444
+        <ElButton v-if="buttonPermissions?.back" danger @click="handleBack">
283 445
           退回
284 446
         </ElButton>
285 447
       </ElSpace>
@@ -295,12 +457,184 @@ const showButton = (buttonType: string) => {
295 457
     @close="handleDrawerClosed"
296 458
     @closed="handleDrawerClosed"
297 459
   >
298
-    <div class="drawer-content">
460
+    <div class="drawer-content pb-20">
299 461
       <CreatOrder
300 462
         :id="drawerId"
301 463
         ref="creatOrderRef"
302 464
         @close="handleCloseDrawer"
303 465
       />
304 466
     </div>
467
+    <div class="absolute bottom-0 left-0 right-0 border-t border-gray-200 p-4 bg-white">
468
+      <div class="flex justify-end space-x-2">
469
+        <ElButton @click="drawerVisible = false">取消</ElButton>
470
+        <ElButton type="primary" @click="handleConfirmEdit">保存</ElButton>
471
+      </div>
472
+    </div>
473
+  </ElDrawer>
474
+
475
+  <!-- 处理工单的抽屉组件 -->
476
+  <ElDrawer
477
+    v-model="handleDrawerVisible"
478
+    title="处理工单"
479
+    width="800px"
480
+    :close-on-click-modal="false">
481
+    <div class="drawer-content p-4 pb-20">
482
+      <ElForm
483
+        :model="handleFormData"
484
+        label-width="120px"
485
+        class="handle-order-form"
486
+      >
487
+        <!-- 处理内容 -->
488
+        <ElFormItem label="处理内容" required>
489
+          <ElInput
490
+            v-model="handleFormData.processContent"
491
+            type="textarea"
492
+            :rows="4"
493
+            placeholder="请输入处理内容"
494
+          />
495
+        </ElFormItem>
496
+
497
+        <!-- 处理附件 -->
498
+        <ElFormItem label="处理附件">
499
+          <ElUpload
500
+            :file-list="handleFileList"
501
+            :action="getSingleImageUploadConfig().action"
502
+            :headers="getSingleImageUploadConfig().headers"
503
+            :on-success="handleUploadSuccess"
504
+            :on-error="handleUploadError"
505
+            :on-remove="handleFileRemove"
506
+            list-type="picture-card"
507
+            multiple
508
+            :limit="5"
509
+          >
510
+            <UploadFilled />
511
+            <template #tip>
512
+              <div class="el-upload__tip">
513
+                支持上传图片格式文件,最多5个,多个文件用逗号分隔
514
+              </div>
515
+            </template>
516
+          </ElUpload>
517
+        </ElFormItem>
518
+      </ElForm>
519
+    </div>
520
+    <div class="absolute bottom-0 left-0 right-0 border-t border-gray-200 p-4 bg-white">
521
+      <div class="flex justify-end space-x-2">
522
+        <ElButton @click="handleDrawerVisible = false">取消</ElButton>
523
+        <ElButton type="primary" @click="handleSubmitForm">提交</ElButton>
524
+      </div>
525
+    </div>
526
+  </ElDrawer>
527
+
528
+  <!-- 延时申请的抽屉组件 -->
529
+  <ElDrawer
530
+    v-model="delayDrawerVisible"
531
+    title="延时申请"
532
+    width="800px"
533
+    :close-on-click-modal="false">
534
+    <div class="drawer-content p-4 pb-20">
535
+      <ElForm
536
+        :model="delayFormData"
537
+        label-width="120px"
538
+        class="delay-order-form"
539
+      >
540
+        <!-- 延时原因 -->
541
+        <ElFormItem label="延时原因" required>
542
+          <ElInput
543
+            v-model="delayFormData.delayReason"
544
+            type="textarea"
545
+            :rows="4"
546
+            placeholder="请输入延时原因"
547
+          />
548
+        </ElFormItem>
549
+
550
+        <!-- 延时时长 -->
551
+        <ElFormItem label="延时时长(小时)" required>
552
+          <ElInput
553
+            v-model.number="delayFormData.delayDuration"
554
+            type="number"
555
+            placeholder="请输入延时时长"
556
+            min="1"
557
+          />
558
+        </ElFormItem>
559
+
560
+        <!-- 申请附件 -->
561
+        <ElFormItem label="申请附件">
562
+          <ElUpload
563
+            :file-list="delayFileList"
564
+            :action="getSingleImageUploadConfig().action"
565
+            :headers="getSingleImageUploadConfig().headers"
566
+            :on-success="handleDelayUploadSuccess"
567
+            :on-error="handleUploadError"
568
+            :on-remove="handleDelayFileRemove"
569
+            list-type="picture-card"
570
+            multiple
571
+            :limit="5"
572
+          >
573
+            <UploadFilled />
574
+            <template #tip>
575
+              <div class="el-upload__tip">
576
+                支持上传图片格式文件,最多5个,多个文件用逗号分隔
577
+              </div>
578
+            </template>
579
+          </ElUpload>
580
+        </ElFormItem>
581
+      </ElForm>
582
+    </div>
583
+    <div class="absolute bottom-0 left-0 right-0 border-t border-gray-200 p-4 bg-white">
584
+      <div class="flex justify-end space-x-2">
585
+        <ElButton @click="delayDrawerVisible = false">取消</ElButton>
586
+        <ElButton type="primary" @click="handleDelaySubmit">提交</ElButton>
587
+      </div>
588
+    </div>
589
+  </ElDrawer>
590
+
591
+  <!-- 抄送的抽屉组件 -->
592
+  <ElDrawer
593
+    v-model="ccDrawerVisible"
594
+    title="抄送"
595
+    width="800px"
596
+    :close-on-click-modal="false">
597
+    <div class="drawer-content p-4 pb-20">
598
+      <ElForm
599
+        :model="ccFormData"
600
+        label-width="120px"
601
+        class="cc-order-form"
602
+      >
603
+        <!-- 部门选择 -->
604
+        <ElFormItem label="选择部门" required>
605
+          <ElTreeSelect
606
+            v-model="selectedDeptId"
607
+            :data="deptTree"
608
+            node-key="id"
609
+            :props="{ label: 'label', children: 'children' }"
610
+            placeholder="请选择部门"
611
+            @change="handleDeptChange"
612
+          />
613
+        </ElFormItem>
614
+
615
+        <!-- 人员选择 -->
616
+        <ElFormItem label="选择人员" required>
617
+          <ElSelect
618
+            v-model="selectedUsers"
619
+            multiple
620
+            placeholder="请选择人员"
621
+            @change="handleUserChange"
622
+          >
623
+            <ElOption
624
+              v-for="user in userList"
625
+              :key="user.id"
626
+              :label="user.nickname || user.username"
627
+              :value="user.id"
628
+            />
629
+          </ElSelect>
630
+        </ElFormItem>
631
+      </ElForm>
632
+    </div>
633
+    <div class="absolute bottom-0 left-0 right-0 border-t border-gray-200 p-4 bg-white">
634
+      <div class="flex justify-end space-x-2">
635
+        <ElButton @click="ccDrawerVisible = false">取消</ElButton>
636
+        <ElButton type="primary" @click="handleCCSubmit">提交</ElButton>
637
+      </div>
638
+    </div>
305 639
   </ElDrawer>
306 640
 </template>

+ 4 - 3
apps/web-ele/src/views/workflow/components/approval-details.vue

@@ -14,7 +14,8 @@ defineOptions({
14 14
 });
15 15
 
16 16
 defineProps<{
17
-  task: TaskInfo;
17
+  task?: TaskInfo;
18
+  workOrderDetail?: any;
18 19
 }>();
19 20
 </script>
20 21
 
@@ -27,8 +28,8 @@ defineProps<{
27 28
     <!-- <component :is="flowComponentsMap[task.formPath as FlowComponentsMapMapKey]" :business-id="task.businessId" /> -->
28 29
     <component
29 30
       :is="flowComponentsMap['/workflow/leaveEdit/index']"
30
-      :task="task"
31
+      :work-order-detail="workOrderDetail"
31 32
     />
32
-    <ApprovalTimeline :id="task.id || task.orderId" />
33
+    <ApprovalTimeline :id="workOrderDetail?.id" />
33 34
   </div>
34 35
 </template>

+ 15 - 10
apps/web-ele/src/views/workflow/components/approval-panel.vue

@@ -42,6 +42,10 @@ interface Props {
42 42
    */
43 43
   task?: TaskInfo;
44 44
   /**
45
+   * 工单详情
46
+   */
47
+  workOrderDetail?: any;
48
+  /**
45 49
    * 审批类型
46 50
    */
47 51
   type: ApprovalType;
@@ -144,14 +148,14 @@ async function handleCopy(text: string) {
144 148
 <template>
145 149
   <div :class="cn('thin-scrollbar', 'flex flex-1 overflow-y-hidden')">
146 150
     <ElCard
147
-      v-if="task"
151
+      v-if="workOrderDetail"
148 152
       :body-style="{ overflowY: 'auto', height: '100%' }"
149 153
       :loading="loading"
150 154
       class="thin-scrollbar flex-1 overflow-y-hidden"
151 155
       size="small"
152 156
     >
153 157
       <template #extra>
154
-        <el-button size="small" @click="() => handleLoadInfo(task)">
158
+        <el-button size="small" @click="() => handleLoadInfo(workOrderDetail)">   
155 159
           <div class="flex items-center justify-center">
156 160
             <span class="icon-[material-symbols--refresh] size-24px"></span>
157 161
           </div>
@@ -162,36 +166,36 @@ async function handleCopy(text: string) {
162 166
         <div class="flex flex-col gap-3">
163 167
           <div class="flex items-center gap-2">
164 168
             <div class="text-2xl font-bold">
165
-              {{ task.orderNo }}
169
+              {{ workOrderDetail.orderNo }}
166 170
             </div>
167
-            <el-icon @click="() => handleCopy(task.orderNo)">
171
+            <el-icon @click="() => handleCopy(workOrderDetail.orderNo)">
168 172
               <CopyDocument />
169 173
             </el-icon>
170 174
             <div>
171 175
               <component
172
-                :is="renderDict(task.status, DictEnum.TICKET_STATUS)"
176
+                :is="renderDict(workOrderDetail.status, DictEnum.TICKET_STATUS)"
173 177
               />
174 178
             </div>
175 179
           </div>
176 180
 
177 181
           <div class="flex items-center gap-2">
178 182
             <VbenAvatar
179
-              :alt="task?.createBy ?? ''"
183
+              :alt="workOrderDetail?.createBy ?? ''" 
180 184
               class="bg-primary size-[28px] rounded-full text-white"
181 185
               src=""
182 186
             />
183 187
 
184
-            <span>{{ task.createBy }}</span>
188
+            <span>{{ workOrderDetail.createBy }}</span>
185 189
 
186 190
             <div class="flex items-center opacity-50">
187 191
               <div class="flex items-center gap-1">
188 192
                 <span class="icon-[bxs--category-alt] size-[16px]"></span>
189
-                流程分类: {{ task.ticketTypeName }}
193
+                流程分类: {{ workOrderDetail.ticketTypeName }}
190 194
               </div>
191 195
 
192 196
               <div class="flex items-center gap-1">
193 197
                 <span class="icon-[mdi--clock-outline] size-[16px]"></span>
194
-                提交时间: {{ task.createTime }}
198
+                提交时间: {{ workOrderDetail.createTime }}
195 199
               </div>
196 200
             </div>
197 201
           </div>
@@ -201,7 +205,7 @@ async function handleCopy(text: string) {
201 205
           <ElTabPane key="1" label="工单详情">
202 206
             <ApprovalDetails
203 207
               :current-flow-info="currentFlowInfo"
204
-              :task="task"
208
+              :work-order-detail="workOrderDetail"
205 209
             />
206 210
           </ElTabPane>
207 211
 
@@ -217,6 +221,7 @@ async function handleCopy(text: string) {
217 221
         v-if="showFooter"
218 222
         :type="type"
219 223
         :task="task"
224
+        :work-order-detail="workOrderDetail"
220 225
         :button-permissions="buttonPermissions"
221 226
         @reload="$emit('reload')"
222 227
       />

+ 2 - 0
apps/web-ele/src/views/workflow/components/approval-timeline.vue

@@ -36,11 +36,13 @@ async function loadData() {
36 36
 
37 37
 // 组件挂载时加载数据
38 38
 onMounted(() => {
39
+  console.log(props.id);
39 40
   loadData();
40 41
 });
41 42
 
42 43
 // 监听id属性变化,当id变化时重新加载数据
43 44
 watch(() => props.id, () => {
45
+  console.log(props.id);
44 46
   loadData();
45 47
 });
46 48
 </script>

+ 12 - 12
apps/web-ele/src/views/workflow/leave/leave-description.vue

@@ -10,7 +10,7 @@ defineOptions({
10 10
   inheritAttrs: false,
11 11
 });
12 12
 
13
-const props = defineProps<{ task: LeaveVO }>();
13
+const props = defineProps<{ workOrderDetail: LeaveVO }>();
14 14
 
15 15
 // 附件数组,使用ref存储以保持引用稳定
16 16
 const attachmentsArray = ref<string[]>([]);
@@ -21,7 +21,7 @@ const previewIndex = ref(0);
21 21
 
22 22
 // 监听附件URL变化,更新附件数组
23 23
 watchEffect(() => {
24
-  if (!props.task?.attachmentsUrl) {
24
+  if (!props.workOrderDetail?.attachmentsUrl) {
25 25
     attachmentsArray.value = [];
26 26
     return;
27 27
   }
@@ -29,12 +29,12 @@ watchEffect(() => {
29 29
   let urls: string[] = [];
30 30
   
31 31
   // 如果已经是数组,确保每个元素都是字符串
32
-  if (Array.isArray(props.task.attachmentsUrl)) {
33
-    urls = props.task.attachmentsUrl.map(item => String(item));
32
+  if (Array.isArray(props.workOrderDetail.attachmentsUrl)) {
33
+    urls = props.workOrderDetail.attachmentsUrl.map(item => String(item));
34 34
   } else {
35 35
     try {
36 36
       // 尝试解析JSON字符串
37
-      const parsed = JSON.parse(String(props.task.attachmentsUrl));
37
+      const parsed = JSON.parse(String(props.workOrderDetail.attachmentsUrl));
38 38
       if (Array.isArray(parsed)) {
39 39
         urls = parsed.map(item => String(item));
40 40
       } else {
@@ -42,7 +42,7 @@ watchEffect(() => {
42 42
       }
43 43
     } catch (e) {
44 44
       // 解析失败,将整个字符串作为单个URL
45
-      urls = [String(props.task.attachmentsUrl)];
45
+      urls = [String(props.workOrderDetail.attachmentsUrl)];
46 46
     }
47 47
   }
48 48
   
@@ -64,21 +64,21 @@ function closePreview() {
64 64
 
65 65
 <template>
66 66
   <div class="rounded-[6px] border p-2">
67
-    <ElDescriptions v-if="props.task" :column="1">
67
+    <ElDescriptions v-if="props.workOrderDetail" :column="1">
68 68
       <ElDescriptionsItem label="工单类型:">
69
-        {{ props.task.ticketTypeName }}
69
+        {{ props.workOrderDetail.ticketTypeName }}
70 70
       </ElDescriptionsItem>
71 71
       <ElDescriptionsItem label="场站:">
72
-        {{ props.task.stationName || '无' }}
72
+        {{ props.workOrderDetail.stationName || '无' }}
73 73
       </ElDescriptionsItem>
74 74
       <ElDescriptionsItem label="联系人:">
75
-        {{ props.task.contact || '无' }}
75
+        {{ props.workOrderDetail.contact || '无' }}
76 76
       </ElDescriptionsItem>
77 77
       <ElDescriptionsItem label="联系电话:">
78
-        {{ props.task.phone || '无' }}
78
+        {{ props.workOrderDetail.phone || '无' }}
79 79
       </ElDescriptionsItem>
80 80
       <ElDescriptionsItem label="提报内容:">
81
-        {{ props.task.content || '无' }}
81
+        {{ props.workOrderDetail.content || '无' }}
82 82
       </ElDescriptionsItem>
83 83
       <ElDescriptionsItem label="附件:">
84 84
         <div v-if="attachmentsArray.length > 0" class="flex flex-wrap gap-2">

+ 7 - 7
apps/web-ele/src/views/workflow/task/myDocument.vue

@@ -60,7 +60,7 @@ async function reload(resetFields: boolean = false) {
60 60
   cardContainerRef.value?.scroll({ top: 0, behavior: 'auto' });
61 61
 
62 62
   page.value = 1;
63
-  currentTask.value = undefined;
63
+  currentWorkOrderDetail.value = undefined;
64 64
   taskTotal.value = 0;
65 65
   lastSelectId.value = '';
66 66
 
@@ -106,7 +106,7 @@ async function reload(resetFields: boolean = false) {
106 106
   // 默认选中第一个
107 107
   if (taskList.value.length > 0) {
108 108
     const firstTask = taskList.value[0]!;
109
-    currentTask.value = firstTask;
109
+    currentWorkOrderDetail.value = firstTask;
110 110
     handleCardClick(firstTask);
111 111
   }
112 112
 }
@@ -167,14 +167,14 @@ const handleScroll = debounce(async (e: Event) => {
167 167
 }, 200);
168 168
 
169 169
 const lastSelectId = ref('');
170
-const currentTask = ref<TaskInfo>();
170
+const currentWorkOrderDetail = ref<any>();
171 171
 async function handleCardClick(item: TaskInfo) {
172 172
   const { id } = item;
173 173
   // 点击的是同一个
174 174
   if (lastSelectId.value === id) {
175 175
     return;
176 176
   }
177
-  currentTask.value = item;
177
+  currentWorkOrderDetail.value = item;
178 178
   // 反选状态 & 如果已经点击了 不变 & 保持只能有一个选中
179 179
   taskList.value.forEach((item) => {
180 180
     item.active = item.id === id;
@@ -187,11 +187,11 @@ const { refreshTab } = useTabs();
187 187
 // 按钮权限控制
188 188
 const currentTaskButtonPermissions = computed(() => {
189 189
   // 如果没有当前任务,返回空对象
190
-  if (!currentTask.value) {
190
+  if (!currentWorkOrderDetail.value) {
191 191
     return {};
192 192
   }
193 193
   // 根据任务状态判断工单类型
194
-  const { status } = currentTask.value;
194
+  const { status } = currentWorkOrderDetail.value;
195 195
   // 初始化权限对象
196 196
   const permissions: Record<string, boolean> = {};
197 197
   // 新工单 (status: "news")
@@ -291,7 +291,7 @@ const currentTaskButtonPermissions = computed(() => {
291 291
         </div>
292 292
       </div>
293 293
       <ApprovalPanel
294
-        :task="currentTask"
294
+        :work-order-detail="currentWorkOrderDetail"
295 295
         :button-permissions="currentTaskButtonPermissions"
296 296
         type="myself"
297 297
         @reload="refreshTab"

+ 6 - 8
apps/web-ele/src/views/workflow/task/taskWaiting.vue

@@ -158,6 +158,7 @@ const handleScroll = debounce(async (e: Event) => {
158 158
 
159 159
 const lastSelectId = ref('');
160 160
 const currentTask = ref<TaskInfo>();
161
+const currentWorkOrderDetail = ref<any>();
161 162
 const currentTaskButtonData = ref<any>('');
162 163
 async function handleCardClick(item: TaskInfo) {
163 164
   const { taskId, orderId } = item;
@@ -175,8 +176,8 @@ async function handleCardClick(item: TaskInfo) {
175 176
   // 调用获取工单详情的接口
176 177
   try {
177 178
     const detail = await getWorkOrderDetail(orderId);
178
-    // 可以在这里使用获取到的工单详情数据
179
-    currentTask.value = detail;
179
+    // 保存工单详情
180
+    currentWorkOrderDetail.value = detail;
180 181
   } catch (error) {
181 182
     console.error('获取工单详情失败:', error);
182 183
     ElMessage.error('获取工单详情失败');
@@ -214,13 +215,9 @@ const currentTaskButtonPermissions = computed(() => {
214 215
 <template>
215 216
   <Page :auto-content-height="true">
216 217
     <div class="flex h-full gap-2">
217
-      <div
218
-        class="bg-background relative flex h-full min-w-[320px] max-w-[320px] flex-col rounded-lg"
219
-      >
218
+      <div class="bg-background relative flex h-full min-w-[320px] max-w-[320px] flex-col rounded-lg">
220 219
         <!-- 搜索条件 -->
221
-        <div
222
-          class="bg-background z-100 sticky left-0 top-0 w-full rounded-t-lg border-b-[1px] border-solid p-2"
223
-        >
220
+        <div class="bg-background z-100 sticky left-0 top-0 w-full rounded-t-lg border-b-[1px] border-solid p-2" >
224 221
           <div class="grid grid-cols-1 gap-2">
225 222
             <div class="flex items-center gap-1">
226 223
               <ElInput
@@ -275,6 +272,7 @@ const currentTaskButtonPermissions = computed(() => {
275 272
       </div>
276 273
       <ApprovalPanel
277 274
         :task="currentTask"
275
+        :work-order-detail="currentWorkOrderDetail"
278 276
         :button-permissions="currentTaskButtonPermissions"
279 277
         type="waiting"
280 278
         @reload="refreshTab"