This commit is contained in:
2026-04-14 13:35:50 +08:00
14 changed files with 162 additions and 19 deletions

View File

@@ -55,4 +55,13 @@ public class SceneController extends BaseController {
{ {
return success(sceneService.findOneById(id)); return success(sceneService.findOneById(id));
} }
/**
* 根据场景id获取场景下所有行为树
*/
@GetMapping("/getAllTree/{id}")
@ApiOperation("根据场景id获取场景下所有行为树")
public AjaxResult getAllTree(@PathVariable Integer id){
return success(sceneService.getAllTree(id));
}
} }

View File

@@ -49,6 +49,17 @@ public class Behaviortree extends BaseEntity
@Excel(name = "平台ID") @Excel(name = "平台ID")
private Integer platformId; private Integer platformId;
@Excel(name = "场景ID")
private Integer scenarioId;
public Integer getScenarioId() {
return scenarioId;
}
public void setScenarioId(Integer scenarioId) {
this.scenarioId = scenarioId;
}
public Integer getPlatformId() { public Integer getPlatformId() {
return platformId; return platformId;
} }

View File

@@ -2,6 +2,7 @@ package com.solution.system.mapper;
import com.solution.system.domain.PlatformTree; import com.solution.system.domain.PlatformTree;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List; import java.util.List;
@@ -13,12 +14,12 @@ public interface PlatformMapper {
* @param id * @param id
* @return * @return
*/ */
PlatformTree getPlatformByTreeId(Long id); PlatformTree getPlatformByTreeId(Integer id);
/** /**
* 根据下属平台英文名获取中文名返回 * 根据下属平台英文名获取中文名返回
* @param underlingEnglishName * @param underlingEnglishName
* @return * @return
*/ */
List<String> selectPlatformChineseName(List<String> underlingEnglishName); List<String> selectPlatformChineseName(@Param("underlingEnglishName") List<String> underlingEnglishName);
} }

View File

@@ -121,11 +121,11 @@ public class BehaviortreeServiceImpl implements IBehaviortreeService
throw new RuntimeException(ExceptionConstants.PARAMETER_EXCEPTION); throw new RuntimeException(ExceptionConstants.PARAMETER_EXCEPTION);
} }
Behaviortree behaviortree = behaviortreeMapper.selectBehaviortreeById(Long.valueOf(treeId)); Behaviortree behaviortree = behaviortreeMapper.selectBehaviortreeById(Long.valueOf(treeId));
if(ObjectUtil.isEmpty(behaviortree) && null == behaviortree.getId()){ if(ObjectUtil.isEmpty(behaviortree) || null == behaviortree.getId()){
throw new RuntimeException(ExceptionConstants.PARAMETER_EXCEPTION); throw new RuntimeException(ExceptionConstants.PARAMETER_EXCEPTION);
} }
//根据行为树id获取行为树所属平台 //根据行为树id获取行为树所属平台
PlatformTree platform = platformMapper.getPlatformByTreeId(behaviortree.getId()); PlatformTree platform = platformMapper.getPlatformByTreeId(behaviortree.getPlatformId());
//根据平台name获取平台下属英文名 //根据平台name获取平台下属英文名
List<String> underlingEnglishName = platformCommunicationMapper.getUnderlingBytreeId(platform.getName()); List<String> underlingEnglishName = platformCommunicationMapper.getUnderlingBytreeId(platform.getName());
//根据下属平台英文名获取中文名返回 //根据下属平台英文名获取中文名返回

View File

