添加行为树页面的场景选择
This commit is contained in:
@@ -853,6 +853,7 @@
|
|||||||
.ks-model-builder-content,
|
.ks-model-builder-content,
|
||||||
.ks-model-builder-right {
|
.ks-model-builder-right {
|
||||||
height: calc(100vh - 90px);
|
height: calc(100vh - 90px);
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
.ant-card-body {
|
.ant-card-body {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
@@ -987,6 +988,7 @@
|
|||||||
|
|
||||||
.ant-collapse-content-box {
|
.ant-collapse-content-box {
|
||||||
max-height: 37vh;
|
max-height: 37vh;
|
||||||
|
height: fit-content;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1555,6 +1557,44 @@
|
|||||||
border: 1px solid #0f4a7c;
|
border: 1px solid #0f4a7c;
|
||||||
color: #eee;
|
color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 修复 mini 模式分页滚动条问题
|
||||||
|
&.ant-pagination-mini {
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
|
||||||
|
.ant-pagination-simple-pager {
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
|
||||||
|
input {
|
||||||
|
height: 22px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 0 4px;
|
||||||
|
margin: 0 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-pagination-total-text {
|
||||||
|
height: 24px;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-pagination-prev,
|
||||||
|
.ant-pagination-next,
|
||||||
|
.ant-pagination-jump-prev,
|
||||||
|
.ant-pagination-jump-next {
|
||||||
|
height: 24px;
|
||||||
|
line-height: 22px;
|
||||||
|
|
||||||
|
.ant-pagination-item-link {
|
||||||
|
height: 22px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,13 @@
|
|||||||
<a-layout class="ks-layout-body">
|
<a-layout class="ks-layout-body">
|
||||||
<div class="ks-model-builder-body">
|
<div class="ks-model-builder-body">
|
||||||
<div class="ks-model-builder-left">
|
<div class="ks-model-builder-left">
|
||||||
|
<ScenariosCard
|
||||||
|
ref="scenariosCardRef"
|
||||||
|
@select-scenario="handleSelectScenario"
|
||||||
|
/>
|
||||||
<TressCard
|
<TressCard
|
||||||
ref="treesCardRef"
|
ref="treesCardRef"
|
||||||
|
:scenarioId="currentScenarioId"
|
||||||
@create-tree="handleCreateTree"
|
@create-tree="handleCreateTree"
|
||||||
@select-tree="handleSelectTree"
|
@select-tree="handleSelectTree"
|
||||||
/>
|
/>
|
||||||
@@ -78,6 +83,7 @@ import { findAllBasicPlatforms, findAllNodeCommands } from '../api';
|
|||||||
import type { NodeCommand, Platform } from '../types';
|
import type { NodeCommand, Platform } from '../types';
|
||||||
import { createTree, findOneTreeById, findOneTreeByPlatformId, updateTree, findSubPlatforms } from './api';
|
import { createTree, findOneTreeById, findOneTreeByPlatformId, updateTree, findSubPlatforms } from './api';
|
||||||
import TressCard from './trees-card.vue';
|
import TressCard from './trees-card.vue';
|
||||||
|
import ScenariosCard from './scenarios-card.vue';
|
||||||
import NodesCard from './nodes-card.vue';
|
import NodesCard from './nodes-card.vue';
|
||||||
|
|
||||||
const TeleportContainer = defineComponent(getTeleport());
|
const TeleportContainer = defineComponent(getTeleport());
|
||||||
@@ -86,6 +92,7 @@ registerNodeElement();
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
ScenariosCard,
|
||||||
TressCard,
|
TressCard,
|
||||||
NodesCard,
|
NodesCard,
|
||||||
Wrapper,
|
Wrapper,
|
||||||
@@ -111,11 +118,12 @@ export default defineComponent({
|
|||||||
const selectedModelNode = ref<Node<NodeProperties> | null>(null);
|
const selectedModelNode = ref<Node<NodeProperties> | null>(null);
|
||||||
const selectedNodeTaskElement = ref<GraphTaskElement | null>(null);
|
const selectedNodeTaskElement = ref<GraphTaskElement | null>(null);
|
||||||
const changed = ref<boolean>(false);
|
const changed = ref<boolean>(false);
|
||||||
|
const scenariosCardRef = ref<InstanceType<typeof ScenariosCard> | null>(null);
|
||||||
const treesCardRef = ref<InstanceType<typeof TressCard> | null>(null);
|
const treesCardRef = ref<InstanceType<typeof TressCard> | null>(null);
|
||||||
const platforms = ref<Platform[]>([]);
|
const platforms = ref<Platform[]>([]);
|
||||||
const subPlatforms = ref<Platform[]>([]);
|
const subPlatforms = ref<Platform[]>([]);
|
||||||
const nodeCommands = ref<NodeCommand[]>([])
|
const nodeCommands = ref<NodeCommand[]>([])
|
||||||
const currentScenarioId = ref<number | null>(null);
|
const currentScenarioId = ref<number | undefined>();
|
||||||
const currentPlatformId = ref<number | null>(null);
|
const currentPlatformId = ref<number | null>(null);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -262,7 +270,7 @@ export default defineComponent({
|
|||||||
const handleSelectTree = (tree: BehaviorTree) => {
|
const handleSelectTree = (tree: BehaviorTree) => {
|
||||||
destroyGraph();
|
destroyGraph();
|
||||||
currentPlatformId.value = null;
|
currentPlatformId.value = null;
|
||||||
currentScenarioId.value = null;
|
// currentScenarioId.value = undefined;
|
||||||
|
|
||||||
console.info('handleSelectTree', tree);
|
console.info('handleSelectTree', tree);
|
||||||
findOneTreeById(tree.id).then(r => {
|
findOneTreeById(tree.id).then(r => {
|
||||||
@@ -327,11 +335,13 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const resolveQuery = ()=> {
|
const resolveQuery = ()=> {
|
||||||
|
console.log(currentRoute);
|
||||||
|
|
||||||
let scenarioId = Number(currentRoute.query.scenario);
|
let scenarioId = Number(currentRoute.query.scenario);
|
||||||
if (!isNaN(scenarioId)) {
|
if (!isNaN(scenarioId)) {
|
||||||
currentScenarioId.value = scenarioId;
|
currentScenarioId.value = scenarioId;
|
||||||
} else {
|
} else {
|
||||||
currentScenarioId.value = null;
|
currentScenarioId.value = undefined;
|
||||||
}
|
}
|
||||||
let platformId = Number(currentRoute.query.platform);
|
let platformId = Number(currentRoute.query.platform);
|
||||||
if (!isNaN(platformId)) {
|
if (!isNaN(platformId)) {
|
||||||
@@ -341,6 +351,11 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 处理选择场景
|
||||||
|
const handleSelectScenario = (scenario: any) => {
|
||||||
|
currentScenarioId.value = scenario.id;
|
||||||
|
};
|
||||||
|
|
||||||
const handleCreateTree = () => {
|
const handleCreateTree = () => {
|
||||||
destroyGraph();
|
destroyGraph();
|
||||||
|
|
||||||
@@ -423,15 +438,19 @@ export default defineComponent({
|
|||||||
|
|
||||||
const init = () => {
|
const init = () => {
|
||||||
console.info('init');
|
console.info('init');
|
||||||
|
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
initGraph();
|
initGraph();
|
||||||
window.addEventListener('resize', handleResize);
|
window.addEventListener('resize', handleResize);
|
||||||
console.log('节点挂载完成');
|
console.log('节点挂载完成');
|
||||||
|
|
||||||
resolveQuery();
|
resolveQuery();
|
||||||
|
|
||||||
if (currentPlatformId.value) {
|
if (currentPlatformId.value) {
|
||||||
findOneTreeByPlatformId(currentPlatformId.value).then(r => {
|
findOneTreeByPlatformId(currentPlatformId.value).then(r => {
|
||||||
|
console.log(r);
|
||||||
|
|
||||||
if (r.data) {
|
if (r.data) {
|
||||||
handleSelectTree(r.data);
|
handleSelectTree(r.data);
|
||||||
} else {
|
} else {
|
||||||
@@ -511,8 +530,10 @@ export default defineComponent({
|
|||||||
currentScenarioId,
|
currentScenarioId,
|
||||||
platforms,
|
platforms,
|
||||||
subPlatforms,
|
subPlatforms,
|
||||||
|
scenariosCardRef,
|
||||||
treesCardRef,
|
treesCardRef,
|
||||||
handleCreateTree,
|
handleCreateTree,
|
||||||
|
handleSelectScenario,
|
||||||
currentTreeEditing,
|
currentTreeEditing,
|
||||||
currentBehaviorTree,
|
currentBehaviorTree,
|
||||||
currentGraph,
|
currentGraph,
|
||||||
|
|||||||
179
modeler/src/views/decision/designer/scenarios-card.vue
Normal file
179
modeler/src/views/decision/designer/scenarios-card.vue
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
<template>
|
||||||
|
<a-collapse v-model:activeKey="activeKey" :accordion="false" class="ks-trees-collapse">
|
||||||
|
<a-collapse-panel key="1" style="position: relative">
|
||||||
|
<template #header>
|
||||||
|
<a-flex>
|
||||||
|
<span class="ks-model-builder-title-icon icon-model"></span>
|
||||||
|
<span style="color: #82c4e9;font-size: 16px;">我的场景</span>
|
||||||
|
</a-flex>
|
||||||
|
</template>
|
||||||
|
<div class="w-full" style="padding: 5px;">
|
||||||
|
<a-flex>
|
||||||
|
<a-input-search v-model:value="scenarioQuery.name" allowClear placeholder="场景名称" size="small" @search="loadScenarios()" />
|
||||||
|
</a-flex>
|
||||||
|
</div>
|
||||||
|
<a-list :data-source="scenarios || []" size="small" style="min-height: 25vh">
|
||||||
|
<template #renderItem="{ item }">
|
||||||
|
<a-list-item @click="()=> handleSelect(item)">
|
||||||
|
<a-flex>
|
||||||
|
<a-tooltip placement="bottom">
|
||||||
|
<template #title>
|
||||||
|
<p>名称: {{ item.name }}</p>
|
||||||
|
<p>说明: {{ item.description }}</p>
|
||||||
|
</template>
|
||||||
|
<span>{{ substring(item.name, 15) }}</span>
|
||||||
|
</a-tooltip>
|
||||||
|
<a-flex class="ks-tree-actions">
|
||||||
|
<a-popconfirm
|
||||||
|
title="确定复制?"
|
||||||
|
@confirm="()=> handleCopy(item)"
|
||||||
|
>
|
||||||
|
<span class="ks-tree-action ks-tree-action-copy" @click.stop style="margin-right: 10px"><CopyOutlined /></span>
|
||||||
|
</a-popconfirm>
|
||||||
|
<a-popconfirm
|
||||||
|
title="确定删除?"
|
||||||
|
@confirm="()=> handleDelete(item)"
|
||||||
|
>
|
||||||
|
<span class="ks-tree-action ks-tree-action-delete" @click.stop><DeleteOutlined /></span>
|
||||||
|
</a-popconfirm>
|
||||||
|
</a-flex>
|
||||||
|
</a-flex>
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
<a-pagination
|
||||||
|
v-model:current="scenarioQuery.pageNum"
|
||||||
|
:page-size="scenarioQuery.pageSize"
|
||||||
|
:total="totalScenarios"
|
||||||
|
style="position: unset; margin: 5px 0;"
|
||||||
|
simple size="small" @change="handleChange" />
|
||||||
|
</a-collapse-panel>
|
||||||
|
</a-collapse>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, onMounted, ref } from 'vue';
|
||||||
|
import { CopyOutlined, DeleteOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||||||
|
import type { Scenario, ScenarioRequest } from '../communication/types';
|
||||||
|
import { findScenarioByQuery } from '../communication/api';
|
||||||
|
import { substring } from '@/utils/strings';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
emits: ['select-scenario'],
|
||||||
|
components: {
|
||||||
|
CopyOutlined,
|
||||||
|
PlusOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
},
|
||||||
|
setup(_props, { emit }) {
|
||||||
|
const scenarios = ref<Scenario[]>([]);
|
||||||
|
const scenarioQuery = ref<Partial<ScenarioRequest>>({
|
||||||
|
name: null,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: 8,
|
||||||
|
});
|
||||||
|
const activeKey = ref<number>(1);
|
||||||
|
const totalScenarios = ref<number>(0);
|
||||||
|
|
||||||
|
const loadScenarios = (cb?: () => void) => {
|
||||||
|
findScenarioByQuery(scenarioQuery.value).then(r => {
|
||||||
|
scenarios.value = r.rows;
|
||||||
|
totalScenarios.value = r.total ?? 0;
|
||||||
|
if(cb) cb();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (page: number, pageSize: number) => {
|
||||||
|
scenarioQuery.value.pageNum = page;
|
||||||
|
scenarioQuery.value.pageSize = pageSize;
|
||||||
|
loadScenarios();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDelete = (item: Scenario) => {
|
||||||
|
// TODO: 实现删除场景的API调用
|
||||||
|
console.log('删除场景:', item);
|
||||||
|
loadScenarios();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCopy = (item: Scenario) => {
|
||||||
|
// TODO: 实现复制场景的API调用
|
||||||
|
console.log('复制场景:', item);
|
||||||
|
loadScenarios();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSelect = (record: Scenario) => {
|
||||||
|
emit('select-scenario', record);
|
||||||
|
};
|
||||||
|
|
||||||
|
const refresh = () => loadScenarios();
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadScenarios(() => {
|
||||||
|
if(scenarios.value.length > 0){
|
||||||
|
emit('select-scenario', scenarios.value[0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
refresh,
|
||||||
|
totalScenarios,
|
||||||
|
substring,
|
||||||
|
activeKey,
|
||||||
|
scenarios,
|
||||||
|
scenarioQuery,
|
||||||
|
loadScenarios,
|
||||||
|
handleSelect,
|
||||||
|
handleChange,
|
||||||
|
handleDelete,
|
||||||
|
handleCopy,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ks-tree-actions {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-tree-action {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 2px 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-tree-action:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-tree-action-copy {
|
||||||
|
color: #1890ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ks-tree-action-delete {
|
||||||
|
color: #ff4d4f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.a-list-item {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 8px 12px;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.a-list-item:hover {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.a-list-item:hover .ks-tree-actions {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-scenario::before {
|
||||||
|
content: '\e6b8';
|
||||||
|
font-family: 'iconfont';
|
||||||
|
margin-right: 8px;
|
||||||
|
color: #82c4e9;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -25,6 +25,7 @@ export interface BehaviorTree {
|
|||||||
export interface BehaviorTreeRequest extends BehaviorTree {
|
export interface BehaviorTreeRequest extends BehaviorTree {
|
||||||
pageNum: number,
|
pageNum: number,
|
||||||
pageSize: number,
|
pageSize: number,
|
||||||
|
scenarioId?: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -50,19 +50,24 @@
|
|||||||
v-model:current="behaviorTreeQuery.pageNum"
|
v-model:current="behaviorTreeQuery.pageNum"
|
||||||
:page-size="behaviorTreeQuery.pageSize"
|
:page-size="behaviorTreeQuery.pageSize"
|
||||||
:total="totalTress"
|
:total="totalTress"
|
||||||
|
style="position: unset; margin: 5px 0;"
|
||||||
simple size="small" @change="handleChange" />
|
simple size="small" @change="handleChange" />
|
||||||
</a-collapse-panel>
|
</a-collapse-panel>
|
||||||
</a-collapse>
|
</a-collapse>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, onMounted, ref } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
|
import { defineComponent, ref, watch } from 'vue';
|
||||||
import { CheckOutlined, CopyOutlined, DeleteOutlined, EditFilled, PlusOutlined } from '@ant-design/icons-vue';
|
import { CheckOutlined, CopyOutlined, DeleteOutlined, EditFilled, PlusOutlined } from '@ant-design/icons-vue';
|
||||||
import type { BehaviorTree, BehaviorTreeRequest } from './tree';
|
import type { BehaviorTree, BehaviorTreeRequest } from './tree';
|
||||||
import { copyTree, deleteOneTreeById, findTreesByQuery } from './api';
|
import { copyTree, deleteOneTreeById, findTreesByQuery } from './api';
|
||||||
import { substring } from '@/utils/strings';
|
import { substring } from '@/utils/strings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
scenarioId:Number as PropType<number>,
|
||||||
|
},
|
||||||
emits: ['select-tree', 'create-tree'],
|
emits: ['select-tree', 'create-tree'],
|
||||||
components: {
|
components: {
|
||||||
CheckOutlined,
|
CheckOutlined,
|
||||||
@@ -77,11 +82,27 @@ export default defineComponent({
|
|||||||
name: null,
|
name: null,
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
pageSize: 8,
|
pageSize: 8,
|
||||||
|
scenarioId: _props.scenarioId,
|
||||||
});
|
});
|
||||||
const activeKey = ref<number>(1);
|
const activeKey = ref<number>(1);
|
||||||
const totalTress = ref<number>(0);
|
const totalTress = ref<number>(0);
|
||||||
|
|
||||||
const loadTress = () => {
|
watch(
|
||||||
|
() => _props.scenarioId,
|
||||||
|
() => {
|
||||||
|
if (!_props.scenarioId) {
|
||||||
|
behaviorTrees.value = [];
|
||||||
|
totalTress.value = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
behaviorTreeQuery.value.pageNum = 1;
|
||||||
|
behaviorTreeQuery.value.scenarioId = _props.scenarioId;
|
||||||
|
loadTress();
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
function loadTress(){
|
||||||
findTreesByQuery(behaviorTreeQuery.value).then(r => {
|
findTreesByQuery(behaviorTreeQuery.value).then(r => {
|
||||||
behaviorTrees.value = r.rows;
|
behaviorTrees.value = r.rows;
|
||||||
totalTress.value = r.total ?? 0;
|
totalTress.value = r.total ?? 0;
|
||||||
@@ -131,10 +152,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
const refresh = () => loadTress();
|
const refresh = () => loadTress();
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
loadTress();
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
refresh,
|
refresh,
|
||||||
totalTress,
|
totalTress,
|
||||||
|
|||||||
Reference in New Issue
Block a user