@lambo-design/workflow-approve 1.0.0-beta.140 → 1.0.0-beta.142

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.
@@ -0,0 +1,837 @@
1
+ <template>
2
+ <div class="reject-node-prototype">
3
+ <Table
4
+ border
5
+ size="small"
6
+ :data="tableRows"
7
+ :columns="tableColumns"
8
+ :span-method="spanMethod"
9
+ :row-class-name="rowClassName"
10
+ @on-row-click="handleRowClick"
11
+ />
12
+
13
+ <Form :label-width="90" class="reject-node-prototype__takeover-form">
14
+ <FormItem label="驳回给:">
15
+ <RadioGroup v-model="rejectToTakeOver" @on-change="handleRejectToTakeOverChange">
16
+ <Radio label="original">原办理人</Radio>
17
+ <Radio label="actual">实际办理人</Radio>
18
+ </RadioGroup>
19
+ </FormItem>
20
+ </Form>
21
+
22
+ <div class="reject-node-prototype__summary">
23
+ 当前选择:<strong>{{ selectedSummary || '未选择' }}</strong>
24
+ </div>
25
+ </div>
26
+ </template>
27
+
28
+ <script>
29
+ export default {
30
+ name: 'RejectNodeTable',
31
+ props: {
32
+ nodes: {
33
+ type: Array,
34
+ default: () => []
35
+ },
36
+ currentTaskNode: {
37
+ type: [String, Number],
38
+ default: ''
39
+ },
40
+ defaultRejectToTakeOver: {
41
+ type: Boolean,
42
+ default: false
43
+ },
44
+ visible: {
45
+ type: Boolean,
46
+ default: false
47
+ }
48
+ },
49
+ data() {
50
+ return {
51
+ rejectNodeCollapsedGroupKeys: [],
52
+ selectedRejectNodeTaskNodes: [],
53
+ selectedRejectNodePathKeys: [],
54
+ selectedRejectNodePathEntries: [],
55
+ selectedRejectNodeNames: [],
56
+ rejectToTakeOver: this.defaultRejectToTakeOver ? 'actual' : 'original'
57
+ }
58
+ },
59
+ computed: {
60
+ tableRows() {
61
+ if (!Array.isArray(this.nodes) || this.nodes.length === 0) {
62
+ return []
63
+ }
64
+ return this.buildRejectNodeTableRows()
65
+ },
66
+ tableColumns() {
67
+ const self = this
68
+ return [
69
+ {
70
+ title: '',
71
+ key: 'selected',
72
+ width: 56,
73
+ align: 'center',
74
+ renderHeader: h => h('span'),
75
+ render: (h, params) => {
76
+ if (params.row.type === 'group') {
77
+ return h('div', {
78
+ class: 'reject-node-prototype__group-cell'
79
+ }, [
80
+ h('Button', {
81
+ class: 'reject-node-prototype__group-toggle',
82
+ props: { type: 'text' },
83
+ style: {
84
+ paddingLeft: `${Math.max((params.row.groupLevel || 1) - 1, 0) * 16}px`
85
+ },
86
+ on: {
87
+ click: event => {
88
+ event.stopPropagation()
89
+ self.toggleRejectNodeGroup(params.row)
90
+ }
91
+ }
92
+ }, [
93
+ h('span', {
94
+ class: 'reject-node-prototype__group-arrow'
95
+ }, self.isRejectNodeGroupCollapsed(params.row.groupId) ? '▸' : '▾'),
96
+ h('span', {
97
+ class: 'reject-node-prototype__group-label'
98
+ }, params.row.groupName || params.row.gatewayLabel || '无网关')
99
+ ])
100
+ ].filter(Boolean))
101
+ }
102
+ const checked = self.isRejectNodeSelected(params.row)
103
+ const disabled = self.isRejectNodeDisabled(params.row) && !checked
104
+ return h('Checkbox', {
105
+ props: {
106
+ value: checked,
107
+ disabled
108
+ },
109
+ nativeOn: {
110
+ click: event => event.stopPropagation()
111
+ },
112
+ on: {
113
+ 'on-change': value => {
114
+ self.toggleRejectNodeSelection(params.row, value)
115
+ }
116
+ }
117
+ })
118
+ }
119
+ },
120
+ {
121
+ title: '节点名称',
122
+ key: 'taskName',
123
+ minWidth: 180,
124
+ render: (h, params) => {
125
+ if (params.row.type === 'group') {
126
+ return h('div')
127
+ }
128
+ return h('div', {
129
+ class: 'reject-node-prototype__name-cell',
130
+ style: {
131
+ paddingLeft: `${Math.min(params.row.depth || 0, 4) * 16}px`
132
+ }
133
+ }, [
134
+ h('span', {
135
+ class: {
136
+ 'reject-node-prototype__node-name': true,
137
+ 'is-current': String(params.row.taskNode) === String(this.currentTaskNode)
138
+ }
139
+ }, params.row.taskName || params.row.name || params.row.title || '')
140
+ ])
141
+ }
142
+ },
143
+ {
144
+ title: '节点状态',
145
+ key: 'auditResult',
146
+ width: 160,
147
+ align: 'center',
148
+ render: (h, params) => {
149
+ if (params.row.type === 'group') {
150
+ return h('div')
151
+ }
152
+ const status = self.getRejectNodeStatus(params.row)
153
+ return h('Tag', { props: { color: status.color } }, status.label)
154
+ }
155
+ }
156
+ ]
157
+ },
158
+ selectedSummary() {
159
+ return this.selectedRejectNodeNames.join('、')
160
+ }
161
+ },
162
+ watch: {
163
+ visible: {
164
+ immediate: true,
165
+ handler(value) {
166
+ if (value) {
167
+ this.resetSelection()
168
+ return
169
+ }
170
+ this.resetSelection(false)
171
+ }
172
+ },
173
+ nodes: {
174
+ deep: true,
175
+ handler() {
176
+ if (this.visible) {
177
+ this.resetSelection()
178
+ }
179
+ }
180
+ }
181
+ },
182
+ methods: {
183
+ resetSelection(emitChange = true) {
184
+ this.rejectNodeCollapsedGroupKeys = []
185
+ this.selectedRejectNodeTaskNodes = []
186
+ this.selectedRejectNodePathKeys = []
187
+ this.selectedRejectNodePathEntries = []
188
+ this.selectedRejectNodeNames = []
189
+ this.rejectToTakeOver = this.defaultRejectToTakeOver ? 'actual' : 'original'
190
+ if (emitChange) {
191
+ this.emitSelectionChange()
192
+ }
193
+ },
194
+ emitSelectionChange() {
195
+ this.$emit('selection-change', {
196
+ taskNodes: this.selectedRejectNodeTaskNodes.slice(),
197
+ taskNames: this.selectedRejectNodeNames.slice(),
198
+ pathKeys: this.selectedRejectNodePathKeys.slice(),
199
+ pathEntries: this.selectedRejectNodePathEntries.map(item => ({
200
+ pathKey: item.pathKey,
201
+ pathIds: Array.isArray(item.pathIds) ? item.pathIds.slice() : []
202
+ })),
203
+ rejectToTakeOver: this.rejectToTakeOver
204
+ })
205
+ },
206
+ handleRejectToTakeOverChange() {
207
+ this.emitSelectionChange()
208
+ },
209
+ handleRowClick(row) {
210
+ if (!row) {
211
+ return
212
+ }
213
+ if (row.type === 'group') {
214
+ this.toggleRejectNodeGroup(row)
215
+ return
216
+ }
217
+ this.toggleRejectNodeSelection(row)
218
+ },
219
+ normalizeRejectNode(node, nodeIndex, nodeNameMap) {
220
+ const rejectPaths = Array.isArray(node?.rejectPaths) ? node.rejectPaths : []
221
+ const startGatewayPaths = Array.isArray(node?.startGatewayPaths) ? node.startGatewayPaths : []
222
+ const pathEntries = rejectPaths
223
+ .map((path, index) => {
224
+ const pathIds = Array.isArray(path) ? path.filter(Boolean).map(item => String(item)) : []
225
+ const pathKey = pathIds.join('>')
226
+ const gatewayPath = Array.isArray(startGatewayPaths[index]) ? startGatewayPaths[index] : []
227
+ const gatewayLabel = this.formatGatewayPathLabel(gatewayPath)
228
+ const pathLabel = this.formatRejectPathLabel(pathIds, nodeNameMap)
229
+ const pathOrder = pathIds.indexOf(String(node?.taskNode))
230
+ return {
231
+ pathKey,
232
+ pathLabel,
233
+ gatewayLabel,
234
+ gatewayPath,
235
+ pathOrder: pathOrder === -1 ? pathIds.length : pathOrder,
236
+ pathIds
237
+ }
238
+ })
239
+ .filter(item => item.pathKey)
240
+ .sort((left, right) => this.compareRejectNodePathEntries(left, right))
241
+
242
+ return {
243
+ ...node,
244
+ _nodeIndex: nodeIndex,
245
+ pathEntries,
246
+ pathKeys: pathEntries.map(item => item.pathKey)
247
+ }
248
+ },
249
+ formatRejectPathLabel(pathIds, nodeNameMap) {
250
+ return pathIds.map(id => nodeNameMap.get(id) || id).join(' > ')
251
+ },
252
+ formatGatewayPathLabel(gatewayPath) {
253
+ if (!Array.isArray(gatewayPath) || gatewayPath.length === 0) {
254
+ return ''
255
+ }
256
+ return gatewayPath
257
+ .map(item => item.groupName || item.groupId)
258
+ .filter(Boolean)
259
+ .join(' > ')
260
+ },
261
+ getRejectNodePrimaryGatewayPath(node) {
262
+ const pathEntries = Array.isArray(node?.pathEntries) && node.pathEntries.length > 0
263
+ ? node.pathEntries
264
+ : this.normalizeRejectNode(node, 0, new Map()).pathEntries
265
+ const primaryEntry = pathEntries.find(item => Array.isArray(item?.gatewayPath) && item.gatewayPath.length > 0)
266
+ return Array.isArray(primaryEntry?.gatewayPath) ? primaryEntry.gatewayPath : []
267
+ },
268
+ getRejectNodeGatewaySortKey(gatewayPath) {
269
+ if (!Array.isArray(gatewayPath) || gatewayPath.length === 0) {
270
+ return ''
271
+ }
272
+ return gatewayPath
273
+ .map(item => String(item?.groupId || item?.groupName || ''))
274
+ .filter(Boolean)
275
+ .join('>')
276
+ },
277
+ compareRejectNodePathEntries(left, right) {
278
+ const leftDepth = Array.isArray(left?.gatewayPath) ? left.gatewayPath.length : 0
279
+ const rightDepth = Array.isArray(right?.gatewayPath) ? right.gatewayPath.length : 0
280
+ if (leftDepth !== rightDepth) {
281
+ return leftDepth - rightDepth
282
+ }
283
+ const leftGatewayKey = this.getRejectNodeGatewaySortKey(left?.gatewayPath)
284
+ const rightGatewayKey = this.getRejectNodeGatewaySortKey(right?.gatewayPath)
285
+ if (leftGatewayKey !== rightGatewayKey) {
286
+ return leftGatewayKey.localeCompare(rightGatewayKey)
287
+ }
288
+ const leftPathOrder = typeof left?.pathOrder === 'number' ? left.pathOrder : Number.MAX_SAFE_INTEGER
289
+ const rightPathOrder = typeof right?.pathOrder === 'number' ? right.pathOrder : Number.MAX_SAFE_INTEGER
290
+ if (leftPathOrder !== rightPathOrder) {
291
+ return leftPathOrder - rightPathOrder
292
+ }
293
+ return String(left?.pathKey || '').localeCompare(String(right?.pathKey || ''))
294
+ },
295
+ getRejectNodePathKeys(node) {
296
+ if (Array.isArray(node?.pathKeys) && node.pathKeys.length > 0) {
297
+ return node.pathKeys
298
+ }
299
+ if (node?.pathKey) {
300
+ return [node.pathKey]
301
+ }
302
+ return this.normalizeRejectNode(node, 0, new Map()).pathKeys
303
+ },
304
+ isRejectNodeSelected(row) {
305
+ if (!row || row.type !== 'node') {
306
+ return false
307
+ }
308
+ return this.selectedRejectNodeTaskNodes.includes(String(row.taskNode))
309
+ },
310
+ getRejectNodePathKeysByTaskNode(taskNode) {
311
+ if (!taskNode) {
312
+ return []
313
+ }
314
+ const nodes = Array.isArray(this.nodes)
315
+ ? this.nodes.filter(item => item && String(item.taskNode) === String(taskNode))
316
+ : []
317
+ if (!nodes.length) {
318
+ return []
319
+ }
320
+ const pathKeys = []
321
+ nodes.forEach(node => {
322
+ this.getRejectNodePathKeys(node).forEach(pathKey => {
323
+ if (pathKey && !pathKeys.includes(pathKey)) {
324
+ pathKeys.push(pathKey)
325
+ }
326
+ })
327
+ })
328
+ return pathKeys
329
+ },
330
+ getRejectNodePathEntriesByTaskNode(taskNode) {
331
+ if (!taskNode) {
332
+ return []
333
+ }
334
+ const nodes = Array.isArray(this.nodes)
335
+ ? this.nodes.filter(item => item && String(item.taskNode) === String(taskNode))
336
+ : []
337
+ if (!nodes.length) {
338
+ return []
339
+ }
340
+ const pathEntries = []
341
+ nodes.forEach(node => {
342
+ this.normalizeRejectNode(node, 0, new Map()).pathEntries.forEach(pathEntry => {
343
+ if (!pathEntry || !pathEntry.pathKey) {
344
+ return
345
+ }
346
+ if (!pathEntries.some(item => item.pathKey === pathEntry.pathKey)) {
347
+ pathEntries.push({
348
+ pathKey: pathEntry.pathKey,
349
+ pathIds: Array.isArray(pathEntry.pathIds) ? pathEntry.pathIds.slice() : []
350
+ })
351
+ }
352
+ })
353
+ })
354
+ return pathEntries
355
+ },
356
+ isRejectPathRelated(pathIdsA, pathIdsB) {
357
+ if (!Array.isArray(pathIdsA) || !Array.isArray(pathIdsB) || pathIdsA.length === 0 || pathIdsB.length === 0) {
358
+ return false
359
+ }
360
+ const minLength = Math.min(pathIdsA.length, pathIdsB.length)
361
+ for (let i = 0; i < minLength; i += 1) {
362
+ if (String(pathIdsA[i]) !== String(pathIdsB[i])) {
363
+ return false
364
+ }
365
+ }
366
+ return true
367
+ },
368
+ syncSelection(taskNodeList) {
369
+ const uniqueTaskNodes = Array.from(new Set((taskNodeList || []).map(item => String(item)).filter(Boolean)))
370
+ this.selectedRejectNodeTaskNodes = uniqueTaskNodes
371
+
372
+ const selectedNames = []
373
+ const selectedPathKeys = []
374
+ const selectedPathEntries = []
375
+ uniqueTaskNodes.forEach(taskNode => {
376
+ const node = Array.isArray(this.nodes) ? this.nodes.find(item => item && String(item.taskNode) === taskNode) : null
377
+ const nodeName = node ? (node.taskName || node.name || node.title || '') : ''
378
+ if (nodeName) {
379
+ selectedNames.push(nodeName)
380
+ }
381
+ this.getRejectNodePathEntriesByTaskNode(taskNode).forEach(pathEntry => {
382
+ if (!pathEntry || !pathEntry.pathKey) {
383
+ return
384
+ }
385
+ if (!selectedPathKeys.includes(pathEntry.pathKey)) {
386
+ selectedPathKeys.push(pathEntry.pathKey)
387
+ }
388
+ const exists = selectedPathEntries.some(item => item.pathKey === pathEntry.pathKey)
389
+ if (!exists) {
390
+ selectedPathEntries.push({
391
+ pathKey: pathEntry.pathKey,
392
+ pathIds: Array.isArray(pathEntry.pathIds) ? pathEntry.pathIds.slice() : []
393
+ })
394
+ }
395
+ })
396
+ })
397
+ this.selectedRejectNodeNames = selectedNames
398
+ this.selectedRejectNodePathKeys = selectedPathKeys
399
+ this.selectedRejectNodePathEntries = selectedPathEntries
400
+ this.emitSelectionChange()
401
+ },
402
+ toggleRejectNodeSelection(row, checked) {
403
+ if (!row || row.type !== 'node') {
404
+ return
405
+ }
406
+ const taskNode = String(row.taskNode)
407
+ const selectedTaskNodes = this.selectedRejectNodeTaskNodes.slice()
408
+ const existsIndex = selectedTaskNodes.indexOf(taskNode)
409
+ const shouldSelect = typeof checked === 'boolean' ? checked : existsIndex === -1
410
+ if (shouldSelect) {
411
+ if (existsIndex === -1) {
412
+ if (this.isRejectNodeDisabled(row)) {
413
+ return
414
+ }
415
+ selectedTaskNodes.push(taskNode)
416
+ }
417
+ } else if (existsIndex > -1) {
418
+ selectedTaskNodes.splice(existsIndex, 1)
419
+ }
420
+ this.syncSelection(selectedTaskNodes)
421
+ },
422
+ isRejectNodeGroupCollapsed(groupId) {
423
+ return this.rejectNodeCollapsedGroupKeys.includes(groupId)
424
+ },
425
+ toggleRejectNodeGroup(row) {
426
+ if (!row || !row.groupId) {
427
+ return
428
+ }
429
+ const nextKeys = this.rejectNodeCollapsedGroupKeys.slice()
430
+ const collapsedIndex = nextKeys.indexOf(row.groupId)
431
+ if (collapsedIndex === -1) {
432
+ nextKeys.push(row.groupId)
433
+ } else {
434
+ nextKeys.splice(collapsedIndex, 1)
435
+ }
436
+ this.rejectNodeCollapsedGroupKeys = nextKeys
437
+ },
438
+ buildRejectNodeTableRows() {
439
+ const nodeNameMap = new Map()
440
+ const groupedNodes = this.sortRejectNodesForTable(this.mergeRejectNodesByTaskNode(this.nodes))
441
+ groupedNodes.forEach(node => {
442
+ if (node && node.taskNode) {
443
+ nodeNameMap.set(String(node.taskNode), node.taskName || node.name || node.taskNode)
444
+ }
445
+ })
446
+
447
+ const rows = []
448
+ const groupSet = new Set()
449
+ const nodeRowMap = new Map()
450
+ groupedNodes.forEach((node, nodeIndex) => {
451
+ const normalizedNode = this.normalizeRejectNode(node, nodeIndex, nodeNameMap)
452
+ const nodeKey = String(normalizedNode.taskNode || `node-${nodeIndex}`)
453
+ let nodeRow = nodeRowMap.get(nodeKey) || null
454
+ normalizedNode.pathEntries.forEach(pathEntry => {
455
+ const gatewayPath = Array.isArray(pathEntry.gatewayPath) ? pathEntry.gatewayPath : []
456
+ const ancestorGroupIds = []
457
+ let parentGroupId = ''
458
+ gatewayPath.forEach((gateway, gatewayIndex) => {
459
+ const groupId = String(gateway.groupId || `${nodeIndex}-${pathEntry.pathKey}-${gatewayIndex}`)
460
+ if (!groupSet.has(groupId)) {
461
+ groupSet.add(groupId)
462
+ rows.push({
463
+ type: 'group',
464
+ rowKey: `group:${groupId}`,
465
+ groupId,
466
+ groupName: gateway.groupName || gateway.groupId || groupId,
467
+ groupLevel: gatewayIndex + 1,
468
+ gatewayLabel: this.formatGatewayPathLabel(gatewayPath),
469
+ pathLabel: pathEntry.pathLabel,
470
+ parentGroupId,
471
+ ancestorGroupIds: ancestorGroupIds.slice()
472
+ })
473
+ }
474
+ ancestorGroupIds.push(groupId)
475
+ parentGroupId = groupId
476
+ })
477
+
478
+ if (!nodeRow) {
479
+ nodeRow = {
480
+ ...normalizedNode,
481
+ type: 'node',
482
+ rowKey: nodeKey,
483
+ pathKey: pathEntry.pathKey,
484
+ pathLabel: pathEntry.pathLabel,
485
+ gatewayLabel: pathEntry.gatewayLabel,
486
+ ancestorGroupIds: ancestorGroupIds.slice(),
487
+ depth: gatewayPath.length,
488
+ displayIndex: 0,
489
+ pathOrder: pathEntry.pathOrder,
490
+ pathKeys: [pathEntry.pathKey],
491
+ pathLabels: pathEntry.pathLabel ? [pathEntry.pathLabel] : [],
492
+ gatewayLabels: pathEntry.gatewayLabel ? [pathEntry.gatewayLabel] : []
493
+ }
494
+ } else {
495
+ if (!Array.isArray(nodeRow.pathKeys)) {
496
+ nodeRow.pathKeys = []
497
+ }
498
+ if (pathEntry.pathKey && !nodeRow.pathKeys.includes(pathEntry.pathKey)) {
499
+ nodeRow.pathKeys.push(pathEntry.pathKey)
500
+ }
501
+ if (!Array.isArray(nodeRow.pathLabels)) {
502
+ nodeRow.pathLabels = []
503
+ }
504
+ if (pathEntry.pathLabel && !nodeRow.pathLabels.includes(pathEntry.pathLabel)) {
505
+ nodeRow.pathLabels.push(pathEntry.pathLabel)
506
+ }
507
+ if (!Array.isArray(nodeRow.gatewayLabels)) {
508
+ nodeRow.gatewayLabels = []
509
+ }
510
+ if (pathEntry.gatewayLabel && !nodeRow.gatewayLabels.includes(pathEntry.gatewayLabel)) {
511
+ nodeRow.gatewayLabels.push(pathEntry.gatewayLabel)
512
+ }
513
+ nodeRow.ancestorGroupIds = Array.from(new Set([...(nodeRow.ancestorGroupIds || []), ...ancestorGroupIds]))
514
+ nodeRow.depth = Math.max(nodeRow.depth || 0, gatewayPath.length)
515
+ nodeRow.pathOrder = Math.min(nodeRow.pathOrder ?? pathEntry.pathOrder, pathEntry.pathOrder)
516
+ }
517
+ })
518
+ if (nodeRow && !nodeRowMap.has(nodeKey)) {
519
+ nodeRowMap.set(nodeKey, nodeRow)
520
+ rows.push(nodeRow)
521
+ }
522
+ })
523
+
524
+ const visibleRows = []
525
+ rows.forEach(row => {
526
+ const hidden = Array.isArray(row.ancestorGroupIds) && row.ancestorGroupIds.some(groupId => this.isRejectNodeGroupCollapsed(groupId))
527
+ if (hidden) {
528
+ return
529
+ }
530
+ visibleRows.push(row)
531
+ })
532
+
533
+ return visibleRows
534
+ },
535
+ sortRejectNodesForTable(nodes) {
536
+ const list = Array.isArray(nodes) ? nodes.slice() : []
537
+ const bucketMap = new Map()
538
+ const bucketOrder = []
539
+
540
+ list.forEach((node, index) => {
541
+ const normalizedNode = this.normalizeRejectNode(node, index, new Map())
542
+ const primaryGatewayPath = this.getRejectNodePrimaryGatewayPath(normalizedNode)
543
+ const gatewayKey = primaryGatewayPath.length > 0
544
+ ? this.getRejectNodeGatewaySortKey(primaryGatewayPath)
545
+ : '__reject_node_no_gateway__'
546
+ let bucket = bucketMap.get(gatewayKey)
547
+ if (!bucket) {
548
+ bucket = {
549
+ gatewayKey,
550
+ hasGateway: primaryGatewayPath.length > 0,
551
+ firstIndex: index,
552
+ nodes: []
553
+ }
554
+ bucketMap.set(gatewayKey, bucket)
555
+ bucketOrder.push(bucket)
556
+ }
557
+ bucket.nodes.push(node)
558
+ })
559
+
560
+ bucketOrder.sort((left, right) => {
561
+ if (left.hasGateway !== right.hasGateway) {
562
+ return left.hasGateway ? 1 : -1
563
+ }
564
+ return left.firstIndex - right.firstIndex
565
+ })
566
+
567
+ const sortedNodes = []
568
+ bucketOrder.forEach(bucket => {
569
+ bucket.nodes.forEach(node => {
570
+ sortedNodes.push(node)
571
+ })
572
+ })
573
+ return sortedNodes
574
+ },
575
+ mergeRejectNodesByTaskNode(nodes) {
576
+ const groupedMap = new Map()
577
+ const sourceNodes = Array.isArray(nodes) ? nodes : []
578
+ sourceNodes.forEach((node, index) => {
579
+ if (!node) {
580
+ return
581
+ }
582
+ const taskNodeKey = node.taskNode ? String(node.taskNode) : `__index__${index}`
583
+ const existing = groupedMap.get(taskNodeKey)
584
+ if (!existing) {
585
+ groupedMap.set(taskNodeKey, {
586
+ ...node,
587
+ rejectPaths: Array.isArray(node.rejectPaths) ? node.rejectPaths.slice() : [],
588
+ startGatewayPaths: Array.isArray(node.startGatewayPaths) ? node.startGatewayPaths.slice() : []
589
+ })
590
+ return
591
+ }
592
+ if (!Array.isArray(existing.rejectPaths)) {
593
+ existing.rejectPaths = []
594
+ }
595
+ if (!Array.isArray(existing.startGatewayPaths)) {
596
+ existing.startGatewayPaths = []
597
+ }
598
+ ;(Array.isArray(node.rejectPaths) ? node.rejectPaths : []).forEach((path, pathIndex) => {
599
+ const pathKey = JSON.stringify(path || [])
600
+ const exists = existing.rejectPaths.some(item => JSON.stringify(item || []) === pathKey)
601
+ if (!exists) {
602
+ existing.rejectPaths.push(Array.isArray(path) ? path.slice() : path)
603
+ const gatewayPath = Array.isArray(node.startGatewayPaths) ? node.startGatewayPaths[pathIndex] : null
604
+ if (gatewayPath) {
605
+ const gatewayKey = JSON.stringify(gatewayPath || [])
606
+ const gatewayExists = existing.startGatewayPaths.some(item => JSON.stringify(item || []) === gatewayKey)
607
+ if (!gatewayExists) {
608
+ existing.startGatewayPaths.push(Array.isArray(gatewayPath) ? gatewayPath.slice() : gatewayPath)
609
+ }
610
+ }
611
+ }
612
+ })
613
+ Object.keys(node).forEach(key => {
614
+ if (key === 'rejectPaths' || key === 'startGatewayPaths') {
615
+ return
616
+ }
617
+ if (existing[key] === undefined || existing[key] === null || existing[key] === '') {
618
+ existing[key] = node[key]
619
+ }
620
+ })
621
+ })
622
+ return Array.from(groupedMap.values())
623
+ },
624
+ isRejectNodeDisabled(row) {
625
+ if (!row || row.type !== 'node') {
626
+ return false
627
+ }
628
+ if (this.isRejectNodeSelected(row)) {
629
+ return false
630
+ }
631
+ const rowPathEntries = Array.isArray(row.pathEntries) && row.pathEntries.length > 0
632
+ ? row.pathEntries
633
+ : this.normalizeRejectNode(row, 0, new Map()).pathEntries
634
+ if (rowPathEntries.length === 0 || this.selectedRejectNodePathEntries.length === 0) {
635
+ return false
636
+ }
637
+ return rowPathEntries.some(rowPathEntry => {
638
+ return this.selectedRejectNodePathEntries.some(selectedPathEntry => {
639
+ return this.isRejectPathRelated(rowPathEntry.pathIds, selectedPathEntry.pathIds)
640
+ })
641
+ })
642
+ },
643
+ spanMethod({ row, columnIndex }) {
644
+ if (row && row.type === 'group') {
645
+ return columnIndex === 0 ? [1, this.tableColumns.length] : [0, 0]
646
+ }
647
+ return [1, 1]
648
+ },
649
+ rowClassName(row) {
650
+ if (!row) {
651
+ return ''
652
+ }
653
+ if (row.type === 'group') {
654
+ return 'reject-node-prototype__group-row'
655
+ }
656
+ const selected = this.isRejectNodeSelected(row)
657
+ const disabled = !selected && this.isRejectNodeDisabled(row)
658
+ return [
659
+ 'reject-node-prototype__node-row',
660
+ selected && 'is-selected',
661
+ disabled && 'is-disabled'
662
+ ].filter(Boolean).join(' ')
663
+ },
664
+ getRejectNodeStatus(row) {
665
+ if (String(row.taskNode) === String(this.currentTaskNode)) {
666
+ return { label: '当前节点', color: 'orange' }
667
+ }
668
+ if (!row.auditResult) {
669
+ return { label: `未${row.handleName ? row.handleName : '审批'}`, color: 'orange' }
670
+ }
671
+ const statusMap = {
672
+ '30': { label: `${row.handleName ? row.handleName : '审批'}通过`, color: 'green' },
673
+ '10': { label: '首节点自动跳过', color: 'green' },
674
+ '11': { label: '与上一环节办理人相同自动跳过', color: 'green' },
675
+ '12': { label: '与发起人相同自动跳过', color: 'green' },
676
+ '13': { label: '办理人为空自动跳过', color: 'green' },
677
+ '14': { label: '符合流程变量条件自动跳过', color: 'green' },
678
+ '40': { label: `${row.rejectName ? row.rejectName : '驳回'}到上一节点`, color: 'volcano' },
679
+ '50': { label: `${row.rejectName ? row.rejectName : '驳回'}到原点`, color: 'red' },
680
+ '51': { label: '流程终止', color: 'purple' },
681
+ '60': { label: '撤回', color: 'blue' },
682
+ '61': { label: '交回委派任务', color: 'green' },
683
+ '62': { label: '委派任务已撤回', color: 'blue' },
684
+ '63': { label: '委派任务', color: 'orange' },
685
+ '80': { label: '跳转到指定节点', color: 'cyan' },
686
+ '82': { label: '指定他人处理', color: 'cyan' },
687
+ '83': { label: '会签减签', color: 'blue' },
688
+ '90': { label: `${row.rejectName ? row.rejectName : '驳回'}到指定节点`, color: 'magenta' },
689
+ '92': { label: `${row.rejectName ? row.rejectName : '驳回'}到指定节点`, color: 'magenta' },
690
+ '31': { label: '会签表决通过', color: 'green' }
691
+ }
692
+ return statusMap[row.auditResult] || { label: row.auditResult, color: 'default' }
693
+ }
694
+ }
695
+ }
696
+ </script>
697
+
698
+ <style lang="less" scoped>
699
+ .reject-node-prototype {
700
+ display: flex;
701
+ flex-direction: column;
702
+ gap: 12px;
703
+ }
704
+
705
+ .reject-node-prototype /deep/ .ivu-table {
706
+ font-size: 14px;
707
+ color: #333333;
708
+ }
709
+
710
+ .reject-node-prototype /deep/ .ivu-table th,
711
+ .reject-node-prototype /deep/ .ivu-table td {
712
+ box-sizing: border-box;
713
+ text-align: center;
714
+ vertical-align: middle;
715
+ }
716
+
717
+ .reject-node-prototype /deep/ .ivu-table th {
718
+ height: 40px;
719
+ background: #f5f7fa;
720
+ font-weight: 700;
721
+ color: #666666;
722
+ }
723
+
724
+ .reject-node-prototype /deep/ .ivu-table td {
725
+ height: 40px;
726
+ padding: 6px 10px;
727
+ background: #ffffff;
728
+ }
729
+
730
+ .reject-node-prototype /deep/ .ivu-table-cell {
731
+ width: 100%;
732
+ }
733
+
734
+ .reject-node-prototype /deep/ .reject-node-prototype__group-row td {
735
+ height: 32px;
736
+ padding: 0 12px;
737
+ text-align: left;
738
+ }
739
+
740
+ .reject-node-prototype /deep/ .ivu-table-cell .reject-node-prototype__group-toggle {
741
+ display: inline-flex;
742
+ align-items: center;
743
+ gap: 6px;
744
+ padding: 0;
745
+ border: 0;
746
+ background: transparent;
747
+ color: #333333;
748
+ font-size: 14px;
749
+ line-height: 1;
750
+ height: auto;
751
+ cursor: pointer;
752
+ }
753
+
754
+ .reject-node-prototype /deep/ .ivu-table-cell .reject-node-prototype__group-arrow {
755
+ width: 12px;
756
+ color: #808695;
757
+ text-align: center;
758
+ }
759
+
760
+ .reject-node-prototype /deep/ .ivu-table-cell .reject-node-prototype__group-label {
761
+ font-weight: 600;
762
+ }
763
+
764
+ .reject-node-prototype /deep/ .ivu-table-cell .reject-node-prototype__group-desc {
765
+ margin-left: 16px;
766
+ color: #808695;
767
+ font-size: 12px;
768
+ white-space: normal;
769
+ }
770
+
771
+ .reject-node-prototype /deep/ .ivu-table-cell .reject-node-prototype__node-name {
772
+ display: inline-block;
773
+ max-width: 100%;
774
+ overflow: hidden;
775
+ text-overflow: ellipsis;
776
+ white-space: nowrap;
777
+ }
778
+
779
+ .reject-node-prototype /deep/ .ivu-table-cell .reject-node-prototype__name-cell {
780
+ display: flex;
781
+ align-items: center;
782
+ width: 100%;
783
+ text-align: left;
784
+ }
785
+
786
+ .reject-node-prototype /deep/ .ivu-table-cell .reject-node-prototype__node-name.is-current {
787
+ color: #2d8cf0;
788
+ font-weight: 600;
789
+ }
790
+
791
+ .reject-node-prototype /deep/ .ivu-table-cell .reject-node-prototype__group-cell {
792
+ display: flex;
793
+ align-items: center;
794
+ flex-wrap: wrap;
795
+ gap: 6px;
796
+ min-height: 28px;
797
+ text-align: left;
798
+ }
799
+
800
+ .reject-node-prototype /deep/ .reject-node-prototype__node-row {
801
+ cursor: pointer;
802
+ }
803
+
804
+ .reject-node-prototype /deep/ .reject-node-prototype__node-row.is-disabled {
805
+ cursor: not-allowed;
806
+ }
807
+
808
+ .reject-node-prototype /deep/ .reject-node-prototype__group-row {
809
+ cursor: default;
810
+ }
811
+
812
+ .reject-node-prototype__takeover-form {
813
+ margin-top: 4px;
814
+ }
815
+
816
+ .reject-node-prototype__summary {
817
+ min-height: 20px;
818
+ color: #515a6e;
819
+ font-size: 12px;
820
+ }
821
+
822
+ .reject-node-prototype /deep/ .reject-node-prototype__node-row.is-selected td {
823
+ background: #ecf5ff;
824
+ }
825
+
826
+ .reject-node-prototype /deep/ .reject-node-prototype__node-row.is-disabled td {
827
+ color: #c5c8ce;
828
+ }
829
+
830
+ .reject-node-prototype /deep/ .reject-node-prototype__node-row.is-disabled:hover td {
831
+ background: transparent;
832
+ }
833
+
834
+ .reject-node-prototype /deep/ .reject-node-prototype__node-row.is-disabled .reject-node-prototype__node-name {
835
+ color: #c5c8ce;
836
+ }
837
+ </style>