diff --git a/src/views/home/initiateChange/index.vue b/src/views/home/initiateChange/index.vue index 44e5f63..6df42e5 100644 --- a/src/views/home/initiateChange/index.vue +++ b/src/views/home/initiateChange/index.vue @@ -7,6 +7,7 @@ import { countOpenStatus, type ChangeLevel, type ChangeOrder, type ChangeStatus, type ChangeType, } from "@/typings/model"; import { getColorWithOpacity } from "@/utils/common"; +import HighlightText from "@/views/home/modules/HighlightText.vue"; const themeStore = useThemeStore(); @@ -38,55 +39,464 @@ const TABS = [ { id: "accept", name: "验收评价", icon: 'material-symbols:check-circle-outline' }, { id: "close", name: "变更关闭确认表", icon: 'quill:folder-open' }, ]; -const formGen = ref("idle"); const confirmed = ref>({}); const blockedTabs = ref([]); +const aiEnabled = ref(true); +const analyzing = ref(false); +// ---------- 变更预识别 ---------- +const desc = ref( + "某缩合反应现在控在80℃要反应8小时,车间反馈产能跟不上。我们小试做了几组,90℃下4小时转化率就能到98%,但有个未知杂质会从0.05%涨到0.12%。这个杂质结构还没定,不过不是基因毒性警示结构。想申请把温度提到90℃,同时把反应时间缩到4小时。", +); +const rows = ref(null); +const AI_ROWS = [ + { + id: 1, item: "工艺流程", + before: "流程简述(含物料、设备):某缩合反应,原料A与原料B在缩合反应釜中混合,加热至80℃进行保温反应8小时,反应完成后转入后处理工序。\n设计意图:通过缩合反应制得目标产物,保证转化率和杂质水平。", + after: "流程简述(含物料、设备):保温温度提升至90℃,反应时间缩短为4小时,其余流程不变。\n设计意图:在保持转化率98%的前提下缩短反应时间、提升产能。", + hl: ["保温温度提升至90℃,反应时间缩短为4小时", "在保持转化率98%的前提下缩短反应时间、提升产能"], + }, + { + id: 2, item: "设备信息", + before: "基本信息(名称、设计参数、材质、用途):缩合反应釜,设计温度100℃,设计压力0.2MPa,材质SS304,用于缩合反应。\n使用信息(安装位置、连接方式、维护策略):安装于反应工段,夹套加热,按预防性维护计划定期检查。", + after: "无变化", + }, + { + id: 3, item: "运行条件", + before: "运行参数:反应温度80±2℃,保温时间8小时,压力常压。\n管控措施:DCS温度高报警设定85℃,高高报警90℃并联锁切断加热介质。", + after: "运行参数:反应温度改为90±2℃,保温时间改为4小时,压力不变。\n管控措施:DCS温度高报警需上调至95℃,高高报警及联锁值需上调至100℃。", + hl: ["90±2℃", "4小时", "DCS温度高报警需上调至95℃,高高报警及联锁值需上调至100℃"], + }, + { id: 4, item: "操作方式", before: "DCS自动化控制,远程操作,单人监控。", after: "无变化" }, +]; +// ---------- AI 变更识别 ---------- +const runIdentify = () => { + if (!desc.value.trim()) { window.$message?.warning("请先输入变更内容描述"); return; } + analyzing.value = true; + rows.value = null; + setTimeout(() => { + rows.value = AI_ROWS.map((x) => ({ ...x })); + analyzing.value = false; + window.$message?.success("AI 变更识别完成,共 4 项,请逐项人工确认(可直接修改)"); + }, 1200); +}; + +const editing = ref(null); + +// ---------- 风险预分析 ---------- +const preRiskEdit = ref(null); +const preRiskShown = ref(false); +const preRiskText = ref({ + severity: "本次变更为缩合反应温度由80℃提升至90℃、保温时间由8h缩短至4h。变更前后反应体系与物料不变,不新增化学品,不存在新增燃爆、毒害、腐蚀等危害严重性变化;温度提升后仍在溶剂沸点与物料分解温度的安全裕度之内。综上,本次变更未显著增加潜在事件的危害严重程度,事故后果(人员伤亡、财产损失、环境污染)的严重等级与变更前基本一致;但杂质水平由0.05%升至0.12%,需关注长期运行对产品质量与设备结垢的累积影响。", + probability: "变更引入了新的偏差场景。首先,反应温度更接近溶剂回流温度,温控失效或冷却水中断时,超温溜温概率上升,可能引发冲料;其次,保温时间缩短使反应终点判断窗口变窄,人为误判导致转化率不足或副反应增加的概率上升;再者,未知杂质含量升高(0.05%→0.12%),其热稳定性尚未定性,长期累积可能加速釜壁结垢与搅拌负荷异常;此外,DCS报警/联锁值上调后原有报警裕度改变,误报、漏报概率需重新评估。", + protection: "变更主要影响与温度控制相关的保护层。原DCS温度高报警85℃、高高报警及联锁90℃已不适用于新工艺窗口,需同步上调至95℃/100℃并重新整定验证;安全阀起跳压力与泄放能力不受本次温度调整直接影响,仍然有效;操作规程与应急预案须修订后,方可继续作为有效的人为保护层。建议投用前完成联锁测试与报警验证,并将杂质含量纳入日常分析计划。", +}); +const runRiskAnalysis = () => { + analyzing.value = true; + setTimeout(() => { + analyzing.value = false; + preRiskShown.value = true; + window.$message?.success("AI 风险预分析报告已生成(危害严重性 / 事件概率 / 保护措施影响),内容支持手动修改"); + }, 1300); +}; +const saveDraft = () => window.$message?.success("已保存为草稿,可在左侧「我的草稿」中继续编辑"); + +// ---------- 生成变更申请单 ---------- +const formGen = ref("idle"); +const materialsText = ref(""); +const updateDocs = ref([]); +const disciplines = ref([]); +const tools = ref(["JSA", "检查表法", "通用检查表"]); +const plugin = ref<"HAZOP" | "JSA" | "检查表法" | "通用检查表" | null>(null); +const genForm = () => { + if (formGen.value === "generating") return; + formGen.value = "generating"; + window.$message?.info("AI 正在生成变更申请单…(「变更申请表」标签已显示生成中标识)"); + setTimeout(() => { + const main: string[] = []; + for (const row of rows.value ?? []) { + if (row.after && row.after !== "无变化" && row.item === "运行条件") { + main.push("缩合反应温度从80±2℃提升至90±2℃"); + main.push("保温时间从8小时缩短至4小时"); + main.push("DCS温度高报警从85℃上调至95℃,高高报警及联锁值从90℃上调至100℃"); + } + } + form.value = { + name: "缩合反应温度及时间优化", + dept: "", + mainChanges: main.length ? main : ["(请根据识别结果填写主要变更)"], + related: "更新操作规程、DCS联锁设定值、工艺安全信息、岗位操作法", + purposes: ["提高生产效能", "改善操作条件"], + effect: "在保持转化率不低于98%的前提下,反应时间缩短50%,产能提升一倍", + type: "工艺", level: "一般", duration: "永久", urgent: false, date: "", restoreDate: "", + }; + materialsText.value = "1. 施工方案(含作业步骤、隔离与置换方案、作业许可)\n2. 保温材料(釜体保温更换,硅酸铝纤维毡,厚度按设计核算)\n3. 紧固件与垫片(法兰螺栓、金属缠绕垫,材质与原设计一致)\n4. 防腐涂料(釜体外表面除锈防腐)\n5. 脚手架搭拆材料及验收记录"; + updateDocs.value = ["PID图纸", "操作规程", "总图", "设备台账"]; + disciplines.value = ["技术", "仪表"]; + signers.value = { 技术: "王仪表(技术部)", 仪表: "王仪表(技术部 · 仪表)" }; + tools.value = ["JSA", "检查表法", "通用检查表"]; + plugin.value = null; + formGen.value = "done"; + tab.value = "form"; + window.$message?.success("变更申请单已生成:AI 自动总结名称、预填内容,均可手动修改"); + }, 1400); +}; +// ---------- 审批流程设置 ---------- +const approvers = ref>({ + 部门审核: "李主任(一车间主任)", + 最终批准: "李主任(部门负责人 · 固定)", +}); +const signers = ref>({}); +const sheet = ref<"type" | "level" | "approver" | null>(null); +let demoSeq = 43; +function nextChangeId() { + return `MOC-2026-R01-${String(demoSeq++).padStart(4, "0")}`; +} +const today = () => new Date().toISOString().slice(0, 10); +interface LedgerRow { + id: string; + changeId?: string; // 关联 CHANGES,可打开完整详情 + title: string; + type: ChangeType; + level: ChangeLevel; + duration: "永久" | "临时"; + urgent?: boolean; + applyTime: string; // 申请时间 + dept: string; // 申请部门 + applicant: string; // 申请人 + planUse: string; // 计划投用时间 + status: ChangeStatus; + statusDetail: string; // 当前环节说明 + statusTime: string; // 状态更新时间 + overdueDays?: number; + approveTime?: string; // 审批通过时间 + useTime?: string; // 实际投用时间 + handlers: { name: string; done: boolean }[]; // 接班人(当前待办/已办) +} +const LEDGER_ROWS: LedgerRow[] = [ + { id: "MOC-2026-R01-0035", changeId: "MOC-2026-R01-0035", title: "R-201 反应釜搅拌器电机更换(55kW→75kW 防爆电机)", type: "设备", level: "重要", duration: "永久", applyTime: "2026-07-28 09:12", dept: "一车间", applicant: "张工艺", planUse: "2026-08-10", status: "审批中", statusDetail: "专业会签中(周设备、王仪表待签)", statusTime: "2026-07-30 14:20", handlers: [{ name: "王仪表", done: true }, { name: "周设备", done: false }, { name: "王仪表", done: false }] }, + { id: "MOC-2026-R01-0036", changeId: "MOC-2026-R01-0036", title: "聚合反应温度控制上限调整(78℃→82℃)", type: "工艺", level: "重要", duration: "永久", applyTime: "2026-07-25 10:05", dept: "一车间", applicant: "孙丽", planUse: "2026-08-05", status: "审批中", statusDetail: "安全审查(王海燕)", statusTime: "2026-07-29 16:40", handlers: [{ name: "王海燕", done: false }] }, + { id: "MOC-2026-R02-0038", changeId: "MOC-2026-R02-0038", title: "DCS 罐区液位报警值 LIA-301 调整", type: "工艺", level: "一般", duration: "永久", applyTime: "2026-07-20 08:30", dept: "一车间", applicant: "吴强", planUse: "2026-07-31", status: "待PSSR", statusDetail: "培训 / PSSR 资料已传 · 待确认投用", statusTime: "2026-07-27 11:15", approveTime: "2026-07-26 16:40", handlers: [{ name: "吴强", done: false }] }, + { id: "MOC-2026-R01-0039", changeId: "MOC-2026-R01-0039", title: "V-102 安全阀起跳压力临时调整(紧急补办)", type: "设备", level: "一般", duration: "临时", urgent: true, applyTime: "2026-07-15 19:40", dept: "一车间", applicant: "张工艺", planUse: "2026-07-16(已投用)", status: "待关闭", statusDetail: "待关闭确认(资料更新核查中)", statusTime: "2026-07-27 09:02", approveTime: "2026-07-15 21:05", useTime: "2026-07-16 06:30", overdueDays: 4, handlers: [{ name: "李主任", done: false }] }, + { id: "MOC-2026-R03-0040", changeId: "MOC-2026-R03-0040", title: "原料环己烷供应商变更(新增 B 供应商)", type: "管理", level: "重要", duration: "永久", applyTime: "2026-07-18 14:22", dept: "供应部", applicant: "刘芳", planUse: "2026-08-01", status: "实施中", statusDetail: "实施准备中 · 培训 / PSSR 资料待上传", statusTime: "2026-07-26 10:30", handlers: [{ name: "刘芳", done: false }] }, + { id: "MOC-2026-R02-0031", title: "冷冻盐水泵 P-103 叶轮材质变更", type: "设备", level: "一般", duration: "永久", applyTime: "2026-06-28 09:50", dept: "二车间", applicant: "周涛", planUse: "2026-07-15", status: "待验收", statusDetail: "变更验收(72h 运行验证)", statusTime: "2026-07-24 15:44", overdueDays: 7, handlers: [{ name: "李主任", done: false }] }, + { id: "MOC-2026-R01-0029", title: "操作规程修订(夏季工况)", type: "管理", level: "一般", duration: "临时", applyTime: "2026-06-20 11:26", dept: "一车间", applicant: "张工艺", planUse: "2026-07-01", status: "审批中", statusDetail: "部门审核(李主任)", statusTime: "2026-06-21 08:40", handlers: [{ name: "李主任", done: false }] }, + { id: "MOC-2026-R02-0033", title: "包装线贴标机控制程序升级", type: "设备", level: "一般", duration: "永久", applyTime: "2026-07-08 13:35", dept: "二车间", applicant: "吴强", planUse: "2026-08-02", status: "已批准", statusDetail: "待实施(计划 8 月 2 日投用)", statusTime: "2026-07-22 09:12", handlers: [{ name: "周设备", done: false }] }, + { id: "MOC-2026-R03-0027", title: "化验室通风橱整体更换", type: "设备", level: "一般", duration: "永久", applyTime: "2026-06-12 15:10", dept: "质量部", applicant: "陈静", planUse: "2026-06-25", status: "已关闭", statusDetail: "关闭确认完成,已归档", statusTime: "2026-07-02 10:18", handlers: [{ name: "钱峰", done: true }] }, + { id: "MOC-2026-R01-0024", title: "氮气管网压力分级调整", type: "工艺", level: "重要", duration: "永久", applyTime: "2026-05-30 09:00", dept: "一车间", applicant: "孙丽", planUse: "2026-06-20", status: "已关闭", statusDetail: "关闭确认完成,已归档", statusTime: "2026-06-28 16:30", handlers: [{ name: "李主任", done: true }, { name: "刘副总", done: true }] }, +]; +const ROLES = [ + { id: "applicant", name: "申请人", person: "张工艺", org: "一车间 · 工艺组", desc: "发起变更申请、AI 辅助判定、跟踪进度" }, + { id: "process", name: "专业会签(仪表)", person: "王仪表", org: "技术部 · 仪表科", desc: "专业会签、HAZOP 分析、确认连带变更" }, + { id: "process2", name: "专业会签(设备)", person: "周设备", org: "设备管理部 · 设备科", desc: "专业会签、设备完整性检查、行动项落实" }, + { id: "safety", name: "安全工程师", person: "王海燕", org: "安全环保部", desc: "安全审查、PSSR 检查表确认、风险分析组织" }, + { id: "dept", name: "车间主任", person: "李主任", org: "一车间", desc: "部门审核、现场验收、变更关闭确认" }, + { id: "vp", name: "分管领导", person: "刘副总", org: "公司领导", desc: "重要变更最终批准、移动端审批" }, + { id: "admin", name: "系统管理员", person: "刘敏", org: "信息化部", desc: "流程配置、字典维护、权限分配" }, + { id: "quality", name: "质量工程师", person: "陈质量", org: "质量部", desc: "质量会签、产品合格判定、检验方案确认" }, + { id: "viewer", name: "非审批人员", person: "吴新", org: "相关部门", desc: "以信息查看为主,不参与变更流程" }, +]; +function nowStr() { + const d = new Date(); + const p = (n: number) => String(n).padStart(2, "0"); + return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`; +} +type DemoListener = () => void; +const demoListeners = new Set(); +function emitDemo() { demoListeners.forEach((f) => f()); } +function submitChange(c: ChangeOrder) { + CHANGES.unshift(c); + const cur = c.flow.find((n) => n.status === "current"); + LEDGER_ROWS.unshift({ + id: c.id, + changeId: c.id, + title: c.title, + type: c.type, + level: c.level, + duration: c.duration, + urgent: c.urgent || undefined, + applyTime: nowStr(), + dept: c.org.split("·")[0].trim(), + applicant: c.applicant, + planUse: c.date || "待定", + status: c.status, + statusDetail: cur ? `${cur.name}(待处理)` : "审批中", + statusTime: nowStr(), + handlers: (cur?.roles ?? []).map((rid) => ({ name: ROLES.find((r) => r.id === rid)?.person ?? rid, done: false })), + }); + emitDemo(); +} +// ---------- 提交 ---------- +const submitApply = () => { + if (!desc.value.trim()) { window.$message?.warning("请先录入变更描述并完成 AI 识别"); return; } + if (!form.value) { window.$message?.warning("请先在「变更预识别」页点击「生成变更申请单」,生成申请表后再提交"); return; } + const unconfirmed = ["form", "risk", "train", "pssr", "accept", "close"].filter((t) => !confirmed.value[t]); + if (unconfirmed.length) { + blockedTabs.value = unconfirmed; + window.$message?.warning(`全部标签页确认后方可提交,请先完成以下标签页的「内容确认完毕」(标签栏已用红点标出):${unconfirmed.map((t) => TAB_NAME[t]).join("、")}`); + return; + } + blockedTabs.value = []; + const id = nextChangeId(); + const level: ChangeLevel = form.value.level === "重要" ? "重要" : "一般"; + const flow: any[] = level === "重要" + ? [ + { name: "部门审核", kind: "审批", roles: ["dept"], status: "current" }, + { name: "专业会签", kind: "会签", roles: ["process", "process2"], status: "todo", locked: true, members: [{ name: "王仪表(仪表)", done: false }, { name: "周设备(设备)", done: false }] }, + { name: "安全审查", kind: "审批", roles: ["safety"], status: "todo", locked: true }, + { name: "分管领导最终批准", kind: "最终批准", roles: ["vp"], status: "todo", locked: true }, + ] + : [ + { name: "部门审核", kind: "审批", roles: ["dept"], status: "current" }, + { name: "专业审批", kind: "审批", roles: ["process"], status: "todo", locked: true }, + { name: "部门负责人批准", kind: "最终批准", roles: ["dept"], status: "todo", locked: true }, + ]; + const order: ChangeOrder = { + id, + title: form.value.name || desc.value.slice(0, 24) || "未命名变更", + type: (form.value.type || "工艺") as ChangeType, + level, + duration: form.value.duration === "临时" ? "临时" : "永久", + urgent: !!form.value.urgent, + status: "审批中", + applicant: r.person, + org: form.value.dept || r.org, + device: "—", + date: today(), + purpose: form.value.purposes.join("、") || "提高生产效能", + effect: form.value.effect || "—", + before: rows.value?.map((x) => `${x.item}:${x.before}`).join(";") || desc.value.slice(0, 60), + after: rows.value?.map((x) => `${x.item}:${x.after}`).join(";") || "—", + related: form.value.related ? form.value.related.split("、") : updateDocs.value, + materials: materialsText.value ? materialsText.value.split("\n").filter(Boolean) : [], + riskTools: tools.value, + flow, + }; + submitChange(order); + window.$message?.success(`已提交 ${id},进入「部门审核」节点(台账 / 审批中心 / 角标已联动)`); + // emit("openChange", order); +}; + - + diff --git a/src/views/home/modules/HighlightText.vue b/src/views/home/modules/HighlightText.vue new file mode 100644 index 0000000..ec63c5f --- /dev/null +++ b/src/views/home/modules/HighlightText.vue @@ -0,0 +1,36 @@ + +