/** * Generate S2 制造协同业务需求描述.docx * 严格按照 S1 产销协同业务需求描述.docx 的格式: * 标题 → 文档信息 → 目录 → (一)模块功能说明+业务描述 → ... */ const fs = require('fs'); const { Document, Packer, Paragraph, TextRun, HeadingLevel, AlignmentType, PageBreak, TableOfContents, convertInchesToTwip, } = require('docx'); const FONT = '微软雅黑'; // ── 辅助函数 ── function empty() { return new Paragraph({ spacing: { after: 80 }, children: [] }); } function pageBreak() { return new Paragraph({ children: [new PageBreak()] }); } function normalPara(text, opts = {}) { return new Paragraph({ children: [new TextRun({ text, size: 21, font: FONT, ...opts })], spacing: { after: 100, line: 360 }, indent: opts.indent ? { left: convertInchesToTwip(opts.indent) } : undefined, }); } // H2: (一) 生产排程 function sectionHeading(text) { return new Paragraph({ children: [new TextRun({ text, bold: true, size: 28, font: FONT })], heading: HeadingLevel.HEADING_2, spacing: { before: 400, after: 200 }, }); } // H3: 功能说明 / 业务描述 function subHeading(text) { return new Paragraph({ children: [new TextRun({ text, bold: true, size: 22, font: FONT })], heading: HeadingLevel.HEADING_3, spacing: { before: 200, after: 100 }, }); } // Title paragraph function titlePara(text) { return new Paragraph({ children: [new TextRun({ text, bold: true, size: 36, font: FONT, color: '1F4E79' })], alignment: AlignmentType.CENTER, spacing: { after: 300 }, }); } function docInfoPara(text) { return new Paragraph({ children: [new TextRun({ text, size: 21, font: FONT })], spacing: { after: 40 }, bullet: { level: 0 }, }); } // ═══════════════════════════════════════════════════ // 各模块业务需求描述数据 // ═══════════════════════════════════════════════════ const CN_NUM = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一']; const modules = [ { title: '生产排程', funcDesc: [ '生产排程模块承接S1(产销协同)下达的生产工单,实现在线工单工序排程管理,是制造协同的核心调度层。', '工单工序排程列表以WorkOrdMaster为数据基础,展示工单的优先级、物料、数量、齐套状态和执行进度,支持多条件筛选查询。', '通过工具栏"生产排程"按钮统一触发排程计算,系统综合考虑产线工作日历、工序顺序和资源产能约束,自动生成排产结果。', '支持工单优先级在线调整(加急/特急),快速响应插单和生产异常;支持同步物料需求(MRP联动)和同步工艺路线(从产品设计获取)。', '提供工单关闭(批量操作)、工单执行追踪、工单物料明细和工序明细查看等辅助功能,形成完整的排程闭环。', '排产异常记录模块独立管理排产数据维护过程中的异常信息(ScheduleExceptionMaster表),支持新增、编辑、删除操作,异常可追溯。', ], bizDesc: [ '计划员/调度人员登录DOP系统,进入"S2制造协同→生产排程→工单工序排程"菜单,查看工单排程列表。', '通过工单编号、生产批号、物料编码、开工日期、生产车间、状态等条件筛选目标工单。', '点击工具栏"生产排程"按钮,触发排程算法计算(基于产线日历、工序产能约束),系统自动生成或更新排产结果。', '点击工具栏"同步物料需求"按钮,生成MRP物料需求计划,确保排产物料齐套。', '如需调整工单优先级,在操作列点击"加急"(提升为优先级2)或"特急"(提升为优先级3),弹出表单选择原因说明后确认。', '点击操作列"同步工艺路线",从S1产品设计中获取最新工艺路线并应用到当前工单的工序明细中。', '工具栏支持批量"工单关闭":勾选多行已完成的工单后点击关闭按钮,工单状态变更为"已关闭",关闭操作不可逆。', '在"生产排程→排产异常记录"页面中,可新增排产数据维护异常记录(填写工单编号、物料编码、操作类型和执行时间),与工单排程数据关联追溯。', ], }, { title: '作业计划', funcDesc: [ '作业计划模块在工单排程完成后,生成面向车间产线的可执行日计划,将排产结果精确到每天、每道工序、每台设备。', '可执行日计划列表以排程结果为基础,默认展示"计划日期≥今天"且工单未关闭的日计划数据;支持通过生产指令、物料编码、生产批次、工单状态、工作中心、设备类型、工序等多条件筛选。', '日计划采用批量下达模式:勾选多行日计划后点击"下达"按钮,将确认的日计划下发至S6 MES执行层,驱动车间实际生产。', '产线工作日历管理:定义每条产线每周每天的工作班次(班次1和班次2的开始时间与工作时长),为排程和日计划提供可用工时基础数据。', '产线休息时间管理:定义每个产线的固定休息开始时间点和休息时长(分钟),排程时自动避开停休时段。', '产线节假日管理:维护节假日和调班日期(类型可选"休假"或"调班"),排程时自动过滤休假日期,确保不占用法定休息日。', '产线加班管理:定义临时加班时段(ResourceOccupancyTime),记录加班起止时间、有效工作时长和休息时长,为紧急加产提供延长工时支持。', ], bizDesc: [ '计划员/调度人员进入"S2制造协同→作业计划→可执行日计划"菜单,系统默认加载当天及未来的日计划数据。', '通过生产指令、物料编码、生产批次、工单状态、日计划下达状态、工作中心、设备类型、工序等多维条件筛选待处理的日计划。', '勾选确认无误的日计划行,点击工具栏"下达"按钮完成批量下达;下达后日计划状态更新,MES系统即可接收并执行。', '基础数据管理员进入"产线工作日历管理"菜单,可新增/编辑/删除各产线的工作日定义:设置星期一至星期日每天的班次开始时间和持续时长(支持两个班次)。', '进入"产线休息时间管理"菜单,新增/编辑/删除各产线的固定休息时段:选择产线(下拉搜索LineMaster产线主数据),设置休息开始时间点和休息时长。', '进入"产线节假日管理"菜单,新增/编辑/删除节假日记录:选择节假日名称、日期和类型(休假/调班);调班日期用于特殊情况下将休息日调整为工作日。', '进入"产线加班管理"菜单,新增/编辑/删除加班记录:选择产线、设定加班起止时间、系统自动计算有效工作时长和休息时长。', '所有基础数据(日历、休息、节假日、加班)修改后自动作为排程算法的产能约束,无需手动同步。', ], }, { title: '制造协同看板与KPI', funcDesc: [ '制造协同看板为管理层和业务人员提供S2模块的核心KPI可视化监控和工单执行进度追踪。', '工单执行进度看板以列表形式展示每张工单的全流程关键进度,包括工单数量、入库数量、未入库数量、领料状态和进度百分比(进度条)。', '进度条以百分比直观展示(入库数量÷工单数量×100%),领料状态关联MES/WMS领料数据,反映物料准备的实时状况。', '工单单据类型区分"销售工单(s)"和"计划工单(p)",单据状态区分为"投产(w)""下达(r)""关闭(c)"。', '通过DynamicModuleDashboard动态看板组件(module-code="S2")展示L1层级核心KPI指标:订单排程满足率(S2-L1-A)、订单排程周期(S2-L1-B)、在制库存周转天数(S2-L1-C)、订单排程人效(S2-L1-D)。', 'KPI指标数据按天粒度存储于ado_s9_kpi_value_*表中,通过MDP作业定时或手动刷新,确保与前端看板数据口径一致。', ], bizDesc: [ '管理层/计划员进入"S2制造协同→制造协同看板→工单执行进度看板"菜单,查看所有工单的执行进度概览。', '通过工单编号、物料编码、计划开工日期等条件筛选特定范围的工单。', '在列表中查看每张工单的进度条(绿色),直观了解完工比例;同时关注领料状态字段,判断物料是否已到位。', '对于进度滞后或领料异常的工单,可返回"工单工序排程"页面进行优先级调整或排程重算。', '进入S2指标看板页面(DynamicModuleDashboard),查看L1核心KPI卡片:排程满足率反映排程计划的达成水平,排程周期反映从工单下达到排程完成的平均耗时。', '在制库存周转天数和排程人效指标为管理层提供制造协同效率的量化参考。', 'KPI数据支持按日/周/月周期切换查看趋势变化;支持从L1下钻到L2分解指标进行深层分析。', ], }, { title: '数据中台架构', funcDesc: [ 'S2制造协同模块采用Ai-DOP统一数据中台分层架构(STG→STD→DWD→KPI),将工单排程数据、产线基础数据和MES执行反馈数据标准化处理后服务于前端页面和KPI考核。', '贴源层(STG/mdp_stg_production)保留WorkOrdMaster、ScheduleDailyPlan、产线基础数据等运行表的原始数据快照,含sync_batch_id批次标识。', '标准层(STD/mdp_std_production)统一字段口径、清洗脏数据,形成标准化的排程、日计划和产线日历业务对象。', '宽表层(DWD)构建dwd_production_schedule(排程主题宽表)和dwd_line_calendar(产线日历宽表),关联工单、工序、产线、物料等多维度数据。', '指标层(KPI/ado_s9_kpi_value_*)按天存储S2的L1-L4指标值,包括订单排程满足率、排程周期、在制库存周转天数和排程人效。', 'MDP作业(S2_MDP_SYNC_TRANSFORM)负责S2数据的全链路同步转换,支持手动触发和未来扩展定时调度,作业执行日志可观测、异常可追溯。', ], bizDesc: [ 'S2模块的三个核心数据链路通过MDP作业自动同步至数据中台:', '工单排程/日计划链路:WorkOrdMaster、ScheduleDailyPlan等运行表→mdp_stg_production贴源层→mdp_std_production标准层→dwd_production_schedule宽表→KPI指标计算。', '产线基础数据链路:ShopCalendarWorkCtr、QualityLineRestDetail、HolidayMaster、ResourceOccupancyTime等运行表→mdp_stg_production贴源层→dwd_line_calendar宽表→排程产能约束计算。', 'MES执行反馈链路:MES领料状态和完工入库数据→mdp_stg_production贴源层→dwd_production_schedule宽表→工单进度看板实时展示。', '系统管理员通过MDP监控页面查看S2_MDP_SYNC_TRANSFORM作业的执行状态、处理行数和耗时,通过mdp_transform_run_log和mdp_sync_log定位异常。', '排程列表、日计划列表和进度看板统一消费DWD层数据,确保各页面数据口径一致。', ], }, { title: '权限管理汇总', funcDesc: [ 'S2制造协同模块涉及以下核心角色和权限:', '计划员/调度:查看工单排程列表;执行生产排程操作;同步物料需求;调整工单优先级(加急/特急);执行工单关闭;查看/下达可执行日计划;查看和管理排产异常记录;查看工单进度看板和KPI指标看板。', '基础数据管理员:新增/编辑/删除产线工作日历(班次定义);新增/编辑/删除产线休息时间;新增/编辑/删除产线节假日(休假/调班);新增/编辑/删除产线加班时段。', '车间主管:查看工单排程列表、可执行日计划列表和产线基础数据;查看工单进度看板。', '管理层:查看S2制造协同看板全部KPI指标(排程满足率、排程周期、在制库存周转天数、排程人效);查看工单执行进度看板。', '系统管理员:管理用户角色权限配置;监控MDP作业(S2_MDP_SYNC_TRANSFORM)执行状态;执行数据修复操作。', ], }, ]; // ═══════════════════════════════════════════════════ // 生成文档 // ═══════════════════════════════════════════════════ function buildDocument() { const sections = []; // ── 封面/标题 ── sections.push(empty(), empty(), empty(), empty()); sections.push(titlePara('S2制造协同业务需求描述')); sections.push(empty()); // ── 文档信息 ── const infoItems = [ '文档作者:彭熙玉', '创建日期:2026-06-09', '更新日期:2026-06-09', '文档编号:DOP-S2-REQ-001', '当前版本:V1.0', ]; infoItems.forEach(item => sections.push(docInfoPara(item))); sections.push(empty(), empty()); // ── 目录 ── sections.push(pageBreak()); sections.push(new Paragraph({ children: [new TextRun({ text: '目录', bold: true, size: 28, font: FONT })], heading: HeadingLevel.HEADING_2, spacing: { before: 200, after: 300 }, })); sections.push(new TableOfContents('目录', { headingStyleRange: '2-3', hyperlink: true, })); sections.push(new Paragraph({ children: [new TextRun({ text: '(如目录未显示,请在 Word 中右键此处 → 更新域)', size: 18, font: FONT, italics: true, color: '888888' })], spacing: { before: 40, after: 200 }, })); // ── 各功能模块 ── for (let i = 0; i < modules.length; i++) { const mod = modules[i]; sections.push(pageBreak()); // 章节标题:(一) 生产排程 sections.push(sectionHeading(`(${CN_NUM[i + 1]})${mod.title}`)); // 功能说明 sections.push(subHeading('功能说明')); (mod.funcDesc || []).forEach(desc => sections.push(normalPara(desc))); // 业务描述 if (mod.bizDesc && mod.bizDesc.length) { sections.push(subHeading('业务描述')); mod.bizDesc.forEach(desc => sections.push(normalPara(desc))); } } return sections; } // ═══════════════════════════════════════════════════ // 主流程 // ═══════════════════════════════════════════════════ async function main() { const sections = buildDocument(); 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.2), right: convertInchesToTwip(1.2) } } }, children: sections, }], }); const buffer = await Packer.toBuffer(doc); const outPath = 'd:\\DEMONET\\doc\\S2制造协同业务需求描述.docx'; const fallbackPath = 'd:\\DEMONET\\doc\\S2制造协同业务需求描述_V2.docx'; const tempPath = 'd:\\DEMONET\\doc\\S2_req_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); });