/** * Generate S3 供应协同模块蓝图设计方案.docx * 参照 generate_s1_blueprint_docx.js 模板格式 * 章节结构: 封面 → 文档控制 → TOC → Ch1 总体方案 → Ch2~12 功能域(各8子节) → Ch13 数据中台 → Ch14 权限汇总 */ const fs = require('fs'); const sharp = require('sharp'); const { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, HeadingLevel, AlignmentType, BorderStyle, WidthType, ShadingType, convertInchesToTwip, PageBreak, ImageRun, TabStopType, TabStopPosition, TableOfContents } = require('docx'); // ═══════════════════════════════════════════════════ // 通用样式与辅助函数 (from S1 template) // ═══════════════════════════════════════════════════ const FONT = '微软雅黑'; const thinBorder = { top: { style: BorderStyle.SINGLE, size: 1 }, bottom: { style: BorderStyle.SINGLE, size: 1 }, left: { style: BorderStyle.SINGLE, size: 1 }, right: { style: BorderStyle.SINGLE, size: 1 }, }; const headerShading = { fill: '4472C4', type: ShadingType.CLEAR }; function p(text, opts = {}) { return new Paragraph({ children: [new TextRun({ text, size: 21, font: FONT, ...opts })], spacing: { after: 120, line: 360 }, }); } function bp(text) { return p(text, { bold: true }); } function empty() { return new Paragraph({ spacing: { after: 80 }, children: [] }); } function pageBreak() { return new Paragraph({ children: [new PageBreak()] }); } function h1(text) { return new Paragraph({ children: [new TextRun({ text, bold: true, size: 32, font: FONT })], heading: HeadingLevel.HEADING_1, spacing: { before: 400, after: 200 }, }); } function h2(text) { return new Paragraph({ children: [new TextRun({ text, bold: true, size: 28, font: FONT })], heading: HeadingLevel.HEADING_2, spacing: { before: 300, after: 150 }, }); } function h3(text) { return new Paragraph({ children: [new TextRun({ text, bold: true, size: 24, font: FONT })], heading: HeadingLevel.HEADING_3, spacing: { before: 200, after: 100 }, }); } function bullet(text, indent = 0) { return new Paragraph({ children: [new TextRun({ text: ` ${text}`, size: 21, font: FONT })], spacing: { after: 60, line: 340 }, indent: { left: 300 + indent * 400 }, }); } // Table helpers function hdrCell(text, w = 1800) { return new TableCell({ children: [new Paragraph({ children: [new TextRun({ text, bold: true, size: 20, font: FONT, color: 'FFFFFF' })], alignment: AlignmentType.CENTER })], width: { size: w, type: WidthType.DXA }, borders: thinBorder, shading: headerShading, }); } function tc(text, w = 1800, opts = {}) { return new TableCell({ children: [new Paragraph({ children: [new TextRun({ text: String(text ?? ''), size: 20, font: FONT })], alignment: opts.center ? AlignmentType.CENTER : AlignmentType.LEFT })], width: { size: w, type: WidthType.DXA }, borders: thinBorder, }); } function table(headers, rows, widths) { return new Table({ rows: [ new TableRow({ children: headers.map((h, i) => hdrCell(h, widths ? widths[i] : 1800)), tableHeader: true }), ...rows.map(r => new TableRow({ children: r.map((c, i) => tc(c, widths ? widths[i] : 1800)) })), ], width: { size: 100, type: WidthType.PERCENTAGE }, }); } // ── 活动流程表(6列) ── function activityTable(rows) { const w = [600, 1400, 1100, 3800, 1400, 1700]; return table(['编号', '活动名称', '执行角色', '活动描述', '输入', '输出'], rows, w); } // ── 业务规则表(3列) ── function ruleTable(rows) { return table(['序列号', '业务情形', '描述/方案'], rows, [900, 2800, 6300]); } // ── 接口表(4列) ── function interfaceTable(rows) { return table(['序号', '接口名称', '接口说明', '频次及触发方式'], rows, [600, 2400, 4200, 2800]); } // ── 报表表(4列) ── function reportTable(rows) { return table(['序号', '名称', '描述', '方案'], rows, [600, 2600, 3600, 3200]); } // ── 权限表(3列) ── function permTable(rows) { return table(['序号', '岗位名称', '对应系统权限'], rows, [600, 2000, 7400]); } // ═══════════════════════════════════════════════════ // 目录 (TOC) // ═══════════════════════════════════════════════════ const TOC2_TAB = 2880; const TOC3_TAB = 3600; const TOC_FONT_SIZE = 20; function tocChapter(num, title) { return new Paragraph({ children: [ new TextRun({ text: String(num), size: TOC_FONT_SIZE, font: FONT }), new TextRun({ text: '\t', size: TOC_FONT_SIZE, font: FONT }), new TextRun({ text: title, bold: true, size: TOC_FONT_SIZE, font: FONT }), new TextRun({ text: '\t', size: TOC_FONT_SIZE, font: FONT }), new TextRun({ text: ' ', size: TOC_FONT_SIZE, font: FONT }), ], tabStops: [ { type: TabStopType.LEFT, position: TOC2_TAB }, { type: TabStopType.RIGHT, position: TabStopPosition.MAX }, ], spacing: { before: 80, after: 40 }, }); } function tocSub(num, title) { return new Paragraph({ children: [ new TextRun({ text: String(num), size: TOC_FONT_SIZE, font: FONT }), new TextRun({ text: '\t', size: TOC_FONT_SIZE, font: FONT }), new TextRun({ text: title, size: TOC_FONT_SIZE, font: FONT }), new TextRun({ text: '\t', size: TOC_FONT_SIZE, font: FONT }), new TextRun({ text: ' ', size: TOC_FONT_SIZE, font: FONT }), ], tabStops: [ { type: TabStopType.LEFT, position: TOC3_TAB }, { type: TabStopType.RIGHT, position: TabStopPosition.MAX }, ], spacing: { before: 30, after: 30 }, }); } function buildTOC() { const ch = []; ch.push(new TableOfContents('目录', { headingStyleRange: '1-2', hyperlink: true })); ch.push(new Paragraph({ children: [new TextRun({ text: '(如目录未显示,请在 Word 中右键此处 → 更新域)', size: 18, font: FONT, italics: true, color: '888888' })], spacing: { before: 40, after: 200 }, })); ch.push(tocChapter('', '文档控制')); ch.push(tocSub('', '更改记录')); ch.push(tocSub('', '审核')); ch.push(tocSub('', '发布')); ch.push(tocChapter('', '目录')); // 第1章 ch.push(tocChapter('1', '总体业务方案')); ch.push(tocSub('1.1', '目标和宗旨')); ch.push(tocSub('1.2', '总体业务流程图')); ch.push(tocSub('1.3', '方案设计')); // 第2~12章(8子章节) const chSubs = [ '目标/宗旨', '业务流程图', '业务流程说明', '业务流程规则', '变化和改进点', '权限管理需求', '系统接口集成', '报表需求', ]; const chTitles = [ '物料需求计划', '物料交货计划', '交货单异常记录', '要货令', '物料采购申请', '物料采购订单', '委外加工订单', '工序外协订单', '供应协同看板', '工单物料齐套上线看板', 'MDP 运行监控', ]; for (let i = 0; i < chTitles.length; i++) { const n = i + 2; ch.push(tocChapter(String(n), chTitles[i])); for (let j = 0; j < chSubs.length; j++) { ch.push(tocSub(`${n}.${j + 1}`, chSubs[j])); } } // 第13章 ch.push(tocChapter('13', '数据中台架构')); ['目标/宗旨', '分层设计', 'S3核心数据流', '对象映射总表', 'MDP作业调度'].forEach((title, i) => { ch.push(tocSub(`13.${i + 1}`, title)); }); // 第14章 ch.push(tocChapter('14', '权限管理汇总')); return ch; } // ═══════════════════════════════════════════════════ // 流程图生成 (S1 style: 纵向左角色+右节点) // ═══════════════════════════════════════════════════ const FLOW_W = 680, BOX_W = 220, BOX_H = 42, GAP_Y = 28; const ROLE_X = 30, BOX_X = 130, MARGIN_Y = 40; const flowImageCache = {}; function flowImageParagraph(pngBuffer) { return new Paragraph({ children: [new ImageRun({ data: pngBuffer, transformation: { width: 540, height: 360 }, type: 'png' })], alignment: AlignmentType.CENTER, spacing: { before: 120, after: 120 }, }); } async function generateFlowPNG(steps) { const N = steps.length; const svgH = MARGIN_Y * 2 + N * (BOX_H + GAP_Y) - GAP_Y; const centerX = BOX_X + BOX_W / 2; let svg = ``; svg += ``; steps.forEach((s, i) => { const y = MARGIN_Y + i * (BOX_H + GAP_Y); svg += `${s.role || ''}`; const isStart = i === 0, isEnd = i === N - 1; const fill = isStart ? '#1565C0' : (isEnd ? '#2E7D32' : '#E3F2FD'); const stroke = isStart ? '#0D47A1' : (isEnd ? '#1B5E20' : '#1565C0'); const textColor = (isStart || isEnd) ? '#FFFFFF' : '#333333'; svg += ``; svg += `${s.label}`; if (i < N - 1) { const ay = y + BOX_H + 4, by2 = ay + GAP_Y - 8; svg += ``; svg += ``; } }); svg += ''; return sharp(Buffer.from(svg)).png().toBuffer(); } // 第1章专用:S3 总体业务流程图(三区: 物料计划 → 采购执行 → 协同看板) async function generateOverviewFlowPNG() { const W = 780, H = 580; let svg = ``; svg += ``; svg += `S3 供应协同 — 总体业务流程`; // 三区背景 const zones = [ { y: 42, h: 170, color: '#E8F0FE', label: '物料计划域(需求→计划→异常)', lx: 10, ly: 60 }, { y: 220, h: 200, color: '#FFF3E0', label: '采购管理域(申请→合并生成要货令/采购订单/委外加工→工单外协)', lx: 10, ly: 238 }, { y: 428, h: 120, color: '#E8F5E9', label: '供应协同看板域(KPI监控→齐套→数据中台)', lx: 10, ly: 446 }, ]; zones.forEach(z => { svg += ``; svg += `${z.label}`; }); // 物料计划域节点 const mpNodes = [ { x: 30, y: 85, w: 130, label: 'MDP数据同步\n(工单/库存/在途)', color: '#1565C0' }, { x: 190, y: 85, w: 130, label: 'MRP净需求计算', color: '#1565C0' }, { x: 350, y: 85, w: 120, label: '发布物料需求', color: '#1565C0' }, { x: 500, y: 85, w: 120, label: '交货计划跟踪', color: '#2E7D32' }, { x: 350, y: 145, w: 120, label: '交货异常记录', color: '#F57C00' }, ]; mpNodes.forEach(n => { const fill = n.color === '#F57C00' ? '#FFF3E0' : n.color; const stroke = n.color === '#F57C00' ? '#E65100' : n.color; const tc = (n.color === '#1565C0' || n.color === '#2E7D32') ? '#fff' : '#333'; svg += ``; const lines = n.label.split('\n'); const cy = n.y + 18; lines.forEach((l, li) => { const off = (lines.length - 1) * -7 + li * 14; svg += `${l}`; }); }); // MP arrows svg += ``; svg += ``; svg += ``; svg += ``; svg += ``; svg += ``; svg += ``; svg += ``; // 采购管理域节点 // Row 1: 物料采购申请(起点—根据物料类型自动合并生成对应订单) const applyNode = { x: 230, y: 255, w: 320, h: 44, label: '物料采购申请\n(根据物料类型自动合并生成要货令/采购订单/委外加工订单)', color: '#1565C0' }; (() => { const n = applyNode; svg += ``; const lines = n.label.split('\n'); const cy = n.y + n.h / 2; lines.forEach((l, li) => { const off = (lines.length - 1) * -7 + li * 14; svg += `${l}`; }); })(); // Row 2: 三路分支(要货令 / 采购订单 / 委外加工订单) const peBranchNodes = [ { x: 30, y: 318, w: 160, h: 40, label: '要货令\n(DO类型)', color: '#E65100' }, { x: 220, y: 318, w: 160, h: 40, label: '采购订单\n(PO类型)', color: '#E65100' }, { x: 410, y: 318, w: 160, h: 40, label: '委外加工订单\n(PW类型)', color: '#6A1B9A' }, ]; peBranchNodes.forEach(n => { const isPurple = n.color === '#6A1B9A'; const fill = isPurple ? '#F3E5F5' : n.color; const stroke = isPurple ? '#6A1B9A' : n.color; const tc = isPurple ? '#333' : '#fff'; svg += ``; const lines = n.label.split('\n'); const cy = n.y + n.h / 2; lines.forEach((l, li) => { const off = (lines.length - 1) * -7 + li * 14; svg += `${l}`; }); }); // Row 3: 工单下达→工序外协订单(独立分支) const peExtNodes = [ { x: 140, y: 378, w: 130, h: 40, label: '工单下达', color: '#1565C0' }, { x: 330, y: 378, w: 180, h: 40, label: '工序外协订单\n(工单工序关联)', color: '#6A1B9A' }, ]; peExtNodes.forEach(n => { const isPurple = n.color === '#6A1B9A'; const fill = isPurple ? '#F3E5F5' : n.color; const stroke = isPurple ? '#6A1B9A' : n.color; const tc = isPurple ? '#333' : '#fff'; svg += ``; const lines = n.label.split('\n'); const cy = n.y + n.h / 2; lines.forEach((l, li) => { const off = (lines.length - 1) * -7 + li * 14; svg += `${l}`; }); }); // PE arrows // 申请 → 三路分支 const applyCx = applyNode.x + applyNode.w / 2; const applyBot = applyNode.y + applyNode.h; peBranchNodes.forEach(n => { const nx = n.x + n.w / 2; svg += ``; svg += ``; }); // 工单下达 → 工序外协 svg += ``; svg += ``; // 分隔标注 svg += `↓ 工单下达时自动生成工序外协订单 ↓`; // 三路分支水平关联虚线 svg += ``; svg += ``; // 供应协同看板域节点 const kbNodes = [ { x: 30, y: 465, w: 140, label: '4维KPI卡片\n+趋势箭头', color: '#2E7D32' }, { x: 210, y: 465, w: 140, label: '工单齐套看板\n(30+字段)', color: '#2E7D32' }, { x: 390, y: 465, w: 140, label: 'MDP运行监控\n(任务状态)', color: '#0D47A1' }, { x: 570, y: 465, w: 140, label: '策略模拟\nWhat-If分析', color: '#B71C1C' }, ]; kbNodes.forEach(n => { const fill = n.color === '#B71C1C' ? '#FFEBEE' : n.color; const stroke = n.color === '#B71C1C' ? '#C62828' : n.color; const tc = (n.color === '#2E7D32' || n.color === '#0D47A1') ? '#fff' : '#333'; svg += ``; const lines = n.label.split('\n'); const cy = n.y + 24; lines.forEach((l, li) => { const off = (lines.length - 1) * -7 + li * 14; svg += `${l}`; }); }); svg += ``; svg += ``; svg += ``; svg += ``; svg += ``; svg += ``; // 串联标注 svg += `↓ 已发布需求驱动采购申请(按物料类型自动合并) ↓`; svg += `↓ 采购订单数据进入DWD宽表供看板消费 ↓`; // 数据标签 svg += `数据链路: 外部系统(ERP/MES/SRM) → MDP入站 → ODS(STG) → STD → DWD宽表 → KPI指标层 → 看板消费`; svg += ''; return sharp(Buffer.from(svg)).png().toBuffer(); } // ═══════════════════════════════════════════════════ // 章节构建函数:8 子章节 // ═══════════════════════════════════════════════════ function buildChapter(num, title, cfg) { const ch = []; const pre = `${num}.`; // §X.1 目标/宗旨 ch.push(h2(`${pre}1 目标/宗旨`)); (cfg.targets || []).forEach(t => ch.push(bullet(t))); // §X.2 业务流程图 ch.push(h2(`${pre}2 业务流程图`)); const img = cfg.flowImage || (cfg.flowSteps ? flowImageCache[num] : null); if (img) { ch.push(flowImageParagraph(img)); } else { ch.push(p('(见系统操作流程图 / 附件 Visio 流程图)')); } if (cfg.flowNote) ch.push(p(cfg.flowNote)); // §X.3 业务流程说明 ch.push(h2(`${pre}3 业务流程说明`)); if (cfg.activities && cfg.activities.length) { ch.push(activityTable(cfg.activities)); } else { ch.push(p('参照系统页面操作流程,主要操作步骤包含:')); (cfg.activityDesc || []).forEach(a => ch.push(bullet(a))); } // §X.4 业务流程规则 ch.push(h2(`${pre}4 业务流程规则`)); if (cfg.rules && cfg.rules.length) { ch.push(ruleTable(cfg.rules)); } else { ch.push(p('无特殊业务规则')); } // §X.5 变化和改进点 ch.push(h2(`${pre}5 变化和改进点`)); (cfg.improvements || []).forEach(i => ch.push(bullet(i))); // §X.6 权限管理需求 ch.push(h2(`${pre}6 权限管理需求`)); if (cfg.permissions && cfg.permissions.length) { ch.push(permTable(cfg.permissions)); } else { ch.push(p('参照第 14 章 权限管理汇总')); } // §X.7 系统接口集成 ch.push(h2(`${pre}7 系统接口集成`)); if (cfg.interfaces && cfg.interfaces.length) { ch.push(interfaceTable(cfg.interfaces)); } else { ch.push(p('无外部系统接口;页面数据通过 Admin.NET 内置 API 获取')); } // §X.8 报表需求 ch.push(h2(`${pre}8 报表需求`)); if (cfg.reports && cfg.reports.length) { ch.push(reportTable(cfg.reports)); } else { ch.push(p('无独立报表需求,相关数据通过看板和列表页面查看')); } return ch; } // ═══════════════════════════════════════════════════ // 章节数据配置 // ═══════════════════════════════════════════════════ // ── Chapter 2: 物料需求计划 ── const _ch2cfg = { targets: [ '实现物料需求计划的在线管理,通过MDP同步外部系统工单需求、库存和采购在途数据。', '利用MRP逻辑自动计算物料净需求,生成可供发布的物料需求计划,为采购管理和交货计划提供数据基础。', '核心KPI为物料净需求的准确性和计划发布的及时性。', ], flowNote: '流程路径:MDP数据同步(工单/库存/在途) → MRP净需求计算 → 勾选发布/全部发布 → 手动调整 → 驱动采购申请/交货计划。', flowSteps: [ { label: 'MDP数据同步(工单/库存/在途)', role: '物料计划员' }, { label: 'MRP净需求计算', role: '物料计划员' }, { label: '勾选发布/全部发布', role: '物料计划员' }, { label: '手动新增/编辑/删除', role: '物料计划员' }, { label: '驱动采购申请/交货计划', role: '系统自动' }, ], activities: [ ['10', '数据同步', '系统(MDP)', 'MDP定时从ERP同步工单需求、库存和采购在途数据写入ODS层', '外部系统数据', 'ODS数据'], ['20', 'MRP净需求计算', '系统(DWD)', 'DWD层清洗关联,计算To-be-Scheduled Qty = MES Qty - Loc Qty - Scheduled Qty', 'ODS工单/库存/在途数据', '物料净需求结果'], ['30', '计划查询筛选', '物料计划员', '按物料编码、物料名称、需求日期等维度过滤查询,支持分页和列设置', '查询条件', '物料需求列表'], ['40', '发布管理', '物料计划员', '支持勾选定向发布或一键全部发布,发布后状态变为"已发布",可取消发布回退', '未发布计划', '已发布/取消发布计划'], ['50', '手动CRUD', '物料计划员', '支持手动新增、编辑、删除物料需求记录,满足特殊场景灵活调整', '手动录入数据', '更新后计划'], ], rules: [ ['1', '净需求计算公式', 'To-be-Scheduled Qty = MES Qty - Loc Qty - Scheduled Qty,结果为负时净需求为零'], ['2', '发布校验', '发布前不做业务规则校验,计划员自行确认数据准确性后执行;仅已发布状态可取消发布'], ['3', '删除限制', '删除操作需二次确认,防止误操作'], ['4', '数据隔离', '不同租户数据通过租户ID隔离,同一租户内计划员共享视图'], ], improvements: [ '原ERP物料需求计算为离线批处理,S3通过MDP实时同步将计算频率从"每日一次"提升为"近实时"。', '新增勾选发布和全部发布两种模式,替代原系统单一全量发布方式,提高操作灵活性。', '新增取消发布功能,填补原系统缺乏"发布回退"能力的空白。', '新增列设置功能,不同角色可按需配置显示的字段组合。', ], permissions: [ ['1', '物料计划员', '查看和增删改查权限;发布/取消发布操作权限'], ['2', '采购员/供应链经理', '仅查看权限(只读)'], ], interfaces: [ ['1', 'MDP入站-工单需求', '从ERP同步工单需求数据(work_order_demand)', '定时(日)'], ['2', 'MDP入站-库存快照', '从库存系统同步期初库存(inventory snapshot)', '定时(日)'], ['3', 'MDP入站-在途采购', '从SRM同步采购在途数据', '定时(日)'], ['4', 'MDP出站-需求发布', '发布后物料需求计划同步至SRM驱动采购申请', '发布时触发'], ], reports: [ ['1', '物料需求计划明细报表', '按日期范围导出指定物料的需求计算明细', 'Excel/CSV格式'], ['2', '需求计划发布统计报表', '按时间段统计发布数量、发布及时率', '按周/月'], ['3', '需求满足率趋势报表', '按周/月展示物料净需求满足趋势', '趋势图表'], ], }; const ch2 = () => buildChapter('2', '物料需求计划', _ch2cfg); // ── Chapter 3: 物料交货计划 ── const _ch3cfg = { targets: [ '基于已发布物料需求计划生成交货计划,并驱动供应商端交货计划同步。', '通过交货状态同步实现供应商与计划端的双向信息互通,提升交货管理的协同效率。', ], flowNote: '流程路径:已发布物料需求计划 → 交货计划生成 → 驱动供应商交货计划 → 交货状态同步。', flowSteps: [ { label: '已发布物料需求计划', role: '物料计划员' }, { label: '交货计划生成', role: '物料计划员' }, { label: '驱动供应商交货计划', role: '物料计划员' }, { label: '交货状态同步', role: '系统自动' }, ], activities: [ ['10', '需求发布', '物料计划员', '基于MRP净需求计算结果确认并发布物料需求计划,作为交货计划的输入来源', 'MRP净需求结果', '已发布物料需求计划'], ['20', '计划生成', '系统(MDP)', '基于已发布物料需求计划自动生成交货计划,含物料、供应商、计划交期等核心信息', '已发布需求', '交货计划记录'], ['30', '驱动供应商', '物料计划员/系统', '交货计划同步至供应商端,驱动供应商按计划安排生产和交货', '交货计划', '供应商交货计划'], ['40', '状态同步', '系统(MDP)', '供应商交货状态回传至计划端,实现双向信息同步更新', '供应商交货状态', '同步后交货计划'], ], rules: [ ['1', '生成条件', '仅基于已发布物料需求计划生成交货计划,未发布需求不进入交货计划流程'], ['2', '供应商驱动', '交货计划生成后自动同步至供应商端,驱动供应商按计划安排交货'], ['3', '状态同步规则', '供应商交货状态变更时自动回传至计划端,确保计划与执行数据一致'], ['4', '交货单号唯一性', '每个交货计划行对应唯一dsnum,用于与供应商端交货单关联匹配'], ], improvements: [ '从原ERP中交货计划与采购订单混合管理升级为独立专项页面,聚焦交货协同视角。', '新增供应商交货计划驱动机制,替代原系统单向信息传递方式,实现双向协同。', '新增交货状态自动同步功能,供应商交货反馈实时回传至计划端。', ], permissions: [ ['1', '物料计划员', '查看和操作权限'], ['2', '采购员/仓库管理员', '仅查看权限'], ['3', '供应链经理', '查看和导出权限'], ], interfaces: [ ['1', 'MDP入站-需求发布', '从物料需求计划读取已发布需求', '发布时触发'], ['2', 'MDP出站-交货计划', '交货计划同步至供应商端驱动生产和交货', '计划生成时'], ['3', 'MDP入站-交货状态', '供应商交货状态变更回传至计划端', '状态变更时'], ['4', '核心数据表', 'srm_polist_ds(采购订单交付计划)', '实时关联'], ], reports: [ ['1', '交货计划执行报表', '按供应商/物料统计交货计划生成与执行情况', '按周/月'], ['2', '供应商交货准时率报表', '按时间段统计各供应商交货准时率', '供应商维度'], ['3', '交货状态同步报表', '监控交货状态同步成功率和延迟情况', '实时监控'], ], }; const ch3 = () => buildChapter('3', '物料交货计划', _ch3cfg); // ── Chapter 4: 交货单异常记录 ── const _ch4cfg = { targets: [ '提供交货过程中产生的异常记录的只读查询视图,帮助物料计划员和质量管理人员快速掌握交货逾期、短缺、质量等异常情况。', '异常数据来源于系统自动比对的交货计划与实际交货差异,为供应链风险管理和供应商绩效评估提供数据支撑。', ], flowNote: '流程路径:MDP同步交货数据 → 系统自动比对计划vs实际 → 差异超阈值自动标记异常 → 异常记录列表展示 → 多维筛选查询 → 明细查看/导出。', flowSteps: [ { label: 'MDP同步交货数据', role: '系统(MDP)' }, { label: '系统自动比对计划vs实际差异', role: '系统自动' }, { label: '超阈值自动标记异常记录', role: '系统自动' }, { label: '多维筛选查询(单号/供应商/类型/日期)', role: '物料计划员' }, { label: '明细查看/导出', role: '物料计划员' }, ], activities: [ ['10', '异常自动标记', '系统(MDP)', '基于交货计划与实际交货数据自动比对,逾期超3天或实收<计划80%时自动生成异常标记', '交货执行数据', '异常记录'], ['20', '异常记录查询', '计划员/质量员', '按交货单号、供应商、异常类型、计划日期范围多维度筛选查询', '筛选条件', '异常记录列表'], ['30', '明细查看', '计划员/质量员', '查看每条异常记录的详细信息:来源交货单、物料、计划/实际数量、异常原因', '异常记录', '异常详情'], ['40', '数据导出', '计划员', '将当前查询结果导出为CSV/Excel文件', '查询结果', '导出文件'], ], rules: [ ['1', '自动标记条件', '逾期超过3个工作日未到货,或实收数量<计划数量80%时,系统自动标记为异常记录'], ['2', '数据来源', '异常记录数据来源于MDP同步的交货计划和实际交货数据自动比对结果'], ['3', '只读视图', '该页面为只读查询视图,不支持手动新增、编辑或删除异常记录,确保数据客观性'], ['4', '可追溯性', '每条异常记录可关联到原始交货计划记录,追溯异常来源和影响范围'], ], improvements: [ '从原系统"纸质异常报告+Excel人工比对"升级为系统自动识别和在线查询,减少人工发现异常的延迟和遗漏。', '新增自动触发规则,系统根据阈值自动标记异常,替代原系统完全依赖人工发现的方式。', '异常数据与供应商绩效评估模块联动,为供应商评级提供量化依据。', ], permissions: [ ['1', '物料计划员', '查看和导出权限'], ['2', '质量管理员', '查看权限(质量追溯)'], ['3', '供应链经理', '查看和导出权限'], ], interfaces: [ ['1', '交货差异比对', 'MDP从交货计划与收货数据自动比对计划vs实际差异', '定时(日)'], ['2', '核心数据表', 'DeliveryExceptionMaster(交货异常记录视图)', '只读查询'], ], reports: [ ['1', '交货异常统计报表', '按供应商/异常类型/时间段统计异常数量及趋势', '按周/月'], ['2', '供应商异常率排名报表', '按异常发生率对供应商排名,用于供应商绩效评估', '供应商维度'], ], }; const ch4 = () => buildChapter('4', '交货单异常记录', _ch4cfg); // ── Chapter 5: 要货令 ── const _ch5cfg = { targets: [ '承接物料采购申请驱动的要货指令(Demand Order)在线管理,作为采购执行的具体载体。', '通过供应选择和物料选择确保要货令的精准下达,建立从申请到执行的衔接。', ], flowNote: '流程路径:物料采购申请驱动 → 要货令创建 → 供应选择 → 物料选择 → 订单保存。', flowSteps: [ { label: '物料采购申请驱动', role: '采购员' }, { label: '要货令创建', role: '采购员' }, { label: '供应选择', role: '采购员' }, { label: '物料选择', role: '采购员' }, { label: '订单保存', role: '采购员' }, ], activities: [ ['10', '申请驱动', '采购员', '接收已批准物料采购申请驱动信号,启动要货令创建流程', '已批准采购申请', '要货令创建入口'], ['20', '要货令创建', '采购员', '填写要货令核心信息:单号、采购组、部门、日期、合同编号等', '采购申请驱动', '要货令主记录'], ['30', '供应选择', '采购员', '从货源清单动态加载下拉选择供应商和采购组,确保数据实时性', '货源清单', '选定供应商/采购组'], ['40', '物料选择', '采购员', '选择要货物料,填写需求数量、交货日期等明细信息', '物料列表', '要货令明细行'], ['50', '订单保存', '采购员', '确认无误后保存要货令,生成DO类型采购订单记录', '要货令数据', '已保存要货令(PurOrdMaster/DO)'], ], rules: [ ['1', '驱动来源', '要货令由已批准物料采购申请驱动生成,确保需求来源可追溯'], ['2', '必填校验', '供应商、物料、需求数量为必填字段,提交时进行非空校验'], ['3', '供应校验', '选择的供应商须在有效货源清单中,确保货源合规'], ['4', '单号唯一性', '要货令单号需保证唯一性,删除操作需二次确认'], ], improvements: [ '从原采购申请/要货令混合管理升级为采购申请驱动→要货令执行的清晰链路。', '新增供应选择独立步骤,从货源清单动态加载,确保供应商资质合规。', '新增物料选择独立步骤,支持明细行级精准管理。', ], permissions: [ ['1', '采购员', '增删改查全部权限'], ['2', '供应链经理', '查看权限'], ], interfaces: [ ['1', 'MDP入站-采购申请', '从物料采购申请读取已批准申请作为驱动来源', '申请批准时触发'], ['2', 'MDP入站-供应商数据', '供应商和采购组数据从SRM系统同步', '定时(日)'], ['3', 'MDP出站-要货令', '保存后要货令数据同步至ERP', '保存时触发'], ['4', '核心数据表', 'PurOrdMaster(采购订单主表,ReqBy=DO类型)', '实时'], ], reports: [ ['1', '要货令执行报表', '按时间段统计要货令数量和供应商分布', '按周/月'], ['2', '供应商要货令统计', '按供应商维度汇总要货令下发情况', '供应商维度'], ], }; const ch5 = () => buildChapter('5', '要货令', _ch5cfg); // ── Chapter 6: 物料采购申请 ── const _ch6cfg = { targets: [ '承接物料交货计划和MRP检查输出的采购需求,通过规范的申请-审批流程确保采购需求的合理性和合规性。', '批准后根据物料类型自动驱动生成对应的采购订单(PO)、要货令(DO)或委外加工订单(PW),作为采购执行的依据。', ], flowNote: '流程路径:物料交货计划/MRP检查 → 采购申请创建 → 审核/批准 → 驱动采购订单/要货令/委外加工订单生成。', flowSteps: [ { label: '物料交货计划/MRP检查驱动', role: '采购员' }, { label: '采购申请创建/编辑', role: '采购员' }, { label: '审核/批准', role: '审批人' }, { label: '驱动采购订单/要货令/委外加工', role: '系统自动' }, ], activities: [ ['10', '申请创建', '采购员', '基于物料交货计划或MRP检查结果新增采购申请,填写申请单号、物料、供应商、需求数量、需求日期', '物料交货计划/MRP检查结果', '采购申请单'], ['20', '查询编辑', '采购员', '按申请单号、物料、供应商、状态多维度筛选查询,支持编辑未提交的申请', '筛选条件', '申请列表'], ['30', '审批流流转', '审批人', '申请单提交后进入审批流,经指定审批人审核后状态更新为"已批准"', '已提交申请', '审核/批准结果'], ['40', '订单驱动', '系统', '已批准申请根据物料类型自动合并生成对应订单:DO物料→要货令,PO物料→采购订单,PW物料→委外加工订单', '已批准申请', '采购订单/要货令/委外加工订单'], ], rules: [ ['1', '审批流规则', '申请单提交后进入审批流,需经指定审批人审核后方可进入"已批准"状态'], ['2', '必填校验', '物料编码、供应商、需求数量、需求日期为必填,需求数量须>0'], ['3', '来源校验', '申请创建时需校验物料交货计划或MRP检查记录已发布且未关闭'], ['4', '批准后保护', '已批准申请单不可编辑或删除,仅可查看,保护审批结果严肃性'], ['5', '订单驱动规则', '批准后系统根据物料类型自动合并生成对应订单:DO物料→要货令,PO物料→采购订单,PW物料→委外加工订单'], ], improvements: [ '从原系统依赖邮件/纸质审批升级为系统化审批流,审批过程可追溯、可审计。', '新增与物料交货计划和MRP检查的关联追溯,确保需求来源可查。', '新增状态驱动的操作权限控制(不同状态下可执行不同操作)。', '新增批准后自动按物料类型分流驱动三类订单(采购订单/要货令/委外加工订单),替代原系统手动分类下达方式。', ], permissions: [ ['1', '采购员', '增删改查和提交权限'], ['2', '审批人(采购经理)', '审核/批准权限'], ['3', '物料计划员', '仅查看权限'], ], interfaces: [ ['1', 'MDP入站-交货计划', '从物料交货计划读取可关联的交货计划行项', '实时'], ['2', 'MDP入站-MRP检查', '从MRP检查结果读取可关联的需求行项', '实时'], ['3', 'MDP出站-批准申请', '批准后采购申请数据同步至ERP,根据物料类型自动分流驱动订单生成', '批准时触发'], ], reports: [ ['1', '采购申请审批效率报表', '统计申请从提交到批准的平均审批时长', '按周/月'], ['2', '采购申请转化率报表', '统计申请转化为各类型订单(PO/DO/PW)的比例', '按周/月'], ['3', '申请金额汇总报表', '按部门/采购组统计采购申请金额', '按周/月'], ], }; const ch6 = () => buildChapter('6', '物料采购申请', _ch6cfg); // ── Chapter 7: 物料采购订单 ── const _ch7cfg = { targets: [ '管理已下达至供应商的正式采购订单,跟踪订单从下达到收货完成的全生命周期。', '确保采购执行的透明度和可控性,为S4交货管理提供数据基础。', ], flowNote: '流程路径:采购订单生成 → 供应商确认/交期回复 → 发货关联 → 订单状态跟踪 → 收货完成/订单关闭。', flowSteps: [ { label: '采购订单生成', role: '采购员' }, { label: '供应商确认/交期回复', role: '采购员' }, { label: '发货关联', role: '采购员' }, { label: '订单状态跟踪', role: '采购员' }, { label: '收货完成/订单关闭', role: '系统自动' }, ], activities: [ ['10', '订单生成', '采购员/系统', '基于已批准采购申请自动或手动生成采购订单,填写供应商、物料、数量、交期等核心信息', '已批准采购申请', '采购订单'], ['20', '供应商确认', '采购员', '供应商在线确认订单并回复预计交期,确认信息回写至订单', '供应商反馈', '确认后订单'], ['30', '发货关联', '采购员', '关联发货单数据,展示发货数量、日期与订单的对应关系', '发货数据', '发货关联视图'], ['40', '状态跟踪', '采购员', '跟踪订单从"已下达→部分收货→已完成→已关闭"完整生命周期状态', '订单数据', '状态视图'], ['50', '收货关闭', '系统', '收货数据累计达订单数量时自动更新为"已完成",已完成订单可手动关闭', '收货数据', '订单关闭'], ], rules: [ ['1', '订单号唯一性', '每个采购订单具有唯一订单号,自动分配或手动输入'], ['2', '供应商校验', '生成订单时校验供应商是否在有效货源清单中,确保货源合规'], ['3', '来源追溯', '订单来源于已批准的采购申请,确保需求可追溯'], ['4', '状态自动更新', '收货数据累计达订单数量时状态自动更新为"已完成"'], ['5', '订单关闭', '已完成/已取消订单可手动关闭,关闭后不可再收货'], ], improvements: [ '从原ERP分散的采购订单管理整合为统一页面,支持跨供应商、跨物料一站式查询。', '新增发货关联视图,替代原系统手动比对发货与订单的低效方式。', '新增订单状态自动流转机制,减少人工状态更新的延迟和错误。', ], permissions: [ ['1', '采购员', '增删改查权限'], ['2', '物料计划员/供应链经理', '仅查看权限'], ['3', '仓库管理员', '查看权限(安排收货计划)'], ], interfaces: [ ['1', 'MDP入站-供应商确认', '从SRM同步供应商订单确认和交期回复数据', '定时(日)'], ['2', 'MDP入站-发货数据', '从WMS/SRM同步发货单数据用于发货关联', '定时(日)'], ['3', 'MDP出站-采购订单', '采购订单数据同步至ERP触发收货和付款流程', '订单变更时'], ['4', '核心数据表', 'vscm_jhjh(采购订单供应商视角)+ PurOrdMaster', '实时'], ], reports: [ ['1', '采购订单执行进度报表', '按订单/供应商展示下达数量、收货数量、完成百分比', '按周/月'], ['2', '采购订单逾期报表', '对超过计划交货日期未完成的订单生成逾期清单', '实时监控'], ['3', '采购金额汇总报表', '按时间段/采购组/供应商汇总采购金额', '按月/季'], ], }; const ch7 = () => buildChapter('7', '物料采购订单', _ch7cfg); // ── Chapter 8: 委外加工订单 ── const _ch8cfg = { targets: [ '管理委托外部供应商进行物料加工的采购订单(PurOrdMaster/PW类型)。', '支持订单明细的增删改查和物料选择,确保委外加工业务的规范化和可追溯性。', ], flowNote: '流程路径:委外加工订单创建 → 委外商选择 → 货源清单物料选择 → 明细行管理 → 订单保存。', flowSteps: [ { label: '委外加工订单创建', role: '外协管理员' }, { label: '委外商选择', role: '外协管理员' }, { label: '货源清单物料选择', role: '外协管理员' }, { label: '明细行管理', role: '外协管理员' }, { label: '订单保存', role: '外协管理员' }, ], activities: [ ['10', '订单创建', '外协管理员', '新增委外加工订单,填写订单基本信息', '委外需求', '委外订单记录'], ['20', '委外商选择', '外协管理员', '从货源清单选择委外加工供应商', '货源清单', '选定委外商'], ['30', '货源物料选择', '外协管理员', '从货源清单(selectSourceList)选择委外加工物料', '货源清单', '选中物料'], ['40', '明细行管理', '外协管理员', '管理每个明细行的物料、数量、单价、交货日期等', '选中物料', '订单明细行'], ['50', '订单保存', '外协管理员', '确认无误后保存委外加工订单,生成PW类型订单记录', '委外订单数据', '已保存委外订单(PurOrdMaster/PW)'], ], rules: [ ['1', '订单类型区分', '委外加工订单类型为PW,与普通采购订单PO类型区分管理'], ['2', '货源校验', '选择委外商和委外物料时需校验其在货源清单中存在且状态有效'], ['3', '必填字段', '委外商、物料、加工数量、计划交付日期为必填项'], ['4', '明细行数量', '每个委外加工订单至少需包含一个明细行,不允许空订单'], ], improvements: [ '从原ERP与普通采购订单混合管理升级为独立页面,支持PW类型专项管理。', '新增货源清单校验,确保委外业务物料选择合规。', '新增订单明细子页面增删改查,替代原系统单层管理方式。', ], permissions: [ ['1', '外协管理员', '增删改查全部权限'], ['2', '采购员/供应链经理', '查看权限'], ], interfaces: [ ['1', 'MDP入站-货源清单', '从SRM同步货源清单数据(sourcing_item表)', '定时(日)'], ['2', 'MDP出站-委外订单', '委外加工订单数据同步至ERP,与生产工单关联', '订单变更时'], ['3', '核心数据表', 'PurOrdMaster(订单类型PW)', '实时'], ], reports: [ ['1', '委外加工订单执行报表', '按委外商/物料统计订单下达和完成情况', '按周/月'], ['2', '委外加工成本分析', '按时间段/委外商统计委外加工总成本', '按月/季'], ], }; const ch8 = () => buildChapter('8', '委外加工订单', _ch8cfg); // ── Chapter 9: 工序外协订单 ── const _ch9cfg = { targets: [ '管理生产过程中特定工序委托外部供应商完成的采购订单。', '支持工单-工序-外协订单三级关联,确保工序外协业务的精细化管理。', ], flowNote: '流程路径:选择生产工单 → 选择外协工序 → 创建外协订单 → 供应商/数量校验 → 订单保存/工单工序关联。', flowSteps: [ { label: '选择生产工单', role: '外协管理员' }, { label: '选择外协工序', role: '外协管理员' }, { label: '创建外协订单', role: '外协管理员' }, { label: '供应商/数量校验', role: '系统自动' }, { label: '订单保存/工单工序关联', role: '系统自动' }, ], activities: [ ['10', '选择工单', '外协管理员', '从生产工单列表选择需要外协的生产工单', '生产工单', '选中工单'], ['20', '选择工序', '外协管理员', '通过selectProcessWorkOrder组件从工单选择需要外协的工序', '选中工单', '选中工序'], ['30', '创建订单', '外协管理员', '基于选中的工单和工序创建外协订单,填写供应商、数量、交期等', '选中工序', '外协订单'], ['40', '供应商/数量校验', '系统', '校验外协商在货源清单中有效、外协数量不超过工序计划生产数量', '外协订单', '校验结果'], ['50', '保存关联', '外协管理员/系统', '保存订单并与生产工单工序建立关联,工单状态联动', '校验通过订单', '已保存关联订单'], ], rules: [ ['1', '工单校验', '选择的工序必须属于有效生产工单(状态不为已关闭或已取消)'], ['2', '工序唯一性', '同一工单同一工序不可重复创建外协订单,防止重复委外'], ['3', '供应商校验', '外协商必须在货源清单中有效,确保外协供应商资质'], ['4', '数量约束', '外协数量不可超过工单该工序的计划生产数量'], ], improvements: [ '从原系统手工Excel管理升级为系统化管理,支持工单-工序-外协订单三级关联。', '新增供应商/数量校验环节,确保外协业务合规。', '新增订单保存与工单工序自动关联,实现工单状态联动。', ], permissions: [ ['1', '外协管理员', '增删改查全部权限'], ['2', '生产计划员', '查看权限'], ], interfaces: [ ['1', 'MDP入站-工单工序', '从MES同步生产工单和工序数据', '定时(日)'], ['2', 'MDP出站-外协订单', '工序外协订单数据同步至ERP', '订单变更时'], ['3', '核心数据表', 'PurOrdMaster(PW类型,关联工单和工序信息)', '实时'], ], reports: [ ['1', '工序外协执行报表', '按工单/工序/外协商统计外协订单执行情况', '按周/月'], ['2', '外协成本分析', '按工序类型统计外协成本', '按月/季'], ], }; const ch9 = () => buildChapter('9', '工序外协订单', _ch9cfg); // ── Chapter 10: 供应协同看板 ── const _ch10cfg = { targets: [ '为管理层和业务人员提供S3模块的核心KPI可视化看板。', '通过三大L1核心指标(工单按需准时齐套率、工单齐套周期、物料库存周转天数)全面监控供应健康度。', '支持策略模拟What-If分析和运营指标建模配置。', ], flowNote: '流程路径:MDP数据同步/运营指标建模 → 4维KPI卡片展示 → 趋势箭头分析 → 多维筛选联动 → 分支看板(需求计划/交货计划) → 策略模拟/导出。', flowSteps: [ { label: 'MDP数据同步/运营指标建模', role: '供应链经理' }, { label: '4维KPI卡片+趋势箭头展示', role: '供应链经理' }, { label: '多维筛选联动/分支看板视图', role: '供应链经理' }, { label: 'MDP同步任务监控', role: 'IT运维人员' }, { label: '策略模拟What-If/报表导出', role: '供应链经理' }, ], activities: [ ['10', '数据加载', '系统', '页面初始化从后端加载homeS3最新KPI计算数据', 'KPI数据库', 'KPI展示数据'], ['20', 'KPI卡片展示', '供应链经理', '4个KPI卡片:物料计划周期、物料计划满足率、物料计划人数、物料库存周转', 'KPI数据', '趋势+标签卡片'], ['30', '基础查询', '供应链经理', '按日期、产品、订单号、产线、物料、供应商维度筛选', '筛选条件', '筛选后数据'], ['40', '分支视图', '供应链经理', '分支一:MRP维度(BOM需求满足趋势+统计表);分支二:MDP维度(交货执行进度+满足率)', '看板数据', '分支详情'], ['50', '操作功能', '供应链经理', '策略模拟(What-If分析)、导出报表、运营指标建模链接跳转', '看板数据', '模拟结果/导出文件'], ], rules: [ ['1', '指标等级判定', '齐套率低于目标标"严重"(红),齐套周期超目标标"警告"(橙),库存周转达标标"优秀"(绿)'], ['2', '趋势计算', '趋势箭头基于同比/环比计算,上升为绿色箭头,下降为红色箭头'], ['3', '数据刷新', '页面不自动刷新,需手动点击刷新按钮获取最新数据'], ['4', '筛选联动', '基础查询条件变更时,KPI卡片和分支视图同步更新'], ], improvements: [ '从原系统零散Excel报表升级为实时可视化看板,支持交互式数据探索。', '新增策略模拟功能(What-If),替代原系统依赖人工计算的分析方式。', '新增指标建模配置入口,支持自定义KPI口径,替代硬编码指标定义方式。', ], permissions: [ ['1', '供应链经理', '查看、导出和策略模拟权限'], ['2', '物料计划员/采购员/仓管员', '查看权限'], ['3', '工厂厂长/总经理', '查看权限'], ], interfaces: [ ['1', '看板聚合API', 'GET /api/AidopKanban/module-detail?moduleCode=S3', '实时(页面加载)'], ['2', 'KPI数据源', 'homeS3数据对象 (demandKitRatePct, kitCycleDays, materialInventoryTurnoverDays)', 'MDP定时刷新'], ['3', '运营指标建模', 'KPI口径和计算公式通过运营指标建模模块配置', '配置驱动'], ], reports: [ ['1', '供应协同月度报告', '含三大L1指标月度趋势和同比分析', '按月度'], ['2', '策略模拟分析报告', '记录策略模拟的输入参数和输出结果', '按需'], ], }; const ch10 = () => buildChapter('10', '供应协同看板', _ch10cfg); // ── Chapter 11: 工单物料齐套上线看板 ── const _ch11cfg = { targets: [ '以工单为维度,展示每个工单所需物料的齐套状态(需求、发料、欠料、备料、在检、在途、承诺数量)。', '帮助生产计划和物料计划人员精准识别缺料工单和责任供应商。', ], flowNote: '流程路径:MDP数据同步(工单/BOM/库存/在途) → MRP齐套计算 → 30+字段齐套信息展示 → 缺料定位/供应商维度分析 → 缺料预警/策略建议。', flowSteps: [ { label: 'MDP同步(工单/BOM/库存/在途)', role: '物料计划员' }, { label: 'MRP齐套计算/手动刷新', role: '物料计划员' }, { label: '30+字段齐套信息展示', role: '物料计划员' }, { label: '欠料定位/供应商维度分析', role: '物料计划员' }, { label: '缺料预警/策略建议输出', role: '系统自动' }, ], activities: [ ['10', '数据加载', '系统', '从WorkOrdDetailTotalKB宽表加载工单物料齐套数据', 'MDP宽表', '齐套数据'], ['20', '多维筛选', '物料计划员', '按订单号、工单号、产品编码、物料编码、供应商名称筛选', '筛选条件', '筛选后列表'], ['30', '齐套信息展示', '物料计划员', '展示30+字段:序号、订单/工单号、BOM版本、物料描述、需求/发料/欠料/备料/在检/在途数量', '齐套数据', '齐套明细'], ['40', '缺料定位', '物料计划员', '欠料数量(shortage)>0标记为"未齐套",定位影响供应商', '齐套明细', '缺料清单'], ['50', '列设置/排序', '物料计划员', '自定义显示/隐藏列,多字段升序/降序排序,分页10/20/50', '视图配置', '个性化视图'], ], rules: [ ['1', '齐套判定', '欠料数量(shortage)>0时该物料行视为"未齐套"'], ['2', '欠料计算', 'shortage = qtyRequired - qtyRec,发料不足差额即为欠料'], ['3', '刷新触发', '调用refreshWorkOrderMaterialReadiness接口重新执行MRP齐套计算'], ['4', '分页显示', '按分页加载,支持10/20/50条每页,优化大数据量页面性能'], ], improvements: [ '从原系统手工Excel跟踪齐套状态升级为实时在线看板,数据来源于MDP实时计算宽表。', '新增30+字段完整视图,替代原系统仅有"物料/需求数量"两个维度的简单跟踪。', '新增供应商维度齐套分析(供应商编码/名称/采购组/采购员),快速定位责任供应商。', '新增列设置和排序功能,支持不同角色个性化视图配置。', ], permissions: [ ['1', '物料计划员/生产计划员', '查看和刷新权限'], ['2', '采购员', '查看权限(了解管辖供应商物料齐套情况)'], ['3', '车间主任/供应链经理', '查看权限'], ], interfaces: [ ['1', 'MDP入站-齐套数据', '从ERP/MES/SRM同步工单需求、BOM、库存、在途、发货数据,DWD关联计算入宽表', '定时(日)'], ['2', '齐套刷新API', 'refreshWorkOrderMaterialReadiness触发MRP齐套重算', '手动触发'], ['3', '核心数据表', 'WorkOrdDetailTotalKB(工单物料欠料宽表)', '实时'], ], reports: [ ['1', '工单齐套日报', '每日按工单汇总齐套率和欠料明细', '日报'], ['2', '供应商齐套分析', '按供应商统计供货工单齐套率,用于供应商绩效评估', '按周/月'], ['3', '欠料预警报表', '对欠料超阈值工单生成预警清单', '实时推送'], ], }; const ch11 = () => buildChapter('11', '工单物料齐套上线看板', _ch11cfg); // ── Chapter 12: MDP 运行监控 ── const _ch12cfg = { targets: [ '提供S3相关MDP数据同步与转换任务的运行状态可视化。', '帮助IT运维人员和业务管理员及时发现和定位数据同步失败、转换异常等问题,确保数据准确性和时效性。', ], flowNote: '流程路径:MDP任务调度引擎运行 → 同步日志记录 → 任务状态列表展示 → 异常告警 → 运维响应处理。', flowSteps: [ { label: 'MDP任务调度引擎运行', role: '系统(MDP)' }, { label: '同步日志记录(成功/失败/运行中)', role: '系统(MDP)' }, { label: 'S3模块任务列表展示', role: 'IT运维人员' }, { label: '失败任务红色高亮告警', role: '系统' }, { label: '运维响应处理/数据修复', role: 'IT运维人员' }, ], activities: [ ['10', '任务列表展示', 'IT运维', '展示S3相关MDP同步任务列表:任务名、运行状态、开始/结束时间、记录数、错误信息', 'MDP日志', '任务列表'], ['20', '状态筛选', 'IT运维', '按任务状态(全部/成功/失败/运行中)过滤', '筛选条件', '筛选后列表'], ['30', '异常告警', '系统', '失败任务红色高亮标识和告警提示,便于及时响应', '任务状态', '告警视图'], ['40', '统一视图', 'IT运维', '与平台级MDP监控互补,S3页面聚焦本模块任务实例', 'S3 MDP任务', '模块监控视图'], ], rules: [ ['1', '状态判定', '任务执行返回码非零判定为失败,零为成功'], ['2', '记录数展示', '展示最近一次成功执行记录数;如最近失败则展示失败前最后成功记录数'], ['3', '刷新频率', '页面不自动刷新,需手动刷新获取最新任务状态'], ['4', '数据来源', '任务执行日志从MDP任务调度引擎日志表读取'], ], improvements: [ '从原系统无统一监控(依赖DBA手动检查数据库日志)升级为可视化监控页面。', '新增S3模块专属任务视图,与平台级监控形成"总-分"监控体系。', '新增错误信息直接展示,替代原系统需要连接数据库查询日志的低效方式。', ], permissions: [ ['1', 'IT运维人员', '查看权限'], ['2', '供应链经理/物料计划员', '查看权限(了解数据同步状态)'], ], interfaces: [ ['1', 'MDP日志接口', '从MDP任务调度引擎读取同步任务日志(sync_logs表)', '实时'], ['2', '核心数据表', 'mdp_sync_task_log(MDP同步任务日志表)', '实时'], ], reports: [ ['1', 'MDP任务运行日报', '每日汇总S3相关MDP任务成功率和平均耗时', '日报'], ['2', '任务失败趋势报表', '按周/月统计任务失败趋势,评估数据同步稳定性', '按周/月'], ], }; const ch12 = () => buildChapter('12', 'MDP 运行监控', _ch12cfg); // ═══════════════════════════════════════════════════ // Chapter 13: 数据中台架构 // ═══════════════════════════════════════════════════ function buildCh13() { const ch = []; ch.push(h1('13 数据中台架构')); ch.push(h2('13.1 目标/宗旨')); ch.push(p('S3供应协同模块采用Ai-DOP统一数据中台分层架构,将业务运行数据经过贴源(STG)、标准化(STD)、宽表构建(DWD)、指标计算(KPI)四层处理,最终服务于前端页面查询、看板展示和KPI考核。')); ch.push(h2('13.2 分层设计')); ch.push(table( ['分层', '表前缀', '职责', '更新机制'], [ ['贴源层(STG)', 'mdp_stg_*', '保留源系统原始数据', 'MDP同步覆盖写入'], ['标准层(STD)', 'mdp_std_*', '统一字段口径,清洗脏数据', 'MDP转换(最新批次)'], ['宽表层(DWD)', 'dwd_*', '面向页面和KPI主题事实表', 'MDP转换(最新批次)'], ['指标层(KPI)', 'ado_s9_kpi_value_*', '按天存储L1-L4指标值', 'MDP KPI计算'], ], [1500, 2000, 4200, 2300] )); ch.push(h2('13.3 S3核心数据流')); ch.push(bp('物料需求/计划链路')); ch.push(p('work_order_demand / inventory_snapshot / srm_in_transit → mdp_stg_demand → mdp_std_demand → dwd_demand_schedule → ado_s9_kpi_value_*')); ch.push(bp('采购订单/交货链路')); ch.push(p('PurOrdMaster / srm_polist_ds / vscm_jhjh → mdp_stg_po → mdp_std_po → dwd_po_delivery → ado_s9_kpi_value_*')); ch.push(bp('齐套/看板链路')); ch.push(p('WorkOrdDetailTotalKB / homeS3 → DWD直接消费 → 前端看板和KPI卡片 → ado_s9_kpi_value_*')); ch.push(h2('13.4 对象映射总表')); ch.push(table( ['业务对象', '运行表', '贴源层', '标准层/DWD', '消费端'], [ ['物料需求计划', 'ic_demandschedule', 'mdp_stg_demand', 'mdp_std_demand / dwd_demand_schedule', '需求页、交货计划'], ['交货计划', 'srm_polist_ds', 'mdp_stg_delivery', 'mdp_std_delivery / dwd_delivery_schedule', '交货页、异常记录'], ['要货令(PurOrd DO)', 'PurOrdMaster', 'mdp_stg_po', 'mdp_std_po', '要货令页'], ['采购订单', 'PurOrdMaster / vscm_jhjh', 'mdp_stg_po', 'mdp_std_po / dwd_po_delivery', '采购订单页、看板'], ['委外加工(PW)', 'PurOrdMaster', 'mdp_stg_po', 'mdp_std_po', '委外页'], ['工序外协', 'PurOrdMaster (PW+工单)', 'mdp_stg_po', 'mdp_std_po', '工序外协页'], ['工单物料齐套', 'WorkOrdDetailTotalKB', '—', 'DWD宽表直接消费', '齐套看板'], ['供应协同KPI', 'homeS3数据对象', '—', 'KPI计算直接消费', '供应看板'], ], [1100, 2200, 1600, 2400, 2700] )); ch.push(h2('13.5 MDP作业调度')); ch.push(table( ['配置项', '内容'], [ ['作业编码', 'S3_MDP_SYNC_TRANSFORM'], ['批次格式', 'S3_MDP_FULL_yyyyMMddHHmmss'], ['手动刷新入口', '各页面刷新按钮 / 计划联动手动触发'], ['监控入口', 'mdp_transform_run_log / mdp_sync_log / MDP运行监控页'], ['执行方式', '定时调度 + 手动触发'], ], [2200, 7800] )); ch.push(h2('13.6 变化和改进点')); ch.push(bullet('建立统一数据中台分层架构,S3业务数据从"各自为政"收敛到标准数据链路。')); ch.push(bullet('页面和看板统一从DWD/KPI层消费,确保数据口径一致。')); ch.push(bullet('MDP作业可观测,支持日志查询和异常追溯。')); ch.push(bullet('新增手动刷新机制,业务人员可按需触发即时数据同步。')); return ch; } // ═══════════════════════════════════════════════════ // Chapter 14: 权限管理汇总 // ═══════════════════════════════════════════════════ function buildCh14() { const ch = []; ch.push(h1('14 权限管理汇总')); ch.push(p('以下汇总S3供应协同模块各功能所涉及的角色和权限:')); ch.push(table( ['序号', '角色', '权限范围', '涉及模块'], [ ['1', '物料计划员', '查看和操作物料需求计划、交货计划;查看交货异常记录;发布/取消发布;刷新齐套看板', '物料需求计划、交货计划、异常记录、齐套看板'], ['2', '采购员', '增删改查要货令、采购申请、采购订单;查看交货计划和交货异常', '要货令、采购申请、采购订单'], ['3', '外协管理员', '增删改查委外加工订单和工序外协订单', '委外加工、工序外协'], ['4', '供应链经理', '查看所有模块;查看供应协同看板和管理KPI;导出报表;策略模拟', '全模块(查看+看板操作)'], ['5', '审批人(采购经理)', '审核采购申请的审批流', '物料采购申请'], ['6', 'IT运维人员', '查看MDP运行监控;监控同步任务状态', 'MDP运行监控'], ['7', '质量管理员', '查看交货异常记录(质量追溯)', '交货单异常记录'], ['8', '仓库管理员', '查看采购订单和交货计划(安排收货)', '采购订单、交货计划'], ['9', '生产计划员/车间主任', '查看工序外协订单和齐套看板', '工序外协、齐套看板'], ['10', '工厂厂长/总经理', '查看供应协同看板全部指标', '供应协同看板'], ], [600, 1600, 5000, 2800] )); return ch; } // ═══════════════════════════════════════════════════ // 文档构建主流程 // ═══════════════════════════════════════════════════ async function buildDocument() { console.log('Generating flow chart images...'); flowImageCache['overview'] = await generateOverviewFlowPNG(); const allChapterConfigs = { '2': _ch2cfg, '3': _ch3cfg, '4': _ch4cfg, '5': _ch5cfg, '6': _ch6cfg, '7': _ch7cfg, '8': _ch8cfg, '9': _ch9cfg, '10': _ch10cfg, '11': _ch11cfg, '12': _ch12cfg, }; for (const [num, cfg] of Object.entries(allChapterConfigs)) { if (cfg.flowSteps) { flowImageCache[num] = await generateFlowPNG(cfg.flowSteps); } } console.log('Flow chart images generated.'); const sections = []; // ── 封面 ── sections.push(empty(), empty(), empty()); sections.push(new Paragraph({ children: [new TextRun({ text: 'S3 供应协同模块', bold: true, size: 52, font: FONT, color: '1F4E79' })], alignment: AlignmentType.CENTER, spacing: { after: 100 }, })); sections.push(new Paragraph({ children: [new TextRun({ text: '蓝图设计方案', bold: true, size: 52, font: FONT, color: '1F4E79' })], alignment: AlignmentType.CENTER, spacing: { after: 600 }, })); sections.push(new Paragraph({ children: [new TextRun({ text: 'Ai-DOP 智慧运营决策平台', size: 28, font: FONT, color: '4472C4' })], alignment: AlignmentType.CENTER, spacing: { after: 120 }, })); sections.push(new Paragraph({ children: [new TextRun({ text: '版本:V1.0 日期:2026年5月27日 作者:AI Agent', size: 22, font: FONT, color: '808080' })], alignment: AlignmentType.CENTER, spacing: { after: 2400 }, })); sections.push(new Paragraph({ children: [new TextRun({ text: '【机密文档 · 仅限项目内部使用】', size: 21, font: FONT, color: 'C00000', italics: true })], alignment: AlignmentType.CENTER, })); // ── 文档控制 ── sections.push(pageBreak(), h1('文档控制')); sections.push(h2('更改记录')); sections.push(table(['日期', '姓名', '版本', '变更说明'], [['2026/05/27', 'AI Agent', 'V1.0', '初版(基于S3模块系统实现)']], [1800, 1200, 1000, 6000])); sections.push(empty()); sections.push(h2('审核')); sections.push(table(['姓名', '职位', '签字/日期'], [['', '', ''], ['', '', '']], [3000, 3000, 4000])); sections.push(empty()); sections.push(h2('发布')); sections.push(table(['编号', '名称', '地点'], [['', '', '']], [3000, 4000, 3000])); // ── 目录 ── sections.push(pageBreak(), h1('目录')); sections.push(...buildTOC()); sections.push(pageBreak()); // ── 第1章: 总体业务方案 ── sections.push(h1('1 总体业务方案')); sections.push(h2('1.1 目标和宗旨')); sections.push(bullet('S3供应协同模块是Ai-DOP平台的核心模块,聚焦物料供需平衡与供应商协同管理。')); sections.push(bullet('承接S1产销协同模块的订单需求和S2制造协同模块的生产计划,通过物料需求计划(MRP)、采购管理和供应看板三大核心能力,实现从需求识别到交付闭环的全流程数字化管控。')); sections.push(bullet('核心KPI:工单按需准时齐套率(S3-L1-A)、工单齐套周期(S3-L1-B)、物料库存周转天数(S3-L1-C)。')); sections.push(h2('1.2 总体业务流程图')); sections.push(p('S3供应协同模块覆盖从"物料需求计算"到"供应协同监控"的完整链路,下图展示了物料计划域、采购管理域和供应协同看板域三大功能域的整体关系:')); sections.push(flowImageParagraph(flowImageCache['overview'])); sections.push(h2('1.3 方案设计')); sections.push(p('S3模块采用"数据中台驱动 + 业务操作闭环"的架构模式,覆盖以下核心功能模块:')); sections.push(bullet('物料需求计划:MDP同步+MRP净需求计算,支持发布管理和手动CRUD')); sections.push(bullet('物料交货计划:交货执行跟踪、批量操作、差异自动标记')); sections.push(bullet('交货单异常记录:只读查询视图,系统自动比对标记异常,支持多维筛选和导出')); sections.push(bullet('要货令:采购流程起点,4状态生命周期管理')); sections.push(bullet('物料采购申请:规范申请-审批流程,确保采购需求合规')); sections.push(bullet('物料采购订单:订单全生命周期跟踪,交货关联和状态自动流转')); sections.push(bullet('委外加工订单:PW类型专项管理,货源清单校验')); sections.push(bullet('工序外协订单:工序级外协精细化管理,工单关联')); sections.push(bullet('供应协同看板:4维KPI卡片+趋势箭头+分支看板+策略模拟')); sections.push(bullet('工单物料齐套上线看板:30+字段齐套展示,供应商维度欠料分析')); sections.push(bullet('MDP运行监控:S3模块专属同步任务可视化监控')); sections.push(p('前端采用Vue 3 + Element Plus + TypeScript技术栈,列表页使用通用AidopDemoShell容器组件,看板页使用KPI卡片+趋势图表组合布局。后端基于Admin.NET框架分层架构实现。S3模块关键L1指标通过运营指标建模支持自定义口径配置。')); // ── 第2~12章: 各功能模块 ── sections.push(pageBreak()); sections.push(h1('2 物料需求计划')); sections.push(...ch2()); sections.push(pageBreak()); sections.push(h1('3 物料交货计划')); sections.push(...ch3()); sections.push(pageBreak()); sections.push(h1('4 交货单异常记录')); sections.push(...ch4()); sections.push(pageBreak()); sections.push(h1('5 要货令')); sections.push(...ch5()); sections.push(pageBreak()); sections.push(h1('6 物料采购申请')); sections.push(...ch6()); sections.push(pageBreak()); sections.push(h1('7 物料采购订单')); sections.push(...ch7()); sections.push(pageBreak()); sections.push(h1('8 委外加工订单')); sections.push(...ch8()); sections.push(pageBreak()); sections.push(h1('9 工序外协订单')); sections.push(...ch9()); sections.push(pageBreak()); sections.push(h1('10 供应协同看板')); sections.push(...ch10()); sections.push(pageBreak()); sections.push(h1('11 工单物料齐套上线看板')); sections.push(...ch11()); sections.push(pageBreak()); sections.push(h1('12 MDP 运行监控')); sections.push(...ch12()); // ── 第13~14章 ── sections.push(pageBreak()); sections.push(...buildCh13()); sections.push(pageBreak()); sections.push(...buildCh14()); return sections; } // ═══════════════════════════════════════════════════ // 生成文档 // ═══════════════════════════════════════════════════ async function main() { const doc = new Document({ styles: { default: { document: { run: { font: FONT, size: 21 } } } }, sections: [{ properties: { page: { margin: { top: convertInchesToTwip(0.8), bottom: convertInchesToTwip(0.8), left: convertInchesToTwip(1.0), right: convertInchesToTwip(1.0) } } }, children: await buildDocument(), }], }); const buffer = await Packer.toBuffer(doc); const outPath = 'd:\\DEMONET\\doc\\S3供应协同模块蓝图设计方案.docx'; const fallbackPath = 'd:\\DEMONET\\doc\\S3供应协同模块蓝图设计方案_V2.docx'; const tempPath = 'd:\\DEMONET\\doc\\S3_blueprint_temp.docx'; fs.writeFileSync(tempPath, buffer); try { fs.unlinkSync(outPath); } catch(e) {} try { fs.renameSync(tempPath, outPath); console.log(`Renamed to: ${outPath}`); } catch(e) { try { fs.unlinkSync(fallbackPath); } catch(_) {} try { fs.renameSync(tempPath, fallbackPath); console.log(`Fallback to: ${fallbackPath}`); } catch(e2) { console.log(`Generated: ${tempPath} (target locked)`); } } console.log(`Size: ${(buffer.length / 1024).toFixed(1)} KB`); } main().catch(err => { console.error('Error:', err); process.exit(1); });