aps-agent/build-manual-v3.js

317 lines
21 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ============================================================
// 图文版操作手册 v3:专业平实文风 + 真实截图
// ============================================================
import fs from "node:fs";
import path from "node:path";
import {
AlignmentType, BorderStyle, Document, Footer, Header, HeadingLevel,
ImageRun, Packer, PageBreak, PageNumber, Paragraph, ShadingType,
Table, TableCell, TableRow, TextRun, WidthType,
} from "docx";
const outputPath = process.argv[2];
if (!outputPath) throw new Error("Usage: node build-manual-v3.js /abs/out.docx");
const ROOT = path.dirname(outputPath);
const SHOTS = path.join(ROOT, "_shots");
const T = String.raw;
const palette = { dark: "1F2A36", primary: "2F4858", light: "6B7A86", fill: "F2F5F7" };
const fontBody = { ascii: "Times New Roman", hAnsi: "Times New Roman", cs: "Times New Roman", eastAsia: "SimSun" };
const fontHead = { ascii: "Times New Roman", hAnsi: "Times New Roman", cs: "Times New Roman", eastAsia: "SimHei" };
const run = (text, options = {}) => new TextRun({ text, font: fontBody, size: 24, ...options });
const para = (children, options = {}) => new Paragraph({
spacing: { after: 140, line: 340 }, ...options,
children: Array.isArray(children) ? children : [children],
});
const body = (text) => para(run(text), { indent: { firstLine: 480 }, alignment: AlignmentType.JUSTIFIED });
const h1 = (text) => para(new TextRun({ text, font: fontHead, bold: true, size: 32, color: palette.dark }), {
heading: HeadingLevel.HEADING_1, spacing: { before: 360, after: 200 },
});
const h2 = (text) => para(new TextRun({ text, font: fontHead, bold: true, size: 26, color: palette.primary }), {
heading: HeadingLevel.HEADING_2, spacing: { before: 240, after: 140 },
});
const tip = (text) => para(
[new TextRun({ text: T`提示:`, font: fontHead, bold: true, size: 24, color: palette.primary }), run(text, { color: palette.primary })],
{ indent: { left: 240 }, shading: { type: ShadingType.CLEAR, fill: palette.fill } },
);
let figNo = 0;
const fig = (file, captionText) => {
figNo += 1;
const img = new ImageRun({
type: "png",
data: fs.readFileSync(path.join(SHOTS, file)),
transformation: { width: 640, height: 400 },
});
return [
new Paragraph({ alignment: AlignmentType.CENTER, spacing: { before: 120, after: 60 }, children: [img] }),
para(new TextRun({ text: T`图 ${figNo} ${captionText}`, font: fontHead, size: 20, color: palette.light }), {
alignment: AlignmentType.CENTER, spacing: { after: 200 },
}),
];
};
const noBorder = { style: BorderStyle.NONE, size: 0, color: "FFFFFF" };
const table3 = (headers, rows, widths) => {
const total = widths.reduce((a, b) => a + b, 0);
const mk = (text, i, opts = {}) => new TableCell({
children: [new Paragraph({
spacing: { after: 30, line: 300 },
children: [new TextRun({ text, font: opts.bold ? fontHead : fontBody, size: 21, bold: !!opts.bold })],
})],
width: { size: widths[i], type: WidthType.DXA },
margins: { top: 70, bottom: 70, left: 100, right: 100 },
borders: opts.borders,
});
return new Table({
width: { size: total, type: WidthType.DXA },
columnWidths: widths,
rows: [
new TableRow({
tableHeader: true,
children: headers.map((h, i) => mk(h, i, {
bold: true,
borders: {
top: { style: BorderStyle.SINGLE, size: 12, color: palette.dark },
bottom: { style: BorderStyle.SINGLE, size: 6, color: palette.dark },
left: noBorder, right: noBorder,
},
})),
}),
...rows.map((row, ri) => new TableRow({
children: row.map((c, i) => mk(String(c), i, {
borders: {
top: noBorder,
bottom: ri === rows.length - 1
? { style: BorderStyle.SINGLE, size: 12, color: palette.dark } : noBorder,
left: noBorder, right: noBorder,
},
})),
})),
],
});
};
const children = [];
const add = (...items) => children.push(...items);
const PAGEBREAK = () => add(new Paragraph({ children: [new PageBreak()] }));
// ---------------- 封面 ----------------
add(
para(new TextRun({ text: T`工业智核 APS 计划排产智能体`, font: fontHead, bold: true, size: 48, color: palette.dark }), {
alignment: AlignmentType.CENTER, spacing: { before: 3200, after: 240 },
}),
para(new TextRun({ text: T`图 文 使 用 手 册`, font: fontHead, bold: true, size: 44, color: palette.dark }), {
alignment: AlignmentType.CENTER, spacing: { after: 900 },
}),
para(run(T`—— 基于系统真实界面的功能操作指南 ——`, { color: palette.light }), {
alignment: AlignmentType.CENTER, spacing: { after: 2400 },
}),
para(run(T`版本:V1.1(按 2026-09-01 系统实际运行界面截图)`), { alignment: AlignmentType.CENTER, spacing: { after: 160 } }),
para(run(T`适用对象:计划员、生产调度、实施顾问及售前人员`), { alignment: AlignmentType.CENTER }),
new Paragraph({ children: [new PageBreak()] }),
);
// ---------------- 手册说明 ----------------
add(
h1(T`手册说明`),
body(T`本手册以系统真实运行界面的截图为基础,逐功能说明工业智核 APS 计划排产智能体的操作方法。手册遵循“先定位、后操作、再核对”的编写原则:每个功能均说明其业务用途、界面入口与操作要点,读者可按图索骥完成全部日常操作。`),
body(T`系统采用“自然语言对话 + 可视化工作台”双交互模式:左侧对话区接收业务指令(如“跑一版柔性排产”),右侧工作台同步呈现甘特、产能、订单等可视化结果。系统覆盖销售订单接入、MRP 分解、多策略排产、方案对比、版本发布、MES 下发与报工回流的完整业务闭环。`),
body(T`系统的核心治理原则是门禁确认机制:凡涉及正式生效的操作(版本发布、采购下达、主数据修改、MES 下发),均须经由确认卡人工批准后执行,执行前自动创建检查点快照。因此日常操作具备可回滚性,误操作可通过时间线检查点恢复。`),
);
// ---------------- 一、系统登录 ----------------
PAGEBREAK();
add(
h1(T`一、系统登录`),
body(T`打开系统后,点击左下角“登录”按钮,在登录弹窗中依次填写企业名称、用户名与密码,提交后进入工作台。企业账号由所属企业管理员在 JMS 平台统一开通与维护,系统不提供自助注册与自助找回密码功能。`),
...fig("01-登录.png", T`登录弹窗:企业名称、用户名、密码三项必填`),
tip(T`桌面端(安装包形态)不使用账号体系,输入有效授权码即可激活使用。`),
);
// ---------------- 二、主界面导览 ----------------
add(
h1(T`二、主界面导览`),
body(T`登录后的主界面划分为三个功能区域,后续全部操作均围绕这三区展开:`),
...fig("02-主界面.png", T`主界面布局:左侧导航、中部对话区、右侧工具导轨`),
table3(
[T`区域`, T`名称`, T`功能说明`],
[
[T`左侧竖栏`, T`导航栏`, T`提供新建任务、订单管理、主数据、柔性工作台等入口,下方为项目与任务列表`],
[T`中部区域`, T`对话区`, T`自然语言指令的输入与回复区域;系统回复中内嵌方案卡、确认卡等可交互组件`],
[T`右侧细条`, T`工具导轨`, T`纵向排列的功能图标,单击即可在右侧展开对应面板(会话结果、订单、主数据、多智能体、图纸识别等)`],
],
[1700, 1700, 5800],
),
body(T`首次进入时,对话区显示欢迎页并提供三条常用操作建议(跑一版柔性排产、试排一版交期优先、多策略方案对比),单击即等同于在对话区发送对应指令,可作为新用户的入门路径。`),
);
// ---------------- 三、对话式操作 ----------------
PAGEBREAK();
add(
h1(T`三、对话式操作`),
h2(T`3.1 对话发起排产`),
body(T`在底部输入框输入“跑一版柔性排产”并回车,系统完成求解后在对话流中返回结果卡,内容包括虚拟产线条数、工单数量、最晚完工时间、准时订单数与冲突数量。若存在缺料、工艺路线未确认等阻断项,系统会逐项列出具体问题对象与修复指引,不会以“排产完成”掩盖异常。`),
...fig("03-对话柔性排产.png", T`对话发起柔性排产:结果卡与阻断项清单一并返回`),
tip(T`同类指令还包括“试排一版交期优先”“按产能均衡排一下”“换型最小化试排”。“试排”仅生成 DRAFT 草稿版本,不影响正式数据。`),
h2(T`3.2 多策略方案对比`),
body(T`输入“对比几种策略”,系统在隔离沙盒中并行执行交期优先、产能均衡、换型最小化、战役合并、综合优化等多种策略,并返回方案卡组。每张方案卡标注延迟、冲突、利用率、换型次数等关键指标;选定后点击“采用此方案”,该策略结果即落入主干草稿。对比过程不改变主干世界状态。`),
...fig("19-对话策略对比.png", T`多策略对比:五种策略方案卡并排呈现,支持一键采用`),
h2(T`3.3 知识库问答`),
body(T`系统内置知识库,承载工艺规定、SOP 等业务文档。直接提问(如“换线有什么规定”)即可检索相关条款,回复中附带来源出处;检索未命中时系统明确告知无相关内容,不生成虚构条文。`),
...fig("20-对话知识问答.png", T`知识库问答:答案附出处,未命中时如实反馈`),
);
// ---------------- 四、柔性工作台 ----------------
PAGEBREAK();
add(
h1(T`四、柔性工作台`),
body(T`点击右侧工具导轨“柔性工作台”图标,展开图形化操作面板。该面板面向多品种小批量、设备可移动的生产模式:系统以工序为粒度组织资源,从具备相应工序能力的设备池中动态取用设备,为订单临时组建虚拟产线,任务完成后设备释放回池。`),
...fig("12-柔性工作台.png", T`柔性工作台:排产、询价、异常、冲突、What-if 集成于同一面板`),
body(T`面板各功能区说明如下:`),
table3(
[T`功能区`, T`操作说明`],
[
[T`瓶颈锚排产 / 正排 / 倒排`, T`三种排产模式:瓶颈工序锚定混合排、按开工顺序正排、按交期倒排`],
[T`三模式对比`, T`三种模式并行求解并对比结果,辅助模式选择`],
[T`滚动时域`, T`设定排产窗口:实时 60 分钟、短窗 2 小时、中窗 2 天、长窗 7 天`],
[T`分级重排`, T`异常响应幅度:L2 短窗重排、L3 日窗重排、L4 全局重排,均须经 P2 确认`],
[T`交期询价`, T`输入产品与数量,模拟插入当前排程,输出乐观 / 预计交期及资源缺口提示`],
[T`SAP 集成 / MES 执行`, T`ERP 订单与库存同步、定稿版本下发车间执行(P3 二次确认)`],
],
[2600, 6600],
),
tip(T`面板下方实时标注当前限制性瓶颈工序及其日产能(图示为“喷涂,日产能≈1728 件”)。系统产能以瓶颈工序为准,设备停机或调区后即时重算。`),
);
// ---------------- 五、结果视图 ----------------
PAGEBREAK();
add(
h1(T`五、结果视图`),
body(T`排产产生结果后,点击工具导轨首图标“会话结果”,右侧展开视口面板,页签包括:甘特图、负荷热力、利用率、交期承诺、分桶计划、KPI、对比表、世界对比、产能池。各视图功能分述如下。`),
h2(T`5.1 产能池仪表盘`),
body(T`按工序能力池逐池展示日产能、设备数量与负载率,并提供未来 4 小时、1 天、1 周的负载预测;顶部显著位置标注当前限制性瓶颈池。设备停机、调区等变更即时触发产能重算。`),
...fig("09-产能池.png", T`产能池仪表盘:瓶颈标注与短中长期负载预测`),
h2(T`5.2 资源利用率`),
body(T`以热力图呈现各设备逐日负载:绿色表示低负载(<50%),黄色至橙色表示负载升高,红色表示超载(≥100%)。可快速识别长期超载设备与闲置设备,评估排产均衡性。`),
...fig("23-利用率.png", T`资源利用率:设备 7 日负载热力图`),
h2(T`5.3 KPI 仪表盘`),
body(T`汇总平均利用率、准时率、总延迟、在制工单、未解冲突、MES 完工率六类运营指标,同时覆盖固定轨与柔性轨两条排产链路。`),
...fig("08-KPI仪表盘.png", T`运营 KPI 仪表盘:六类核心指标一屏汇总`),
h2(T`5.4 分桶计划`),
body(T`面向排产前的中长期评估:近 7 日按日、中期按周、远期按月分桶,将产能与需求放入同一时间框架对比。配套功能包括可行性分析(订单能否按期)、库存投影(断料与安全库存预警)、削峰(超载时段向空档时段的挪动建议)与产供决策(加班、扩线、外协建议)。`),
...fig("07-分桶计划.png", T`分桶计划:粗能力评估、可行性、库存投影与削峰`),
h2(T`5.5 对比表与世界对比`),
body(T`“对比表”将多策略关键指标排列为矩阵并高亮最优项;“世界对比”将两个版本的世界状态并排呈现,逐项列出订单、资源占用与 KPI 差异,适用于方案采用前后或回滚前后的差异核查。`),
...fig("22-世界对比.png", T`两个世界对比:版本间订单、资源与 KPI 差异逐项呈现`),
tip(T`甘特图页签在生成正式排产版本后,以时间条呈现各工单;工单支持拖拽调整(15 分钟吸附、拖拽过程实时校验),松手后生成 P2 确认卡,批准后生效。`),
);
// ---------------- 六、订单管理 ----------------
PAGEBREAK();
add(
h1(T`六、订单管理`),
body(T`点击工具导轨“订单管理”图标进入。面板顶部汇总订单总数、待审、加急与预测四类计数;中部为“闭环 APS 阶段”流水线,将订单生命周期划分为六站:商务订单 → BOM/供需净算 → 制造需求准入 → 排产草案 → P2 发布 → P3 MES 下发。各站设有独立门禁,未满足准入条件时停留在对应站点,并明示缺失项。`),
...fig("13-订单管理.png", T`订单管理:六阶段闭环流水线与站点门禁状态`),
body(T`面板同时提供新增订单、批量批准、一键清理、Excel/CSV 订单导入与排产分析报告功能。相关对话指令同样有效:“订单池”“提交审核”“批量批准”“插单快评”等。`),
);
// ---------------- 七、主数据维护 ----------------
add(
h1(T`七、主数据维护`),
body(T`点击工具导轨“主数据”图标进入。主数据是排产准确性的基础,面板按页签组织:资源(工厂→车间→产线→设备层级树)、工艺模型(物料 / BOM / 工序 / 工艺路线 / 产线绑定 / 换型矩阵)、柔性资源、日历与维保、工时维护。`),
...fig("14-主数据.png", T`主数据:工艺模型页签(物料、BOM、工序、工艺路线)`),
body(T`主数据录入须遵循依赖顺序:工厂与产线 → 物料 → BOM → 工序 → 工艺路线 → 产线产品绑定,最后录入订单。任一环节缺失将导致排产失败或结果缺乏依据。全部修改均经确认卡批准后生效,且仅影响其后生成的排产版本,不回写历史版本。`),
tip(T`批量数据可通过“导入 Excel/CSV”入口处理,遵循“表头映射 → 预览校验 → 确认入库”流程,支持订单、物料、BOM、工艺路线、设备、模具等对象。`),
);
// ---------------- 八、排产结构追溯 ----------------
add(
h1(T`八、排产结构追溯`),
body(T`点击工具导轨“排产结构”图标,查看当前排产版本的结构化分解:每张销售订单拆解为哪些工序、各工序占用哪台设备的哪个时间段。排产结果中的每道工序均可回溯至订单、BOM 与工艺路线,保证排产依据可核查。`),
...fig("15-排产结构.png", T`排产结构:订单—工序—设备的完整追溯链`),
);
// ---------------- 九、多智能体编排 ----------------
PAGEBREAK();
add(
h1(T`九、多智能体编排`),
body(T`点击工具导轨“多智能体编排”图标进入。该功能支持以目标(Goal)驱动的方式组织多智能体协作:创建 Goal(如“锐扬排产全流程”,内置数据解析 → MRP 分解 → 下达 → 排产 → 报告五项任务)后点击“分发执行”,系统按能力边界将任务分配给相应智能体,无匹配智能体时自动创建。`),
...fig("16-多智能体编排.png", T`多智能体编排:Goal 挂载、自动分发与看门狗监控`),
body(T`看门狗机制负责执行监控:任务超时(默认 45 秒)收回重排,多次重试失败升级为人工关注,全部任务完成后自动结案。消息总线实时呈现智能体间的任务接力;失败任务如实标记 FAILED 并升级,不伪报成功。`),
);
// ---------------- 十、DXF 图纸识别 ----------------
add(
h1(T`十、DXF 图纸识别`),
body(T`点击工具导轨“图纸识别”图标,上传 DXF 图纸(或填写本地路径、扫描工程目录)。系统自动解析标题栏的图号、名称、比例、版本等信息,逐字段标注置信度与来源;图纸以 SVG 形式预览,支持缩放、平移与图层开关。`),
...fig("17-图纸识别.png", T`图纸识别:标题栏解析、置信度标注与 SVG 预览`),
body(T`解析结果生成物料候选,经人工核对并通过确认卡批准后方写入主数据。图纸未承载的字段(材质、工时、BOM 子件数量等)一律显式标记为缺失,不做推测填充。`),
);
// ---------------- 十一、命令面板 ----------------
add(
h1(T`十一、命令面板(Ctrl+K)`),
body(T`按下 Ctrl+K 唤出命令面板,输入关键词即可过滤全部面板与视图命令。例如输入“柔性”,即列出“柔性工作台”“柔性甘特”等条目,回车直达目标功能,是跨功能跳转的最高效方式。`),
...fig("18-命令面板.png", T`Ctrl+K 命令面板:关键词过滤、回车直达`),
);
// ---------------- 十二、安全与治理机制 ----------------
PAGEBREAK();
add(
h1(T`十二、安全与治理机制`),
table3(
[T`机制`, T`说明`],
[
[T`门禁确认卡`, T`版本发布、采购下达、主数据修改、MES 下发等正式操作须经人工批准后执行`],
[T`自动检查点`, T`每次执行确认操作前自动创建快照;也可随时通过“存个档”手动创建`],
[T`时间线回滚`, T`点击时间线上的检查点即可恢复历史状态,回滚执行前自动再次存档`],
[T`沙盒隔离`, T`试排与策略对比在草稿或沙盒中进行,不影响主干数据`],
[T`审计哈希链`, T`全部审批与执行操作记入不可篡改的审计链,支持断链检测与倒查`],
[T`诚实阻断`, T`缺料、无可用设备等异常以红色阻断呈现并附修复入口,不输出虚假成功状态`],
],
[2200, 7000],
),
);
// ---------------- 附录 ----------------
add(
h1(T`附录:常用口令速查`),
table3(
[T`业务场景`, T`对话指令`],
[
[T`排产`, T`试排一版交期优先 / 按产能均衡排一下 / 换型最小化试排 / 跑一版柔性排产 / 三模式对比`],
[T`方案对比与发布`, T`对比几种策略 → 采用此方案 → 发布这个版本`],
[T`订单分解`, T`执行MRP分解 / 分解订单 SO-001 / 生成采购建议 / 下达MRP建议单`],
[T`紧急插单`, T`插单快评 → 采用插单`],
[T`计划层分析`, T`时间分桶 / 可行性分析 / 能否按期 / 库存投影 / 削峰 / 产供决策`],
[T`订单管理`, T`订单池 / 提交审核 / 批量批准 / 查看预测 / 预测转正`],
[T`知识检索`, T`换线有什么规定 / @知识:标题`],
[T`报表`, T`生成日报 / 版本对比 / 打开仪表盘`],
[T`存档与回滚`, T`存个档 / 回滚`],
[T`数据管理`, T`分析一下数据文件 / 导入完整生产路线 / 清空数据重新初始化`],
],
[2000, 7200],
),
body(T`说明:系统对无法识别的指令会明确提示无法理解或检索未命中,不会虚构响应。遇到红色阻断时,应按修复指引补齐缺失的物料、工艺或资源后重新排产。`),
);
const doc = new Document({
features: { updateFields: false },
sections: [{
properties: {
page: { size: { width: 11906, height: 16838 }, margin: { top: 1440, bottom: 1440, left: 1440, right: 1440 } },
},
headers: {
default: new Header({ children: [para(run(T`工业智核 APS 计划排产智能体 · 图文使用手册`, { size: 18, color: palette.light }), { alignment: AlignmentType.CENTER, spacing: { after: 0 } })] }),
},
footers: {
default: new Footer({ children: [para(new TextRun({ children: [PageNumber.CURRENT], size: 18 }), { alignment: AlignmentType.CENTER, spacing: { after: 0 } })] }),
},
children,
}],
});
fs.writeFileSync(outputPath, await Packer.toBuffer(doc));