generate_s1_req_docx.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /**
  2. * Generate S1 产销协同业务需求描述.docx
  3. * 严格按照模板 产销协同业务需求描述.docx 的格式:
  4. * 标题 → 文档信息 → (一)模块功能说明+业务描述 → ...
  5. */
  6. const fs = require('fs');
  7. const {
  8. Document, Packer, Paragraph, TextRun, HeadingLevel,
  9. AlignmentType, PageBreak, TableOfContents, convertInchesToTwip,
  10. TabStopType, TabStopPosition, BorderStyle, WidthType, ShadingType, Table, TableRow, TableCell
  11. } = require('docx');
  12. const FONT = '微软雅黑';
  13. // ── 辅助函数 ──
  14. function empty() { return new Paragraph({ spacing: { after: 80 }, children: [] }); }
  15. function pageBreak() { return new Paragraph({ children: [new PageBreak()] }); }
  16. function normalPara(text, opts = {}) {
  17. return new Paragraph({
  18. children: [new TextRun({ text, size: 21, font: FONT, ...opts })],
  19. spacing: { after: 100, line: 360 },
  20. indent: opts.indent ? { left: convertInchesToTwip(opts.indent) } : undefined,
  21. });
  22. }
  23. function boldPara(text) {
  24. return normalPara(text, { bold: true });
  25. }
  26. function bulletPara(text, opts = {}) {
  27. return new Paragraph({
  28. children: [
  29. new TextRun({ text: '• ', size: 21, font: FONT }),
  30. new TextRun({ text, size: 21, font: FONT, ...opts }),
  31. ],
  32. spacing: { after: 60, line: 340 },
  33. indent: { left: convertInchesToTwip(0.3) },
  34. });
  35. }
  36. // H2: (一) 产品设计管理
  37. function sectionHeading(text) {
  38. return new Paragraph({
  39. children: [new TextRun({ text, bold: true, size: 28, font: FONT })],
  40. heading: HeadingLevel.HEADING_2,
  41. spacing: { before: 400, after: 200 },
  42. });
  43. }
  44. // H5: 功能说明 / 业务描述
  45. function subHeading(text) {
  46. return new Paragraph({
  47. children: [new TextRun({ text, bold: true, size: 22, font: FONT })],
  48. heading: HeadingLevel.HEADING_3,
  49. spacing: { before: 200, after: 100 },
  50. });
  51. }
  52. // Image placeholder paragraph
  53. function imagePlaceholder(label) {
  54. return new Paragraph({
  55. children: [new TextRun({ text: `【${label}截图】`, size: 18, font: FONT, italics: true, color: '999999' })],
  56. spacing: { before: 80, after: 80 },
  57. alignment: AlignmentType.CENTER,
  58. });
  59. }
  60. // Title paragraph
  61. function titlePara(text) {
  62. return new Paragraph({
  63. children: [new TextRun({ text, bold: true, size: 36, font: FONT, color: '1F4E79' })],
  64. alignment: AlignmentType.CENTER,
  65. spacing: { after: 300 },
  66. });
  67. }
  68. function docInfoPara(text) {
  69. return new Paragraph({
  70. children: [new TextRun({ text, size: 21, font: FONT })],
  71. spacing: { after: 40 },
  72. bullet: { level: 0 },
  73. });
  74. }
  75. // ═══════════════════════════════════════════════════
  76. // 各模块业务需求描述数据
  77. // ═══════════════════════════════════════════════════
  78. const CN_NUM = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一'];
  79. const modules = [
  80. {
  81. title: '产品设计管理',
  82. funcDesc: [
  83. '产品设计管理模块用于在线管理新产品开发过程中的产品设计BOM(物料清单)和工艺路线信息。',
  84. '设计员可在系统中新建产品设计任务,录入BOM子表(子物料编码、单位用量、损耗率等)和工艺子表(产线选择、路线编码等),保存即生效。',
  85. '该模块采用直接保存模式,无审批流环节,简化设计操作流程,提升设计效率。',
  86. '产品设计数据通过MDP同步至数据中台,纳入KPI考核体系,监控设计周期、满足率和人效指标。',
  87. ],
  88. bizDesc: [
  89. '设计员登录DOP系统,进入"产品设计管理"菜单,点击"添加"按钮新建产品设计任务。',
  90. '在任务主表中填写产品设计基本信息:选择成品物料编码,填写任务名称、计划完成日期、设计要求等必填字段。',
  91. '在BOM子表中逐行新增子物料信息:选择子物料编码后系统自动填入物料名称;填写单位用量和固定损耗率;支持多行物料录入。',
  92. '在工艺子表中逐行新增工艺路线信息:通过下拉框远程搜索选择产线(显示格式为"Line|Describe"),手动输入路线编码。',
  93. '填写完整后点击"保存"按钮,系统自动生成单据编号,数据即时生效,无需经过审批流程。',
  94. '已保存的设计记录可在列表中查看、编辑和删除;删除时关联的BOM和工艺子表数据同步删除。',
  95. ],
  96. },
  97. {
  98. title: '订单评审管理',
  99. funcDesc: [
  100. '订单评审管理模块实现销售订单的在线录入、查询、编辑和删除操作,是产销协同的订单入口。',
  101. '订单主流程(录入→评审→交期确认)无审批流,直接操作即可完成;仅当交期确认后需要修改时触发变更审批流。',
  102. '系统根据成品库存、在制工单和物料齐套等约束条件,对订单进行交期评估,给出预计交付日期。',
  103. '订单变更记录可追溯,变更次数自动累计,变更历史在订单交付Tab2(评审信息)中查看。',
  104. ],
  105. bizDesc: [
  106. '销售/计划员登录DOP系统,进入"订单评审管理"菜单,点击"添加"按钮新建销售订单。',
  107. '在订单表单中录入客户信息、物料编码、订单数量、需求交期等基本信息,订单编号保存时自动生成。',
  108. '订单保存后进入"待评审"状态,计划员对订单执行交期评估:系统根据成品库存、在制工单和物料约束给出建议交期。',
  109. '计划员确认交期结果后执行"交期确认"操作,调用外部交期确认接口,确认成功后订单状态更新为"已确认",产能和物料资源同步锁定。',
  110. '交期确认后如需修改订单,必须发起变更申请并经过审批流;变更记录自动归档,变更次数累计。',
  111. '列表支持按订单号、客户、日期范围等条件筛选,支持对订单进行编辑和删除操作。',
  112. ],
  113. },
  114. {
  115. title: '订单交付管理',
  116. funcDesc: [
  117. '订单交付管理模块以订单行(明细)为粒度,集中展示每笔销售订单的交付状态。',
  118. '通过8个Tab页签实现从"订单接收"到"成品发运"的全链路履约追踪:订单信息(Tab1)、评审与变更(Tab2)、排程(Tab3)、物料需求(Tab4)、采购(Tab5)、备料(Tab6)、生产(Tab7)、入库发运(Tab8)。',
  119. '交付列表数据来源于数据中台宽表层dwd_ship_trans,确保与看板KPI数据口径一致。',
  120. '跨模块Tab(排程/采购/备料/报工IQC/FQC入库)结构已就绪,待S2/S3/S4/S5/S6/S7模块补齐后自动填充数据。',
  121. ],
  122. bizDesc: [
  123. '计划员/物流人员进入"订单交付管理"菜单,查看交付列表,支持按订单号、客户、交付状态、日期范围等条件筛选。',
  124. '点击列表中的订单行,进入交付详情页面,通过8个Tab页签查看该订单的全链路履约状态。',
  125. 'Tab1展示订单基础档案信息(订单编号、客户、物料、状态、审核人等),数据来源mdp_std_so标准层。',
  126. 'Tab2展示交期评估结果和订单变更历史记录,数据来源dwd_requirement_examine_detail及mdp_stg_so变更数据。',
  127. 'Tab4展示BOM需求展开、库存占用、缺料分析和替代料信息,数据来源dwd_requirement_examine_detail。',
  128. 'Tab8展示成品入库和发运记录,数据来源mdp_std_ship_trans。',
  129. '交付状态实时反映订单从"待评审→已评审→排产中→采购中→生产中→已入库→已发运"的完整流转过程。',
  130. ],
  131. },
  132. {
  133. title: '订单发货管理',
  134. funcDesc: [
  135. '订单发货管理模块实现发货单和ASN(预先发货通知)的在线录入、查询、编辑和删除管理。',
  136. '通过销售单号关联将发货单与销售订单联动,发货计划覆盖率和发货达成率自动计算并纳入KPI考核。',
  137. '发货单号保存时自动生成(格式为SH+日期+流水号),客户和销售单号支持远程搜索选择。',
  138. '发货计划和ASN发货数据通过MDP同步至数据中台dwd_ship_trans宽表,与订单交付数据联动。',
  139. ],
  140. bizDesc: [
  141. '物流/仓管人员进入"订单发货管理"菜单,查看发货单列表,支持按发货单号、销售单号、客户、日期范围筛选。',
  142. '点击"新建发货单"按钮,选择关联的销售单号(下拉搜索,回显格式为"BillNo|客户名"),选择客户,填写发货基本信息。',
  143. '在发货明细子表中逐行新增物料信息:选择物料编码后自动填入物料名称,填写发货数量和批次信息;至少保留一行。',
  144. '保存后发货单号自动生成,数据进入运行时表ShippingPlan,通过MDP同步至数据中台。',
  145. 'ASN发货记录单独管理:录入ASN发货单号、物料、发货数量和发货日期,数据同步至mdp_std_ship_trans。',
  146. '已发货的发货单不可删除,防止数据丢失;发货计划覆盖率和发货达成率自动纳入KPI统计。',
  147. ],
  148. },
  149. {
  150. title: '合同评审管理',
  151. funcDesc: [
  152. '合同评审管理模块实现客户合同的在线评审管理,与销售订单评审协同运作。',
  153. '通过审批流(审批流类型:CONTRACT_REVIEW)管控合同评审的多级审核流程,支持同意和驳回操作。',
  154. '合同评审数据纳入KPI考核体系,自动计算合同评审周期(S1_L2_001)、满足率(S1_L2_002)、人效(S1_L2_003)及各审批节点耗时(L3/L4)。',
  155. ],
  156. bizDesc: [
  157. '商务人员进入"合同评审管理"菜单,查看合同评审列表,支持多条件筛选查询。',
  158. '点击"新建合同评审"按钮,录入合同基本信息:合同编号、客户名称、签订日期、合同金额等。',
  159. '填写完整后点击"提交审批",合同进入审批流(CONTRACT_REVIEW类型),由配置的审批人进行多级审核。',
  160. '审批人在审批列表中查看待审合同,可查看合同详情后执行"同意"或"驳回"操作。',
  161. '审批通过后合同状态更新,KPI数据自动计算:评审周期(从提交到通过的总耗时)、满足率(通过占比)、各节点耗时。',
  162. '合同评审数据通过MDP作业同步至数据中台贴源层mdp_stg_so,KPI计算直接消费贴源层数据。',
  163. ],
  164. },
  165. {
  166. title: '计划联动',
  167. funcDesc: [
  168. '计划联动模块实现销售订单、发货计划、ASN发货等业务数据的联动整合。',
  169. '通过MDP作业(S1_MDP_SYNC_TRANSFORM)将多源数据汇聚到dwd_ship_trans宽表,确保各页面数据口径一致。',
  170. '提供手动刷新机制,业务人员可随时触发全量同步转换,立即获取最新联动数据。',
  171. '联动数据覆盖订单(crm_seorder)、发货计划(ShippingPlan)、ASN(ASNBOLShipper)和计划联动(LinkagePlan)四类业务对象。',
  172. ],
  173. bizDesc: [
  174. '计划员进入"计划联动"菜单,查看各业务对象的联动状态列表(联动成功/未联动/数据异常三种状态)。',
  175. '点击"刷新"按钮,触发S1_MDP_SYNC_TRANSFORM全量同步转换作业,批次格式为S1_MDP_FULL_yyyyMMddHHmmss。',
  176. 'MDP作业依次执行:STG贴源层同步→STD标准化转换→DWD宽表构建→KPI指标计算,全链路自动完成。',
  177. '刷新完成后返回最新联动结果:联动达成率、数据一致性状态及各环节处理行数和耗时。',
  178. '系统管理员可通过MDP监控页面查看作业日志(mdp_transform_run_log)和同步日志(mdp_sync_log),定位异常。',
  179. '计划联动达成率(S1_L2_015)自动计算,反映联动成功的业务对象占比。',
  180. ],
  181. },
  182. {
  183. title: '需求明细核验',
  184. funcDesc: [
  185. '需求明细核验模块展示销售订单的BOM需求展开与核验结果,帮助计划人员确认物料需求数量和到货时间的准确性。',
  186. '核验数据来源于运行时表b_examine_result,通过MDP标准化后进入dwd_requirement_examine_detail,只取最新成功批次数据。',
  187. '核验内容包括:物料编码、BOM编码、需求数量、缺料数量、替代料方案、物料满足时间等。',
  188. '核验结果同时服务于订单交付Tab2(评审信息)和Tab4(物料需求),实现跨页面数据共享。',
  189. ],
  190. bizDesc: [
  191. '计划员进入"需求明细核验"菜单,通过订单号、物料编码、核验状态等条件筛选查询核验列表。',
  192. '在核验列表中查看每条订单行的BOM需求展开结果:对应BOM编码下的子物料需求明细。',
  193. '重点关注缺料数量和物料满足时间:系统自动计算当前库存与需求的差额,给出预计满足日期。',
  194. '如存在替代料方案,可在核验明细中查看建议替代物料信息。',
  195. '核验数据自动同步至订单交付详情页的Tab2和Tab4,无需重复查询。',
  196. ],
  197. },
  198. {
  199. title: '工单下达',
  200. funcDesc: [
  201. '工单下达模块管理生产工单的下达操作,是产销协同到制造执行(MES)的衔接环节。',
  202. '工单逐单下达(非批量),每行操作列独立"工单下达"按钮,弹出下达表单填写开工日期和生产批号后确认。',
  203. '下达前必须执行物料齐套检查(调用外部资源审查服务)和物料需求同步(生成MRP物料需求计划),确保物料准备到位。',
  204. '工单下达后MES系统可见,进入S6生产执行阶段;工单状态支持全程跟踪(待下达→已下达→生产中→已完成→已关闭)。',
  205. ],
  206. bizDesc: [
  207. '计划员/调度人员进入"工单下达"菜单,通过工单号、物料编码、开工日期、状态等条件筛选查询工单池列表。',
  208. '点击工具栏"物料齐套检查"按钮,调用外部资源审查服务,检查各工单的物料齐套状态,齐套结果更新到列表的"物料齐套"列。',
  209. '点击工具栏"生成物料需求"按钮,同步生成MRP物料需求计划,确保工单所需物料已纳入供应计划。',
  210. '物料齐套检查和MRP生成通过后,在列表中点击目标工单行的"工单下达"按钮,弹出下达表单。',
  211. '在下达表单中填写开工日期和生产批号(系统自动获取下一批次编号),点击确认后工单状态变更为"已下达"。',
  212. '已下达工单不可重复下达(前端按钮置灰+后端校验双重保障);工单下达后自动同步至MES系统。',
  213. ],
  214. },
  215. {
  216. title: '产销协同看板与KPI',
  217. funcDesc: [
  218. '产销协同看板为管理层和业务人员提供S1模块的核心KPI可视化监控面板。',
  219. '采用DynamicModuleDashboard动态看板组件(module-code="S1"),通过L1/L2/L3/L4多层级指标体系全面监控产销协同健康度。',
  220. 'L1核心指标:订单及时交付率、订单交付周期、订单评审完成率、成品库存周转天数。',
  221. 'L2分解指标:覆盖合同评审(3项)、产品设计(3项)、交期评审(3项)、发货联动(3项)共12项。',
  222. 'L3/L4节点指标:合同评审各审批节点的周期和通过率,支持逐层下钻分析。',
  223. '支持按客户维度筛选过滤,灵活下钻分析,趋势图表展示周期变化规律。',
  224. ],
  225. bizDesc: [
  226. '管理层/计划员进入"S1产销协同看板"菜单,系统自动加载L1核心KPI指标卡片(4项),直观展示当前产销协同健康度。',
  227. '通过客户下拉框选择特定客户维度,看板所有指标数据自动按该客户过滤刷新。',
  228. '点击L1指标卡片可下钻至L2分解指标详情,进一步点击L2指标可查看L3节点指标分布。',
  229. 'L4层级为审批节点明细指标(如合同评审各节点通过率和耗时),支持流程优化分析。',
  230. '趋势图表展示各指标的历史变化规律,支持按日/周/月周期切换查看。',
  231. 'KPI数据通过MDP作业S1_MDP_SYNC_TRANSFORM定时或手动刷新,指标定义存储在ado_smart_ops_kpi_master,计算结果存储在ado_s9_kpi_value_l1~l4_day。',
  232. ],
  233. },
  234. {
  235. title: '数据中台架构',
  236. funcDesc: [
  237. 'S1产销协同模块采用Ai-DOP统一数据中台分层架构(STG→STD→DWD→KPI),确保前端页面、看板展示和KPI考核的数据口径一致。',
  238. '贴源层(STG/mdp_stg_*)保留源系统原始数据;标准层(STD/mdp_std_*)统一字段口径并清洗脏数据;宽表层(DWD/dwd_*)构建面向页面和KPI的主题事实表;指标层(KPI/ado_s9_kpi_value_*)按天存储L1-L4指标值。',
  239. 'MDP作业(S1_MDP_SYNC_TRANSFORM)负责全链路同步转换,支持手动触发和未来扩展定时调度,作业日志可观测、异常可追溯。',
  240. ],
  241. bizDesc: [
  242. 'S1模块的业务数据(销售订单、合同评审、产品设计、发货计划、ASN发货、计划联动、需求核验等)通过MDP作业自动同步至数据中台各层。',
  243. '订单/评审/设计链路:crm_seorder等运行表→mdp_stg_so贴源→mdp_std_so标准→dwd_ship_trans/dwd_requirement_examine_detail宽表→KPI计算。',
  244. '发货/ASN/联动链路:ShippingPlan等运行表→mdp_stg_ship_trans贴源→mdp_std_ship_trans标准→dwd_ship_trans宽表→KPI计算。',
  245. '计划员可通过计划联动页面的"刷新"按钮手动触发全量同步;系统管理员通过MDP监控页面查看作业执行状态和处理日志。',
  246. '页面查询统一消费DWD/KPI层数据,避免直接访问运行时表,确保数据口径一致和查询性能优化。',
  247. ],
  248. },
  249. {
  250. title: '权限管理汇总',
  251. funcDesc: [
  252. 'S1产销协同模块涉及以下核心角色和权限:',
  253. '销售/客服专员:查看销售订单列表和订单交付列表;新建/编辑/删除订单;发起订单变更申请。',
  254. '计划工程师:查看和操作订单评审、工单下达、计划联动、需求核验;执行交期确认;查看KPI看板。',
  255. '商务人员:新建/编辑合同评审;提交审批;查看订单交付。',
  256. '设计员:新建/编辑/删除产品设计任务;录入BOM和工艺子表;保存操作。',
  257. '物流/仓管:新建/编辑/删除发货单和ASN发货单;管理发货明细行;查看订单交付。',
  258. '审批人:审核订单变更申请和合同评审的审批流。',
  259. '管理层:查看S1看板全部指标。',
  260. '系统管理员:管理用户角色权限;监控MDP作业状态;数据修复操作。',
  261. ],
  262. },
  263. ];
  264. // ═══════════════════════════════════════════════════
  265. // 生成文档
  266. // ═══════════════════════════════════════════════════
  267. function buildDocument() {
  268. const sections = [];
  269. // ── 封面/标题 ──
  270. sections.push(empty(), empty(), empty(), empty());
  271. sections.push(titlePara('产销协同业务需求描述'));
  272. sections.push(empty());
  273. // ── 文档信息 ──
  274. const infoItems = [
  275. '文档作者:彭熙玉',
  276. '创建日期:2026-06-08',
  277. '更新日期:2026-06-08',
  278. '文档编号:DOP-S1-REQ-001',
  279. '当前版本:V1.0',
  280. ];
  281. infoItems.forEach(item => sections.push(docInfoPara(item)));
  282. sections.push(empty(), empty());
  283. // ── 目录 ──
  284. sections.push(pageBreak());
  285. sections.push(new Paragraph({
  286. children: [new TextRun({ text: '目录', bold: true, size: 28, font: FONT })],
  287. heading: HeadingLevel.HEADING_2,
  288. spacing: { before: 200, after: 300 },
  289. }));
  290. sections.push(new TableOfContents('目录', {
  291. headingStyleRange: '2-3',
  292. hyperlink: true,
  293. }));
  294. sections.push(new Paragraph({
  295. children: [new TextRun({ text: '(如目录未显示,请在 Word 中右键此处 → 更新域)', size: 18, font: FONT, italics: true, color: '888888' })],
  296. spacing: { before: 40, after: 200 },
  297. }));
  298. // ── 各功能模块 ──
  299. for (let i = 0; i < modules.length; i++) {
  300. const mod = modules[i];
  301. sections.push(pageBreak());
  302. // 章节标题:(一) 产品设计管理
  303. sections.push(sectionHeading(`(${CN_NUM[i + 1]})${mod.title}`));
  304. // 功能说明
  305. sections.push(subHeading('功能说明'));
  306. (mod.funcDesc || []).forEach(desc => sections.push(normalPara(desc)));
  307. // 业务描述
  308. if (mod.bizDesc && mod.bizDesc.length) {
  309. sections.push(subHeading('业务描述'));
  310. mod.bizDesc.forEach(desc => sections.push(normalPara(desc)));
  311. }
  312. }
  313. return sections;
  314. }
  315. // ═══════════════════════════════════════════════════
  316. // 主流程
  317. // ═══════════════════════════════════════════════════
  318. async function main() {
  319. const sections = buildDocument();
  320. const doc = new Document({
  321. styles: { default: { document: { run: { font: FONT, size: 21 } } } },
  322. sections: [{
  323. properties: { page: { margin: { top: convertInchesToTwip(0.8), bottom: convertInchesToTwip(0.8), left: convertInchesToTwip(1.2), right: convertInchesToTwip(1.2) } } },
  324. children: sections,
  325. }],
  326. });
  327. const buffer = await Packer.toBuffer(doc);
  328. const outPath = 'd:\\DEMONET\\doc\\S1产销协同业务需求描述.docx';
  329. const tempPath = 'd:\\DEMONET\\doc\\req_temp.docx';
  330. fs.writeFileSync(tempPath, buffer);
  331. try { fs.unlinkSync(outPath); } catch(e) {}
  332. try { fs.renameSync(tempPath, outPath); console.log(`Renamed to: ${outPath}`); }
  333. catch(e) { console.log(`Generated: ${tempPath}`); }
  334. console.log(`Size: ${(buffer.length / 1024).toFixed(1)} KB`);
  335. }
  336. main().catch(err => { console.error('Error:', err); process.exit(1); });