Initial commit

This commit is contained in:
libertyspy
2026-02-08 22:31:13 +08:00
parent 43837901f3
commit 0b55384442
11 changed files with 88 additions and 79 deletions

View File

@@ -18,6 +18,7 @@ export interface DraggableElement {
draggable: boolean, draggable: boolean,
parent?: DraggableElement, parent?: DraggableElement,
children: DraggableElement[] children: DraggableElement[]
[key: string]: unknown; [key: string]: unknown;
} }

View File

@@ -10,7 +10,7 @@
import { Edge, Graph, Path, Selection } from '@antv/x6'; import { Edge, Graph, Path, Selection } from '@antv/x6';
import type { ModelElement } from './element'; import type { ModelElement } from './element';
import type { Connecting } from '@antv/x6/lib/graph/options'; import type { Connecting } from '@antv/x6/lib/graph/options';
import {createLineOptions} from './line' import { createLineOptions } from './line';
Graph.registerConnector( Graph.registerConnector(
'sequenceFlowConnector', 'sequenceFlowConnector',
@@ -55,7 +55,7 @@ export const createGraphConnectingAttributes = (): Partial<Connecting> => {
attrs: lineOptions.attrs, attrs: lineOptions.attrs,
animation: lineOptions.animation, animation: lineOptions.animation,
markup: lineOptions.markup, markup: lineOptions.markup,
}) });
return edge; return edge;
}, },
validateConnection(this: Graph, { sourceCell, targetCell }) { validateConnection(this: Graph, { sourceCell, targetCell }) {

View File

@@ -13,6 +13,7 @@ import type { NodeViewPositionEventArgs } from '@antv/x6/es/view/node/type';
import { createGraphCanvas } from './graph'; import { createGraphCanvas } from './graph';
import { EventListener } from '@/utils/event'; import { EventListener } from '@/utils/event';
import type { ModelElement } from './element'; import type { ModelElement } from './element';
// import {createLineOptions} from './line' // import {createLineOptions} from './line'
export interface UseGraphCanvas { export interface UseGraphCanvas {
@@ -163,7 +164,7 @@ export const useGraphCanvas = (readonly: boolean = false): UseGraphCanvas => {
router: {}, router: {},
attrs: {}, attrs: {},
target: targetNode.id, target: targetNode.id,
targetName: targetData.name targetName: targetData.name,
}); });
sourceNode.replaceData({ ...sourceData, edges: sourceEdges }); sourceNode.replaceData({ ...sourceData, edges: sourceEdges });
} }

View File

@@ -43,5 +43,5 @@ export const createLineOptions = (): any => {
}, },
], ],
], ],
} };
} };

View File

