Merge branch 'master' of http://101.43.238.71:3000/zouju/auto-solution
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
package com.solution.scene.controller;
|
||||
package com.solution.web.controller.scene;
|
||||
|
||||
import com.solution.common.annotation.Log;
|
||||
import com.solution.common.core.controller.BaseController;
|
||||
@@ -33,7 +33,7 @@ public class SceneController extends BaseController {
|
||||
@ApiOperation("保存场景配置")
|
||||
@PostMapping("/saveSceneConfig")
|
||||
@Log(title = "行为树主", businessType = BusinessType.INSERT)
|
||||
public AjaxResult saveSceneConfig(@RequestBody AfsimScenarioForm afsimScenario)
|
||||
public AjaxResult saveSceneConfig(@RequestBody AfsimScenario afsimScenario)
|
||||
{
|
||||
return toAjax(sceneService.saveOrUpdate(afsimScenario));
|
||||
}
|
||||
@@ -113,6 +113,12 @@
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.34</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
|
||||
@@ -6,4 +6,6 @@ public class PlatformAndModuleConstants {
|
||||
public static final String RED_NEBO_M_1 = "red_nebo_m_1";
|
||||
|
||||
public static final String RED_NEBO_M_2 = "red_nebo_m_2";
|
||||
|
||||
public static final String RED_TANK_1 = "red_tank_1";
|
||||
}
|
||||
|
||||
@@ -24,10 +24,6 @@
|
||||
<artifactId>solution-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
|
||||
@@ -38,8 +38,6 @@ public class WarplaneHandler extends AbstractRuleChainHandler {
|
||||
|
||||
List<PlatformWeaponAggregateVO> resultWeapons = new ArrayList<>();
|
||||
|
||||
//TODO获取所有组件以及count
|
||||
|
||||
Iterator<WeaponModelDTO> iterator = dtoList.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
WeaponModelDTO dto = iterator.next();
|
||||
|
||||
@@ -30,10 +30,6 @@
|
||||
<artifactId>solution-common</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.solution.scene.domain;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 场景配置表
|
||||
* 对应表 afsim_scenario
|
||||
@@ -11,6 +13,16 @@ public class AfsimScenario {
|
||||
private String scenarioPath;
|
||||
private String communicationGraph; // 用于存储场景中的通讯关系
|
||||
|
||||
public List<ScenarioRelation> getRelations() {
|
||||
return relations;
|
||||
}
|
||||
|
||||
public void setRelations(List<ScenarioRelation> relations) {
|
||||
this.relations = relations;
|
||||
}
|
||||
|
||||
private List<ScenarioRelation> relations;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.solution.scene.mapper;
|
||||
|
||||
import com.solution.scene.domain.AfsimScenarioForm;
|
||||
import com.solution.scene.domain.ScenarioRelation;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface PlatFormCommunicationMapper {
|
||||
|
||||
/**
|
||||
* 存储通信关系
|
||||
* @param scenaryId,afsimScenarios
|
||||
*/
|
||||
int insert(@Param("scenaryId") Integer scenaryId,
|
||||
@Param("afsimScenarios") List<ScenarioRelation> afsimScenarios);
|
||||
|
||||
|
||||
/**
|
||||
* 删除通信关系
|
||||
* @param scenaryId
|
||||
* @return
|
||||
*/
|
||||
int delete(Integer scenaryId);
|
||||
}
|
||||
@@ -14,9 +14,9 @@ public interface SceneMapper {
|
||||
* @param afsimScenario
|
||||
* @return
|
||||
*/
|
||||
int insert(AfsimScenarioForm afsimScenario);
|
||||
int insert(AfsimScenario afsimScenario);
|
||||
|
||||
int update(AfsimScenarioForm afsimScenario);
|
||||
int update(AfsimScenario afsimScenario);
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@@ -12,11 +12,11 @@ public interface SceneService {
|
||||
* @param afsimScenario
|
||||
* @return
|
||||
*/
|
||||
int insert(AfsimScenarioForm afsimScenario);
|
||||
int insert(AfsimScenario afsimScenario);
|
||||
|
||||
int update(AfsimScenarioForm afsimScenario);
|
||||
|
||||
int saveOrUpdate(AfsimScenarioForm afsimScenario);
|
||||
int saveOrUpdate(AfsimScenario afsimScenario);
|
||||
|
||||
/**
|
||||
* 获取场景列表
|
||||
|
||||
@@ -2,10 +2,12 @@ package com.solution.scene.service.impl;
|
||||
|
||||
import com.solution.scene.domain.AfsimScenario;
|
||||
import com.solution.scene.domain.AfsimScenarioForm;
|
||||
import com.solution.scene.mapper.PlatFormCommunicationMapper;
|
||||
import com.solution.scene.mapper.SceneMapper;
|
||||
import com.solution.scene.service.SceneService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -16,8 +18,11 @@ public class SceneServiceImpl implements SceneService {
|
||||
@Autowired
|
||||
private SceneMapper sceneMapper;
|
||||
|
||||
@Autowired
|
||||
private PlatFormCommunicationMapper platFormCommunicationMapper;
|
||||
|
||||
@Override
|
||||
public int insert(AfsimScenarioForm afsimScenario) {
|
||||
public int insert(AfsimScenario afsimScenario) {
|
||||
return sceneMapper.insert(afsimScenario);
|
||||
}
|
||||
|
||||
@@ -26,12 +31,29 @@ public class SceneServiceImpl implements SceneService {
|
||||
return sceneMapper.update(afsimScenario);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Override
|
||||
public int saveOrUpdate(AfsimScenarioForm afsimScenario) {
|
||||
public int saveOrUpdate(AfsimScenario afsimScenario) {
|
||||
if (null != afsimScenario.getId() && afsimScenario.getId() > 0) {
|
||||
return sceneMapper.update(afsimScenario);
|
||||
// 更新场景
|
||||
int updated = sceneMapper.update(afsimScenario);
|
||||
// 先删除通信关系
|
||||
platFormCommunicationMapper.delete(afsimScenario.getId());
|
||||
// 再插入通信关系
|
||||
if (afsimScenario.getRelations() != null && !afsimScenario.getRelations().isEmpty()) {
|
||||
platFormCommunicationMapper.insert(afsimScenario.getId(), afsimScenario.getRelations());
|
||||
}
|
||||
return updated;
|
||||
} else {
|
||||
// 新增场景
|
||||
int inserted = sceneMapper.insert(afsimScenario);
|
||||
// 确保获取到生成的 ID
|
||||
if (afsimScenario.getId() != null && afsimScenario.getRelations() != null && !afsimScenario.getRelations().isEmpty()) {
|
||||
// 存储通信关系
|
||||
platFormCommunicationMapper.insert(afsimScenario.getId(), afsimScenario.getRelations());
|
||||
}
|
||||
return inserted;
|
||||
}
|
||||
return insert(afsimScenario);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.solution.scene.mapper.PlatFormCommunicationMapper">
|
||||
|
||||
|
||||
<insert id="insert" parameterType="com.solution.scene.domain.AfsimScenarioForm">
|
||||
INSERT INTO platform_communication (scenary_id, command_platform, subordinate_platform, command_comm, subordinate_comm)
|
||||
VALUES
|
||||
<foreach collection="afsimScenarios" item="item" separator=",">
|
||||
(#{scenaryId}, #{item.sourcePlatform.name}, #{item.targetPlatform.name}, #{item.sourceComponent.name}, #{item.targetComponent.name})
|
||||
</foreach>
|
||||
</insert>
|
||||
<delete id="delete" parameterType="java.lang.Integer">
|
||||
DELETE FROM platform_communication
|
||||
WHERE scenary_id = #{scenaryId}
|
||||
</delete>
|
||||
</mapper>
|
||||
@@ -12,7 +12,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="communicationGraph" column="communication_graph" />
|
||||
</resultMap>
|
||||
|
||||
<insert id="insert" parameterType="com.solution.scene.domain.AfsimScenario">
|
||||
<insert id="insert" parameterType="com.solution.scene.domain.AfsimScenario" useGeneratedKeys="true" keyProperty="id">
|
||||
INSERT INTO afsim_scenario (name, description, scenario_path, communication_graph)
|
||||
VALUES (#{name}, #{description}, #{scenarioPath}, #{communicationGraph})
|
||||
</insert>
|
||||
|
||||
@@ -1291,6 +1291,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.ant-select:not(.ant-select-customize-input) .ant-select-selector{
|
||||
border: 1px solid #475f71
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper.ant-input-password input:-webkit-autofill,
|
||||
.ant-input-affix-wrapper.ant-input-password input:-webkit-autofill:hover,
|
||||
.ant-input-affix-wrapper.ant-input-password input:-webkit-autofill:focus,
|
||||
@@ -1504,9 +1508,7 @@
|
||||
border-inline-end-width: 1px;
|
||||
}
|
||||
}
|
||||
.ant-select:not(.ant-select-customize-input) .ant-select-selector{
|
||||
border: 1px solid #2c2a2a;
|
||||
}
|
||||
|
||||
.ant-select .ant-select-selection-placeholder,
|
||||
.ant-select .ant-select-selection-search-input{
|
||||
background: transparent
|
||||
|
||||
@@ -274,8 +274,11 @@ const getAlgorithmTypeName = (type: NullableString): NullableString => {
|
||||
const load = () => {
|
||||
algorithms.value = [];
|
||||
algorithmsTotal.value = 0;
|
||||
formRef.value?.resetFields();
|
||||
selectedAlgorithm.value = resolveItem(defaultAlgorithm);
|
||||
|
||||
if(selectedAlgorithm.value.id <= 0){
|
||||
formRef.value?.resetFields();
|
||||
selectedAlgorithm.value = resolveItem(defaultAlgorithm);
|
||||
}
|
||||
|
||||
findAlgorithmsByQuery(query.value).then(r => {
|
||||
algorithms.value = r.rows ?? [];
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
<!-- 平台选择框 -->
|
||||
<a-select
|
||||
style="width:280px"
|
||||
v-model:value="selectedPlatformId"
|
||||
:placeholder="'请选择平台'"
|
||||
v-model:value="innerPlatformId"
|
||||
placeholder="请选择平台"
|
||||
:disabled="loading"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in platforms"
|
||||
:key="item.id"
|
||||
:key="`platform-${item.id}`"
|
||||
:value="item.id"
|
||||
>
|
||||
{{ item.description || item.name || '未命名平台' }}
|
||||
@@ -18,13 +19,13 @@
|
||||
<!-- 组件选择框 -->
|
||||
<a-select
|
||||
style="width:280px;"
|
||||
v-model:value="selectedComponentId"
|
||||
:placeholder="'请选择组件'"
|
||||
:disabled="!selectedPlatform"
|
||||
v-model:value="innerComponentId"
|
||||
placeholder="请选择组件"
|
||||
:disabled="!innerPlatformId || loading"
|
||||
>
|
||||
<a-select-option
|
||||
v-for="item in selectedPlatformComponents"
|
||||
:key="item.id"
|
||||
:key="`component-${item.id}`"
|
||||
:value="item.id"
|
||||
>
|
||||
{{ item.description || item.name || '未命名组件' }}
|
||||
@@ -34,135 +35,84 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, onMounted, type PropType, ref, watch } from 'vue';
|
||||
import type { Platform, PlatformComponent, PlatformComponentPayload, PlatformWithComponents } from '../types';
|
||||
import { findAllPlatformWithComponents } from './api';
|
||||
import { computed, defineComponent, type PropType, ref, watch } from 'vue';
|
||||
import type { PlatformComponentPayload } from '../types';
|
||||
import { usePlatformComponents } from './store';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'PlatformSelect',
|
||||
props: {
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
payload: {
|
||||
type: [Object,null] as PropType<PlatformComponentPayload | null>,
|
||||
platformId: {
|
||||
type: [Number, null] as PropType<number | null>,
|
||||
required: false,
|
||||
default: ({
|
||||
platform: null,
|
||||
component: null,
|
||||
}),
|
||||
default: null,
|
||||
},
|
||||
componentId: {
|
||||
type: [Number, null] as PropType<number | null>,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
emits: [
|
||||
'change',
|
||||
],
|
||||
emits: {
|
||||
change: (payload: PlatformComponentPayload) => true,
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const platforms = ref<PlatformWithComponents[]>([]);
|
||||
const platformMapping = ref<Map<number, PlatformWithComponents>>(new Map());
|
||||
const componentsMapping = ref<Map<number, PlatformComponent>>(new Map());
|
||||
const { loading, platforms, platformMap, componentMap } = usePlatformComponents();
|
||||
|
||||
const selectedPlatformComponents = ref<PlatformComponent[]>([])
|
||||
const innerPlatformId = ref<number | null>(props.platformId);
|
||||
const innerComponentId = ref<number | null>(props.componentId);
|
||||
|
||||
const selectedPlatform = ref<PlatformWithComponents|null>(null);
|
||||
const selectedPlatformId = ref<number|null>(null);
|
||||
const selectedPlatformComponents = computed(() => {
|
||||
const platform = platforms.value.find(p => p.id === innerPlatformId.value);
|
||||
return platform?.components || [];
|
||||
});
|
||||
|
||||
const selectedComponent = ref<PlatformComponent|null>(null);
|
||||
const selectedComponentId = ref<number|null>(null);
|
||||
const emitChange = () => {
|
||||
// 根据ID获取完整对象
|
||||
const platform = platformMap.value.get(innerPlatformId.value || -1) || null;
|
||||
const component = componentMap.value.get(innerComponentId.value || -1) || null;
|
||||
|
||||
const load = () => {
|
||||
platforms.value = [];
|
||||
platformMapping.value.clear();
|
||||
componentsMapping.value.clear();
|
||||
const validComponent = component && component.platformId === innerPlatformId.value
|
||||
? component
|
||||
: null;
|
||||
|
||||
findAllPlatformWithComponents().then(re => {
|
||||
platforms.value = re.data ?? [];
|
||||
platforms.value.forEach(platform => {
|
||||
platformMapping.value.set(platform.id, platform);
|
||||
if(platform.components){
|
||||
platform.components.forEach(comp=> {
|
||||
componentsMapping.value.set(comp.id, comp)
|
||||
})
|
||||
}
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error('加载平台组件数据失败:', err);
|
||||
});
|
||||
emit('change', {
|
||||
platform: platform ? {
|
||||
id: platform.id,
|
||||
name: platform.name,
|
||||
description: platform.description,
|
||||
scenarioId: platform.scenarioId,
|
||||
} : null,
|
||||
component: validComponent,
|
||||
} as PlatformComponentPayload);
|
||||
};
|
||||
|
||||
const triggerChange = ()=> {
|
||||
emit('change', {
|
||||
platform: selectedPlatform.value ? {
|
||||
id: selectedPlatform.value?.id,
|
||||
name: selectedPlatform.value?.name,
|
||||
description: selectedPlatform.value?.description,
|
||||
} : null,
|
||||
component: selectedComponent.value ? {
|
||||
id: selectedComponent.value.id,
|
||||
name: selectedComponent.value.name,
|
||||
description: selectedComponent.value.description,
|
||||
num: selectedComponent.value.num,
|
||||
platformId: selectedComponent.value.platformId,
|
||||
type: selectedComponent.value.type,
|
||||
} : null,
|
||||
})
|
||||
}
|
||||
watch([() => props.platformId, () => props.componentId],
|
||||
([newPlatformId, newComponentId]) => {
|
||||
if (!loading.value) {
|
||||
innerPlatformId.value = newPlatformId;
|
||||
innerComponentId.value = newComponentId;
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: false },
|
||||
);
|
||||
|
||||
watch(()=> props.payload, (n: PlatformComponentPayload | null | undefined)=> {
|
||||
if(n && n.platform){
|
||||
selectedPlatform.value = platformMapping.value.get(n.platform?.id) ?? null;
|
||||
selectedPlatformId.value = selectedPlatform.value?.id ?? null;
|
||||
selectedPlatformComponents.value = selectedPlatform.value?.components ?? []
|
||||
} else {
|
||||
selectedPlatform.value = null;
|
||||
selectedPlatformId.value = null;
|
||||
selectedPlatformComponents.value = []
|
||||
watch(innerPlatformId, (newVal) => {
|
||||
if (newVal !== innerPlatformId.value) {
|
||||
innerComponentId.value = null;
|
||||
}
|
||||
emitChange();
|
||||
});
|
||||
|
||||
if(n && n.component){
|
||||
selectedComponent.value = n.component;
|
||||
selectedComponentId.value = selectedComponent.value?.id ?? null;
|
||||
} else {
|
||||
selectedComponent.value = null;
|
||||
selectedComponentId.value = null;
|
||||
}
|
||||
|
||||
console.error('watch',n)
|
||||
}, {deep: true, immediate: true})
|
||||
|
||||
|
||||
watch(()=> selectedPlatformId.value,(n: null | number)=> {
|
||||
if(n && platformMapping.value.get(n)){
|
||||
selectedPlatform.value = platformMapping.value.get(n) ?? null;
|
||||
selectedPlatformComponents.value = selectedPlatform.value?.components ?? []
|
||||
} else {
|
||||
selectedPlatform.value = null;
|
||||
selectedPlatformComponents.value = []
|
||||
}
|
||||
selectedComponentId.value = null;
|
||||
|
||||
triggerChange();
|
||||
})
|
||||
|
||||
watch(()=> selectedComponentId.value,(n: null | number)=> {
|
||||
if(n && componentsMapping.value.get(n)){
|
||||
selectedComponent.value = componentsMapping.value.get(n) ?? null;
|
||||
} else {
|
||||
selectedComponent.value = null;
|
||||
}
|
||||
|
||||
triggerChange();
|
||||
})
|
||||
|
||||
onMounted(() => load());
|
||||
watch(innerComponentId, emitChange);
|
||||
|
||||
return {
|
||||
loading,
|
||||
platforms,
|
||||
selectedPlatformComponents,
|
||||
selectedPlatform,
|
||||
selectedPlatformId,
|
||||
selectedComponent,
|
||||
selectedComponentId,
|
||||
innerPlatformId,
|
||||
innerComponentId,
|
||||
};
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -32,9 +32,7 @@
|
||||
</template>
|
||||
|
||||
<div class="w-full h-full">
|
||||
|
||||
<a-card class="ks-page-card ks-algorithm-card">
|
||||
|
||||
<template #title>
|
||||
<a-space>
|
||||
<span class="point"></span>
|
||||
@@ -43,7 +41,6 @@
|
||||
</template>
|
||||
|
||||
<div class="ks-scrollable" style="height: 80.5vh;overflow-y: auto;padding-right: 10px">
|
||||
|
||||
<a-row :gutter="15">
|
||||
<a-col :span="16">
|
||||
<a-form
|
||||
@@ -57,14 +54,14 @@
|
||||
<a-form-item
|
||||
label="规则名称"
|
||||
:rules="[{ required: true, message: '请输入规则名称!', trigger: ['input', 'change'] }]"
|
||||
:name="['name']"
|
||||
name="name"
|
||||
>
|
||||
<a-input v-model:value="selectedFireRule.name" placeholder="请输入规则名称" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="场景类型"
|
||||
:name="['sceneType']"
|
||||
name="sceneType"
|
||||
>
|
||||
<a-select v-model:value="selectedFireRule.sceneType" placeholder="请选择场景类型">
|
||||
<a-select-option :value="null">通用</a-select-option>
|
||||
@@ -73,23 +70,32 @@
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 触发条件 - 传递ID,保持PlatformComponentPayload结构 -->
|
||||
<a-form-item
|
||||
label="触发条件"
|
||||
:rules="[{ required: true, message: '请输入触发条件!', trigger: [ 'change'] }]"
|
||||
:name="['conditionsArray']"
|
||||
:rules="[{ required: true, message: '请输入触发条件!', trigger: ['change'] }]"
|
||||
name="conditionsArray"
|
||||
>
|
||||
<a-form-item-rest>
|
||||
<div class="ks-sidebar-list-param-list">
|
||||
<div class="ks-sidebar-list-param-item" v-for="(item,index) in selectedFireRule.conditionsArray">
|
||||
<div
|
||||
class="ks-sidebar-list-param-item"
|
||||
v-for="(item,index) in selectedFireRule.conditionsArray"
|
||||
:key="`condition-${index}-${item.platform?.id || 'null'}-${item.component?.id || 'null'}`"
|
||||
>
|
||||
<a-row :gutter="15">
|
||||
<a-col :span="21">
|
||||
<PlatformSelect @change="(payload: PlatformComponentPayload)=> handleUpdateCondition(payload, index)"
|
||||
:payload="item"/>
|
||||
<!-- 只传递ID参数 -->
|
||||
<PlatformSelect
|
||||
:platform-id="item.platform?.id || null"
|
||||
:component-id="item.component?.id || null"
|
||||
@change="(payload)=> handleUpdateCondition(payload, index)"
|
||||
/>
|
||||
</a-col>
|
||||
<a-col :span="3">
|
||||
<a-space class="ks-sidebar-list-param-actions">
|
||||
<MinusCircleOutlined @click="()=> handleMinusCondition(index)" />
|
||||
<PlusCircleOutlined @click="()=> handleAddCondition(index)" v-if="index === 0" />
|
||||
<MinusCircleOutlined @click.stop="()=> handleMinusCondition(index)" />
|
||||
<PlusCircleOutlined @click.stop="()=> handleAddCondition()" v-if="index === 0" />
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
@@ -98,23 +104,32 @@
|
||||
</a-form-item-rest>
|
||||
</a-form-item>
|
||||
|
||||
<!-- 响应动作 - 传递ID,保持PlatformComponentPayload结构 -->
|
||||
<a-form-item
|
||||
label="响应动作"
|
||||
:rules="[{ required: true, message: '请输入响应动作!', trigger: ['change'] }]"
|
||||
:name="['actionsArray']"
|
||||
name="actionsArray"
|
||||
>
|
||||
<a-form-item-rest>
|
||||
<div class="ks-sidebar-list-param-list">
|
||||
<div class="ks-sidebar-list-param-item" v-for="(item,index) in selectedFireRule.actionsArray">
|
||||
<div
|
||||
class="ks-sidebar-list-param-item"
|
||||
v-for="(item,index) in selectedFireRule.actionsArray"
|
||||
:key="`action-${index}-${item.platform?.id || 'null'}-${item.component?.id || 'null'}`"
|
||||
>
|
||||
<a-row :gutter="15">
|
||||
<a-col :span="21">
|
||||
<PlatformSelect @change="(payload: PlatformComponentPayload)=> handleUpdateAction(payload, index)"
|
||||
:payload="item"/>
|
||||
<!-- 只传递ID参数 -->
|
||||
<PlatformSelect
|
||||
:platform-id="item.platform?.id || null"
|
||||
:component-id="item.component?.id || null"
|
||||
@change="(payload)=> handleUpdateAction(payload, index)"
|
||||
/>
|
||||
</a-col>
|
||||
<a-col :span="3">
|
||||
<a-space class="ks-sidebar-list-param-actions">
|
||||
<MinusCircleOutlined @click="()=> handleMinusAction(index)" />
|
||||
<PlusCircleOutlined @click="()=> handleAddAction(index)" v-if="index === 0" />
|
||||
<MinusCircleOutlined @click.stop="()=> handleMinusAction(index)" />
|
||||
<PlusCircleOutlined @click.stop="()=> handleAddAction()" v-if="index === 0" />
|
||||
</a-space>
|
||||
</a-col>
|
||||
</a-row>
|
||||
@@ -126,24 +141,21 @@
|
||||
<a-form-item
|
||||
label="优先级(数值越小优先级越高)"
|
||||
:rules="[{ required: true, message: '请输入优先级!', trigger: ['input', 'change'] }]"
|
||||
:name="['priority']"
|
||||
name="priority"
|
||||
>
|
||||
<a-input-number style="width:100%;" v-model:value="selectedFireRule.priority" placeholder="请输入优先级" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
label="是否启用"
|
||||
:name="['priority']"
|
||||
name="enabled"
|
||||
>
|
||||
<a-switch v-model:checked="selectedFireRule.enabled" />
|
||||
</a-form-item>
|
||||
|
||||
<a-form-item
|
||||
:wrapper-col="{offset: 6}"
|
||||
>
|
||||
<a-form-item :wrapper-col="{offset: 6}">
|
||||
<a-space>
|
||||
<a-button @click="handleSave" type="primary">保存规则</a-button>
|
||||
|
||||
<a-popconfirm
|
||||
v-if="selectedFireRule && selectedFireRule.id > 0"
|
||||
title="确定删除?"
|
||||
@@ -151,112 +163,90 @@
|
||||
>
|
||||
<a-button danger>删除规则</a-button>
|
||||
</a-popconfirm>
|
||||
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
|
||||
</a-form>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
</div>
|
||||
|
||||
</a-card>
|
||||
|
||||
</div>
|
||||
</Layout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, nextTick } from 'vue';
|
||||
import { nextTick, onMounted, ref } from 'vue';
|
||||
import { type FormInstance, message } from 'ant-design-vue';
|
||||
import { MinusCircleOutlined, PlusCircleOutlined, PlusOutlined } from '@ant-design/icons-vue';
|
||||
import Layout from '../layout.vue';
|
||||
import { createFireRule, deleteFireRule, findFireRuleByQuery, updateFireRule } from './api';
|
||||
import type { FireRule, FireRuleRequest } from './types';
|
||||
import type { FireRule, FireRulePageableResponse, FireRuleRequest } from './types';
|
||||
import type { PlatformComponentPayload } from '../types';
|
||||
import { substring } from '@/utils/strings';
|
||||
import PlatformSelect from './PlatformSelect.vue';
|
||||
import type { PlatformComponentPayload } from '../types';
|
||||
|
||||
const query = ref<Partial<FireRuleRequest>>({
|
||||
const query = ref<FireRuleRequest>({
|
||||
id: 0,
|
||||
name: '',
|
||||
sceneType: null,
|
||||
conditions: '',
|
||||
conditionsArray: [],
|
||||
actions: '',
|
||||
actionsArray: [],
|
||||
priority: 0,
|
||||
enabled: true,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
});
|
||||
|
||||
const defaultPayload: PlatformComponentPayload = {
|
||||
platform: null,
|
||||
component: null,
|
||||
};
|
||||
|
||||
const defaultFireRule: FireRule = {
|
||||
id: 0,
|
||||
// 规则名称
|
||||
name: null,
|
||||
// 场景类型:0-防御,1-空降,null表示通用
|
||||
name: '',
|
||||
sceneType: null,
|
||||
// 触发条件(JSON格式)
|
||||
conditions: null,
|
||||
conditionsArray: [
|
||||
{
|
||||
platform: null,
|
||||
component: null,
|
||||
}
|
||||
],
|
||||
// 响应动作(JSON格式)
|
||||
actions: null,
|
||||
actionsArray: [
|
||||
{
|
||||
platform: null,
|
||||
component: null,
|
||||
}
|
||||
],
|
||||
// 优先级(数值越小优先级越高)
|
||||
conditions: '',
|
||||
conditionsArray: [JSON.parse(JSON.stringify(defaultPayload))],
|
||||
actions: '',
|
||||
actionsArray: [JSON.parse(JSON.stringify(defaultPayload))],
|
||||
priority: 0,
|
||||
// 是否启用(0禁用,1启用)
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
const getSceneTypeName = (item: FireRule): string => {
|
||||
if (0 === item.sceneType) {
|
||||
return '防御';
|
||||
}
|
||||
if (1 === item.sceneType) {
|
||||
return '空降';
|
||||
}
|
||||
if (item.sceneType === 0) return '防御';
|
||||
if (item.sceneType === 1) return '空降';
|
||||
return '通用';
|
||||
};
|
||||
|
||||
const resolveItem = (item: FireRule) => {
|
||||
let newItem: FireRule = JSON.parse(JSON.stringify(item)) as FireRule;
|
||||
if (typeof item.conditions === 'string') {
|
||||
try{
|
||||
newItem.conditionsArray = JSON.parse(item.conditions as string);
|
||||
} catch(e: any){
|
||||
newItem.conditionsArray = []
|
||||
}
|
||||
const newItem: FireRule = JSON.parse(JSON.stringify(item)) as FireRule;
|
||||
|
||||
try {
|
||||
newItem.conditionsArray = item.conditions
|
||||
? (JSON.parse(item.conditions) as PlatformComponentPayload[])
|
||||
: [JSON.parse(JSON.stringify(defaultPayload))];
|
||||
} catch (e) {
|
||||
newItem.conditionsArray = [JSON.parse(JSON.stringify(defaultPayload))];
|
||||
}
|
||||
|
||||
if(!newItem.conditionsArray) {
|
||||
newItem.conditionsArray = []
|
||||
}
|
||||
if(newItem.conditionsArray.length===0){
|
||||
newItem.conditionsArray.push({
|
||||
platform: null,
|
||||
component: null,
|
||||
})
|
||||
try {
|
||||
newItem.actionsArray = item.actions
|
||||
? (JSON.parse(item.actions) as PlatformComponentPayload[])
|
||||
: [JSON.parse(JSON.stringify(defaultPayload))];
|
||||
} catch (e) {
|
||||
newItem.actionsArray = [JSON.parse(JSON.stringify(defaultPayload))];
|
||||
}
|
||||
|
||||
if (typeof item.actions === 'string') {
|
||||
try{
|
||||
newItem.actionsArray = JSON.parse(item.actions as string);
|
||||
} catch(e: any){
|
||||
newItem.actionsArray = []
|
||||
}
|
||||
// 确保数组不为空
|
||||
if (!Array.isArray(newItem.conditionsArray) || newItem.conditionsArray.length === 0) {
|
||||
newItem.conditionsArray = [JSON.parse(JSON.stringify(defaultPayload))];
|
||||
}
|
||||
|
||||
if(!newItem.actionsArray){
|
||||
newItem.actionsArray = []
|
||||
}
|
||||
if(newItem.actionsArray.length===0){
|
||||
newItem.actionsArray.push({
|
||||
platform: null,
|
||||
component: null,
|
||||
})
|
||||
if (!Array.isArray(newItem.actionsArray) || newItem.actionsArray.length === 0) {
|
||||
newItem.actionsArray = [JSON.parse(JSON.stringify(defaultPayload))];
|
||||
}
|
||||
|
||||
return newItem;
|
||||
@@ -264,41 +254,43 @@ const resolveItem = (item: FireRule) => {
|
||||
|
||||
const datasource = ref<FireRule[]>([]);
|
||||
const datasourceTotal = ref<number>(0);
|
||||
const selectedFireRule = ref<FireRule>({...defaultFireRule});
|
||||
const selectedFireRule = ref<FireRule>(JSON.parse(JSON.stringify(defaultFireRule)));
|
||||
const formRef = ref<FormInstance | null>(null);
|
||||
|
||||
const load = () => {
|
||||
datasource.value = [];
|
||||
datasourceTotal.value = 0;
|
||||
formRef.value?.resetFields();
|
||||
selectedFireRule.value = {...defaultFireRule};
|
||||
if(selectedFireRule.value.id <= 0){
|
||||
selectedFireRule.value = JSON.parse(JSON.stringify(defaultFireRule));
|
||||
nextTick(() => {
|
||||
formRef.value?.resetFields();
|
||||
});
|
||||
}
|
||||
|
||||
findFireRuleByQuery(query.value).then(r => {
|
||||
findFireRuleByQuery(query.value).then((r: FireRulePageableResponse) => {
|
||||
datasource.value = r.rows ?? [];
|
||||
datasourceTotal.value = r.total ?? 0;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const handleCreate = () => {
|
||||
selectedFireRule.value = {...defaultFireRule};
|
||||
formRef.value?.resetFields();
|
||||
selectedFireRule.value = JSON.parse(JSON.stringify(defaultFireRule));
|
||||
};
|
||||
|
||||
const handleSelect = (item: FireRule) => {
|
||||
// 1. 先重置表单
|
||||
formRef.value?.resetFields();
|
||||
// 2. 再赋值(使用nextTick确保DOM更新完成)
|
||||
nextTick(() => {
|
||||
selectedFireRule.value = resolveItem(item);
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
if (selectedFireRule.value && selectedFireRule.value.id > 0) {
|
||||
if (selectedFireRule.value?.id > 0) {
|
||||
deleteFireRule(selectedFireRule.value.id).then(r => {
|
||||
if (r.code === 200) {
|
||||
load();
|
||||
message.info(r.msg ?? '删除成功');
|
||||
message.success(r.msg ?? '删除成功');
|
||||
} else {
|
||||
message.error(r.msg ?? '删除失败');
|
||||
}
|
||||
@@ -307,91 +299,90 @@ const handleDelete = () => {
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
if (formRef.value) {
|
||||
formRef.value.validate().then(() => {
|
||||
let res = null;
|
||||
let savedValue: FireRule = JSON.parse(JSON.stringify(selectedFireRule.value)) as any as FireRule;
|
||||
savedValue.conditions = JSON.stringify(savedValue.conditionsArray ?? null) as string;
|
||||
savedValue.actions = JSON.stringify(savedValue.actionsArray ?? null) as string;
|
||||
if (savedValue.id > 0) {
|
||||
res = updateFireRule(savedValue);
|
||||
formRef.value?.validate().then(() => {
|
||||
const savedValue: FireRule = JSON.parse(JSON.stringify(selectedFireRule.value));
|
||||
|
||||
savedValue.conditions = JSON.stringify(savedValue.conditionsArray);
|
||||
savedValue.actions = JSON.stringify(savedValue.actionsArray);
|
||||
|
||||
const request = savedValue.id > 0
|
||||
? updateFireRule(savedValue)
|
||||
: createFireRule(savedValue);
|
||||
|
||||
request.then(r => {
|
||||
if (r.code === 200) {
|
||||
load();
|
||||
message.success(r.msg ?? '操作成功');
|
||||
} else {
|
||||
res = createFireRule(savedValue);
|
||||
}
|
||||
if (res) {
|
||||
res.then(r => {
|
||||
if (r.code === 200) {
|
||||
load();
|
||||
message.info(r.msg ?? '操作成功');
|
||||
} else {
|
||||
message.error(r.msg ?? '操作失败');
|
||||
}
|
||||
});
|
||||
message.error(r.msg ?? '操作失败');
|
||||
}
|
||||
}).catch(err => {
|
||||
message.error('请求失败:' + err.message);
|
||||
});
|
||||
}).catch(err => {
|
||||
message.error('表单验证失败:' + err.message);
|
||||
});
|
||||
};
|
||||
|
||||
const handleUpdateCondition = (payload: PlatformComponentPayload, index: number) => {
|
||||
if (selectedFireRule.value && selectedFireRule.value.conditionsArray[index]) {
|
||||
const newArray = [...selectedFireRule.value.conditionsArray];
|
||||
newArray[index] = {
|
||||
platform: payload.platform,
|
||||
component: payload.component,
|
||||
};
|
||||
selectedFireRule.value.conditionsArray = newArray;
|
||||
}
|
||||
};
|
||||
|
||||
const handleUpdateAction = (payload: PlatformComponentPayload, index: number) => {
|
||||
if (selectedFireRule.value && selectedFireRule.value.actionsArray[index]) {
|
||||
const newArray = [...selectedFireRule.value.actionsArray];
|
||||
newArray[index] = {
|
||||
platform: payload.platform,
|
||||
component: payload.component,
|
||||
};
|
||||
selectedFireRule.value.actionsArray = newArray;
|
||||
}
|
||||
};
|
||||
|
||||
// 添加触发条件
|
||||
const handleAddCondition = () => {
|
||||
if (selectedFireRule.value) {
|
||||
selectedFireRule.value.conditionsArray.push(JSON.parse(JSON.stringify(defaultPayload)));
|
||||
}
|
||||
};
|
||||
|
||||
// 删除触发条件
|
||||
const handleMinusCondition = (index: number) => {
|
||||
if(selectedFireRule.value){
|
||||
const paramList = selectedFireRule.value.conditionsArray;
|
||||
if (index === 0 && selectedFireRule.value.conditionsArray.length === 1) {
|
||||
selectedFireRule.value.conditionsArray = [{
|
||||
platform: null,
|
||||
component: null,
|
||||
}];
|
||||
} else if (index >= 0 && index < paramList.length && paramList.length > 1) {
|
||||
paramList.splice(index, 1);
|
||||
selectedFireRule.value.conditionsArray = [...paramList];
|
||||
}
|
||||
if (!selectedFireRule.value) return;
|
||||
const list = [...selectedFireRule.value.conditionsArray];
|
||||
if (list.length <= 1) {
|
||||
selectedFireRule.value.conditionsArray = [JSON.parse(JSON.stringify(defaultPayload))];
|
||||
} else {
|
||||
list.splice(index, 1);
|
||||
selectedFireRule.value.conditionsArray = list;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleAddCondition = (index: number)=> {
|
||||
if(selectedFireRule.value){
|
||||
selectedFireRule.value.conditionsArray.push({
|
||||
platform: null,
|
||||
component: null,
|
||||
})
|
||||
// 添加响应动作
|
||||
const handleAddAction = () => {
|
||||
if (selectedFireRule.value) {
|
||||
selectedFireRule.value.actionsArray.push(JSON.parse(JSON.stringify(defaultPayload)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 删除响应动作
|
||||
const handleMinusAction = (index: number) => {
|
||||
if(selectedFireRule.value){
|
||||
const paramList = selectedFireRule.value.actionsArray;
|
||||
if (index === 0 && selectedFireRule.value.actionsArray.length === 1) {
|
||||
selectedFireRule.value.actionsArray = [{
|
||||
platform: null,
|
||||
component: null,
|
||||
}];
|
||||
} else if (index >= 0 && index < paramList.length && paramList.length > 1) {
|
||||
paramList.splice(index, 1);
|
||||
selectedFireRule.value.actionsArray = [...paramList];
|
||||
}
|
||||
if (!selectedFireRule.value) return;
|
||||
const list = [...selectedFireRule.value.actionsArray];
|
||||
if (list.length <= 1) {
|
||||
selectedFireRule.value.actionsArray = [JSON.parse(JSON.stringify(defaultPayload))];
|
||||
} else {
|
||||
list.splice(index, 1);
|
||||
selectedFireRule.value.actionsArray = list;
|
||||
}
|
||||
}
|
||||
|
||||
const handleAddAction = (_index: number)=> {
|
||||
if(selectedFireRule.value){
|
||||
selectedFireRule.value.actionsArray.push({
|
||||
platform: null,
|
||||
component: null,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateCondition = (payload: PlatformComponentPayload, index: number)=> {
|
||||
console.error('handleUpdateCondition', payload)
|
||||
if(selectedFireRule.value && selectedFireRule.value.conditionsArray[index]){
|
||||
selectedFireRule.value.conditionsArray[index] = payload;
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdateAction = (payload: PlatformComponentPayload, index: number)=> {
|
||||
if(selectedFireRule.value && selectedFireRule.value.actionsArray[index]){
|
||||
selectedFireRule.value.actionsArray[index] = payload;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (page: number, pageSize: number) => {
|
||||
query.value.pageNum = page;
|
||||
@@ -400,5 +391,4 @@ const handleChange = (page: number, pageSize: number) => {
|
||||
};
|
||||
|
||||
onMounted(() => load());
|
||||
|
||||
</script>
|
||||
64
modeler/src/views/decision/rule/store.ts
Normal file
64
modeler/src/views/decision/rule/store.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* This file is part of the kernelstudio package.
|
||||
*
|
||||
* (c) 2014-2026 zlin <admin@kernelstudio.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE file
|
||||
* that was distributed with this source code.
|
||||
*/
|
||||
|
||||
import { onMounted, ref, type Ref } from 'vue';
|
||||
import type { Platform, PlatformComponent, PlatformWithComponents, PlatformWithComponentsResponse } from '../types';
|
||||
import { findAllPlatformWithComponents } from './api';
|
||||
|
||||
const loading: Ref<boolean> = ref<boolean>(true);
|
||||
const platforms: Ref<PlatformWithComponents[]> = ref<PlatformWithComponents[]>([]);
|
||||
const platformMap: Ref<Map<number, Platform>> = ref<Map<number, Platform>>(new Map());
|
||||
const componentMap: Ref<Map<number, PlatformComponent>> = ref<Map<number, PlatformComponent>>(new Map());
|
||||
const loaded: Ref<boolean> = ref<boolean>(false);
|
||||
|
||||
export interface UsePlatformComponentsReturn {
|
||||
loading: Ref<boolean>;
|
||||
platforms: Ref<PlatformWithComponents[]>;
|
||||
platformMap: Ref<Map<number, Platform>>;
|
||||
componentMap: Ref<Map<number, PlatformComponent>>;
|
||||
loaded: Ref<boolean>;
|
||||
}
|
||||
|
||||
export const usePlatformComponents = (): UsePlatformComponentsReturn => {
|
||||
const load = () => {
|
||||
if (!loaded.value) {
|
||||
loading.value = true;
|
||||
platformMap.value.clear();
|
||||
componentMap.value.clear();
|
||||
|
||||
findAllPlatformWithComponents()
|
||||
.then((res: PlatformWithComponentsResponse) => { // 显式标注响应类型
|
||||
platforms.value = res.data || [];
|
||||
platforms.value.forEach(platform => {
|
||||
platformMap.value.set(platform.id, platform);
|
||||
platform.components?.forEach(component => {
|
||||
componentMap.value.set(component.id, component);
|
||||
});
|
||||
});
|
||||
loaded.value = true;
|
||||
})
|
||||
.catch((err: unknown) => {
|
||||
console.error('加载平台组件失败:', err);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => load());
|
||||
|
||||
return {
|
||||
loading,
|
||||
platforms,
|
||||
platformMap,
|
||||
componentMap,
|
||||
loaded,
|
||||
};
|
||||
};
|
||||
23
pom.xml
23
pom.xml
@@ -274,6 +274,29 @@
|
||||
<encoding>${project.build.sourceEncoding}</encoding>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<configuration>
|
||||
<source>11</source>
|
||||
<target>11</target>
|
||||
<annotationProcessorPaths>
|
||||
<!-- 顺序无关,但每个都需要指定版本 -->
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.34</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>org.mapstruct</groupId>
|
||||
<artifactId>mapstruct-processor</artifactId>
|
||||
<version>1.5.5.Final</version>
|
||||
</path>
|
||||
<!-- 如果有其他 processor 也加在这里 -->
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user