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

394 lines
14 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'] }]"
2026-03-17 10:06:55 +08:00
name="name"
2026-03-14 20:55:15 +08:00
>
<a-input v-model:value="selectedFireRule.name" placeholder="请输入规则名称" />
</a-form-item>
<a-form-item
label="场景类型"
2026-03-17 10:06:55 +08:00
name="sceneType"
2026-03-14 20:55:15 +08:00
>
<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>
2026-03-17 10:06:55 +08:00
<!-- 触发条件 - 传递ID保持PlatformComponentPayload结构 -->
2026-03-14 20:55:15 +08:00
<a-form-item
label="触发条件"
2026-03-17 10:06:55 +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">
2026-03-17 10:06:55 +08:00
<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'}`"
>
2026-03-16 22:43:12 +08:00
<a-row :gutter="15">
<a-col :span="21">
2026-03-17 10:06:55 +08:00
<!-- 只传递ID参数 -->
<PlatformSelect
:platform-id="item.platform?.id || null"
:component-id="item.component?.id || null"
@change="(payload)=> handleUpdateCondition(payload, index)"
/>
2026-03-16 22:43:12 +08:00
</a-col>
<a-col :span="3">
<a-space class="ks-sidebar-list-param-actions">
2026-03-17 10:06:55 +08:00
<MinusCircleOutlined @click.stop="()=> handleMinusCondition(index)" />
<PlusCircleOutlined @click.stop="()=> handleAddCondition()" v-if="index === 0" />
2026-03-16 22:43:12 +08:00
</a-space>
</a-col>
</a-row>
</div>
</div>
</a-form-item-rest>
2026-03-14 20:55:15 +08:00
</a-form-item>
2026-03-17 10:06:55 +08:00
<!-- 响应动作 - 传递ID保持PlatformComponentPayload结构 -->
2026-03-14 20:55:15 +08:00
<a-form-item
label="响应动作"
2026-03-16 22:43:12 +08:00
:rules="[{ required: true, message: '请输入响应动作!', trigger: ['change'] }]"
2026-03-17 10:06:55 +08:00
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">
2026-03-17 10:06:55 +08:00
<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'}`"
>
2026-03-16 22:43:12 +08:00
<a-row :gutter="15">
<a-col :span="21">
2026-03-17 10:06:55 +08:00
<!-- 只传递ID参数 -->
<PlatformSelect
:platform-id="item.platform?.id || null"
:component-id="item.component?.id || null"
@change="(payload)=> handleUpdateAction(payload, index)"
/>
2026-03-16 22:43:12 +08:00
</a-col>
<a-col :span="3">
<a-space class="ks-sidebar-list-param-actions">
2026-03-17 10:06:55 +08:00
<MinusCircleOutlined @click.stop="()=> handleMinusAction(index)" />
<PlusCircleOutlined @click.stop="()=> handleAddAction()" v-if="index === 0" />
2026-03-16 22:43:12 +08:00
</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'] }]"
2026-03-17 10:06:55 +08:00
name="priority"
2026-03-14 20:55:15 +08:00
>
<a-input-number style="width:100%;" v-model:value="selectedFireRule.priority" placeholder="请输入优先级" />
</a-form-item>
<a-form-item
label="是否启用"
2026-03-17 10:06:55 +08:00
name="enabled"
2026-03-14 20:55:15 +08:00
>
<a-switch v-model:checked="selectedFireRule.enabled" />
</a-form-item>
2026-03-17 10:06:55 +08:00
<a-form-item :wrapper-col="{offset: 6}">
2026-03-14 20:55:15 +08:00
<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 10:06:55 +08:00
import { nextTick, onMounted, ref } 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';
2026-03-17 10:06:55 +08:00
import type { FireRule, FireRulePageableResponse, FireRuleRequest } from './types';
import type { PlatformComponentPayload } from '../types';
2026-03-14 20:55:15 +08:00
import { substring } from '@/utils/strings';
2026-03-16 22:43:12 +08:00
import PlatformSelect from './PlatformSelect.vue';
2026-03-14 20:55:15 +08:00
2026-03-17 10:06:55 +08:00
const query = ref<FireRuleRequest>({
id: 0,
name: '',
sceneType: null,
conditions: '',
conditionsArray: [],
actions: '',
actionsArray: [],
priority: 0,
enabled: true,
2026-03-14 20:55:15 +08:00
pageNum: 1,
pageSize: 10,
});
2026-03-17 10:06:55 +08:00
const defaultPayload: PlatformComponentPayload = {
platform: null,
component: null,
};
2026-03-14 20:55:15 +08:00
const defaultFireRule: FireRule = {
id: 0,
2026-03-17 10:06:55 +08:00
name: '',
2026-03-14 20:55:15 +08:00
sceneType: null,
2026-03-17 10:06:55 +08:00
conditions: '',
conditionsArray: [JSON.parse(JSON.stringify(defaultPayload))],
actions: '',
actionsArray: [JSON.parse(JSON.stringify(defaultPayload))],
2026-03-14 20:55:15 +08:00
priority: 0,
enabled: true,
};
const getSceneTypeName = (item: FireRule): string => {
2026-03-17 10:06:55 +08:00
if (item.sceneType === 0) return '防御';
if (item.sceneType === 1) return '空降';
2026-03-14 20:55:15 +08:00
return '通用';
};
const resolveItem = (item: FireRule) => {
2026-03-17 10:06:55 +08:00
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))];
2026-03-16 22:43:12 +08:00
}
2026-03-17 10:06:55 +08:00
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))];
2026-03-16 22:43:12 +08:00
}
2026-03-17 00:36:16 +08:00
2026-03-17 10:06:55 +08:00
// 确保数组不为空
if (!Array.isArray(newItem.conditionsArray) || newItem.conditionsArray.length === 0) {
newItem.conditionsArray = [JSON.parse(JSON.stringify(defaultPayload))];
2026-03-16 22:43:12 +08:00
}
2026-03-17 10:06:55 +08:00
if (!Array.isArray(newItem.actionsArray) || newItem.actionsArray.length === 0) {
newItem.actionsArray = [JSON.parse(JSON.stringify(defaultPayload))];
2026-03-16 22:43:12 +08:00
}
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-17 10:06:55 +08:00
const selectedFireRule = ref<FireRule>(JSON.parse(JSON.stringify(defaultFireRule)));
2026-03-14 20:55:15 +08:00
const formRef = ref<FormInstance | null>(null);
const load = () => {
datasource.value = [];
datasourceTotal.value = 0;
2026-03-17 10:06:55 +08:00
if(selectedFireRule.value.id <= 0){
selectedFireRule.value = JSON.parse(JSON.stringify(defaultFireRule));
nextTick(() => {
formRef.value?.resetFields();
});
}
2026-03-14 20:55:15 +08:00
2026-03-17 10:06:55 +08:00
findFireRuleByQuery(query.value).then((r: FireRulePageableResponse) => {
2026-03-14 20:55:15 +08:00
datasource.value = r.rows ?? [];
datasourceTotal.value = r.total ?? 0;
});
};
const handleCreate = () => {
2026-03-17 10:06:55 +08:00
formRef.value?.resetFields();
selectedFireRule.value = JSON.parse(JSON.stringify(defaultFireRule));
2026-03-14 20:55:15 +08:00
};
const handleSelect = (item: FireRule) => {
formRef.value?.resetFields();
2026-03-17 00:36:16 +08:00
nextTick(() => {
selectedFireRule.value = resolveItem(item);
});
2026-03-14 20:55:15 +08:00
};
const handleDelete = () => {
2026-03-17 10:06:55 +08:00
if (selectedFireRule.value?.id > 0) {
2026-03-14 20:55:15 +08:00
deleteFireRule(selectedFireRule.value.id).then(r => {
if (r.code === 200) {
load();
2026-03-17 10:06:55 +08:00
message.success(r.msg ?? '删除成功');
2026-03-14 20:55:15 +08:00
} else {
message.error(r.msg ?? '删除失败');
}
});
}
};
const handleSave = () => {
2026-03-17 10:06:55 +08:00
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 ?? '操作成功');
2026-03-14 20:55:15 +08:00
} else {
2026-03-17 10:06:55 +08:00
message.error(r.msg ?? '操作失败');
2026-03-14 20:55:15 +08:00
}
2026-03-17 10:06:55 +08:00
}).catch(err => {
message.error('请求失败:' + err.message);
2026-03-14 20:55:15 +08:00
});
2026-03-17 10:06:55 +08:00
}).catch(err => {
message.error('表单验证失败:' + err.message);
});
2026-03-14 20:55:15 +08:00
};
2026-03-17 10:06:55 +08:00
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;
2026-03-16 22:43:12 +08:00
}
2026-03-17 10:06:55 +08:00
};
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;
2026-03-16 22:43:12 +08:00
}
2026-03-17 10:06:55 +08:00
};
2026-03-16 22:43:12 +08:00
2026-03-17 10:06:55 +08:00
// 添加触发条件
const handleAddCondition = () => {
if (selectedFireRule.value) {
selectedFireRule.value.conditionsArray.push(JSON.parse(JSON.stringify(defaultPayload)));
2026-03-16 22:43:12 +08:00
}
2026-03-17 10:06:55 +08:00
};
// 删除触发条件
const handleMinusCondition = (index: number) => {
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;
2026-03-16 22:43:12 +08:00
}
2026-03-17 10:06:55 +08:00
};
2026-03-16 22:43:12 +08:00
2026-03-17 10:06:55 +08:00
// 添加响应动作
const handleAddAction = () => {
if (selectedFireRule.value) {
selectedFireRule.value.actionsArray.push(JSON.parse(JSON.stringify(defaultPayload)));
2026-03-16 22:43:12 +08:00
}
2026-03-17 10:06:55 +08:00
};
2026-03-16 22:43:12 +08:00
2026-03-17 10:06:55 +08:00
// 删除响应动作
const handleMinusAction = (index: number) => {
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;
2026-03-16 22:43:12 +08:00
}
2026-03-17 10:06:55 +08:00
};
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>