基线:鉴权会话+工作组+工作台三区修复+编排工作区+产品设计文档

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
2026-07-27 20:43:35 +08:00
co-authored by Claude Fable 5
parent 61fe181678
commit ac85ecf2ea
119 changed files with 16634 additions and 1246 deletions
+58 -17
View File
@@ -20,23 +20,31 @@ export type InstanceMark = {
/** 每行最多几个方框 —— 蛇形折行的行宽;取原型 business 预设的观感 */
const ROW_WIDTH = 4;
export function packageToGraph(pkg: ProcessPackage, marks: readonly InstanceMark[] = []): FlowGraph {
export function packageToGraph(
pkg: ProcessPackage,
marks: readonly InstanceMark[] = [],
/** 活动范式(activityId → loop|flow):案例活动画绿 —— 范式住活动库,包里只有引用 */
paradigms?: ReadonlyMap<string, string>,
): FlowGraph {
const markOf = new Map(marks.map((m) => [m.nodeId, m]));
/*
* 手绘图存证优先:编辑器保存过,**手绘几何即呈现真相**。
* 运行标注仍要每次现算(它是运行态,不入存证),合到存证节点的 note 上。
*/
const stored = readStoredDiagram(pkg.diagram);
if (stored !== undefined) {
return {
...stored,
nodes: stored.nodes.map((n) => {
const state = stateOf(markOf.get(n.id));
return state === undefined ? n : { ...n, note: state };
}),
};
}
const nodes: FlowNode[] = pkg.nodes.map((n) => {
const mark = markOf.get(n.id);
const state =
mark === undefined || !mark.activated
? undefined
: mark.terminal !== undefined
? mark.terminal === 'released'
? '已放行'
: '已终止'
: mark.running
? '运行中'
: mark.waiting
? '等待中'
: '已激活';
const state = stateOf(markOf.get(n.id));
if (n.kind === 'gateway') {
return {
@@ -45,7 +53,8 @@ export function packageToGraph(pkg: ProcessPackage, marks: readonly InstanceMark
label: n.label,
// 并行网关画 +,异或网关画 ×(判断)
mode: n.gateway === 'parallel' ? 'and' : 'x',
...(n.mode === 'join' ? { sub: '汇合' } : { sub: '分叉' }),
...(n.sub === undefined ? (n.mode === 'join' ? { sub: '汇合' } : { sub: '分叉' }) : { sub: n.sub }),
...(n.basis === undefined ? {} : { basis: n.basis }),
...(state === undefined ? {} : { note: state }),
};
}
@@ -58,13 +67,20 @@ export function packageToGraph(pkg: ProcessPackage, marks: readonly InstanceMark
kind: 'activity',
label: n.label,
code: n.id,
...(n.sub === undefined ? {} : { sub: n.sub }),
...(state === undefined ? {} : { note: state }),
};
if (n.kind === 'approval') {
// approval **不是一种活动**:它挂在 kind:"activity" 下仅因共用同一套方框几何
return { ...base, flavor: 'approval', owner: n.approver.position };
}
return { ...base, owner: n.owner.position };
return {
...base,
owner: n.owner.position,
...(paradigms?.get(n.activityId) === 'loop' ? { flavor: 'case' as const } : {}),
...(n.in === undefined ? {} : { in: [...n.in] }),
...(n.out === undefined ? {} : { out: [...n.out] }),
};
});
/** 蛇形折行:偶数行 L→R、奇数行 R→L —— 行的划分交给拓扑序 */
@@ -76,13 +92,38 @@ export function packageToGraph(pkg: ProcessPackage, marks: readonly InstanceMark
from: e.from,
to: e.to,
// 回边按声明走「回 A4 重开新实例」,视觉上标红以区分正向流转
...(e.reopen ? { tone: 'bad' as const } : {}),
...(e.tone !== undefined ? { tone: e.tone } : e.reopen ? { tone: 'bad' as const } : {}),
...(e.label === undefined ? (e.condition === undefined ? {} : { label: e.condition }) : { label: e.label }),
}));
return { nodes, rows, anchors: [], edges };
}
/**
* 手绘图存证的在场校验:`diagram` 由本仓 `graph-to-pkg` 序列化而来,结构即 FlowGraph;
* 这里只验骨架在不在(nodes/edges 数组、非空),不逐字段复检 —— 写入侧是唯一生产者。
*/
function readStoredDiagram(d: Record<string, unknown> | undefined): FlowGraph | undefined {
if (d === undefined) return undefined;
const nodes = d['nodes'];
const edges = d['edges'];
if (!Array.isArray(nodes) || nodes.length === 0 || !Array.isArray(edges)) return undefined;
return {
nodes,
edges,
rows: Array.isArray(d['rows']) ? d['rows'] : [],
anchors: Array.isArray(d['anchors']) ? d['anchors'] : [],
manual: d['manual'] === true,
} as FlowGraph;
}
/** 运行标注:节点实例态 → 画布角注文字;未激活不标 */
function stateOf(mark: InstanceMark | undefined): string | undefined {
if (mark === undefined || !mark.activated) return undefined;
if (mark.terminal !== undefined) return mark.terminal === 'released' ? '已放行' : '已终止';
return mark.running ? '运行中' : mark.waiting ? '等待中' : '已激活';
}
/** 拓扑序:回边不参与定序(否则成环),同层按声明顺序稳定排列 */
function topologicalOrder(pkg: ProcessPackage): string[] {
const ids = pkg.nodes.map((n) => n.id as string);