miaofuhao 4 天之前
父节点
当前提交
65677b8856

+ 2 - 2
apps/web-ele/.env.development

@@ -4,8 +4,8 @@ VITE_PORT=8081
4 4
 VITE_BASE=/
5 5
 
6 6
 # 接口地址
7
-# VITE_GLOB_API_URL=http://39.164.159.226:8088
8
-VITE_GLOB_API_URL=http://192.168.1.7:8080
7
+VITE_GLOB_API_URL=http://39.164.159.226:8088
8
+# VITE_GLOB_API_URL=http://192.168.1.7:8080
9 9
 # VITE_GLOB_API_URL=http://192.168.1.170:8080
10 10
 # VITE_GLOB_FLOW_URL=http://192.168.31.160:8082
11 11
 VITE_GLOB_FLOW_URL=http://192.168.1.21:8082

+ 187 - 181
apps/web-ele/src/api/workflow/task/index.ts

@@ -1,181 +1,187 @@
1
-import type {
2
-  CompleteTaskReqData,
3
-  NextNodeInfo,
4
-  StartWorkFlowReqData,
5
-  TaskInfo,
6
-  TaskOperationData,
7
-  TaskOperationType,
8
-} from './model';
9
-
10
-import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
11
-
12
-import { requestClient } from '#/api/request';
13
-
14
-/**
15
- * 启动任务
16
- * @param data
17
- */
18
-export function startWorkFlow(data: StartWorkFlowReqData) {
19
-  return requestClient.post<{
20
-    processInstanceId: string;
21
-    taskId: string;
22
-  }>('/workflow/task/startWorkFlow', data);
23
-}
24
-
25
-/**
26
- * 提交工单
27
- * @param taskId 任务id
28
- */
29
-export function submitOrder(taskId: string) {
30
-  return requestClient.put<void>(`/workOrder/order/submit/${taskId}`);
31
-}
32
-
33
-/**
34
- * 办理任务
35
- * @param data
36
- */
37
-export function completeTask(data: CompleteTaskReqData) {
38
-  return requestClient.postWithMsg<void>('/workflow/task/completeTask', data);
39
-}
40
-
41
-/**
42
- * 查询当前用户的待办任务
43
- * @param params
44
- */
45
-export function pageByTaskWait(params?: PageQuery) {
46
-  return requestClient.get<PageResult<TaskInfo>>(
47
-    '/workflow/task/pageByTaskWait',
48
-    { params },
49
-  );
50
-}
51
-
52
-/**
53
- * 查询当前用户的已办任务
54
- * @param params
55
- */
56
-export function pageByTaskFinish(params?: PageQuery) {
57
-  return requestClient.get<PageResult<TaskInfo>>(
58
-    '/workflow/task/pageByTaskFinish',
59
-    { params },
60
-  );
61
-}
62
-
63
-/**
64
- * 查询所有待办任务
65
- * @param params
66
- */
67
-export function pageByAllTaskWait(params?: PageQuery) {
68
-  return requestClient.get<PageResult<TaskInfo>>(
69
-    '/workflow/task/pageByAllTaskWait',
70
-    { params },
71
-  );
72
-}
73
-
74
-/**
75
- * 查询已办任务
76
- * @param params
77
- */
78
-export function pageByAllTaskFinish(params?: PageQuery) {
79
-  return requestClient.get<PageResult<TaskInfo>>(
80
-    '/workflow/task/pageByAllTaskFinish',
81
-    { params },
82
-  );
83
-}
84
-
85
-/**
86
- * 查询当前用户的抄送
87
- * @param params
88
- */
89
-export function pageByTaskCopy(params?: PageQuery) {
90
-  return requestClient.get<PageResult<TaskInfo>>(
91
-    '/workflow/task/pageByTaskCopy',
92
-    { params },
93
-  );
94
-}
95
-
96
-/**
97
- * 根据taskId查询代表任务
98
- * @param taskId 任务id
99
- * @returns info
100
- */
101
-export function getTaskByTaskId(taskId: string) {
102
-  return requestClient.get<TaskInfo>(`/workflow/task/getTask/${taskId}`);
103
-}
104
-
105
-/**
106
- * 终止任务
107
- */
108
-export function terminationTask(data: { comment?: string; taskId: string }) {
109
-  return requestClient.postWithMsg<void>(
110
-    '/workflow/task/terminationTask',
111
-    data,
112
-  );
113
-}
114
-
115
-/**
116
- * 任务操作
117
- * @param taskOperationData 参数
118
- * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
119
- */
120
-export function taskOperation(
121
-  taskOperationData: TaskOperationData,
122
-  taskOperation: TaskOperationType,
123
-) {
124
-  return requestClient.postWithMsg<void>(
125
-    `/workflow/task/taskOperation/${taskOperation}`,
126
-    taskOperationData,
127
-  );
128
-}
129
-
130
-/**
131
- * 修改任务办理人
132
- * @param taskIdList 任务id
133
- * @param userId 办理人id
134
- */
135
-export function updateAssignee(taskIdList: IDS, userId: ID) {
136
-  return requestClient.putWithMsg<void>(
137
-    `/workflow/task/updateAssignee/${userId}`,
138
-    taskIdList,
139
-  );
140
-}
141
-
142
-/**
143
- * 驳回审批
144
- * @param data 参数
145
- */
146
-export function backProcess(data: any) {
147
-  return requestClient.postWithMsg<void>('/workflow/task/backProcess', data);
148
-}
149
-
150
-/**
151
- * 获取可驳回节点
152
- * @param taskId 任务ID
153
- * @param nodeCode 当前节点编码
154
- */
155
-export function getBackTaskNode(taskId: string, nodeCode: string) {
156
-  return requestClient.get<{ nodeCode: string; nodeName: string }[]>(
157
-    `/workflow/task/getBackTaskNode/${taskId}/${nodeCode}`,
158
-  );
159
-}
160
-
161
-/**
162
- * 获取当前任务的所有办理人
163
- * @param taskId 任务id
164
- */
165
-export function currentTaskAllUser(taskId: ID) {
166
-  return requestClient.get<any>(`/workflow/task/currentTaskAllUser/${taskId}`);
167
-}
168
-
169
-/**
170
- * 获取下一节点
171
- * @param data data
172
- * @param data.taskId taskId
173
- * @returns NextNodeInfo
174
- */
175
-export function getNextNodeList(data: { taskId: string }) {
176
-  return requestClient.post<NextNodeInfo[]>(
177
-    '/workflow/task/getNextNodeList',
178
-    data,
179
-  );
180
-}
181
-
1
+import type {
2
+  CompleteTaskReqData,
3
+  NextNodeInfo,
4
+  StartWorkFlowReqData,
5
+  TaskInfo,
6
+  TaskOperationData,
7
+  TaskOperationType,
8
+} from './model';
9
+
10
+import type { ID, IDS, PageQuery, PageResult } from '#/api/common';
11
+
12
+import { requestClient } from '#/api/request';
13
+
14
+/**
15
+ * 启动任务
16
+ * @param data
17
+ */
18
+export function startWorkFlow(data: StartWorkFlowReqData) {
19
+  return requestClient.post<{
20
+    processInstanceId: string;
21
+    taskId: string;
22
+  }>('/workflow/task/startWorkFlow', data);
23
+}
24
+
25
+/**
26
+ * 提交工单
27
+ * @param taskId 任务id
28
+ */
29
+export function submitOrder(taskId: string) {
30
+  return requestClient.put<void>(`/workOrder/order/submit/${taskId}`);
31
+}
32
+
33
+/**
34
+ * 删除工单
35
+ * @param taskId 任务id
36
+ */
37
+export function deleteOrder(taskId: string) {
38
+  return requestClient.delete<void>(`/workOrder/order/${taskId}`);
39
+}
40
+/**
41
+ * 办理任务
42
+ * @param data
43
+ */
44
+export function completeTask(data: CompleteTaskReqData) {
45
+  return requestClient.postWithMsg<void>('/workflow/task/completeTask', data);
46
+}
47
+
48
+/**
49
+ * 查询当前用户的待办任务
50
+ * @param params
51
+ */
52
+export function pageByTaskWait(params?: PageQuery) {
53
+  return requestClient.get<PageResult<TaskInfo>>(
54
+    '/workflow/task/pageByTaskWait',
55
+    { params },
56
+  );
57
+}
58
+
59
+/**
60
+ * 查询当前用户的已办任务
61
+ * @param params
62
+ */
63
+export function pageByTaskFinish(params?: PageQuery) {
64
+  return requestClient.get<PageResult<TaskInfo>>(
65
+    '/workflow/task/pageByTaskFinish',
66
+    { params },
67
+  );
68
+}
69
+
70
+/**
71
+ * 查询所有待办任务
72
+ * @param params
73
+ */
74
+export function pageByAllTaskWait(params?: PageQuery) {
75
+  return requestClient.get<PageResult<TaskInfo>>(
76
+    '/workflow/task/pageByAllTaskWait',
77
+    { params },
78
+  );
79
+}
80
+
81
+/**
82
+ * 查询已办任务
83
+ * @param params
84
+ */
85
+export function pageByAllTaskFinish(params?: PageQuery) {
86
+  return requestClient.get<PageResult<TaskInfo>>(
87
+    '/workflow/task/pageByAllTaskFinish',
88
+    { params },
89
+  );
90
+}
91
+
92
+/**
93
+ * 查询当前用户的抄送
94
+ * @param params
95
+ */
96
+export function pageByTaskCopy(params?: PageQuery) {
97
+  return requestClient.get<PageResult<TaskInfo>>(
98
+    '/workflow/task/pageByTaskCopy',
99
+    { params },
100
+  );
101
+}
102
+
103
+/**
104
+ * 根据taskId查询代表任务
105
+ * @param taskId 任务id
106
+ * @returns info
107
+ */
108
+export function getTaskByTaskId(taskId: string) {
109
+  return requestClient.get<TaskInfo>(`/workflow/task/getTask/${taskId}`);
110
+}
111
+
112
+/**
113
+ * 终止任务
114
+ */
115
+export function terminationTask(data: { comment?: string; taskId: string }) {
116
+  return requestClient.postWithMsg<void>(
117
+    '/workflow/task/terminationTask',
118
+    data,
119
+  );
120
+}
121
+
122
+/**
123
+ * 任务操作
124
+ * @param taskOperationData 参数
125
+ * @param taskOperation 操作类型,委派 delegateTask、转办 transferTask、加签 addSignature、减签 reductionSignature
126
+ */
127
+export function taskOperation(
128
+  taskOperationData: TaskOperationData,
129
+  taskOperation: TaskOperationType,
130
+) {
131
+  return requestClient.postWithMsg<void>(
132
+    `/workflow/task/taskOperation/${taskOperation}`,
133
+    taskOperationData,
134
+  );
135
+}
136
+
137
+/**
138
+ * 修改任务办理人
139
+ * @param taskIdList 任务id
140
+ * @param userId 办理人id
141
+ */
142
+export function updateAssignee(taskIdList: IDS, userId: ID) {
143
+  return requestClient.putWithMsg<void>(
144
+    `/workflow/task/updateAssignee/${userId}`,
145
+    taskIdList,
146
+  );
147
+}
148
+
149
+/**
150
+ * 驳回审批
151
+ * @param data 参数
152
+ */
153
+export function backProcess(data: any) {
154
+  return requestClient.postWithMsg<void>('/workflow/task/backProcess', data);
155
+}
156
+
157
+/**
158
+ * 获取可驳回节点
159
+ * @param taskId 任务ID
160
+ * @param nodeCode 当前节点编码
161
+ */
162
+export function getBackTaskNode(taskId: string, nodeCode: string) {
163
+  return requestClient.get<{ nodeCode: string; nodeName: string }[]>(
164
+    `/workflow/task/getBackTaskNode/${taskId}/${nodeCode}`,
165
+  );
166
+}
167
+
168
+/**
169
+ * 获取当前任务的所有办理人
170
+ * @param taskId 任务id
171
+ */
172
+export function currentTaskAllUser(taskId: ID) {
173
+  return requestClient.get<any>(`/workflow/task/currentTaskAllUser/${taskId}`);
174
+}
175
+
176
+/**
177
+ * 获取下一节点
178
+ * @param data data
179
+ * @param data.taskId taskId
180
+ * @returns NextNodeInfo
181
+ */
182
+export function getNextNodeList(data: { taskId: string }) {
183
+  return requestClient.post<NextNodeInfo[]>(
184
+    '/workflow/task/getNextNodeList',
185
+    data,
186
+  );
187
+}

