vue2-client 1.15.14 → 1.15.15
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/jest.config.js +22 -22
- package/package.json +1 -1
- package/src/base-client/components/common/XForm/demo.vue +105 -105
- package/src/base-client/components/common/XRate/demo.vue +102 -102
- package/src/pages/WorkflowDetail/WorkFlowDemo2.vue +16 -311
- package/src/pages/WorkflowDetail/WorkflowDetail.vue +20 -4
- package/src/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowHandle.vue +475 -148
- package/src/pages/WorkflowDetail/WorkflowPageDetail/WorkFlowTimeline.vue +677 -188
- package/src/pages/WorkflowDetail/WorkflowPageDetail/WorkflowLog.vue +1 -1
- package/src/pages/WorkflowDetail/WorkflowPageDetail/components/WorkflowPersonSelector.vue +25 -23
- package/src/pages/addressSelect/addressDemo.vue +24 -24
- package/src/router/async/router.map.js +1 -1
- package/src/router/index.js +27 -27
- package/src/services/api/workFlow.js +0 -4
- package/test/request.test.js +17 -17
- package/vue.config.js +2 -2
@@ -1,89 +1,153 @@
|
|
1
1
|
<template>
|
2
|
-
<div class="timeline" ref="timelineContent" style="white-space: nowrap; overflow-x: auto">
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
<
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
2
|
+
<div class="timeline-wrapper" ref="timelineContent" style="white-space: nowrap; overflow-x: auto">
|
3
|
+
<!-- 动态渲染时间轴段落 -->
|
4
|
+
<template v-for="(segment, segmentIndex) in getTimelineSegments()">
|
5
|
+
|
6
|
+
<!-- 主时间轴段落 -->
|
7
|
+
<div v-if="segment.type === 'main'" :key="'main-' + segmentIndex" class="timeline-section main-timeline">
|
8
|
+
<a-steps
|
9
|
+
:current="getCurrentStepInSection(segment.steps)"
|
10
|
+
:initial="1">
|
11
|
+
<template #progressDot="{index}">
|
12
|
+
<span v-if="!changeAble" class="step-label in-steps"><i :class="['step-icon', getStepIconColor(index, segment.steps)]"></i></span>
|
13
|
+
<span v-else :key="displayStepId" :class="['step-icon-filled digital', getStepIconColor(index, segment.steps)]">
|
14
|
+
<a-icon v-if="isStepCompleted(segment.steps[index - 1])" type="check-circle" theme="filled" :class="['step-icon-filled icon', getStepIconColor(index, segment.steps)]" />
|
15
|
+
<span v-else :class="['step-icon-filled digital', getStepIconColor(index, segment.steps)]">{{ getStepNumber(segmentIndex, index) }}</span>
|
16
|
+
</span>
|
17
|
+
</template>
|
18
|
+
|
19
|
+
<a-step
|
20
|
+
v-for="item in segment.steps"
|
21
|
+
:key="item.id"
|
22
|
+
class="step-item"
|
23
|
+
@click.stop="onStepClick(item.id)"
|
24
|
+
>
|
25
|
+
<template #title>
|
26
|
+
<div class="step-title-container">
|
27
|
+
<h3 v-if="item.name">{{ item.name }}</h3>
|
28
|
+
<!-- 判断节点特殊标识 -->
|
29
|
+
<div v-if="item.type === 'condition'" class="condition-indicators">
|
30
|
+
<a-tag color="purple" size="small" class="condition-tag">
|
31
|
+
<a-icon type="branches" /> 条件节点
|
32
|
+
</a-tag>
|
33
|
+
<a-tooltip title="此节点根据条件判断后续流程走向">
|
34
|
+
<a-icon type="question-circle" class="condition-help" />
|
35
|
+
</a-tooltip>
|
36
|
+
</div>
|
37
|
+
</div>
|
38
|
+
</template>
|
39
|
+
<template #description>
|
40
|
+
<div>
|
41
|
+
<p v-if="item.handler">负责人:
|
42
|
+
<trim-text-tail :text="item.handler" :length="14"/>
|
43
|
+
</p>
|
44
|
+
<p v-if="item.date">填报时间:{{ formatDate(item.date, 'yyyy-MM-dd hh:mm') }}</p>
|
45
|
+
<p v-if="item.deadline" :class="{ 'text-red': item.id === currentStepId && isOverdue }">截止时间:{{ formatDate(item.deadline, 'yyyy-MM-dd hh:mm') }}</p>
|
46
|
+
<p v-if="item.note">备注:
|
47
|
+
<trim-text-tail :text="item.note" :length="15"/>
|
48
|
+
</p>
|
49
|
+
</div>
|
50
|
+
</template>
|
51
|
+
</a-step>
|
52
|
+
</a-steps>
|
53
|
+
</div>
|
54
|
+
|
55
|
+
<!-- 并行分支段落 -->
|
56
|
+
<div v-else-if="segment.type === 'parallel'" :key="'parallel-' + segmentIndex" class="parallel-section">
|
57
|
+
<!-- 左侧连接线 -->
|
58
|
+
<div class="connection-line left-line"></div>
|
59
|
+
|
60
|
+
<!-- 并行分支容器 -->
|
61
|
+
<div class="parallel-branches-container">
|
62
|
+
<!-- 动态渲染并行分支 -->
|
63
|
+
<div
|
64
|
+
v-for="(branch, branchIndex) in segment.branches"
|
65
|
+
:key="'segment-' + segmentIndex + '-branch-' + branchIndex"
|
66
|
+
class="branch-row">
|
67
|
+
|
68
|
+
<!-- 分支时间轴 -->
|
69
|
+
<div :class="['branch-timeline', getBranchTimelineClass(branch)]">
|
70
|
+
<a-steps size="small" class="branch-steps">
|
71
|
+
<a-step
|
72
|
+
v-for="step in branch"
|
73
|
+
:key="'segment-' + segmentIndex + '-branch-' + branchIndex + '-step-' + step.id"
|
74
|
+
:class="['branch-step', getBranchStepClass(step)]"
|
75
|
+
@click.stop="onStepClick(step.id)">
|
76
|
+
<template #title>
|
77
|
+
<a-popover placement="top" trigger="hover" :mouseEnterDelay="0.3">
|
78
|
+
<template #content>
|
79
|
+
<div class="branch-step-popover">
|
80
|
+
<div class="popover-item" v-if="step.handler">
|
81
|
+
<span class="popover-label">负责人:</span>
|
82
|
+
<span class="popover-value">{{ step.handler }}</span>
|
83
|
+
</div>
|
84
|
+
<div class="popover-item" v-if="step.date">
|
85
|
+
<span class="popover-label">填报时间:</span>
|
86
|
+
<span class="popover-value">{{ formatDate(step.date, 'yyyy-MM-dd hh:mm') }}</span>
|
87
|
+
</div>
|
88
|
+
<div class="popover-item" v-if="step.deadline">
|
89
|
+
<span class="popover-label">截止时间:</span>
|
90
|
+
<span class="popover-value">{{ formatDate(step.deadline, 'yyyy-MM-dd hh:mm') }}</span>
|
91
|
+
</div>
|
92
|
+
<div class="popover-item" v-if="step.note">
|
93
|
+
<span class="popover-label">备注:</span>
|
94
|
+
<span class="popover-value">{{ step.note }}</span>
|
95
|
+
</div>
|
96
|
+
<div class="popover-item no-data" v-if="!step.handler && !step.date && !step.deadline && !step.note">
|
97
|
+
<span class="popover-value">暂无详细信息</span>
|
98
|
+
</div>
|
99
|
+
</div>
|
100
|
+
</template>
|
101
|
+
<template #title>
|
102
|
+
<div class="popover-title">
|
103
|
+
<a-icon type="info-circle" />
|
104
|
+
{{ step.name }} - 详细信息
|
105
|
+
</div>
|
106
|
+
</template>
|
107
|
+
<span class="branch-step-title">{{ step.name }}</span>
|
108
|
+
</a-popover>
|
109
|
+
</template>
|
110
|
+
<template #description>
|
111
|
+
<div class="branch-step-desc">
|
112
|
+
<p v-if="step.handler">{{ step.handler }}</p>
|
113
|
+
<p v-if="step.date">{{ formatDate(step.date, 'MM-dd hh:mm') }}</p>
|
114
|
+
</div>
|
115
|
+
</template>
|
116
|
+
</a-step>
|
117
|
+
</a-steps>
|
30
118
|
</div>
|
31
|
-
<!-- 并行节点特殊标识 -->
|
32
|
-
<div v-else-if="isParallelStep(item)" class="parallel-indicators">
|
33
|
-
<a-tag color="blue" size="small" class="parallel-tag">
|
34
|
-
<a-icon type="fork" /> 并行节点
|
35
|
-
</a-tag>
|
36
|
-
<a-tooltip title="此节点将启动多个并行分支">
|
37
|
-
<a-icon type="question-circle" class="parallel-help" />
|
38
|
-
</a-tooltip>
|
39
|
-
</div>
|
40
|
-
</div>
|
41
|
-
</template>
|
42
|
-
<template #description>
|
43
|
-
<div>
|
44
|
-
<p v-if="item.handler">负责人:
|
45
|
-
<trim-text-tail :text="item.handler" :length="14"/>
|
46
|
-
</p>
|
47
|
-
<p v-if="item.date">填报时间:{{ formatDate(item.date, 'yyyy-MM-dd hh:mm') }}</p>
|
48
|
-
<p v-if="item.deadline" :class="{ 'text-red': item.id === currentStepId && isOverdue }">截止时间:{{ formatDate(item.deadline, 'yyyy-MM-dd hh:mm') }}</p>
|
49
|
-
<p v-if="item.note">备注:
|
50
|
-
<trim-text-tail :text="item.note" :length="15"/>
|
51
|
-
</p>
|
52
|
-
</div>
|
53
|
-
</template>
|
54
|
-
</a-step>
|
55
|
-
|
56
|
-
<!-- 当步骤被截断时显示省略状态 -->
|
57
|
-
<a-step
|
58
|
-
v-if="hasMoreSteps"
|
59
|
-
key="more-steps"
|
60
|
-
class="step-item more-steps-item">
|
61
|
-
<template #title>
|
62
|
-
<div class="more-steps-container">
|
63
|
-
<h3>后续步骤</h3>
|
64
|
-
<a-tag color="default" size="small" class="pending-tag">
|
65
|
-
<a-icon type="ellipsis" /> 待条件确定
|
66
|
-
</a-tag>
|
67
119
|
</div>
|
68
|
-
</
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
120
|
+
</div>
|
121
|
+
|
122
|
+
<!-- 右侧连接线 -->
|
123
|
+
<div class="connection-line right-line"></div>
|
124
|
+
</div>
|
125
|
+
|
126
|
+
</template>
|
127
|
+
|
128
|
+
<!-- 当步骤被截断时显示省略状态 -->
|
129
|
+
<div class="more-steps-section" v-if="hasMoreSteps">
|
130
|
+
<a-steps :current="1" :initial="1">
|
131
|
+
<a-step
|
132
|
+
key="more-steps"
|
133
|
+
class="step-item more-steps-item">
|
134
|
+
<template #title>
|
135
|
+
<div class="more-steps-container">
|
136
|
+
<h3>后续步骤</h3>
|
137
|
+
</div>
|
138
|
+
</template>
|
139
|
+
<template #description>
|
140
|
+
<div class="more-steps-desc">
|
141
|
+
<p>根据上述条件判断结果,将继续执行相应的后续流程</p>
|
142
|
+
<p class="steps-count">剩余 {{ remainingStepsCount }} 个步骤</p>
|
143
|
+
</div>
|
144
|
+
</template>
|
145
|
+
<template #icon>
|
146
|
+
<a-icon type="more" style="color: #d9d9d9;" />
|
147
|
+
</template>
|
148
|
+
</a-step>
|
149
|
+
</a-steps>
|
150
|
+
</div>
|
87
151
|
</div>
|
88
152
|
</template>
|
89
153
|
|
@@ -135,7 +199,7 @@ export default {
|
|
135
199
|
}
|
136
200
|
},
|
137
201
|
computed: {
|
138
|
-
//
|
202
|
+
// 控制显示的步骤:当判断节点未执行时只显示到判断节点,执行后显示包括并行分支的所有步骤
|
139
203
|
displaySteps () {
|
140
204
|
const steps = this.steps || []
|
141
205
|
|
@@ -154,12 +218,12 @@ export default {
|
|
154
218
|
|
155
219
|
const firstConditionStep = steps[firstConditionStepIndex]
|
156
220
|
|
157
|
-
//
|
221
|
+
// 如果当前步骤在第一个判断节点之前或等于判断节点,只显示到判断节点
|
158
222
|
if (this.currentStepId <= firstConditionStep.id) {
|
159
223
|
return steps.slice(0, firstConditionStepIndex + 1)
|
160
224
|
}
|
161
225
|
|
162
|
-
//
|
226
|
+
// 如果判断节点已经执行,显示所有步骤(包括并行分支)
|
163
227
|
return steps
|
164
228
|
},
|
165
229
|
|
@@ -208,6 +272,138 @@ export default {
|
|
208
272
|
this.$emit('activeStep', this.displayStepId)
|
209
273
|
},
|
210
274
|
|
275
|
+
// 获取时间轴段落数据
|
276
|
+
getTimelineSegments () {
|
277
|
+
const steps = this.displaySteps
|
278
|
+
const segments = []
|
279
|
+
let currentIndex = 0
|
280
|
+
|
281
|
+
while (currentIndex < steps.length) {
|
282
|
+
// 收集连续的主流程步骤(包括并行分支入口节点)
|
283
|
+
const mainSteps = []
|
284
|
+
while (currentIndex < steps.length && !this.isParallelStep(steps[currentIndex])) {
|
285
|
+
mainSteps.push(steps[currentIndex])
|
286
|
+
|
287
|
+
// 如果当前步骤是并行分支入口,处理完后跳出循环准备处理并行分支
|
288
|
+
if (this.isParallelBranchEntry(steps[currentIndex])) {
|
289
|
+
currentIndex++
|
290
|
+
break
|
291
|
+
}
|
292
|
+
currentIndex++
|
293
|
+
}
|
294
|
+
|
295
|
+
if (mainSteps.length > 0) {
|
296
|
+
segments.push({
|
297
|
+
type: 'main',
|
298
|
+
steps: mainSteps
|
299
|
+
})
|
300
|
+
}
|
301
|
+
|
302
|
+
// 检查是否有并行分支需要处理
|
303
|
+
if (currentIndex > 0 && this.isParallelBranchEntry(steps[currentIndex - 1])) {
|
304
|
+
// 获取这个并行分支的所有步骤
|
305
|
+
const branchIndex = steps[currentIndex - 1].properties.branchIndex
|
306
|
+
const parallelSteps = this.getParallelStepsByBranchIndex(steps, branchIndex)
|
307
|
+
|
308
|
+
if (parallelSteps.length > 0) {
|
309
|
+
// 按branchPath分组
|
310
|
+
const branches = this.groupParallelSteps(parallelSteps)
|
311
|
+
segments.push({
|
312
|
+
type: 'parallel',
|
313
|
+
branches: branches
|
314
|
+
})
|
315
|
+
|
316
|
+
// 跳过已处理的并行步骤
|
317
|
+
currentIndex = this.skipProcessedParallelSteps(steps, currentIndex, parallelSteps)
|
318
|
+
}
|
319
|
+
}
|
320
|
+
}
|
321
|
+
|
322
|
+
return segments
|
323
|
+
},
|
324
|
+
|
325
|
+
// 根据branchIndex获取并行步骤
|
326
|
+
getParallelStepsByBranchIndex (steps, branchIndex) {
|
327
|
+
return steps.filter(step =>
|
328
|
+
step.properties &&
|
329
|
+
step.properties.branchPath &&
|
330
|
+
step.properties.branchPath.includes(`parallel_${branchIndex}_`)
|
331
|
+
)
|
332
|
+
},
|
333
|
+
|
334
|
+
// 将并行步骤按branchPath分组
|
335
|
+
groupParallelSteps (parallelSteps) {
|
336
|
+
const branches = {}
|
337
|
+
parallelSteps.forEach(step => {
|
338
|
+
const branchPath = step.properties.branchPath
|
339
|
+
if (!branches[branchPath]) {
|
340
|
+
branches[branchPath] = []
|
341
|
+
}
|
342
|
+
branches[branchPath].push(step)
|
343
|
+
})
|
344
|
+
|
345
|
+
// 对每个分支内的步骤按id排序
|
346
|
+
Object.keys(branches).forEach(branchPath => {
|
347
|
+
branches[branchPath].sort((a, b) => a.id - b.id)
|
348
|
+
})
|
349
|
+
|
350
|
+
return Object.values(branches)
|
351
|
+
},
|
352
|
+
|
353
|
+
// 跳过已处理的并行步骤
|
354
|
+
skipProcessedParallelSteps (steps, currentIndex, processedSteps) {
|
355
|
+
const processedIds = new Set(processedSteps.map(step => step.id))
|
356
|
+
while (currentIndex < steps.length && processedIds.has(steps[currentIndex].id)) {
|
357
|
+
currentIndex++
|
358
|
+
}
|
359
|
+
return currentIndex
|
360
|
+
},
|
361
|
+
|
362
|
+
// 判断是否为并行分支入口
|
363
|
+
isParallelBranchEntry (step) {
|
364
|
+
return step.properties &&
|
365
|
+
step.properties.branchType === 'parallelBranch'
|
366
|
+
},
|
367
|
+
|
368
|
+
// 判断是否为分支汇合节点
|
369
|
+
isBranchExit (step) {
|
370
|
+
return step.properties &&
|
371
|
+
step.properties.flowRole === 'branchExit'
|
372
|
+
},
|
373
|
+
|
374
|
+
// 获取在某个section中的当前步骤索引
|
375
|
+
getCurrentStepInSection (sectionSteps) {
|
376
|
+
if (!sectionSteps || sectionSteps.length === 0) return 0
|
377
|
+
|
378
|
+
const currentStepIndex = sectionSteps.findIndex(step => step.id === this.currentStepId)
|
379
|
+
return currentStepIndex >= 0 ? currentStepIndex + 1 : 0
|
380
|
+
},
|
381
|
+
|
382
|
+
// 获取步骤编号
|
383
|
+
getStepNumber (segmentIndex, stepIndex) {
|
384
|
+
const segments = this.getTimelineSegments()
|
385
|
+
let stepNumber = 0
|
386
|
+
|
387
|
+
// 计算前面所有段落的步骤数
|
388
|
+
for (let i = 0; i < segmentIndex; i++) {
|
389
|
+
const segment = segments[i]
|
390
|
+
if (segment.type === 'main') {
|
391
|
+
stepNumber += segment.steps.length
|
392
|
+
} else if (segment.type === 'parallel') {
|
393
|
+
// 并行分支计算总步骤数
|
394
|
+
stepNumber += segment.branches.reduce((total, branch) => total + branch.length, 0)
|
395
|
+
}
|
396
|
+
}
|
397
|
+
|
398
|
+
return stepNumber + stepIndex
|
399
|
+
},
|
400
|
+
|
401
|
+
// 判断步骤是否已完成
|
402
|
+
isStepCompleted (step) {
|
403
|
+
if (!step) return false
|
404
|
+
return step.id < this.currentStepId || this.state
|
405
|
+
},
|
406
|
+
|
211
407
|
// 判断id是否为流程中最后一个
|
212
408
|
isLastStep (stepId) {
|
213
409
|
return stepId >= this.steps.length
|
@@ -215,14 +411,16 @@ export default {
|
|
215
411
|
|
216
412
|
// 判断是否为并行步骤
|
217
413
|
isParallelStep (step) {
|
218
|
-
|
219
|
-
|
414
|
+
return step.properties &&
|
415
|
+
step.properties.branchPath &&
|
416
|
+
step.properties.branchPath.includes('parallel_')
|
220
417
|
},
|
221
418
|
|
222
419
|
// 动态展示时间线节点颜色
|
223
|
-
getStepIconColor (index) {
|
224
|
-
|
225
|
-
|
420
|
+
getStepIconColor (index, sectionSteps) {
|
421
|
+
if (!sectionSteps || !sectionSteps[index - 1]) return 'gray'
|
422
|
+
|
423
|
+
const stepId = sectionSteps[index - 1].id
|
226
424
|
|
227
425
|
if (this.changeAble && stepId === this.displayStepId) {
|
228
426
|
return 'yellow'
|
@@ -237,26 +435,66 @@ export default {
|
|
237
435
|
}
|
238
436
|
return 'gray'
|
239
437
|
},
|
438
|
+
|
439
|
+
// 获取分支步骤的CSS类
|
440
|
+
getBranchStepClass (step) {
|
441
|
+
if (!step) return 'branch-step-gray'
|
442
|
+
|
443
|
+
// 如果在可编辑状态下且是当前显示的步骤
|
444
|
+
if (this.changeAble && step.id === this.displayStepId) {
|
445
|
+
return 'branch-step-yellow'
|
446
|
+
}
|
447
|
+
|
448
|
+
// 根据 status 判断颜色
|
449
|
+
switch (step.status) {
|
450
|
+
case 0: // 未处理
|
451
|
+
return 'branch-step-gray'
|
452
|
+
case 1: // 正在处理
|
453
|
+
// 检查是否逾期
|
454
|
+
if (step.deadline && !this.state && this.formatDate(new Date(), 'yyyy-MM-dd hh:mm') > step.deadline) {
|
455
|
+
return 'branch-step-red'
|
456
|
+
}
|
457
|
+
return 'branch-step-blue'
|
458
|
+
case 2: // 已处理
|
459
|
+
return 'branch-step-green'
|
460
|
+
default:
|
461
|
+
return 'branch-step-gray'
|
462
|
+
}
|
463
|
+
},
|
464
|
+
|
465
|
+
// 获取分支时间轴的CSS类(根据分支中的步骤状态)
|
466
|
+
getBranchTimelineClass (branch) {
|
467
|
+
if (!branch || branch.length === 0) return 'branch-timeline-gray'
|
468
|
+
|
469
|
+
// 检查分支中所有步骤的状态
|
470
|
+
const hasCompleted = branch.some(step => step.status === 2) // 有已完成的
|
471
|
+
const hasProcessing = branch.some(step => step.status === 1) // 有正在处理的
|
472
|
+
const allPending = branch.every(step => step.status === 0 || step.status === undefined) // 全部未处理
|
473
|
+
|
474
|
+
// 优先级:正在处理 > 已完成 > 未处理
|
475
|
+
if (hasProcessing) {
|
476
|
+
return 'branch-timeline-blue' // 正在进行
|
477
|
+
} else if (hasCompleted) {
|
478
|
+
return 'branch-timeline-green' // 已完成
|
479
|
+
} else if (allPending) {
|
480
|
+
return 'branch-timeline-gray' // 未抵达
|
481
|
+
} else {
|
482
|
+
return 'branch-timeline-gray' // 默认
|
483
|
+
}
|
484
|
+
},
|
485
|
+
|
240
486
|
onStepClick (stepId) {
|
241
|
-
console.log('stepId', stepId)
|
242
487
|
if (!this.changeAble || stepId === this.displayStepId) {
|
243
488
|
return
|
244
489
|
}
|
245
|
-
|
490
|
+
const curStep = this.steps.find(item => item.id === stepId)
|
491
|
+
if (stepId > this.currentStepId && curStep.status !== 1 && curStep.status !== 2) {
|
246
492
|
return this.$message.warn('请先完成当前步骤')
|
247
493
|
}
|
248
494
|
this.$emit('activeStep', stepId)
|
249
495
|
this.displayStepId = stepId
|
250
496
|
},
|
251
497
|
|
252
|
-
// 切换显示所有步骤
|
253
|
-
// toggleShowAllSteps () {
|
254
|
-
// this.showAllSteps = !this.showAllSteps
|
255
|
-
// if (this.showAllSteps) {
|
256
|
-
// this.$message.info('已展示全部步骤,部分步骤可能根据条件判断而不执行')
|
257
|
-
// }
|
258
|
-
// },
|
259
|
-
|
260
498
|
formatDate,
|
261
499
|
},
|
262
500
|
watch: {
|
@@ -268,64 +506,285 @@ export default {
|
|
268
506
|
</script>
|
269
507
|
|
270
508
|
<style lang="less" scoped>
|
271
|
-
.timeline {
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
509
|
+
.timeline-wrapper {
|
510
|
+
display: flex;
|
511
|
+
align-items: flex-start;
|
512
|
+
gap: 0;
|
513
|
+
|
514
|
+
.timeline-section {
|
515
|
+
flex-shrink: 0;
|
516
|
+
|
517
|
+
/deep/ .ant-steps-dot {
|
518
|
+
margin-bottom: 6px;
|
519
|
+
.ant-steps-item-tail {
|
520
|
+
top: 7px;
|
521
|
+
margin-left: 106px;
|
522
|
+
width: calc(100% - 23px);
|
523
|
+
}
|
524
|
+
.ant-steps-item-icon {
|
525
|
+
margin-left: 90px;
|
526
|
+
width: 8px;
|
527
|
+
height: 8px;
|
528
|
+
line-height: 8px;
|
529
|
+
}
|
530
|
+
.ant-steps-item-content {
|
531
|
+
min-width: 195px;
|
532
|
+
margin-top: 24px;
|
533
|
+
.ant-steps-item-description {
|
534
|
+
text-align: left;
|
535
|
+
background: #fff;
|
536
|
+
border-radius: 4px;
|
537
|
+
padding: 12px;
|
538
|
+
position: relative;
|
539
|
+
|
540
|
+
p {
|
541
|
+
position: relative;
|
542
|
+
padding: 8px 0;
|
543
|
+
margin: 0;
|
544
|
+
font-size: 13px;
|
545
|
+
color: #595959;
|
546
|
+
line-height: 1.5;
|
547
|
+
white-space: nowrap;
|
548
|
+
overflow: visible;
|
549
|
+
|
550
|
+
&:first-child {
|
551
|
+
border-top: 1px dotted #e8e8e8;
|
552
|
+
}
|
553
|
+
|
554
|
+
&:not(:last-child) {
|
555
|
+
border-bottom: 1px dashed #f0f0f0;
|
556
|
+
}
|
557
|
+
|
558
|
+
&:last-child {
|
559
|
+
padding-bottom: 0;
|
560
|
+
}
|
561
|
+
}
|
562
|
+
}
|
563
|
+
}
|
564
|
+
&.ant-steps {
|
565
|
+
padding-top: 8px;
|
566
|
+
}
|
278
567
|
}
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
568
|
+
|
569
|
+
/deep/ .ant-steps-item-title {
|
570
|
+
font-size: 14px;
|
571
|
+
h3 {
|
572
|
+
margin-bottom: 0;
|
573
|
+
}
|
284
574
|
}
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
575
|
+
}
|
576
|
+
|
577
|
+
.parallel-section {
|
578
|
+
display: flex;
|
579
|
+
align-items: flex-start;
|
580
|
+
position: relative;
|
581
|
+
|
582
|
+
.connection-line {
|
583
|
+
width: 2rem;
|
584
|
+
height: 0px;
|
585
|
+
// background: #f0f0f0;
|
586
|
+
flex-shrink: 0;
|
587
|
+
margin-top: 1rem;
|
588
|
+
|
589
|
+
&.left-line {
|
590
|
+
margin-right: 0;
|
293
591
|
position: relative;
|
294
592
|
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
593
|
+
&::before {
|
594
|
+
content: '';
|
595
|
+
position: absolute;
|
596
|
+
left: -4.8rem;
|
597
|
+
top: 0;
|
598
|
+
width: 6rem;
|
599
|
+
height: 2.5px;
|
600
|
+
background: #f0f0f0;
|
601
|
+
}
|
602
|
+
}
|
603
|
+
|
604
|
+
&.right-line {
|
605
|
+
margin-left: 0;
|
606
|
+
position: relative;
|
607
|
+
|
608
|
+
&::before {
|
609
|
+
content: '';
|
610
|
+
position: absolute;
|
611
|
+
right: -4.5rem;
|
612
|
+
top: 0;
|
613
|
+
width: 6rem;
|
614
|
+
height: 2.5px;
|
615
|
+
background: #f0f0f0;
|
616
|
+
}
|
617
|
+
}
|
618
|
+
}
|
619
|
+
|
620
|
+
.parallel-branches-container {
|
621
|
+
display: flex;
|
622
|
+
flex-direction: column;
|
623
|
+
gap: 16px;
|
624
|
+
padding: 16px 20px;
|
625
|
+
background: #fafafa;
|
626
|
+
border: 1px solid #e0e0e0;
|
627
|
+
border-radius: 8px;
|
628
|
+
min-width: 400px;
|
629
|
+
width: fit-content;
|
630
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
631
|
+
|
632
|
+
.branch-row {
|
633
|
+
.branch-timeline {
|
634
|
+
padding: 12px 16px;
|
635
|
+
background: #fff;
|
636
|
+
border-radius: 6px;
|
637
|
+
border-left: 4px solid #d9d9d9;
|
638
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.05);
|
639
|
+
|
640
|
+
.branch-steps {
|
641
|
+
/deep/ .ant-steps-dot {
|
642
|
+
margin-bottom: 6px;
|
643
|
+
|
644
|
+
.ant-steps-item-tail {
|
645
|
+
top: 7px;
|
646
|
+
margin-left: 70px;
|
647
|
+
width: calc(100% - 16px);
|
648
|
+
}
|
649
|
+
|
650
|
+
.ant-steps-item-icon {
|
651
|
+
margin-left: 60px;
|
652
|
+
width: 8px;
|
653
|
+
height: 8px;
|
654
|
+
line-height: 8px;
|
655
|
+
}
|
656
|
+
|
657
|
+
.ant-steps-item-content {
|
658
|
+
min-width: 160px;
|
659
|
+
margin-top: 24px;
|
660
|
+
|
661
|
+
.ant-steps-item-description {
|
662
|
+
text-align: left;
|
663
|
+
background: #fff;
|
664
|
+
border-radius: 4px;
|
665
|
+
padding: 10px 12px;
|
666
|
+
position: relative;
|
667
|
+
border: 1px solid #f0f0f0;
|
668
|
+
|
669
|
+
p {
|
670
|
+
position: relative;
|
671
|
+
padding: 4px 0;
|
672
|
+
margin: 0;
|
673
|
+
font-size: 12px;
|
674
|
+
color: #666;
|
675
|
+
line-height: 1.4;
|
676
|
+
white-space: nowrap;
|
677
|
+
overflow: visible;
|
678
|
+
|
679
|
+
&:first-child {
|
680
|
+
border-top: 1px dotted #e8e8e8;
|
681
|
+
}
|
682
|
+
|
683
|
+
&:not(:last-child) {
|
684
|
+
border-bottom: 1px dashed #f0f0f0;
|
685
|
+
}
|
686
|
+
|
687
|
+
&:last-child {
|
688
|
+
padding-bottom: 0;
|
689
|
+
}
|
690
|
+
}
|
691
|
+
}
|
692
|
+
}
|
693
|
+
}
|
694
|
+
|
695
|
+
/deep/ .ant-steps-item-title {
|
696
|
+
font-size: 14px;
|
697
|
+
line-height: 22px;
|
698
|
+
margin-bottom: 6px;
|
699
|
+
font-weight: 500;
|
700
|
+
}
|
701
|
+
}
|
702
|
+
|
703
|
+
.branch-step-title {
|
704
|
+
font-size: 14px;
|
705
|
+
font-weight: 500;
|
706
|
+
color: #262626;
|
707
|
+
cursor: pointer;
|
708
|
+
|
709
|
+
&:hover {
|
710
|
+
color: #1890ff;
|
711
|
+
}
|
712
|
+
}
|
713
|
+
|
714
|
+
.branch-step-desc {
|
715
|
+
p {
|
716
|
+
margin: 0;
|
717
|
+
padding: 4px 0;
|
718
|
+
font-size: 12px;
|
719
|
+
color: #666;
|
720
|
+
border: none !important;
|
721
|
+
}
|
307
722
|
}
|
308
723
|
|
309
|
-
|
310
|
-
|
724
|
+
// 移除固定的分支颜色,改为动态状态颜色
|
725
|
+
// &:nth-child(1) {
|
726
|
+
// border-left-color: #52c41a;
|
727
|
+
// }
|
728
|
+
|
729
|
+
// &:nth-child(2) {
|
730
|
+
// border-left-color: #1890ff;
|
731
|
+
// }
|
732
|
+
|
733
|
+
// &:nth-child(3) {
|
734
|
+
// border-left-color: #722ed1;
|
735
|
+
// }
|
736
|
+
|
737
|
+
&:hover {
|
738
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);
|
739
|
+
transform: translateY(-2px);
|
740
|
+
transition: all 0.3s ease;
|
311
741
|
}
|
312
742
|
|
313
|
-
|
314
|
-
|
743
|
+
/deep/ .ant-steps-icon {
|
744
|
+
color: #f0f0f0;
|
745
|
+
}
|
746
|
+
|
747
|
+
// 分支步骤状态颜色
|
748
|
+
/deep/ .branch-step-gray .ant-steps-item-icon {
|
749
|
+
background-color: #d9d9d9 !important;
|
750
|
+
border-color: #d9d9d9 !important;
|
751
|
+
}
|
752
|
+
|
753
|
+
/deep/ .branch-step-blue .ant-steps-item-icon {
|
754
|
+
background-color: #1890ff !important;
|
755
|
+
border-color: #1890ff !important;
|
756
|
+
}
|
757
|
+
|
758
|
+
/deep/ .branch-step-green .ant-steps-item-icon {
|
759
|
+
background-color: #52c41a !important;
|
760
|
+
border-color: #52c41a !important;
|
761
|
+
}
|
762
|
+
|
763
|
+
/deep/ .branch-step-red .ant-steps-item-icon {
|
764
|
+
background-color: #ff4d4f !important;
|
765
|
+
border-color: #ff4d4f !important;
|
766
|
+
}
|
767
|
+
|
768
|
+
/deep/ .branch-step-yellow .ant-steps-item-icon {
|
769
|
+
background-color: #faad14 !important;
|
770
|
+
border-color: #faad14 !important;
|
771
|
+
}
|
772
|
+
|
773
|
+
// 分支时间轴左侧边框颜色
|
774
|
+
&.branch-timeline-gray {
|
775
|
+
border-left-color: #d9d9d9;
|
776
|
+
}
|
777
|
+
|
778
|
+
&.branch-timeline-green {
|
779
|
+
border-left-color: #52c41a;
|
780
|
+
}
|
781
|
+
|
782
|
+
&.branch-timeline-blue {
|
783
|
+
border-left-color: #1890ff;
|
315
784
|
}
|
316
785
|
}
|
317
786
|
}
|
318
787
|
}
|
319
|
-
&.ant-steps {
|
320
|
-
padding-top: 8px;
|
321
|
-
}
|
322
|
-
}
|
323
|
-
|
324
|
-
/deep/ .ant-steps-item-title {
|
325
|
-
font-size: 14px;
|
326
|
-
h3 {
|
327
|
-
margin-bottom: 0;
|
328
|
-
}
|
329
788
|
}
|
330
789
|
|
331
790
|
@red: rgb(255, 77, 79);
|
@@ -394,20 +853,17 @@ export default {
|
|
394
853
|
|
395
854
|
// 新增样式:步骤标题容器
|
396
855
|
.step-title-container {
|
397
|
-
.condition-indicators
|
398
|
-
.parallel-indicators {
|
856
|
+
.condition-indicators {
|
399
857
|
margin-top: 8px;
|
400
858
|
display: flex;
|
401
859
|
align-items: center;
|
402
860
|
gap: 8px;
|
403
861
|
|
404
|
-
.condition-tag
|
405
|
-
.parallel-tag {
|
862
|
+
.condition-tag {
|
406
863
|
margin: 0;
|
407
864
|
}
|
408
865
|
|
409
|
-
.condition-help
|
410
|
-
.parallel-help {
|
866
|
+
.condition-help {
|
411
867
|
color: #999;
|
412
868
|
cursor: pointer;
|
413
869
|
&:hover {
|
@@ -447,47 +903,80 @@ export default {
|
|
447
903
|
}
|
448
904
|
|
449
905
|
// 省略步骤样式
|
450
|
-
|
451
|
-
|
906
|
+
.more-steps-section {
|
907
|
+
flex-shrink: 0;
|
908
|
+
// margin-top: 24px;
|
909
|
+
|
910
|
+
.more-steps-item {
|
911
|
+
opacity: 0.7;
|
912
|
+
|
913
|
+
.more-steps-container {
|
914
|
+
.pending-tag {
|
915
|
+
margin-top: 8px;
|
916
|
+
margin-left: 0;
|
917
|
+
}
|
918
|
+
}
|
919
|
+
|
920
|
+
.more-steps-desc {
|
921
|
+
p {
|
922
|
+
// font-style: italic;
|
923
|
+
color: #999 !important;
|
452
924
|
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
925
|
+
&.steps-count {
|
926
|
+
font-weight: bold;
|
927
|
+
color: #666 !important;
|
928
|
+
}
|
929
|
+
}
|
930
|
+
}
|
457
931
|
}
|
458
932
|
}
|
933
|
+
}
|
459
934
|
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
935
|
+
// 分支步骤 Popover 样式
|
936
|
+
/deep/ .ant-popover {
|
937
|
+
.popover-title {
|
938
|
+
display: flex;
|
939
|
+
align-items: center;
|
940
|
+
gap: 6px;
|
941
|
+
font-weight: 600;
|
942
|
+
color: #1890ff;
|
943
|
+
|
944
|
+
.anticon {
|
945
|
+
font-size: 14px;
|
946
|
+
}
|
947
|
+
}
|
464
948
|
|
465
|
-
|
466
|
-
|
467
|
-
color: #666 !important;
|
468
|
-
}
|
469
|
-
}
|
949
|
+
.branch-step-popover {
|
950
|
+
min-width: 200px;
|
470
951
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
color: #1890ff;
|
952
|
+
.popover-item {
|
953
|
+
display: flex;
|
954
|
+
align-items: flex-start;
|
955
|
+
margin-bottom: 8px;
|
476
956
|
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
}
|
481
|
-
}
|
957
|
+
&:last-child {
|
958
|
+
margin-bottom: 0;
|
959
|
+
}
|
482
960
|
|
483
|
-
|
484
|
-
|
961
|
+
&.no-data {
|
962
|
+
justify-content: center;
|
963
|
+
font-style: italic;
|
964
|
+
color: #999;
|
965
|
+
}
|
485
966
|
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
967
|
+
.popover-label {
|
968
|
+
font-weight: 600;
|
969
|
+
color: #262626;
|
970
|
+
min-width: 70px;
|
971
|
+
flex-shrink: 0;
|
972
|
+
}
|
973
|
+
|
974
|
+
.popover-value {
|
975
|
+
color: #595959;
|
976
|
+
word-break: break-all;
|
977
|
+
flex: 1;
|
978
|
+
}
|
979
|
+
}
|
980
|
+
}
|
981
|
+
}
|
982
|
+
</style>
|