@@ -5,13 +5,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="com.solution.system.mapper.BehaviortreeMapper"> <mapper namespace="com.solution.system.mapper.BehaviortreeMapper">
<resultMap type="Behaviortree" id="BehaviortreeResult"> <resultMap type="Behaviortree" id="BehaviortreeResult">
<result property="id" column="id" /> <result property="id" column="id" />
<result property="name" column="name" /> <result property="name" column="name" />
<result property="description" column="description" /> <result property="description" column="description" />
<result property="createdAt" column="created_at" /> <result property="createdAt" column="created_at" />
<result property="updatedAt" column="updated_at" /> <result property="updatedAt" column="updated_at" />
<result property="englishName" column="english_name" /> <result property="englishName" column="english_name"/>
<result property="xmlContent" column="xml_content" /> <result property="xmlContent" column="xml_content" />
<result property="platformId" column="platform_id" />
<result property="scenarioId" column="scenario_id" />
</resultMap> </resultMap>
<select id="findOneByPlatformId" resultMap="BehaviortreeResult"> <select id="findOneByPlatformId" resultMap="BehaviortreeResult">
@@ -37,7 +39,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</select> </select>
<select id="selectBehaviortreeById" parameterType="Long" resultMap="BehaviortreeResult"> <select id="selectBehaviortreeById" parameterType="Long" resultMap="BehaviortreeResult">
<include refid="selectBehaviortreeVo"/> select id, name, description, created_at, updated_at, english_name,graph, xml_content ,platform_id, scenario_id from behaviortree
where id = #{id} where id = #{id}
</select> </select>

View File

@@ -6,7 +6,7 @@
<select id="getPlatformByTreeId" resultType="com.solution.system.domain.PlatformTree" <select id="getPlatformByTreeId" resultType="com.solution.system.domain.PlatformTree"
parameterType="java.lang.Long"> parameterType="java.lang.Integer">
SELECT id , name , description, scenario_id SELECT id , name , description, scenario_id
FROM platform FROM platform
WHERE id = #{id} WHERE id = #{id}

View File

@@ -36,6 +36,11 @@
<artifactId>springfox-boot-starter</artifactId> <artifactId>springfox-boot-starter</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.solution</groupId>
<artifactId>solution-behaviour</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@@ -2,6 +2,7 @@ package com.solution.scene.mapper;
import com.solution.scene.domain.AfsimScenario; import com.solution.scene.domain.AfsimScenario;
import com.solution.scene.domain.AfsimScenarioForm; import com.solution.scene.domain.AfsimScenarioForm;
import com.solution.system.domain.Behaviortree;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import java.util.List; import java.util.List;
@@ -26,4 +27,11 @@ public interface SceneMapper {
List<AfsimScenario> selectSceneList(); List<AfsimScenario> selectSceneList();
AfsimScenario findOneById(Long id); AfsimScenario findOneById(Long id);
/**
* 根据场景id获取场景下所有行为树
* @param id
* @return
*/
List<Behaviortree> selectAllTreeBySceneId(Integer id);
} }

View File

@@ -2,6 +2,7 @@ package com.solution.scene.service;
import com.solution.scene.domain.AfsimScenario; import com.solution.scene.domain.AfsimScenario;
import com.solution.scene.domain.AfsimScenarioForm; import com.solution.scene.domain.AfsimScenarioForm;
import com.solution.system.domain.Behaviortree;
import java.util.List; import java.util.List;
@@ -25,4 +26,11 @@ public interface SceneService {
List<AfsimScenario> selectSceneList(); List<AfsimScenario> selectSceneList();
AfsimScenario findOneById(Long id); AfsimScenario findOneById(Long id);
/**
* 根据场景id获取场景下所有行为树
* @param id
* @return
*/
List<Behaviortree> getAllTree(Integer id);
} }

View File

