20260923230500

This commit is contained in:
oneao committed 2026-09-23 23:05:01 +08:00
1 parent e6935b8fa4
commit 0405cd198a
36 files changed
+3668 -911

No files matched your search

@@ -0,0 +1,221 @@
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)
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)
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)
})
})