@@ -47,7 +47,7 @@ import { elementProps } from './props';
import type { ModelElement } from './element'; import type { ModelElement } from './element';
import { DeleteOutlined, SettingOutlined } from '@ant-design/icons-vue'; import { DeleteOutlined, SettingOutlined } from '@ant-design/icons-vue';
import type { Graph } from '@antv/x6'; import type { Graph } from '@antv/x6';
import {substring} from '@/utils/strings' import { substring } from '@/utils/strings';
export default defineComponent({ export default defineComponent({
name: 'ModelElement', name: 'ModelElement',
@@ -184,6 +184,7 @@ export default defineComponent({
background: url('@/assets/icons/m-02.png') center / 100% 100%; background: url('@/assets/icons/m-02.png') center / 100% 100%;
} }
} }
&.ks-designer-input-node { &.ks-designer-input-node {
background: linear-gradient(150deg, #083058 1%, #1e5d9b 55%); background: linear-gradient(150deg, #083058 1%, #1e5d9b 55%);

View File

@@ -48,12 +48,12 @@
</div> </div>
<Properties <Properties
v-if="graph" v-if="graph"
@update-element="handleUpdateElement"
:tree="currentBehaviorTree"
:tree-editing="currentTreeEditing"
:element="selectedNodeTaskElement" :element="selectedNodeTaskElement"
:graph="graph as any" :graph="graph as any"
:node="selectedModelNode as any" /> :node="selectedModelNode as any"
:tree="currentBehaviorTree"
:tree-editing="currentTreeEditing"
@update-element="handleUpdateElement" />
</div> </div>
</a-layout> </a-layout>
</a-layout> </a-layout>
@@ -70,16 +70,16 @@ import { Wrapper } from '@/components/wrapper';
import { safePreventDefault, safeStopPropagation } from '@/utils/event'; import { safePreventDefault, safeStopPropagation } from '@/utils/event';
import Header from './header.vue'; import Header from './header.vue';
import Properties from './properties.vue'; import Properties from './properties.vue';
import { useGraphCanvas } from './builder/hooks';
import { registerNodeElement } from './builder/register';
import type { BehaviorTree, NodeTemplate } from './types'; import type { BehaviorTree, NodeTemplate } from './types';
import type { GraphTaskElement, NodeGraph } from './builder/element'; import type { GraphTaskElement, NodeGraph } from './builder/element';
import { useGraphCanvas } from './builder/hooks';
import { registerNodeElement } from './builder/register';
import { createLineOptions } from './builder/line';
import { createTree, findOneTreeById, updateTree } from './api'; import { createTree, findOneTreeById, updateTree } from './api';
import { createGraphTaskElement, hasElements, hasRootElementNode, resolveNodeGraph } from './builder/utils'; import { createGraphTaskElement, hasElements, hasRootElementNode, resolveNodeGraph } from './builder/utils';
import { createGraphTaskElementFromTemplate } from './utils/node'; import { createGraphTaskElementFromTemplate } from './utils/node';
import TressCard from './trees-card.vue'; import TressCard from './trees-card.vue';
import NodesCard from './nodes-card.vue'; import NodesCard from './nodes-card.vue';
import { createLineOptions } from '@/views/decision/builder/line.ts';
const TeleportContainer = defineComponent(getTeleport()); const TeleportContainer = defineComponent(getTeleport());
@@ -268,7 +268,7 @@ export default defineComponent({
}, 100); // 延迟一会儿,免得连线错位 }, 100); // 延迟一会儿,免得连线错位
} }
} }
}, 100) }, 100);
}); });
}; };
@@ -285,16 +285,16 @@ export default defineComponent({
nodes: [], nodes: [],
}, },
updatedAt: null, updatedAt: null,
} };
currentNodeGraph.value = { currentNodeGraph.value = {
edges: [], edges: [],
nodes: [], nodes: [],
} };
selectedModelNode.value = null; selectedModelNode.value = null;
selectedNodeTaskElement.value = null; selectedNodeTaskElement.value = null;
createElements(); createElements();
} };
// 初始化X6画布 // 初始化X6画布
const initGraph = () => { const initGraph = () => {
@@ -362,7 +362,7 @@ export default defineComponent({
console.info('handleUpdateElement', element); console.info('handleUpdateElement', element);
// 更新本地引用 // 更新本地引用
selectedNodeTaskElement.value = element; selectedNodeTaskElement.value = element;
changed.value = true changed.value = true;
}; };
const handleSave = () => { const handleSave = () => {

View File

@@ -7,7 +7,7 @@
</template> </template>
<div class="w-full h-full"> <div class="w-full h-full">
<a-row> <a-row>
<a-col :span="12" v-for="nm in controlTemplates"> <a-col v-for="nm in controlTemplates" :span="12">
<div <div
:key="nm.id" :key="nm.id"
:data-type="nm.type" :data-type="nm.type"
@@ -15,7 +15,7 @@
@dragend="handleDragEnd" @dragend="handleDragEnd"
@dragstart="handleDragStart($event, nm)" @dragstart="handleDragStart($event, nm)"
> >
<img class="icon" src="@/assets/icons/model-4.svg" :alt="nm.name ?? ''" /> <img :alt="nm.name ?? ''" class="icon" src="@/assets/icons/model-4.svg" />
<span class="desc">{{ nm.name }}</span> <span class="desc">{{ nm.name }}</span>
</div> </div>
</a-col> </a-col>
@@ -28,7 +28,7 @@
</template> </template>
<div class="w-full h-full"> <div class="w-full h-full">
<a-row> <a-row>
<a-col :span="12" v-for="nm in conditionTemplates"> <a-col v-for="nm in conditionTemplates" :span="12">
<div <div
:key="nm.id" :key="nm.id"
:data-type="nm.type" :data-type="nm.type"
@@ -36,7 +36,7 @@
@dragend="handleDragEnd" @dragend="handleDragEnd"
@dragstart="handleDragStart($event, nm)" @dragstart="handleDragStart($event, nm)"
> >
<img class="icon" src="@/assets/icons/model-4.svg" :alt="nm.name ?? ''" /> <img :alt="nm.name ?? ''" class="icon" src="@/assets/icons/model-4.svg" />
<span class="desc">{{ nm.name }}</span> <span class="desc">{{ nm.name }}</span>
</div> </div>
</a-col> </a-col>
@@ -49,7 +49,7 @@
</template> </template>
<div class="w-full h-full"> <div class="w-full h-full">
<a-row> <a-row>
<a-col :span="12" v-for="nm in actionsTemplates"> <a-col v-for="nm in actionsTemplates" :span="12">
<div <div
:key="nm.id" :key="nm.id"
:data-type="nm.type" :data-type="nm.type"
@@ -57,7 +57,7 @@
@dragend="handleDragEnd" @dragend="handleDragEnd"
@dragstart="handleDragStart($event, nm)" @dragstart="handleDragStart($event, nm)"
> >
<img class="icon" src="@/assets/icons/model-4.svg" :alt="nm.name ?? ''" /> <img :alt="nm.name ?? ''" class="icon" src="@/assets/icons/model-4.svg" />
<span class="desc">{{ nm.name }}</span> <span class="desc">{{ nm.name }}</span>
</div> </div>
</a-col> </a-col>
@@ -161,6 +161,6 @@ export default defineComponent({
handleDragEnd, handleDragEnd,
}; };
}, },
}) });
</script> </script>

