257 lines
8.9 KiB
JavaScript
257 lines
8.9 KiB
JavaScript
import { describe, expect, it } from 'vitest'
|
||
import { spreadBranchNodes } from '@/views/system/workflow/designer/utils'
|
||
|
||
/** 构造一个画布节点 */
|
||
function node(id, type, x, y, width, height, text) {
|
||
return { id, type, x, y, width, height, text: text ?? { value: id, x, y } }
|
||
}
|
||
|
||
function edge(id, sourceNodeId, targetNodeId) {
|
||
return { id, sourceNodeId, targetNodeId, offset: 15 }
|
||
}
|
||
|
||
/** 默认出口表:source → 出线目标 */
|
||
function defaultExits(entries) {
|
||
return new Map(Object.entries(entries).map(([source, targets]) => [source, new Set(targets)]))
|
||
}
|
||
|
||
describe('一键整理的布局后处理', () => {
|
||
it('旁支与默认出口排在同一列(连线从它正中穿过)时,推到该连线的外侧', () => {
|
||
const graph = {
|
||
nodes: [
|
||
node('amount_gateway', 'fms-exclusive-gateway', 200, 300, 68, 68),
|
||
node('gm_approve', 'fms-user-task', 200, 400, 160, 48),
|
||
node('finance_review', 'fms-user-task', 200, 500, 160, 48),
|
||
],
|
||
edges: [
|
||
edge('e3', 'amount_gateway', 'gm_approve'),
|
||
edge('e4', 'amount_gateway', 'finance_review'),
|
||
edge('e5', 'gm_approve', 'finance_review'),
|
||
],
|
||
}
|
||
|
||
const moved = spreadBranchNodes(graph, {
|
||
defaultExitTargets: defaultExits({ amount_gateway: ['finance_review'] }),
|
||
})
|
||
|
||
expect(moved.has('gm_approve')).toBe(true)
|
||
// 线在 x=200(金额判断与财务复核同列),旁支被推到线右侧、留白 120
|
||
expect(graph.nodes[1].x).toBe(400)
|
||
// 源、目标本身不动
|
||
expect(graph.nodes[0].x).toBe(200)
|
||
expect(graph.nodes[2].x).toBe(200)
|
||
})
|
||
|
||
it('文本坐标跟着节点一起搬,否则框动了字还留在原地', () => {
|
||
const graph = {
|
||
nodes: [
|
||
node('amount_gateway', 'fms-exclusive-gateway', 200, 300, 68, 68, { value: '金额判断', x: 200, y: 300 }),
|
||
node('gm_approve', 'fms-user-task', 200, 400, 160, 48, { value: '总经理审批', x: 200, y: 400 }),
|
||
node('finance_review', 'fms-user-task', 200, 500, 160, 48, { value: '财务复核', x: 200, y: 500 }),
|
||
],
|
||
edges: [
|
||
edge('e3', 'amount_gateway', 'gm_approve'),
|
||
edge('e4', 'amount_gateway', 'finance_review'),
|
||
edge('e5', 'gm_approve', 'finance_review'),
|
||
],
|
||
}
|
||
|
||
spreadBranchNodes(graph, {
|
||
defaultExitTargets: defaultExits({ amount_gateway: ['finance_review'] }),
|
||
})
|
||
|
||
expect(graph.nodes[1].text.x).toBe(graph.nodes[1].x)
|
||
expect(graph.nodes[0].text.x).toBe(200)
|
||
})
|
||
|
||
it('网关旁支与主干贴得太近时,推到固定留白处(含旁支下游整条)', () => {
|
||
const graph = {
|
||
nodes: [
|
||
node('split', 'fms-exclusive-gateway', 0, 0, 68, 68),
|
||
node('branch', 'fms-user-task', 120, 200, 160, 48),
|
||
node('branch_2', 'fms-user-task', 120, 320, 160, 48),
|
||
node('join', 'fms-user-task', 0, 440, 160, 48),
|
||
],
|
||
edges: [
|
||
edge('e1', 'split', 'branch'),
|
||
edge('e2', 'branch', 'branch_2'),
|
||
edge('e3', 'branch_2', 'join'),
|
||
edge('e4', 'split', 'join'),
|
||
],
|
||
}
|
||
|
||
const moved = spreadBranchNodes(graph, { defaultExitTargets: defaultExits({ split: ['join'] }) })
|
||
|
||
// 间距只有 6px,补到 120:120 + (120 - 6) = 234
|
||
expect(moved.has('branch')).toBe(true)
|
||
expect(moved.has('branch_2')).toBe(true)
|
||
expect(graph.nodes[1].x).toBe(234)
|
||
expect(graph.nodes[2].x).toBe(234)
|
||
// 与网关同列的默认出口不动
|
||
expect(graph.nodes[3].x).toBe(0)
|
||
})
|
||
|
||
it('旁支已经让开足够距离时不动它', () => {
|
||
const graph = {
|
||
nodes: [
|
||
node('split', 'fms-exclusive-gateway', 0, 0, 68, 68),
|
||
node('branch', 'fms-user-task', 300, 200, 160, 48),
|
||
node('join', 'fms-user-task', 0, 400, 160, 48),
|
||
],
|
||
edges: [
|
||
edge('e1', 'split', 'branch'),
|
||
edge('e2', 'branch', 'join'),
|
||
edge('e3', 'split', 'join'),
|
||
],
|
||
}
|
||
|
||
const moved = spreadBranchNodes(graph, { defaultExitTargets: defaultExits({ split: ['join'] }) })
|
||
|
||
expect(moved.size).toBe(0)
|
||
expect(graph.nodes[1].x).toBe(300)
|
||
})
|
||
|
||
it('并行网关对齐到三条分支的水平中心,中间那条直上直下', () => {
|
||
const graph = {
|
||
nodes: [
|
||
node('split', 'fms-parallel-gateway', 0, 0, 68, 68),
|
||
node('a', 'fms-user-task', 0, 200, 160, 48),
|
||
node('b', 'fms-user-task', 260, 200, 160, 48),
|
||
node('c', 'fms-user-task', 520, 200, 160, 48),
|
||
node('join', 'fms-parallel-gateway', 260, 400, 68, 68),
|
||
],
|
||
edges: [
|
||
edge('e1', 'split', 'a'),
|
||
edge('e2', 'split', 'b'),
|
||
edge('e3', 'split', 'c'),
|
||
edge('e4', 'a', 'join'),
|
||
edge('e5', 'b', 'join'),
|
||
edge('e6', 'c', 'join'),
|
||
],
|
||
}
|
||
|
||
const moved = spreadBranchNodes(graph)
|
||
|
||
expect(moved.has('split')).toBe(true)
|
||
// 三条分支的中间那条在 260,分叉点与汇合点都对齐到这里
|
||
expect(graph.nodes[0].x).toBe(260)
|
||
expect(graph.nodes[4].x).toBe(260)
|
||
// 分支节点自己不动
|
||
expect(graph.nodes[1].x).toBe(0)
|
||
expect(graph.nodes[3].x).toBe(520)
|
||
})
|
||
|
||
it('并行网关下面两条分支时,网关落在两条分支中间', () => {
|
||
const graph = {
|
||
nodes: [
|
||
node('split', 'fms-parallel-gateway', 0, 0, 68, 68),
|
||
node('a', 'fms-user-task', 0, 200, 160, 48),
|
||
node('b', 'fms-user-task', 260, 200, 160, 48),
|
||
node('join', 'fms-parallel-gateway', 0, 400, 68, 68),
|
||
],
|
||
edges: [edge('e1', 'split', 'a'), edge('e2', 'split', 'b'), edge('e3', 'a', 'join'), edge('e4', 'b', 'join')],
|
||
}
|
||
|
||
spreadBranchNodes(graph)
|
||
|
||
expect(graph.nodes[0].x).toBe(130)
|
||
expect(graph.nodes[3].x).toBe(130)
|
||
})
|
||
|
||
it('主干排成两列时拉直成一条竖线,挂在主干上的旁支跟着搬', () => {
|
||
// dagre 的常见输出:并行段前面那段主干在 0,并行段之后在 260
|
||
const graph = {
|
||
nodes: [
|
||
node('start', 'fms-start', 0, 0, 52, 52),
|
||
node('check', 'fms-user-task', 0, 200, 160, 48),
|
||
node('gm', 'fms-user-task', 234, 300, 160, 48),
|
||
node('split', 'fms-parallel-gateway', 260, 400, 68, 68),
|
||
node('a', 'fms-user-task', 0, 600, 160, 48),
|
||
node('b', 'fms-user-task', 260, 600, 160, 48),
|
||
node('c', 'fms-user-task', 520, 600, 160, 48),
|
||
node('join', 'fms-parallel-gateway', 260, 800, 68, 68),
|
||
node('end', 'fms-end', 260, 1000, 52, 52),
|
||
],
|
||
edges: [
|
||
edge('e1', 'start', 'check'),
|
||
edge('e2', 'check', 'split'),
|
||
edge('e3', 'check', 'gm'),
|
||
edge('e4', 'gm', 'split'),
|
||
edge('e5', 'split', 'a'),
|
||
edge('e6', 'split', 'b'),
|
||
edge('e7', 'split', 'c'),
|
||
edge('e8', 'a', 'join'),
|
||
edge('e9', 'b', 'join'),
|
||
edge('e10', 'c', 'join'),
|
||
edge('e11', 'join', 'end'),
|
||
],
|
||
}
|
||
|
||
spreadBranchNodes(graph, { defaultExitTargets: defaultExits({ check: ['split'] }) })
|
||
|
||
// 主轴取主干 x 的中位数 = 260(并行段中心),前半段整段拉过来
|
||
expect(graph.nodes.map((item) => [item.id, item.x])).toEqual([
|
||
['start', 260],
|
||
['check', 260],
|
||
// 旁支跟着主干走,保持它相对主干的偏移(234 - 0)
|
||
['gm', 494],
|
||
['split', 260],
|
||
['a', 0],
|
||
['b', 260],
|
||
['c', 520],
|
||
['join', 260],
|
||
['end', 260],
|
||
])
|
||
})
|
||
|
||
it('条件网关的出线落在不同层时不居中(默认出口继续直下)', () => {
|
||
const graph = {
|
||
nodes: [
|
||
node('gateway', 'fms-exclusive-gateway', 0, 0, 68, 68),
|
||
node('branch', 'fms-user-task', 300, 200, 160, 48),
|
||
node('next', 'fms-user-task', 0, 400, 160, 48),
|
||
],
|
||
edges: [
|
||
edge('e1', 'gateway', 'branch'),
|
||
edge('e2', 'gateway', 'next'),
|
||
edge('e3', 'branch', 'next'),
|
||
],
|
||
}
|
||
|
||
spreadBranchNodes(graph, { defaultExitTargets: defaultExits({ gateway: ['next'] }) })
|
||
|
||
expect(graph.nodes[0].x).toBe(0)
|
||
})
|
||
|
||
it('条件网关两条都是显式条件、没有兜底时,两条支线左右分开、主干走到汇合点', () => {
|
||
const graph = {
|
||
nodes: [
|
||
node('start', 'fms-start', 0, 0, 52, 52),
|
||
node('gateway', 'fms-exclusive-gateway', 0, 100, 68, 68),
|
||
node('left', 'fms-user-task', -200, 200, 160, 48),
|
||
node('right', 'fms-user-task', 200, 200, 160, 48),
|
||
node('join', 'fms-user-task', 0, 300, 160, 48),
|
||
],
|
||
edges: [
|
||
edge('e1', 'start', 'gateway'),
|
||
edge('e2', 'gateway', 'left'),
|
||
edge('e3', 'gateway', 'right'),
|
||
edge('e4', 'left', 'join'),
|
||
edge('e5', 'right', 'join'),
|
||
],
|
||
}
|
||
|
||
const moved = spreadBranchNodes(graph)
|
||
|
||
// 没有默认出口,主干跳过两条支线直接走到汇合点,两条支线都算旁支
|
||
expect(moved.has('left')).toBe(true)
|
||
expect(moved.has('right')).toBe(true)
|
||
expect(graph.nodes[1].x).toBe(0)
|
||
// 左右各留白 120:86 + (120 - 86)
|
||
expect(graph.nodes[2].x).toBe(-234)
|
||
expect(graph.nodes[3].x).toBe(234)
|
||
// 汇合点在主轴上,不动
|
||
expect(graph.nodes[4].x).toBe(0)
|
||
})
|
||
})
|