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

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
+112 -3
View File
@@ -1,16 +1,125 @@
/**
* 编排画布 —— diagram-js 画布件的宿主(编码规范 §6.1「PRD 画布件 1:1 平移」)。
*
* 原型的 `HostExample.FlowFigureBlock` 同时带手绘编辑器;此处先接**只读态**:
* 流程包 → `FlowGraph`(`pkg-to-graph`)→ 布局引擎算几何 → `FlowDiagram` 绘制。
* 节点实例落位以角注呈现,几何不因运行态而变——**图是定义,标注是运行**。
* `FlowFigureBlock` 自原型 `HostExample` 平移:区块小标题右侧「编辑」芯片进手绘编辑器
* (FlowEditor,画布内工具栏含 取消/保存绘图);展示态 hero/cap 框 + FlowDiagram
* (单击节点下钻/选中、双击活动就地改文字);图例贴在流程图正下方。
* 必须包在 `.process-desk > .process-doc` 纸面容器内(flow-canvas.css 规则 scoped 到它)。
*
* `FlowFigure` 保留为只读便捷壳(任务页的流程图用它)。
*/
import { useState } from 'react';
import type { ProcessPackage } from '@contracts';
import { Ico } from '@ui';
import { FlowDiagram } from './FlowDiagram.tsx';
import { FlowEditor } from './FlowEditor.tsx';
import type { FlowGraph } from './flow-layout.ts';
import type { SpPosition } from './support.tsx';
import { packageToGraph } from './pkg-to-graph.ts';
import type { InstanceMark } from './pkg-to-graph.ts';
import './flow-canvas.css';
export function FlowFigureBlock({
title,
oneLiner,
graph,
drilledIds,
positions,
canEdit,
onNodeClick,
onEditNodeText,
onSaveFlowGraph,
}: {
title: string;
oneLiner?: string | undefined;
graph: FlowGraph | null;
/** 已建立下钻内容的节点 id(删除这些节点时编辑器会二次确认) */
drilledIds: string[];
positions?: SpPosition[] | undefined;
canEdit: boolean;
onNodeClick: (nodeId: string) => void;
/** 双击流程图活动就地改文字(标题 / 主办) */
onEditNodeText?: ((nodeId: string, patch: { label: string; owner?: string }) => Promise<void>) | undefined;
/** 手工绘图:整图保存(idMap = 本次编辑会话 原id→现id,宿主用它重键下钻内容) */
onSaveFlowGraph?: ((graph: FlowGraph, idMap: Record<string, string>) => Promise<void>) | undefined;
}) {
const [editing, setEditing] = useState(false);
return (
<>
<div className="view-lbl">
流程图 · 顺序
{canEdit && onSaveFlowGraph !== undefined && !editing && (
<button
type="button"
className="dc2-addbtn"
title="手工绘图(珊格正交:活动/网关/起止/卡点,拖拽连线);画布内工具栏有 取消/保存绘图"
onClick={() => setEditing(true)}
>
<Ico name="pen-line" s={11} /> 编辑
</button>
)}
</div>
{editing && onSaveFlowGraph !== undefined ? (
<div className="hero">
<div className="cap">
<span>FIG — {title}流程 · 手工绘图</span>
<span>珊格 10px · 直线与直角折线</span>
</div>
<FlowEditor
initial={graph}
drilledIds={drilledIds}
positions={positions}
onSave={async (next, idMap) => {
await onSaveFlowGraph(next, idMap);
setEditing(false);
}}
onCancel={() => setEditing(false)}
/>
</div>
) : (
<div className="hero">
<div className="cap">
<span>FIG — {title}流程</span>
<span>{oneLiner ?? '活动 · 网关 · 顺序流'}</span>
</div>
<div className="fig-body">
<FlowDiagram
graph={graph}
variant="business"
onNodeClick={onNodeClick}
onEditNode={canEdit ? onEditNodeText : undefined}
ownerOptions={positions}
ariaLabel={`${title}业务流程图`}
/>
</div>
</div>
)}
{/* 图例贴在流程图正下方,图标与绘图工具(元素盘)同款 SVG */}
<div className="legend">
<span>
<b>图例</b>
</span>
<span><i className="lg-i fe-pi-start" aria-hidden /> 起始</span>
<span><i className="lg-i fe-pi-end" aria-hidden /> 结束</span>
<span><i className="lg-i fe-pi-sop" aria-hidden /> 标准活动</span>
<span><i className="lg-i fe-pi-case" aria-hidden /> 案例活动</span>
<span><i className="lg-i fe-pi-approval" aria-hidden /> 审批点</span>
<span><i className="lg-i fe-pi-gwx" aria-hidden /> 判断网关</span>
<span><i className="lg-i fe-pi-gwand" aria-hidden /> 并行网关</span>
<span><i className="lg-i fe-pi-callout" aria-hidden /> 卡点</span>
<span><i className="lg-i lg-flow" aria-hidden /> 顺序流</span>
<span className="sep">|</span>
<span>
<b>责任</b>
</span>
<span>右上角标 责任人</span>
</div>
</>
);
}
/** 只读壳:流程包 → 图 → 画(任务页 / 工作流实例页用) */
export function FlowFigure({
pkg,
instances,