9
9
:icon =" getApprovalNodeIcon(activity.status, activity.nodeType)"
10
10
:color =" getApprovalNodeColor(activity.status)"
11
11
>
12
+ <template #dot >
13
+ <div
14
+ class =" position-absolute left--10px top--6px rounded-full border border-solid border-#dedede w-30px h-30px flex justify-center items-center bg-#3f73f7 p-5px"
15
+ >
16
+ <img class =" w-full h-full" :src =" getApprovalNodeImg(activity.nodeType)" alt =" " />
17
+ <div
18
+ class =" position-absolute top-17px left-17px bg-#fff rounded-full flex items-center p-2px"
19
+ >
20
+ <el-icon :size =" 12" :color =" getApprovalNodeColor(activity.status)" >
21
+ <component :is =" getApprovalNodeIcon(activity.status, activity.nodeType)" />
22
+ </el-icon >
23
+ </div >
24
+ </div >
25
+ </template >
12
26
<div class =" flex flex-col items-start" >
13
- <div class =" font-bold" > {{ activity.name }}</div >
27
+ <!-- 第一行:节点名称、时间 -->
28
+ <div class =" flex w-full" >
29
+ <div class =" font-bold" > {{ activity.name }}</div >
30
+ <!-- 信息:时间 -->
31
+ <div
32
+ v-if =" activity.status !== TaskStatusEnum.NOT_START"
33
+ class =" text-#a5a5a5 text-13px mt-1 ml-auto"
34
+ >
35
+ {{ getApprovalNodeTime(activity) }}
36
+ </div >
37
+ </div >
14
38
<div class =" flex items-center flex-wrap mt-1" >
15
39
<!-- 情况一:遍历每个审批节点下的【进行中】task 任务 -->
16
40
<div v-for =" (task, idx) in activity.tasks" :key =" idx" class =" flex items-center" >
17
- <div class =" flex flex-col pr-2" >
18
- <div class =" position-relative" v-if =" task.assigneeUser || task.ownerUser" >
19
- <!-- 信息:头像 -->
20
- <el-avatar
21
- v-if =" task.assigneeUser && task.assigneeUser.avatar"
22
- :size =" 36"
23
- :src =" task.assigneeUser.avatar"
24
- />
25
- <el-avatar v-else-if =" task.assigneeUser && task.assigneeUser.nickname" >
26
- {{ task.assigneeUser.nickname.substring(0, 1) }}
27
- </el-avatar >
28
- <el-avatar
29
- v-else-if =" task.ownerUser && task.ownerUser.avatar"
30
- :src =" task.ownerUser.avatar"
31
- />
32
- <el-avatar v-else-if =" task.ownerUser && task.ownerUser.nickname" >
33
- {{ task.ownerUser.nickname.substring(0, 1) }}
34
- </el-avatar >
35
- <!-- 信息:任务 ICON -->
41
+ <div class =" flex flex-col pr-2 gap2" >
42
+ <div
43
+ class =" position-relative flex flex-wrap gap2"
44
+ v-if =" task.assigneeUser || task.ownerUser"
45
+ >
46
+ <!-- 信息:头像昵称 -->
36
47
<div
37
- class =" position-absolute top-26px left-26px bg-#fff rounded-full flex items-center p-2px "
48
+ class =" bg-gray-100 h-35px rounded-3xl flex items-center p-8px gap-2 dark:color-gray-600 position-relative "
38
49
>
39
- <Icon
40
- :size =" 12"
41
- :icon =" statusIconMap2[task.status]?.icon"
42
- :color =" statusIconMap2[task.status]?.color"
43
- />
44
- </div >
45
- </div >
46
- <div class =" flex flex-col mt-1" >
47
- <!-- 信息:昵称 -->
48
- <div
49
- v-if =" task.assigneeUser && task.assigneeUser.nickname"
50
- class =" text-12px text-align-center"
51
- >
52
- {{ task.assigneeUser.nickname }}
53
- </div >
54
- <div
55
- v-else-if =" task.ownerUser && task.ownerUser.nickname"
56
- class =" text-10px text-align-center"
57
- >
58
- {{ task.ownerUser.nickname }}
50
+ <template v-if =" task .assigneeUser ?.avatar || task .assigneeUser ?.nickname " >
51
+ <el-avatar
52
+ :size =" 28"
53
+ v-if =" task.assigneeUser?.avatar"
54
+ :src =" task.assigneeUser?.avatar"
55
+ />
56
+ <el-avatar :size =" 28" v-else >
57
+ {{ task.assigneeUser?.nickname.substring(0, 1) }}
58
+ </el-avatar >
59
+ {{ task.assigneeUser?.nickname }}
60
+ </template >
61
+ <template v-else-if =" task .ownerUser ?.avatar || task .ownerUser ?.nickname " >
62
+ <el-avatar
63
+ :size =" 28"
64
+ v-if =" task.ownerUser?.avatar"
65
+ :src =" task.ownerUser?.avatar"
66
+ />
67
+ <el-avatar :size =" 28" v-else >
68
+ {{ task.ownerUser?.nickname.substring(0, 1) }}
69
+ </el-avatar >
70
+ {{ task.ownerUser?.nickname }}
71
+ </template >
72
+ <!-- 信息:任务 ICON -->
73
+ <div
74
+ v-if =" onlyStatusIconShow.includes(task.status)"
75
+ class =" position-absolute top-22px left-26px bg-#fff rounded-full flex items-center p-2px"
76
+ >
77
+ <Icon
78
+ :size =" 12"
79
+ :icon =" statusIconMap2[task.status]?.icon"
80
+ :color =" statusIconMap2[task.status]?.color"
81
+ />
82
+ </div >
59
83
</div >
84
+ <!-- 情况二:遍历每个审批节点下的【候选的】task 任务。例如说,1)依次审批,2)未来的审批任务等 -->
60
85
<div
61
- v-if =" task.reason && activity.nodeType === NodeType.USER_TASK_NODE"
62
- class =" text-#a5a5a5 text-13px mt-1"
86
+ v-for =" (user, idx1) in activity.candidateUsers"
87
+ :key =" idx1"
88
+ class =" bg-gray-100 h-35px rounded-3xl flex items-center p-8px gap-2 dark:color-gray-600 position-relative"
63
89
>
64
- 审批意见:{{ task.reason }}
65
- </div >
66
- </div >
67
- </div >
68
- </div >
69
- <!-- 情况二:遍历每个审批节点下的【候选的】task 任务。例如说,1)依次审批,2)未来的审批任务等 -->
70
- <div
71
- v-for =" (user, idx1) in activity.candidateUsers"
72
- :key =" idx1"
73
- class =" flex items-center"
74
- >
75
- <div class =" flex items-center flex-col pr-2" >
76
- <div class =" position-relative" >
77
- <!-- 信息:头像 -->
78
- <el-avatar :size =" 36" v-if =" user.avatar" :src =" user.avatar" />
79
- <el-avatar v-else-if =" user.nickname && user.nickname" >
80
- {{ user.nickname.substring(0, 1) }}
81
- </el-avatar >
82
- <!-- 信息:任务 ICON -->
83
- <div
84
- class =" position-absolute top-26px left-26px bg-#fff rounded-full flex items-center p-2px"
85
- >
86
- <Icon
87
- :size =" 12"
88
- :icon =" statusIconMap2['-1']?.icon"
89
- :color =" statusIconMap2['-1']?.color"
90
- />
91
- </div >
92
- </div >
93
- <div class =" flex flex-col mt-1" >
94
- <!-- 信息:昵称 -->
95
- <div v-if =" user.nickname" class =" text-10px text-align-center" >
90
+ <el-avatar :size =" 28" v-if =" user.avatar" :src =" user.avatar" />
91
+ <el-avatar :size =" 28" v-else >
92
+ {{ user.nickname.substring(0, 1) }}
93
+ </el-avatar >
96
94
{{ user.nickname }}
95
+
96
+ <!-- 信息:任务 ICON -->
97
+ <div
98
+ v-if =" onlyStatusIconShow.includes(task.status)"
99
+ class =" position-absolute top-22px left-26px bg-#fff rounded-full flex items-center p-2px"
100
+ >
101
+ <Icon
102
+ :size =" 12"
103
+ :icon =" statusIconMap2['-1']?.icon"
104
+ :color =" statusIconMap2['-1']?.color"
105
+ />
106
+ </div >
97
107
</div >
98
108
</div >
109
+ <div
110
+ v-if =" task.reason && activity.nodeType === NodeType.USER_TASK_NODE"
111
+ class =" text-#a5a5a5 text-13px mt-1 w-full bg-#f8f8fa p2 rounded-md"
112
+ >
113
+ 审批意见:{{ task.reason }}
114
+ </div >
99
115
</div >
100
116
</div >
101
117
</div >
102
- <!-- 信息:时间 -->
103
- <div
104
- v-if =" activity.status !== TaskStatusEnum.NOT_START"
105
- class =" text-#a5a5a5 text-13px mt-1"
106
- >
107
- {{ getApprovalNodeTime(activity) }}
108
- </div >
109
118
</div >
110
119
</el-timeline-item >
111
120
</el-timeline >
@@ -117,16 +126,21 @@ import * as ProcessInstanceApi from '@/api/bpm/processInstance'
117
126
import { TaskStatusEnum } from ' @/api/bpm/task'
118
127
import { NodeType } from ' @/components/SimpleProcessDesignerV2/src/consts'
119
128
import { Check , Close , Loading , Clock , Minus , Delete } from ' @element-plus/icons-vue'
129
+ import starterSvg from ' @/assets/svgs/bpm/starter.svg'
130
+ import auditorSvg from ' @/assets/svgs/bpm/auditor.svg'
131
+ import copySvg from ' @/assets/svgs/bpm/copy.svg'
132
+ import conditionSvg from ' @/assets/svgs/bpm/condition.svg'
133
+ import parallelSvg from ' @/assets/svgs/bpm/parallel.svg'
134
+
120
135
defineOptions ({ name: ' BpmProcessInstanceTimeline' })
121
136
defineProps <{
122
137
approveNodes: ProcessInstanceApi .ApprovalNodeInfo [] // 审批节点信息
123
138
}>()
124
139
125
140
// 审批节点
126
-
127
141
const statusIconMap2 = {
128
142
// 未开始
129
- ' -1' : { color: ' #e5e7ec ' , icon: ' ep-clock' },
143
+ ' -1' : { color: ' #909398 ' , icon: ' ep-clock' },
130
144
// 待审批
131
145
' 0' : { color: ' #e5e7ec' , icon: ' ep:loading' },
132
146
// 审批中
@@ -147,7 +161,7 @@ const statusIconMap2 = {
147
161
148
162
const statusIconMap = {
149
163
// 审批未开始
150
- ' -1' : { color: ' #e5e7ec ' , icon: Clock },
164
+ ' -1' : { color: ' #909398 ' , icon: Clock },
151
165
' 0' : { color: ' #e5e7ec' , icon: Clock },
152
166
// 审批中
153
167
' 1' : { color: ' #448ef7' , icon: Loading },
@@ -165,6 +179,27 @@ const statusIconMap = {
165
179
' 7' : { color: ' #00b32a' , icon: Check }
166
180
}
167
181
182
+ const nodeTypeSvgMap = {
183
+ // 发起人节点
184
+ [NodeType .START_USER_NODE ]: { color: ' #ffffff' , svg: starterSvg },
185
+ // 审批人节点
186
+ [NodeType .USER_TASK_NODE ]: { color: ' #ff943e' , svg: auditorSvg },
187
+ // 抄送人节点
188
+ [NodeType .COPY_TASK_NODE ]: { color: ' #3296fb' , svg: copySvg },
189
+ // 条件分支节点
190
+ [NodeType .CONDITION_NODE ]: { color: ' #14bb83' , svg: conditionSvg },
191
+ // 并行分支节点
192
+ [NodeType .PARALLEL_BRANCH_NODE ]: { color: ' #14bb83' , svg: parallelSvg }
193
+ }
194
+
195
+ // 只有只有状态是 -1、0、1 才展示头像右小角状态小icon
196
+ const onlyStatusIconShow = [- 1 , 0 , 1 ]
197
+
198
+ // timeline时间线上icon图标
199
+ const getApprovalNodeImg = (nodeType : NodeType ) => {
200
+ return nodeTypeSvgMap [nodeType ]?.svg
201
+ }
202
+
168
203
const getApprovalNodeIcon = (taskStatus : number , nodeType : NodeType ) => {
169
204
if (taskStatus == TaskStatusEnum .NOT_START ) {
170
205
return statusIconMap [taskStatus ]?.icon
@@ -181,13 +216,13 @@ const getApprovalNodeColor = (taskStatus: number) => {
181
216
182
217
const getApprovalNodeTime = (node : ProcessInstanceApi .ApprovalNodeInfo ) => {
183
218
if (node .nodeType === NodeType .START_USER_NODE && node .startTime ) {
184
- return ` 发起时间: ${formatDate (node .startTime )}`
219
+ return ` ${formatDate (node .startTime )} `
185
220
}
186
221
if (node .endTime ) {
187
- return ` 审批时间: ${formatDate (node .endTime )}`
222
+ return ` ${formatDate (node .endTime )} `
188
223
}
189
224
if (node .startTime ) {
190
- return ` 创建时间: ${formatDate (node .startTime )}`
225
+ return ` ${formatDate (node .startTime )} `
191
226
}
192
227
}
193
228
</script >
0 commit comments