View File

@@ -7,7 +7,7 @@
<span class="ks-model-builder-title-icon icon-input"></span> <span class="ks-model-builder-title-icon icon-input"></span>
</template> </template>
<a-tab-pane key="1" tab="行为树属性" v-if="tree"> <a-tab-pane v-if="tree" key="1" tab="行为树属性">
<a-form <a-form
autocomplete="off" autocomplete="off"
layout="vertical" layout="vertical"
@@ -15,21 +15,21 @@
style="padding-bottom:15px;" style="padding-bottom:15px;"
> >
<a-form-item label="行为树名称"> <a-form-item label="行为树名称">
<a-input size="small" v-model:value="tree.name" placeholder="行为树名称" /> <a-input v-model:value="tree.name" placeholder="行为树名称" size="small" />
</a-form-item> </a-form-item>
<a-form-item label="行为树英文名称"> <a-form-item label="行为树英文名称">
<a-input size="small" v-model:value="tree.englishName" placeholder="行为树英文名称" /> <a-input v-model:value="tree.englishName" placeholder="行为树英文名称" size="small" />
</a-form-item> </a-form-item>
<a-form-item label="行为树说明"> <a-form-item label="行为树说明">
<a-textarea size="small" v-model:value="tree.description" placeholder="行为树说明" /> <a-textarea v-model:value="tree.description" placeholder="行为树说明" size="small" />
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-tab-pane> </a-tab-pane>
<a-tab-pane key="2" tab="节点属性" v-if="currentElement"> <a-tab-pane v-if="currentElement" key="2" tab="节点属性">
<a-form <a-form
autocomplete="off" autocomplete="off"
layout="vertical" layout="vertical"
@@ -37,28 +37,28 @@
style="padding-bottom:15px;" style="padding-bottom:15px;"
> >
<a-form-item label="节点名称"> <a-form-item label="节点名称">
<a-input size="small" v-model:value="currentElement.name" :placeholder="currentElement.name" /> <a-input v-model:value="currentElement.name" :placeholder="currentElement.name" size="small" />
</a-form-item> </a-form-item>
<a-form-item label="节点介绍"> <a-form-item label="节点介绍">
<a-textarea size="small" v-model:value="currentElement.description" :placeholder="currentElement.description" /> <a-textarea v-model:value="currentElement.description" :placeholder="currentElement.description" size="small" />
</a-form-item> </a-form-item>
<a-divider /> <a-divider />
<a-form-item label="输入"> <a-form-item label="输入">
<a-textarea size="small" v-model:value="currentElement.inputs" /> <a-textarea v-model:value="currentElement.inputs" size="small" />
</a-form-item> </a-form-item>
<a-form-item label="输出"> <a-form-item label="输出">
<a-textarea size="small" v-model:value="currentElement.outputs" /> <a-textarea v-model:value="currentElement.outputs" size="small" />
</a-form-item> </a-form-item>
<a-divider v-if="currentElement.settings && currentElement.parameters.length > 0" /> <a-divider v-if="currentElement.settings && currentElement.parameters.length > 0" />
<a-form-item :label="setting.description" v-for="setting in currentElement.parameters"> <a-form-item v-for="setting in currentElement.parameters" :label="setting.description">
<a-input-number size="small" style="width:100%;" v-if="setting.dataType === 'double'" v-model:value="setting.defaultValue" :placeholder="setting.description" /> <a-input-number v-if="setting.dataType === 'double'" v-model:value="setting.defaultValue" :placeholder="setting.description" size="small" style="width:100%;" />
<a-input v-else size="small" v-model:value="setting.defaultValue" :placeholder="setting.description" /> <a-input v-else v-model:value="setting.defaultValue" :placeholder="setting.description" size="small" />
</a-form-item> </a-form-item>
</a-form> </a-form>
</a-tab-pane> </a-tab-pane>
@@ -129,7 +129,7 @@
import { defineComponent, onMounted, type PropType, ref, watch } from 'vue'; import { defineComponent, onMounted, type PropType, ref, watch } from 'vue';
import { CheckOutlined } from '@ant-design/icons-vue'; import { CheckOutlined } from '@ant-design/icons-vue';
import type { ElementVariable, GraphTaskElement } from './builder/element'; import type { ElementVariable, GraphTaskElement } from './builder/element';
import type {BehaviorTree} from './types' import type { BehaviorTree } from './types';
import type { Graph, Node, NodeProperties } from '@antv/x6'; import type { Graph, Node, NodeProperties } from '@antv/x6';
import { generateKey } from '@/utils/strings'; import { generateKey } from '@/utils/strings';
@@ -145,9 +145,9 @@ export default defineComponent({
components: { CheckOutlined }, components: { CheckOutlined },
props: { props: {
tree: { type: [Object, null] as PropType<BehaviorTree | null | undefined>, required: false }, tree: { type: [Object, null] as PropType<BehaviorTree | null | undefined>, required: false },
treeEditing: { type: Boolean as PropType<boolean>, required: true, default: false, }, treeEditing: { type: Boolean as PropType<boolean>, required: true, default: false },
node: { type: [Object, null] as PropType<Node<NodeProperties> | null | undefined>, required: false }, node: { type: [Object, null] as PropType<Node<NodeProperties> | null | undefined>, required: false },
graph: { type: [Object, null] as PropType<Graph | null | undefined>, required: true } graph: { type: [Object, null] as PropType<Graph | null | undefined>, required: true },
}, },
emits: ['update-element', 'update-tree'], emits: ['update-element', 'update-tree'],
setup(props, { emit }) { setup(props, { emit }) {
@@ -187,8 +187,8 @@ export default defineComponent({
value: null, value: null,
defaults: null, defaults: null,
unit: null, unit: null,
}) });
} };
const removeVariable = (row: ElementVariable) => { const removeVariable = (row: ElementVariable) => {
if (currentElement.value && currentElement.value.variables) { if (currentElement.value && currentElement.value.variables) {

View File

@@ -10,11 +10,13 @@
</template> </template>
<div class="w-full" style="padding: 5px;"> <div class="w-full" style="padding: 5px;">
<a-flex> <a-flex>
<a-input-search size="small" allowClear v-model:value="behaviorTreeQuery.name" placeholder="行为树名称" @search="loadTress" /> <a-input-search v-model:value="behaviorTreeQuery.name" allowClear placeholder="行为树名称" size="small" @search="loadTress" />
<a-button size="small" style="margin-left: 10px;"><PlusOutlined style="margin-top: 0px;display: block;" @click="$emit('create-tree')"/></a-button> <a-button size="small" style="margin-left: 10px;">
<PlusOutlined style="margin-top: 0px;display: block;" @click="$emit('create-tree')" />
</a-button>
</a-flex> </a-flex>
</div> </div>
<a-list size="small" :data-source="behaviorTrees || []" style="min-height: 25vh"> <a-list :data-source="behaviorTrees || []" size="small" style="min-height: 25vh">
<template #renderItem="{ item }"> <template #renderItem="{ item }">
<a-list-item> <a-list-item>
<a-flex> <a-flex>
@@ -39,10 +41,10 @@
</template> </template>
</a-list> </a-list>
<a-pagination <a-pagination
size="small"
v-model:current="behaviorTreeQuery.pageNum" v-model:current="behaviorTreeQuery.pageNum"
:page-size="behaviorTreeQuery.pageSize" :page-size="behaviorTreeQuery.pageSize"
simple :total="totalTress" @change="handleChange" /> :total="totalTress"
simple size="small" @change="handleChange" />
</a-collapse-panel> </a-collapse-panel>
</a-collapse> </a-collapse>
</template> </template>
@@ -69,7 +71,7 @@ export default defineComponent({
pageNum: 1, pageNum: 1,
pageSize: 8, pageSize: 8,
}); });
const activeKey = ref<number>(1) const activeKey = ref<number>(1);
const totalTress = ref<number>(0); const totalTress = ref<number>(0);
const loadTress = () => { const loadTress = () => {
@@ -102,7 +104,7 @@ export default defineComponent({
const handleSelect = (record: BehaviorTree) => { const handleSelect = (record: BehaviorTree) => {
emit('select-tree', record); emit('select-tree', record);
} };
const customRow = (record: BehaviorTree) => { const customRow = (record: BehaviorTree) => {
return { return {
@@ -133,7 +135,7 @@ export default defineComponent({
handleDelete, handleDelete,
}; };
}, },
}) });
</script> </script>
@@ -176,6 +178,7 @@ export default defineComponent({
position: absolute; position: absolute;
bottom: 10px; bottom: 10px;
width: 100%; width: 100%;
.ant-pagination-disabled .ant-pagination-item-link, .ant-pagination-disabled .ant-pagination-item-link,
.ant-pagination-disabled:hover .ant-pagination-item-link, .ant-pagination-disabled:hover .ant-pagination-item-link,
.ant-pagination-prev .ant-pagination-item-link, .ant-pagination-prev .ant-pagination-item-link,
@@ -184,6 +187,7 @@ export default defineComponent({
&.ant-pagination-mini .ant-pagination-simple-pager { &.ant-pagination-mini .ant-pagination-simple-pager {
color: rgb(255 255 255 / 95%); color: rgb(255 255 255 / 95%);
} }
&.ant-pagination-simple .ant-pagination-simple-pager input { &.ant-pagination-simple .ant-pagination-simple-pager input {
background-color: transparent; background-color: transparent;
border: 1px solid #0f4a7c; border: 1px solid #0f4a7c;
@@ -192,9 +196,11 @@ export default defineComponent({
} }
} }
} }
.create-tree-icon { .create-tree-icon {
cursor: pointer; cursor: pointer;
} }
.ant-list-item { .ant-list-item {
padding: 3px 5px; padding: 3px 5px;
cursor: pointer; cursor: pointer;

View File

@@ -7,5 +7,5 @@
* that was distributed with this source code. * that was distributed with this source code.
*/ */
export * from './tree' export * from './tree';
export * from './template' export * from './template';

View File

@@ -15,8 +15,8 @@ export const createGraphTaskElementFromTemplate = (
template: NodeTemplate, template: NodeTemplate,
rect?: GraphTaskRect, rect?: GraphTaskRect,
): GraphTaskElement => { ): GraphTaskElement => {
let realRect = { width: 200, height: 100, x: 0, y: 0, ...rect || {} } let realRect = { width: 200, height: 100, x: 0, y: 0, ...rect || {} };
console.info('rect',rect) console.info('rect', rect);
return { return {
id: 0, id: 0,
key: generateKey(template.type), key: generateKey(template.type),