From 1de4f9db8d461e2464076f93549ca55e1cca7c38 Mon Sep 17 00:00:00 2001 From: yitaikarma Date: Fri, 17 Apr 2026 19:30:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=8D=E5=90=91=E6=A0=91?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E5=8A=9F=E8=83=BD=EF=BC=8C=E9=87=8D=E6=9E=84?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E5=92=8C=E6=A0=91=E7=9A=84=E9=80=89=E6=8B=A9?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Copilot --- modeler/package.json | 1 + .../views/decision/communication/relation.ts | 2 +- modeler/src/views/decision/designer/api.ts | 61 +++- .../src/views/decision/designer/designer.vue | 204 ++++++------- modeler/src/views/decision/designer/node.vue | 4 +- .../views/decision/designer/nodes-card.vue | 4 +- .../views/decision/designer/properties.vue | 9 +- .../reverse-tree/reverse-tree-loader.ts | 49 ++++ .../designer/reverse-tree/reverse-tree.ts | 267 ++++++++++++++++++ .../reverse-tree/tree-graph-resolver.ts | 43 +++ .../decision/designer/scenarios-card.vue | 20 +- .../designer/template-metadata-loader.ts | 32 +++ .../views/decision/designer/trees-card.vue | 33 ++- modeler/src/views/decision/graph/element.ts | 4 +- modeler/src/views/decision/graph/hooks.ts | 17 +- 15 files changed, 611 insertions(+), 139 deletions(-) create mode 100644 modeler/src/views/decision/designer/reverse-tree/reverse-tree-loader.ts create mode 100644 modeler/src/views/decision/designer/reverse-tree/reverse-tree.ts create mode 100644 modeler/src/views/decision/designer/reverse-tree/tree-graph-resolver.ts create mode 100644 modeler/src/views/decision/designer/template-metadata-loader.ts diff --git a/modeler/package.json b/modeler/package.json index af2e824..56c17c7 100644 --- a/modeler/package.json +++ b/modeler/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "@antv/g6": "^5.0.49", + "@ant-design/icons-vue": "^7.0.1", "@antv/x6": "^3.1.2", "@antv/x6-vue-shape": "^3.0.2", "ant-design-vue": "^4.2.6", diff --git a/modeler/src/views/decision/communication/relation.ts b/modeler/src/views/decision/communication/relation.ts index 72e8226..d454ec8 100644 --- a/modeler/src/views/decision/communication/relation.ts +++ b/modeler/src/views/decision/communication/relation.ts @@ -26,7 +26,7 @@ export function resolveConnectionRelation(graph: Graph): PlatformRelation[] { // 过滤无效/临时边 const validEdges = edges.filter(edge => { // 过滤临时边(X6 拖拽连线时生成的未完成边) - const isTempEdge = edge?.attr('line/stroke') === 'transparent' || edge.id.includes('temp'); + const isTempEdge = edge?.attr('line/stroke') === 'transparent' || String(edge.id).includes('temp'); if (isTempEdge) { tempEdgeIds.add(edge.id); return false; diff --git a/modeler/src/views/decision/designer/api.ts b/modeler/src/views/decision/designer/api.ts index a647086..71308fc 100644 --- a/modeler/src/views/decision/designer/api.ts +++ b/modeler/src/views/decision/designer/api.ts @@ -10,9 +10,54 @@ import { HttpRequestClient } from '@/utils/request'; import type { NodeTemplatesResponse } from './template'; import type { BehaviorTree, BehaviorTreeDetailsResponse, BehaviorTreePageResponse, BehaviorTreeRequest } from './tree'; -import type { BasicResponse } from '@/types'; +import type { BasicResponse, PageableResponse } from '@/types'; import type { PlatformListableResponse } from '../types'; + + +export interface TreeTemplateRow { + id: number; + type: string; + name: string; + multiable?: boolean; +} + +export interface TreeNodeInstanceRow { + id: number; + treeId: number; + templateId: number; + instanceName: string; + isRoot: number; +} + +export interface TreeConnectionRow { + id: number; + treeId: number; + parentNodeId: number; + childNodeId: number; + orderIndex: number; +} + +export interface TreeTemplateParameterDefRow { + id: number; + templateId: number; + paramKey: string; + dataType: string; + defaultValue: string; + description: string; + templateType: string; +} + +export interface TreeNodeParameterRow { + id: number; + treeId: number; + nodeInstanceId: number; + paramDefId: number; + value: string; + groupIndex: number; +} + + const req = HttpRequestClient.create({ baseURL: '/api', }); @@ -20,6 +65,20 @@ const req = HttpRequestClient.create({ export const findNodeTemplates = (): Promise => { return req.get('/system/nodetemplate/all'); }; +export const findTemplateParameterDefs = (query={pageSize: 1000, pageNum: 1}): Promise> => { + return req.get('/system/templateparameterdef/list', query); +} +export const findNodeConnections = (query: {treeId: number}): Promise> => { + return req.get('/system/nodeconnection/list', {pageSize: 1000, pageNum: 1, ...query}); +}; +export const findNodeParameters = (query: {treeId: number}): Promise> => { + return req.get('/system/nodeparameter/list', {pageSize: 1000, pageNum: 1, ...query}); +} +export const findTreeNodeInstances = (query: {treeId: number}): Promise> => { + return req.get('/system/treenodeinstance/list', {pageSize: 1000, pageNum: 1, ...query}); +} + + export const findTreesByQuery = (query: Partial = {}): Promise => { return req.get('/system/behaviortree/list', query); diff --git a/modeler/src/views/decision/designer/designer.vue b/modeler/src/views/decision/designer/designer.vue index e822b7b..e91fb6c 100644 --- a/modeler/src/views/decision/designer/designer.vue +++ b/modeler/src/views/decision/designer/designer.vue @@ -7,11 +7,13 @@
@@ -76,6 +78,7 @@ import Properties from './properties.vue'; import type { NodeDragTemplate } from './template'; import type { BehaviorTree } from './tree'; import { createGraphTaskElementFromTemplate } from './utils'; +import { resolveBehaviorTreeGraph } from './reverse-tree/tree-graph-resolver'; import { createGraphTaskElement, createLineOptions, type GraphContainer, type GraphTaskElement, hasElements, hasRootElementNode, resolveGraph, useGraphCanvas } from '../graph'; import { registerNodeElement } from './register'; @@ -268,102 +271,6 @@ export default defineComponent({ } }; - const handleSelectTree = (tree: BehaviorTree) => { - destroyGraph(); - currentPlatformId.value = null; - - console.info('handleSelectTree', tree); - findOneTreeById(tree.id).then(r => { - if (r.data) { - let nodeGraph: GraphContainer | null = null; - try { - nodeGraph = JSON.parse(r.data?.xmlContent as unknown as string) as unknown as GraphContainer; - } catch (e: any) { - console.error('parse error,cause:', e); - } - if (!nodeGraph) { - nodeGraph = { - nodes: [], - edges: [], - }; - } - currentBehaviorTree.value = { - ...r.data, - graph: nodeGraph, - }; - currentTreeEditing.value = true; - - // 加载下属平台 - loadSubPlatforms(r.data.platformId); - - nextTick(() => { - initGraph(); - }); - } else { - message.error(r.msg ?? '行为树不存在.'); - } - }); - }; - - const createElements = () => { - clearGraph(); - nextTick(() => { - if (currentBehaviorTree.value?.graph && graph.value) { - if (currentBehaviorTree.value?.graph.nodes) { - currentBehaviorTree.value?.graph.nodes.forEach(ele => { - const node = createGraphTaskElement(ele as GraphTaskElement); - console.info('create node: ', ele); - // 将节点添加到画布 - graph.value?.addNode(node as Node); - }); - fitToScreen(); - } - - // 然后添加所有边,确保包含桩点信息 - currentBehaviorTree.value?.graph.edges.forEach(edgeData => { - graph.value?.addEdge({ - ...edgeData, - ...createLineOptions(), - }); - }); - } - }); - }; - - const STORAGE_KEY_SCENARIO = 'designer_from_scenario_id'; - - const resolveQuery = ()=> { - console.log(currentRoute); - - let scenarioId = Number(currentRoute.query.scenario); - if (!isNaN(scenarioId) && scenarioId > 0) { - currentScenarioId.value = scenarioId; - fromScenarioPage.value = true; - sessionStorage.setItem(STORAGE_KEY_SCENARIO, String(scenarioId)); - } else { - // 尝试从 sessionStorage 恢复(页面刷新或 SPA 内部跳转后 query 参数丢失的情况) - const stored = sessionStorage.getItem(STORAGE_KEY_SCENARIO); - const storedId = Number(stored); - if (stored && !isNaN(storedId) && storedId > 0) { - currentScenarioId.value = storedId; - fromScenarioPage.value = true; - } else { - fromScenarioPage.value = false; - } - } - let platformId = Number(currentRoute.query.platform); - if (!isNaN(platformId)) { - currentPlatformId.value = platformId; - } else { - currentPlatformId.value = null; - } - } - - // 处理选择场景 - const handleSelectScenario = (scenario: any) => { - currentScenarioId.value = scenario.id; - }; - const initGraphConfig = (_graph?: GraphContainer) => { const graph: GraphContainer = _graph ? _graph : { nodes: [], @@ -384,6 +291,96 @@ export default defineComponent({ }; }; + const createElements = () => { + clearGraph(); + nextTick(() => { + if (currentBehaviorTree.value?.graph && graph.value) { + if (currentBehaviorTree.value?.graph.nodes) { + currentBehaviorTree.value?.graph.nodes.forEach(ele => { + const node = createGraphTaskElement(ele as GraphTaskElement); + // 将节点添加到画布 + graph.value?.addNode(node as Node); + }); + } + setTimeout(() => { + // 然后添加所有边,确保包含桩点信息 + currentBehaviorTree.value?.graph.edges.forEach(edgeData => { + graph.value?.addEdge({ + ...edgeData, + ...createLineOptions(), + }); + }); + }); + fitToScreen(); + + console.info('create elements: ', currentBehaviorTree.value?.graph); + } + }); + }; + + const applyBehaviorTree = (tree: BehaviorTree) => { + destroyGraph(); + currentPlatformId.value = tree.platformId ?? null; + currentBehaviorTree.value = tree; + currentTreeEditing.value = true; + selectedModelNode.value = null; + selectedNodeTaskElement.value = null; + loadSubPlatforms(currentPlatformId.value); + console.log('currentBehaviorTree.value: ', tree); + + nextTick(() => { + initGraph(); + console.log('initGraphTree: ', tree); + + }); + }; + + const handleSelectTree = (tree: BehaviorTree) => { + console.info('handleSelectTree', tree); + findOneTreeById(tree.id).then(r => { + if (r.data) { + resolveBehaviorTreeGraph(r.data.id, r.data.xmlContent).then(nodeGraph => { + applyBehaviorTree({ + ...r.data, + graph: nodeGraph, + }); + }).catch(error => { + console.error('resolve tree graph error:', error); + message.error('加载行为树图失败'); + }); + } else { + message.error(r.msg ?? '行为树不存在.'); + } + }); + }; + + const resolveQuery = ()=> { + console.log(currentRoute); + if (!currentRoute.query.scenario) { + return + } + + let scenarioId = Number(currentRoute.query.scenario); + if (!isNaN(scenarioId)) { + currentScenarioId.value = scenarioId; + fromScenarioPage.value = true; + } else { + fromScenarioPage.value = false; + } + + let platformId = Number(currentRoute.query.platform); + if (!isNaN(platformId)) { + currentPlatformId.value = platformId; + } else { + currentPlatformId.value = null; + } + } + + // 处理选择场景 + const handleSelectScenario = (scenario: any) => { + currentScenarioId.value = scenario.id; + }; + const handleCreateTree = () => { destroyGraph(); initGraphConfig(); @@ -407,9 +404,17 @@ export default defineComponent({ try { graph.value = createCanvas(canvas.value); console.log('画布初始化成功'); - initGraphConfig(); + if (!currentBehaviorTree.value) { + initGraphConfig(); + } createElements(); + graph.value?.on('edge:click', (args: any) => { + const edge = args.edge; + console.info('点击了连线:', args); + // 这里可以添加选中连线的逻辑,比如显示属性面板等 + }); + // 监听缩放变化 handleGraphEvent('scale', ({ sx }: { sx: number }) => { currentZoom.value = sx; @@ -450,7 +455,6 @@ export default defineComponent({ const init = () => { console.info('init'); - nextTick(() => { initGraph(); @@ -461,8 +465,6 @@ export default defineComponent({ if (currentPlatformId.value) { findOneTreeByPlatformId(currentPlatformId.value).then(r => { - console.log(r); - if (r.data) { handleSelectTree(r.data); } else { @@ -488,7 +490,6 @@ export default defineComponent({ }; const handleGoback = ()=> { - sessionStorage.removeItem(STORAGE_KEY_SCENARIO); window.location.href = `/app/decision/communication?scenario=${currentScenarioId.value}` } @@ -542,6 +543,7 @@ export default defineComponent({ return { nodeCommands, currentScenarioId, + currentPlatformId, platforms, subPlatforms, scenariosCardRef, diff --git a/modeler/src/views/decision/designer/node.vue b/modeler/src/views/decision/designer/node.vue index 39d1f87..31033fd 100644 --- a/modeler/src/views/decision/designer/node.vue +++ b/modeler/src/views/decision/designer/node.vue @@ -18,7 +18,7 @@ -
+
@@ -31,7 +31,7 @@

-
+
diff --git a/modeler/src/views/decision/designer/nodes-card.vue b/modeler/src/views/decision/designer/nodes-card.vue index 76b3ecf..a9d0f37 100644 --- a/modeler/src/views/decision/designer/nodes-card.vue +++ b/modeler/src/views/decision/designer/nodes-card.vue @@ -72,8 +72,8 @@