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,
parent?: DraggableElement,
children: DraggableElement[]
[key: string]: unknown;
}

View File

@@ -10,7 +10,7 @@
import { Edge, Graph, Path, Selection } from '@antv/x6';
import type { ModelElement } from './element';
import type { Connecting } from '@antv/x6/lib/graph/options';
import {createLineOptions} from './line'
import { createLineOptions } from './line';
Graph.registerConnector(
'sequenceFlowConnector',
@@ -55,7 +55,7 @@ export const createGraphConnectingAttributes = (): Partial<Connecting> => {
attrs: lineOptions.attrs,
animation: lineOptions.animation,
markup: lineOptions.markup,
})
});
return edge;
},
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 { EventListener } from '@/utils/event';
import type { ModelElement } from './element';
// import {createLineOptions} from './line'
export interface UseGraphCanvas {
@@ -163,7 +164,7 @@ export const useGraphCanvas = (readonly: boolean = false): UseGraphCanvas => {
router: {},
attrs: {},
target: targetNode.id,
targetName: targetData.name
targetName: targetData.name,
});
sourceNode.replaceData({ ...sourceData, edges: sourceEdges });
}

View File

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

View File

@@ -19,10 +19,10 @@
<div class="w-full">
<a-tooltip>
<template #title>
{{element?.description ?? element?.name}}
{{ element?.description ?? element?.name }}
</template>
<p>
{{ substring(element?.description ?? (element?.name ?? '-') ,40) }}
{{ substring(element?.description ?? (element?.name ?? '-'), 40) }}
</p>
</a-tooltip>
</div>
@@ -47,7 +47,7 @@ import { elementProps } from './props';
import type { ModelElement } from './element';
import { DeleteOutlined, SettingOutlined } from '@ant-design/icons-vue';
import type { Graph } from '@antv/x6';
import {substring} from '@/utils/strings'
import { substring } from '@/utils/strings';
export default defineComponent({
name: 'ModelElement',
@@ -133,7 +133,7 @@ export default defineComponent({
width: 100%;
height: 100%;
cursor: pointer;
position: relative;
position: relative;
.ant-card-head {
border: 0;
@@ -184,6 +184,7 @@ export default defineComponent({
background: url('@/assets/icons/m-02.png') center / 100% 100%;
}
}
&.ks-designer-input-node {
background: linear-gradient(150deg, #083058 1%, #1e5d9b 55%);

View File

@@ -48,12 +48,12 @@
</div>
<Properties
v-if="graph"
@update-element="handleUpdateElement"
:tree="currentBehaviorTree"
:tree-editing="currentTreeEditing"
:element="selectedNodeTaskElement"
:graph="graph as any"
:node="selectedModelNode as any" />
:node="selectedModelNode as any"
:tree="currentBehaviorTree"
:tree-editing="currentTreeEditing"
@update-element="handleUpdateElement" />
</div>
</a-layout>
</a-layout>
@@ -70,16 +70,16 @@ import { Wrapper } from '@/components/wrapper';
import { safePreventDefault, safeStopPropagation } from '@/utils/event';
import Header from './header.vue';
import Properties from './properties.vue';
import { useGraphCanvas } from './builder/hooks';
import { registerNodeElement } from './builder/register';
import type { BehaviorTree, NodeTemplate } from './types';
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 { createGraphTaskElement, hasElements, hasRootElementNode, resolveNodeGraph } from './builder/utils';
import { createGraphTaskElementFromTemplate } from './utils/node';
import TressCard from './trees-card.vue';
import NodesCard from './nodes-card.vue';
import { createLineOptions } from '@/views/decision/builder/line.ts';
const TeleportContainer = defineComponent(getTeleport());
@@ -241,12 +241,12 @@ export default defineComponent({
const createElements = () => {
nextTick(() => {
try{
try {
graph.value?.clearCells();
} catch (e: any){
console.error('clear cells error, cause:',e);
} catch (e: any) {
console.error('clear cells error, cause:', e);
}
setTimeout(()=> {
setTimeout(() => {
if (currentBehaviorTree.value?.graph && graph.value) {
if (currentBehaviorTree.value?.graph.nodes) {
currentBehaviorTree.value?.graph.nodes.forEach(ele => {
@@ -268,11 +268,11 @@ export default defineComponent({
}, 100); // 延迟一会儿,免得连线错位
}
}
}, 100)
}, 100);
});
};
const handleCreateTree = ()=> {
const handleCreateTree = () => {
currentBehaviorTree.value = {
id: 0,
name: '行为树',
@@ -285,16 +285,16 @@ export default defineComponent({
nodes: [],
},
updatedAt: null,
}
};
currentNodeGraph.value = {
edges: [],
nodes: [],
}
};
selectedModelNode.value = null;
selectedNodeTaskElement.value = null;
createElements();
}
};
// 初始化X6画布
const initGraph = () => {
@@ -362,7 +362,7 @@ export default defineComponent({
console.info('handleUpdateElement', element);
// 更新本地引用
selectedNodeTaskElement.value = element;
changed.value = true
changed.value = true;
};
const handleSave = () => {
@@ -377,11 +377,11 @@ export default defineComponent({
graph: graphData,
xmlContent: JSON.stringify(graphData),
};
if(! newTree.name){
if (!newTree.name) {
message.error('行为树名称不能为空.');
return;
}
if(! newTree.englishName){
if (!newTree.englishName) {
message.error('行为树英文名称不能为空.');
return;
}

View File

@@ -7,7 +7,7 @@
</template>
<div class="w-full h-full">
<a-row>
<a-col :span="12" v-for="nm in controlTemplates">
<a-col v-for="nm in controlTemplates" :span="12">
<div
:key="nm.id"
:data-type="nm.type"
@@ -15,7 +15,7 @@
@dragend="handleDragEnd"
@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>
</div>
</a-col>
@@ -28,7 +28,7 @@
</template>
<div class="w-full h-full">
<a-row>
<a-col :span="12" v-for="nm in conditionTemplates">
<a-col v-for="nm in conditionTemplates" :span="12">
<div
:key="nm.id"
:data-type="nm.type"
@@ -36,7 +36,7 @@
@dragend="handleDragEnd"
@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>
</div>
</a-col>
@@ -49,7 +49,7 @@
</template>
<div class="w-full h-full">
<a-row>
<a-col :span="12" v-for="nm in actionsTemplates">
<a-col v-for="nm in actionsTemplates" :span="12">
<div
:key="nm.id"
:data-type="nm.type"
@@ -57,7 +57,7 @@
@dragend="handleDragEnd"
@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>
</div>
</a-col>
@@ -161,6 +161,6 @@ export default defineComponent({
handleDragEnd,
};
},
})
});
</script>

View File

@@ -1,13 +1,13 @@
<template>
<div class="ks-model-builder-right">
<template v-if="currentElement || tree">
<template v-if="currentElement || tree">
<a-tabs v-model:activeKey="activeTopTabsKey" class="ks-model-builder-tabs settings-tab">
<template #leftExtra>
<span class="ks-model-builder-title-icon icon-input"></span>
</template>
<a-tab-pane key="1" tab="行为树属性" v-if="tree">
<a-tab-pane v-if="tree" key="1" tab="行为树属性">
<a-form
autocomplete="off"
layout="vertical"
@@ -15,21 +15,21 @@
style="padding-bottom:15px;"
>
<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 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 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>
</a-tab-pane>
<a-tab-pane key="2" tab="节点属性" v-if="currentElement">
<a-tab-pane v-if="currentElement" key="2" tab="节点属性">
<a-form
autocomplete="off"
layout="vertical"
@@ -37,35 +37,35 @@
style="padding-bottom:15px;"
>
<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 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-divider />
<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 label="输出">
<a-textarea size="small" v-model:value="currentElement.outputs" />
<a-textarea v-model:value="currentElement.outputs" size="small" />
</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-input-number size="small" style="width:100%;" v-if="setting.dataType === 'double'" v-model:value="setting.defaultValue" :placeholder="setting.description" />
<a-input v-else size="small" v-model:value="setting.defaultValue" :placeholder="setting.description" />
<a-form-item v-for="setting in currentElement.parameters" :label="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 v-model:value="setting.defaultValue" :placeholder="setting.description" size="small" />
</a-form-item>
</a-form>
</a-tab-pane>
</a-tabs>
<a-tabs v-if="currentElement" v-model:activeKey="activeBottomTabsKey" class="ks-model-builder-tabs parameters-tabs">
<a-tabs v-if="currentElement" v-model:activeKey="activeBottomTabsKey" class="ks-model-builder-tabs parameters-tabs">
<template #leftExtra>
<span class="ks-model-builder-title-icon icon-input"></span>
</template>
@@ -100,7 +100,7 @@
</a-button>
</template>
<template v-else>
<a-input v-model:value="record[column.dataIndex]" size="small"/>
<a-input v-model:value="record[column.dataIndex]" size="small" />
</template>
</template>
</a-table>
@@ -129,7 +129,7 @@
import { defineComponent, onMounted, type PropType, ref, watch } from 'vue';
import { CheckOutlined } from '@ant-design/icons-vue';
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 { generateKey } from '@/utils/strings';
@@ -145,9 +145,9 @@ export default defineComponent({
components: { CheckOutlined },
props: {
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 },
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'],
setup(props, { emit }) {
@@ -155,7 +155,7 @@ export default defineComponent({
const activeBottomTabsKey = ref<string>('1');
const activeBottomTabs2Key = ref<string>('1');
const currentTree = ref<BehaviorTree| null>(props.tree ?? null);
const currentTree = ref<BehaviorTree | null>(props.tree ?? null);
const treeEditing = ref<boolean>(props.treeEditing);
const currentNode = ref<Node | null>(props.node ?? null);
const currentElement = ref<GraphTaskElement | null>(null);
@@ -173,7 +173,7 @@ export default defineComponent({
}
};
const addVariable = ()=> {
const addVariable = () => {
if (!currentElement.value) {
return;
}
@@ -187,8 +187,8 @@ export default defineComponent({
value: null,
defaults: null,
unit: null,
})
}
});
};
const removeVariable = (row: ElementVariable) => {
if (currentElement.value && currentElement.value.variables) {

View File

@@ -5,28 +5,30 @@
<a-flex>
<span class="ks-model-builder-title-icon icon-model"></span>
<span style="color: #82c4e9;font-size: 16px;">我的行为树</span>
<!-- <span style="position: absolute; right: 15px;"><PlusOutlined @click="$emit('create-tree')"/></span>-->
<!-- <span style="position: absolute; right: 15px;"><PlusOutlined @click="$emit('create-tree')"/></span>-->
</a-flex>
</template>
<div class="w-full" style="padding: 5px;">
<a-flex>
<a-input-search size="small" allowClear v-model:value="behaviorTreeQuery.name" placeholder="行为树名称" @search="loadTress" />
<a-button size="small" style="margin-left: 10px;"><PlusOutlined style="margin-top: 0px;display: block;" @click="$emit('create-tree')"/></a-button>
<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-flex>
</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 }">
<a-list-item>
<a-flex>
<a-tooltip placement="right">
<template #title>
<p>名称: {{ item.name }}</p>
<p>说明: {{item.description}}</p>
<p>说明: {{ item.description }}</p>
</template>
<span>{{ substring(item.name, 15) }}</span>
</a-tooltip>
<a-flex class="ks-tree-actions">
<span style="margin-right: 10px" @click="()=> handleSelect(item)"><EditFilled /></span>
<span style="margin-right: 10px" @click="()=> handleSelect(item)"><EditFilled /></span>
<a-popconfirm
title="确定删除?"
@confirm="()=> handleDelete(item)"
@@ -39,10 +41,10 @@
</template>
</a-list>
<a-pagination
size="small"
v-model:current="behaviorTreeQuery.pageNum"
:page-size="behaviorTreeQuery.pageSize"
simple :total="totalTress" @change="handleChange" />
:total="totalTress"
simple size="small" @change="handleChange" />
</a-collapse-panel>
</a-collapse>
</template>
@@ -55,7 +57,7 @@ import { deleteOneTreeById, findTreesByQuery } from './api';
import { substring } from '@/utils/strings';
export default defineComponent({
emits: ['select-tree','create-tree'],
emits: ['select-tree', 'create-tree'],
components: {
CheckOutlined,
PlusOutlined,
@@ -69,7 +71,7 @@ export default defineComponent({
pageNum: 1,
pageSize: 8,
});
const activeKey = ref<number>(1)
const activeKey = ref<number>(1);
const totalTress = ref<number>(0);
const loadTress = () => {
@@ -102,7 +104,7 @@ export default defineComponent({
const handleSelect = (record: BehaviorTree) => {
emit('select-tree', record);
}
};
const customRow = (record: BehaviorTree) => {
return {
@@ -112,7 +114,7 @@ export default defineComponent({
};
};
const refresh = ()=> loadTress();
const refresh = () => loadTress();
onMounted(() => {
loadTress();
@@ -133,7 +135,7 @@ export default defineComponent({
handleDelete,
};
},
})
});
</script>
@@ -172,29 +174,33 @@ export default defineComponent({
position: relative;
}
.ant-pagination{
.ant-pagination {
position: absolute;
bottom: 10px;
width: 100%;
.ant-pagination-disabled .ant-pagination-item-link,
.ant-pagination-disabled:hover .ant-pagination-item-link,
.ant-pagination-prev .ant-pagination-item-link,
.ant-pagination-next .ant-pagination-item-link,
&.ant-pagination-mini .ant-pagination-total-text,
&.ant-pagination-mini .ant-pagination-simple-pager{
&.ant-pagination-mini .ant-pagination-simple-pager {
color: rgb(255 255 255 / 95%);
}
&.ant-pagination-simple .ant-pagination-simple-pager input {
background-color: transparent;
border: 1px solid #0f4a7c;
color:#eee;
color: #eee;
}
}
}
}
.create-tree-icon{
.create-tree-icon {
cursor: pointer;
}
.ant-list-item {
padding: 3px 5px;
cursor: pointer;

View File

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

View File

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