本专业高风险页面修改以及删除多余文件

This commit is contained in:
2026-09-21 10:00:25 +08:00
parent 1c85b2ae92
commit 3fe8da170c
5 changed files with 48 additions and 615 deletions
+45 -130
View File
@@ -1,146 +1,62 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { useAppStore } from '@/store/modules/app';
import { Icon } from '@iconify/vue'
import { useThemeStore } from '@/store/modules/theme';
import { aiKnowledgeIngest, pollTask, AiError } from '@/service/api/ai';
import { docListApi, historyVersionListApi } from '@/service/api/doc';
const appStore = useAppStore();
const themeStore = useThemeStore();
const gap = computed(() => (appStore.isMobile ? 0 : 16));
const uploadFiles = () => {
window.$message?.success('演示:上传资料(限资料管理员 / 各专业专责维护;上传后进入受控评审,发布生效并生成新版本号,全程留痕)')
}
const KNOWLEDGE_DOCS = [
{ name: "PID-R201-03 反应釜工艺流程图(Rev C)", cat: "工艺技术资料", device: "一车间", ver: "Rev C", date: "2026-07-29" },
{ name: "聚合岗位操作规程(2026 版)", cat: "工艺技术资料", device: "一车间", ver: "V2026", date: "2026-07-26" },
{ name: "M-201A 搅拌电机设备台账", cat: "设备资料", device: "一车间", ver: "V3.2", date: "2026-07-28" },
{ name: "环己烷 MSDS(供应商 B)", cat: "化学品资料", device: "原料罐区", ver: "V1.0", date: "2026-07-18" },
{ name: "AQ/T 3034 化工企业工艺安全管理实施导则", cat: "法规标准库", device: "全厂", ver: "2013 版", date: "2025-12-01" },
{ name: "PSSR 检查表模板(设备类)", cat: "检查表模板库", device: "全厂", ver: "V2.1", date: "2026-05-10" },
{ name: "2025 年度典型变更案例汇编", cat: "历史变更案例库", device: "全厂", ver: "2025 版", date: "2026-01-15" },
{ name: "HAZOP 分析报告(R-101 温度变更)", cat: "历史变更案例库", device: "一车间", ver: "V1.0", date: "2026-07-26" },
];
const libHits = computed(() => (keyword.value ? KNOWLEDGE_DOCS.filter((d:any) => d.name.includes(keyword.value) || d.cat.includes(keyword.value)) : []));
const preview = (d:any) => {
window.$message?.info(`演示:在线预览 ${d.name}`)
}
const download = (d:any) => {
window.$message?.success(`演示:下载 ${d.name}`)
}
// 已纳入 AI 知识库的条目(name -> true)与摄入中状态
const ingested = ref<Record<string, boolean>>({});
const ingesting = ref<Record<string, boolean>>({});
const call = async (d:any) => {
if (ingesting.value[d.name] || ingested.value[d.name]) return;
ingesting.value[d.name] = true;
try {
const { task_id } = await aiKnowledgeIngest({ name: d.name, version: d.ver, category: d.cat });
await pollTask(task_id, {});
ingested.value[d.name] = true;
window.$message?.success(`已将「${d.name}」纳入 AI 知识库(调用记录留痕)`);
} catch (e: any) {
if (e instanceof AiError) {
window.$message?.warning(`AI 知识摄入失败:${e.message},可稍后重试`);
} else {
window.$message?.warning('AI 知识摄入失败,可稍后重试');
}
} finally {
ingesting.value[d.name] = false;
}
}
interface LibDoc { name: string; ver: string; date: string }
interface LibFolder { label: string; docs: LibDoc[] }
interface LibGroup { cat: string; folders: LibFolder[] }
const LIB_ORGS: { org: string; groups: LibGroup[] }[] = [
{ org: "一车间", groups: [
{ cat: "工艺", folders: [
{ label: "操作规程", docs: [
{ name: "聚合岗位操作规程(2026 版)", ver: "V2026", date: "2026-07-26" },
{ name: "干燥岗位操作规程(2026 版)", ver: "V2026", date: "2026-06-30" } ]},
{ label: "PID 图纸", docs: [
{ name: "PID-R201-03 反应釜工艺流程图(Rev C)", ver: "Rev C", date: "2026-07-29" },
{ name: "PID-V102-01 罐区工艺流程图(Rev B)", ver: "Rev B", date: "2026-05-12" } ]},
{ label: "工艺卡片", docs: [
{ name: "R-201 反应釜工艺卡片(夏季工况)", ver: "V2.0", date: "2026-07-01" } ]},
]},
{ cat: "设备", folders: [
{ label: "设备台账", docs: [
{ name: "M-201A 搅拌电机设备台账", ver: "V3.2", date: "2026-07-28" },
{ name: "P-204 输送泵设备台账", ver: "V2.8", date: "2026-06-15" } ]},
{ label: "安全阀台账", docs: [
{ name: "一车间安全阀台账(PSV-101 ~ PSV-118)", ver: "V5.1", date: "2026-07-10" } ]},
]},
{ cat: "仪表", folders: [
{ label: "报警台账", docs: [
{ name: "一车间 DCS 报警台账(2026H1)", ver: "V4.0", date: "2026-07-20" } ]},
{ label: "联锁台账", docs: [
{ name: "一车间联锁逻辑台账(SIS-01 ~ SIS-09)", ver: "V3.6", date: "2026-07-22" } ]},
]},
{ cat: "安全", folders: [
{ label: "总图", docs: [{ name: "一车间装置总平面布置图", ver: "Rev D", date: "2026-04-18" } ]},
{ label: "现场气体报警仪布置图", docs: [{ name: "一车间可燃 / 有毒气体报警仪布置图", ver: "Rev B", date: "2026-05-28" } ]},
{ label: "防爆分区图", docs: [{ name: "一车间爆炸危险区域划分图", ver: "Rev C", date: "2026-03-15" } ]},
]},
]},
{ org: "二车间", groups: [
{ cat: "工艺", folders: [
{ label: "操作规程", docs: [{ name: "二车间精馏岗位操作规程(2026 版)", ver: "V2026", date: "2026-06-20" } ]},
{ label: "PID 图纸", docs: [{ name: "PID-T301-02 精馏塔工艺流程图(Rev A)", ver: "Rev A", date: "2026-03-08" } ]},
]},
{ cat: "设备", folders: [
{ label: "设备台账", docs: [{ name: "P-103 冷冻盐水泵设备台账", ver: "V2.2", date: "2026-05-30" } ]},
{ label: "安全阀台账", docs: [{ name: "二车间安全阀台账(PSV-201 ~ PSV-212)", ver: "V4.3", date: "2026-06-11" } ]},
]},
{ cat: "仪表", folders: [
{ label: "报警台账", docs: [{ name: "二车间 DCS 报警台账(2026H1)", ver: "V3.5", date: "2026-07-02" } ]},
{ label: "联锁台账", docs: [{ name: "二车间联锁逻辑台账(SIS-11 ~ SIS-16)", ver: "V2.9", date: "2026-06-25" } ]},
]},
{ cat: "安全", folders: [
{ label: "总图", docs: [{ name: "二车间装置总平面布置图", ver: "Rev B", date: "2026-02-14" } ]},
{ label: "现场气体报警仪布置图", docs: [{ name: "二车间可燃 / 有毒气体报警仪布置图", ver: "Rev A", date: "2026-04-02" } ]},
{ label: "防爆分区图", docs: [{ name: "二车间爆炸危险区域划分图", ver: "Rev B", date: "2026-01-20" } ]},
]},
]},
{ org: "全厂共用", groups: [
{ cat: "法规", folders: [
{ label: "法规标准库", docs: [{ name: "AQ/T 3034 化工企业工艺安全管理实施导则", ver: "2013 版", date: "2025-12-01" } ]},
]},
{ cat: "化学品", folders: [
{ label: "MSDS", docs: [{ name: "环己烷 MSDS(供应商 B)", ver: "V1.0", date: "2026-07-18" } ]},
]},
{ cat: "模板", folders: [
{ label: "检查表模板", docs: [{ name: "PSSR 检查表模板(设备类)", ver: "V2.1", date: "2026-05-10" } ]},
]},
{ cat: "案例", folders: [
{ label: "历史变更案例", docs: [
{ name: "2025 年度典型变更案例汇编", ver: "2025 版", date: "2026-01-15" },
{ name: "HAZOP 分析报告(R-101 温度变更)", ver: "V1.0", date: "2026-07-26" } ]},
]},
]},
];
const openOrgs = ref<Record<string, boolean>>({ 一车间: true });
const libSel = ref({ org: "一车间", cat: "工艺", label: "操作规程" });
const libCur = computed(() => docList.value.find((o) => o.org_name === libSel.value.org)?.categories.find((g) => g.category === libSel.value.cat)?.folders.find((f) => f.folder === libSel.value.label));
const loading = ref<boolean>(false);
const rightLoading = ref<boolean>(false);
// 展开节点
const openOrgs = ref<Record<string, boolean>>({});
// 选中的资料库节点
const libSel = ref({ org: "", cat: "", label: "" });
// 当前选中的资料库列表
const libCur = computed(() => docList.value.find((o:any) => o.org_name === libSel.value.org)?.categories.find((g:any) => g.category === libSel.value.cat)?.folders.find((f:any) => f.folder === libSel.value.label));
// 搜索关键词
const keyword = ref<string>('');
// 资料库树状列表
const docList = ref<any[]>([]);
// 历史版本列表
const historyList = ref<any[]>([]);
// 展示数还是列表
const showTree = ref<boolean>(true);
// 在线预览资料
const preview = (d:any) => {
window.$message?.info(`演示:在线预览 ${d.name}`)
}
// 下载资料
const download = (d:any) => {
window.$message?.success(`演示:下载 ${d.name}`)
}
// 上传资料
const uploadFiles = () => {
window.$message?.success('演示:上传资料(限资料管理员 / 各专业专责维护;上传后进入受控评审,发布生效并生成新版本号,全程留痕)')
}
// 搜索
const searchHandle = () => {
if(!keyword.value) {
showTree.value = true;
return;
};
showTree.value = false;
}
// 获取资料库树状列表
const getDocList = async () => {
loading.value = true;
const {data,error} = await docListApi();
if(!error){
console.log(data);
docList.value = data ?? [];
console.log(docList.value);
if(docList.value.length){
openOrgs.value = {[docList.value[0]?.org_name]:true};
libSel.value = {org: docList.value[0]?.org_name, cat: docList.value[0]?.categories[0]?.category, label: docList.value[0]?.categories[0]?.folders[0]?.folder};
}
}
loading.value = false;
}
@@ -155,7 +71,7 @@ onMounted(() => {
<!-- 我的草稿箱 -->
<NSpin :show="loading" size="small">
<NCard :bordered="false" size="small" :style="{ borderRadius: themeStore.themeRadius + 'px' }">
<NGrid :x-gap="gap" :y-gap="16" responsive="screen" item-responsive class="pb-[12px] border-b">
<NGrid :x-gap="16" :y-gap="16" responsive="screen" item-responsive class="pb-[12px] border-b">
<NGi span="24 s:24 m:16">
<div class="h-100% flex items-center gap-2">
<Icon icon="mage:book" class="size-20px" :style="{ color: themeStore.themeColor }" />
@@ -164,9 +80,9 @@ onMounted(() => {
</NGi>
<NGi span="24 s:24 m:8" class="flex items-center justify-end gap-12px">
<div class="flex items-center gap-2">
<NInput v-model:value="keyword" size="small" type="text" class="w-40 text-xs" clearable placeholder="全文检索…">
<NInput v-model:value="keyword" size="small" type="text" class="w-40 text-xs" clearable placeholder="全文检索…" @clear="keyword = ''; searchHandle();">
<template #suffix>
<Icon icon="akar-icons:search" class="size-14px text-slate-400 cursor-pointer" />
<Icon icon="akar-icons:search" class="size-14px text-slate-400 cursor-pointer" @click="searchHandle" />
</template>
</NInput>
<NButton size="small" type="primary" class="text-xs" @click="uploadFiles">
@@ -179,10 +95,10 @@ onMounted(() => {
按「组织 → 专业类别 → 资料文件夹」归档具体资料(操作规程 / PID 图纸 / 工艺卡片 / 设备台账 / 安全阀台账 / 报警台账 / 联锁台账 / 总图 / 现场气体报警仪布置图 / 防爆分区图等);资料由指定维护人(资料管理员 / 各专业专责)上传维护,版本受控;「调用」可将资料引用为当前变更的 AI 知识来源,调用记录留痕。
</div>
<!-- 全文检索:跨文件夹平铺结果 -->
<div v-if="keyword">
<div class="mb-1.5 text-xs text-slate-400">全文检索「{{ keyword }}」:跨全部文件夹命中 {{ libHits.length }} 份</div>
<div v-if="!showTree">
<div class="mb-1.5 text-xs text-slate-400">全文检索「{{ keyword }}」:跨全部文件夹命中 {{ historyList.length }} 份</div>
<div class="divide-y rounded-lg border bg-white">
<div v-for="d in libHits" :key="d.name" class="flex flex-wrap items-center gap-3 px-2 py-2.5">
<div v-for="d in historyList" :key="d.name" class="flex flex-wrap items-center gap-3 px-2 py-2.5">
<FileText class="h-4 w-4 shrink-0 text-slate-400" />
<div class="min-w-0 flex-1">
<div class="truncate text-sm">{{ d.name }}</div>
@@ -196,7 +112,7 @@ onMounted(() => {
<button class="text-[#1D4E9C] hover:underline" @click="download(d)">下载</button>
</div>
</div>
<div v-if="libHits.length === 0" class="py-6 text-center text-xs text-slate-400">未找到匹配「{{ keyword }}」的资料</div>
<div v-if="historyList.length === 0" class="py-6 text-center text-xs text-slate-400">未找到匹配「{{ keyword }}」的资料</div>
</div>
</div>
<!-- 文件夹树 + 当前文件夹资料 -->
@@ -248,10 +164,9 @@ onMounted(() => {
</div>
</div>
<div class="flex shrink-0 gap-3 text-xs">
<NButton type="primary" text class="hover:underline text-xs" @click="preview(d)">查看</NButton>
<NButton type="primary" text class="hover:underline text-xs">查看历史</NButton>
<NButton type="primary" text class="hover:underline text-xs" @click="preview(d)">预览</NButton>
<NButton type="primary" text class="hover:underline text-xs" @click="download(d)">下载</NButton>
<NTag v-if="ingested[d.name]" size="small" type="success" class="text-[10px]">已纳入 AI 知识库</NTag>
<NButton v-else type="primary" text class="hover:underline text-xs" :loading="!!ingesting[d.name]" @click="call(d)">调用</NButton>
</div>
</div>
</div>