@ebiz/designer-components 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/designer-components.css +1 -1
- package/dist/index.mjs +13766 -13150
- package/package.json +1 -1
- package/src/components/EbizEmployeeSelector.vue +2 -1
- package/src/components/EbizSApprovalProcess.vue +1132 -0
- package/src/components/mItems/UserInfo.vue +343 -0
- package/src/index.js +88 -86
|
@@ -0,0 +1,1132 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="ebiz-approval-process">
|
|
3
|
+
<div class="block-base-style">
|
|
4
|
+
<ebiz-tdesign-loading v-if="state.loading" :loading="true" theme="circular" size="small" text=""
|
|
5
|
+
:reverse="false" layout="vertical" :delay="0" class="component-base-style">
|
|
6
|
+
<span style="display: inline-block" class="component-base-style">加载中</span>
|
|
7
|
+
</ebiz-tdesign-loading>
|
|
8
|
+
|
|
9
|
+
<div v-if="!state.loading" class="card">
|
|
10
|
+
<div style="margin: 10px 0" class="component-base-style">
|
|
11
|
+
<span style="display: inline-block" class="title">审批流程</span>
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<!-- 流程基本信息 -->
|
|
15
|
+
<div v-if="state.processInfo" class="process-info">
|
|
16
|
+
<div class="info-item" v-if="getStartUserInfo().userId">
|
|
17
|
+
<span class="label">发起人:</span>
|
|
18
|
+
<user-info :userId="getStartUserInfo().userId" :userInfo="getStartUserInfo().userInfo"
|
|
19
|
+
avatar-size="small" name-size="small" :show-job-number="true" :show-department="false" />
|
|
20
|
+
</div>
|
|
21
|
+
<div class="info-item">
|
|
22
|
+
<span class="label">发起时间:</span>
|
|
23
|
+
<span>{{ state.processInfo.startTimeStr || '--' }}</span>
|
|
24
|
+
</div>
|
|
25
|
+
<div class="info-item">
|
|
26
|
+
<span class="label">流程状态:</span>
|
|
27
|
+
<t-tag :theme="getProcessStatusTheme(state.processInfo.processStatus)" size="small">
|
|
28
|
+
{{ getProcessStatusText(state.processInfo.processStatus) }}
|
|
29
|
+
</t-tag>
|
|
30
|
+
</div>
|
|
31
|
+
<!-- 抄送人信息 -->
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
<!-- 审批步骤 -->
|
|
35
|
+
<div class="simple-approval-steps">
|
|
36
|
+
<!-- 节点步骤 -->
|
|
37
|
+
<div v-for="(node, index) in state.nodes" :key="'node-' + index" class="simple-step-item">
|
|
38
|
+
<div class="step-header">
|
|
39
|
+
<div class="step-icon" :class="getSimpleStepIconClass(node)">
|
|
40
|
+
<t-icon name="user" size="12px" color="white" />
|
|
41
|
+
</div>
|
|
42
|
+
<div class="step-info">
|
|
43
|
+
<div class="step-title-row">
|
|
44
|
+
<span class="step-title">{{ node.nodeName }}</span>
|
|
45
|
+
<t-tag :theme="getNodeStatusTheme(node)" size="small">
|
|
46
|
+
{{ getNodeStatusText(node) }}
|
|
47
|
+
</t-tag>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<!-- 简化的审批人信息 -->
|
|
53
|
+
<div class="step-content">
|
|
54
|
+
<!-- 已完成节点 -->
|
|
55
|
+
<div v-for="approver in getCompletedApprovers(node)"
|
|
56
|
+
:key="approver.nodeUser?.userId || approver.userId" class="simple-approver-wrapper">
|
|
57
|
+
<div class="simple-approver">
|
|
58
|
+
<!-- 操作用户信息 -->
|
|
59
|
+
<div class="approver-user-info">
|
|
60
|
+
<user-info :userId="approver.nodeUser?.userId || approver.userId"
|
|
61
|
+
:userInfo="getUserInfo(approver)" avatar-size="small" name-size="small"
|
|
62
|
+
:show-department="false" />
|
|
63
|
+
</div>
|
|
64
|
+
|
|
65
|
+
<!-- 操作类型和时间 -->
|
|
66
|
+
<div class="approver-action-info">
|
|
67
|
+
<div class="action-type">{{ getOperationTypeText(approver) }}</div>
|
|
68
|
+
<div class="approver-time">{{ formatTime(approver.operation?.operationTime ||
|
|
69
|
+
approver.completedTime || approver.endTime) }}</div>
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<!-- 目标用户信息(转审、加签等操作) -->
|
|
74
|
+
<div v-if="approver.targetUser && needShowTargetUser(approver)"
|
|
75
|
+
class="target-user-info">
|
|
76
|
+
<div class="target-label">{{ getTargetUserLabel(approver) }}</div>
|
|
77
|
+
<user-info :userId="approver.targetUser.userId"
|
|
78
|
+
:userInfo="getTargetUserInfo(approver)" avatar-size="small" name-size="small"
|
|
79
|
+
:show-department="false" />
|
|
80
|
+
</div>
|
|
81
|
+
|
|
82
|
+
<!-- 评论信息 -->
|
|
83
|
+
<div v-if="approver.comment" class="approver-comment">{{ approver.comment }}</div>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
<!-- 进行中节点 -->
|
|
87
|
+
<!-- 当前处理人 -->
|
|
88
|
+
<div v-if="getCurrentApprover(node)" class="simple-approver">
|
|
89
|
+
<user-info
|
|
90
|
+
:userId="getCurrentApprover(node).nodeUser?.userId || getCurrentApprover(node).userId"
|
|
91
|
+
:userInfo="getUserInfo(getCurrentApprover(node))" avatar-size="small"
|
|
92
|
+
name-size="small" :show-department="false" />
|
|
93
|
+
<div class="approver-time">处理中</div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<!-- 待处理人 -->
|
|
97
|
+
<div v-for="approver in getPendingApprovers(node)"
|
|
98
|
+
:key="'pending-' + (approver.nodeUser?.userId || approver.userId)"
|
|
99
|
+
class="simple-approver">
|
|
100
|
+
<user-info :userId="approver.nodeUser?.userId || approver.userId"
|
|
101
|
+
:userInfo="getUserInfo(approver)" avatar-size="small" name-size="small"
|
|
102
|
+
:show-department="false" />
|
|
103
|
+
<!-- <div class="approver-time">待处理</div> -->
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
<!-- 抄送人步骤 -->
|
|
109
|
+
<div v-if="state.processInfo" class="simple-step-item">
|
|
110
|
+
<div class="step-header">
|
|
111
|
+
<div class="step-icon" :class="getCcSimpleIconClass()">
|
|
112
|
+
<t-icon name="mail" size="12px" color="white" />
|
|
113
|
+
</div>
|
|
114
|
+
<div class="step-info">
|
|
115
|
+
<div class="step-title-row">
|
|
116
|
+
<span class="step-title">抄送</span>
|
|
117
|
+
<!-- 增加抄送人按钮 -->
|
|
118
|
+
<t-button theme="default" variant="outline" size="mini" @click="handleAddCcUser"
|
|
119
|
+
class="add-cc-button-inline">
|
|
120
|
+
<t-icon name="add" size="12px" />
|
|
121
|
+
增加抄送人
|
|
122
|
+
</t-button>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<div class="step-content">
|
|
128
|
+
<div v-for="ccUser in state.processInfo.ccUserList"
|
|
129
|
+
:key="ccUser.nodeUser?.userId || ccUser.userId" class="simple-approver">
|
|
130
|
+
<user-info :userId="ccUser.nodeUser?.userId || ccUser.userId"
|
|
131
|
+
:userInfo="ccUser.nodeUser || ccUser" avatar-size="small" name-size="small"
|
|
132
|
+
:show-department="false" />
|
|
133
|
+
<div class="approver-time">{{ getCcTimeText() }}</div>
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
</div>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
<ebiz-employee-selector :single="false" defaultTab="organization" class="component-base-style"
|
|
141
|
+
v-model="state.selectedCCList" v-model:visible="state.showCcListSelector" @confirm="onAddCcListConfirm">
|
|
142
|
+
</ebiz-employee-selector>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</template>
|
|
146
|
+
|
|
147
|
+
<script>
|
|
148
|
+
/**
|
|
149
|
+
* @displayName 审批流程
|
|
150
|
+
* @description 审批流程组件,用于展示审批流程的详细信息
|
|
151
|
+
* @category 业务组件
|
|
152
|
+
* @name EbizApprovalProcess
|
|
153
|
+
*/
|
|
154
|
+
export default {
|
|
155
|
+
name: "EbizApprovalProcess",
|
|
156
|
+
components: {
|
|
157
|
+
't-tag': Tag,
|
|
158
|
+
't-icon': Icon,
|
|
159
|
+
't-button': Button
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
</script>
|
|
163
|
+
|
|
164
|
+
<script setup>
|
|
165
|
+
import { reactive, onMounted } from 'vue'
|
|
166
|
+
import { defineProps, defineEmits } from 'vue'
|
|
167
|
+
import { Tag, Icon, Button, MessagePlugin as message } from 'tdesign-vue-next'
|
|
168
|
+
import EbizEmployeeSelector from './EbizEmployeeSelector.vue'
|
|
169
|
+
import EbizTdesignLoading from './EbizTdesignLoading.vue'
|
|
170
|
+
import dataService from '../apiService/simpleDataService.js'
|
|
171
|
+
import UserInfo from './mItems/UserInfo.vue'
|
|
172
|
+
|
|
173
|
+
// 定义 props
|
|
174
|
+
const props = defineProps({
|
|
175
|
+
/**
|
|
176
|
+
* 业务键
|
|
177
|
+
*/
|
|
178
|
+
businessKey: {
|
|
179
|
+
type: String,
|
|
180
|
+
default: ''
|
|
181
|
+
},
|
|
182
|
+
/**
|
|
183
|
+
* 业务类型
|
|
184
|
+
*/
|
|
185
|
+
type: {
|
|
186
|
+
type: String,
|
|
187
|
+
default: ''
|
|
188
|
+
}
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
// 定义 emits
|
|
192
|
+
const emit = defineEmits(['load-success', 'add-cc-user'])
|
|
193
|
+
|
|
194
|
+
// 响应式状态
|
|
195
|
+
const state = reactive({
|
|
196
|
+
loading: false,
|
|
197
|
+
processInfo: null,
|
|
198
|
+
nodes: [], // 直接保存节点数据
|
|
199
|
+
historyRecords: [],
|
|
200
|
+
currentNodes: [],
|
|
201
|
+
futureNodes: [],
|
|
202
|
+
approvalDetail: {},
|
|
203
|
+
selectedCCList: [],
|
|
204
|
+
showCcListSelector: false
|
|
205
|
+
})
|
|
206
|
+
|
|
207
|
+
// 处理审批详情响应
|
|
208
|
+
const handleApprovalDetailResponse = (data) => {
|
|
209
|
+
// 构建流程信息
|
|
210
|
+
state.processInfo = {
|
|
211
|
+
processInstanceId: data.processInstanceId,
|
|
212
|
+
businessKey: data.businessKey,
|
|
213
|
+
processDefinitionKey: data.processDefinitionKey,
|
|
214
|
+
processDefinitionName: data.processDefinitionName,
|
|
215
|
+
startTime: data.startTime,
|
|
216
|
+
startTimeStr: data.startTime, // 使用startTime作为显示时间
|
|
217
|
+
endTime: data.endTime,
|
|
218
|
+
startUserId: data.startUserId,
|
|
219
|
+
startUserName: data.startUserName,
|
|
220
|
+
startUserInfo: data.startUserInfo,
|
|
221
|
+
processStatus: data.processStatus,
|
|
222
|
+
processStatusDesc: data.processStatusDesc,
|
|
223
|
+
ccUserList: data.ccUserList || []
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 直接保存节点数据,不进行拆分
|
|
227
|
+
state.nodes = data.nodes || []
|
|
228
|
+
|
|
229
|
+
// 清空原有的分类数据
|
|
230
|
+
state.historyRecords = []
|
|
231
|
+
state.currentNodes = []
|
|
232
|
+
state.futureNodes = []
|
|
233
|
+
|
|
234
|
+
state.approvalDetail = data
|
|
235
|
+
state.loading = false
|
|
236
|
+
|
|
237
|
+
emit('load-success', data)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// 处理审批详情错误
|
|
241
|
+
const handleApprovalDetailError = (err) => {
|
|
242
|
+
state.loading = false
|
|
243
|
+
message.error(err.message || '获取审批信息失败')
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// 请求审批详情
|
|
247
|
+
const requestApprovalDetail = (businessKey, type) => {
|
|
248
|
+
state.loading = true
|
|
249
|
+
|
|
250
|
+
const requestData = {
|
|
251
|
+
businessKey: businessKey,
|
|
252
|
+
businessType: type
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// 使用新的接口获取审批详情
|
|
256
|
+
dataService.fetch(
|
|
257
|
+
requestData,
|
|
258
|
+
{},
|
|
259
|
+
'/tasks/approval-detail'
|
|
260
|
+
).then((res) => {
|
|
261
|
+
console.log("approval-detail res", res)
|
|
262
|
+
handleApprovalDetailResponse(res)
|
|
263
|
+
}).catch((err) => {
|
|
264
|
+
handleApprovalDetailError(err)
|
|
265
|
+
})
|
|
266
|
+
|
|
267
|
+
// 临时测试数据(可以删除)
|
|
268
|
+
// const testData = {
|
|
269
|
+
// "processInstanceId": "130953",
|
|
270
|
+
// "businessKey": "357",
|
|
271
|
+
// "processDefinitionKey": "Out_Visitor_Application",
|
|
272
|
+
// "processDefinitionName": "访客自助登记",
|
|
273
|
+
// "processStatus": "ACTIVE",
|
|
274
|
+
// "processStatusDesc": "进行中",
|
|
275
|
+
// "startTime": "2025-06-13 16:04:52",
|
|
276
|
+
// "startUserId": null,
|
|
277
|
+
// "endTime": null,
|
|
278
|
+
// "ccUserList": [
|
|
279
|
+
// {
|
|
280
|
+
// "userId": "3180",
|
|
281
|
+
// "name": "邓强杰",
|
|
282
|
+
// "employeeNo": "4879",
|
|
283
|
+
// "photo": "http://oas.guokeai.cn:9003/upload/20250529/20250529_26f77dfaf1324a96b341e4b9b142ae23.jpg",
|
|
284
|
+
// "deptName": "技术部"
|
|
285
|
+
// }
|
|
286
|
+
// ],
|
|
287
|
+
// "nodes": [
|
|
288
|
+
// {
|
|
289
|
+
// "nodeId": "receiver",
|
|
290
|
+
// "nodeName": "接待人审批",
|
|
291
|
+
// "nodeStatus": "COMPLETED",
|
|
292
|
+
// "isMultiInstance": false,
|
|
293
|
+
// "approvers": [
|
|
294
|
+
// {
|
|
295
|
+
// "userId": "3176",
|
|
296
|
+
// "userName": "吴跃忠",
|
|
297
|
+
// "employeeNo": "LaiRiFangZhang",
|
|
298
|
+
// "deptName": "技术部",
|
|
299
|
+
// "approvalStatus": "COMPLETED",
|
|
300
|
+
// "completedTime": "2025-06-13 16:06:11"
|
|
301
|
+
// }
|
|
302
|
+
// ]
|
|
303
|
+
// }
|
|
304
|
+
// ]
|
|
305
|
+
// }
|
|
306
|
+
// handleApprovalDetailResponse(testData)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// 获取操作类型的样式类
|
|
310
|
+
const getOperationClass = (operationType, operationResult) => {
|
|
311
|
+
const typeMap = {
|
|
312
|
+
'START': 'start',
|
|
313
|
+
'COMPLETE': operationResult === '通过' ? 'approved' : operationResult === '拒绝' ? 'rejected' : 'completed',
|
|
314
|
+
'CLAIM': 'claimed',
|
|
315
|
+
'ASSIGN': 'assigned',
|
|
316
|
+
'TRANSFER': 'transferred',
|
|
317
|
+
'REJECT': 'rejected',
|
|
318
|
+
'ADD_SIGN': 'add-sign'
|
|
319
|
+
}
|
|
320
|
+
return typeMap[operationType] || 'default'
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// 获取操作类型的文本
|
|
324
|
+
const getOperationTypeText = (approver) => {
|
|
325
|
+
if (!approver.operation) {
|
|
326
|
+
return getSimpleStatusText(null, approver)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const operationType = approver.operation.operationType
|
|
330
|
+
switch (operationType) {
|
|
331
|
+
case 'COMPLETE':
|
|
332
|
+
// 从operationData中获取审批结果
|
|
333
|
+
try {
|
|
334
|
+
const operationData = JSON.parse(approver.operation.operationData || '{}')
|
|
335
|
+
if (operationData.approved === true) {
|
|
336
|
+
return '已同意'
|
|
337
|
+
} else if (operationData.approved === false) {
|
|
338
|
+
return '已拒绝'
|
|
339
|
+
}
|
|
340
|
+
} catch (e) {
|
|
341
|
+
// 解析失败,使用默认逻辑
|
|
342
|
+
}
|
|
343
|
+
return '已完成'
|
|
344
|
+
case 'TRANSFER':
|
|
345
|
+
return '转审'
|
|
346
|
+
case 'ADD_SIGN':
|
|
347
|
+
return '加签'
|
|
348
|
+
case 'REJECT':
|
|
349
|
+
return '退回'
|
|
350
|
+
case 'CLAIM':
|
|
351
|
+
return '认领'
|
|
352
|
+
case 'ASSIGN':
|
|
353
|
+
return '分配'
|
|
354
|
+
default:
|
|
355
|
+
return '已处理'
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// 获取流程状态主题
|
|
360
|
+
const getProcessStatusTheme = (status) => {
|
|
361
|
+
const statusMap = {
|
|
362
|
+
'ACTIVE': 'primary',
|
|
363
|
+
'COMPLETED': 'success',
|
|
364
|
+
'SUSPENDED': 'warning'
|
|
365
|
+
}
|
|
366
|
+
return statusMap[status] || 'default'
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// 获取流程状态文本
|
|
370
|
+
const getProcessStatusText = (status) => {
|
|
371
|
+
const statusMap = {
|
|
372
|
+
'ACTIVE': '进行中',
|
|
373
|
+
'COMPLETED': '已完成',
|
|
374
|
+
'SUSPENDED': '已暂停'
|
|
375
|
+
}
|
|
376
|
+
return statusMap[status] || status
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
// 获取当前步骤索引
|
|
380
|
+
const getCurrentStepIndex = () => {
|
|
381
|
+
// 已完成节点数量
|
|
382
|
+
const completedNodes = state.nodes.filter(node => node.nodeStatus === 'COMPLETED').length
|
|
383
|
+
return completedNodes
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// 获取节点步骤状态
|
|
387
|
+
const getNodeStepStatus = (node) => {
|
|
388
|
+
switch (node.nodeStatus) {
|
|
389
|
+
case 'COMPLETED':
|
|
390
|
+
return 'finish'
|
|
391
|
+
case 'ACTIVE':
|
|
392
|
+
return 'process'
|
|
393
|
+
default:
|
|
394
|
+
return 'wait'
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// 获取节点步骤样式类
|
|
399
|
+
const getNodeStepClass = (node) => {
|
|
400
|
+
switch (node.nodeStatus) {
|
|
401
|
+
case 'ACTIVE':
|
|
402
|
+
return 'current-step'
|
|
403
|
+
case 'PENDING':
|
|
404
|
+
case 'WAITING':
|
|
405
|
+
return 'future-step'
|
|
406
|
+
default:
|
|
407
|
+
return ''
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// 获取节点状态主题
|
|
412
|
+
const getNodeStatusTheme = (node) => {
|
|
413
|
+
switch (node.nodeStatus) {
|
|
414
|
+
case 'COMPLETED':
|
|
415
|
+
return 'success'
|
|
416
|
+
case 'ACTIVE':
|
|
417
|
+
return 'primary'
|
|
418
|
+
default:
|
|
419
|
+
return 'default'
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// 获取节点状态文本
|
|
424
|
+
const getNodeStatusText = (node) => {
|
|
425
|
+
switch (node.nodeStatus) {
|
|
426
|
+
case 'COMPLETED':
|
|
427
|
+
return '已完成'
|
|
428
|
+
case 'ACTIVE':
|
|
429
|
+
return '进行中'
|
|
430
|
+
default:
|
|
431
|
+
return '未开始'
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// 获取已完成的审批人
|
|
436
|
+
const getCompletedApprovers = (node) => {
|
|
437
|
+
if (!node.approvers) return []
|
|
438
|
+
return node.approvers.filter(approver => approver.approvalStatus === 'COMPLETED')
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
// 获取当前审批人
|
|
442
|
+
const getCurrentApprover = (node) => {
|
|
443
|
+
if (!node.approvers) return null
|
|
444
|
+
return node.approvers.find(approver => approver.approvalStatus === 'ACTIVE' && approver.isCurrent)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// 获取待处理审批人
|
|
448
|
+
const getPendingApprovers = (node) => {
|
|
449
|
+
if (!node.approvers) return []
|
|
450
|
+
return node.approvers.filter(approver => approver.approvalStatus === 'PENDING')
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// 获取用户信息
|
|
454
|
+
const getUserInfo = (approver) => {
|
|
455
|
+
// 新数据结构:用户信息在nodeUser对象中
|
|
456
|
+
const userInfo = approver.nodeUser || approver
|
|
457
|
+
return {
|
|
458
|
+
userId: userInfo.userId,
|
|
459
|
+
name: userInfo.userName,
|
|
460
|
+
employeeNo: userInfo.employeeNo,
|
|
461
|
+
photo: userInfo.photo,
|
|
462
|
+
departmentName: userInfo.deptName,
|
|
463
|
+
position: userInfo.position,
|
|
464
|
+
phone: userInfo.phone,
|
|
465
|
+
email: userInfo.email
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// 判断流程是否已完成
|
|
470
|
+
const isProcessCompleted = () => {
|
|
471
|
+
return state.processInfo && state.processInfo.processStatus === 'COMPLETED'
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// 获取抄送步骤状态
|
|
475
|
+
const getCcStepStatus = () => {
|
|
476
|
+
return isProcessCompleted() ? 'finish' : 'wait'
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// 获取抄送步骤样式类
|
|
480
|
+
const getCcStepClass = () => {
|
|
481
|
+
return isProcessCompleted() ? '' : 'future-step'
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// 获取抄送状态样式类
|
|
485
|
+
const getCcStatusClass = () => {
|
|
486
|
+
return isProcessCompleted() ? 'cc-status' : 'cc-pending'
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
// 获取抄送状态文本
|
|
490
|
+
const getCcStatusText = () => {
|
|
491
|
+
return isProcessCompleted() ? '已抄送' : '待抄送'
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
// 获取简单步骤图标类
|
|
495
|
+
const getSimpleStepIconClass = (node) => {
|
|
496
|
+
switch (node.nodeStatus) {
|
|
497
|
+
case 'COMPLETED':
|
|
498
|
+
return 'step-icon-completed'
|
|
499
|
+
case 'ACTIVE':
|
|
500
|
+
return 'step-icon-active'
|
|
501
|
+
default:
|
|
502
|
+
return 'step-icon-waiting'
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// 获取抄送简单图标类
|
|
507
|
+
const getCcSimpleIconClass = () => {
|
|
508
|
+
return isProcessCompleted() ? 'step-icon-completed' : 'step-icon-waiting'
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// 获取简单状态文本
|
|
512
|
+
const getSimpleStatusText = (node, approver) => {
|
|
513
|
+
// 优先使用approvalResult
|
|
514
|
+
if (approver.approvalResult) {
|
|
515
|
+
return approver.approvalResult === '通过' ? '已同意' : approver.approvalResult === '拒绝' ? '已拒绝' : '已完成'
|
|
516
|
+
}
|
|
517
|
+
// 如果没有approvalResult,使用approved字段
|
|
518
|
+
if (approver.approved !== null && approver.approved !== undefined) {
|
|
519
|
+
return approver.approved ? '已同意' : '已拒绝'
|
|
520
|
+
}
|
|
521
|
+
// 默认返回已完成
|
|
522
|
+
return '已完成'
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// 格式化时间
|
|
526
|
+
const formatTime = (timeStr) => {
|
|
527
|
+
if (!timeStr) return '--'
|
|
528
|
+
|
|
529
|
+
let date
|
|
530
|
+
// 如果是数字(时间戳),直接使用
|
|
531
|
+
if (typeof timeStr === 'number') {
|
|
532
|
+
date = new Date(timeStr)
|
|
533
|
+
} else {
|
|
534
|
+
// 如果是字符串,尝试解析
|
|
535
|
+
date = new Date(timeStr)
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (isNaN(date.getTime())) return timeStr
|
|
539
|
+
|
|
540
|
+
const month = date.getMonth() + 1
|
|
541
|
+
const day = date.getDate()
|
|
542
|
+
const hours = date.getHours().toString().padStart(2, '0')
|
|
543
|
+
const minutes = date.getMinutes().toString().padStart(2, '0')
|
|
544
|
+
|
|
545
|
+
return `${month}/${day} ${hours}:${minutes}`
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// 获取抄送时间文本
|
|
549
|
+
const getCcTimeText = () => {
|
|
550
|
+
if (isProcessCompleted()) {
|
|
551
|
+
return `已抄送 · ${formatTime(state.processInfo.endTime || state.processInfo.startTimeStr)}`
|
|
552
|
+
}
|
|
553
|
+
return ''
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// 获取发起人信息
|
|
557
|
+
const getStartUserInfo = () => {
|
|
558
|
+
// 优先从历史记录中查找发起人
|
|
559
|
+
const startRecord = state.historyRecords.find(record => record.operationType === 'START')
|
|
560
|
+
if (startRecord) {
|
|
561
|
+
return {
|
|
562
|
+
userId: startRecord.operatorId,
|
|
563
|
+
userInfo: startRecord.assigneeInfo
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// 如果没有发起记录,从流程信息中获取
|
|
568
|
+
if (state.processInfo && state.processInfo.startUserId) {
|
|
569
|
+
return {
|
|
570
|
+
userId: state.processInfo.startUserId,
|
|
571
|
+
userInfo: state.processInfo.startUserInfo || {
|
|
572
|
+
name: state.processInfo.startUserName || '未知用户'
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// 如果都没有,尝试从第一个已完成节点的审批人获取(可能是发起人)
|
|
578
|
+
if (state.historyRecords.length > 0) {
|
|
579
|
+
const firstRecord = state.historyRecords[0]
|
|
580
|
+
return {
|
|
581
|
+
userId: firstRecord.operatorId,
|
|
582
|
+
userInfo: firstRecord.assigneeInfo
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return { userId: '', userInfo: {} }
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// 处理增加抄送人
|
|
590
|
+
const handleAddCcUser = () => {
|
|
591
|
+
state.showCcListSelector = true
|
|
592
|
+
emit('add-cc-user', {
|
|
593
|
+
processInstanceId: state.processInfo?.processInstanceId,
|
|
594
|
+
businessKey: state.processInfo?.businessKey,
|
|
595
|
+
processDefinitionKey: state.processInfo?.processDefinitionKey
|
|
596
|
+
})
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
function onAddCcListConfirm(event) {
|
|
600
|
+
if (state.selectedCCList?.length === 0) return
|
|
601
|
+
state.showCcListSelector = false
|
|
602
|
+
dataService.fetch(
|
|
603
|
+
{
|
|
604
|
+
businessKey: state.processInfo?.businessKey,
|
|
605
|
+
type: state.processInfo?.processDefinitionKey,
|
|
606
|
+
processInstanceId: state.processInfo?.processInstanceId,
|
|
607
|
+
ccUsers: state.selectedCCList.map((item) => Number(item))
|
|
608
|
+
},
|
|
609
|
+
{},
|
|
610
|
+
'/tasks/batchAddCcInfo'
|
|
611
|
+
)
|
|
612
|
+
.then((res) => { })
|
|
613
|
+
.catch((err) => {
|
|
614
|
+
message.error(err.message)
|
|
615
|
+
})
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// 判断是否需要显示目标用户
|
|
619
|
+
const needShowTargetUser = (approver) => {
|
|
620
|
+
if (!approver.operation || !approver.targetUser) return false
|
|
621
|
+
|
|
622
|
+
const operationType = approver.operation.operationType
|
|
623
|
+
return ['TRANSFER', 'ADD_SIGN'].includes(operationType)
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// 获取目标用户标签
|
|
627
|
+
const getTargetUserLabel = (approver) => {
|
|
628
|
+
if (!approver.operation) return ''
|
|
629
|
+
|
|
630
|
+
const operationType = approver.operation.operationType
|
|
631
|
+
switch (operationType) {
|
|
632
|
+
case 'TRANSFER':
|
|
633
|
+
return '转审给:'
|
|
634
|
+
case 'ADD_SIGN':
|
|
635
|
+
return '加签:'
|
|
636
|
+
default:
|
|
637
|
+
return '目标:'
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// 获取目标用户信息
|
|
642
|
+
const getTargetUserInfo = (approver) => {
|
|
643
|
+
const targetUser = approver.targetUser
|
|
644
|
+
return {
|
|
645
|
+
userId: targetUser.userId,
|
|
646
|
+
name: targetUser.userName,
|
|
647
|
+
employeeNo: targetUser.employeeNo,
|
|
648
|
+
photo: targetUser.photo,
|
|
649
|
+
departmentName: targetUser.deptName,
|
|
650
|
+
position: targetUser.position,
|
|
651
|
+
phone: targetUser.phone,
|
|
652
|
+
email: targetUser.email
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// 组件挂载时请求数据
|
|
657
|
+
onMounted(() => {
|
|
658
|
+
if (props.businessKey && props.type) {
|
|
659
|
+
requestApprovalDetail(String(props.businessKey), props.type)
|
|
660
|
+
}
|
|
661
|
+
})
|
|
662
|
+
|
|
663
|
+
// 暴露方法供外部调用
|
|
664
|
+
defineExpose({
|
|
665
|
+
requestApprovalDetail,
|
|
666
|
+
state
|
|
667
|
+
})
|
|
668
|
+
</script>
|
|
669
|
+
|
|
670
|
+
<style scoped>
|
|
671
|
+
.ebiz-approval-process {
|
|
672
|
+
width: 100%;
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
.card {
|
|
676
|
+
background-color: #ffffff;
|
|
677
|
+
padding: 10px;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
.title {
|
|
681
|
+
font-size: 16px;
|
|
682
|
+
font-weight: bold;
|
|
683
|
+
color: #333;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.process-info {
|
|
687
|
+
background-color: #fafafa;
|
|
688
|
+
padding: 10px 12px;
|
|
689
|
+
border-radius: 6px;
|
|
690
|
+
margin-bottom: 12px;
|
|
691
|
+
border: 1px solid #f0f0f0;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.info-item {
|
|
695
|
+
display: flex;
|
|
696
|
+
align-items: center;
|
|
697
|
+
margin-bottom: 6px;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
.info-item:last-child {
|
|
701
|
+
margin-bottom: 0;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
.label {
|
|
705
|
+
font-weight: 500;
|
|
706
|
+
color: #595959;
|
|
707
|
+
margin-right: 8px;
|
|
708
|
+
min-width: 70px;
|
|
709
|
+
font-size: 13px;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
.step-content {
|
|
713
|
+
/* padding: 8px 0; */
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.operation-info {
|
|
717
|
+
margin-bottom: 8px;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.operation-tag {
|
|
721
|
+
padding: 4px 8px;
|
|
722
|
+
border-radius: 4px;
|
|
723
|
+
font-size: 12px;
|
|
724
|
+
font-weight: 500;
|
|
725
|
+
display: inline-block;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.operation-tag.start {
|
|
729
|
+
background-color: #f3e5f5;
|
|
730
|
+
color: #7b1fa2;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
.operation-tag.approved {
|
|
734
|
+
background-color: #e8f5e8;
|
|
735
|
+
color: #388e3c;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.operation-tag.rejected {
|
|
739
|
+
background-color: #ffebee;
|
|
740
|
+
color: #d32f2f;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.operation-tag.completed {
|
|
744
|
+
background-color: #e3f2fd;
|
|
745
|
+
color: #1976d2;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
.operation-tag.claimed {
|
|
749
|
+
background-color: #f3e5f5;
|
|
750
|
+
color: #7b1fa2;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
.operation-tag.assigned {
|
|
754
|
+
background-color: #e0f2f1;
|
|
755
|
+
color: #00695c;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.operation-tag.transferred {
|
|
759
|
+
background-color: #fff8e1;
|
|
760
|
+
color: #f57c00;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
.operation-tag.add-sign {
|
|
764
|
+
background-color: #fce4ec;
|
|
765
|
+
color: #c2185b;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.operation-tag.pending {
|
|
769
|
+
background-color: #fff3e0;
|
|
770
|
+
color: #f57c00;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.operation-tag.future {
|
|
774
|
+
background-color: #f5f5f5;
|
|
775
|
+
color: #757575;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
.operation-tag.cc-status {
|
|
779
|
+
background-color: #fffbe6;
|
|
780
|
+
color: #faad14;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
.operation-tag.cc-pending {
|
|
784
|
+
background-color: #f5f5f5;
|
|
785
|
+
color: #999999;
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
.step-detail {
|
|
789
|
+
display: flex;
|
|
790
|
+
align-items: flex-start;
|
|
791
|
+
margin-bottom: 4px;
|
|
792
|
+
font-size: 14px;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.step-detail:last-child {
|
|
796
|
+
margin-bottom: 0;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
.current-step {
|
|
800
|
+
background-color: #f8f9fa;
|
|
801
|
+
padding: 12px;
|
|
802
|
+
border-radius: 8px;
|
|
803
|
+
border-left: 4px solid #1976d2;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
.future-step {
|
|
807
|
+
opacity: 0.7;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.multi-instance-details {
|
|
811
|
+
margin-top: 8px;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
.instance-list {
|
|
815
|
+
margin-top: 12px;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
.instance-item {
|
|
819
|
+
background-color: #ffffff;
|
|
820
|
+
border: 1px solid #e0e0e0;
|
|
821
|
+
border-radius: 6px;
|
|
822
|
+
padding: 8px;
|
|
823
|
+
margin-bottom: 8px;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.instance-item:last-child {
|
|
827
|
+
margin-bottom: 0;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
.instance-header {
|
|
831
|
+
display: flex;
|
|
832
|
+
justify-content: space-between;
|
|
833
|
+
align-items: center;
|
|
834
|
+
margin-bottom: 4px;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
.instance-status {
|
|
838
|
+
padding: 2px 6px;
|
|
839
|
+
border-radius: 3px;
|
|
840
|
+
font-size: 11px;
|
|
841
|
+
font-weight: 500;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
.instance-approved {
|
|
845
|
+
background-color: #e8f5e8;
|
|
846
|
+
color: #388e3c;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.instance-rejected {
|
|
850
|
+
background-color: #ffebee;
|
|
851
|
+
color: #d32f2f;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
.instance-completed {
|
|
855
|
+
background-color: #e3f2fd;
|
|
856
|
+
color: #1976d2;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
.instance-pending {
|
|
860
|
+
background-color: #fff3e0;
|
|
861
|
+
color: #f57c00;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
.instance-comment {
|
|
865
|
+
font-size: 12px;
|
|
866
|
+
color: #666;
|
|
867
|
+
margin-bottom: 4px;
|
|
868
|
+
line-height: 1.4;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
.instance-time {
|
|
872
|
+
font-size: 11px;
|
|
873
|
+
color: #999;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
.multi-instance-badge {
|
|
877
|
+
background-color: #e3f2fd;
|
|
878
|
+
color: #1976d2;
|
|
879
|
+
padding: 2px 6px;
|
|
880
|
+
border-radius: 3px;
|
|
881
|
+
font-size: 11px;
|
|
882
|
+
font-weight: 500;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
.instance-section {
|
|
886
|
+
margin-bottom: 12px;
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
.instance-section h5 {
|
|
890
|
+
font-size: 12px;
|
|
891
|
+
color: #666;
|
|
892
|
+
margin: 0 0 8px 0;
|
|
893
|
+
font-weight: 500;
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
.instance-section:last-child {
|
|
897
|
+
margin-bottom: 0;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
/* 用户信息相关样式 */
|
|
901
|
+
.assignee-info {
|
|
902
|
+
display: flex;
|
|
903
|
+
align-items: center;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.approver-info {
|
|
907
|
+
margin-bottom: 12px;
|
|
908
|
+
padding-bottom: 8px;
|
|
909
|
+
border-bottom: 1px solid #f0f0f0;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
.approver-info:last-child {
|
|
913
|
+
margin-bottom: 0;
|
|
914
|
+
border-bottom: none;
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
.candidate-users {
|
|
918
|
+
display: flex;
|
|
919
|
+
flex-wrap: wrap;
|
|
920
|
+
gap: 8px;
|
|
921
|
+
align-items: center;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
.candidate-user {
|
|
925
|
+
background-color: #f8f9fa;
|
|
926
|
+
padding: 4px 8px;
|
|
927
|
+
border-radius: 12px;
|
|
928
|
+
border: 1px solid #e9ecef;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/* 抄送人相关样式 */
|
|
932
|
+
.cc-users {
|
|
933
|
+
display: flex;
|
|
934
|
+
flex-wrap: wrap;
|
|
935
|
+
gap: 6px;
|
|
936
|
+
align-items: center;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
.cc-user {
|
|
940
|
+
background-color: #f6ffed;
|
|
941
|
+
padding: 3px 6px;
|
|
942
|
+
border-radius: 10px;
|
|
943
|
+
border: 1px solid #d9f7be;
|
|
944
|
+
font-size: 12px;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
.cc-users-list {
|
|
948
|
+
display: flex;
|
|
949
|
+
flex-direction: column;
|
|
950
|
+
gap: 8px;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.cc-user-item {
|
|
954
|
+
background-color: #fffbe6;
|
|
955
|
+
padding: 8px;
|
|
956
|
+
border-radius: 8px;
|
|
957
|
+
border: 1px solid #ffd666;
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
/* 简化审批步骤样式 */
|
|
961
|
+
.simple-approval-steps {
|
|
962
|
+
background-color: #ffffff;
|
|
963
|
+
padding: 12px 16px;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
.simple-step-item {
|
|
967
|
+
position: relative;
|
|
968
|
+
padding-bottom: 16px;
|
|
969
|
+
border-left: 2px solid #e8e8e8;
|
|
970
|
+
margin-left: 10px;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
.simple-step-item:last-child {
|
|
974
|
+
border-left: none;
|
|
975
|
+
padding-bottom: 0;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
.step-header {
|
|
979
|
+
display: flex;
|
|
980
|
+
align-items: center;
|
|
981
|
+
margin-bottom: 8px;
|
|
982
|
+
margin-left: -11px;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
.step-icon {
|
|
986
|
+
width: 20px;
|
|
987
|
+
height: 20px;
|
|
988
|
+
border-radius: 50%;
|
|
989
|
+
display: flex;
|
|
990
|
+
align-items: center;
|
|
991
|
+
justify-content: center;
|
|
992
|
+
margin-right: 10px;
|
|
993
|
+
flex-shrink: 0;
|
|
994
|
+
position: relative;
|
|
995
|
+
z-index: 1;
|
|
996
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
.step-icon-completed {
|
|
1000
|
+
background: linear-gradient(135deg, #52c41a, #73d13d);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
.step-icon-active {
|
|
1004
|
+
background: linear-gradient(135deg, #1890ff, #40a9ff);
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
.step-icon-waiting {
|
|
1008
|
+
background: linear-gradient(135deg, #d9d9d9, #f0f0f0);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
.step-info {
|
|
1012
|
+
flex: 1;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
.step-title-row {
|
|
1016
|
+
display: flex;
|
|
1017
|
+
align-items: center;
|
|
1018
|
+
justify-content: space-between;
|
|
1019
|
+
width: 100%;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
.step-title {
|
|
1023
|
+
font-size: 15px;
|
|
1024
|
+
font-weight: 600;
|
|
1025
|
+
color: #262626;
|
|
1026
|
+
line-height: 1.3;
|
|
1027
|
+
flex: 1;
|
|
1028
|
+
margin-right: 8px;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
.step-status {
|
|
1032
|
+
margin-left: 8px;
|
|
1033
|
+
white-space: nowrap;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
.step-content {
|
|
1037
|
+
margin-left: 19px;
|
|
1038
|
+
padding-bottom: 4px;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
.simple-approver-wrapper {
|
|
1042
|
+
padding: 6px 0;
|
|
1043
|
+
margin: 6px 0;
|
|
1044
|
+
border-bottom: 1px solid #f5f5f5;
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
.simple-approver-wrapper:last-child {
|
|
1048
|
+
border-bottom: none;
|
|
1049
|
+
padding-bottom: 0;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
.simple-approver {
|
|
1053
|
+
display: flex;
|
|
1054
|
+
align-items: flex-start;
|
|
1055
|
+
justify-content: space-between;
|
|
1056
|
+
min-height: 40px;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
.approver-user-info {
|
|
1060
|
+
flex: 1;
|
|
1061
|
+
margin-right: 8px;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
.approver-action-info {
|
|
1065
|
+
display: flex;
|
|
1066
|
+
flex-direction: column;
|
|
1067
|
+
align-items: flex-end;
|
|
1068
|
+
white-space: nowrap;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
.action-type {
|
|
1072
|
+
font-size: 12px;
|
|
1073
|
+
font-weight: 500;
|
|
1074
|
+
color: #1890ff;
|
|
1075
|
+
margin-bottom: 2px;
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
.target-user-info {
|
|
1079
|
+
padding: 8px 12px;
|
|
1080
|
+
background-color: #f8f9fa;
|
|
1081
|
+
border-radius: 6px;
|
|
1082
|
+
border-left: 3px solid #1890ff;
|
|
1083
|
+
display: flex;
|
|
1084
|
+
align-items: center;
|
|
1085
|
+
gap: 8px;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
.target-label {
|
|
1089
|
+
font-size: 12px;
|
|
1090
|
+
color: #666;
|
|
1091
|
+
font-weight: 500;
|
|
1092
|
+
white-space: nowrap;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
.approver-time {
|
|
1096
|
+
font-size: 11px;
|
|
1097
|
+
color: #8c8c8c;
|
|
1098
|
+
margin-left: 8px;
|
|
1099
|
+
white-space: nowrap;
|
|
1100
|
+
font-weight: 500;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
.approver-comment {
|
|
1104
|
+
background-color: #fafafa;
|
|
1105
|
+
padding: 8px 12px;
|
|
1106
|
+
border-radius: 6px;
|
|
1107
|
+
font-size: 12px;
|
|
1108
|
+
color: #595959;
|
|
1109
|
+
line-height: 1.4;
|
|
1110
|
+
width: 100%;
|
|
1111
|
+
border: 1px solid #f0f0f0;
|
|
1112
|
+
box-sizing: border-box;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
/* 增加抄送人按钮样式 */
|
|
1116
|
+
.add-cc-button-inline {
|
|
1117
|
+
display: flex;
|
|
1118
|
+
align-items: center;
|
|
1119
|
+
gap: 4px;
|
|
1120
|
+
font-size: 11px;
|
|
1121
|
+
border-color: #d9d9d9;
|
|
1122
|
+
color: #666;
|
|
1123
|
+
height: 24px;
|
|
1124
|
+
padding: 0 8px;
|
|
1125
|
+
white-space: nowrap;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
.add-cc-button-inline:hover {
|
|
1129
|
+
border-color: #1890ff;
|
|
1130
|
+
color: #1890ff;
|
|
1131
|
+
}
|
|
1132
|
+
</style>
|