| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803 |
- import { customAlphabet } from 'nanoid';
- import { inject, injectable, optional, postConstruct } from 'inversify';
- import { Disposable, Emitter, type IPoint } from '@flowgram.ai/utils';
- import { NodeEngineContext } from '@flowgram.ai/form-core';
- import { FlowDocument, FlowNodeBaseType, FlowNodeTransformData } from '@flowgram.ai/document';
- import {
- injectPlaygroundContext,
- PlaygroundConfigEntity,
- PlaygroundContext,
- PositionData,
- TransformData,
- } from '@flowgram.ai/core';
- import { WorkflowLinesManager } from './workflow-lines-manager';
- import {
- WorkflowDocumentOptions,
- WorkflowDocumentOptionsDefault,
- } from './workflow-document-option';
- import { getFlowNodeFormData } from './utils/flow-node-form-data';
- import { delay, fitView, getAntiOverlapPosition } from './utils';
- import {
- type WorkflowContentChangeEvent,
- WorkflowContentChangeType,
- WorkflowEdgeJSON,
- type WorkflowJSON,
- type WorkflowNodeJSON,
- type WorkflowNodeMeta,
- type WorkflowNodeRegistry,
- WorkflowSubCanvas,
- } from './typings';
- import { WorkflowSelectService } from './service/workflow-select-service';
- import { FREE_LAYOUT_KEY, type FreeLayout } from './layout';
- import { WorkflowNodeLinesData } from './entity-datas';
- import {
- WorkflowLineEntity,
- WorkflowLinePortInfo,
- WorkflowNodeEntity,
- WorkflowPortEntity,
- } from './entities';
- const nanoid = customAlphabet('1234567890', 5);
- export const WorkflowDocumentProvider = Symbol('WorkflowDocumentProvider');
- export type WorkflowDocumentProvider = () => WorkflowDocument;
- @injectable()
- export class WorkflowDocument extends FlowDocument {
- private _onContentChangeEmitter = new Emitter<WorkflowContentChangeEvent>();
- protected readonly onLoadedEmitter = new Emitter<void>();
- readonly onContentChange = this._onContentChangeEmitter.event;
- private _onReloadEmitter = new Emitter<WorkflowDocument>();
- readonly onReload = this._onReloadEmitter.event;
- private disposed = false;
- /**
- * 数据加载完成
- */
- readonly onLoaded = this.onLoadedEmitter.event;
- protected _loading = false;
- @inject(WorkflowLinesManager) linesManager: WorkflowLinesManager;
- @inject(PlaygroundConfigEntity) playgroundConfig: PlaygroundConfigEntity;
- @injectPlaygroundContext() playgroundContext: PlaygroundContext;
- @inject(WorkflowDocumentOptions)
- options: WorkflowDocumentOptions = {};
- @inject(NodeEngineContext) @optional() nodeEngineContext: NodeEngineContext;
- @inject(WorkflowSelectService) selectServices: WorkflowSelectService;
- get loading(): boolean {
- return this._loading;
- }
- async fitView(easing?: boolean): Promise<void> {
- return fitView(this, this.playgroundConfig, easing).then(() => {
- this.linesManager.forceUpdate();
- });
- }
- @postConstruct()
- init(): void {
- super.init();
- this.currentLayoutKey = this.options.defaultLayout || FREE_LAYOUT_KEY;
- this.linesManager.init(this);
- this.playgroundConfig.getCursors = () => this.options.cursors;
- this.linesManager.onAvailableLinesChange((e) => this.fireContentChange(e));
- this.playgroundConfig.onReadonlyOrDisabledChange(({ readonly }) => {
- if (this.nodeEngineContext) {
- this.nodeEngineContext.readonly = readonly;
- }
- });
- }
- async load(): Promise<void> {
- this._loading = true;
- await super.load();
- this._loading = false;
- this.onLoadedEmitter.fire();
- }
- async reload(json: WorkflowJSON, delayTime = 0): Promise<void> {
- this._loading = true;
- this.clear();
- this.fromJSON(json);
- // loading添加delay,避免reload时触发fireContentChange的副作用
- await delay(delayTime);
- this._loading = false;
- this._onReloadEmitter.fire(this);
- }
- /**
- * 从数据加载
- * @param json
- */
- fromJSON(json: Partial<WorkflowJSON>, fireRender = true): void {
- const { flattenJSON, nodeBlocks, nodeEdges } = this.flatJSON(json);
- const nestedJSON = this.nestJSON(flattenJSON, nodeBlocks, nodeEdges);
- // 触发画布更新
- this.entityManager.changeEntityLocked = true;
- // 逐层渲染
- this.renderJSON(nestedJSON);
- this.entityManager.changeEntityLocked = false;
- this.transformer.loading = false;
- // 批量触发画布更新
- if (fireRender) {
- this.fireRender();
- }
- }
- /**
- * 清空画布
- */
- clear(): void {
- this.getAllNodes().map((node) => node.dispose()); // 清空节点
- this.linesManager.getAllLines().map((line) => line.dispose()); // 清空线条
- this.getAllPorts().map((port) => port.dispose()); // 清空端口
- this.selectServices.clear(); // 清空选择
- }
- /**
- * 创建流程节点
- * @param json
- */
- createWorkflowNode(
- json: WorkflowNodeJSON,
- isClone: boolean = false,
- parentId?: string
- ): WorkflowNodeEntity {
- // 是否是一个已经存在的节点
- const isExistedNode = this.getNode(json.id);
- const parent = this.getNode(parentId ?? this.root.id) ?? this.root;
- const node = this.addNode(
- {
- ...json,
- parent,
- },
- undefined,
- true
- ) as WorkflowNodeEntity;
- const registry = node.getNodeRegistry() as WorkflowNodeRegistry;
- const { formMeta } = registry;
- const meta = node.getNodeMeta<WorkflowNodeMeta>();
- const formData = getFlowNodeFormData(node);
- const transform = node.getData<FlowNodeTransformData>(FlowNodeTransformData)!;
- const freeLayout = this.layout as FreeLayout;
- transform.onDataChange(() => {
- // TODO 这个有点难以理解,其实是为了同步size 数据
- freeLayout.syncTransform(node);
- });
- let { position } = meta;
- if (!position) {
- // 获取默认的位置
- position = this.getNodeDefaultPosition(json.type);
- }
- // 更新节点位置信息
- node.getData(TransformData)!.update({
- position,
- });
- // 初始化表单数据
- if (formMeta && formData && !formData.formModel.initialized) {
- // 如果表单数据在前置步骤(fromJSON)内已定义,则跳过表单初始化逻辑
- formData.createForm(formMeta, json.data);
- formData.onDataChange(() => {
- this.fireContentChange({
- type: WorkflowContentChangeType.NODE_DATA_CHANGE,
- toJSON: () => formData.toJSON(),
- entity: node,
- });
- });
- }
- // 位置变更
- const positionData = node.getData<PositionData>(PositionData)!;
- positionData.onDataChange(() => {
- this.fireContentChange({
- type: WorkflowContentChangeType.MOVE_NODE,
- toJSON: () => positionData.toJSON(),
- entity: node,
- });
- });
- const subCanvas = this.getNodeSubCanvas(node);
- if (!isExistedNode && !subCanvas?.isCanvas) {
- this.fireContentChange({
- type: WorkflowContentChangeType.ADD_NODE,
- entity: node,
- toJSON: () => this.toNodeJSON(node),
- });
- node.toDispose.push(
- Disposable.create(() => {
- this.fireContentChange({
- type: WorkflowContentChangeType.DELETE_NODE,
- entity: node,
- toJSON: () => this.toNodeJSON(node),
- });
- })
- );
- node.toDispose.push(
- Disposable.create(() => {
- if (!node.parent || node.parent.flowNodeType === FlowNodeBaseType.ROOT) {
- return;
- }
- const parentTransform = node.parent.getData(FlowNodeTransformData);
- // 加延迟是因为这个回调触发时节点实体还没有被销毁
- setTimeout(() => {
- parentTransform.fireChange();
- }, 0);
- })
- );
- }
- // 若存在子节点,则创建子节点
- if (json.blocks) {
- this.renderJSON(
- { nodes: json.blocks, edges: json.edges ?? [] },
- {
- parent: node,
- isClone,
- }
- );
- }
- // 子画布联动
- if (subCanvas) {
- const canvasTransform = subCanvas.canvasNode.getData<TransformData>(TransformData);
- canvasTransform.update({
- position: subCanvas.parentNode.getNodeMeta()?.canvasPosition,
- });
- subCanvas.parentNode.onDispose(() => {
- subCanvas.canvasNode.dispose();
- });
- subCanvas.canvasNode.onDispose(() => {
- subCanvas.parentNode.dispose();
- });
- }
- this.onNodeCreateEmitter.fire({
- node,
- data: json,
- });
- return node;
- }
- /**
- * 获取默认的 x y 坐标, 默认为当前画布可视区域中心
- * @param type
- * @protected
- */
- getNodeDefaultPosition(type: string | number): IPoint {
- const { size } = this.getNodeRegistry(type).meta || {};
- // 当前可视区域的中心位置
- let position = this.playgroundConfig.getViewport(true).center;
- if (size) {
- position = {
- x: position.x,
- y: position.y - size.height / 2,
- };
- }
- // 去掉叠加的
- return getAntiOverlapPosition(this, position);
- }
- /**
- * 通过类型创建节点, 如果没有提供position 则直接放在画布中间
- * @param type
- */
- createWorkflowNodeByType(
- type: string | number,
- position?: IPoint,
- json: Partial<WorkflowNodeJSON> = {},
- parentID?: string
- ): WorkflowNodeEntity {
- let id: string = json.id as string;
- if (id === undefined) {
- // 保证 id 不要重复
- do {
- id = `1${nanoid()}`;
- } while (this.entityManager.getEntityById(id));
- } else {
- if (this.entityManager.getEntityById(id)) {
- throw new Error(`[WorkflowDocument.createWorkflowNodeByType] Node Id "${id}" duplicated.`);
- }
- }
- return this.createWorkflowNode(
- {
- ...json,
- id,
- type,
- meta: { position, ...json?.meta }, // TODO title 和 meta 要从注册数据去拿
- data: json?.data,
- blocks: json?.blocks,
- edges: json?.edges,
- },
- false,
- parentID
- );
- }
- getAllNodes(): WorkflowNodeEntity[] {
- return this.entityManager
- .getEntities<WorkflowNodeEntity>(WorkflowNodeEntity)
- .filter((n) => n.id !== FlowNodeBaseType.ROOT);
- }
- getAllPorts(): WorkflowPortEntity[] {
- return this.entityManager
- .getEntities<WorkflowPortEntity>(WorkflowPortEntity)
- .filter((p) => p.node.id !== FlowNodeBaseType.ROOT);
- }
- /**
- * 获取画布中的非游离节点
- * 1. 开始节点
- * 2. 从开始节点出发能走到的节点
- * 3. 结束节点
- * 4. 默认所有子画布内节点为游离节点
- */
- getAssociatedNodes(): WorkflowNodeEntity[] {
- const allNode = this.getAllNodes();
- const allLines = this.linesManager
- .getAllLines()
- .filter((line) => line.from && line.to)
- .map((line) => ({
- from: line.from.id,
- to: line.to!.id,
- }));
- const startNodeId = allNode.find((node) => node.isStart)!.id;
- const endNodeId = allNode.find((node) => node.isNodeEnd)!.id;
- // 子画布内节点无需开始/结束
- const nodeInSubCanvas = allNode
- .filter((node) => node.parent?.flowNodeType === FlowNodeBaseType.SUB_CANVAS)
- .map((node) => node.id);
- const associatedCache = new Set([endNodeId, ...nodeInSubCanvas]);
- const bfs = (nodeId: string) => {
- if (associatedCache.has(nodeId)) {
- return;
- }
- associatedCache.add(nodeId);
- const nextNodes = allLines.reduce((ids, { from, to }) => {
- if (from === nodeId && !associatedCache.has(to)) {
- ids.push(to);
- }
- return ids;
- }, [] as string[]);
- nextNodes.forEach(bfs);
- };
- bfs(startNodeId);
- const associatedNodes = allNode.filter((node) => associatedCache.has(node.id));
- return associatedNodes;
- }
- /**
- * 触发渲染
- */
- fireRender() {
- this.entityManager.fireEntityChanged(WorkflowNodeEntity.type);
- this.entityManager.fireEntityChanged(WorkflowLineEntity.type);
- this.entityManager.fireEntityChanged(WorkflowPortEntity.type);
- }
- fireContentChange(event: WorkflowContentChangeEvent): void {
- if (this._loading || this.disposed || this.entityManager.changeEntityLocked) {
- return;
- }
- this._onContentChangeEmitter.fire(event);
- }
- toNodeJSON(node: WorkflowNodeEntity): WorkflowNodeJSON {
- // 如果是子画布,返回其父节点的JSON
- const subCanvas = this.getNodeSubCanvas(node);
- if (subCanvas?.isCanvas === true) {
- return this.toNodeJSON(subCanvas.parentNode);
- }
- const json = this.toNodeJSONFromOptions(node);
- const children = this.getNodeChildren(node);
- // 计算子节点 JSON
- const blocks = children.map((child) => this.toNodeJSON(child));
- // 计算子线条 JSON
- const linesMap = new Map<string, WorkflowEdgeJSON>();
- children.forEach((child) => {
- const childLinesData = child.getData<WorkflowNodeLinesData>(WorkflowNodeLinesData);
- [...childLinesData.inputLines, ...childLinesData.outputLines]
- .filter(Boolean)
- .forEach((line) => {
- const lineJSON = this.toLineJSON(line);
- if (!lineJSON || linesMap.has(line.id)) {
- return;
- }
- linesMap.set(line.id, lineJSON);
- });
- });
- const edges = Array.from(linesMap.values()); // 使用 Map 防止线条重复
- // 拼接 JSON
- if (blocks.length > 0) json.blocks = blocks;
- if (edges.length > 0) json.edges = edges;
- return json;
- }
- /**
- * 节点转换为JSON, 没有format的过程
- * @param node
- * @returns
- */
- private toNodeJSONFromOptions(node: WorkflowNodeEntity): WorkflowNodeJSON {
- if (this.options.toNodeJSON) {
- return this.options.toNodeJSON(node) as WorkflowNodeJSON;
- }
- return WorkflowDocumentOptionsDefault.toNodeJSON!(node) as WorkflowNodeJSON;
- }
- copyNode(
- node: WorkflowNodeEntity,
- newNodeId?: string | undefined,
- format?: (json: WorkflowNodeJSON) => WorkflowNodeJSON,
- position?: IPoint
- ): WorkflowNodeEntity {
- let json = this.toNodeJSON(node);
- if (format) {
- json = format(json);
- }
- position = position || {
- x: json.meta!.position!.x + 30,
- y: json.meta!.position!.y + 30,
- };
- return this.createWorkflowNode(
- {
- id: newNodeId || `1${nanoid()}`,
- type: node.flowNodeType,
- meta: {
- ...json.meta,
- position,
- },
- data: json.data,
- blocks: json.blocks,
- edges: json.edges,
- },
- true,
- node.parent?.id
- );
- }
- copyNodeFromJSON(
- flowNodeType: string,
- nodeJSON: WorkflowNodeJSON,
- newNodeId?: string | undefined,
- position?: IPoint,
- parentId?: string
- ): WorkflowNodeEntity {
- position = position || {
- x: nodeJSON.meta!.position!.x + 30,
- y: nodeJSON.meta!.position!.y + 30,
- };
- return this.createWorkflowNode(
- {
- id: newNodeId || `1${nanoid()}`,
- type: flowNodeType,
- meta: {
- ...nodeJSON.meta,
- position,
- },
- data: nodeJSON.data,
- blocks: nodeJSON.blocks,
- edges: nodeJSON.edges,
- },
- true,
- parentId
- );
- }
- canRemove(node: WorkflowNodeEntity, silent?: boolean): boolean {
- const meta = node.getNodeMeta<WorkflowNodeMeta>();
- if (meta.deleteDisable) {
- return false;
- }
- if (this.options.canDeleteNode && !this.options.canDeleteNode(node, silent)) {
- return false;
- }
- return true;
- }
- /**
- * 判断端口是否为错误态
- */
- isErrorPort(port: WorkflowPortEntity) {
- if (typeof this.options.isErrorPort === 'function') {
- return this.options.isErrorPort(port);
- }
- return false;
- }
- /**
- * 导出数据
- */
- toJSON(): WorkflowJSON {
- // 要等 一些节点的 dispose 触发结束
- // await delay(10);
- const rootJSON = this.toNodeJSON(this.root);
- return {
- nodes: rootJSON.blocks ?? [],
- edges: rootJSON.edges ?? [],
- };
- }
- dispose() {
- if (this.disposed) {
- return;
- }
- super.dispose();
- this.disposed = true;
- this._onReloadEmitter.dispose();
- }
- private getEdgeID(edge: WorkflowEdgeJSON): string {
- return WorkflowLineEntity.portInfoToLineId({
- from: edge.sourceNodeID,
- to: edge.targetNodeID,
- fromPort: edge.sourcePortID,
- toPort: edge.targetPortID,
- });
- }
- /**
- * 拍平树形json结构,将结构信息提取到map
- */
- private flatJSON(json: Partial<WorkflowJSON> = { nodes: [], edges: [] }): {
- flattenJSON: WorkflowJSON;
- nodeBlocks: Map<string, string[]>;
- nodeEdges: Map<string, string[]>;
- } {
- const nodeBlocks = new Map<string, string[]>();
- const nodeEdges = new Map<string, string[]>();
- const rootNodes = json.nodes ?? [];
- const rootEdges = json.edges ?? [];
- const flattenNodeJSONs: WorkflowNodeJSON[] = [...rootNodes];
- const flattenEdgeJSONs: WorkflowEdgeJSON[] = [...rootEdges];
- const rootBlockIDs: string[] = rootNodes.map((node) => node.id);
- const rootEdgeIDs: string[] = rootEdges.map((edge) => this.getEdgeID(edge));
- nodeBlocks.set(FlowNodeBaseType.ROOT, rootBlockIDs);
- nodeEdges.set(FlowNodeBaseType.ROOT, rootEdgeIDs);
- // 如需支持多层结构,以下部分改为递归
- rootNodes.forEach((nodeJSON) => {
- const { blocks, edges } = nodeJSON;
- if (blocks) {
- flattenNodeJSONs.push(...blocks);
- const blockIDs: string[] = [];
- blocks.forEach((block) => {
- blockIDs.push(block.id);
- });
- nodeBlocks.set(nodeJSON.id, blockIDs);
- delete nodeJSON.blocks;
- }
- if (edges) {
- flattenEdgeJSONs.push(...edges);
- const edgeIDs: string[] = [];
- edges.forEach((edge) => {
- const edgeID = this.getEdgeID(edge);
- edgeIDs.push(edgeID);
- });
- nodeEdges.set(nodeJSON.id, edgeIDs);
- delete nodeJSON.edges;
- }
- });
- const flattenJSON: WorkflowJSON = {
- nodes: flattenNodeJSONs,
- edges: flattenEdgeJSONs,
- };
- return {
- flattenJSON,
- nodeBlocks,
- nodeEdges,
- };
- }
- /**
- * 对JSON进行分层
- */
- private nestJSON(
- flattenJSON: WorkflowJSON,
- nodeBlocks: Map<string, string[]>,
- nodeEdges: Map<string, string[]>
- ): WorkflowJSON {
- const nestJSON: WorkflowJSON = {
- nodes: [],
- edges: [],
- };
- const nodeMap = new Map<string, WorkflowNodeJSON>();
- const edgeMap = new Map<string, WorkflowEdgeJSON>();
- const rootBlockSet = new Set<string>(nodeBlocks.get(FlowNodeBaseType.ROOT) ?? []);
- const rootEdgeSet = new Set<string>(nodeEdges.get(FlowNodeBaseType.ROOT) ?? []);
- // 构造缓存
- flattenJSON.nodes.forEach((nodeJSON) => {
- nodeMap.set(nodeJSON.id, nodeJSON);
- });
- flattenJSON.edges.forEach((edgeJSON) => {
- const edgeID = this.getEdgeID(edgeJSON);
- edgeMap.set(edgeID, edgeJSON);
- });
- // 恢复层级数据
- flattenJSON.nodes.forEach((nodeJSON) => {
- if (rootBlockSet.has(nodeJSON.id)) {
- nestJSON.nodes.push(nodeJSON);
- }
- // 恢复blocks
- if (nodeBlocks.has(nodeJSON.id)) {
- const blockIDs = nodeBlocks.get(nodeJSON.id)!;
- const blockJSONs: WorkflowNodeJSON[] = blockIDs
- .map((blockID) => nodeMap.get(blockID)!)
- .filter(Boolean);
- nodeJSON.blocks = blockJSONs;
- }
- // 恢复edges
- if (nodeEdges.has(nodeJSON.id)) {
- const edgeIDs = nodeEdges.get(nodeJSON.id)!;
- const edgeJSONs: WorkflowEdgeJSON[] = edgeIDs
- .map((edgeID) => edgeMap.get(edgeID)!)
- .filter(Boolean);
- nodeJSON.edges = edgeJSONs;
- }
- });
- flattenJSON.edges.forEach((edgeJSON) => {
- const edgeID = this.getEdgeID(edgeJSON);
- if (rootEdgeSet.has(edgeID)) {
- nestJSON.edges.push(edgeJSON);
- }
- });
- return nestJSON;
- }
- /**
- * 逐层创建节点和线条
- */
- private renderJSON(
- json: WorkflowJSON,
- options?: {
- parent?: WorkflowNodeEntity;
- isClone?: boolean;
- }
- ) {
- // await delay(0); // Loop 节点 onCreate 存在异步创建子画布
- const { parent = this.root, isClone = false } = options ?? {};
- // 创建节点
- const containerID = this.getNodeSubCanvas(parent)?.canvasNode.id ?? parent.id;
- json.nodes.forEach((nodeJSON: WorkflowNodeJSON) => {
- this.createWorkflowNode(nodeJSON, isClone, containerID);
- }),
- // 创建线条
- json.edges.forEach((edge) => this.createWorkflowLine(edge, containerID));
- }
- private getNodeSubCanvas(node: WorkflowNodeEntity): WorkflowSubCanvas | undefined {
- if (!node) return;
- const nodeMeta = node.getNodeMeta<WorkflowNodeMeta>();
- const subCanvas = nodeMeta.subCanvas?.(node);
- return subCanvas;
- }
- private getNodeChildren(node: WorkflowNodeEntity): WorkflowNodeEntity[] {
- if (!node) return [];
- const subCanvas = this.getNodeSubCanvas(node);
- const childrenWithCanvas = subCanvas
- ? subCanvas.canvasNode.collapsedChildren
- : node.collapsedChildren;
- // 过滤掉子画布的JSON数据
- const children = childrenWithCanvas
- .filter((child) => {
- const childMeta = child.getNodeMeta<WorkflowNodeMeta>();
- return !childMeta.subCanvas?.(node)?.isCanvas;
- })
- .filter(Boolean);
- return children;
- }
- private toLineJSON(line: WorkflowLineEntity): WorkflowEdgeJSON | undefined {
- const lineJSON = line.toJSON();
- if (!line.to || !line.info.to || !line.toPort) {
- return;
- }
- // 父子节点之间连线,需替换子画布为父节点
- const fromSubCanvas = this.getNodeSubCanvas(line.from);
- const toSubCanvas = this.getNodeSubCanvas(line.to);
- if (fromSubCanvas && !fromSubCanvas.isCanvas && toSubCanvas && toSubCanvas.isCanvas) {
- // 忽略子画布与父节点的连线
- return;
- }
- if (line.from === line.to.parent && fromSubCanvas) {
- return {
- ...lineJSON,
- sourceNodeID: fromSubCanvas.parentNode.id,
- };
- }
- if (line.to === line.from.parent && toSubCanvas) {
- return {
- ...lineJSON,
- targetNodeID: toSubCanvas.parentNode.id,
- };
- }
- return lineJSON;
- }
- private createWorkflowLine(
- json: WorkflowEdgeJSON,
- parentId?: string
- ): WorkflowLineEntity | undefined {
- const fromNode = this.getNode(json.sourceNodeID);
- const toNode = this.getNode(json.targetNodeID);
- // 脏数据清除
- if (!fromNode || !toNode) {
- return;
- }
- const lineInfo: WorkflowLinePortInfo = {
- from: json.sourceNodeID,
- fromPort: json.sourcePortID,
- to: json.targetNodeID,
- toPort: json.targetPortID,
- };
- if (!parentId) {
- return this.linesManager.createLine(lineInfo);
- }
- // 父子节点之间连线,需替换父节点为子画布
- const canvasNode = this.getNode(parentId);
- if (!canvasNode) {
- return this.linesManager.createLine(lineInfo);
- }
- const parentSubCanvas = this.getNodeSubCanvas(canvasNode);
- if (!parentSubCanvas) {
- return this.linesManager.createLine(lineInfo);
- }
- if (lineInfo.from === parentSubCanvas.parentNode.id) {
- return this.linesManager.createLine({
- ...lineInfo,
- from: parentSubCanvas.canvasNode.id,
- });
- }
- if (lineInfo.to === parentSubCanvas.parentNode.id) {
- return this.linesManager.createLine({
- ...lineInfo,
- to: parentSubCanvas.canvasNode.id,
- });
- }
- return this.linesManager.createLine(lineInfo);
- }
- }
|