| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136 |
- /**
- * Generate S1 产销协同模块蓝图设计方案.docx
- * 严格按照原文档模板格式:每个功能章节含 8 个子章节
- * [目标/宗旨, 业务流程图, 业务流程说明, 业务流程规则, 变化和改进点, 权限管理需求, 系统接口集成, 报表需求]
- */
- 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,
- InternalHyperlink, TableOfContents
- } = require('docx');
- // ═══════════════════════════════════════════════════
- // 通用样式与辅助函数
- // ═══════════════════════════════════════════════════
- 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 },
- });
- }
- // ── 活动流程表(5列) ──
- 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]);
- }
- // ── 目录条目(模板格式:编号 + Tab + 标题 + Tab + 页码占位) ──
- // Template uses: TOC2 tab at 2880 twip, TOC3 tab at 3600 twip, left-align tab
- const TOC2_TAB = 2880; // ~2 inches for chapter entries
- const TOC3_TAB = 3600; // ~2.5 inches for sub-section entries
- const TOC_FONT_SIZE = 20; // 10pt, matching template
- function tocChapter(num, title) {
- // TOC2 style: "1" + TAB(at 2880) + "总体业务方案" + TAB + page placeholder
- 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) {
- // TOC3 style: "1.1" + TAB(at 3600) + "目标和宗旨" + TAB + page placeholder
- 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 = [];
- // TOC field code (user updates in Word to auto-generate with page numbers)
- 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~10章(8子章节) ──
- const chSubs = [
- '目标/宗旨', '业务流程图', '业务流程说明', '业务流程规则',
- '变化和改进点', '权限管理需求', '系统接口集成', '报表需求',
- ];
- const chTitles = [
- '产品设计管理', '订单评审管理', '订单交付管理', '订单发货管理',
- '合同评审管理', '计划联动', '需求明细核验', '工单下达', '产销协同看板与KPI',
- ];
- 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]));
- }
- }
- // ── 第11章 ──
- ch.push(tocChapter('11', '数据中台架构'));
- ['目标/宗旨', '分层设计', 'S1核心数据流', '对象映射总表', 'MDP作业调度'].forEach((title, i) => {
- ch.push(tocSub(`11.${i + 1}`, title));
- });
- // ── 第12章 ──
- ch.push(tocChapter('12', '权限管理汇总'));
- return ch;
- }
- // ═══════════════════════════════════════════════════
- // 流程图生成:根据步骤数组生成 SVG → sharp 转 PNG
- // ═══════════════════════════════════════════════════
- const FLOW_W = 680, BOX_W = 220, BOX_H = 42, GAP_Y = 28;
- const ROLE_X = 30, BOX_X = 130, MARGIN_Y = 40;
- // 流程图 PNG 缓存:key = 章节号,value = Buffer
- 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) {
- // steps: [{label: '活动名称', role: '执行角色'}, ...] — 纯纵向流程
- 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 xmlns="http://www.w3.org/2000/svg" width="${FLOW_W}" height="${svgH}">`;
- svg += `<rect width="100%" height="100%" fill="#FAFBFC"/>`;
- steps.forEach((s, i) => {
- const y = MARGIN_Y + i * (BOX_H + GAP_Y);
- // 角色标签
- svg += `<text x="${ROLE_X}" y="${y + BOX_H / 2 + 5}" font-family="Microsoft YaHei" font-size="12" fill="#666" text-anchor="start">${s.role || ''}</text>`;
- // 节点框
- 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 += `<rect x="${BOX_X}" y="${y}" width="${BOX_W}" height="${BOX_H}" rx="6" fill="${fill}" stroke="${stroke}" stroke-width="1.5"/>`;
- svg += `<text x="${centerX}" y="${y + BOX_H / 2 + 5}" font-family="Microsoft YaHei" font-size="13" fill="${textColor}" text-anchor="middle">${s.label}</text>`;
- // 箭头
- if (i < N - 1) {
- const ay = y + BOX_H + 4, by2 = ay + GAP_Y - 8;
- svg += `<line x1="${centerX}" y1="${ay}" x2="${centerX}" y2="${by2}" stroke="#888" stroke-width="1.5"/>`;
- svg += `<polygon points="${centerX - 5},${by2 - 10} ${centerX + 5},${by2 - 10} ${centerX},${by2}" fill="#888"/>`;
- }
- });
- svg += '</svg>';
- return sharp(Buffer.from(svg)).png().toBuffer();
- }
- // 第1章专用:三层复合流程图(主线+支撑+数据流)
- async function generateOverviewFlowPNG() {
- const W = 780, H = 620;
- let svg = `<svg xmlns="http://www.w3.org/2000/svg" width="${W}" height="${H}">`;
- svg += `<rect width="100%" height="100%" fill="#FAFBFC"/>`;
- // ── 标题栏 ──
- svg += `<text x="${W/2}" y="28" font-family="Microsoft YaHei" font-size="15" font-weight="bold" fill="#1F4E79" text-anchor="middle">S1 产销协同 — 总体业务流程</text>`;
- // ── 区域背景 ──
- const zones = [
- { y: 42, h: 200, color: '#E8F0FE', label: '主线流程(订单履约链)', lx: 10, ly: 60 },
- { y: 250, h: 120, color: '#FFF3E0', label: '支撑流程', lx: 10, ly: 268 },
- { y: 378, h: 90, color: '#E8F5E9', label: '数据中台链路', lx: 10, ly: 396 },
- ];
- zones.forEach(z => {
- svg += `<rect x="8" y="${z.y}" width="${W-16}" height="${z.h}" rx="6" fill="${z.color}" stroke="#ccc" stroke-width="0.5" stroke-dasharray="4,3"/>`;
- svg += `<text x="${z.lx}" y="${z.ly}" font-family="Microsoft YaHei" font-size="12" font-weight="bold" fill="#555">${z.label}</text>`;
- });
- // ── 主线流程节点 ──
- const mainNodes = [
- { x: 30, y: 85, w: 130, h: 38, label: '销售订单接收', color: '#1565C0' },
- { x: 190, y: 85, w: 130, h: 38, label: '订单评审\n(交期评估)', color: '#1565C0' },
- { x: 350, y: 85, w: 110, h: 38, label: '工单下达', color: '#1565C0' },
- { x: 485, y: 85, w: 110, h: 38, label: '排产执行', color: '#6C757D' },
- { x: 620, y: 85, w: 110, h: 38, label: '采购备料', color: '#6C757D' },
- { x: 485, y: 155, w: 110, h: 38, label: '生产制造', color: '#6C757D' },
- { x: 620, y: 155, w: 110, h: 38, label: '成品入库', color: '#2E7D32' },
- { x: 350, y: 170, w: 100, h: 38, label: '交期确认', color: '#1565C0' },
- { x: 215, y: 170, w: 100, h: 38, label: '变更管理', color: '#F57C00' },
- ];
- // 子流程节点 (smaller, secondary)
- const subNodes = [
- { x: 30, y: 170, w: 145, h: 38, label: '发货计划/ASN发货', color: '#2E7D32' },
- { x: 190, y: 170, w: 24, h: 0, label: '', color: '' }, // dummy
- ];
- [...mainNodes, subNodes[0]].filter(n => n.h > 0).forEach(n => {
- const fill = n.color === '#6C757D' ? '#E0E0E0' : n.color;
- const stroke = n.color === '#6C757D' ? '#999' : n.color;
- const tc = n.color === '#6C757D' ? '#555' : '#fff';
- svg += `<rect x="${n.x}" y="${n.y}" width="${n.w}" height="${n.h}" rx="5" fill="${fill}" stroke="${stroke}" stroke-width="1.2"/>`;
- 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 += `<text x="${n.x + n.w/2}" y="${cy + off + 4}" font-family="Microsoft YaHei" font-size="11" fill="${tc}" text-anchor="middle">${l}</text>`;
- });
- });
- // 主线箭头 (simplified)
- const arrows = [
- { x1: 160, y1: 104, x2: 190, y2: 104 }, // 接收→评审
- { x1: 320, y1: 104, x2: 350, y2: 104 }, // 评审→工单
- { x1: 460, y1: 104, x2: 485, y2: 104 }, // 工单→排程
- { x1: 595, y1: 104, x2: 620, y2: 104 }, // 排程→采购
- { x1: 595, y1: 123, x2: 540, y2: 155 }, // 采购→生产 (down-left)
- { x1: 540, y1: 193, x2: 460, y2: 185 }, // 生产→入库 (left)
- { x1: 350, y1: 123, x2: 350, y2: 170 }, // 工单→交期确认 (down)
- ];
- arrows.forEach(a => {
- svg += `<line x1="${a.x1}" y1="${a.y1}" x2="${a.x2}" y2="${a.y2}" stroke="#666" stroke-width="1.2"/>`;
- const ang = Math.atan2(a.y2 - a.y1, a.x2 - a.x1);
- const lx = a.x2 - 6 * Math.cos(ang), ly = a.y2 - 6 * Math.sin(ang);
- svg += `<polygon points="${lx + 4 * Math.sin(ang)},${ly - 4 * Math.cos(ang)} ${lx - 4 * Math.sin(ang)},${ly + 4 * Math.cos(ang)} ${lx + 6 * Math.cos(ang)},${ly + 6 * Math.sin(ang)}" fill="#666"/>`;
- });
- // 灰色标记:虚线边框表示"跨模块就绪,待其他模块补齐"
- svg += `<text x="530" y="108" font-family="Microsoft YaHei" font-size="9" fill="#999" text-anchor="middle">(S2/S4/S5/S6/S7)</text>`;
- // ── 支撑流程节点 ──
- const suppNodes = [
- { x: 40, y: 295, w: 160, h: 36, label: '产品设计管理', color: '#E65100' },
- { x: 250, y: 295, w: 160, h: 36, label: '合同评审管理', color: '#E65100' },
- { x: 460, y: 295, w: 160, h: 36, label: '需求明细核验', color: '#E65100' },
- ];
- suppNodes.forEach(n => {
- svg += `<rect x="${n.x}" y="${n.y}" width="${n.w}" height="${n.h}" rx="5" fill="${n.color}" stroke="${n.color}" stroke-width="1.2"/>`;
- svg += `<text x="${n.x + n.w/2}" y="${n.y + n.h/2 + 4}" font-family="Microsoft YaHei" font-size="11" fill="#fff" text-anchor="middle">${n.label}</text>`;
- });
- // 支撑箭头
- svg += `<line x1="200" y1="313" x2="250" y2="313" stroke="#666" stroke-width="1.2"/>`;
- svg += `<polygon points="246,308 246,318 253,313" fill="#666"/>`;
- svg += `<line x1="410" y1="313" x2="460" y2="313" stroke="#666" stroke-width="1.2"/>`;
- svg += `<polygon points="456,308 456,318 463,313" fill="#666"/>`;
- // ── 数据流节点 ──
- const dataNodes = [
- { x: 40, y: 418, w: 140, h: 36, label: '业务运行表', color: '#2E7D32' },
- { x: 210, y: 418, w: 120, h: 36, label: 'mdp_stg_*', color: '#6A1B9A' },
- { x: 360, y: 418, w: 120, h: 36, label: 'mdp_std_*', color: '#6A1B9A' },
- { x: 510, y: 418, w: 120, h: 36, label: 'dwd_* (宽表)', color: '#0D47A1' },
- { x: 660, y: 418, w: 100, h: 36, label: 'KPI 指标层', color: '#B71C1C' },
- ];
- dataNodes.forEach(n => {
- svg += `<rect x="${n.x}" y="${n.y}" width="${n.w}" height="${n.h}" rx="5" fill="${n.color}" stroke="${n.color}" stroke-width="1.2"/>`;
- svg += `<text x="${n.x + n.w/2}" y="${n.y + n.h/2 + 4}" font-family="Microsoft YaHei" font-size="10" fill="#fff" text-anchor="middle">${n.label}</text>`;
- });
- // 数据箭头
- for (let i = 0; i < dataNodes.length - 1; i++) {
- const a = dataNodes[i], b = dataNodes[i + 1];
- const ax = a.x + a.w, ay = a.y + a.h / 2;
- const bx = b.x;
- svg += `<line x1="${ax}" y1="${ay}" x2="${bx}" y2="${ay}" stroke="#666" stroke-width="1.2"/>`;
- svg += `<polygon points="${bx - 6},${ay - 4} ${bx - 6},${ay + 4} ${bx},${ay}" fill="#666"/>`;
- }
- // ── 层级标注 ──
- svg += `<text x="45" y="475" font-family="Microsoft YaHei" font-size="10" fill="#555">STG(贴源)</text>`;
- svg += `<text x="215" y="475" font-family="Microsoft YaHei" font-size="10" fill="#555">STD(标准)</text>`;
- svg += `<text x="365" y="475" font-family="Microsoft YaHei" font-size="10" fill="#555">DWD(宽表)</text>`;
- svg += `<text x="515" y="475" font-family="Microsoft YaHei" font-size="10" fill="#555">KPI(指标)</text>`;
- // ── 串联标注(支撑→主线) ──
- svg += `<text x="150" y="240" font-family="Microsoft YaHei" font-size="10" fill="#888" text-anchor="middle">↓ 为订单评审提供设计/合同/物料约束 ↓</text>`;
- svg += '</svg>';
- return sharp(Buffer.from(svg)).png().toBuffer();
- }
- // ═══════════════════════════════════════════════════
- // 章节构建函数:自动生成 8 子章节
- // ═══════════════════════════════════════════════════
- // cfg.flowSteps: [{label, role}] → 自动生成纵向流程图
- // cfg.flowImage: Buffer → 直接嵌入(优先于 flowSteps)
- 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('参照第 12 章 权限管理汇总'));
- }
- // ── §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: [
- '实现产品设计任务的在线管理,涵盖产品设计BOM和工艺路线的录入与维护。',
- '将产品设计任务纳入 KPI 考核体系,监控设计周期、满足率和人效指标。',
- '产品设计采用直接保存模式,无审批流环节,保存即生效。',
- ],
- flowNote: '流程路径:产品设计新建 → BOM子表录入 → 工艺子表录入 → 保存 → 设计记录生效。',
- flowSteps: [
- { label: '新建产品设计任务', role: '设计员' },
- { label: 'BOM子表录入', role: '设计员' },
- { label: '工艺子表录入', role: '设计员' },
- { label: '保存生效', role: '设计员' },
- ],
- activities: [
- ['10', '新建产品设计任务', '设计员', '录入产品设计基本信息,选择成品物料编码,填写设计要求', '产品需求', '产品设计任务'],
- ['20', 'BOM子表录入', '设计员', '在BOM子表中新增行,选择子物料编码,填写单位用量和损耗率', '物料主数据', 'BOM清单'],
- ['30', '工艺子表录入', '设计员', '在工艺子表中新增行,通过下拉框选择产线,手动输入路线编码', '产线数据', '工艺路线'],
- ['40', '保存', '设计员', '填写完整信息后点击保存,单据编号自动生成,数据即时生效', '产品设计任务', '已保存记录'],
- ],
- rules: [
- ['1', 'BOM子表物料选择', '选择子物料编码后系统自动填入物料名称;父级物料关系通过任务主表关联;单位用量和固定损耗支持手动编辑'],
- ['2', '工艺子表产线选择', '产线列显示下拉框,从LineMaster表远程搜索选择,显示格式为「Line|Describe」;路线编码支持手动输入'],
- ['3', '保存/编辑/删除', '保存后列表显示新记录、单据编号自动生成;编辑后字段正确更新;删除后记录移除且关联BOM/工艺子表数据同步删除'],
- ['4', '必填字段校验', '物料编码、任务名称、计划完成日期为必填项;BOM子表至少保留一行;前后端双重校验'],
- ['5', '无审批流', '产品设计采用直接保存模式,保存即生效,无需经过审批流程;无审批状态列'],
- ],
- improvements: [
- '产品设计任务实现在线化闭环管理,替代线下Excel跟踪方式。',
- 'BOM和工艺信息直接录入系统,避免数据孤岛。',
- '设计周期、满足率和人效纳入KPI自动化考核。',
- '采用直接保存模式,简化操作流程,提升设计效率。',
- ],
- permissions: [
- ['1', '设计员', '新建/编辑/删除产品设计任务;录入BOM和工艺子表;保存操作'],
- ['2', '计划工程师', '查看产品设计列表和KPI指标'],
- ],
- interfaces: [
- ['1', '物料主数据同步', '通过MDP从SAP定时同步物料主数据,供产品设计选择使用', '定时(日)'],
- ['2', '产线主数据查询', '工艺子表通过API实时查询LineMaster表获取产线列表', '实时(下拉触发)'],
- ],
- reports: [
- ['1', '产品设计周期分析', '统计各设计任务的计划周期与实际完成周期差异', '按任务/按月度'],
- ['2', '产品设计满足率', '统计按时完成的设计任务占比', '按月度/按人员'],
- ],
- };
- const ch2 = () => buildChapter('2', '产品设计管理', _ch2cfg);
- // ── Chapter 3: 订单评审管理 ──
- const _ch3cfg = {
- targets: [
- '实现销售订单的在线录入、查询、编辑和删除操作。',
- '对无法被成品库存直接满足的订单进行交期评审,给出预计交付日期。',
- '支持订单变更管理,变更记录可追溯,变更时通过审批流管控。',
- '订单主流程无审批流:录入→评审→确认直接完成;仅变更场景触发审批。',
- ],
- flowNote: '流程路径:订单信息录入 → 订单评审(交期评估) → 交期确认 → 如需变更则发起变更审批流。',
- flowSteps: [
- { label: '订单信息录入', role: '销售/计划员' },
- { label: '订单评审(交期评估)', role: '计划员' },
- { label: '交期确认 / 资源锁定', role: '计划员' },
- { label: '变更审批(如需要)', role: '审批人' },
- ],
- activities: [
- ['10', '订单列表查询', '销售/计划员', '通过订单号、客户、日期范围等条件筛选查询订单', '查询条件', '订单列表'],
- ['20', '订单新增保存', '销售/计划员', '录入销售订单基本信息(客户、物料、数量、交期等)', '销售需求', '待评审订单'],
- ['30', '订单评审/交期评估', '计划员', '系统根据成品库存、在制工单、物料齐套约束给出预计交期', '订单信息', '建议交期'],
- ['40', '交期确认', '计划员', '确认交期结果,锁定产能和物料资源', '建议交期', '已确认订单'],
- ['50', '订单变更(审批流)', '销售/计划员→审批人', '交期确认后如需修改订单,发起变更申请,走审批流;变更记录自动归档并累加次数', '变更需求', '变更记录/审批流'],
- ],
- rules: [
- ['1', '订单编号', '订单编号全局唯一,保存时自动生成'],
- ['2', '订单主流程无审批', '订单从录入到评审到交期确认,无需经过审批流;保存和确认操作直接生效'],
- ['3', '变更审批流', '交期确认后如需修改订单,必须发起变更申请并通过审批流;变更记录可追溯,变更次数+1'],
- ['4', '变更历史可查', '变更历史记录在订单交付Tab2(评审信息)中查看'],
- ['5', '订单类型', '订单类型分为「销售订单」和「计划订单」,系统按类型区别处理'],
- ['6', '交期确认', '调用外部交期确认接口返回OK表示确认成功;确认后订单状态更新为已确认'],
- ['7', 'closed字段', '订单closed字段默认值为0(未关闭),订单关闭时更新为1'],
- ],
- improvements: [
- '订单管理实现在线化,替代线下Excel和纸质单据管理方式。',
- '变更记录自动归档,每次变更次数累计,支持历史追踪,审批流仅在变更时触发。',
- '交期评估系统化,替代人工估算方式。',
- '主流程简化(无审批),仅变更场景走审批流,降低操作复杂度。',
- ],
- permissions: [
- ['1', '销售/客服专员', '查看订单列表;新建/编辑/删除订单;发起变更申请'],
- ['2', '计划工程师', '查看订单列表;执行订单评审和交期确认操作'],
- ['3', '审批人', '审核订单变更申请(仅变更场景触发)'],
- ],
- interfaces: [
- ['1', '销售订单同步', '通过MDP从SAP定时同步销售订单到中台贴源层mdp_stg_so', '定时(日)'],
- ['2', '交期确认接口', '调用外部交期确认接口(不含Authorization头),返回OK表示成功', '手动触发'],
- ['3', '订单列表API', 'GET /api/Order/list 读取mdp_std_so标准层数据', '实时(页面加载)'],
- ],
- reports: [
- ['1', '订单评审周期分析', '统计从订单录入到交期确认的各环节耗时', '按月度/按客户'],
- ['2', '订单变更频率分析', '统计订单变更次数和变更原因分布', '按月度/按产品线'],
- ],
- };
- const ch3 = () => buildChapter('3', '订单评审管理', _ch3cfg);
- // ── Chapter 4: 订单交付管理 ──
- const _ch4cfg = {
- targets: [
- '以订单行(明细)为粒度,集中展示每笔订单的交付状态。',
- '通过8个Tab页签实现从"订单接收"到"成品发运"的全链路履约追踪。',
- '接入数据中台宽表层dwd_ship_trans,实现交付数据的统一口径。',
- ],
- flowNote: '流程路径:订单交付列表 → 多条件筛选 → 点击订单行 → 8Tab全景追踪(订单信息→评审→排程→物料需求→采购→备料→生产→入库发运)。',
- flowSteps: [
- { label: '交付列表筛选查询', role: '计划员/物流' },
- { label: '点击订单行进入详情', role: '计划员/物流' },
- { label: 'Tab1 查看订单信息', role: '计划员/物流' },
- { label: 'Tab2 查看评审/变更', role: '计划员/物流' },
- { label: 'Tab4 查看物料需求', role: '计划员/物流' },
- { label: 'Tab8 入库发运追踪', role: '计划员/物流' },
- ],
- activities: [
- ['10', '交付列表查询', '计划员/物流', '通过订单号、客户、交付状态、日期范围等条件筛选', '筛选条件', '交付列表数据'],
- ['20', '进入交付详情', '计划员/物流', '点击交付列表中的订单行,进入8Tab全景追踪页面', '订单行ID', '交付详情'],
- ['30', '查看订单信息(Tab1)', '计划员/物流', '查看订单基础档案信息(订单编号、客户、状态、审核人等)', 'mdp_std_so', '订单档案'],
- ['40', '查看评审信息(Tab2)', '计划员/物流', '查看交期评估结果和订单变更历史记录', 'dwd_requirement_examine_detail', '评审详情'],
- ['50', '查看物料需求(Tab4)', '计划员/物流', '查看BOM展开、库存占用、缺料分析和替代料信息', 'dwd_requirement_examine_detail', '物料需求明细'],
- ],
- rules: [
- ['1', '交付列表数据来源', '读取dwd_ship_trans宽表,只取最新成功批次(sync_batch_id=max);确保数据口径一致'],
- ['2', '交付列表字段', '客户编码、订单号、工单编号、物料编码、物料名称、规格型号、数量、客户单号、计划交付日期、实际交付日期、交付状态'],
- ['3', '交付状态流转', '待评审→已评审→排产中→采购中→生产中→已入库→已发运'],
- ['4', '8Tab数据来源', 'Tab1读mdp_std_so;Tab2读dwd_requirement_examine_detail+mdp_stg_so变更;Tab4读dwd_requirement_examine_detail;Tab8发运读mdp_std_ship_trans'],
- ['5', '跨模块Tab渐进就绪', 'Tab3排程待S2补齐;Tab5采购待S4补齐;Tab6备料待S6/WMS补齐;Tab7报工IQC待S5/S6补齐;Tab8 FQC入库待S7补齐'],
- ],
- improvements: [
- '交付状态一屏展示,替代多地分散查询的方式。',
- '8Tab全景追踪实现"一单到底",从订单到发运全链路可视化。',
- '接入数据中台宽表,确保各页面读取的数据口径一致。',
- '跨模块Tab结构已就绪,后续模块补齐后自动填充数据。',
- ],
- permissions: [
- ['1', '计划工程师', '查看交付列表和详情;筛选和排序操作'],
- ['2', '物流/仓管', '查看交付列表;查看发运相关Tab'],
- ['3', '销售/客服', '查看交付列表;跟踪订单交付状态'],
- ],
- interfaces: [
- ['1', '订单交付列表API', 'GET /api/Order/delivery/list 读取dwd_ship_trans', '实时(页面加载)'],
- ['2', '订单交付详情API', 'GET /api/Order/delivery/flow?entryId= 聚合多表数据', '实时(点击触发)'],
- ['3', '需求核验API', 'GET /api/RequirementExamineDetail/list 读取dwd_requirement_examine_detail', '实时'],
- ],
- reports: [
- ['1', '订单交付状态统计', '按交付状态汇总订单数量,分析履约瓶颈', '按日/周/月'],
- ['2', '订单交付周期分析', '统计从订单确认到实际交付的各阶段耗时', '按订单/按客户'],
- ],
- };
- const ch4 = () => buildChapter('4', '订单交付管理', _ch4cfg);
- // ── Chapter 5: 订单发货管理 ──
- const _ch5cfg = {
- targets: [
- '实现发货单的在线录入、查询、编辑和删除管理。',
- '通过销售单号关联,将发货单与销售订单联动。',
- '实现发货计划覆盖追踪和ASN发货记录管理。',
- '将发货数据纳入KPI考核(发货计划覆盖率、发货达成率)。',
- ],
- flowNote: '流程路径:发货计划制定 → 发货单新建 → 选择销售单号 → 填写发货信息 → 保存发货单 → 数据进入MDP中台。',
- flowSteps: [
- { label: '制定发货计划', role: '物流/仓管' },
- { label: '新建发货单', role: '物流/仓管' },
- { label: '选择关联销售单号', role: '物流/仓管' },
- { label: '填写发货明细行', role: '物流/仓管' },
- { label: '保存 → MDP数据同步', role: '系统(MDP)' },
- ],
- activities: [
- ['10', '发货单列表查询', '物流/仓管', '通过发货单号、销售单号、客户、日期范围筛选', '查询条件', '发货单列表'],
- ['20', '新建发货单', '物流/仓管', '选择销售单号(下拉搜索),选择客户,填写发货信息', '销售订单', '发货单'],
- ['30', '发货明细行管理', '物流/仓管', '在明细子表中新增行,填写物料、数量、批次等信息', '发货单', '发货明细'],
- ['40', 'ASN发货录入', '物流/仓管', '录入ASN发货单号、物料、发货数量、发货日期', '发货通知', 'ASN记录'],
- ['50', '数据同步中台', '系统(MDP)', '发货计划和ASN数据定时同步至mdp_stg_ship_trans,经标准化后进入dwd_ship_trans', '运行时表', '中台宽表'],
- ],
- rules: [
- ['1', '发货单号自动生成', '保存时自动生成,格式为SH+日期+流水号'],
- ['2', '销售单号下拉框', '支持远程搜索,回显格式为「BillNo|客户名」'],
- ['3', '客户下拉框', '支持远程搜索选择客户'],
- ['4', '明细行管理', '支持增删行;物料选择后自动填入物料名称;至少保留一行'],
- ['5', '已发货不可删除', '已发货的发货单不可删除,防止数据丢失'],
- ['6', '发货计划覆盖', '发货计划与销售订单关联,用于计算S1_L2_013发货计划覆盖率'],
- ['7', 'ASN发货追踪', 'ASN发货记录进入mdp_std_ship_trans,用于计算S1_L2_014发货达成率'],
- ],
- improvements: [
- '发货单实现在线管理,替代线下纸质单据流转。',
- '发货单号和销售单号自动关联,数据联动减少重复录入。',
- '发货数据和KPI自动对接,发货计划覆盖率和发货达成率自动计算。',
- ],
- permissions: [
- ['1', '物流/仓管', '新建/编辑/删除发货单和ASN发货单;管理发货明细行'],
- ['2', '计划工程师', '查看发货列表和发货KPI指标'],
- ],
- interfaces: [
- ['1', '发货数据同步', '运行时表ShippingPlan→mdp_stg_ship_trans→mdp_std_ship_trans→dwd_ship_trans', '定时(日)'],
- ['2', 'ASN数据同步', '运行时表ASNBOLShipper→mdp_stg_ship_trans→mdp_std_ship_trans', '定时(日)'],
- ],
- reports: [
- ['1', '发货计划覆盖率', 'S1_L2_013:统计有发货计划覆盖的订单占比', '按月度/按客户'],
- ['2', '发货达成率', 'S1_L2_014:统计实际发货与计划发货的一致率', '按月度/按产品线'],
- ],
- };
- const ch5 = () => buildChapter('5', '订单发货管理', _ch5cfg);
- // ── Chapter 6: 合同评审管理 ──
- const _ch6cfg = {
- targets: [
- '实现客户合同的在线评审管理,与销售订单评审协同运作。',
- '通过审批流管控合同评审的多级审核流程。',
- '将合同评审数据纳入KPI考核体系(周期、满足率、人效及L3/L4节点指标)。',
- ],
- flowNote: '流程路径:合同录入 → 合同评审列表 → 提交审批 → 审批流流转 → 审核通过/驳回 → KPI计算。',
- flowSteps: [
- { label: '合同录入', role: '商务人员' },
- { label: '查看合同评审列表', role: '商务人员' },
- { label: '提交审批流', role: '商务人员' },
- { label: '多级审批流转', role: '审批人' },
- { label: '审核通过/驳回→KPI计算', role: '系统' },
- ],
- activities: [
- ['10', '合同评审列表查询', '商务人员', '查看合同评审列表,支持多条件筛选', '查询条件', '合同评审列表'],
- ['20', '新建合同评审', '商务人员', '录入合同基本信息(合同编号、客户、签订日期等)', '合同信息', '待评审合同'],
- ['30', '提交审批', '商务人员', '提交合同进入审批流(审批流类型:CONTRACT_REVIEW)', '待评审合同', '审批中合同'],
- ['40', '审批流流转', '审批人', '多级审批节点流转,同意或驳回', '审批中合同', '已完成/已驳回'],
- ],
- rules: [
- ['1', '审批流类型', '使用CONTRACT_REVIEW审批流类型,通过IFlowBizHandler接口回调处理业务逻辑'],
- ['2', 'KPI关联', '合同评审周期(S1_L2_001)、满足率(S1_L2_002)、人效(S1_L2_003)自动计算'],
- ['3', 'L3/L4节点指标', '合同评审流程每个审批节点耗时单独统计(S1_L3_001~005、S1_L4_001~004)'],
- ['4', '数据链路', '运行时表ado_contract_review→mdp_stg_so贴源→KPI直接消费贴源层计算'],
- ],
- improvements: [
- '合同评审实现线上审批,替代纸质审批流程。',
- '合同评审周期和节点耗时自动统计,支持流程优化分析。',
- '与销售订单评审数据协同,形成完整的评审闭环。',
- ],
- permissions: [
- ['1', '商务人员', '新建/编辑合同评审;提交审批'],
- ['2', '审批人', '多级审核合同(同意/驳回)'],
- ['3', '计划工程师', '查看合同评审列表和KPI指标'],
- ],
- interfaces: [
- ['1', '合同评审数据同步', '运行时表ado_contract_review→mdp_stg_so→KPI计算', '定时(日)'],
- ],
- reports: [
- ['1', '合同评审周期分析', 'S1_L2_001:统计合同审批平均周期', '按月度'],
- ['2', '合同评审满足率', 'S1_L2_002:统计合同评审通过率', '按月度'],
- ['3', '合同节点耗时统计', 'S1_L3/L4:统计各审批节点耗时分布', '按节点/按月度'],
- ],
- };
- const ch6 = () => buildChapter('6', '合同评审管理', _ch6cfg);
- // ── Chapter 7: 计划联动 ──
- const _ch7cfg = {
- targets: [
- '实现销售订单、发货计划、ASN发货等业务数据的联动整合。',
- '通过MDP同步转换,将多源数据汇聚到dwd_ship_trans宽表。',
- '提供手动刷新机制,支持业务人员触发最新的数据联动计算。',
- ],
- flowNote: '流程路径:计划联动列表 → 查看联动状态 → 点击刷新按钮 → 触发S1_MDP_SYNC_TRANSFORM作业 → 数据联动更新 → 返回最新联动结果。',
- flowSteps: [
- { label: '查看联动列表/状态', role: '计划员' },
- { label: '点击手动刷新按钮', role: '计划员' },
- { label: 'MDP执行全量同步转换', role: '系统(MDP)' },
- { label: 'STG→STD→DWD→KPI 链路', role: '系统(MDP)' },
- { label: '返回最新联动结果', role: '系统' },
- ],
- activities: [
- ['10', '查看联动列表', '计划员', '查看各业务对象的联动状态(订单/发货/ASN)', '—', '联动列表'],
- ['20', '手动刷新', '计划员', '点击刷新按钮,触发S1_MDP_SYNC_TRANSFORM全量同步转换', '刷新请求', '最新联动数据'],
- ['30', 'MDP同步转换', '系统(MDP)', '执行STG贴源→STD标准化→DWD宽表构建→KPI计算全链路', 'S1_MDP作业', '更新后数据'],
- ['40', '查看联动结果', '计划员', '刷新完成后查看最新的联动达成率和数据一致性状态', 'MDP结果', '联动报告'],
- ],
- rules: [
- ['1', '作业编码', 'S1_MDP_SYNC_TRANSFORM,批次格式S1_MDP_FULL_yyyyMMddHHmmss'],
- ['2', '联动数据源', '订单(crm_seorder)、发货计划(ShippingPlan)、ASN(ASNBOLShipper)、联动(LinkagePlan)'],
- ['3', '联动状态', '联动成功/未联动/数据异常三种状态'],
- ['4', '刷新方式', '支持手动触发;未来可扩展定时调度'],
- ['5', '监控入口', 'mdp_transform_run_log记录作业状态;mdp_sync_log记录实体同步日志'],
- ['6', 'KPI关联', 'S1_L2_015计划联动达成率自动计算'],
- ],
- improvements: [
- '多源数据自动联动,替代人工Excel手工比对方式。',
- '手动刷新机制灵活可控,业务人员可根据需要随时触发。',
- '作业日志可观测,异常可追溯。',
- ],
- permissions: [
- ['1', '计划工程师', '查看联动列表;执行手动刷新操作;查看联动KPI'],
- ['2', '系统管理员', '监控MDP作业状态;处理执行异常'],
- ],
- interfaces: [
- ['1', '手动刷新API', 'POST /api/Order/linkageplan/refresh 触发全量同步转换', '手动触发'],
- ['2', 'MDP作业监控', 'mdp_transform_run_log/mdp_sync_log记录作业状态', '作业执行时写入'],
- ['3', '联动数据同步', 'LinkagePlan运行数据→mdp_stg_ship_trans→mdp_std_ship_trans→dwd_ship_trans', '定时(日)/手动'],
- ],
- reports: [
- ['1', '计划联动达成率', 'S1_L2_015:统计联动成功的业务对象占比', '按批次/按日'],
- ['2', 'MDP作业状态监控', '查看每次MDP转换作业的执行状态、处理行数和耗时', '按批次'],
- ],
- };
- const ch7 = () => buildChapter('7', '计划联动', _ch7cfg);
- // ── Chapter 8: 需求明细核验 ──
- const _ch8cfg = {
- targets: [
- '展示销售订单的BOM需求展开与核验结果。',
- '帮助计划人员确认物料需求数量和到货时间的准确性。',
- '核验数据服务于订单交付Tab2评审和Tab4物料需求。',
- ],
- flowNote: '流程路径:需求核验列表 → 多条件筛选 → 查看核验结果 → 核验结果同步展示在订单交付Tab2和Tab4。',
- flowSteps: [
- { label: '核验列表筛选查询', role: '计划员' },
- { label: '查看BOM需求展开', role: '计划员' },
- { label: '确认库存占用/缺料', role: '计划员' },
- { label: '数据同步到交付Tab2/Tab4', role: '系统' },
- ],
- activities: [
- ['10', '核验列表查询', '计划员', '通过订单号、物料编码、核验状态等条件筛选', '筛选条件', '核验列表'],
- ['20', '查看核验明细', '计划员', '查看订单行的BOM需求展开、库存占用、缺料分析和替代料信息', '核验结果', '需求明细'],
- ['30', '同步订单交付', '系统', '核验结果自动同步到订单交付详情Tab2和Tab4', '核验数据', '交付详情'],
- ],
- rules: [
- ['1', '数据来源', '运行时表b_examine_result/b_bom_child_examine→mdp_stg_so→dwd_requirement_examine_detail'],
- ['2', '核验内容', '物料编码、BOM编码、需求数量、缺料数量、替代料方案、满足时间'],
- ['3', '数据过滤', '只取最新成功批次的核验数据,确保数据一致性'],
- ['4', '跨页面复用', '核验结果同时在需求核验页面和订单交付Tab2/Tab4中使用'],
- ],
- improvements: [
- '需求核验数据在线化,替代手工Excel核对方式。',
- '核验结果跨页面共享,避免数据重复计算。',
- '接入中台DWD层,数据口径统一。',
- ],
- permissions: [
- ['1', '计划工程师', '查看需求核验列表;筛选和排序操作'],
- ],
- interfaces: [
- ['1', '需求核验API', 'GET /api/RequirementExamineDetail/list 读取dwd_requirement_examine_detail', '实时(页面加载)'],
- ['2', '核验数据同步', 'b_examine_result→mdp_stg_so→dwd_requirement_examine_detail', '定时(日)'],
- ],
- reports: [],
- };
- const ch8 = () => buildChapter('8', '需求明细核验', _ch8cfg);
- // ── Chapter 9: 工单下达 ──
- const _ch9cfg = {
- targets: [
- '管理生产工单的下达,是产销协同到制造执行的衔接环节。',
- '下达前必须执行物料齐套检查和物料需求同步(生成MRP),确保物料准备到位。',
- '工单逐单下达(非批量),每行操作列独立触发,下达后MES系统可见。',
- '支持工单状态的全程跟踪。',
- ],
- flowNote: '流程路径:工单列表 → 物料齐套检查(工具栏按钮) → 生成物料需求/同步MRP → 点击单行[工单下达]按钮 → 填写下达信息确认 → 工单状态变更 → MES可见。',
- flowSteps: [
- { label: '工单列表筛选查询', role: '计划员/调度' },
- { label: '物料齐套检查', role: '计划员/调度' },
- { label: '生成物料需求(MRP同步)', role: '计划员/调度' },
- { label: '逐行点击工单下达', role: '计划员/调度' },
- { label: '确认下达→状态变更→MES可见', role: '系统' },
- ],
- activities: [
- ['10', '工单列表查询', '计划员/调度', '通过工单号、物料编码、开工日期、状态筛选', '查询条件', '工单列表'],
- ['20', '物料齐套检查', '计划员/调度', '点击工具栏"物料齐套检查"按钮,调用外部资源审查服务检查各工单物料齐套状态', '工单列表', '齐套状态列更新'],
- ['30', '生成物料需求', '计划员/调度', '点击工具栏"生成物料需求"按钮,同步生成物料需求计划(MRP)', '工单列表', '物料需求计划生成'],
- ['40', '工单下达(逐单)', '计划员/调度', '点击单行操作列"工单下达"按钮,弹出下达表单填写开工日期和生产批号,确认后工单状态变更为"已下达"', '单行工单', '已下达工单'],
- ['50', '工单状态跟踪', '计划员/调度', '按状态筛选工单,跟踪工单从下达到完成的全过程', '工单列表', '状态跟踪'],
- ],
- rules: [
- ['1', '工单状态', '待下达→已下达→生产中→已完成→已关闭;下达前状态为"待下达"'],
- ['2', '防重复下达', '已下达工单不可重复下达;前端按钮置灰+后端校验双重保障'],
- ['3', '逐单下达', '工单逐行单个下达,操作列每行独立[工单下达]按钮,不支持批量一键下达'],
- ['4', '物料齐套检查', '下达前必须先通过工具栏"物料齐套检查"确认物料准备状态;调用外部资源审查服务'],
- ['5', '物料需求同步', '下达前需按需通过工具栏"生成物料需求"同步生成MRP物料需求计划'],
- ['6', '下游联动', '下达后MES系统可见,进入S6生产执行阶段'],
- ['7', '工单编码', '工单号全局唯一,由上游系统生成'],
- ],
- improvements: [
- '工单下达实现在线逐单操作,替代线下手工派发方式。',
- '物料齐套检查与物料需求同步(MRP生成)前置化,确保下达前物料准备到位。',
- '工单状态实时跟踪,下游系统联动自动化。',
- '防重复下达机制保障数据安全。',
- ],
- permissions: [
- ['1', '计划员/调度', '查看工单列表;执行工单下达操作;跟踪工单状态'],
- ],
- interfaces: [
- ['1', '工单下达列表API', 'GET /api/WorkOrder/dispatch/list', '实时(页面加载)'],
- ['2', '物料齐套检查API', 'GET 外部资源审查服务(前端直连)', '手动触发(工具栏)'],
- ['3', '生成物料需求API', 'GET 外部MRP服务(前端直连)', '手动触发(工具栏)'],
- ['4', '工单下达操作API', 'POST /api/WorkOrder/dispatch/release', '手动触发(逐行下达)'],
- ['5', '工单状态同步MES', '工单下达后状态同步至MES系统', '实时(下达触发)'],
- ],
- reports: [
- ['1', '工单下达及时率', '统计计划下达时间和工单下达时间差异', '按周/按月'],
- ],
- };
- const ch9 = () => buildChapter('9', '工单下达', _ch9cfg);
- // ── Chapter 10: 产销协同看板与KPI ──
- const _ch10cfg = {
- targets: [
- '为管理层和业务人员提供S1模块的核心KPI可视化看板。',
- '通过L1/L2/L3/L4多层级指标全面监控产销协同健康度。',
- '支持按客户维度筛选,灵活下钻分析。',
- ],
- flowNote: '流程路径:产销协同看板入口 → L1核心指标卡片 → 趋势图表 → 客户筛选 → 指标下钻 → L2/L3/L4分解指标。',
- flowSteps: [
- { label: '进入S1产销协同看板', role: '管理层/计划员' },
- { label: '查看L1核心KPI卡片', role: '管理层/计划员' },
- { label: '客户维度筛选过滤', role: '管理层/计划员' },
- { label: '指标下钻L2→L3→L4', role: '管理层/计划员' },
- { label: '趋势图表分析', role: '管理层/计划员' },
- ],
- activities: [
- ['10', '查看看板', '管理层/计划员', '进入S1产销协同看板,观察L1核心指标卡片', '—', 'L1指标展示'],
- ['20', '客户筛选', '管理层/计划员', '选择客户维度,看板数据按客户过滤刷新', '客户选择', '筛选后数据'],
- ['30', '指标下钻', '管理层/计划员', '点击指标卡片下钻查看L2分解指标详情', 'L1指标', 'L2指标详情'],
- ['40', '趋势分析', '管理层/计划员', '查看指标周期趋势图表,分析变化规律', '历史数据', '趋势图表'],
- ],
- rules: [
- ['1', '组件架构', '使用DynamicModuleDashboard动态看板组件,module-code="S1"'],
- ['2', 'L1核心指标', '订单及时交付率(S1_L1_001)、订单交付周期(S1_L1_002)、订单评审完成率(S1_L1_003)、成品库存周转天数(S1_L1_004)'],
- ['3', 'L2分解指标', '合同评审3项(S1_L2_001~003)、产品设计3项(S1_L2_004~006)、交期评审3项(S1_L2_010~012)、发货联动3项(S1_L2_013~015)'],
- ['4', 'L3/L4节点指标', '合同评审各审批节点的周期和通过率(S1_L3_001~005/101~105、S1_L4_001~004/101~104)'],
- ['5', '指标存储', '指标定义写入ado_smart_ops_kpi_master;计算结果写入ado_s9_kpi_value_l1~l4_day'],
- ['6', '刷新方式', '通过MDP作业S1_MDP_SYNC_TRANSFORM定时或手动刷新KPI数据'],
- ['7', 'S1_L1_004口径说明', '当前为数量代理口径(基于dwd_ship_trans),正式成本口径待S7成品库存快照和成本数据确认后升级'],
- ],
- improvements: [
- '实现S1模块KPI在线可视化和实时监控。',
- '多层级指标下钻,支持从L1到L4逐层分析。',
- 'KPI数据自动计算,替代人工Excel统计。',
- ],
- permissions: [
- ['1', '管理层', '查看S1看板全部指标'],
- ['2', '计划工程师', '查看S1看板;按客户维度筛选分析'],
- ['3', '销售/商务', '查看S1看板(本部门相关指标)'],
- ],
- interfaces: [
- ['1', '看板聚合API', 'GET /api/AidopKanban/module-detail?moduleCode=S1', '实时(页面加载)'],
- ['2', 'KPI数据源', 'ado_s9_kpi_value_l1~l4_day 按天粒度存储', 'MDP定时刷新'],
- ['3', '手动刷新(计划联动)', 'POST /api/Order/linkageplan/refresh 触发S1全链路刷新', '手动触发'],
- ],
- reports: [],
- };
- const ch10 = () => buildChapter('10', '产销协同看板与KPI', _ch10cfg);
- // ── Chapter 11: 数据中台架构 ──
- function buildCh11() {
- const ch = [];
- ch.push(h1('11 数据中台架构'));
-
- ch.push(h2('11.1 目标/宗旨'));
- ch.push(p('S1产销协同模块采用Ai-DOP统一数据中台分层架构,将业务运行数据经过贴源(STG)、标准化(STD)、宽表构建(DWD)、指标计算(KPI)四层处理,最终服务于前端页面查询、看板展示和KPI考核。'));
-
- ch.push(h2('11.2 分层设计'));
- ch.push(table(
- ['分层', '表前缀', '职责', '更新机制'],
- [
- ['贴源层(STG)', 'mdp_stg_*', '保留源系统原始数据,含raw_data/source_table/sync_batch_id', '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('11.3 S1核心数据流'));
- ch.push(bp('订单/评审/设计链路'));
- ch.push(p('crm_seorder / ado_contract_review / ado_product_design / b_examine_result'));
- ch.push(p(' → mdp_stg_so(贴源层)→ mdp_std_so(标准层)→ dwd_ship_trans / dwd_requirement_examine_detail(宽表)→ ado_s9_kpi_value_*(指标层)'));
- ch.push(bp('发货/ASN/联动链路'));
- ch.push(p('ShippingPlan / ASNBOLShipper / LinkagePlan'));
- ch.push(p(' → mdp_stg_ship_trans(贴源层)→ mdp_std_ship_trans(标准层)→ dwd_ship_trans(宽表)→ ado_s9_kpi_value_*(指标层)'));
- ch.push(h2('11.4 对象映射总表'));
- ch.push(table(
- ['业务对象', '运行表', '贴源层', '标准层/DWD', '消费端'],
- [
- ['销售订单', 'crm_seorder', 'mdp_stg_so', 'mdp_std_so / dwd_ship_trans', '订单列表、交付、KPI'],
- ['订单变更', 'crm_seorder_change', 'mdp_stg_so', '关联mdp_std_so', 'Tab2变更记录'],
- ['合同评审', 'ado_contract_review', 'mdp_stg_so', 'KPI直接消费', 'S1_L2_001~003'],
- ['产品设计', 'ado_product_design', 'mdp_stg_so', 'KPI直接消费', 'S1_L2_004~006'],
- ['发货计划', 'ShippingPlan', 'mdp_stg_ship_trans', 'mdp_std_ship_trans / dwd_ship_trans', 'S1_L2_013'],
- ['ASN发货', 'ASNBOLShipper', 'mdp_stg_ship_trans', 'mdp_std_ship_trans / dwd_ship_trans', 'S1_L2_014'],
- ['计划联动', 'LinkagePlan', 'mdp_stg_ship_trans', 'mdp_std_ship_trans / dwd_ship_trans', 'S1_L2_015'],
- ['需求核验', 'b_examine_result', 'mdp_stg_so', 'dwd_requirement_examine_detail', '核验页/Tab2/Tab4'],
- ],
- [1100, 1800, 1800, 2600, 2700]
- ));
- ch.push(h2('11.5 MDP作业调度'));
- ch.push(table(
- ['配置项', '内容'],
- [
- ['作业编码', 'S1_MDP_SYNC_TRANSFORM'],
- ['批次格式', 'S1_MDP_FULL_yyyyMMddHHmmss'],
- ['手动刷新入口', 'POST /api/Order/linkageplan/refresh'],
- ['监控入口', 'mdp_transform_run_log(作业日志)、mdp_sync_log(同步日志)、前端MDP监控页'],
- ['执行方式', '手动触发 + 未来扩展定时调度'],
- ],
- [2200, 7800]
- ));
- ch.push(h2('11.6 变化和改进点'));
- ch.push(bullet('建立统一数据中台分层架构,业务数据从"各自为政"收敛到标准数据链路。'));
- ch.push(bullet('页面读取统一从DWD/KPI层消费,确保数据口径一致。'));
- ch.push(bullet('MDP作业可观测,支持日志查询和异常追溯。'));
- return ch;
- }
- // ── Chapter 12: 权限管理汇总 ──
- function buildCh12() {
- const ch = [];
- ch.push(h1('12 权限管理汇总'));
- ch.push(p('以下汇总S1产销协同模块各功能所涉及的角色和权限:'));
- ch.push(table(
- ['序号', '角色', '权限范围', '涉及模块'],
- [
- ['1', '销售/客服专员', '查看销售订单列表、订单交付列表;新建/编辑/删除订单;发起订单变更申请', '订单评审、订单交付'],
- ['2', '计划工程师', '查看和操作订单评审、工单下达、计划联动、需求核验;执行交期确认;查看KPI看板', '所有模块(操作权限)'],
- ['3', '商务人员', '新建/编辑合同评审;提交审批;查看订单交付', '合同评审'],
- ['4', '设计员', '新建/编辑/删除产品设计任务;录入BOM和工艺子表;保存操作', '产品设计'],
- ['5', '物流/仓管', '新建/编辑/删除发货单和ASN发货单;管理发货明细行;查看订单交付', '订单发货'],
- ['6', '管理层', '查看S1看板全部指标', '看板与KPI'],
- ['7', '审批人', '审核订单变更申请/合同评审的审批流', '订单评审(变更)、合同评审'],
- ['8', '系统管理员', '管理用户角色权限;监控MDP作业状态;数据修复操作', '系统配置'],
- ],
- [600, 1800, 5000, 2600]
- ));
- return ch;
- }
- // ═══════════════════════════════════════════════════
- // 文档构建主流程
- // ═══════════════════════════════════════════════════
- async function buildDocument() {
- // ── 预生成所有流程图 PNG ──
- console.log('Generating flow chart images...');
- flowImageCache['overview'] = await generateOverviewFlowPNG();
- // 收集所有章节的 flowSteps 定义并预生成流程图
- const allChapterConfigs = {
- '2': _ch2cfg, '3': _ch3cfg, '4': _ch4cfg, '5': _ch5cfg,
- '6': _ch6cfg, '7': _ch7cfg, '8': _ch8cfg, '9': _ch9cfg, '10': _ch10cfg,
- };
- 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: 'S1 产销协同模块', 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: '版本:V2.0 日期:2026年6月8日 作者:彭熙玉', 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/06/08', '彭熙玉', 'V1.0', '初版(基于DOP整体方案设计)'],
- ['2026/06/08', '彭熙玉', 'V2.0', '根据系统实际S1模块实现重写,聚焦产销协同范围,按模板格式补充8子章节']],
- [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('S1产销协同模块是Ai-DOP平台订单履约链路的起点,承担"从订单到交付"的产销协同管理职能。'));
- sections.push(bullet('指导销售订单从接收→评审→排产→采购→生产→发运的全流程在线化协同。'));
- sections.push(bullet('通过KPI指标体系监控产销协同健康度,驱动业务流程持续改善。'));
- sections.push(h2('1.2 总体业务流程图'));
- sections.push(p('S1产销协同模块覆盖从"产品设计"到"成品发运"的订单履约全链路,下图展示了主线流程(订单履约链)、支撑流程和底层数据中台链路的整体关系:'));
- // 嵌入总体流程图(在 buildDocument 头部预生成)
- sections.push(flowImageParagraph(flowImageCache['overview']));
- sections.push(h2('1.3 方案设计'));
- sections.push(p('S1模块作为Ai-DOP S0-S9模块化架构中的"产销协同"功能域,覆盖以下核心功能模块:'));
- sections.push(bullet('产品设计管理:新产品开发中BOM和工艺路线的在线录入与保存,无审批流'));
- sections.push(bullet('订单评审管理:销售订单的CRUD、交期评估与确认;变更场景走审批流'));
- sections.push(bullet('订单交付管理:8Tab全景追踪,从订单信息到成品发运的全链路可视化'));
- sections.push(bullet('订单发货管理:发货计划、ASN发货、计划联动的在线管理'));
- sections.push(bullet('合同评审管理:客户合同的多级审批与KPI考核'));
- sections.push(bullet('需求明细核验:BOM需求展开与核验结果的在线查看'));
- sections.push(bullet('工单下达:生产工单的物料齐套检查、MRP同步与逐单下达'));
- sections.push(bullet('产销协同看板:L1/L2/L3/L4多层级KPI可视化监控'));
- sections.push(p('数据层面,S1采用数据中台分层架构,业务运行数据通过MDP同步转换作业沉淀到中台表,前端页面和看板统一消费中台数据,确保数据口径一致。跨模块依赖的Tab数据(排程、采购、备料、报工IQC、FQC入库)界面结构已就绪,待S2/S3/S4/S5/S6/S7模块补齐后自动填充。'));
- // ── 第2~10章: 各功能模块 ──
- const moduleChapters = [ch2, ch3, ch4, ch5, ch6, ch7, ch8, ch9, ch10];
- for (const chFn of moduleChapters) {
- sections.push(pageBreak());
- sections.push(h1(chFn().find(el => {
- // extract the chapter title from h2 children
- if (el.root && el.root[0] && el.root[0].children) {
- return chFn.name;
- }
- return false;
- })));
- // Actually, the above approach is wrong. Let me just push the results.
- }
- // Let me restructure - push each chapter directly
- 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 产销协同看板与KPI')); sections.push(...ch10());
- // ── 第11~12章 ──
- sections.push(pageBreak()); sections.push(...buildCh11());
- sections.push(pageBreak()); sections.push(...buildCh12());
- 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\\S1产销协同模块蓝图设计方案.docx';
- const fallbackPath = 'd:\\DEMONET\\doc\\S1产销协同模块蓝图设计方案_V2.docx';
- const tempPath = 'd:\\DEMONET\\doc\\S1_blueprint_temp.docx';
- fs.writeFileSync(tempPath, buffer);
- // 先尝试写入主文件名,若被占用则写入 V2 副本
- try { fs.unlinkSync(outPath); } catch(e) { /* 被占用则跳过 */ }
- try { fs.renameSync(tempPath, outPath); console.log(`Renamed to: ${outPath}`); }
- catch(e) {
- // 主文件被锁定,写入 V2 副本
- 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); });
|