@@ -1,10 +1,13 @@
package com.solution.scene.service.impl; package com.solution.scene.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.solution.common.constant.ExceptionConstants;
import com.solution.scene.domain.AfsimScenario; import com.solution.scene.domain.AfsimScenario;
import com.solution.scene.domain.AfsimScenarioForm; import com.solution.scene.domain.AfsimScenarioForm;
import com.solution.scene.mapper.PlatFormCommunicationMapper; import com.solution.scene.mapper.PlatFormCommunicationMapper;
import com.solution.scene.mapper.SceneMapper; import com.solution.scene.mapper.SceneMapper;
import com.solution.scene.service.SceneService; import com.solution.scene.service.SceneService;
import com.solution.system.domain.Behaviortree;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -70,4 +73,21 @@ public class SceneServiceImpl implements SceneService {
return sceneMapper.findOneById(id); return sceneMapper.findOneById(id);
} }
/**
* 根据场景id获取场景下所有行为树
* @param id
* @return
*/
@Override
public List<Behaviortree> getAllTree(Integer id) {
if(null == id || id <= 0){
throw new RuntimeException(ExceptionConstants.PARAMETER_EXCEPTION);
}
List<Behaviortree> allTree = sceneMapper.selectAllTreeBySceneId(id);
if(CollUtil.isEmpty(allTree)){
throw new RuntimeException("该场景下不存在行为树");
}
return allTree;
}
} }

View File

@@ -25,6 +25,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectSceneList" resultMap="SceneMap"> <select id="selectSceneList" resultMap="SceneMap">
SELECT id, name, description, scenario_path, communication_graph FROM afsim_scenario SELECT id, name, description, scenario_path, communication_graph FROM afsim_scenario
</select> </select>
<select id="selectAllTreeBySceneId" resultType="com.solution.system.domain.Behaviortree"
parameterType="java.lang.Integer">
SELECT id, name, description, created_at, updated_at, english_name, graph,xml_content,platform_id,scenario_id
FROM behaviortree
WHERE scenario_id=#{id}
</select>
<insert id="update" parameterType="com.solution.scene.domain.AfsimScenario"> <insert id="update" parameterType="com.solution.scene.domain.AfsimScenario">
update afsim_scenario update afsim_scenario

View File

@@ -28,6 +28,10 @@ export const findOneTreeByPlatformId = (platformId: number): Promise<BehaviorTre
return req.get(`/system/behaviortree/platform/${platformId}`); return req.get(`/system/behaviortree/platform/${platformId}`);
}; };
export const findSubPlatforms = (treeId: number): Promise<BehaviorTreeDetailsResponse> => {
return req.get(`/system/behaviortree/underling/${treeId}`);
};
export const findOneTreeById = (id: number): Promise<BehaviorTreeDetailsResponse> => { export const findOneTreeById = (id: number): Promise<BehaviorTreeDetailsResponse> => {
return req.get(`/system/behaviortree/${id}`); return req.get(`/system/behaviortree/${id}`);
}; };

View File

