Files
auto-solution/modeler/src/views/decision/designer/properties.vue

271 lines
9.7 KiB
Vue
Raw Normal View History

2026-02-08 15:59:14 +08:00
<template>
<div class="ks-model-builder-right">
2026-02-08 22:31:13 +08:00
<template v-if="currentElement || tree">
2026-02-08 15:59:14 +08:00
<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>
2026-02-08 22:09:28 +08:00
2026-02-08 22:31:13 +08:00
<a-tab-pane v-if="tree" key="1" tab="行为树属性">
2026-02-08 22:09:28 +08:00
<a-form
autocomplete="off"
layout="vertical"
name="basic"
style="padding-bottom:15px;"
>
<a-form-item label="行为树名称">
2026-02-08 22:31:13 +08:00
<a-input v-model:value="tree.name" placeholder="行为树名称" size="small" />
2026-02-08 22:09:28 +08:00
</a-form-item>
2026-02-08 22:28:52 +08:00
<a-form-item label="行为树英文名称">
2026-02-08 22:31:13 +08:00
<a-input v-model:value="tree.englishName" placeholder="行为树英文名称" size="small" />
2026-02-08 22:28:52 +08:00
</a-form-item>
2026-02-08 22:09:28 +08:00
<a-form-item label="行为树说明">
2026-02-08 22:31:13 +08:00
<a-textarea v-model:value="tree.description" placeholder="行为树说明" size="small" />
2026-02-08 22:09:28 +08:00
</a-form-item>
</a-form>
</a-tab-pane>
2026-02-08 22:31:13 +08:00
<a-tab-pane v-if="currentElement" key="2" tab="节点属性">
2026-02-08 15:59:14 +08:00
<a-form
autocomplete="off"
layout="vertical"
name="basic"
style="padding-bottom:15px;"
>
<a-form-item label="节点名称">
2026-02-08 22:31:13 +08:00
<a-input v-model:value="currentElement.name" :placeholder="currentElement.name" size="small" />
2026-02-08 15:59:14 +08:00
</a-form-item>
<a-form-item label="节点介绍">
2026-02-08 22:31:13 +08:00
<a-textarea v-model:value="currentElement.description" :placeholder="currentElement.description" size="small" />
2026-02-08 15:59:14 +08:00
</a-form-item>
2026-03-13 10:40:44 +08:00
<a-form-item label="排序">
<a-input-number style="width:100%;" v-model:value="currentElement.order" size="small" />
</a-form-item>
2026-02-08 15:59:14 +08:00
<a-divider />
<a-form-item label="输入">
2026-02-08 22:31:13 +08:00
<a-textarea v-model:value="currentElement.inputs" size="small" />
2026-02-08 15:59:14 +08:00
</a-form-item>
<a-form-item label="输出">
2026-02-08 22:31:13 +08:00
<a-textarea v-model:value="currentElement.outputs" size="small" />
2026-02-08 15:59:14 +08:00
</a-form-item>
2026-03-13 10:40:44 +08:00
<!-- <a-divider v-if="currentElement.settings && currentElement.parameters.length > 0" />-->
2026-02-08 15:59:14 +08:00
2026-03-13 10:40:44 +08:00
<!-- <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>-->
2026-02-08 15:59:14 +08:00
</a-form>
</a-tab-pane>
</a-tabs>
2026-02-08 22:31:13 +08:00
<a-tabs v-if="currentElement" v-model:activeKey="activeBottomTabsKey" class="ks-model-builder-tabs parameters-tabs">
2026-02-08 15:59:14 +08:00
<template #leftExtra>
<span class="ks-model-builder-title-icon icon-input"></span>
</template>
<a-tab-pane key="1" tab="节点变量">
2026-03-13 10:40:44 +08:00
<a-form
v-if="currentElement.parameters && currentElement.parameters.length > 0"
autocomplete="off"
layout="vertical"
name="basic"
style="padding-bottom:15px;"
>
<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-empty v-else>
</a-empty>
<!-- <div class="w-full">-->
<!-- <a-space>-->
<!-- <a-button size="small" type="primary" @click="addVariable">添加</a-button>-->
<!-- </a-space>-->
<!-- <a-table-->
<!-- :columns="actionSpaceColumns"-->
<!-- :dataSource="currentElement.variables"-->
<!-- :pagination="false"-->
<!-- :scroll="{ x: 500 }"-->
<!-- class="mt-1"-->
<!-- row-key="key"-->
<!-- size="small"-->
<!-- style="overflow-y:auto;height:35vh;"-->
<!-- >-->
<!-- <template #bodyCell="{column, record, index}">-->
<!-- <template v-if="column.dataIndex === 'index'">-->
<!-- {{ index + 1 }}-->
<!-- </template>-->
<!-- <template v-else-if="column.dataIndex === '_actions'">-->
<!-- <a-button-->
<!-- class="btn-link-delete"-->
<!-- danger-->
<!-- size="small"-->
<!-- type="text"-->
<!-- @click="()=> removeVariable(record)"-->
<!-- >-->
<!-- 删除-->
<!-- </a-button>-->
<!-- </template>-->
<!-- <template v-else>-->
<!-- <a-input v-model:value="record[column.dataIndex]" size="small" />-->
<!-- </template>-->
<!-- </template>-->
<!-- </a-table>-->
<!-- </div>-->
2026-02-08 15:59:14 +08:00
</a-tab-pane>
</a-tabs>
</template>
<a-tabs v-else :activeKey="'0'" class="ks-model-builder-tabs parameters-tabs empty">
<template #leftExtra>
<span class="ks-model-builder-title-icon icon-input"></span>
</template>
<a-tab-pane :key="'0'" tab="请选择或者创建决策树">
<a-empty>
<template #description>
请选择或者创建决策树
</template>
</a-empty>
</a-tab-pane>
</a-tabs>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, type PropType, ref, watch } from 'vue';
import { CheckOutlined } from '@ant-design/icons-vue';
2026-03-14 21:37:07 +08:00
import type { ElementVariable, GraphTaskElement } from '../builder/element';
import type { BehaviorTree } from '../types';
2026-02-08 15:59:14 +08:00
import type { Graph, Node, NodeProperties } from '@antv/x6';
2026-02-08 20:27:40 +08:00
import { generateKey } from '@/utils/strings';
2026-02-08 15:59:14 +08:00
const actionSpaceColumns = [
{ title: '序号', dataIndex: 'index', key: 'index', width: 40 },
{ title: '变量名', dataIndex: 'name', key: 'name', width: 80 },
{ title: '参数值', dataIndex: 'value', key: 'value', width: 80 },
{ title: '单位', dataIndex: 'unit', key: 'unit', width: 80 },
{ title: '操作', dataIndex: '_actions', key: '_actions', width: 60 },
];
export default defineComponent({
components: { CheckOutlined },
props: {
2026-02-08 22:09:28 +08:00
tree: { type: [Object, null] as PropType<BehaviorTree | null | undefined>, required: false },
2026-02-08 22:31:13 +08:00
treeEditing: { type: Boolean as PropType<boolean>, required: true, default: false },
2026-02-08 15:59:14 +08:00
node: { type: [Object, null] as PropType<Node<NodeProperties> | null | undefined>, required: false },
2026-02-08 22:31:13 +08:00
graph: { type: [Object, null] as PropType<Graph | null | undefined>, required: true },
2026-02-08 15:59:14 +08:00
},
2026-02-08 22:09:28 +08:00
emits: ['update-element', 'update-tree'],
2026-02-08 15:59:14 +08:00
setup(props, { emit }) {
const activeTopTabsKey = ref<string>('1');
const activeBottomTabsKey = ref<string>('1');
const activeBottomTabs2Key = ref<string>('1');
2026-02-08 22:31:13 +08:00
const currentTree = ref<BehaviorTree | null>(props.tree ?? null);
2026-02-08 22:09:28 +08:00
const treeEditing = ref<boolean>(props.treeEditing);
2026-02-08 15:59:14 +08:00
const currentNode = ref<Node | null>(props.node ?? null);
2026-02-08 20:27:40 +08:00
const currentElement = ref<GraphTaskElement | null>(null);
2026-02-08 15:59:14 +08:00
const load = () => {
};
const resolveNode = (n?: Node | null | undefined) => {
currentNode.value = n ?? null;
if (n) {
const data = n.getData();
2026-02-08 20:27:40 +08:00
currentElement.value = JSON.parse(JSON.stringify(data || {})) as GraphTaskElement;
2026-02-08 15:59:14 +08:00
} else {
currentElement.value = null;
}
};
2026-02-08 22:31:13 +08:00
const addVariable = () => {
2026-02-08 15:59:14 +08:00
if (!currentElement.value) {
return;
}
if (!currentElement.value.variables) {
currentElement.value.variables = [];
}
currentElement.value?.variables.push({
key: generateKey('variable'),
name: null,
value: null,
defaults: null,
unit: null,
2026-02-08 22:31:13 +08:00
});
};
2026-02-08 15:59:14 +08:00
const removeVariable = (row: ElementVariable) => {
if (currentElement.value && currentElement.value.variables) {
const filteredVars = currentElement.value.variables.filter(v => v.key !== row.key);
currentElement.value.variables = [...filteredVars];
}
};
const updateNode = () => {
if (currentNode.value && currentElement.value) {
// 深拷贝当前元素数据
2026-02-08 20:27:40 +08:00
const newElement = JSON.parse(JSON.stringify(currentElement.value)) as GraphTaskElement;
2026-02-08 15:59:14 +08:00
// 更新节点数据
currentNode.value.replaceData(newElement);
// 触发事件通知父组件
emit('update-element', newElement);
}
};
watch(
() => props.node,
(n?: Node | null | undefined) => resolveNode(n),
{ deep: true, immediate: true },
);
2026-02-08 22:09:28 +08:00
watch(
() => props.tree,
(n?: BehaviorTree | null | undefined) => {
currentTree.value = n ?? null;
},
{ deep: true, immediate: true },
);
watch(
() => props.treeEditing,
(n?: boolean | null | undefined) => {
treeEditing.value = n === true;
},
{ deep: true, immediate: true },
);
2026-02-08 15:59:14 +08:00
watch(() => currentElement.value, () => updateNode(), { deep: true });
onMounted(() => load());
return {
actionSpaceColumns,
activeTopTabsKey,
activeBottomTabsKey,
activeBottomTabs2Key,
currentElement,
addVariable,
removeVariable,
2026-02-08 22:09:28 +08:00
currentTree,
treeEditing,
2026-02-08 15:59:14 +08:00
// currentElementParameters,
};
},
});
</script>