+ 5 - 0
apps/web-ele/src/api/workflow/task/model.d.ts

@@ -5,6 +5,7 @@ export interface ButtonWithPermission {
5 5
 }
6 6
 
7 7
 export interface TaskInfo {
8
+  status: string;
8 9
   taskId: string;
9 10
   orderId: string;
10 11
   id: string;
@@ -41,6 +42,10 @@ export interface TaskInfo {
41 42
   createByName: string;
42 43
   targetNodeName?: string;
43 44
   buttonList: ButtonWithPermission[];
45
+  /**
46
+   * 操作按钮,逗号分隔的字符串,如:handle,delay,cc,back
47
+   */
48
+  button?: string;
44 49
 }
45 50
 
46 51
 export interface CompleteTaskReqData {

+ 180 - 42
apps/web-ele/src/views/workflow/components/actions/flow-actions.vue

@@ -1,17 +1,21 @@
1 1
 <script setup lang="ts">
2 2
 import type { ApprovalType } from '../type';
3
+
3 4
 import type { TaskInfo } from '#/api/workflow/task/model';
4 5
 
5 6
 import { computed, ref } from 'vue';
6 7
 
7 8
 import { cn } from '@vben/utils';
8 9
 
9
-import { ElSpace, ElMessageBox, ElButton, ElDrawer } from 'element-plus';
10
+import { ElButton, ElDrawer, ElMessageBox, ElSpace } from 'element-plus';
10 11
 
11 12
 import {
12
-  deleteByInstanceIds,
13
-} from '#/api/workflow/instance';
14
-import { submitOrder } from '#/api/workflow/task';
13
+  backProcess,
14
+  completeTask,
15
+  deleteOrder,
16
+  submitOrder,
17
+  taskOperation,
18
+} from '#/api/workflow/task';
15 19
 import CreatOrder from '#/views/workflow/order/creatOrder.vue';
16 20
 
17 21
 interface Props {
@@ -26,14 +30,18 @@ interface Props {
26 30
   /**
27 31
    * 为审批类型时候 显示的按钮(按钮权限)
28 32
    */
29
-  buttonPermissions: Record<string, boolean>;
33
+  buttonPermissions?: Record<string, boolean>;
30 34
 }
35
+
31 36
 const props = defineProps<Props>();
32 37
 
33 38
 const emit = defineEmits<{
34 39
   reload: [];
35 40
 }>();
36 41
 
42
+// 创建CreatOrder组件的ref
43
+const creatOrderRef = ref<InstanceType<typeof CreatOrder>>();
44
+
37 45
 /**
38 46
  * 是否可编辑/删除
39 47
  */
@@ -48,7 +56,7 @@ const editableAndRemoveable = computed(() => {
48 56
 const drawerVisible = ref(false);
49 57
 const drawerId = ref<string>('');
50 58
 
51
-// 重新编辑
59
+// 编辑
52 60
 const handleEdit = () => {
53 61
   drawerId.value = props.task!.id;
54 62
   drawerVisible.value = true;
@@ -57,6 +65,14 @@ const handleEdit = () => {
57 65
 // 关闭抽屉
58 66
 const handleCloseDrawer = () => {
59 67
   drawerVisible.value = false;
68
+  emit('reload');
69
+};
70
+
71
+// 确认编辑
72
+const handleConfirmEdit = async () => {
73
+  if (creatOrderRef.value) {
74
+    await creatOrderRef.value.handleSubmit();
75
+  }
60 76
 };
61 77
 
62 78
 // 抽屉关闭后的回调
@@ -66,18 +82,14 @@ const handleDrawerClosed = () => {
66 82
 
67 83
 // 删除
68 84
 function handleRemove() {
69
-  ElMessageBox.confirm(
70
-    '确定删除该申请吗?',
71
-    '提示',
72
-    {
73
-      confirmButtonText: '确定',
74
-      cancelButtonText: '取消',
75
-      type: 'warning',
76
-      center: true,
77
-    }
78
-  )
85
+  ElMessageBox.confirm('确定删除该工单吗?', '提示', {
86
+    confirmButtonText: '确定',
87
+    cancelButtonText: '取消',
88
+    type: 'warning',
89
+    center: true,
90
+  })
79 91
     .then(async () => {
80
-      await deleteByInstanceIds([props.task!.id]);
92
+      await deleteOrder([props.task!.id]);
81 93
       emit('reload');
82 94
     })
83 95
     .catch(() => {
@@ -89,23 +101,123 @@ function handleRemove() {
89 101
 // 提交
90 102
 async function handleSubmit() {
91 103
   try {
92
-    await ElMessageBox.confirm(
93
-      '确定要提交该申请吗?',
94
-      '提示',
95
-      {
96
-        confirmButtonText: '确定',
97
-        cancelButtonText: '取消',
98
-        type: 'warning',
99
-        center: true,
100
-      }
101
-    );
104
+    await ElMessageBox.confirm('确定要提交该工单吗?', '提示', {
105
+      confirmButtonText: '确定',
106
+      cancelButtonText: '取消',
107
+      type: 'warning',
108
+      center: true,
109
+    });
102 110
     await submitOrder(props.task!.id);
103 111
     emit('reload');
104
-  } catch (error) {
112
+  } catch {
105 113
     // 用户取消操作,不做任何处理
106 114
     console.log('用户取消了提交操作');
107 115
   }
108 116
 }
117
+
118
+// 处理
119
+async function handleApprove() {
120
+  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('用户取消了处理操作');
139
+  }
140
+}
141
+
142
+// 延时
143
+async function handleDelay() {
144
+  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
+    );
157
+    emit('reload');
158
+  } catch {
159
+    // 用户取消操作,不做任何处理
160
+    console.log('用户取消了延时操作');
161
+  }
162
+}
163
+
164
+// 抄送
165
+async function handleCopy() {
166
+  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
+    );
180
+    emit('reload');
181
+  } catch {
182
+    // 用户取消操作,不做任何处理
183
+    console.log('用户取消了抄送操作');
184
+  }
185
+}
186
+
187
+// 退回
188
+async function handleBack() {
189
+  try {
190
+    await ElMessageBox.confirm('确定要退回该工单吗?', '提示', {
191
+      confirmButtonText: '确定',
192
+      cancelButtonText: '取消',
193
+      type: 'warning',
194
+      center: true,
195
+    });
196
+    await backProcess({
197
+      taskId: props.task!.taskId,
198
+    });
199
+    emit('reload');
200
+  } catch {
201
+    // 用户取消操作,不做任何处理
202
+    console.log('用户取消了退回操作');
203
+  }
204
+}
205
+
206
+// 获取可用按钮
207
+const availableButtons = computed(() => {
208
+  if (!props.task || !props.task.button) {
209
+    return [];
210
+  }
211
+  return props.task.button.split(',');
212
+});
213
+
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
+};
109 221
 </script>
110 222
 
111 223
 <template>
@@ -120,15 +232,15 @@ async function handleSubmit() {
120 232
   >
121 233
     <div class="flex justify-end">
122 234
       <ElSpace v-if="type === 'myself'">
123
-        <el-button
235
+        <ElButton
124 236
           type="primary"
125 237
           text
126 238
           v-if="buttonPermissions?.edit || editableAndRemoveable"
127 239
           @click="handleEdit"
128 240
         >
129
-          重新编辑
130
-        </el-button>
131
-        <el-button
241
+          编辑
242
+        </ElButton>
243
+        <ElButton
132 244
           v-if="buttonPermissions?.delete || editableAndRemoveable"
133 245
           danger
134 246
           text
@@ -136,33 +248,59 @@ async function handleSubmit() {
136 248
           @click="handleRemove"
137 249
         >
138 250
           删除
139
-        </el-button>
251
+        </ElButton>
140 252
         <!-- 提交按钮 -->
141
-        <el-button
253
+        <ElButton
142 254
           v-if="buttonPermissions?.submit"
143 255
           type="primary"
144 256
           text
145 257
           @click="handleSubmit"
146 258
         >
147 259
           提交
148
-        </el-button>
260
+        </ElButton>
261
+      </ElSpace>
262
+
263
+      <!-- 审批操作按钮 -->
264
+      <ElSpace v-if="type === 'waiting'">
265
+        <ElButton
266
+          v-if="showButton('handle')"
267
+          type="primary"
268
+          @click="handleApprove"
269
+        >
270
+          处理
271
+        </ElButton>
272
+        <ElButton
273
+          v-if="showButton('delay')"
274
+          type="warning"
275
+          @click="handleDelay"
276
+        >
277
+          延时
278
+        </ElButton>
279
+        <ElButton v-if="showButton('cc')" type="info" @click="handleCopy">
280
+          抄送
281
+        </ElButton>
282
+        <ElButton v-if="showButton('back')" danger @click="handleBack">
283
+          退回
284
+        </ElButton>
149 285
       </ElSpace>
150 286
     </div>
151 287
   </div>
152
-  
288
+
153 289
   <!-- 普通的el-drawer组件 -->
154 290
   <ElDrawer
155 291
     v-model="drawerVisible"
156 292
     title="编辑工单"
157 293
     width="800px"
158 294
     :close-on-click-modal="false"
159
-    @close="handleCloseDrawer"
295
+    @close="handleDrawerClosed"
160 296
     @closed="handleDrawerClosed"
161 297
   >
162
-    <CreatOrder 
163
-      :id="drawerId" 
164
-      @reload="emit('reload')" 
165
-      @close="handleCloseDrawer"
166
-    />
298
+    <div class="drawer-content">
299
+      <CreatOrder
300
+        :id="drawerId"
301
+        ref="creatOrderRef"
302
+        @close="handleCloseDrawer"
303
+      />
304
+    </div>
167 305
   </ElDrawer>
168 306
 </template>

+ 63 - 53
apps/web-ele/src/views/workflow/order/creatOrder.vue

@@ -1,25 +1,38 @@
1 1
 <script lang="ts" setup>
2
-import { ref, reactive, onMounted, watch } from 'vue';
2
+import { onMounted, reactive, ref, watch } from 'vue';
3 3
 import { useRoute, useRouter } from 'vue-router';
4
+
4 5
 import { Page } from '@vben/common-ui';
5
-import { ElForm, ElFormItem, ElInput, ElSelect, ElUpload, ElSwitch, ElButton, ElMessage, ElTreeSelect } from 'element-plus';
6
+
6 7
 import { UploadFilled } from '@element-plus/icons-vue';
7
-import { categoryTree } from '#/api/workflow/category/index';
8
-import { selectAllSysStation } from '#/api/system/infoEntry/stationInfo/stationInfo';
9
-import { getSingleImageUploadConfig } from '#/components/upload/config';
8
+import {
9
+  ElButton,
10
+  ElForm,
11
+  ElFormItem,
12
+  ElInput,
13
+  ElMessage,
14
+  ElSelect,
15
+  ElSwitch,
16
+  ElTreeSelect,
17
+  ElUpload,
18
+} from 'element-plus';
19
+
10 20
 import { requestClient } from '#/api/request';
21
+import { selectAllSysStation } from '#/api/system/infoEntry/stationInfo/stationInfo';
22
+import { categoryTree } from '#/api/workflow/category/index';
11 23
 import { getWorkOrderDetail } from '#/api/workflow/instance/index';
12
-
13
-// 定义emit事件
14
-const emit = defineEmits<{
15
-  close: [];
16
-}>();
24
+import { getSingleImageUploadConfig } from '#/components/upload/config';
17 25
 
18 26
 // 接收props参数
19 27
 const props = defineProps<{
20 28
   id?: string;
21 29
 }>();
22 30
 
31
+// 定义emit事件
32
+const emit = defineEmits<{
33
+  close: [];
34
+}>();
35
+
23 36
 // 路由相关
24 37
 const route = useRoute();
25 38
 const router = useRouter();
@@ -32,19 +45,25 @@ const formData = reactive({
32 45
   phone: '',
33 46
   content: '',
34 47
   attachments: '',
35
-  isSubmit: false
48
+  isSubmit: false,
36 49
 });
37 50
 
38 51
 // 表单规则
39 52
 const formRules = reactive({
40
-  ticketType: [{ required: true, message: '请选择工单类型', trigger: 'change' }],
53
+  ticketType: [
54
+    { required: true, message: '请选择工单类型', trigger: 'change' },
55
+  ],
41 56
   stationId: [{ required: true, message: '请选择场站', trigger: 'change' }],
42 57
   contact: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
43 58
   phone: [
44 59
     { required: true, message: '请输入联系电话', trigger: 'blur' },
45
-    { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: 'blur' }
60
+    {
61
+      pattern: /^1[3-9]\d{9}$/,
62
+      message: '请输入正确的手机号码',
63
+      trigger: 'blur',
64
+    },
46 65
   ],
47
-  content: [{ required: true, message: '请输入提报内容', trigger: 'blur' }]
66
+  content: [{ required: true, message: '请输入提报内容', trigger: 'blur' }],
48 67
 });
49 68
 
50 69
 // 工单类型选项
@@ -86,7 +105,7 @@ const handleUploadSuccess = (response, file, fileList) => {
86 105
   if (response.code === 200) {
87 106
     // 将文件路径添加到attachments字段
88 107
     console.log(response, file, fileList);
89
-    const paths = fileList.map(f => f.response.data.fileName).join(',');
108
+    const paths = fileList.map((f) => f.response.data.fileName).join(',');
90 109
     formData.attachments = paths;
91 110
   } else {
92 111
     ElMessage.error('文件上传失败');
@@ -102,7 +121,7 @@ const handleUploadError = (error) => {
102 121
 // 移除文件回调
103 122
 const handleRemove = (file, fileList) => {
104 123
   // 更新attachments字段(文件名)
105
-  const fileNames = fileList.map(f => f.response.data.fileName).join(',');
124
+  const fileNames = fileList.map((f) => f.response.data.fileName).join(',');
106 125
   formData.attachments = fileNames;
107 126
 };
108 127
 
@@ -110,7 +129,7 @@ const handleRemove = (file, fileList) => {
110 129
 const getOrderDetail = async (orderId?: string) => {
111 130
   const id = orderId || props.id || route.query.id;
112 131
   if (!id) return;
113
-  
132
+
114 133
   try {
115 134
     const detail = await getWorkOrderDetail(id as string);
116 135
     console.log('工单详情:', detail);
@@ -122,14 +141,18 @@ const getOrderDetail = async (orderId?: string) => {
122 141
     formData.content = detail.content || '';
123 142
     formData.attachments = detail.attachments || '';
124 143
     formData.isSubmit = detail.isSubmit || false;
125
-    
144
+
126 145
     // 处理附件文件列表
127 146
     if (detail.attachmentsUrl && Array.isArray(detail.attachmentsUrl)) {
128
-      const fileNames = formData.attachments ? formData.attachments.split(',') : [];
147
+      const fileNames = formData.attachments
148
+        ? formData.attachments.split(',')
149
+        : [];
129 150
       fileList.value = detail.attachmentsUrl.map((url, index) => ({
130 151
         name: fileNames[index] || `file-${index}`,
131
-        url: url,
132
-        response: { data: { url: url, fileName: fileNames[index] || `file-${index}` } }
152
+        url,
153
+        response: {
154
+          data: { url, fileName: fileNames[index] || `file-${index}` },
155
+        },
133 156
       }));
134 157
     }
135 158
   } catch (error) {
@@ -146,23 +169,23 @@ watch(
146 169
       getOrderDetail(newId);
147 170
     }
148 171
   },
149
-  { immediate: true }
172
+  { immediate: true },
150 173
 );
151 174
 
152 175
 // 表单提交
153 176
 const handleSubmit = async () => {
154 177
   if (!formRef.value) return;
155
-  
178
+
156 179
   try {
157 180
     await formRef.value.validate();
158 181
     console.log(formData);
159 182
     const id = props.id || route.query.id;
160
-    
183
+
161 184
     if (id) {
162 185
       // 更新工单
163 186
       await requestClient.put(`/workOrder/order/${id}`, formData);
164 187
       ElMessage.success('工单更新成功');
165
-      
188
+
166 189
       // 如果是在drawer中打开的,需要关闭drawer
167 190
       if (props.id) {
168 191
         // 触发close事件通知drawer关闭
@@ -172,7 +195,7 @@ const handleSubmit = async () => {
172 195
       // 创建工单
173 196
       await requestClient.post('/workOrder/order', formData);
174 197
       ElMessage.success('工单创建成功');
175
-      
198
+
176 199
       // 重置表单
177 200
       formRef.value.resetFields();
178 201
       fileList.value = [];
@@ -183,7 +206,7 @@ const handleSubmit = async () => {
183 206
       // 表单验证失败,Element Plus会自动提示错误信息
184 207
       return;
185 208
     }
186
-    
209
+
187 210
     ElMessage.error(id ? '工单更新失败' : '工单创建失败');
188 211
     console.error('工单操作失败:', error);
189 212
   }
@@ -204,6 +227,11 @@ const initData = () => {
204 227
 onMounted(() => {
205 228
   initData();
206 229
 });
230
+
231
+// 暴露方法给父组件
232
+defineExpose({
233
+  handleSubmit,
234
+});
207 235
 </script>
208 236
 
209 237
 <template>
@@ -226,7 +254,7 @@ onMounted(() => {
226 254
             style="width: 100%"
227 255
             :props="{ label: 'label', value: 'id', children: 'children' }"
228 256
             filterable
229
-          ></ElTreeSelect>
257
+          />
230 258
         </ElFormItem>
231 259
 
232 260
         <!-- 场站 -->
@@ -241,24 +269,18 @@ onMounted(() => {
241 269
               :key="option.id"
242 270
               :label="option.stationName"
243 271
               :value="option.id"
244
-            ></ElOption>
272
+            />
245 273
           </ElSelect>
246 274
         </ElFormItem>
247 275
 
248 276
         <!-- 联系人 -->
249 277
         <ElFormItem label="联系人" prop="contact">
250
-          <ElInput
251
-            v-model="formData.contact"
252
-            placeholder="请输入联系人"
253
-          ></ElInput>
278
+          <ElInput v-model="formData.contact" placeholder="请输入联系人" />
254 279
         </ElFormItem>
255 280
 
256 281
         <!-- 联系电话 -->
257 282
         <ElFormItem label="联系电话" prop="phone">
258
-          <ElInput
259
-            v-model="formData.phone"
260
-            placeholder="请输入联系电话"
261
-          ></ElInput>
283
+          <ElInput v-model="formData.phone" placeholder="请输入联系电话" />
262 284
         </ElFormItem>
263 285
 
264 286
         <!-- 提报内容 -->
@@ -268,7 +290,7 @@ onMounted(() => {
268 290
             type="textarea"
269 291
             :rows="4"
270 292
             placeholder="请输入提报内容"
271
-          ></ElInput>
293
+          />
272 294
         </ElFormItem>
273 295
 
274 296
         <!-- 提报附件 -->
@@ -295,11 +317,11 @@ onMounted(() => {
295 317
 
296 318
         <!-- 是否提交 -->
297 319
         <ElFormItem label="是否提交">
298
-          <ElSwitch v-model="formData.isSubmit"></ElSwitch>
320
+          <ElSwitch v-model="formData.isSubmit" />
299 321
         </ElFormItem>
300 322
 
301
-        <!-- 提交按钮 -->
302
-        <ElFormItem>
323
+        <!-- 提交按钮 - 仅在创建模式下显示 -->
324
+        <ElFormItem v-if="!props.id">
303 325
           <ElButton type="primary" @click="handleSubmit">创建工单</ElButton>
304 326
         </ElFormItem>
305 327
       </ElForm>
@@ -318,15 +340,3 @@ onMounted(() => {
318 340
   max-width: 600px;
319 341
 }
320 342
 </style>
321
-
322
-
323
-
324
-
325
-
326
-
327
-
328
-
329
-
330
-
331
-
332
-

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

@@ -5,19 +5,26 @@ import type { TaskInfo } from '#/api/workflow/task/model';
5 5
 import { computed, onMounted, ref, useTemplateRef } from 'vue';
6 6
 
7 7
 import { Page } from '@vben/common-ui';
8
+import { DictEnum } from '@vben/constants';
8 9
 import { useTabs } from '@vben/hooks';
9 10
 
10 11
 import { Refresh, Search } from '@element-plus/icons-vue';
11
-import { ElButton, ElEmpty, ElInput, ElMessage, ElSelect, ElOption, ElTooltip } from 'element-plus';
12
-
12
+import {
13
+  ElButton,
14
+  ElEmpty,
15
+  ElInput,
16
+  ElMessage,
17
+  ElOption,
18
+  ElSelect,
19
+  ElTooltip,
20
+} from 'element-plus';
13 21
 import { cloneDeep, debounce } from 'lodash-es';
14 22
 
15 23
 import { pageByCurrent } from '#/api/workflow/instance';
24
+import { getDictOptions } from '#/utils/dict';
16 25
 
17
-import { bottomOffset } from './constant';
18 26
 import { ApprovalCard, ApprovalPanel } from '../components';
19
-import { DictEnum } from '@vben/constants';
20
-import { getDictOptions } from '#/utils/dict';
27
+import { bottomOffset } from './constant';
21 28
 
22 29
 const emptyImage = ElEmpty.PRESENTED_IMAGE_SIMPLE;
23 30
 
@@ -66,7 +73,7 @@ async function reload(resetFields: boolean = false) {
66 73
     // 根据搜索关键词类型动态决定搜索字段
67 74
     const searchParams = { ...formData.value };
68 75
     const { searchKeyword, ...otherParams } = searchParams;
69
-    
76
+
70 77
     // 如果有搜索关键词
71 78
     if (searchKeyword) {
72 79
       // 检查是否为数字
@@ -78,13 +85,17 @@ async function reload(resetFields: boolean = false) {
78 85
         otherParams.content = searchKeyword;
79 86
       }
80 87
     }
81
-    
88
+
82 89
     const resp = await pageByCurrent({
83 90
       pageSize: 10,
84 91
       pageNum: page.value,
85 92
       ...otherParams,
86 93
     });
87
-    taskList.value = resp.rows.map((item) => ({ ...item, active: false, id: String(item.id) }));
94
+    taskList.value = resp.rows.map((item) => ({
95
+      ...item,
96
+      active: false,
97
+      id: String(item.id),
98
+    }));
88 99
     taskTotal.value = resp.total;
89 100
   } catch {
90 101
     ElMessage.error('加载任务列表失败');
@@ -118,11 +129,11 @@ const handleScroll = debounce(async (e: Event) => {
118 129
     loading.value = true;
119 130
     try {
120 131
       page.value += 1;
121
-      
132
+
122 133
       // 根据搜索关键词类型动态决定搜索字段
123 134
       const searchParams = { ...formData.value };
124 135
       const { searchKeyword, ...otherParams } = searchParams;
125
-      
136
+
126 137
       // 如果有搜索关键词
127 138
       if (searchKeyword) {
128 139
         // 检查是否为数字
@@ -134,14 +145,18 @@ const handleScroll = debounce(async (e: Event) => {
134 145
           otherParams.content = searchKeyword;
135 146
         }
136 147
       }
137
-      
148
+
138 149
       const resp = await pageByCurrent({
139 150
         pageSize: 10,
140 151
         pageNum: page.value,
141 152
         ...otherParams,
142 153
       });
143 154
       taskList.value.push(
144
-        ...resp.rows.map((item) => ({ ...item, active: false, id: String(item.id) })),
155
+        ...resp.rows.map((item) => ({
156
+          ...item,
157
+          active: false,
158
+          id: String(item.id),
159
+        })),
145 160
       );
146 161
     } catch {
147 162
       ElMessage.error('加载更多任务失败');
@@ -175,28 +190,24 @@ const currentTaskButtonPermissions = computed(() => {
175 190
   if (!currentTask.value) {
176 191
     return {};
177 192
   }
178
-  
179 193
   // 根据任务状态判断工单类型
180 194
   const { status } = currentTask.value;
181
-  console.log(status);
182 195
   // 初始化权限对象
183 196
   const permissions: Record<string, boolean> = {};
184
-  
185 197
   // 新工单 (status: "news")
186
-  if (status === "new") {
198
+  if (status === 'new') {
187 199
     // 新工单可以进行的操作
188 200
     permissions.edit = true; // 编辑
189 201
     permissions.submit = true; // 提交
190 202
     permissions.delete = true; // 删除
191 203
   }
192 204
   // 已处理工单 (status: "processed")
193
-  else if (status === "processed") {
205
+  else if (status === 'processed') {
194 206
     // 已处理工单可以进行的操作
195 207
     permissions.edit = false; // 编辑
196 208
     permissions.submit = false; // 提交
197 209
     permissions.delete = false; // 删除
198 210
   }
199
-  console.log(permissions);
200 211
   return permissions;
201 212
 });
202 213
 </script>
@@ -271,13 +282,20 @@ const currentTaskButtonPermissions = computed(() => {
271 282
           ></div>
272 283
         </div>
273 284
         <!-- total显示 -->
274
-        <div class="bg-background sticky bottom-0 w-full rounded-b-lg border-t-[1px] py-2" >
285
+        <div
286
+          class="bg-background sticky bottom-0 w-full rounded-b-lg border-t-[1px] py-2"
287
+        >
275 288
           <div class="flex items-center justify-center">
276 289
             共 {{ taskTotal }} 条记录
277 290
           </div>
278 291
         </div>
279 292
       </div>
280
-      <ApprovalPanel :task="currentTask" :button-permissions="currentTaskButtonPermissions" type="myself" @reload="refreshTab" />
293
+      <ApprovalPanel
294
+        :task="currentTask"
295
+        :button-permissions="currentTaskButtonPermissions"
296
+        type="myself"
297
+        @reload="refreshTab"
298
+      />
281 299
     </div>
282 300
   </Page>
283 301
 </template>
@@ -293,4 +311,3 @@ const currentTaskButtonPermissions = computed(() => {
293 311
   @apply thin-scrollbar;
294 312
 }
295 313
 </style>
296
-

+ 55 - 14
apps/web-ele/src/views/workflow/task/taskWaiting.vue

@@ -9,13 +9,12 @@ import { useTabs } from '@vben/hooks';
9 9
 
10 10
 import { Refresh, Search } from '@element-plus/icons-vue';
11 11
 import { ElButton, ElEmpty, ElInput, ElMessage, ElTooltip } from 'element-plus';
12
-
13 12
 import { cloneDeep, debounce } from 'lodash-es';
14 13
 
15
-import { pageByPending, getWorkOrderDetail } from '#/api/workflow/instance';
14
+import { getWorkOrderDetail, pageByPending } from '#/api/workflow/instance';
16 15
 
17
-import { bottomOffset } from './constant';
18 16
 import { ApprovalCard, ApprovalPanel } from '../components';
17
+import { bottomOffset } from './constant';
19 18
 
20 19
 const emptyImage = ElEmpty.PRESENTED_IMAGE_SIMPLE;
21 20
 
@@ -63,7 +62,7 @@ async function reload(resetFields: boolean = false) {
63 62
     // 根据搜索关键词类型动态决定搜索字段
64 63
     const searchParams = { ...formData.value };
65 64
     const { searchKeyword, ...otherParams } = searchParams;
66
-    
65
+
67 66
     // 如果有搜索关键词
68 67
     if (searchKeyword) {
69 68
       // 检查是否为数字
@@ -75,13 +74,17 @@ async function reload(resetFields: boolean = false) {
75 74
         otherParams.content = searchKeyword;
76 75
       }
77 76
     }
78
-    
77
+
79 78
     const resp = await pageByPending({
80 79
       pageSize: 10,
81 80
       pageNum: page.value,
82 81
       ...otherParams,
83 82
     });
84
-    taskList.value = resp.rows.map((item) => ({ ...item, active: false, id: String(item.id) }));
83
+    taskList.value = resp.rows.map((item) => ({
84
+      ...item,
85
+      active: false,
86
+      id: String(item.id),
87
+    }));
85 88
     taskTotal.value = resp.total;
86 89
   } catch {
87 90
     ElMessage.error('加载任务列表失败');
@@ -93,6 +96,7 @@ async function reload(resetFields: boolean = false) {
93 96
   if (taskList.value.length > 0) {
94 97
     const firstTask = taskList.value[0]!;
95 98
     currentTask.value = firstTask;
99
+    currentTaskButtonData.value = firstTask.button;
96 100
     handleCardClick(firstTask);
97 101
   }
98 102
 }
@@ -115,11 +119,11 @@ const handleScroll = debounce(async (e: Event) => {
115 119
     loading.value = true;
116 120
     try {
117 121
       page.value += 1;
118
-      
122
+
119 123
       // 根据搜索关键词类型动态决定搜索字段
120 124
       const searchParams = { ...formData.value };
121 125
       const { searchKeyword, ...otherParams } = searchParams;
122
-      
126
+
123 127
       // 如果有搜索关键词
124 128
       if (searchKeyword) {
125 129
         // 检查是否为数字
@@ -131,14 +135,18 @@ const handleScroll = debounce(async (e: Event) => {
131 135
           otherParams.content = searchKeyword;
132 136
         }
133 137
       }
134
-      
138
+
135 139
       const resp = await pageByPending({
136 140
         pageSize: 10,
137 141
         pageNum: page.value,
138 142
         ...otherParams,
139 143
       });
140 144
       taskList.value.push(
141
-        ...resp.rows.map((item) => ({ ...item, active: false, id: String(item.id) })),
145
+        ...resp.rows.map((item) => ({
146
+          ...item,
147
+          active: false,
148
+          id: String(item.id),
149
+        })),
142 150
       );
143 151
     } catch {
144 152
       ElMessage.error('加载更多任务失败');
@@ -150,6 +158,7 @@ const handleScroll = debounce(async (e: Event) => {
150 158
 
151 159
 const lastSelectId = ref('');
152 160
 const currentTask = ref<TaskInfo>();
161
+const currentTaskButtonData = ref<any>('');
153 162
 async function handleCardClick(item: TaskInfo) {
154 163
   const { taskId, orderId } = item;
155 164
   // 点击的是同一个
@@ -157,12 +166,12 @@ async function handleCardClick(item: TaskInfo) {
157 166
     return;
158 167
   }
159 168
   currentTask.value = item;
169
+  currentTaskButtonData.value = item.button;
160 170
   // 反选状态 & 如果已经点击了 不变 & 保持只能有一个选中
161 171
   taskList.value.forEach((item) => {
162 172
     item.active = item.taskId === taskId;
163 173
   });
164 174
   lastSelectId.value = taskId;
165
-  
166 175
   // 调用获取工单详情的接口
167 176
   try {
168 177
     const detail = await getWorkOrderDetail(orderId);
@@ -175,6 +184,31 @@ async function handleCardClick(item: TaskInfo) {
175 184
 }
176 185
 
177 186
 const { refreshTab } = useTabs();
187
+
188
+// 按钮权限控制
189
+const currentTaskButtonPermissions = computed(() => {
190
+  // 如果没有当前任务,返回空对象
191
+  if (!currentTaskButtonData.value) {
192
+    return {};
193
+  }
194
+  // 初始化权限对象
195
+  const permissions: Record<string, boolean> = {};
196
+
197
+  // 获取 button 字段
198
+  const button = currentTaskButtonData.value;
199
+  // 如果 button 字段存在,解析为数组
200
+  if (button) {
201
+    const buttonArray = button.split(',');
202
+    console.log('buttonArray', buttonArray);
203
+    // 设置对应按钮的权限
204
+    permissions.handle = buttonArray.includes('handle');
205
+    permissions.delay = buttonArray.includes('delay');
206
+    permissions.cc = buttonArray.includes('cc');
207
+    permissions.back = buttonArray.includes('back');
208
+  }
209
+  console.log('currentTaskButtonPermissions', permissions);
210
+  return permissions;
211
+});
178 212
 </script>
179 213
 
180 214
 <template>
@@ -197,7 +231,7 @@ const { refreshTab } = useTabs();
197 231
                 :suffix-icon="Search"
198 232
                 @keyup.enter="reload(false)"
199 233
               />
200
-               <ElTooltip placement="top" content="重置">
234
+              <ElTooltip placement="top" content="重置">
201 235
                 <ElButton @click="reload(true)" :icon="Refresh" />
202 236
               </ElTooltip>
203 237
             </div>
@@ -231,13 +265,20 @@ const { refreshTab } = useTabs();
231 265
           ></div>
232 266
         </div>
233 267
         <!-- total显示 -->
234
-        <div class="bg-background sticky bottom-0 w-full rounded-b-lg border-t-[1px] py-2">
268
+        <div
269
+          class="bg-background sticky bottom-0 w-full rounded-b-lg border-t-[1px] py-2"
270
+        >
235 271
           <div class="flex items-center justify-center">
236 272
             共 {{ taskTotal }} 条记录
237 273
           </div>
238 274
         </div>
239 275
       </div>
240
-      <ApprovalPanel :task="currentTask" type="myself" @reload="refreshTab" />
276
+      <ApprovalPanel
277
+        :task="currentTask"
278
+        :button-permissions="currentTaskButtonPermissions"
279
+        type="waiting"
280
+        @reload="refreshTab"
281
+      />
241 282
     </div>
242 283
   </Page>
243 284
 </template>