风险矩阵配置接口完成

This commit is contained in:
2026-08-31 15:11:53 +08:00
parent 8bb82e7bdf
commit a3e03466e1
3 changed files with 258 additions and 197 deletions
+8
View File
@@ -84,5 +84,13 @@ export function matrixConfigApi(bizType:string) {
method: 'get', method: 'get',
}); });
} }
// 保存风险矩阵配置
export function saveMatrixConfigApi(bizType:string,data:any) {
return request({
url: `/api/risk-matrix/${bizType}`,
method: 'put',
data,
});
}
+1 -1
View File
@@ -43,7 +43,7 @@ const form = ref<ApplyForm>({
name: "", dept: "", mainChanges: [""], related: "", purposes: [], effect: "", name: "", dept: "", mainChanges: [""], related: "", purposes: [], effect: "",
type: "", level: "", duration: "", urgent: false, date: null, restoreDate: null, type: "", level: "", duration: "", urgent: false, date: null, restoreDate: null,
}); });
const tab = ref<string>("risk"); const tab = ref<string>("pre");
const TABS = [ const TABS = [
{ id: "pre", name: "变更预识别", icon: 'lucide:sparkles' }, { id: "pre", name: "变更预识别", icon: 'lucide:sparkles' },
{ id: "form", name: "变更申请表", icon: 'akar-icons:file' }, { id: "form", name: "变更申请表", icon: 'akar-icons:file' },
+203 -150
View File
@@ -10,7 +10,8 @@ import {
editSystemConfigApi, editSystemConfigApi,
deleteSystemConfigApi, deleteSystemConfigApi,
updateConfigApi, updateConfigApi,
matrixConfigApi matrixConfigApi,
saveMatrixConfigApi
} from '@/service/api/system'; } from '@/service/api/system';
const appStore = useAppStore(); const appStore = useAppStore();
@@ -273,6 +274,13 @@ const ruleOptions = ref<{label:string, value:string}[]>([
{label:'按年度重置',value:'YEARLY'}, {label:'按年度重置',value:'YEARLY'},
{label:'连续不重置',value:'CONTINUE'}, {label:'连续不重置',value:'CONTINUE'},
]) ])
const levelOptions = ref<{label:string, value:string | null}[]>([
{label:'低',value:'低'},
{label:'一般',value:'一般'},
{label:'较高',value:'较高'},
{label:'高',value:'高'},
{label:'很高',value:'很高'},
])
// 保存编号规则 // 保存编号规则
const saveRule = async () => { const saveRule = async () => {
@@ -292,82 +300,102 @@ const saveRule = async () => {
// *************** 风险矩阵设置(按分析方法) ***************// // *************** 风险矩阵设置(按分析方法) ***************//
const matrixLoading = ref<boolean>(false);
const dimensionModal = ref<boolean>(false); const dimensionModal = ref<boolean>(false);
const dimensionLoading = ref<boolean>(false); const dimForm = ref<{s:{key:string, label:string}[], l:{key:string, label:string}[]}>({ s: [], l: [] });
const dimForm = ref<{s:string[], l:string[]}>({ s: [], l: [] });
// 默认风险矩阵维度分级定义
const matrices = ref([
{
tool: "HAZOP",
sLabels: ["轻微", "一般", "较重", "严重", "灾难"],
lLabels: ["极少发生", "较少发生", "偶尔发生", "可能发生", "频繁发生"],
levels: [
{ name: "低", min: 1, max: 4, bgColor:'#d1fae5', color:'#047857' },
{ name: "一般", min: 5, max: 9, bgColor:'#fef9c3', color:'#c27707' },
{ name: "较大", min: 10, max: 16, bgColor:'#fee2e2', color:'#c2410c' },
{ name: "重大", min: 17, max: 25, bgColor:'#fff3cd', color:'#b91c1c' },
],
},
{
tool: "JSA",
sLabels: ["轻微伤害", "轻伤", "重伤", "单人死亡", "多人死亡"],
lLabels: ["极不可能", "不太可能", "有可能", "较可能", "很可能"],
levels: [
{ name: "低", min: 1, max: 6, bgColor:'#d1fae5', color:'#047857' },
{ name: "一般", min: 7, max: 12, bgColor:'#fef9c3', color:'#c27707' },
{ name: "较大", min: 13, max: 19, bgColor:'#fee2e2', color:'#c2410c' },
{ name: "重大", min: 20, max: 25, bgColor:'#fff3cd', color:'#b91c1c' },
],
},
{
tool: "SCL",
sLabels: ["轻微影响", "一般影响", "较大影响", "严重影响", "灾难性影响"],
lLabels: ["极少", "较少", "偶尔", "可能", "经常"],
levels: [
{ name: "低", min: 1, max: 2, bgColor:'#d1fae5', color:'#047857' },
{ name: "一般", min: 3, max: 6, bgColor:'#fef9c3', color:'#c27707' },
{ name: "较大", min: 7, max: 12, bgColor:'#fee2e2', color:'#c2410c' },
{ name: "重大", min: 13, max: 25, bgColor:'#fff3cd', color:'#b91c1c' },
],
},
]);
// 当前选中的风险矩阵索引 // 当前选中的风险矩阵索引
const activeMatrix = ref(0); const activeMatrix = ref('HAZOP');
// 当前选中的风险矩阵 // 当前选中的风险矩阵
const curMatrix = ref<any>(null); const curMatrix = ref<any>(null);
const cellScore = (s:number, l:number) => (s + 1) * (l + 1); // 查找匹配的等级配置
function findMatchingConfig(num:number) {
for (let i = 0; i < curMatrix.value?.risk_grades.length; i++) {
const item = curMatrix.value?.risk_grades[i];
if (num >= item.min && num <= item.max) {
return item; // 返回整条数据
}
}
return null;
}
// 计算单元格等级
const cellScore = (s:number, l:number) => {
return s*l;
}
const cellLevel = (s:number, l:number) => { const cellLevel = (s:number, l:number) => {
const sc = cellScore(s, l); const info = findMatchingConfig(s*l);
return curMatrix.value?.levels.find((lv:{min:number,max:number}) => sc >= lv.min && sc <= lv.max); return info? info:null;
} }
// 风险矩阵tabs切换 // 风险矩阵tabs切换
const handleTabChange = (v: number) => { const handleTabChange = (v: string) => {
activeMatrix.value = v; activeMatrix.value = v;
curMatrix.value = matrices.value[v]; matrixConfig();
} }
// 打开风险矩阵编辑弹窗 // 打开风险矩阵编辑弹窗
const openDimEdit = () => { const openDimEdit = () => {
dimForm.value = { s: [...curMatrix.value?.sLabels], l: [...curMatrix.value?.lLabels] }; dimForm.value = { s: [...curMatrix.value?.consequence], l: [...curMatrix.value?.probability] };
dimensionModal.value = true; dimensionModal.value = true;
} }
// 添加后果严重性 S // 添加后果严重性 S
const addS = () => { const addS = () => {
dimForm.value.s.push(""); dimForm.value.s.push({key:'S'+(dimForm.value.s.length+1), label:''});
} }
// 添加发生可能性 L // 添加发生可能性 L
const addL = () => { const addL = () => {
dimForm.value.l.push(""); dimForm.value.l.push({key:'L'+(dimForm.value.l.length+1), label:''});
}
// 删除后果严重性 S
const deleteS = (i:number) => {
dimForm.value.s.splice(i, 1);
}
// 删除发生可能性 L
const deleteL = (i:number) => {
dimForm.value.l.splice(i, 1);
}
// 添加等级配置
const addLevelConfig = () => {
curMatrix.value?.risk_grades.push({name:null,bg_color:'#333333',font_color:'#ffffff', min:null, max:null});
}
// 删除等级配置
const delLevelConfig = (index:number) => {
curMatrix.value?.risk_grades.splice(index, 1);
} }
// 矩阵维度分级定义保存 // 矩阵维度分级定义保存
const dimensionSave = () => { const dimensionSave = () => {
dimensionLoading.value = true; const hasEmptyLabel = dimForm.value.s.some((item:any) => item.label === '');
setTimeout(() => { if(hasEmptyLabel){
window.$message?.success("操作成功"); return window.$message?.warning("请完善后果严重性S信息");
dimensionLoading.value = false; }
const hasEmptyLabelL = dimForm.value.l.some((item:any) => item.label === '');
if(hasEmptyLabelL){
return window.$message?.warning("请完善发生可能性L信息");
}
curMatrix.value.consequence = [...dimForm.value.s];
curMatrix.value.probability = [...dimForm.value.l];
dimensionModal.value = false; dimensionModal.value = false;
}, 1000); }
// 保存风险矩阵
const saveMatrix = async () => {
if(curMatrix.value.risk_grades.length === 0){
return window.$message?.warning("请添加按分值区间定级信息");
}
const hasNull = curMatrix.value.risk_grades.some((item:any) =>
item.name === null || item.min === null || item.max === null
);
if(hasNull){
return window.$message?.warning("请完善按分值区间定级信息");
}
matrixLoading.value = true;
const {error} = await saveMatrixConfigApi(activeMatrix.value,{
consequence:curMatrix.value.consequence,
probability:curMatrix.value.probability,
risk_grades:curMatrix.value.risk_grades,
});
if(!error){
window.$message?.success("保存成功");
}
matrixLoading.value = false;
} }
// 获取配置 // 获取配置
@@ -407,15 +435,13 @@ const getConfig = async () => {
// 获取风险矩阵配置 // 获取风险矩阵配置
const matrixConfig = async () => { const matrixConfig = async () => {
const {data,error} = await matrixConfigApi(curMatrix.value?.tool); const {data,error} = await matrixConfigApi(activeMatrix.value);
if(!error){ if(!error){
// curMatrix.value = data; curMatrix.value = data;
console.log(data);
} }
} }
onMounted(() => { onMounted(() => {
curMatrix.value = matrices.value[activeMatrix.value];
matrixConfig(); matrixConfig();
getConfig(); getConfig();
}) })
@@ -714,36 +740,39 @@ onMounted(() => {
<Icon icon="akar-icons:edit" class="size-14px mr-1" /> <Icon icon="akar-icons:edit" class="size-14px mr-1" />
维度分级定义 维度分级定义
</NButton> </NButton>
<NButton size="small" type="primary" class="text-xs"> <NButton size="small" type="primary" class="text-xs" :loading="matrixLoading" @click="saveMatrix">
保存矩阵 保存矩阵
</NButton> </NButton>
</div> </div>
<div class="py-3 px-4"> <div class="py-3 px-4">
<NTabs type="segment" animated :on-update:value="handleTabChange"> <NTabs type="segment" animated :on-update:value="handleTabChange">
<NTabPane :name="0" tab="HAZOP分析矩阵"> <NTabPane name="HAZOP" tab="HAZOP分析矩阵">
<div class="flex flex-wrap items-start gap-6"> <div class="flex flex-wrap items-start gap-6">
<div class="shrink-0"> <div class="shrink-0">
<table class="border-collapse text-center text-[11px]"> <table class="border-collapse text-center text-[11px]">
<thead> <thead>
<tr> <tr>
<th class="px-1"></th> <th class="px-1"></th>
<th v-for="(lb, li) in curMatrix?.lLabels" :key="li" class="px-0.5 pb-1 font-normal leading-tight text-slate-500"> <th v-for="(lb, li) in curMatrix?.probability" :key="li" class="px-0.5 pb-1 font-normal leading-tight text-slate-500">
L{{ Number(li) + 1 }}<br />{{ lb }} {{ lb.key }}<br />{{ lb.label }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="row in 5" :key="row"> <tr v-for="(row,rowIndex) in curMatrix?.consequence" :key="row.key">
<td class="whitespace-nowrap pr-1.5 text-right leading-tight text-slate-500">S{{ 6 - row }} {{ curMatrix?.sLabels[5 - row] }}</td> <td class="whitespace-nowrap pr-1.5 text-right leading-tight text-slate-500">
<td v-for="col in 5" :key="col" class="p-0.5"> {{ curMatrix?.consequence[curMatrix?.consequence.length - (Number(rowIndex)+1)]?.key }}
{{ curMatrix?.consequence[curMatrix?.consequence.length - (Number(rowIndex)+1)]?.label }}
</td>
<td v-for="(col,colIndex) in curMatrix?.probability" :key="col.key" class="p-0.5">
<div <div
class="flex h-9 w-12 items-center justify-center rounded font-semibold" class="flex h-9 w-12 items-center justify-center rounded font-semibold"
:style="{ :style="{
backgroundColor:cellLevel(5 - row, col - 1)?.bgColor, backgroundColor:cellLevel(curMatrix?.consequence.length - Number(rowIndex), (Number(colIndex)+1))?.bg_color,
color:cellLevel(5 - row, col - 1)?.color, color:cellLevel(curMatrix?.consequence.length - Number(rowIndex), (Number(colIndex)+1))?.font_color,
}" }"
> >
{{ cellScore(5 - row, col - 1) }} {{ cellScore(curMatrix?.consequence.length - Number(rowIndex), (Number(colIndex)+1)) }}
</div> </div>
</td> </td>
</tr> </tr>
@@ -758,15 +787,15 @@ onMounted(() => {
<!-- 等级分值区间 --> <!-- 等级分值区间 -->
<div class="min-w-72 flex-1"> <div class="min-w-72 flex-1">
<div class="mb-2 text-xs text-slate-500 flex items-center gap-2"> <div class="mb-2 text-xs text-slate-500 flex items-center gap-2">
<NButton size="tiny" ghost type="primary"> <NButton size="tiny" ghost type="primary" @click="addLevelConfig">
<Icon icon="ic:round-plus" class="size-14px" />新增 <Icon icon="ic:round-plus" class="size-14px" />新增
</NButton> </NButton>
风险值 = 严重性 S × 可能性 L按分值区间定级 风险值 = 严重性 S × 可能性 L按分值区间定级
</div> </div>
<div class="space-y-2"> <div class="space-y-2">
<div v-for="lv in curMatrix?.levels" :key="lv.name" class="flex items-center gap-2 rounded-lg border px-2.5 py-2"> <div v-for="(lv,index) in curMatrix?.risk_grades" :key="lv.name" class="flex items-center gap-2 rounded-lg border px-2.5 py-2">
<span class="text-xs">背景</span> <span class="text-xs">背景</span>
<NColorPicker v-model:value="lv.bgColor"> <NColorPicker v-model:value="lv.bg_color">
<template #trigger="{ value, onClick, ref: triggerRef }"> <template #trigger="{ value, onClick, ref: triggerRef }">
<div <div
:ref="triggerRef" :ref="triggerRef"
@@ -780,7 +809,7 @@ onMounted(() => {
</template> </template>
</NColorPicker> </NColorPicker>
<span class="text-xs">字体</span> <span class="text-xs">字体</span>
<NColorPicker v-model:value="lv.color"> <NColorPicker v-model:value="lv.font_color">
<template #trigger="{ value, onClick, ref: triggerRef }"> <template #trigger="{ value, onClick, ref: triggerRef }">
<div <div
:ref="triggerRef" :ref="triggerRef"
@@ -793,21 +822,32 @@ onMounted(() => {
></div> ></div>
</template> </template>
</NColorPicker> </NColorPicker>
<NInput v-model:value="lv.name" size="small" class="!w-16 text-xs" /> <NSelect v-model:value="lv.name" :options="levelOptions" size="small" class="!w-20 text-xs" />
<span class="shrink-0 text-xs text-slate-400">分值</span> <span class="shrink-0 text-xs text-slate-400">分值</span>
<NInputNumber v-model:value="lv.min" :min="1" :max="25" size="small" :show-button="false" class="!w-14 text-center text-xs" /> <NInputNumber v-model:value="lv.min" :min="1" size="small" :show-button="false" class="!w-16 text-center text-xs" />
<span class="text-slate-400"></span> <span class="text-slate-400"></span>
<NInputNumber v-model:value="lv.max" :min="1" :max="25" size="small" :show-button="false" class="!w-14 text-center text-xs" /> <NInputNumber v-model:value="lv.max" :min="1" size="small" :show-button="false" class="!w-16 text-center text-xs" />
<NTag <NTag
v-if="lv.name"
size="small" size="small"
:color="{color: lv.bgColor, textColor: lv.color, borderColor: lv.bgColor}" :color="{color: lv.bg_color, textColor: lv.font_color, borderColor: lv.bg_color}"
class="ml-auto" class="ml-auto"
> >
{{ lv.name }}风险 {{ lv.name }}风险
</NTag> </NTag>
<NButton text type="error"> <NPopconfirm
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
@positive-click="delLevelConfig(Number(index))"
>
<template #trigger>
<NButton text type="error" :class="lv.name?'':'ml-auto'">
<Icon icon="akar-icons:circle-minus" class="size-16px" /> <Icon icon="akar-icons:circle-minus" class="size-16px" />
</NButton> </NButton>
</template>
确定删除吗
</NPopconfirm>
</div> </div>
</div> </div>
<p class="mt-2.5 text-[11px] text-slate-400"> <p class="mt-2.5 text-[11px] text-slate-400">
@@ -816,24 +856,33 @@ onMounted(() => {
</div> </div>
</div> </div>
</NTabPane> </NTabPane>
<NTabPane :name="1" tab="JSA分析矩阵"> <NTabPane name="JSA" tab="JSA分析矩阵">
<div class="flex flex-wrap items-start gap-6"> <div class="flex flex-wrap items-start gap-6">
<div class="shrink-0"> <div class="shrink-0">
<table class="border-collapse text-center text-[11px]"> <table class="border-collapse text-center text-[11px]">
<thead> <thead>
<tr> <tr>
<th class="px-1"></th> <th class="px-1"></th>
<th v-for="(lb, li) in curMatrix?.lLabels" :key="li" class="px-0.5 pb-1 font-normal leading-tight text-slate-500"> <th v-for="(lb, li) in curMatrix?.probability" :key="li" class="px-0.5 pb-1 font-normal leading-tight text-slate-500">
L{{ li + 1 }}<br />{{ lb }} {{ lb.key }}<br />{{ lb.label }}
</th> </th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr v-for="row in 5" :key="row"> <tr v-for="(row,rowIndex) in curMatrix?.consequence" :key="row.key">
<td class="whitespace-nowrap pr-1.5 text-right leading-tight text-slate-500">S{{ 6 - row }} {{ curMatrix?.sLabels[5 - row] }}</td> <td class="whitespace-nowrap pr-1.5 text-right leading-tight text-slate-500">
<td v-for="col in 5" :key="col" class="p-0.5"> {{ curMatrix?.consequence[curMatrix?.consequence.length - (Number(rowIndex)+1)]?.key }}
<div class="flex h-9 w-12 items-center justify-center rounded border font-semibold" :class="cellLevel(5 - row, col - 1)?.cls"> {{ curMatrix?.consequence[curMatrix?.consequence.length - (Number(rowIndex)+1)]?.label }}
{{ cellScore(5 - row, col - 1) }} </td>
<td v-for="(col,colIndex) in curMatrix?.probability" :key="col.key" class="p-0.5">
<div
class="flex h-9 w-12 items-center justify-center rounded font-semibold"
:style="{
backgroundColor:cellLevel(curMatrix?.consequence.length - Number(rowIndex), (Number(colIndex)+1))?.bg_color,
color:cellLevel(curMatrix?.consequence.length - Number(rowIndex), (Number(colIndex)+1))?.font_color,
}"
>
{{ cellScore(curMatrix?.consequence.length - Number(rowIndex), (Number(colIndex)+1)) }}
</div> </div>
</td> </td>
</tr> </tr>
@@ -847,65 +896,58 @@ onMounted(() => {
<!-- 等级分值区间 --> <!-- 等级分值区间 -->
<div class="min-w-72 flex-1"> <div class="min-w-72 flex-1">
<div class="mb-2 text-xs text-slate-500">风险值 = 严重性 S × 可能性 L5×5按分值区间定级</div> <div class="mb-2 text-xs text-slate-500 flex items-center gap-2">
<NButton size="tiny" ghost type="primary" @click="addLevelConfig">
<Icon icon="ic:round-plus" class="size-14px" />新增
</NButton>
风险值 = 严重性 S × 可能性 L按分值区间定级
</div>
<div class="space-y-2"> <div class="space-y-2">
<div v-for="lv in curMatrix?.levels" :key="lv.name" class="flex items-center gap-2 rounded-lg border px-2.5 py-2"> <div v-for="(lv,index) in curMatrix?.risk_grades" :key="lv.name" class="flex items-center gap-2 rounded-lg border px-2.5 py-2">
<span class="h-3 w-3 shrink-0 rounded-sm border" :class="lv.cls"></span> <span class="text-xs">背景</span>
<NInput v-model:value="lv.name" size="small" class="!w-16 text-xs" /> <NColorPicker v-model:value="lv.bg_color">
<template #trigger="{ value, onClick, ref: triggerRef }">
<div
:ref="triggerRef"
class="h-4 w-4 rounded-sm border cursor-pointer"
:style="{
backgroundColor: value || '#000',
cursor: 'pointer',
}"
@click="onClick"
></div>
</template>
</NColorPicker>
<span class="text-xs">字体</span>
<NColorPicker v-model:value="lv.font_color">
<template #trigger="{ value, onClick, ref: triggerRef }">
<div
:ref="triggerRef"
class="h-4 w-4 rounded-sm border cursor-pointer"
:style="{
backgroundColor: value || '#000',
cursor: 'pointer',
}"
@click="onClick"
></div>
</template>
</NColorPicker>
<NSelect v-model:value="lv.name" :options="levelOptions" size="small" class="!w-20 text-xs" />
<span class="shrink-0 text-xs text-slate-400">分值</span> <span class="shrink-0 text-xs text-slate-400">分值</span>
<NInputNumber v-model:value="lv.min" :min="1" :max="25" size="small" :show-button="false" class="!w-14 text-center text-xs" /> <NInputNumber v-model:value="lv.min" :min="1" size="small" :show-button="false" class="!w-16 text-center text-xs" />
<span class="text-slate-400"></span> <span class="text-slate-400"></span>
<NInputNumber v-model:value="lv.max" :min="1" :max="25" size="small" :show-button="false" class="!w-14 text-center text-xs" /> <NInputNumber v-model:value="lv.max" :min="1" size="small" :show-button="false" class="!w-16 text-center text-xs" />
<NTag size="small" :class="lv.cls" class="ml-auto">{{ lv.name }}风险</NTag> <NTag
</div> v-if="lv.name"
</div> size="small"
<p class="mt-2.5 text-[11px] text-slate-400"> :color="{color: lv.bg_color, textColor: lv.font_color, borderColor: lv.bg_color}"
各分析方法独立维护矩阵与维度分级风险分析记录表按所选工具对应的矩阵自动定级分值区间不得重叠须落在 125 在途分析记录按原矩阵保留定级快照 class="ml-auto"
</p> >
</div> {{ lv.name }}风险
</div> </NTag>
</NTabPane> <NButton text type="error" :class="lv.name?'':'ml-auto'" @click="delLevelConfig(Number(index))">
<NTabPane :name="2" tab="SCL分析矩阵"> <Icon icon="akar-icons:circle-minus" class="size-16px" />
<div class="flex flex-wrap items-start gap-6"> </NButton>
<div class="shrink-0">
<table class="border-collapse text-center text-[11px]">
<thead>
<tr>
<th class="px-1"></th>
<th v-for="(lb, li) in curMatrix?.lLabels" :key="li" class="px-0.5 pb-1 font-normal leading-tight text-slate-500">
L{{ li + 1 }}<br />{{ lb }}
</th>
</tr>
</thead>
<tbody>
<tr v-for="row in 5" :key="row">
<td class="whitespace-nowrap pr-1.5 text-right leading-tight text-slate-500">S{{ 6 - row }} {{ curMatrix?.sLabels[5 - row] }}</td>
<td v-for="col in 5" :key="col" class="p-0.5">
<div class="flex h-9 w-12 items-center justify-center rounded border font-semibold" :class="cellLevel(5 - row, col - 1)?.cls">
{{ cellScore(5 - row, col - 1) }}
</div>
</td>
</tr>
</tbody>
</table>
<div class="mt-1.5 flex justify-between text-[11px] text-slate-400">
<span>纵轴后果严重性 S</span>
<span>横轴发生可能性 L</span>
</div>
</div>
<!-- 等级分值区间 -->
<div class="min-w-72 flex-1">
<div class="mb-2 text-xs text-slate-500">风险值 = 严重性 S × 可能性 L5×5按分值区间定级</div>
<div class="space-y-2">
<div v-for="lv in curMatrix?.levels" :key="lv.name" class="flex items-center gap-2 rounded-lg border px-2.5 py-2">
<span class="h-3 w-3 shrink-0 rounded-sm border" :class="lv.cls"></span>
<NInput v-model:value="lv.name" size="small" class="!w-16 text-xs" />
<span class="shrink-0 text-xs text-slate-400">分值</span>
<NInputNumber v-model:value="lv.min" :min="1" :max="25" size="small" :show-button="false" class="!w-14 text-center text-xs" />
<span class="text-slate-400"></span>
<NInputNumber v-model:value="lv.max" :min="1" :max="25" size="small" :show-button="false" class="!w-14 text-center text-xs" />
<NTag size="small" :class="lv.cls" class="ml-auto">{{ lv.name }}风险</NTag>
</div> </div>
</div> </div>
<p class="mt-2.5 text-[11px] text-slate-400"> <p class="mt-2.5 text-[11px] text-slate-400">
@@ -1092,39 +1134,50 @@ onMounted(() => {
<div class="space-y-6"> <div class="space-y-6">
<div> <div>
<div class="mb-1.5 text-xs font-semibold text-slate-600 flex items-center"> <div class="mb-1.5 text-xs font-semibold text-slate-600 flex items-center">
后果严重性 SS1 S5 递增 后果严重性 S{{dimForm.s[0].key}} {{dimForm.s[dimForm.s.length-1].key}} 递增
<NButton size="tiny" ghost type="primary" @click="addS"> <NButton size="tiny" ghost type="primary" @click="addS">
<Icon icon="ic:round-plus" class="size-14px" />新增 <Icon icon="ic:round-plus" class="size-14px" />新增
</NButton> </NButton>
</div> </div>
<div class="grid grid-cols-5 gap-1.5 mt-3"> <div class="grid grid-cols-5 gap-1.5 mt-3">
<label v-for="(_, i) in dimForm.s" :key="'s' + i" class="text-center text-xs text-slate-400"> <label v-for="(item, i) in dimForm.s" :key="'s' + i" class="text-center text-xs text-slate-400">
<div class="flex items-center justify-center gap-2 mb-1"> <div class="flex items-center justify-center gap-2 mb-1">
S{{ i + 1 }} {{ item.key }}
<NPopconfirm
v-if="dimForm.s.length > 5"
positive-text="确定"
:positiveButtonProps="{ size: 'tiny' }"
:negativeButtonProps="{ size: 'tiny' }"
@positive-click="deleteS(i)"
>
<template #trigger>
<NButton text type="error"> <NButton text type="error">
<Icon icon="akar-icons:circle-minus" class="size-16px" /> <Icon icon="akar-icons:circle-minus" class="size-16px" />
</NButton> </NButton>
</template>
确定删除吗
</NPopconfirm>
</div> </div>
<NInput v-model:value="dimForm.s[i]" size="small" class="mt-0.5 text-center text-xs" /> <NInput v-model:value="item.label" size="small" class="mt-0.5 text-center text-xs" />
</label> </label>
</div> </div>
</div> </div>
<div> <div>
<div class="mb-1.5 text-xs font-semibold text-slate-600 flex items-center"> <div class="mb-1.5 text-xs font-semibold text-slate-600 flex items-center">
发生可能性 LL1 L5 递增 发生可能性 L{{dimForm.l[0].key}} {{dimForm.l[dimForm.l.length-1].key}} 递增
<NButton size="tiny" ghost type="primary" @click="addL"> <NButton size="tiny" ghost type="primary" @click="addL">
<Icon icon="ic:round-plus" class="size-14px" />新增 <Icon icon="ic:round-plus" class="size-14px" />新增
</NButton> </NButton>
</div> </div>
<div class="grid grid-cols-5 gap-1.5 mt-3"> <div class="grid grid-cols-5 gap-1.5 mt-3">
<label v-for="(_, i) in dimForm.l" :key="'l' + i" class="text-center text-xs text-slate-400"> <label v-for="(item, i) in dimForm.l" :key="'l' + i" class="text-center text-xs text-slate-400">
<div class="flex items-center justify-center gap-2 mb-1"> <div class="flex items-center justify-center gap-2 mb-1">
L{{ i + 1 }} {{ item.key }}
<NButton text type="error"> <NButton v-if="dimForm.l.length > 5" text type="error" @click="deleteL(i)">
<Icon icon="akar-icons:circle-minus" class="size-16px" /> <Icon icon="akar-icons:circle-minus" class="size-16px" />
</NButton> </NButton>
</div> </div>
<NInput v-model:value="dimForm.l[i]" size="small" class="mt-0.5 text-center text-xs" /> <NInput v-model:value="item.label" size="small" class="mt-0.5 text-center text-xs" />
</label> </label>
</div> </div>
</div> </div>
@@ -1132,7 +1185,7 @@ onMounted(() => {
<template #footer> <template #footer>
<div class="flex justify-end gap-[10px]"> <div class="flex justify-end gap-[10px]">
<NButton size="small" @click="dimensionModal = false">取消</NButton> <NButton size="small" @click="dimensionModal = false">取消</NButton>
<NButton size="small" type="primary" :loading="dimensionLoading" @click="dimensionSave">确定</NButton> <NButton size="small" type="primary" @click="dimensionSave">确定</NButton>
</div> </div>
</template> </template>
</NModal> </NModal>