系统配置静态页完成
This commit is contained in:
@@ -9,29 +9,158 @@ const appStore = useAppStore();
|
||||
const themeStore = useThemeStore();
|
||||
const gap = computed(() => (appStore.isMobile ? 0 : 16));
|
||||
|
||||
const aiEnabled = ref<boolean>(true);
|
||||
// AI 辅助功能配置
|
||||
const aiEnabled = ref<boolean>(true);
|
||||
const aiConfig = ref<{address:string, mode:number|null, key:string,timeout:null|number}>({
|
||||
address:'',
|
||||
mode:null,
|
||||
key:'',
|
||||
timeout:null,
|
||||
})
|
||||
const aiTested = ref<string>("none");
|
||||
const modeOptions = ref<{label:string, value:number}[]>([
|
||||
{label:'kimi-k2(企业私有化部署)',value:1}
|
||||
])
|
||||
const testing = ref<boolean>(false);
|
||||
const showLog = ref<boolean>(false);
|
||||
const AI_LOGS = [
|
||||
{ scene: "AI-01 变更识别", user: "张工艺", change: "MOC-2026-R01-0041", time: "08-24 09:12", cost: "1.8s", adopted: "修改后采纳" },
|
||||
{ scene: "AI-03 风险预分析", user: "张工艺", change: "MOC-2026-R01-0041", time: "08-24 09:15", cost: "2.4s", adopted: "采纳" },
|
||||
{ scene: "AI-07 审批辅助", user: "李主任", change: "MOC-2026-R01-0039", time: "08-24 08:47", cost: "1.2s", adopted: "采纳" },
|
||||
{ scene: "AI-06 PSSR 生成", user: "张工艺", change: "MOC-2026-R02-0052", time: "08-23 16:20", cost: "2.1s", adopted: "未采纳" },
|
||||
{ scene: "AI-09 关闭辅助判定", user: "系统管理员", change: "MOC-2026-R01-0035", time: "08-23 15:02", cost: "1.5s", adopted: "采纳" },
|
||||
];
|
||||
|
||||
// 变更类型
|
||||
const typeRef = ref<any>(null);
|
||||
const typeModal = ref<boolean>(false);
|
||||
const typeLoading = ref<boolean>(false);
|
||||
const currentType = ref<string>('add');
|
||||
const typeInfo = ref<{id:number, name:string, desc?:string}>({
|
||||
id:0,
|
||||
name:'',
|
||||
desc:'',
|
||||
})
|
||||
const typeRules = {
|
||||
name:{required:true, message:'请输入类型名称', trigger:'blur'},
|
||||
}
|
||||
const typeList = ref<{id:number, name:string, desc?:string}[]>([
|
||||
{id:1,name:'工艺', desc:'工艺参数、配方、操作条件、操作规程等工艺技术类变更'},
|
||||
{id:2,name:'设备', desc:'设备本体、附件、材质、规格、备件等硬件类变更'},
|
||||
{id:3,name:'管理', desc:'制度、职责、程序、组织与人员等管理类变更'},
|
||||
])
|
||||
// 新增类型
|
||||
const addType = () => {
|
||||
typeInfo.value = {
|
||||
id:0,
|
||||
name:'',
|
||||
desc:'',
|
||||
}
|
||||
currentType.value = 'add';
|
||||
typeModal.value = true;
|
||||
}
|
||||
// 编辑类型
|
||||
const editType = (row:any) => {
|
||||
typeInfo.value = {
|
||||
id:row.id,
|
||||
name:row.name,
|
||||
desc:row.desc,
|
||||
}
|
||||
currentType.value = 'edit';
|
||||
typeModal.value = true;
|
||||
}
|
||||
// 删除类型
|
||||
const deleteType = (item:any) => {
|
||||
typeList.value = typeList.value.filter((i:any) => i.id !== item.id);
|
||||
}
|
||||
// 保存类型
|
||||
const typeSave = async (e:MouseEvent) => {
|
||||
e.preventDefault()
|
||||
typeRef.value?.validate((errors:any) => {
|
||||
if (!errors) {
|
||||
typeLoading.value = true;
|
||||
try {
|
||||
// await addTypeApi(typeInfo.value);
|
||||
window.$message?.success('操作成功')
|
||||
typeLoading.value = false;
|
||||
typeModal.value = false;
|
||||
} finally {
|
||||
typeLoading.value = false;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
// 变更等级
|
||||
const levelRef = ref<any>(null);
|
||||
const levelModal = ref<boolean>(false);
|
||||
const levelLoading = ref<boolean>(false);
|
||||
const currentLevel = ref<string>('add');
|
||||
const toolsOptions = ref<{label:string, value:number}[]>([
|
||||
{label:'AI预分析',value:1},
|
||||
{label:'检查表法',value:2},
|
||||
{label:'HAZOP',value:3},
|
||||
{label:'JSA',value:4},
|
||||
{label:'SCL',value:5},
|
||||
])
|
||||
const levelInfo = ref<{id:number, name:string, way:string,tools:number[]}>({
|
||||
id:0,
|
||||
name:'',
|
||||
way:'',
|
||||
tools:[],
|
||||
})
|
||||
const levelRules = {
|
||||
name:{required:true, message:'请输入等级名称', trigger:'blur'},
|
||||
way:{required:true, message:'请输入等级判定方式', trigger:'blur'},
|
||||
tools:{type:'array', required:true, message:'请选择分析工具', trigger:['blur','change']},
|
||||
}
|
||||
const levelList = ref<{id:number, name:string, way:string,tools:{id:number, name:string}[]}[]>([
|
||||
{id:1,name:'一般', way:'等级评分< 20 分',tools:[{id:1,name:'AI预分析'},{id:2,name:'检查表法'}]},
|
||||
{id:2,name:'重要', way:'等级评分 > 20 分',tools:[{id:1,name:'AI预分析'},{id:2,name:'HAZOP'},{id:3,name:'JSA'},{id:4,name:'SCL'}]},
|
||||
])
|
||||
// 新增等级
|
||||
const addLevel = () => {
|
||||
levelInfo.value = {
|
||||
id:0,
|
||||
name:'',
|
||||
way:'',
|
||||
tools:[],
|
||||
}
|
||||
currentLevel.value = 'add';
|
||||
levelModal.value = true;
|
||||
}
|
||||
// 编辑类型
|
||||
const editLevel = (row:any) => {
|
||||
levelInfo.value = {
|
||||
id:row.id,
|
||||
name:row.name,
|
||||
way:row.way,
|
||||
tools:row.tools.map((item:any) => (item.id)),
|
||||
}
|
||||
currentLevel.value = 'edit';
|
||||
levelModal.value = true;
|
||||
}
|
||||
// 删除类型
|
||||
const deleteLevel = (item:any) => {
|
||||
levelList.value = levelList.value.filter((i:any) => i.id !== item.id);
|
||||
}
|
||||
// 保存类型
|
||||
const levelSave = async (e:MouseEvent) => {
|
||||
e.preventDefault()
|
||||
levelRef.value?.validate((errors:any) => {
|
||||
if (!errors) {
|
||||
levelLoading.value = true;
|
||||
try {
|
||||
// await addLevelApi(levelInfo.value);
|
||||
window.$message?.success('操作成功')
|
||||
levelLoading.value = false;
|
||||
levelModal.value = false;
|
||||
} finally {
|
||||
levelLoading.value = false;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 变更编号规则
|
||||
const ruleInfo = ref<{prefix:string, year:null|string, code:number|null, digit:number|null, rule:number|null}>({
|
||||
prefix:'MOC',
|
||||
@@ -50,14 +179,91 @@ const ruleOptions = ref<{label:string, value:number}[]>([
|
||||
{label:'按年度+装置代码重置',value:1}
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ---------- 风险矩阵设置(按分析方法) ----------
|
||||
const dimensionModal = ref<boolean>(false);
|
||||
const dimensionLoading = ref<boolean>(false);
|
||||
const dimForm = ref({ s: [], l: [] });
|
||||
const LV_CLS = [
|
||||
"border-emerald-300 bg-emerald-100 text-emerald-700",
|
||||
"border-yellow-300 bg-yellow-100 text-yellow-700",
|
||||
"border-orange-300 bg-orange-100 text-orange-700",
|
||||
"border-red-300 bg-red-100 text-red-700",
|
||||
];
|
||||
const matrices = ref([
|
||||
{
|
||||
tool: "HAZOP",
|
||||
sLabels: ["轻微", "一般", "较重", "严重", "灾难"],
|
||||
lLabels: ["极少发生", "较少发生", "偶尔发生", "可能发生", "频繁发生"],
|
||||
levels: [
|
||||
{ name: "低", min: 1, max: 4, cls: LV_CLS[0] },
|
||||
{ name: "一般", min: 5, max: 9, cls: LV_CLS[1] },
|
||||
{ name: "较大", min: 10, max: 16, cls: LV_CLS[2] },
|
||||
{ name: "重大", min: 17, max: 25, cls: LV_CLS[3] },
|
||||
],
|
||||
},
|
||||
{
|
||||
tool: "JSA",
|
||||
sLabels: ["轻微伤害", "轻伤", "重伤", "单人死亡", "多人死亡"],
|
||||
lLabels: ["极不可能", "不太可能", "有可能", "较可能", "很可能"],
|
||||
levels: [
|
||||
{ name: "低", min: 1, max: 6, cls: LV_CLS[0] },
|
||||
{ name: "一般", min: 7, max: 12, cls: LV_CLS[1] },
|
||||
{ name: "较大", min: 13, max: 19, cls: LV_CLS[2] },
|
||||
{ name: "重大", min: 20, max: 25, cls: LV_CLS[3] },
|
||||
],
|
||||
},
|
||||
{
|
||||
tool: "SCL",
|
||||
sLabels: ["轻微影响", "一般影响", "较大影响", "严重影响", "灾难性影响"],
|
||||
lLabels: ["极少", "较少", "偶尔", "可能", "经常"],
|
||||
levels: [
|
||||
{ name: "低", min: 1, max: 2, cls: LV_CLS[0] },
|
||||
{ name: "一般", min: 3, max: 6, cls: LV_CLS[1] },
|
||||
{ name: "较大", min: 7, max: 12, cls: LV_CLS[2] },
|
||||
{ name: "重大", min: 13, max: 25, cls: LV_CLS[3] },
|
||||
],
|
||||
},
|
||||
]);
|
||||
const activeMatrix = ref(0);
|
||||
const curMatrix = computed(() => matrices.value[activeMatrix.value]);
|
||||
const cellScore = (s:number, l:number) => (s + 1) * (l + 1);
|
||||
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);
|
||||
}
|
||||
// AI 辅助功能切换
|
||||
const toggle = (v: boolean) => {
|
||||
window.$message?.success(v ? "AI 辅助功能已启用" : "AI 辅助功能已关闭");
|
||||
aiEnabled.value = v;
|
||||
}
|
||||
const testConn = () => {
|
||||
testing.value = true;
|
||||
setTimeout(() => {
|
||||
testing.value = false;
|
||||
aiTested.value = "ok";
|
||||
window.$message?.success(`连接测试通过:${aiConfig.value.mode} 响应正常(耗时 0.8s)`);
|
||||
}, 900);
|
||||
}
|
||||
const saveAiCfg = () => {
|
||||
window.$message?.success("AI 接口配置已保存(配置变更留痕,立即生效)");
|
||||
}
|
||||
const dimensionSave = () => {
|
||||
dimensionLoading.value = true;
|
||||
setTimeout(() => {
|
||||
window.$message?.success("操作成功");
|
||||
dimensionLoading.value = false;
|
||||
dimensionModal.value = false;
|
||||
}, 1000);
|
||||
}
|
||||
const openDimEdit = () => {
|
||||
dimForm.value = { s: [...curMatrix.value.sLabels], l: [...curMatrix.value.lLabels] };
|
||||
dimensionModal.value = true;
|
||||
}
|
||||
|
||||
// tabs 切换
|
||||
const handleTabChange = (v: number) => {
|
||||
activeMatrix.value = v;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
@@ -96,6 +302,11 @@ const toggle = (v: boolean) => {
|
||||
当前状态:{{ aiEnabled ? "已启用 —— 变更申请界面提供 AI 变更识别与申请表生成" : "已关闭 —— 变更申请界面为纯手动模式" }}
|
||||
</div>
|
||||
<div class="space-y-2 border rounded-md p-3 mt-3">
|
||||
<div class="flex items-center">
|
||||
<Icon icon="bx:plug" class="size-14px text-slate-400 mr-1" />
|
||||
AI 接口配置
|
||||
<NTag v-if="aiTested === 'ok'" size="small" type="success" class="ml-auto">连接正常</NTag>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<p class="w-100px text-left">接口地址</p>
|
||||
<div class="flex-1">
|
||||
@@ -121,9 +332,9 @@ const toggle = (v: boolean) => {
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<NButton size="small" type="primary" class="text-xs">测试连接</NButton>
|
||||
<NButton size="small" class="text-xs">保存配置</NButton>
|
||||
<NButton size="small" class="text-xs">
|
||||
<NButton size="small" type="primary" class="text-xs" :loading="testing" @click="testConn">测试连接</NButton>
|
||||
<NButton size="small" class="text-xs" @click="saveAiCfg">保存配置</NButton>
|
||||
<NButton size="small" class="text-xs" @click="showLog = true">
|
||||
<Icon icon="akar-icons:file" class="size-14px mr-1" />
|
||||
调用记录查询
|
||||
</NButton>
|
||||
@@ -140,7 +351,7 @@ const toggle = (v: boolean) => {
|
||||
<Icon icon="ep:setting" class="size-16px mr-1" />
|
||||
变更类型设置(支持自定义)
|
||||
</div>
|
||||
<NButton size="small" type="primary" class="text-xs">
|
||||
<NButton size="small" type="primary" class="text-xs" @click="addType">
|
||||
<Icon icon="ic:round-plus" class="size-16px" />新增类型
|
||||
</NButton>
|
||||
</div>
|
||||
@@ -153,12 +364,22 @@ const toggle = (v: boolean) => {
|
||||
<p class="flex-1">{{item.desc}}</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<NButton text type="primary" class="text-xs">
|
||||
<NButton text type="primary" class="text-xs" @click="editType(item)">
|
||||
<Icon icon="akar-icons:edit" class="size-14px" />编辑
|
||||
</NButton>
|
||||
<NButton text type="error" class="text-xs">
|
||||
<Icon icon="ep:delete" class="size-12px" />删除
|
||||
</NButton>
|
||||
<NPopconfirm
|
||||
positive-text="确定"
|
||||
:positiveButtonProps="{ size: 'tiny' }"
|
||||
:negativeButtonProps="{ size: 'tiny' }"
|
||||
@positive-click="deleteType(item)"
|
||||
>
|
||||
<template #trigger>
|
||||
<NButton text type="error" class="text-xs">
|
||||
<Icon icon="ep:delete" class="size-12px" />删除
|
||||
</NButton>
|
||||
</template>
|
||||
确定删除吗?
|
||||
</NPopconfirm>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -188,7 +409,7 @@ const toggle = (v: boolean) => {
|
||||
<Icon icon="ep:setting" class="size-16px mr-1" />
|
||||
变更等级设定(支持自定义)
|
||||
</div>
|
||||
<NButton size="small" type="primary" class="text-xs">
|
||||
<NButton size="small" type="primary" class="text-xs" @click="addLevel">
|
||||
<Icon icon="ic:round-plus" class="size-16px" />新增等级
|
||||
</NButton>
|
||||
</div>
|
||||
@@ -202,12 +423,22 @@ const toggle = (v: boolean) => {
|
||||
<p class="flex-1">判定方式:<b>{{item.way}}</b></p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<NButton text type="primary" class="text-xs">
|
||||
<NButton text type="primary" class="text-xs" @click="editLevel(item)">
|
||||
<Icon icon="akar-icons:edit" class="size-14px" />编辑
|
||||
</NButton>
|
||||
<NButton text type="error" class="text-xs">
|
||||
<Icon icon="ep:delete" class="size-12px" />删除
|
||||
</NButton>
|
||||
<NPopconfirm
|
||||
positive-text="确定"
|
||||
:positiveButtonProps="{ size: 'tiny' }"
|
||||
:negativeButtonProps="{ size: 'tiny' }"
|
||||
@positive-click="deleteLevel(item)"
|
||||
>
|
||||
<template #trigger>
|
||||
<NButton text type="error" class="text-xs">
|
||||
<Icon icon="ep:delete" class="size-12px" />删除
|
||||
</NButton>
|
||||
</template>
|
||||
确定删除吗?
|
||||
</NPopconfirm>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap mt-2">
|
||||
@@ -302,7 +533,7 @@ const toggle = (v: boolean) => {
|
||||
<Icon icon="icon-park-outline:all-application" class="size-16px mr-1" />
|
||||
风险矩阵设置(按分析方法)
|
||||
</div>
|
||||
<NButton size="small" class="text-xs">
|
||||
<NButton size="small" class="text-xs" @click="openDimEdit">
|
||||
<Icon icon="akar-icons:edit" class="size-14px mr-1" />
|
||||
维度分级定义
|
||||
</NButton>
|
||||
@@ -311,21 +542,294 @@ const toggle = (v: boolean) => {
|
||||
</NButton>
|
||||
</div>
|
||||
<div class="py-3 px-4">
|
||||
<NTabs type="segment" animated>
|
||||
<NTabPane name="chap1" tab="HAZOP分析矩阵">
|
||||
HAZOP分析矩阵
|
||||
<NTabs type="segment" animated :on-update:value="handleTabChange">
|
||||
<NTabPane :name="0" 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{{ 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>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2.5 text-[11px] text-slate-400">
|
||||
各分析方法独立维护矩阵与维度分级;风险分析记录表按所选工具对应的矩阵自动定级。分值区间不得重叠、须落在 1–25 内;在途分析记录按原矩阵保留定级快照。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</NTabPane>
|
||||
<NTabPane name="chap2" tab="JSA分析矩阵">
|
||||
JSA分析矩阵
|
||||
<NTabPane :name="1" 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>
|
||||
</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>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2.5 text-[11px] text-slate-400">
|
||||
各分析方法独立维护矩阵与维度分级;风险分析记录表按所选工具对应的矩阵自动定级。分值区间不得重叠、须落在 1–25 内;在途分析记录按原矩阵保留定级快照。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</NTabPane>
|
||||
<NTabPane name="chap3" tab="SCL分析矩阵">
|
||||
SCL分析矩阵
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
<p class="mt-2.5 text-[11px] text-slate-400">
|
||||
各分析方法独立维护矩阵与维度分级;风险分析记录表按所选工具对应的矩阵自动定级。分值区间不得重叠、须落在 1–25 内;在途分析记录按原矩阵保留定级快照。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</NTabPane>
|
||||
</NTabs>
|
||||
</div>
|
||||
</NCard>
|
||||
</NGi>
|
||||
</NGrid>
|
||||
|
||||
<!-- AI调用记录查询 -->
|
||||
<NDrawer v-model:show="showLog" :width="700" placement="right">
|
||||
<NDrawerContent title="调用记录查询" closable>
|
||||
<table class="w-full text-xs">
|
||||
<thead>
|
||||
<tr class="border-b text-left text-slate-500">
|
||||
<th class="py-2 font-semibold">AI 场景</th>
|
||||
<th class="py-2 font-semibold">调用人</th>
|
||||
<th class="py-2 font-semibold">关联变更</th>
|
||||
<th class="py-2 font-semibold">时间</th>
|
||||
<th class="py-2 text-right font-semibold">耗时</th>
|
||||
<th class="py-2 text-right font-semibold">采纳结果</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(r, i) in AI_LOGS" :key="i" class="border-b last:border-0">
|
||||
<td class="py-2 text-slate-700">{{ r.scene }}</td>
|
||||
<td class="py-2 text-slate-600">{{ r.user }}</td>
|
||||
<td class="py-2 font-mono text-slate-500">{{ r.change }}</td>
|
||||
<td class="py-2 text-slate-500">{{ r.time }}</td>
|
||||
<td class="py-2 text-right text-slate-600">{{ r.cost }}</td>
|
||||
<td class="py-2 text-right">
|
||||
<NTag v-if="r.adopted === '采纳'" size="small" type="success">{{ r.adopted }}</NTag>
|
||||
<NTag v-if="r.adopted === '修改后采纳'" size="small" type="warning">{{ r.adopted }}</NTag>
|
||||
<NTag v-if="r.adopted === '未采纳'" size="small">{{ r.adopted }}</NTag>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="mt-3 text-[11px] text-slate-400">调用记录含输入摘要(脱敏)、模型与提示词版本、耗时与采纳结果,支持采纳率统计;完整输出存对象存储。</p>
|
||||
</NDrawerContent>
|
||||
</NDrawer>
|
||||
<!-- 新增/编辑类型 -->
|
||||
<NModal
|
||||
v-model:show="typeModal"
|
||||
preset="card"
|
||||
:title="currentType === 'add' ? '新增变更类型' : '编辑变更类型'"
|
||||
:auto-focus="false"
|
||||
:style="{ width: '450px', height: 'auto' }"
|
||||
:segmented="{ content: true, footer: true }"
|
||||
>
|
||||
<div>
|
||||
<NForm
|
||||
ref="typeRef"
|
||||
label-width="auto"
|
||||
:model="typeInfo"
|
||||
:rules="typeRules"
|
||||
>
|
||||
<NFormItem label="类型名称" path="name">
|
||||
<NInput v-model:value="typeInfo.name" placeholder="如:仪表控制" />
|
||||
</NFormItem>
|
||||
<NFormItem label="类型定义描述" path="desc">
|
||||
<NInput v-model:value="typeInfo.desc" type="textarea" placeholder="该类型覆盖的变更范围说明" />
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-[10px]">
|
||||
<NButton size="small" @click="typeModal = false">取消</NButton>
|
||||
<NButton size="small" type="primary" :loading="typeLoading" @click="typeSave">确定</NButton>
|
||||
</div>
|
||||
</template>
|
||||
</NModal>
|
||||
<!-- 新增/编辑等级 -->
|
||||
<NModal
|
||||
v-model:show="levelModal"
|
||||
preset="card"
|
||||
:title="currentLevel === 'add' ? '新增变更等级' : '编辑变更等级'"
|
||||
:auto-focus="false"
|
||||
:style="{ width: '500px', height: 'auto' }"
|
||||
:segmented="{ content: true, footer: true }"
|
||||
>
|
||||
<div>
|
||||
<NForm
|
||||
ref="levelRef"
|
||||
label-width="auto"
|
||||
:model="levelInfo"
|
||||
:rules="levelRules"
|
||||
>
|
||||
<NFormItem label="等级名称" path="name">
|
||||
<NInput v-model:value="levelInfo.name" placeholder="如:重大" />
|
||||
</NFormItem>
|
||||
<NFormItem label="等级判定方式" path="way">
|
||||
<NInput v-model:value="levelInfo.way" placeholder="如:等级评分 ≥ 20 分" />
|
||||
</NFormItem>
|
||||
<NFormItem label="对应分析工具(多选)" path="tools">
|
||||
<NSelect v-model:value="levelInfo.tools" multiple :options="toolsOptions" placeholder="请选择分析工具" />
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-[10px]">
|
||||
<NButton size="small" @click="levelModal = false">取消</NButton>
|
||||
<NButton size="small" type="primary" :loading="levelLoading" @click="levelSave">确定</NButton>
|
||||
</div>
|
||||
</template>
|
||||
</NModal>
|
||||
<!-- 维度分级定义 -->
|
||||
<NModal
|
||||
v-model:show="dimensionModal"
|
||||
preset="card"
|
||||
:title="curMatrix.tool+'矩阵维度分级定义'"
|
||||
:auto-focus="false"
|
||||
:style="{ width: '500px', height: 'auto' }"
|
||||
:segmented="{ content: true, footer: true }"
|
||||
>
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<div class="mb-1.5 text-xs font-semibold text-slate-600">后果严重性 S(S1 → S5 递增)</div>
|
||||
<div class="grid grid-cols-5 gap-1.5">
|
||||
<label v-for="(_, i) in dimForm.s" :key="'s' + i" class="text-center text-[10px] text-slate-400">
|
||||
S{{ i + 1 }}
|
||||
<NInput v-model:value="dimForm.s[i]" 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">发生可能性 L(L1 → L5 递增)</div>
|
||||
<div class="grid grid-cols-5 gap-1.5">
|
||||
<label v-for="(_, i) in dimForm.l" :key="'l' + i" class="text-center text-[10px] text-slate-400">
|
||||
L{{ i + 1 }}
|
||||
<NInput v-model:value="dimForm.l[i]" size="small" class="mt-0.5 text-center text-xs" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
</div>
|
||||
</template>
|
||||
</NModal>
|
||||
|
||||
</NSpace>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user