generate_operation_manuals.js 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085
  1. /**
  2. * 生成 S1-S4 模块用户操作手册 (DOCX)
  3. * 基于模板:DOP生产管理用户操作手册.docx
  4. * 输出文件:
  5. * - 【S1产销协同模块用户操作手册】DOP生产管理用户操作手册.docx
  6. * - 【S2制造协同模块用户操作手册】DOP生产管理用户操作手册.docx
  7. * - 【S3供应协同模块用户操作手册】DOP生产管理用户操作手册.docx
  8. * - 【S4采购执行模块用户操作手册】DOP生产管理用户操作手册.docx
  9. */
  10. const fs = require('fs');
  11. const path = require('path');
  12. const {
  13. Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell,
  14. HeadingLevel, AlignmentType, BorderStyle, WidthType, ShadingType,
  15. convertInchesToTwip, PageBreak, TabStopType, TabStopPosition,
  16. TableOfContents, ImageRun
  17. } = require('docx');
  18. // ═══════════════════════════════════════════════════
  19. // 通用样式与辅助函数
  20. // ═══════════════════════════════════════════════════
  21. const FONT = '微软雅黑';
  22. const FONT_BODY = '宋体';
  23. const BLUE = '1F4E79';
  24. const thinBorder = {
  25. top: { style: BorderStyle.SINGLE, size: 1 },
  26. bottom: { style: BorderStyle.SINGLE, size: 1 },
  27. left: { style: BorderStyle.SINGLE, size: 1 },
  28. right: { style: BorderStyle.SINGLE, size: 1 },
  29. };
  30. const headerShading = { fill: '1F3864', type: ShadingType.CLEAR };
  31. const lightShading = { fill: 'E8F0FE', type: ShadingType.CLEAR };
  32. function p(text, opts = {}) {
  33. return new Paragraph({
  34. children: [new TextRun({ text, size: 21, font: FONT_BODY, ...opts })],
  35. spacing: { after: 120, line: 360 },
  36. });
  37. }
  38. function bp(text, opts = {}) {
  39. return new Paragraph({
  40. children: [new TextRun({ text, bold: true, size: 21, font: FONT, ...opts })],
  41. spacing: { after: 80, line: 360 },
  42. });
  43. }
  44. function empty() { return new Paragraph({ spacing: { after: 80 }, children: [] }); }
  45. function pageBreak() { return new Paragraph({ children: [new PageBreak()] }); }
  46. function note(text) {
  47. return new Paragraph({
  48. children: [new TextRun({ text: '【说明】' + text, size: 20, font: FONT_BODY, italics: true, color: '666666' })],
  49. spacing: { after: 100, line: 320 },
  50. });
  51. }
  52. function tip(text) {
  53. return new Paragraph({
  54. children: [new TextRun({ text: '【注意】' + text, size: 20, font: FONT_BODY, color: 'CC0000' })],
  55. spacing: { after: 100, line: 320 },
  56. });
  57. }
  58. function h1(text) {
  59. return new Paragraph({
  60. children: [new TextRun({ text, bold: true, size: 32, font: FONT, color: BLUE })],
  61. heading: HeadingLevel.HEADING_1,
  62. spacing: { before: 400, after: 200 },
  63. });
  64. }
  65. function h2(text) {
  66. return new Paragraph({
  67. children: [new TextRun({ text, bold: true, size: 28, font: FONT, color: '2E75B6' })],
  68. heading: HeadingLevel.HEADING_2,
  69. spacing: { before: 300, after: 150 },
  70. });
  71. }
  72. function h3(text) {
  73. return new Paragraph({
  74. children: [new TextRun({ text, bold: true, size: 24, font: FONT })],
  75. heading: HeadingLevel.HEADING_3,
  76. spacing: { before: 200, after: 100 },
  77. });
  78. }
  79. function step(num, text) {
  80. return new Paragraph({
  81. children: [
  82. new TextRun({ text: `步骤${num}:`, bold: true, size: 21, font: FONT, color: BLUE }),
  83. new TextRun({ text, size: 21, font: FONT_BODY }),
  84. ],
  85. spacing: { after: 80, line: 360 },
  86. indent: { left: 200 },
  87. });
  88. }
  89. function bullet(text, indent = 0) {
  90. return new Paragraph({
  91. children: [new TextRun({ text: ` ● ${text}`, size: 21, font: FONT_BODY })],
  92. spacing: { after: 60, line: 340 },
  93. indent: { left: 300 + indent * 400 },
  94. });
  95. }
  96. // Table helpers
  97. function hdrCell(text, w) {
  98. return new TableCell({
  99. children: [new Paragraph({ children: [new TextRun({ text, bold: true, size: 20, font: FONT, color: 'FFFFFF' })], alignment: AlignmentType.CENTER })],
  100. width: { size: w, type: WidthType.DXA }, borders: thinBorder, shading: headerShading,
  101. });
  102. }
  103. function tc(text, w, opts = {}) {
  104. return new TableCell({
  105. children: [new Paragraph({ children: [new TextRun({ text: String(text ?? ''), size: 20, font: FONT_BODY, bold: opts.bold || false })], alignment: opts.center ? AlignmentType.CENTER : AlignmentType.LEFT })],
  106. width: { size: w, type: WidthType.DXA }, borders: thinBorder, shading: opts.shading || undefined,
  107. });
  108. }
  109. function table(headers, rows, widths) {
  110. return new Table({
  111. rows: [
  112. new TableRow({ children: headers.map((h, i) => hdrCell(h, widths ? widths[i] : 1800)), tableHeader: true }),
  113. ...rows.map(r => new TableRow({ children: r.map((c, i) => tc(c, widths ? widths[i] : 1800)) })),
  114. ],
  115. width: { size: 100, type: WidthType.PERCENTAGE },
  116. });
  117. }
  118. // Image placeholder
  119. function imgPlaceholder(caption) {
  120. return [
  121. new Paragraph({
  122. children: [new TextRun({ text: `【${caption}】`, size: 20, font: FONT_BODY, italics: true, color: '888888' })],
  123. alignment: AlignmentType.CENTER,
  124. spacing: { before: 100, after: 60 },
  125. border: { top: { style: BorderStyle.DASHED, size: 1, color: 'CCCCCC' }, bottom: { style: BorderStyle.DASHED, size: 1, color: 'CCCCCC' }, left: { style: BorderStyle.DASHED, size: 1, color: 'CCCCCC' }, right: { style: BorderStyle.DASHED, size: 1, color: 'CCCCCC' } },
  126. indent: { left: 1200, right: 1200 },
  127. }),
  128. new Paragraph({
  129. children: [new TextRun({ text: `(截图区域:${caption},请替换为实际系统截图)`, size: 18, font: FONT_BODY, italics: true, color: 'AAAAAA' })],
  130. alignment: AlignmentType.CENTER,
  131. spacing: { after: 100 },
  132. }),
  133. ];
  134. }
  135. function operationRow(stepNum, operation, desc) {
  136. const w = [600, 3400, 6000];
  137. return table(['步骤', '操作', '说明'], [[String(stepNum), operation, desc]], w);
  138. }
  139. // TOC
  140. function buildTOC() {
  141. return [
  142. new TableOfContents('目录', { headingStyleRange: '1-3', hyperlink: true }),
  143. new Paragraph({
  144. children: [new TextRun({ text: '(如目录未显示,请在 Word 中右键此处 → 更新域)', size: 18, font: FONT, italics: true, color: '888888' })],
  145. spacing: { before: 40, after: 200 },
  146. }),
  147. ];
  148. }
  149. // ═══════════════════════════════════════════════════
  150. // 封面生成
  151. // ═══════════════════════════════════════════════════
  152. function buildCover(moduleCode, moduleName) {
  153. const sections = [];
  154. sections.push(empty(), empty(), empty(), empty());
  155. // 项目名称
  156. sections.push(new Paragraph({
  157. children: [new TextRun({ text: 'Ai-DOP智慧运营管理系统', bold: true, size: 36, font: FONT, color: BLUE })],
  158. alignment: AlignmentType.CENTER, spacing: { after: 200 },
  159. }));
  160. // 模块名
  161. sections.push(new Paragraph({
  162. children: [new TextRun({ text: `${moduleCode} ${moduleName}`, bold: true, size: 48, font: FONT, color: BLUE })],
  163. alignment: AlignmentType.CENTER, spacing: { after: 100 },
  164. }));
  165. // 文档类型
  166. sections.push(new Paragraph({
  167. children: [new TextRun({ text: '用户操作手册', bold: true, size: 44, font: FONT, color: BLUE })],
  168. alignment: AlignmentType.CENTER, spacing: { after: 600 },
  169. }));
  170. // 信息区
  171. const infoData = [
  172. ['作 者:', '智造易项目组'],
  173. ['创建日期:', '2026-07-30'],
  174. ['修订日期:', '2026-07-30'],
  175. ['当前版本:', 'V1.0'],
  176. ];
  177. infoData.forEach(([k, v]) => {
  178. sections.push(new Paragraph({
  179. children: [
  180. new TextRun({ text: k, bold: true, size: 22, font: FONT }),
  181. new TextRun({ text: v, size: 22, font: FONT_BODY }),
  182. ],
  183. alignment: AlignmentType.CENTER,
  184. spacing: { after: 60 },
  185. }));
  186. });
  187. return sections;
  188. }
  189. // ═══════════════════════════════════════════════════
  190. // 通用章节:系统登录与首页
  191. // ═══════════════════════════════════════════════════
  192. function buildLoginSection() {
  193. const sections = [];
  194. sections.push(h1('1. 系统登录与首页'));
  195. sections.push(h2('1.1 登录系统'));
  196. sections.push(step('1', '打开浏览器,在地址栏输入系统URL。'));
  197. sections.push(step('2', '输入用户名和密码,点击"登录"按钮进入系统。'));
  198. sections.push(step('3', '如忘记密码,请联系系统管理员重置。'));
  199. sections.push(note('系统支持Chrome、Edge、Firefox等主流浏览器,推荐使用Chrome最新版本。'));
  200. sections.push(...imgPlaceholder('图1.1 系统登录页面'));
  201. sections.push(h2('1.2 系统首页'));
  202. sections.push(p('登录成功后进入系统首页,页面主要包含以下区域:'));
  203. sections.push(bullet('顶部导航栏:显示系统LOGO、当前模块菜单、全屏切换等'));
  204. sections.push(bullet('左侧菜单栏:按模块分组展示功能菜单,点击展开/折叠'));
  205. sections.push(bullet('右侧工作区:显示当前选中功能页面的内容'));
  206. sections.push(bullet('右上角用户区:显示当前登录用户信息,下拉菜单含个人中心、修改密码、退出登录'));
  207. sections.push(...imgPlaceholder('图1.2 系统首页布局'));
  208. sections.push(h2('1.3 修改密码'));
  209. sections.push(step('1', '点击页面右上角用户头像/用户名区域。'));
  210. sections.push(step('2', '在下拉菜单中选择"个人中心"。'));
  211. sections.push(step('3', '点击"修改密码"标签页。'));
  212. sections.push(step('4', '输入旧密码、新密码并确认,点击"保存"。'));
  213. sections.push(tip('密码长度不少于6位,建议使用字母+数字+特殊字符组合。'));
  214. sections.push(...imgPlaceholder('图1.3 修改密码页面'));
  215. sections.push(h2('1.4 退出系统'));
  216. sections.push(step('1', '点击右上角用户头像/用户名。'));
  217. sections.push(step('2', '在下拉菜单中选择"退出系统"。'));
  218. sections.push(note('为保障数据安全,长时间不操作系统将自动退出登录。'));
  219. return sections;
  220. }
  221. // ═══════════════════════════════════════════════════
  222. // 功能操作说明构建函数
  223. // ═══════════════════════════════════════════════════
  224. function buildFuncGuide(funcNum, funcName, route, role, funcData) {
  225. const sections = [];
  226. sections.push(h3(`${funcNum} ${funcName}`));
  227. // 功能概述
  228. sections.push(bp('【功能概述】'));
  229. sections.push(p(funcData.overview));
  230. // 适用角色
  231. sections.push(bp('【适用角色】'));
  232. sections.push(p(role));
  233. // 页面路径
  234. if (route) {
  235. sections.push(bp('【菜单路径】'));
  236. sections.push(p(`左侧菜单 → ${route}`));
  237. }
  238. // 操作步骤
  239. sections.push(bp('【操作步骤】'));
  240. if (funcData.steps) {
  241. funcData.steps.forEach((s, i) => {
  242. sections.push(step(String(i + 1), s));
  243. });
  244. }
  245. // 截图
  246. if (funcData.screenshots) {
  247. funcData.screenshots.forEach(cap => {
  248. sections.push(...imgPlaceholder(cap));
  249. });
  250. }
  251. // 操作说明表
  252. if (funcData.ops) {
  253. sections.push(empty());
  254. sections.push(table(['步骤', '操作', '说明'], funcData.ops, [600, 3400, 6000]));
  255. }
  256. // 注意事项
  257. if (funcData.notes && funcData.notes.length > 0) {
  258. sections.push(bp('【注意事项】'));
  259. funcData.notes.forEach(n => sections.push(tip(n)));
  260. }
  261. // 常见问题
  262. if (funcData.faq && funcData.faq.length > 0) {
  263. sections.push(bp('【常见问题】'));
  264. funcData.faq.forEach(([q, a]) => {
  265. sections.push(new Paragraph({
  266. children: [
  267. new TextRun({ text: `Q: ${q}`, bold: true, size: 20, font: FONT }),
  268. ],
  269. spacing: { after: 40 },
  270. }));
  271. sections.push(new Paragraph({
  272. children: [new TextRun({ text: `A: ${a}`, size: 20, font: FONT_BODY })],
  273. spacing: { after: 80 },
  274. indent: { left: 300 },
  275. }));
  276. });
  277. }
  278. return sections;
  279. }
  280. // ═══════════════════════════════════════════════════
  281. // S1 产销协同 操作手册数据
  282. // ═══════════════════════════════════════════════════
  283. const S1_DATA = {
  284. moduleCode: 'S1',
  285. moduleName: '产销协同',
  286. overview: 'S1产销协同模块是Ai-DOP平台订单履约链路的起点,负责从产品设计、订单接收、评审交期、工单下达到发货管理的全流程在线协同。本手册将指导您如何使用该模块的各项功能。',
  287. functions: {
  288. '2.1': {
  289. funcNum: '2.1', funcName: '产品设计管理', route: '产销协同 → 产品设计',
  290. role: '设计员、计划工程师',
  291. data: {
  292. overview: '产品设计管理用于在线录入和维护新产品设计过程中的BOM(物料清单)和工艺路线信息。采用直接保存模式,保存即生效,无需审批。',
  293. steps: [
  294. '在左侧菜单展开"产销协同",点击"产品设计"进入列表页面。',
  295. '点击"新建"按钮,在弹出的表单中填写产品设计基本信息:选择成品物料编码、填写任务名称、计划完成日期。',
  296. '在BOM子表中,点击"新增行",选择子物料编码(系统自动填入物料名称),填写单位用量和损耗率。',
  297. '在工艺子表中,点击"新增行",通过下拉框选择产线(支持远程搜索),手动输入路线编码。',
  298. '确认信息填写完整后,点击"保存"。单据编号自动生成,页面返回列表并显示新记录。',
  299. ],
  300. screenshots: ['图2.1.1 产品设计列表页', '图2.1.2 产品设计编辑表单'],
  301. ops: [
  302. ['1', '进入产品设计列表', '打开产品设计列表页面,可查看所有已创建的设计任务'],
  303. ['2', '新建产品设计', '点击"新建"按钮,弹出空白表单'],
  304. ['3', '填写BOM子表', '在子表中新增行,选择物料编码并填写用量'],
  305. ['4', '填写工艺子表', '在子表中新增行,选择产线并输入路线编码'],
  306. ['5', '保存', '点击"保存"按钮,数据生效,列表自动刷新'],
  307. ],
  308. notes: ['物料编码、任务名称、计划完成日期为必填项,缺失时无法保存。', 'BOM子表至少保留一行数据。', '产品设计无审批流,保存即生效。'],
  309. faq: [['如何修改已保存的设计任务?', '在列表中点击对应行的"编辑"按钮,修改后保存即可。'], ['BOM子表中的物料搜索不到?', '请确认物料主数据是否已同步。可联系系统管理员检查MDP同步状态。']],
  310. },
  311. },
  312. '2.2': {
  313. funcNum: '2.2', funcName: '合同评审管理', route: '产销协同 → 合同评审',
  314. role: '商务人员、审批人',
  315. data: {
  316. overview: '合同评审管理用于客户合同的在线评审,支持多级审批流程。审批通过后合同数据纳入KPI考核体系。',
  317. steps: [
  318. '在左侧菜单点击"合同评审"进入列表页面。',
  319. '点击"新建"按钮,录入合同基本信息:合同编号、客户名称、签订日期等。',
  320. '确认信息无误后,点击"提交审批"。',
  321. '审批人登录后,在"审批中心"查看待办任务,点击"处理"进入审批页面。',
  322. '审批人可选择"同意"或"驳回",填写审批意见后提交。',
  323. '流程结束后,合同状态更新为"已通过"或"已驳回"。',
  324. ],
  325. screenshots: ['图2.2.1 合同评审列表', '图2.2.2 合同评审审批页面'],
  326. ops: [
  327. ['1', '查看合同评审列表', '支持按合同编号、客户、状态筛选'],
  328. ['2', '新建合同评审', '录入合同信息并保存'],
  329. ['3', '提交审批', '发起审批流,系统自动匹配审批人'],
  330. ['4', '审批处理', '审批人进行同意/驳回/转办等操作'],
  331. ],
  332. notes: ['提交审批前请确认合同信息完整准确。', '审批流程中各节点审批人由系统根据流程配置自动分配。'],
  333. faq: [['审批流没有启动?', '请联系管理员确认CONTRACT_REVIEW审批流是否已配置并发布。']],
  334. },
  335. },
  336. '2.3': {
  337. funcNum: '2.3', funcName: '订单评审管理', route: '产销协同 → 订单管理',
  338. role: '销售专员、计划工程师',
  339. data: {
  340. overview: '订单评审管理用于销售订单的在线录入、查询、编辑和交期评估。主流程(录入→评审→确认)无需审批,仅订单变更时触发审批流。',
  341. steps: [
  342. '点击"订单管理"进入订单列表页面,可通过订单号、客户、日期范围等条件筛选。',
  343. '点击"新建"按钮录入销售订单:选择客户、物料编码、填写数量和需求交期。',
  344. '保存后订单进入"待评审"状态。计划员点击"评审"按钮执行交期评估。',
  345. '系统给出建议交期后,计划员点击"确认交期"完成。',
  346. '如需修改已确认的订单,点击"变更"发起变更申请,走审批流。',
  347. ],
  348. screenshots: ['图2.3.1 订单列表页', '图2.3.2 订单编辑表单', '图2.3.3 订单变更审批'],
  349. ops: [
  350. ['1', '查询订单列表', '支持多条件筛选和排序'],
  351. ['2', '新建销售订单', '填写客户、物料、数量、交期等信息'],
  352. ['3', '执行订单评审', '计划员评估交期'],
  353. ['4', '确认交期', '确认后订单进入执行阶段'],
  354. ['5', '订单变更', '已确认订单变更需走审批流'],
  355. ],
  356. notes: ['订单编号系统自动生成,全局唯一。', '订单主流程无需审批,直接确认生效。', '仅"已确认"状态的订单可发起变更。'],
  357. faq: [['如何查看订单变更历史?', '进入订单交付详情页面,Tab2(评审信息)中可查看变更记录。']],
  358. },
  359. },
  360. '2.4': {
  361. funcNum: '2.4', funcName: '订单交付管理', route: '产销协同 → 订单交付',
  362. role: '计划工程师、物流/仓管',
  363. data: {
  364. overview: '订单交付管理以订单行为粒度,通过8个Tab页签实现从"订单接收"到"成品发运"的全链路履约状态追踪。',
  365. steps: [
  366. '点击"订单交付"进入交付列表页面,可通过订单号、客户、交付状态筛选。',
  367. '在列表中找到目标订单行,点击进入详情页面。',
  368. '详情页含8个Tab页签:订单信息(Tab1) → 评审信息(Tab2) → 排程(Tab3) → 物料需求(Tab4) → 采购(Tab5) → 备料(Tab6) → 生产(Tab7) → 入库发运(Tab8)。',
  369. '点击各Tab查看对应环节的执行状态和详细信息。',
  370. ],
  371. screenshots: ['图2.4.1 订单交付列表', '图2.4.2 订单交付详情-8Tab'],
  372. ops: [
  373. ['1', '查询交付列表', '按订单号、客户、交付状态筛选'],
  374. ['2', '进入交付详情', '点击订单行进入8Tab全景追踪页面'],
  375. ['3', '查看订单信息(Tab1)', '查看订单基础档案信息'],
  376. ['4', '查看评审信息(Tab2)', '查看交期评估和变更历史'],
  377. ['5', '查看物料需求(Tab4)', '查看BOM展开和缺料分析'],
  378. ],
  379. notes: ['跨模块Tab(排程/采购/备料/生产/入库)的数据需对应模块完成后才有内容。', '交付状态从"待评审"到"已发运"自动流转。'],
  380. faq: [['某个Tab显示无数据?', '该Tab对应的模块尚未完成数据同步,请等待对应环节执行完成。']],
  381. },
  382. },
  383. '2.5': {
  384. funcNum: '2.5', funcName: '订单发货管理', route: '产销协同 → 发货管理',
  385. role: '物流/仓管',
  386. data: {
  387. overview: '订单发货管理用于发货单和ASN(预先发货通知)的在线管理,与销售订单联动,跟踪发货计划执行情况。',
  388. steps: [
  389. '点击"发货管理"进入发货单列表页面。',
  390. '点击"新建"创建发货单:在下拉框中选择关联的销售单号(支持远程搜索)。',
  391. '选择客户,在明细子表中新增行,填写物料编码、发货数量、批次等信息。',
  392. '保存后发货单号自动生成(格式SH+日期+流水号)。',
  393. '如需录入ASN发货信息,在ASN发货标签页中填写ASN单号、物料、发货数量和日期。',
  394. ],
  395. screenshots: ['图2.5.1 发货单列表', '图2.5.2 发货单编辑表单'],
  396. ops: [
  397. ['1', '查询发货单列表', '按发货单号、销售单号、客户筛选'],
  398. ['2', '新建发货单', '关联销售单号,填写发货信息'],
  399. ['3', '管理发货明细', '在子表中增删物料行'],
  400. ['4', '录入ASN发货', '填写ASN发运信息'],
  401. ],
  402. notes: ['已发货的发货单不可删除,防止数据丢失。', '发货单号格式为SH+日期+流水号,自动生成。'],
  403. faq: [['销售单号下拉框中找不到?', '请确认销售订单已确认且未被其他发货单全额关联。']],
  404. },
  405. },
  406. '2.6': {
  407. funcNum: '2.6', funcName: '工单下达', route: '产销协同 → 工单下达',
  408. role: '计划员/调度',
  409. data: {
  410. overview: '工单下达是产销协同到制造执行的衔接环节,负责生产工单的物料齐套检查和逐单下达操作。',
  411. steps: [
  412. '点击"工单下达"进入工单列表页面,可按工单号、物料编码、状态筛选。',
  413. '点击工具栏"物料齐套检查"按钮,系统检查各工单的物料准备状态。',
  414. '点击工具栏"生成物料需求"按钮,同步生成物料需求计划(MRP)。',
  415. '确认物料齐套后,在目标工单行的操作列点击"工单下达"按钮。',
  416. '在弹出的表单中填写开工日期和生产批号,点击"确认下达"。',
  417. '工单状态变更为"已下达",MES系统可见。',
  418. ],
  419. screenshots: ['图2.6.1 工单下达列表', '图2.6.2 工单下达确认表单'],
  420. ops: [
  421. ['1', '查询工单列表', '按工单号、物料、状态筛选'],
  422. ['2', '物料齐套检查', '工具栏按钮,检查物料准备状态'],
  423. ['3', '生成物料需求', '工具栏按钮,同步生成MRP'],
  424. ['4', '逐单下达', '点击操作列"工单下达",填写信息确认'],
  425. ],
  426. notes: ['工单逐行单个下达,不支持批量一键下达。', '已下达的工单不可重复下达(按钮置灰+后端校验)。', '下达前必须完成物料齐套检查。'],
  427. faq: [['工单下达按钮灰色不可点击?', '请确认工单状态为"待下达",且已完成物料齐套检查。']],
  428. },
  429. },
  430. '2.7': {
  431. funcNum: '2.7', funcName: '计划联动看板', route: '产销协同 → 计划联动',
  432. role: '计划工程师',
  433. data: {
  434. overview: '计划联动看板用于查看和刷新销售订单、发货计划、ASN发货等业务数据的联动状态,支持手动触发数据同步。',
  435. steps: [
  436. '点击"计划联动"进入联动列表页面,查看各业务对象的联动状态。',
  437. '如需刷新数据,点击"手动刷新"按钮。',
  438. '系统触发MDP全量同步转换作业,执行STG→STD→DWD→KPI全链路。',
  439. '刷新完成后页面自动更新为最新联动结果。',
  440. ],
  441. screenshots: ['图2.7.1 计划联动看板'],
  442. ops: [
  443. ['1', '查看联动列表', '查看各业务对象的联动状态'],
  444. ['2', '手动刷新', '点击按钮触发全量数据同步'],
  445. ['3', '查看刷新结果', '刷新完成后页面自动更新'],
  446. ],
  447. notes: ['手动刷新会触发后台作业,刷新时间取决于数据量。', '可通过MDP运行监控页面查看作业执行状态。'],
  448. faq: [['刷新后数据没有变化?', '请检查MDP运行监控页面确认作业是否执行成功。']],
  449. },
  450. },
  451. '2.8': {
  452. funcNum: '2.8', funcName: '需求明细核验', route: '产销协同 → 需求核验',
  453. role: '计划工程师',
  454. data: {
  455. overview: '需求明细核验用于展示销售订单的BOM需求展开与核验结果,帮助计划人员确认物料需求数量和到货时间。',
  456. steps: [
  457. '点击"需求核验"进入核验列表页面。',
  458. '通过订单号、物料编码、核验状态等条件筛选。',
  459. '查看BOM需求展开结果:物料编码、需求数量、缺料数量、替代料方案。',
  460. '核验结果同时展示在订单交付详情的Tab2和Tab4中。',
  461. ],
  462. screenshots: ['图2.8.1 需求核验列表'],
  463. ops: [
  464. ['1', '查询核验列表', '按订单号、物料编码筛选'],
  465. ['2', '查看核验明细', '查看BOM需求展开和缺料分析'],
  466. ],
  467. notes: ['核验数据取最新成功批次,确保数据一致性。'],
  468. faq: [['核验数据为空?', '请确认MDP需求核验同步作业已执行完成。']],
  469. },
  470. },
  471. '2.9': {
  472. funcNum: '2.9', funcName: '产销协同看板(KPI)', route: '产销协同 → 产销协同看板',
  473. role: '管理层、计划工程师',
  474. data: {
  475. overview: '产销协同看板为管理层和业务人员提供S1模块核心KPI的可视化监控,支持L1-L4多层级指标下钻分析。',
  476. steps: [
  477. '点击"产销协同看板"进入看板页面。',
  478. '查看L1核心KPI指标卡片:订单及时交付率、订单交付周期、订单评审完成率、成品库存周转天数。',
  479. '可通过客户维度下拉框筛选数据。',
  480. '点击指标卡片可下钻查看L2分解指标详情。',
  481. '选择日期范围查看趋势图表。',
  482. ],
  483. screenshots: ['图2.9.1 产销协同看板主页'],
  484. ops: [
  485. ['1', '查看L1核心指标', '4项核心KPI指标卡片'],
  486. ['2', '客户维度筛选', '下拉框选择客户过滤数据'],
  487. ['3', '指标下钻', '点击卡片查看L2/L3详细指标'],
  488. ['4', '趋势分析', '查看指标周期趋势图表'],
  489. ],
  490. notes: ['KPI数据由MDP作业定时计算,非实时更新。', '如KPI数据为空,请通过计划联动页面的"手动刷新"触发计算。'],
  491. faq: [['KPI指标显示为空?', '请在计划联动页面点击"手动刷新"触发MDP作业。']],
  492. },
  493. },
  494. },
  495. };
  496. // ═══════════════════════════════════════════════════
  497. // S2 制造协同 操作手册数据
  498. // ═══════════════════════════════════════════════════
  499. const S2_DATA = {
  500. moduleCode: 'S2',
  501. moduleName: '制造协同',
  502. overview: 'S2制造协同模块承接S1工单下达后的生产排程与执行管理,实现从排程优化到日计划执行的制造协同闭环。',
  503. functions: {
  504. '2.1': {
  505. funcNum: '2.1', funcName: '生产排程', route: '制造协同 → 生产排程',
  506. role: '计划员/调度',
  507. data: {
  508. overview: '生产排程基于产能约束、物料齐套、优先级等条件,对已下达工单进行智能排程计算,并以甘特图形式展示排程结果。',
  509. steps: [
  510. '点击"生产排程"进入排程列表页面。',
  511. '设置排程参数(优先级、产能约束等),选择需要排程的工单。',
  512. '点击"排程计算"按钮触发排程引擎计算。',
  513. '排程完成后,在甘特图区域查看工单在产线上的时间分布。',
  514. '排程结果自动写入ScheduleResultOpMaster表。',
  515. ],
  516. screenshots: ['图2.1.1 生产排程列表', '图2.1.2 排程甘特图'],
  517. ops: [
  518. ['1', '查询排程列表', '查看待排程和已排程工单'],
  519. ['2', '设置排程参数', '配置优先级、产能约束'],
  520. ['3', '执行排程计算', '触发排程引擎'],
  521. ['4', '查看甘特图', '可视化查看工单排程结果'],
  522. ],
  523. notes: ['排程按优先级ASC排序。', '排程计算耗时取决于工单数量和产能复杂度。'],
  524. faq: [['排程计算失败?', '请检查排产异常记录页面查看具体错误原因。']],
  525. },
  526. },
  527. '2.2': {
  528. funcNum: '2.2', funcName: '排产异常记录', route: '制造协同 → 排产异常',
  529. role: '计划员/调度',
  530. data: {
  531. overview: '排产异常记录用于查看排程过程中产生的异常信息,帮助快速定位和解决排程问题。',
  532. steps: [
  533. '点击"排产异常"进入异常记录列表。',
  534. '可按工单号、异常类型、日期范围筛选。',
  535. '点击异常记录查看详细错误信息和处理建议。',
  536. ],
  537. screenshots: ['图2.2.1 排产异常记录'],
  538. ops: [
  539. ['1', '查询异常记录', '按工单号、异常类型筛选'],
  540. ['2', '查看异常详情', '查看错误原因和处理建议'],
  541. ],
  542. notes: ['异常记录由排程引擎自动生成。'],
  543. faq: [],
  544. },
  545. },
  546. '2.3': {
  547. funcNum: '2.3', funcName: '可执行日计划', route: '制造协同 → 可执行日计划',
  548. role: '计划员/调度',
  549. data: {
  550. overview: '可执行日计划将排程结果转化为每日可执行的生产计划,按日期展示当日任务和模具分配信息。',
  551. steps: [
  552. '点击"可执行日计划"进入日计划列表页面。',
  553. '列表按PlanDate排序,显示每日生产任务。',
  554. '查看各工单的模具分配数量(MoldAllocationCount)。',
  555. '可修改未来两天的工单数量,支持计划撤回。',
  556. ],
  557. screenshots: ['图2.3.1 可执行日计划列表'],
  558. ops: [
  559. ['1', '查看日计划列表', '按日期排列的每日任务'],
  560. ['2', '修改计划数量', '可调整未来两天工单数量'],
  561. ['3', '计划撤回', '撤回未开始的日计划'],
  562. ],
  563. notes: ['默认展示未来3天计划,可手动调整日期范围查看更久。', '日计划下单后支持修改后两天的工单数量。'],
  564. faq: [['如何查看更久远的计划?', '在日期筛选条件中调整日期范围即可。']],
  565. },
  566. },
  567. '2.4': {
  568. funcNum: '2.4', funcName: '产线日历管理', route: '制造协同 → 产线日历',
  569. role: '计划员',
  570. data: {
  571. overview: '产线日历管理用于维护各产线的工作日历、休息时间和节假日,为排程提供产能约束基础数据。',
  572. steps: [
  573. '点击"工作日历"进入日历列表,查看各产线日历配置。',
  574. '点击"新建"为产线配置工作日历,选择产线和日期。',
  575. '在"休息时间"页面配置产线休息时段(如午休)。',
  576. '在"节假日"页面维护法定节假日和厂休日。',
  577. ],
  578. screenshots: ['图2.4.1 工作日历列表', '图2.4.2 休息时间配置'],
  579. ops: [
  580. ['1', '配置工作日历', '选择产线、设置工作日期'],
  581. ['2', '设置休息时间', '配置每日休息时段'],
  582. ['3', '维护节假日', '添加法定节假日和厂休日'],
  583. ],
  584. notes: ['系统默认排产每天7.5小时,加班需在加班维护中添加。'],
  585. faq: [],
  586. },
  587. },
  588. '2.5': {
  589. funcNum: '2.5', funcName: '产线加班管理', route: '制造协同 → 加班管理',
  590. role: '计划员',
  591. data: {
  592. overview: '产线加班管理用于配置产线的加班时间,排程时将自动纳入加班产能计算。',
  593. steps: [
  594. '点击"加班管理"进入加班配置列表。',
  595. '点击"新建"选择产线和加班日期。',
  596. '填写加班起止时间和加班产能系数。',
  597. '保存后,排程计算将自动考虑加班时间。',
  598. ],
  599. screenshots: ['图2.5.1 加班管理列表'],
  600. ops: [
  601. ['1', '新建加班配置', '选择产线、日期、加班时段'],
  602. ['2', '设置加班系数', '配置加班产能系数'],
  603. ],
  604. notes: ['系统默认每天7.5小时排产,超出部分需配置加班。'],
  605. faq: [],
  606. },
  607. },
  608. '2.6': {
  609. funcNum: '2.6', funcName: '工单执行追踪', route: '制造协同 → 工单执行追踪',
  610. role: '调度',
  611. data: {
  612. overview: '工单执行追踪用于跟踪工单从下达到完成的全过程,包括物料消耗和工序进度。',
  613. steps: [
  614. '点击"工单执行追踪"进入追踪列表。',
  615. '按工单号或状态筛选,查看工单执行状态(待下达→已下达→生产中→已完成→已关闭)。',
  616. '点击"物料明细"查看工单物料消耗情况。',
  617. '点击"工序明细"查看工单各工序的执行进度。',
  618. ],
  619. screenshots: ['图2.6.1 工单执行追踪'],
  620. ops: [
  621. ['1', '查询工单状态', '按工单号筛选,查看执行状态'],
  622. ['2', '查看物料明细', '查看物料消耗汇总'],
  623. ['3', '查看工序明细', '查看各工序完成情况'],
  624. ],
  625. notes: ['工单状态W/S/R/P自动流转。'],
  626. faq: [],
  627. },
  628. },
  629. '2.7': {
  630. funcNum: '2.7', funcName: '制造协同看板(KPI)', route: '制造协同 → 制造协同看板',
  631. role: '管理层',
  632. data: {
  633. overview: '制造协同看板为管理层提供S2模块核心KPI可视化监控,包括排程达成率、日计划执行率等指标。',
  634. steps: [
  635. '点击"制造协同看板"进入看板页面。',
  636. '查看L1核心KPI指标。',
  637. '可下钻查看L2分解指标详情。',
  638. '选择日期范围查看趋势变化。',
  639. ],
  640. screenshots: ['图2.7.1 制造协同看板'],
  641. ops: [
  642. ['1', '查看L1指标', '核心KPI卡片展示'],
  643. ['2', '指标下钻', '点击卡片查看详细指标'],
  644. ['3', '趋势分析', '查看指标趋势图表'],
  645. ],
  646. notes: ['KPI数据定时刷新,非实时。'],
  647. faq: [],
  648. },
  649. },
  650. },
  651. };
  652. // ═══════════════════════════════════════════════════
  653. // S3 供应协同 操作手册数据
  654. // ═══════════════════════════════════════════════════
  655. const S3_DATA = {
  656. moduleCode: 'S3',
  657. moduleName: '供应协同',
  658. overview: 'S3供应协同模块承接S2排程后的物料需求,实现从MRP物料需求计划到采购订单执行的供应协同闭环。',
  659. functions: {
  660. '2.1': {
  661. funcNum: '2.1', funcName: '物料需求计划(MRP)', route: '供应协同 → 物料需求计划',
  662. role: '计划员',
  663. data: {
  664. overview: '物料需求计划(MRP)基于排程结果和BOM展开,计算各物料的净需求数量和需求日期。',
  665. steps: [
  666. '点击"物料需求计划"进入需求列表页面。',
  667. '点击"MRP计算"按钮,系统基于排程结果和BOM自动展开计算。',
  668. '计算完成后列表显示各物料的净需求数量、需求日期。',
  669. '可根据需求结果,一键生成采购申请。',
  670. ],
  671. screenshots: ['图2.1.1 物料需求计划列表'],
  672. ops: [
  673. ['1', '触发MRP计算', '点击按钮启动物料需求展开'],
  674. ['2', '查看需求结果', '查看物料净需求和日期'],
  675. ['3', '生成采购申请', '一键将需求转为采购申请'],
  676. ],
  677. notes: ['MRP计算采用幂等生成,同一需求不会重复创建采购申请。'],
  678. faq: [['MRP计算结果为空?', '请确认排程已完成且BOM数据已维护。']],
  679. },
  680. },
  681. '2.2': {
  682. funcNum: '2.2', funcName: '物料交货计划', route: '供应协同 → 交货计划',
  683. role: '采购员/计划员',
  684. data: {
  685. overview: '物料交货计划用于制定供应商物料交货计划,跟踪交货执行状态,支持批量制定和状态跟踪。',
  686. steps: [
  687. '点击"交货计划"进入列表页面。',
  688. '点击"新建"制定交货计划:选择物料、分配供应商、填写交货日期和数量。',
  689. '支持"批量制定"功能,勾选多条需求后一键生成交货计划。',
  690. '列表显示交货状态,可实时跟踪供应商交货执行情况。',
  691. ],
  692. screenshots: ['图2.2.1 交货计划列表', '图2.2.2 批量制定交货计划'],
  693. ops: [
  694. ['1', '制定交货计划', '选择物料、供应商、交货日期'],
  695. ['2', '批量制定', '勾选多条需求批量生成'],
  696. ['3', '跟踪交货状态', '查看交货执行进度'],
  697. ],
  698. notes: ['交货计划与采购申请关联。'],
  699. faq: [],
  700. },
  701. },
  702. '2.3': {
  703. funcNum: '2.3', funcName: '交货单异常记录', route: '供应协同 → 交货异常',
  704. role: '采购员',
  705. data: {
  706. overview: '交货单异常记录用于记录和跟踪交货过程中的异常情况,如延迟交货、数量不符等。',
  707. steps: [
  708. '点击"交货异常"进入异常列表。',
  709. '按交货单号、供应商、异常类型筛选。',
  710. '查看异常详情和处理状态。',
  711. ],
  712. screenshots: ['图2.3.1 交货异常列表'],
  713. ops: [
  714. ['1', '查询异常记录', '按交货单号、供应商筛选'],
  715. ['2', '查看异常详情', '了解异常原因和处理进展'],
  716. ],
  717. notes: [],
  718. faq: [],
  719. },
  720. },
  721. '2.4': {
  722. funcNum: '2.4', funcName: '物料采购申请', route: '供应协同 → 采购申请',
  723. role: '计划员',
  724. data: {
  725. overview: '物料采购申请用于提交物料采购需求并走审批流程,审批通过后自动生成采购订单。',
  726. steps: [
  727. '点击"采购申请"进入列表页面。',
  728. '点击"新建"创建采购申请:选择需求物料、填写采购数量、需求日期。',
  729. '保存后点击"提交审批"。',
  730. '审批人审批通过后,系统自动生成采购订单。',
  731. ],
  732. screenshots: ['图2.4.1 采购申请列表', '图2.4.2 采购申请表单'],
  733. ops: [
  734. ['1', '新建采购申请', '选择物料、填写数量、需求日期'],
  735. ['2', '提交审批', '发起审批流程'],
  736. ['3', '查看审批状态', '跟踪审批进度'],
  737. ],
  738. notes: ['采购申请state状态:1=新建, 2=审批中, 5=已审批。', '系统防止重复生成采购申请。'],
  739. faq: [['采购申请状态一直为"审批中"?', '请确认审批流是否正常,可在审批中心查看待办。']],
  740. },
  741. },
  742. '2.5': {
  743. funcNum: '2.5', funcName: '要货令', route: '供应协同 → 要货令',
  744. role: '采购员',
  745. data: {
  746. overview: '要货令用于向供应商发出正式的要货指令,关联采购订单,驱动供应商按计划交货。',
  747. steps: [
  748. '点击"要货令"进入列表页面。',
  749. '点击"新建"创建要货令:选择关联的采购订单,系统自动填入物料信息。',
  750. '填写要货数量和交货日期。',
  751. '保存后要货令下达给供应商。',
  752. ],
  753. screenshots: ['图2.5.1 要货令列表', '图2.5.2 要货令表单'],
  754. ops: [
  755. ['1', '新建要货令', '关联采购订单,填写要货信息'],
  756. ['2', '选择采购订单', '下拉框远程搜索选择'],
  757. ['3', '下达供应商', '保存后要货指令生效'],
  758. ],
  759. notes: ['物料编码通过远程搜索选择。'],
  760. faq: [],
  761. },
  762. },
  763. '2.6': {
  764. funcNum: '2.6', funcName: '物料采购订单', route: '供应协同 → 采购订单',
  765. role: '采购员',
  766. data: {
  767. overview: '物料采购订单管理采购订单的全流程,从创建、下达供应商到执行跟踪。',
  768. steps: [
  769. '点击"采购订单"进入列表页面。',
  770. '采购申请审批通过后系统自动生成采购订单,也可手动新建。',
  771. '点击"下达"将采购订单下达给供应商。',
  772. '跟踪订单执行状态。',
  773. ],
  774. screenshots: ['图2.6.1 采购订单列表'],
  775. ops: [
  776. ['1', '查询采购订单', '按订单号、供应商、状态筛选'],
  777. ['2', '新建采购订单', '手动创建或由采购申请自动生成'],
  778. ['3', '下达供应商', '将订单发送给供应商'],
  779. ['4', '跟踪执行状态', '查看订单执行进度'],
  780. ],
  781. notes: ['采购订单与采购申请关联。'],
  782. faq: [],
  783. },
  784. },
  785. '2.7': {
  786. funcNum: '2.7', funcName: '委外加工订单', route: '供应协同 → 委外加工',
  787. role: '采购员',
  788. data: {
  789. overview: '委外加工订单用于管理委外加工业务的订单创建、执行与跟踪。',
  790. steps: [
  791. '点击"委外加工"进入订单列表。',
  792. '点击"新建"创建委外订单:选择供应商、物料编码。',
  793. '在明细子表中管理委外加工明细行。',
  794. '保存后跟踪委外执行状态。',
  795. ],
  796. screenshots: ['图2.7.1 委外加工订单列表', '图2.7.2 委外加工订单表单'],
  797. ops: [
  798. ['1', '新建委外订单', '选择供应商和物料'],
  799. ['2', '管理明细行', '在子表中增删委外明细'],
  800. ['3', '跟踪执行状态', '查看委外加工进度'],
  801. ],
  802. notes: ['委外订单与采购申请关联。'],
  803. faq: [],
  804. },
  805. },
  806. '2.8': {
  807. funcNum: '2.8', funcName: '工单物料齐套看板', route: '供应协同 → 齐套看板',
  808. role: '调度/计划员',
  809. data: {
  810. overview: '工单物料齐套看板实时监控各工单的物料准备状态,识别缺料风险,驱动紧急采购。',
  811. steps: [
  812. '点击"齐套看板"进入看板页面。',
  813. '按工单查看物料齐套状态:绿色=齐套,红色=缺料。',
  814. '点击缺料工单查看具体缺料物料清单。',
  815. '可根据缺料情况触发紧急采购流程。',
  816. ],
  817. screenshots: ['图2.8.1 工单物料齐套看板'],
  818. ops: [
  819. ['1', '查看齐套状态', '绿色/红色直观显示齐套情况'],
  820. ['2', '识别缺料物料', '点击查看缺料明细'],
  821. ['3', '触发紧急采购', '基于缺料发起采购流程'],
  822. ],
  823. notes: ['缺料数量=需求-库存-在途。'],
  824. faq: [],
  825. },
  826. },
  827. },
  828. };
  829. // ═══════════════════════════════════════════════════
  830. // S4 采购执行 操作手册数据
  831. // ═══════════════════════════════════════════════════
  832. const S4_DATA = {
  833. moduleCode: 'S4',
  834. moduleName: '采购执行',
  835. overview: 'S4采购执行模块承接S3采购订单后的执行跟踪与交付管理,实现从供应商交货、发货单管理到采购退货的采购执行闭环。',
  836. functions: {
  837. '2.1': {
  838. funcNum: '2.1', funcName: '供应商交货管理', route: '采购执行 → 交货管理',
  839. role: '采购员/仓管',
  840. data: {
  841. overview: '供应商交货管理用于跟踪供应商交货计划的执行状态,管理交货全过程。',
  842. steps: [
  843. '点击"交货管理"进入列表页面。',
  844. '通过供应商、物料编码、交货日期等条件筛选。',
  845. '列表按ShipDate(发货日期)排序,显示交货状态。',
  846. '支持导出交货数据。',
  847. ],
  848. screenshots: ['图2.1.1 供应商交货管理列表'],
  849. ops: [
  850. ['1', '查询交货列表', '按供应商、物料、日期筛选'],
  851. ['2', '查看交货状态', '跟踪交货执行情况'],
  852. ['3', '导出数据', '将交货数据导出为Excel'],
  853. ],
  854. notes: ['数据来源采购订单和交货计划。'],
  855. faq: [],
  856. },
  857. },
  858. '2.2': {
  859. funcNum: '2.2', funcName: '供应商发货单', route: '采购执行 → 发货单管理',
  860. role: '采购员/仓管',
  861. data: {
  862. overview: '供应商发货单用于管理供应商发货单的创建、编辑、附件上传和状态跟踪。',
  863. steps: [
  864. '点击"发货单管理"进入列表页面。',
  865. '点击"新建"创建发货单:选择供应商、物料编码、填写发货数量。',
  866. '支持上传附件(如发货清单、质检报告等)。',
  867. '保存后跟踪发货状态。',
  868. '如需取消,点击"取消"按钮,系统自动清理相关标签页。',
  869. ],
  870. screenshots: ['图2.2.1 发货单列表', '图2.2.2 发货单编辑表单'],
  871. ops: [
  872. ['1', '新建发货单', '选择供应商、物料、填写数量'],
  873. ['2', '上传附件', '上传发货相关文件'],
  874. ['3', '保存发货单', '保存后状态可跟踪'],
  875. ['4', '取消发货单', '取消操作自动清理标签页'],
  876. ],
  877. notes: ['取消操作会清理相关标签页。', '附件大小限制请参考系统配置。'],
  878. faq: [['如何取消已保存的发货单?', '在操作列点击"取消"按钮即可。']],
  879. },
  880. },
  881. '2.3': {
  882. funcNum: '2.3', funcName: '采购退货单', route: '采购执行 → 退货管理',
  883. role: '采购员/仓管',
  884. data: {
  885. overview: '采购退货单用于管理采购退货的创建、审批与执行,需关联收货单进行退货操作。',
  886. steps: [
  887. '点击"退货管理"进入退货单列表。',
  888. '点击"新建"创建退货单:选择关联的收货单(系统自动加载收货单明细)。',
  889. '选择需要退货的物料,填写退货数量和退货原因。',
  890. '保存后提交审批。',
  891. '审批通过后执行退货出库。',
  892. ],
  893. screenshots: ['图2.3.1 退货单列表', '图2.3.2 退货单编辑表单'],
  894. ops: [
  895. ['1', '新建退货单', '选择收货单,填写退货信息'],
  896. ['2', '选择收货单', '系统自动加载收货明细'],
  897. ['3', '提交审批', '提交退货审批流'],
  898. ['4', '执行退货', '审批通过后执行退货'],
  899. ],
  900. notes: ['退货单需关联收货单。', '筛选条件已放宽,确保能找到所有可退货的收货单。', '退货单号(RecID)自动生成。'],
  901. faq: [['找不到要退货的收货单?', '请确认收货单已生成且未被全部退货。系统已放宽筛选条件。']],
  902. },
  903. },
  904. '2.4': {
  905. funcNum: '2.4', funcName: 'IQC退货查询', route: '采购执行 → IQC退货查询',
  906. role: '质量/仓管',
  907. data: {
  908. overview: 'IQC退货查询用于查询来料检验(IQC)判退的退货结果,支持按照物料、供应商、日期等多维度筛选和导出。',
  909. steps: [
  910. '点击"IQC退货查询"进入查询列表。',
  911. '通过物料编码、供应商、检验日期等条件筛选。',
  912. '查看退货详情:检验结果、退货数量、不合格原因。',
  913. '支持导出退货查询结果为Excel。',
  914. ],
  915. screenshots: ['图2.4.1 IQC退货查询列表'],
  916. ops: [
  917. ['1', '查询退货记录', '按物料、供应商、日期筛选'],
  918. ['2', '查看退货详情', '查看不合格原因和退货数量'],
  919. ['3', '导出数据', '导出退货查询结果'],
  920. ],
  921. notes: ['数据来源于IQC检验结果。'],
  922. faq: [],
  923. },
  924. },
  925. '2.5': {
  926. funcNum: '2.5', funcName: '供应商欠料看板', route: '采购执行 → 欠料看板',
  927. role: '采购员/管理层',
  928. data: {
  929. overview: '供应商欠料看板实时监控供应商的欠料状态,识别供应风险,支持按供应商维度筛选分析。',
  930. steps: [
  931. '点击"欠料看板"进入看板页面。',
  932. '查看各供应商的欠料状态(订单量 vs 已交货量)。',
  933. '通过供应商下拉框筛选特定供应商。',
  934. '识别风险物料,及时触发催货。',
  935. ],
  936. screenshots: ['图2.5.1 供应商欠料看板'],
  937. ops: [
  938. ['1', '查看欠料状态', '实时显示供应商欠料情况'],
  939. ['2', '按供应商筛选', '下拉选择特定供应商'],
  940. ['3', '识别风险物料', '定位欠料严重的物料'],
  941. ['4', '触发催货', '基于欠料信息发起催货流程'],
  942. ],
  943. notes: ['欠料=订单量-已交货量,实时计算。'],
  944. faq: [],
  945. },
  946. },
  947. '2.6': {
  948. funcNum: '2.6', funcName: '采购执行看板(KPI)', route: '采购执行 → 采购执行看板',
  949. role: '管理层',
  950. data: {
  951. overview: '采购执行看板为管理层提供S4模块核心KPI可视化监控,包括交货及时率、退货率、欠料率等指标。',
  952. steps: [
  953. '点击"采购执行看板"进入看板页面。',
  954. '查看L1核心KPI指标卡片。',
  955. '可下钻查看L2分解指标详情。',
  956. '选择日期范围查看趋势图表。',
  957. ],
  958. screenshots: ['图2.6.1 采购执行看板'],
  959. ops: [
  960. ['1', '查看L1指标', '核心KPI卡片展示'],
  961. ['2', '指标下钻', '点击卡片查看详细指标'],
  962. ['3', '趋势分析', '查看指标趋势图表'],
  963. ],
  964. notes: ['KPI数据定时刷新。'],
  965. faq: [],
  966. },
  967. },
  968. },
  969. };
  970. // ═══════════════════════════════════════════════════
  971. // 完整文档构建
  972. // ═══════════════════════════════════════════════════
  973. function buildDocument(modData) {
  974. const sections = [];
  975. // 封面
  976. sections.push(...buildCover(modData.moduleCode, modData.moduleName));
  977. // 目录
  978. sections.push(pageBreak());
  979. sections.push(h1('目录'));
  980. sections.push(...buildTOC());
  981. sections.push(pageBreak());
  982. // 第1章:系统登录与首页
  983. sections.push(...buildLoginSection());
  984. sections.push(pageBreak());
  985. // 第2章:模块操作说明
  986. sections.push(h1('2. 模块操作说明'));
  987. sections.push(p(modData.overview));
  988. const funcKeys = Object.keys(modData.functions);
  989. funcKeys.forEach((key, idx) => {
  990. const func = modData.functions[key];
  991. sections.push(pageBreak());
  992. sections.push(h2(`${func.funcNum} ${func.funcName}`));
  993. sections.push(...buildFuncGuide(func.funcNum, func.funcName, func.route, func.role, func.data));
  994. });
  995. return sections;
  996. }
  997. async function generateDoc(modData) {
  998. const doc = new Document({
  999. styles: {
  1000. default: {
  1001. document: { run: { font: FONT_BODY, size: 21 } },
  1002. heading1: { run: { font: FONT, size: 32, bold: true, color: BLUE } },
  1003. heading2: { run: { font: FONT, size: 28, bold: true, color: '2E75B6' } },
  1004. heading3: { run: { font: FONT, size: 24, bold: true } },
  1005. },
  1006. },
  1007. sections: [{
  1008. properties: {
  1009. page: {
  1010. margin: {
  1011. top: convertInchesToTwip(0.8),
  1012. bottom: convertInchesToTwip(0.8),
  1013. left: convertInchesToTwip(1.2),
  1014. right: convertInchesToTwip(1.0),
  1015. },
  1016. },
  1017. },
  1018. children: buildDocument(modData),
  1019. }],
  1020. });
  1021. const buffer = await Packer.toBuffer(doc);
  1022. const fileName = `【${modData.moduleCode}${modData.moduleName}模块用户操作手册】DOP生产管理用户操作手册.docx`;
  1023. const outPath = path.join('d:\\DEMONET\\doc', fileName);
  1024. fs.writeFileSync(outPath, buffer);
  1025. console.log(`Generated: ${fileName} (${(buffer.length / 1024).toFixed(1)} KB)`);
  1026. return outPath;
  1027. }
  1028. // ═══════════════════════════════════════════════════
  1029. // 主入口
  1030. // ═══════════════════════════════════════════════════
  1031. async function main() {
  1032. console.log('=== 开始生成 S1-S4 用户操作手册 ===\n');
  1033. const modules = [S1_DATA, S2_DATA, S3_DATA, S4_DATA];
  1034. for (const mod of modules) {
  1035. console.log(`生成 ${mod.moduleCode} ${mod.moduleName}...`);
  1036. await generateDoc(mod);
  1037. }
  1038. console.log('\n=== 全部生成完成 ===');
  1039. console.log('输出目录: d:\\DEMONET\\doc\\');
  1040. }
  1041. main().catch(err => { console.error('Error:', err); process.exit(1); });