pssr检查内容完成
This commit is contained in:
@@ -4,70 +4,44 @@ import { ref } from 'vue';
|
|||||||
import { Icon } from '@iconify/vue'
|
import { Icon } from '@iconify/vue'
|
||||||
import { useThemeStore } from '@/store/modules/theme';
|
import { useThemeStore } from '@/store/modules/theme';
|
||||||
import Footer from './footer.vue';
|
import Footer from './footer.vue';
|
||||||
|
import { uploadFileApi } from "@/service/api/file";
|
||||||
|
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
const props = defineProps(['type','isAiOpen','title','currentId'])
|
const props = defineProps(['type','isAiOpen','title','currentId'])
|
||||||
const emit = defineEmits(['save','submit','confirmTab']);
|
const emit = defineEmits(['save','submit','confirmTab']);
|
||||||
|
|
||||||
const form = ref<{ content: string }>({
|
const uploadLoading = ref<boolean>(false);
|
||||||
content: ''
|
const uploadFileRef = ref<any>(null);
|
||||||
});
|
const isUploaded = ref<boolean>(false);
|
||||||
|
|
||||||
const editing = ref<any>(null);
|
const editing = ref<any>(null);
|
||||||
const pssrGroups = ref<{ g: string; items: any[] }[]>([
|
|
||||||
{ g: "一、风险分析行动项落实", items: [
|
const list = ref<{ g: string; type:number; na_flag:number; items: any[] }[]>([
|
||||||
{ c: "联锁跳车电流设定值校核并留存记录", p: "投用前" },
|
{ g: "一、风险分析行动项落实", type:1, na_flag:0, items: [] },
|
||||||
{ c: "电缆与开关容量校核升级完成", p: "投用前" },
|
{ g: "二、现场设备安装检查确认", type:2, na_flag:0, items: [] },
|
||||||
{ c: "操作人员培训完成并考核合格", p: "投用前" },
|
{ g: "三、保护措施确认", type:3, na_flag:0, items: [] },
|
||||||
] },
|
{ g: "四、资料归档确认", type:4, na_flag:0, items: [] },
|
||||||
{ g: "二、现场设备安装检查确认", items: [
|
|
||||||
{ c: "电机安装就位,联轴器对中合格", p: "投用前" },
|
|
||||||
{ c: "地脚螺栓紧固,减振垫安装到位", p: "投用前" },
|
|
||||||
{ c: "电缆接线、防爆格兰头密封良好", p: "投用前" },
|
|
||||||
] },
|
|
||||||
{ g: "三、保护措施确认", items: [
|
|
||||||
{ c: "联锁跳车设定值与新电机额定电流匹配", p: "投用前" },
|
|
||||||
{ c: "电机外壳接地、防护罩完好", p: "投用前" },
|
|
||||||
{ c: "紧急停机按钮功能试验正常", p: "投用前" },
|
|
||||||
] },
|
|
||||||
{ g: "四、资料归档确认", items: [
|
|
||||||
{ c: "P&ID(图号 PID-R201-03)已更新并受控", p: "关闭前" },
|
|
||||||
{ c: "设备台账、备件清单已更新", p: "关闭前" },
|
|
||||||
{ c: "培训签到表、考核记录已归档", p: "关闭前" },
|
|
||||||
] },
|
|
||||||
]);
|
]);
|
||||||
const pssrDone = ref<Record<string, { by: string; at: string }>>({});
|
|
||||||
const pssrNa = ref<Record<string, boolean>>({});
|
const pssrNa = ref<Record<string, boolean>>({});
|
||||||
const pssrFileRef = ref<any>(null);
|
|
||||||
const pssrSheet = ref<any>(null);
|
// 添加检查项
|
||||||
const closeDocs = ref([
|
const addItem = (g:any, gi: number) => {
|
||||||
{ name: "PID 图纸(PID-R201-03,受控最新版)", cat: "图纸与规程类", scope: "是", archived: true },
|
list.value[gi].items.push({id:0, group_type:g.type, content: '新检查项(点击直接编辑内容)', phase: 1, na_flag: 0 });
|
||||||
{ name: "操作规程(含超温应急处置卡)", cat: "图纸与规程类", scope: "是", archived: false },
|
}
|
||||||
{ name: "应急预案修订", cat: "图纸与规程类", scope: "不涉及", archived: false },
|
|
||||||
{ name: "总图更新", cat: "图纸与规程类", scope: "否", archived: false },
|
|
||||||
{ name: "DCS 联锁台账(新报警 / 联锁值)", cat: "台账与制度类", scope: "是", archived: false },
|
|
||||||
{ name: "设备台账与备件清单", cat: "台账与制度类", scope: "是", archived: true },
|
|
||||||
{ name: "风险分析报告(HAZOP / 检查表法)", cat: "过程与结果文件类", scope: "是", archived: true },
|
|
||||||
{ name: "培训签到与考核记录", cat: "过程与结果文件类", scope: "是", archived: true },
|
|
||||||
{ name: "PSSR 检查记录(含现场照片)", cat: "过程与结果文件类", scope: "是", archived: false },
|
|
||||||
{ name: "验收报告与化验数据", cat: "过程与结果文件类", scope: "是", archived: false },
|
|
||||||
]);
|
|
||||||
const today = () => new Date().toISOString().slice(0, 10);
|
|
||||||
// 上传纸质确认表
|
// 上传纸质确认表
|
||||||
const onPssrFile = (e: Event) => {
|
const uploadFile = async (e: any) => {
|
||||||
const input = e.target as HTMLInputElement;
|
const file = e.target.files[0];
|
||||||
const f = input.files?.[0]; input.value = "";
|
if (!file) return;
|
||||||
if (!f) return;
|
const formData = new FormData();
|
||||||
pssrSheet.value = f.name;
|
formData.append('file', file);
|
||||||
const at = today();
|
formData.append('step', '2');
|
||||||
const n = { ...pssrDone.value };
|
uploadLoading.value = true;
|
||||||
pssrGroups.value.forEach((g:any) => { if (!pssrNa.value[g.g]) g.items.forEach((it:any) => { n[it.c] = { by: "纸质确认表上传", at }; }); });
|
const {error} = await uploadFileApi(props.currentId, formData);
|
||||||
pssrDone.value = n;
|
if(!error){
|
||||||
const archGroup = pssrGroups.value[pssrGroups.value.length - 1];
|
isUploaded.value = true;
|
||||||
if (archGroup && !pssrNa.value[archGroup.g]) {
|
window.$message?.success(`已上传 PSSR 纸质确认表:不做内容识别,上传即视为全部检查项完成确认(「不涉及」组除外),原件归档至变更档案`);
|
||||||
closeDocs.value = closeDocs.value.map((d:any) => (d.name.includes("PID") || d.name.includes("设备台账") || d.name.includes("培训签到") ? { ...d, archived: true } : d));
|
|
||||||
}
|
}
|
||||||
window.$message?.success(`已上传 PSSR 纸质确认表「${f.name}」:不做内容识别,上传即视为全部检查项完成确认(「不涉及」组除外),原件归档至变更档案`);
|
uploadLoading.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 保存草稿
|
// 保存草稿
|
||||||
@@ -83,7 +57,7 @@ const confirmTab = (tab:string, val:boolean) => {
|
|||||||
emit('confirmTab', tab, val);
|
emit('confirmTab', tab, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({form})
|
defineExpose({list})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -98,35 +72,36 @@ defineExpose({form})
|
|||||||
✨ AI 生成 · 需人工确认
|
✨ AI 生成 · 需人工确认
|
||||||
</span>
|
</span>
|
||||||
<span class="flex items-center gap-2">
|
<span class="flex items-center gap-2">
|
||||||
<NButton ghost size="small" class="text-xs" title="上传 PSSR 纸质确认表照片 / 扫描件(JPG / PNG / PDF),系统不做内容识别,上传即视为全部检查项完成确认" @click="pssrFileRef?.click()">
|
<NButton ghost size="small" :disabled="uploadLoading" class="text-xs" title="上传 PSSR 纸质确认表照片 / 扫描件(JPG / PNG / PDF),系统不做内容识别,上传即视为全部检查项完成确认" @click="uploadFileRef?.click()">
|
||||||
<Icon icon="material-symbols:upload" class="size-14px" />
|
<Icon v-if="uploadLoading" icon="ri:loader-4-fill" class="size-14px animate-spin" />
|
||||||
|
<Icon v-else icon="material-symbols:upload" class="size-14px" />
|
||||||
上传纸质确认表
|
上传纸质确认表
|
||||||
</NButton>
|
</NButton>
|
||||||
<input ref="pssrFileRef" type="file" accept="image/*,.pdf" class="hidden" @change="onPssrFile" />
|
<input ref="uploadFileRef" type="file" accept="image/*,.pdf" class="hidden" @change="uploadFile" />
|
||||||
<span class="hidden text-xs text-slate-400 xl:inline">申请阶段:点击条目内容直接编辑,可增删项</span>
|
<span class="hidden text-xs text-slate-400 xl:inline">申请阶段:点击条目内容直接编辑,可增删项</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="pssrSheet" class="flex items-center gap-2 rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-2 text-xs text-emerald-700">
|
<div v-if="isUploaded" class="flex items-center gap-2 rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-2 text-xs text-emerald-700">
|
||||||
<Icon icon="ix:success" class="size-16px" />
|
<Icon icon="ix:success" class="size-16px" />
|
||||||
已上传 PSSR 纸质确认表「{{ pssrSheet }}」:上传即视为全部检查项完成确认(未做内容识别),原件已归档至变更档案
|
已上传 PSSR 纸质确认表:上传即视为全部检查项完成确认(未做内容识别),原件已归档至变更档案
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-for="(g, gi) in pssrGroups" :key="g.g" class="border" :class="pssrNa[g.g] ? 'opacity-70' : ''" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
<div v-for="(g, gi) in list" :key="g.g" class="border" :class="g.na_flag ? 'opacity-70' : ''" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
|
||||||
<div class="flex items-center bg-slate-100 px-3 py-2 text-sm font-medium text-slate-700">
|
<div class="flex items-center bg-slate-100 px-3 py-2 text-sm font-medium text-slate-700">
|
||||||
{{ g.g }}
|
{{ g.g }}
|
||||||
<NTag v-if="pssrNa[g.g]" size="small" class="ml-2">不涉及</NTag>
|
<NTag v-if="g.na_flag" size="small" class="ml-2">不涉及</NTag>
|
||||||
<span v-else class="ml-2 text-xs font-normal text-slate-400">{{ g.items.filter((it) => pssrDone[it.c]).length }}/{{ g.items.length }} 已确认</span>
|
<div class="ml-auto flex items-center">
|
||||||
<NButton text type="primary" class="ml-auto text-xs font-normal hover:underline"
|
<NButton v-if="g.items.length" text type="primary" class="text-xs font-normal hover:underline"
|
||||||
:title="pssrNa[g.g] ? '恢复本组检查清单' : '本次变更不涉及本组内容时点击标记,标记后不计入完成统计'"
|
:title="pssrNa[g.g] ? '恢复本组检查清单' : '本次变更不涉及本组内容时点击标记,标记后不计入完成统计'"
|
||||||
@click="pssrNa = { ...pssrNa, [g.g]: !pssrNa[g.g] }">
|
@click="g.na_flag = g.na_flag ? 0 : 1">
|
||||||
{{ pssrNa[g.g] ? '恢复清单' : '标记不涉及' }}
|
{{ g.na_flag ? '恢复清单' : '标记不涉及' }}
|
||||||
</NButton>
|
</NButton>
|
||||||
<NButton text type="primary" v-if="!pssrNa[g.g]" class="ml-3 text-xs font-normal hover:underline"
|
<NButton text type="primary" v-if="!g.na_flag" class="ml-3 text-xs font-normal hover:underline" @click="addItem(g,gi)">
|
||||||
@click="pssrGroups = pssrGroups.map((x, xi) => xi === gi ? { ...x, items: [...x.items, { c: '新检查项(点击直接编辑内容)', p: '投用前' }] } : x)">
|
|
||||||
<Icon icon="ic:round-plus" class="size-14px" /> 添加检查项
|
<Icon icon="ic:round-plus" class="size-14px" /> 添加检查项
|
||||||
</NButton>
|
</NButton>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="pssrNa[g.g]" class="border-t bg-slate-50 px-3 py-3 text-xs text-slate-400">
|
</div>
|
||||||
|
<div v-if="g.na_flag" class="border-t bg-slate-50 px-3 py-3 text-xs text-slate-400">
|
||||||
本组内容经评估本次变更不涉及(如:无现场安装作业 / 不改变保护措施 / 无需归档资料),已不计入 PSSR 完成统计;如需恢复检查清单,点击右上角「恢复清单」。
|
本组内容经评估本次变更不涉及(如:无现场安装作业 / 不改变保护措施 / 无需归档资料),已不计入 PSSR 完成统计;如需恢复检查清单,点击右上角「恢复清单」。
|
||||||
</div>
|
</div>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@@ -135,7 +110,7 @@ defineExpose({form})
|
|||||||
<NInput
|
<NInput
|
||||||
v-if="editing === `pssr-c-${gi}-${i}`"
|
v-if="editing === `pssr-c-${gi}-${i}`"
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
v-model:value="it.c"
|
v-model:value="it.content"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
autofocus
|
autofocus
|
||||||
rows="2"
|
rows="2"
|
||||||
@@ -144,19 +119,19 @@ defineExpose({form})
|
|||||||
<button v-else @click="editing = `pssr-c-${gi}-${i}`" title="点击编辑内容"
|
<button v-else @click="editing = `pssr-c-${gi}-${i}`" title="点击编辑内容"
|
||||||
class="min-w-0 flex-1 rounded-md px-1 text-left text-slate-800 transition hover:bg-[#EAF0F9] bg-transparent"
|
class="min-w-0 flex-1 rounded-md px-1 text-left text-slate-800 transition hover:bg-[#EAF0F9] bg-transparent"
|
||||||
>
|
>
|
||||||
{{ it.c }}
|
{{ it.content }}
|
||||||
</button>
|
</button>
|
||||||
<span class="flex items-center gap-1 py-1">
|
<span class="flex items-center gap-1 py-1">
|
||||||
<NRadio :checked="it.p === '投用前'" :value="'投用前'" label="投用前完成"
|
<NRadio :checked="it.phase === 1" :value="1" label="投用前完成"
|
||||||
@change="pssrGroups = pssrGroups.map((x, xi) => xi === gi ? { ...x, items: x.items.map((y, yi) => yi === i ? { ...y, p: '投用前' } : y) } : x)" />
|
@change="list = list.map((x, xi) => xi === gi ? { ...x, items: x.items.map((y, yi) => yi === i ? { ...y, phase: 1 } : y) } : x)" />
|
||||||
<NRadio :checked="it.p === '关闭前'" :value="'关闭前'" label="关闭前完成"
|
<NRadio :checked="it.phase === 2" :value="2" label="关闭前完成"
|
||||||
@change="pssrGroups = pssrGroups.map((x, xi) => xi === gi ? { ...x, items: x.items.map((y, yi) => yi === i ? { ...y, p: '关闭前' } : y) } : x)" />
|
@change="list = list.map((x, xi) => xi === gi ? { ...x, items: x.items.map((y, yi) => yi === i ? { ...y, phase: 2 } : y) } : x)" />
|
||||||
</span>
|
</span>
|
||||||
<NPopconfirm
|
<NPopconfirm
|
||||||
positive-text="确定"
|
positive-text="确定"
|
||||||
:positiveButtonProps="{ size: 'tiny' }"
|
:positiveButtonProps="{ size: 'tiny' }"
|
||||||
:negativeButtonProps="{ size: 'tiny' }"
|
:negativeButtonProps="{ size: 'tiny' }"
|
||||||
@positive-click="pssrGroups = pssrGroups.map((x, xi) => xi === gi ? { ...x, items: x.items.filter((_, yi) => yi !== i) } : x)"
|
@positive-click="list = list.map((x, xi) => xi === gi ? { ...x, items: x.items.filter((_, yi) => yi !== i) } : x)"
|
||||||
>
|
>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NButton text type="error" title="删除该项">
|
<NButton text type="error" title="删除该项">
|
||||||
|
|||||||
Reference in New Issue
Block a user