Files
auto-solution/modeler/src/views/decision/rule/management.vue

404 lines
13 KiB
Vue
Raw Normal View History

2026-03-14 20:55:15 +08:00
<template>
<Layout>
<template #sidebar>
<div class="ks-sidebar-header">
<a-flex class="ks-sidebar-title">
<span class="icon"></span>
<span class="text">火力规则管理</span>
</a-flex>
<a-button class="ks-sidebar-add" size="small" @click="handleCreate">
<PlusOutlined />
新增
</a-button>
</div>
<a-list item-layout="horizontal" :data-source="datasource" class="ks-sidebar-list">
<template #renderItem="{ item }">
<a-list-item @click="()=> handleSelect(item)" :class="selectedFireRule?.id === item.id ? 'selected' : null">
<a-list-item-meta :description="substring(item.description,20)">
<template #title>
<span class="ks-algorithm-name">{{ substring(item.name, 20) }}</span>
<span class="ks-sidebar-list-type"><a-badge size="small" :count="getSceneTypeName(item)"></a-badge></span>
</template>
</a-list-item-meta>
</a-list-item>
</template>
</a-list>
<a-pagination
v-model:current="query.pageNum"
:page-size="query.pageSize"
:total="datasourceTotal"
simple size="small" @change="handleChange" />
</template>
<div class="w-full h-full">
<a-card class="ks-page-card ks-algorithm-card">
<template #title>
<a-space>
<span class="point"></span>
<span class="text">规则配置</span>
</a-space>
</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
ref="formRef"
:label-col="{span: 6}"
:model="selectedFireRule"
autocomplete="off"
layout="horizontal"
name="basic"
>
<a-form-item
label="规则名称"
:rules="[{ required: true, message: '请输入规则名称!', trigger: ['input', 'change'] }]"
:name="['name']"
>
<a-input v-model:value="selectedFireRule.name" placeholder="请输入规则名称" />
</a-form-item>
<a-form-item
label="场景类型"
:name="['sceneType']"
>
<a-select v-model:value="selectedFireRule.sceneType" placeholder="请选择场景类型">
<a-select-option :value="null">通用</a-select-option>
<a-select-option :value="0">防御</a-select-option>
<a-select-option :value="1">空降</a-select-option>
</a-select>
</a-form-item>
<a-form-item
label="触发条件"
2026-03-16 22:43:12 +08:00
:rules="[{ required: true, message: '请输入触发条件!', trigger: [ 'change'] }]"
:name="['conditionsArray']"
2026-03-14 20:55:15 +08:00
>
2026-03-16 22:43:12 +08:00
<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">
<a-row :gutter="15">
<a-col :span="21">
2026-03-17 00:36:16 +08:00
<PlatformSelect @change="(payload: PlatformComponentPayload)=> handleUpdateCondition(payload, index)"
:payload="item"/>
2026-03-16 22:43:12 +08:00
</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" />
</a-space>
</a-col>
</a-row>
</div>
</div>
</a-form-item-rest>
2026-03-14 20:55:15 +08:00
</a-form-item>
<a-form-item
label="响应动作"
2026-03-16 22:43:12 +08:00
:rules="[{ required: true, message: '请输入响应动作!', trigger: ['change'] }]"
:name="['actionsArray']"
2026-03-14 20:55:15 +08:00
>
2026-03-16 22:43:12 +08:00
<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">
<a-row :gutter="15">
<a-col :span="21">
2026-03-17 00:36:16 +08:00
<PlatformSelect @change="(payload: PlatformComponentPayload)=> handleUpdateAction(payload, index)"
:payload="item"/>
2026-03-16 22:43:12 +08:00
</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" />
</a-space>
</a-col>
</a-row>
</div>
</div>
</a-form-item-rest>
2026-03-14 20:55:15 +08:00
</a-form-item>
<a-form-item
label="优先级(数值越小优先级越高)"
:rules="[{ required: true, message: '请输入优先级!', trigger: ['input', 'change'] }]"
:name="['priority']"
>
<a-input-number style="width:100%;" v-model:value="selectedFireRule.priority" placeholder="请输入优先级" />
</a-form-item>
<a-form-item
label="是否启用"
:name="['priority']"
>
<a-switch v-model:checked="selectedFireRule.enabled" />
</a-form-item>
<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="确定删除?"
@confirm="handleDelete"
>
<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">
2026-03-17 00:36:16 +08:00
import { onMounted, ref, nextTick } from 'vue';
2026-03-14 20:55:15 +08:00
import { type FormInstance, message } from 'ant-design-vue';
2026-03-16 22:43:12 +08:00
import { MinusCircleOutlined, PlusCircleOutlined, PlusOutlined } from '@ant-design/icons-vue';
2026-03-14 20:55:15 +08:00
import Layout from '../layout.vue';
import { createFireRule, deleteFireRule, findFireRuleByQuery, updateFireRule } from './api';
import type { FireRule, FireRuleRequest } from './types';
import { substring } from '@/utils/strings';
2026-03-16 22:43:12 +08:00
import PlatformSelect from './PlatformSelect.vue';
import type { PlatformComponentPayload } from '../types';
2026-03-14 20:55:15 +08:00
const query = ref<Partial<FireRuleRequest>>({
pageNum: 1,
pageSize: 10,
});
const defaultFireRule: FireRule = {
id: 0,
// 规则名称
name: null,
// 场景类型0-防御1-空降null表示通用
sceneType: null,
// 触发条件JSON格式
conditions: null,
2026-03-16 22:43:12 +08:00
conditionsArray: [
{
platform: null,
component: null,
}
],
2026-03-14 20:55:15 +08:00
// 响应动作JSON格式
actions: null,
2026-03-16 22:43:12 +08:00
actionsArray: [
{
platform: null,
component: null,
}
],
2026-03-14 20:55:15 +08:00
// 优先级(数值越小优先级越高)
priority: 0,
// 是否启用0禁用1启用
enabled: true,
};
const getSceneTypeName = (item: FireRule): string => {
if (0 === item.sceneType) {
return '防御';
}
if (1 === item.sceneType) {
return '空降';
}
return '通用';
};
const resolveItem = (item: FireRule) => {
2026-03-17 00:36:16 +08:00
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 = []
}
2026-03-16 22:43:12 +08:00
}
2026-03-17 00:36:16 +08:00
2026-03-16 22:43:12 +08:00
if(!newItem.conditionsArray) {
newItem.conditionsArray = []
}
if(newItem.conditionsArray.length===0){
newItem.conditionsArray.push({
platform: null,
component: null,
})
}
2026-03-17 00:36:16 +08:00
if (typeof item.actions === 'string') {
try{
newItem.actionsArray = JSON.parse(item.actions as string);
} catch(e: any){
newItem.actionsArray = []
}
2026-03-16 22:43:12 +08:00
}
2026-03-17 00:36:16 +08:00
2026-03-16 22:43:12 +08:00
if(!newItem.actionsArray){
newItem.actionsArray = []
}
if(newItem.actionsArray.length===0){
newItem.actionsArray.push({
platform: null,
component: null,
})
}
2026-03-17 00:36:16 +08:00
2026-03-14 20:55:15 +08:00
return newItem;
};
const datasource = ref<FireRule[]>([]);
const datasourceTotal = ref<number>(0);
2026-03-16 22:43:12 +08:00
const selectedFireRule = ref<FireRule>({...defaultFireRule});
2026-03-14 20:55:15 +08:00
const formRef = ref<FormInstance | null>(null);
const load = () => {
datasource.value = [];
datasourceTotal.value = 0;
formRef.value?.resetFields();
2026-03-16 22:43:12 +08:00
selectedFireRule.value = {...defaultFireRule};
2026-03-14 20:55:15 +08:00
findFireRuleByQuery(query.value).then(r => {
datasource.value = r.rows ?? [];
datasourceTotal.value = r.total ?? 0;
});
};
const handleCreate = () => {
2026-03-16 22:43:12 +08:00
selectedFireRule.value = {...defaultFireRule};
2026-03-14 20:55:15 +08:00
};
const handleSelect = (item: FireRule) => {
2026-03-17 00:36:16 +08:00
// 1. 先重置表单
2026-03-14 20:55:15 +08:00
formRef.value?.resetFields();
2026-03-17 00:36:16 +08:00
// 2. 再赋值使用nextTick确保DOM更新完成
nextTick(() => {
selectedFireRule.value = resolveItem(item);
});
2026-03-14 20:55:15 +08:00
};
const handleDelete = () => {
if (selectedFireRule.value && selectedFireRule.value.id > 0) {
deleteFireRule(selectedFireRule.value.id).then(r => {
if (r.code === 200) {
load();
message.info(r.msg ?? '删除成功');
} else {
message.error(r.msg ?? '删除失败');
}
});
}
};
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;
2026-03-16 22:43:12 +08:00
savedValue.conditions = JSON.stringify(savedValue.conditionsArray ?? null) as string;
savedValue.actions = JSON.stringify(savedValue.actionsArray ?? null) as string;
2026-03-14 20:55:15 +08:00
if (savedValue.id > 0) {
res = updateFireRule(savedValue);
} else {
res = createFireRule(savedValue);
}
if (res) {
res.then(r => {
if (r.code === 200) {
load();
message.info(r.msg ?? '操作成功');
} else {
message.error(r.msg ?? '操作失败');
}
});
}
});
}
};
2026-03-16 22:43:12 +08:00
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];
}
}
}
const handleAddCondition = (index: number)=> {
if(selectedFireRule.value){
selectedFireRule.value.conditionsArray.push({
platform: null,
component: null,
})
}
}
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];
}
}
}
const handleAddAction = (_index: number)=> {
if(selectedFireRule.value){
selectedFireRule.value.actionsArray.push({
platform: null,
component: null,
})
}
}
const handleUpdateCondition = (payload: PlatformComponentPayload, index: number)=> {
2026-03-17 00:36:16 +08:00
console.error('handleUpdateCondition', payload)
2026-03-16 22:43:12 +08:00
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;
}
}
2026-03-14 20:55:15 +08:00
const handleChange = (page: number, pageSize: number) => {
query.value.pageNum = page;
query.value.pageSize = pageSize;
load();
};
onMounted(() => load());
</script>