风险矩阵配置接口完成
This commit is contained in:
@@ -84,5 +84,13 @@ export function matrixConfigApi(bizType:string) {
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
// 保存风险矩阵配置
|
||||
export function saveMatrixConfigApi(bizType:string,data:any) {
|
||||
return request({
|
||||
url: `/api/risk-matrix/${bizType}`,
|
||||
method: 'put',
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ const form = ref<ApplyForm>({
|
||||
name: "", dept: "", mainChanges: [""], related: "", purposes: [], effect: "",
|
||||
type: "", level: "", duration: "", urgent: false, date: null, restoreDate: null,
|
||||
});
|
||||
const tab = ref<string>("risk");
|
||||
const tab = ref<string>("pre");
|
||||
const TABS = [
|
||||
{ id: "pre", name: "变更预识别", icon: 'lucide:sparkles' },
|
||||
{ id: "form", name: "变更申请表", icon: 'akar-icons:file' },
|
||||
|
||||
@@ -10,7 +10,8 @@ import {
|
||||
editSystemConfigApi,
|
||||
deleteSystemConfigApi,
|
||||
updateConfigApi,
|
||||
matrixConfigApi
|
||||
matrixConfigApi,
|
||||
saveMatrixConfigApi
|
||||
} from '@/service/api/system';
|
||||
|
||||
const appStore = useAppStore();
|
||||
@@ -273,6 +274,13 @@ const ruleOptions = ref<{label:string, value:string}[]>([
|
||||
{label:'按年度重置',value:'YEARLY'},
|
||||
{label:'连续不重置',value:'CONTINUE'},
|
||||
])
|
||||
const levelOptions = ref<{label:string, value:string | null}[]>([
|
||||
{label:'低',value:'低'},
|
||||
{label:'一般',value:'一般'},
|
||||
{label:'较高',value:'较高'},
|
||||
{label:'高',value:'高'},
|
||||
{label:'很高',value:'很高'},
|
||||
])
|
||||
|
||||
// 保存编号规则
|
||||
const saveRule = async () => {
|
||||
@@ -292,82 +300,102 @@ const saveRule = async () => {
|
||||
|
||||
// *************** 风险矩阵设置(按分析方法) ***************//
|
||||
|
||||
const matrixLoading = ref<boolean>(false);
|
||||
const dimensionModal = ref<boolean>(false);
|
||||
const dimensionLoading = ref<boolean>(false);
|
||||
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 dimForm = ref<{s:{key:string, label:string}[], l:{key:string, label:string}[]}>({ s: [], l: [] });
|
||||
// 当前选中的风险矩阵索引
|
||||
const activeMatrix = ref(0);
|
||||
const activeMatrix = ref('HAZOP');
|
||||
// 当前选中的风险矩阵
|
||||
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 sc = cellScore(s, l);
|
||||
return curMatrix.value?.levels.find((lv:{min:number,max:number}) => sc >= lv.min && sc <= lv.max);
|
||||
const info = findMatchingConfig(s*l);
|
||||
return info? info:null;
|
||||
}
|
||||
|
||||
// 风险矩阵tabs切换
|
||||
const handleTabChange = (v: number) => {
|
||||
const handleTabChange = (v: string) => {
|
||||
activeMatrix.value = v;
|
||||
curMatrix.value = matrices.value[v];
|
||||
matrixConfig();
|
||||
}
|
||||
|
||||
// 打开风险矩阵编辑弹窗
|
||||
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;
|
||||
}
|
||||
// 添加后果严重性 S
|
||||
const addS = () => {
|
||||
dimForm.value.s.push("");
|
||||
dimForm.value.s.push({key:'S'+(dimForm.value.s.length+1), label:''});
|
||||
}
|
||||
// 添加发生可能性 L
|
||||
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 = () => {
|
||||
dimensionLoading.value = true;
|
||||
setTimeout(() => {
|
||||
window.$message?.success("操作成功");
|
||||
dimensionLoading.value = false;
|
||||
const hasEmptyLabel = dimForm.value.s.some((item:any) => item.label === '');
|
||||
if(hasEmptyLabel){
|
||||
return window.$message?.warning("请完善后果严重性S信息");
|
||||
}
|
||||
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;
|
||||
}, 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 {data,error} = await matrixConfigApi(curMatrix.value?.tool);
|
||||
const {data,error} = await matrixConfigApi(activeMatrix.value);
|
||||
if(!error){
|
||||
// curMatrix.value = data;
|
||||
console.log(data);
|
||||
curMatrix.value = data;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
curMatrix.value = matrices.value[activeMatrix.value];
|
||||
matrixConfig();
|
||||
getConfig();
|
||||
})
|
||||
@@ -714,36 +740,39 @@ onMounted(() => {
|
||||
<Icon icon="akar-icons:edit" class="size-14px mr-1" />
|
||||
维度分级定义
|
||||
</NButton>
|
||||
<NButton size="small" type="primary" class="text-xs">
|
||||
<NButton size="small" type="primary" class="text-xs" :loading="matrixLoading" @click="saveMatrix">
|
||||
保存矩阵
|
||||
</NButton>
|
||||
</div>
|
||||
<div class="py-3 px-4">
|
||||
<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="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{{ Number(li) + 1 }}<br />{{ lb }}
|
||||
<th v-for="(lb, li) in curMatrix?.probability" :key="li" class="px-0.5 pb-1 font-normal leading-tight text-slate-500">
|
||||
{{ lb.key }}<br />{{ lb.label }}
|
||||
</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">
|
||||
<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">
|
||||
{{ 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
|
||||
class="flex h-9 w-12 items-center justify-center rounded font-semibold"
|
||||
:style="{
|
||||
backgroundColor:cellLevel(5 - row, col - 1)?.bgColor,
|
||||
color:cellLevel(5 - row, col - 1)?.color,
|
||||
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(5 - row, col - 1) }}
|
||||
{{ cellScore(curMatrix?.consequence.length - Number(rowIndex), (Number(colIndex)+1)) }}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -758,15 +787,15 @@ onMounted(() => {
|
||||
<!-- 等级分值区间 -->
|
||||
<div class="min-w-72 flex-1">
|
||||
<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" />新增
|
||||
</NButton>
|
||||
风险值 = 严重性 S × 可能性 L,按分值区间定级:
|
||||
</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">
|
||||
<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>
|
||||
<NColorPicker v-model:value="lv.bgColor">
|
||||
<NColorPicker v-model:value="lv.bg_color">
|
||||
<template #trigger="{ value, onClick, ref: triggerRef }">
|
||||
<div
|
||||
:ref="triggerRef"
|
||||
@@ -780,7 +809,7 @@ onMounted(() => {
|
||||
</template>
|
||||
</NColorPicker>
|
||||
<span class="text-xs">字体</span>
|
||||
<NColorPicker v-model:value="lv.color">
|
||||
<NColorPicker v-model:value="lv.font_color">
|
||||
<template #trigger="{ value, onClick, ref: triggerRef }">
|
||||
<div
|
||||
:ref="triggerRef"
|
||||
@@ -793,21 +822,32 @@ onMounted(() => {
|
||||
></div>
|
||||
</template>
|
||||
</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>
|
||||
<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>
|
||||
<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
|
||||
v-if="lv.name"
|
||||
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"
|
||||
>
|
||||
{{ lv.name }}风险
|
||||
</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" />
|
||||
</NButton>
|
||||
</template>
|
||||
确定删除吗?
|
||||
</NPopconfirm>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2.5 text-[11px] text-slate-400">
|
||||
@@ -816,24 +856,33 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
</NTabPane>
|
||||
<NTabPane :name="1" tab="JSA分析矩阵">
|
||||
<NTabPane name="JSA" tab="JSA分析矩阵">
|
||||
<div class="flex flex-wrap items-start gap-6">
|
||||
<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 v-for="(lb, li) in curMatrix?.probability" :key="li" class="px-0.5 pb-1 font-normal leading-tight text-slate-500">
|
||||
{{ lb.key }}<br />{{ lb.label }}
|
||||
</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) }}
|
||||
<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">
|
||||
{{ 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
|
||||
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>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -847,65 +896,58 @@ onMounted(() => {
|
||||
|
||||
<!-- 等级分值区间 -->
|
||||
<div class="min-w-72 flex-1">
|
||||
<div class="mb-2 text-xs text-slate-500">风险值 = 严重性 S × 可能性 L(5×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 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" />
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<p class="mt-2.5 text-[11px] text-slate-400">
|
||||
各分析方法独立维护矩阵与维度分级;风险分析记录表按所选工具对应的矩阵自动定级。分值区间不得重叠、须落在 1–25 内;在途分析记录按原矩阵保留定级快照。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</NTabPane>
|
||||
<NTabPane :name="2" tab="SCL分析矩阵">
|
||||
<div class="flex flex-wrap items-start gap-6">
|
||||
<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 × 可能性 L(5×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>
|
||||
<NInputNumber v-model:value="lv.max" :min="1" size="small" :show-button="false" class="!w-16 text-center text-xs" />
|
||||
<NTag
|
||||
v-if="lv.name"
|
||||
size="small"
|
||||
:color="{color: lv.bg_color, textColor: lv.font_color, borderColor: lv.bg_color}"
|
||||
class="ml-auto"
|
||||
>
|
||||
{{ lv.name }}风险
|
||||
</NTag>
|
||||
<NButton text type="error" :class="lv.name?'':'ml-auto'" @click="delLevelConfig(Number(index))">
|
||||
<Icon icon="akar-icons:circle-minus" class="size-16px" />
|
||||
</NButton>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2.5 text-[11px] text-slate-400">
|
||||
@@ -1092,39 +1134,50 @@ onMounted(() => {
|
||||
<div class="space-y-6">
|
||||
<div>
|
||||
<div class="mb-1.5 text-xs font-semibold text-slate-600 flex items-center">
|
||||
后果严重性 S(S1 → S5 递增)
|
||||
后果严重性 S({{dimForm.s[0].key}} → {{dimForm.s[dimForm.s.length-1].key}} 递增)
|
||||
<NButton size="tiny" ghost type="primary" @click="addS">
|
||||
<Icon icon="ic:round-plus" class="size-14px" />新增
|
||||
</NButton>
|
||||
</div>
|
||||
<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">
|
||||
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">
|
||||
<Icon icon="akar-icons:circle-minus" class="size-16px" />
|
||||
</NButton>
|
||||
</template>
|
||||
确定删除吗?
|
||||
</NPopconfirm>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="mb-1.5 text-xs font-semibold text-slate-600 flex items-center">
|
||||
发生可能性 L(L1 → L5 递增)
|
||||
发生可能性 L({{dimForm.l[0].key}} → {{dimForm.l[dimForm.l.length-1].key}} 递增)
|
||||
<NButton size="tiny" ghost type="primary" @click="addL">
|
||||
<Icon icon="ic:round-plus" class="size-14px" />新增
|
||||
</NButton>
|
||||
</div>
|
||||
<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">
|
||||
L{{ i + 1 }}
|
||||
<NButton text type="error">
|
||||
{{ item.key }}
|
||||
<NButton v-if="dimForm.l.length > 5" text type="error" @click="deleteL(i)">
|
||||
<Icon icon="akar-icons:circle-minus" class="size-16px" />
|
||||
</NButton>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1132,7 +1185,7 @@ onMounted(() => {
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-[10px]">
|
||||
<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>
|
||||
</template>
|
||||
</NModal>
|
||||
|
||||
Reference in New Issue
Block a user