风险检查表分析工具完成

This commit is contained in:
2026-08-26 16:34:10 +08:00
parent b51de262b3
commit 26192167f3
5 changed files with 119 additions and 6 deletions
@@ -141,7 +141,7 @@ const rrOf = (l: number, s: number) => {
</NButton>
<NButton size="small" ghost type="primary" class="text-xs" @click="save">保存</NButton>
<span class="text-sm font-bold text-[var(--theme-color)]">HAZOP 分析插件</span>
<NTag size="small" type="primary">插件</NTag>
<NTag size="small" type="info">插件</NTag>
<NTag size="small">MOC 变更缩合反应温度及时间优化演示</NTag>
<span class="text-[11px] text-slate-500">{{ `分析进度 ${devDone}/${devTotal} 个偏离 · ${recTotal} 条记录` }}</span>
<div class="relative">
+1 -1
View File
@@ -154,7 +154,7 @@ const toRec = (step: string, row: any): any => ({
</NButton>
<NButton size="small" ghost type="primary" class="text-xs" @click="save">保存</NButton>
<span class="text-sm font-bold text-[var(--theme-color)]">JSA 分析插件</span>
<NTag size="small" type="primary">插件</NTag>
<NTag size="small" type="info">插件</NTag>
<NTag size="small">MOC 变更缩合反应温度及时间优化演示</NTag>
<span class="text-[11px] text-slate-500">{{`LS 矩阵 · ${steps.length} 个作业步骤 · ${recTotal} 条危害因素记录`}}</span>
<div class="relative">
@@ -0,0 +1,109 @@
<script setup lang="ts">
import { computed, ref } from "vue";
import { useMessage } from "naive-ui";
import { Icon } from '@iconify/vue'
const message = useMessage();
const emit = defineEmits<{
back: [];
}>();
const RISK_CHECKS_INIT = [
{
id: 1, group: "安全健康", ans: "是",
q: "是否存在任何可能导致安全问题的化学反应?检查化学反应禁忌表。",
risk: "反应温度从80℃升至90℃,反应速率加快,放热更集中,可能引发反应失控或副反应,导致超温超压。",
measure: "1. 进行反应量热试验或查阅反应热数据,确认90℃下的放热速率和绝热温升;2. 评估现有冷却系统能力是否满足最大放热需求;3. 更新化学反应风险评估报告;4. 验证反应釜搅拌、冷却系统完好。",
},
{ id: 2, group: "安全健康", ans: "否", q: "是否存在任何易燃易爆化学物质或粉尘?" },
{
id: 3, group: "安全健康", ans: "是",
q: "是否存在任何有危险的原材料流速、成分或温度条件变更?",
risk: "反应温度条件从80±2℃变更至90±2℃,接近设备设计温度上限100℃,可能造成副反应增加或杂质生成。",
measure: "1. 通过小试实验验证90℃下的副反应种类及含量,确保产品杂质合格;2. 确认原料A和B在此温度下的稳定性;3. 将温度控制精度要求写入操作参数表。",
},
{
id: 4, group: "安全健康", ans: "是",
q: "是否会因加热、冷却或精确的温度控制失控而导致安全问题?",
risk: "温度控制失效(如加热阀门卡死、冷却中断)可能使实际温度超过100℃,导致设备超温、压力升高或反应失控。",
measure: "1. 调试并确认DCS温度高报警(95℃)和高高报警联锁(100℃)功能正常;2. 执行联锁回路功能测试(温度变送器、DCS卡件、电磁阀、切断阀);3. 确认加热介质切断阀为故障安全型。",
},
{
id: 5, group: "安全健康", ans: "是",
q: "是否具有为安全操作所必需的仪表、控制、紧急制动、开关或报警?",
risk: "变更后温度报警值上调,现有温度仪表量程可能不足或精度不够,影响安全操作。",
measure: "1. 检查温度变送器量程是否覆盖0~100℃,精度是否优于0.5级;2. 确认DCS报警值设定正确且已组态;3. 在DCS画面中明显标注新报警值。",
},
{
id: 6, group: "工艺与操作", ans: "是",
q: "变更后是否需要对操作人员进行专门培训?",
risk: "新工况(90℃ / 4小时)与原操作习惯差异较大,误操作可能引发超温或产品质量波动。",
measure: "1. 修订操作规程并组织专项培训考核;2. 投用首周实行双人复核操作;3. 关键参数调整权限上收至班长。",
},
{ id: 7, group: "工艺与操作", ans: "否", q: "是否涉及应急预案或消防设施的调整?" },
];
const pluginDone = ref<Record<string, number>>({});
const riskChecks = ref<any[]>(RISK_CHECKS_INIT.map((x) => ({ ...x })));
const riskGroups = computed(() => [...new Set(riskChecks.value.map((x) => x.group))]);
const riskFilter = ref<string>("全部");
const onBack = () => {
pluginDone.value = { ...pluginDone.value, RISK_CHECK: riskChecks.value.filter((x) => x.ans === '是').length };
emit("back");
}
const save = () => {
pluginDone.value = { ...pluginDone.value, RISK_CHECK: riskChecks.value.filter((x) => x.ans === '是').length };
message.success("已手动保存,分析记录数已同步至工具卡片(内容修改实时自动保存,退出不丢失)");
};
</script>
<template>
<div class="space-y-4">
<div class="flex flex-wrap items-center gap-3">
<NButton size="small" ghost type="primary" class="text-xs" @click="onBack">
<Icon icon="basil:arrow-left-outline" class="size-18px" /> 返回工具列表
</NButton>
<NButton size="small" ghost type="primary" class="text-xs" @click="save">保存</NButton>
<span class="flex items-center gap-1.5 text-sm font-semibold text-slate-700">变更风险检查表通用</span>
<NTag size="small" type="info">插件</NTag>
<div class="flex items-center gap-3">
<NRadioGroup v-model:value="riskFilter" name="radiogroup">
<NRadio v-for="song in [{label:'全部',value:'全部'},{label:'仅看「是」',value:'是'}]" :key="song.value" :value="song.value">
{{ song.label }}
</NRadio>
</NRadioGroup>
</div>
<span class="ml-auto inline-flex items-center gap-1 rounded-full border border-violet-200 bg-violet-100 px-2 py-0.5 text-xs font-medium text-violet-700">
AI 生成 · 需人工确认
</span>
</div>
<p class="text-[11px] text-slate-400">逐项判定 / / 不涉及判定为的检查项输出风险描述与管控措施完成后点返回工具列表回显完成项数</p>
<div v-for="g in riskGroups" :key="g" class="overflow-hidden rounded-lg border">
<div class="bg-slate-100 px-3 py-2 text-sm font-medium text-slate-700">{{ g }}</div>
<div v-for="item in riskChecks.filter((x) => x.group === g && (riskFilter === '全部' || x.ans === '是'))" :key="item.id"
class="grid gap-3 border-t px-3 py-3 grid-cols-[1.1fr_1fr_1fr]">
<div>
<div class="text-sm text-slate-700">{{ item.q }}</div>
<div class="mt-2 flex items-center gap-4">
<span v-for="a in ['是', '否', 'NA']" :key="a">
<NRadio
:checked="item.ans === a"
@change="riskChecks = riskChecks.map((x) => (x.id === item.id ? { ...x, ans: a } : x))"
>
{{ a }}
</NRadio>
</span>
</div>
</div>
<template v-if="item.ans === '是'">
<div class="rounded-lg bg-slate-50 p-2.5 text-xs leading-relaxed text-slate-600">
<span class="font-medium text-slate-500">风险描述</span>{{ item.risk }}
</div>
<div class="rounded-lg bg-slate-50 p-2.5 text-xs leading-relaxed text-slate-600">
<span class="font-medium text-slate-500">管控措施</span>{{ item.measure }}
</div>
</template>
<div v-else class="text-xs text-slate-300 self-center col-span-2">回答为{{ item.ans }}无风险描述</div>
</div>
</div>
</div>
</template>
+1 -1
View File
@@ -113,7 +113,7 @@ const groups = ref([
</NButton>
<NButton size="small" ghost type="primary" class="text-xs" @click="save">保存</NButton>
<span class="text-sm font-bold text-[var(--theme-color)]">SCL 安全检查表插件</span>
<NTag size="small" type="primary">插件</NTag>
<NTag size="small" type="info">插件</NTag>
<NTag size="small">MOC 变更缩合反应温度及时间优化演示</NTag>
<span class="text-[11px] text-slate-500">{{ `${groups.length} 个检查分类 · ${recTotal} 项检查记录` }}</span>
<div class="relative">