@@ -43,10 +43,11 @@
<Properties <Properties
v-if="graph" v-if="graph"
:platforms="platforms" :platforms="platforms"
:sub-platforms="subPlatforms"
:nodeCommands="nodeCommands" :nodeCommands="nodeCommands"
:element="selectedNodeTaskElement" :element="selectedNodeTaskElement"
:graph="graph as any" :graph="(graph as any)"
:node="selectedModelNode as any" :node="(selectedModelNode as any)"
:tree="currentBehaviorTree" :tree="currentBehaviorTree"
:tree-editing="currentTreeEditing" :tree-editing="currentTreeEditing"
@update-element="handleUpdateElement" /> @update-element="handleUpdateElement" />
@@ -74,8 +75,8 @@ import { createGraphTaskElementFromTemplate } from './utils';
import { createGraphTaskElement, createLineOptions, type GraphContainer, type GraphTaskElement, hasElements, hasRootElementNode, resolveGraph, useGraphCanvas } from '../graph'; import { createGraphTaskElement, createLineOptions, type GraphContainer, type GraphTaskElement, hasElements, hasRootElementNode, resolveGraph, useGraphCanvas } from '../graph';
import { registerNodeElement } from './register'; import { registerNodeElement } from './register';
import { findAllBasicPlatforms, findAllNodeCommands } from '../api'; import { findAllBasicPlatforms, findAllNodeCommands } from '../api';
import type { Platform } from '../types'; import type { NodeCommand, Platform } from '../types';
import { createTree, findOneTreeById, findOneTreeByPlatformId, updateTree } from './api'; import { createTree, findOneTreeById, findOneTreeByPlatformId, updateTree, findSubPlatforms } from './api';
import TressCard from './trees-card.vue'; import TressCard from './trees-card.vue';
import NodesCard from './nodes-card.vue'; import NodesCard from './nodes-card.vue';
@@ -112,6 +113,7 @@ export default defineComponent({
const changed = ref<boolean>(false); const changed = ref<boolean>(false);
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 nodeCommands = ref<NodeCommand[]>([]) const nodeCommands = ref<NodeCommand[]>([])
const currentScenarioId = ref<number | null>(null); const currentScenarioId = ref<number | null>(null);
const currentPlatformId = ref<number | null>(null); const currentPlatformId = ref<number | null>(null);
@@ -153,6 +155,27 @@ export default defineComponent({
loadNodeCommands(); loadNodeCommands();
} }
// 加载下属平台
const loadSubPlatforms = (treeId: number) => {
console.log(treeId);
if (!treeId || treeId <= 0) {
subPlatforms.value = [];
return;
}
findSubPlatforms(treeId).then(r => {
if (r.data && Array.isArray(r.data)) {
subPlatforms.value = r.data as Platform[];
} else {
subPlatforms.value = [];
}
}).catch(err => {
console.error('加载下属平台失败:', err);
subPlatforms.value = [];
});
};
// 处理拖动开始 // 处理拖动开始
const handleDragStart = (nm: NodeDragTemplate) => { const handleDragStart = (nm: NodeDragTemplate) => {
draggedNodeData.value = nm; draggedNodeData.value = nm;
@@ -267,6 +290,10 @@ export default defineComponent({
graph: nodeGraph, graph: nodeGraph,
}; };
currentTreeEditing.value = true; currentTreeEditing.value = true;
// 加载下属平台
loadSubPlatforms(r.data.id);
nextTick(() => { nextTick(() => {
initGraph(); initGraph();
}); });
@@ -343,6 +370,7 @@ export default defineComponent({
}; };
selectedModelNode.value = null; selectedModelNode.value = null;
selectedNodeTaskElement.value = null; selectedNodeTaskElement.value = null;
subPlatforms.value = []; // 重置下属平台
nextTick(() => { nextTick(() => {
initGraph(); initGraph();
@@ -487,6 +515,7 @@ export default defineComponent({
nodeCommands, nodeCommands,
currentScenarioId, currentScenarioId,
platforms, platforms,
subPlatforms,
treesCardRef, treesCardRef,
handleCreateTree, handleCreateTree,
currentTreeEditing, currentTreeEditing,

View File

@@ -101,7 +101,7 @@
size="small" size="small"
type="editable-card" type="editable-card"
@edit="onEditParameterTab"> @edit="onEditParameterTab">
<a-tab-pane v-for="(grouped,index) in groupedParameters" :key="index" :tab="`平台 ${index + 1}`" :closable="true"> <a-tab-pane v-for="(grouped,index) in groupedParameters" :key="index" :tab="getPlatformTabName(index)" :closable="true">
<a-form-item v-for="setting in grouped" :label="setting.description"> <a-form-item v-for="setting in grouped" :label="setting.description">
<a-input-number v-if="setting.dataType === 'double'" <a-input-number v-if="setting.dataType === 'double'"
v-model:value="setting.defaultValue" v-model:value="setting.defaultValue"
@@ -109,7 +109,7 @@
<a-select :placeholder="`请选择${setting.description}`" <a-select :placeholder="`请选择${setting.description}`"
allow-clear allow-clear
v-else-if="setting.paramKey === 'platforms'" v-model:value="setting.defaultValue"> v-else-if="setting.paramKey === 'platforms'" v-model:value="setting.defaultValue">
<a-select-option v-for="pl in platforms" :value="pl.name">{{pl.description}}</a-select-option> <a-select-option v-for="pl in getAvailablePlatforms()" :value="pl.name">{{pl.description}}</a-select-option>
</a-select> </a-select>
<a-select :placeholder="`请选择${setting.description}`" <a-select :placeholder="`请选择${setting.description}`"
allow-clear allow-clear
@@ -194,11 +194,13 @@ export default defineComponent({
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 },
platforms: { type: Array as PropType<Platform[]>, required: true }, platforms: { type: Array as PropType<Platform[]>, required: true },
subPlatforms: { type: Array as PropType<Platform[]>, required: false, default: () => [] },
nodeCommands: { type: Array as PropType<NodeCommand[]>, required: true }, nodeCommands: { type: Array as PropType<NodeCommand[]>, required: true },
}, },
emits: ['update-element', 'update-tree'], emits: ['update-element', 'update-tree'],
setup(props, { emit }) { setup(props, { emit }) {
const platforms = ref<Platform[]>(props.platforms ?? []); const platforms = ref<Platform[]>(props.platforms ?? []);
const subPlatforms = ref<Platform[]>(props.subPlatforms ?? []);
const nodeCommands = ref<NodeCommand[]>(props.nodeCommands ?? []); const nodeCommands = ref<NodeCommand[]>(props.nodeCommands ?? []);
const activeTopTabsKey = ref<string>('1'); const activeTopTabsKey = ref<string>('1');
@@ -299,6 +301,41 @@ export default defineComponent({
multiableParameters.value = multiable === true && groupedParameters.value.length > 0; multiableParameters.value = multiable === true && groupedParameters.value.length > 0;
}; };
// 获取平台Tab显示名称
const getPlatformTabName = (index: number): string => {
if (!currentTree.value?.platformId) {
return `平台 ${index + 1}`;
}
// 查找当前行为树绑定的平台
const currentPlatform = platforms.value.find(p => p.id === currentTree.value?.platformId);
if (!currentPlatform) {
return `平台 ${index + 1}`;
}
// 如果有多个分组,显示平台名称和索引
if (groupedParameters.value.length > 1) {
return `${currentPlatform.name || '未知平台'}-${index + 1}`;
}
return currentPlatform.name || '平台';
};
// 获取可用的平台列表(包括当前平台和其下属平台)
const getAvailablePlatforms = (): Platform[] => {
if (!currentTree.value?.platformId) {
return platforms.value;
}
// 如果有下属平台,返回下属平台列表
if (subPlatforms.value && subPlatforms.value.length > 0) {
return subPlatforms.value;
}
// 否则返回所有平台
return platforms.value;
};
const resolveNode = (n?: Node | null | undefined) => { const resolveNode = (n?: Node | null | undefined) => {
groupedParametersActiveTab.value = 0; groupedParametersActiveTab.value = 0;
@@ -389,6 +426,7 @@ export default defineComponent({
watch(() => props.nodeCommands, (n: NodeCommand[] | null | undefined) => nodeCommands.value = n ?? [], { deep: true, immediate: true }); watch(() => props.nodeCommands, (n: NodeCommand[] | null | undefined) => nodeCommands.value = n ?? [], { deep: true, immediate: true });
watch(() => props.platforms, (n: Platform[] | null | undefined) => platforms.value = n ?? [], { deep: true, immediate: true }); watch(() => props.platforms, (n: Platform[] | null | undefined) => platforms.value = n ?? [], { deep: true, immediate: true });
watch(() => props.subPlatforms, (n: Platform[] | null | undefined) => subPlatforms.value = n ?? [], { deep: true, immediate: true });
onMounted(() => load()); onMounted(() => load());
@@ -400,6 +438,8 @@ export default defineComponent({
multiableParameters, multiableParameters,
onEditParameterTab, onEditParameterTab,
groupedParameters, groupedParameters,
getPlatformTabName,
getAvailablePlatforms,
actionSpaceColumns, actionSpaceColumns,
activeTopTabsKey, activeTopTabsKey,
activeBottomTabsKey, activeBottomTabsKey,