# print-ok **Repository Path**: iotplc/print-ok ## Basic Information - **Project Name**: print-ok - **Description**: Print-OK — 所见即所得打印模板设计器,提供 HTTP API 静默打印接口。支持文本、表格、条码、二维码、图表等元素可视化拖拽设计,单文件部署,WMS/ERP 一个请求即可打印。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-04-18 - **Last Updated**: 2026-05-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README

🖨️ Print-OK 打印设计器

一句话让 AI 帮你设计打印模板 · 一个 HTTP 接口让打印机直接出纸
所见即所得的打印模板设计器 · HTTP / 本机 WS / 远程长连接 三通道静默打印 · 一个 EXE 搞定 WMS/ERP 打印需求

Platform Release AI Deploy License

30 秒看懂 · 效果预览 · 快速开始 · 立即下载

--- ## 🎬 功能速览 - 🤖 **AI 一句话生成模板**:描述需求 → 模板自动成型 - 🎨 **拖拽式可视化设计**:所见即所得 · 实时 PDF 预览 - ⚡ **HTTP 一键静默打印**:POST 一下 · 打印机直接出纸 > 📺 **完整视频演示:** [AI 设计报表.mp4](AI设计报表.mp4)(点击下载后本地播放,约 500MB,展示 AI 助手从描述到打印的完整流程) --- ## ✨ 核心卖点 | | 能力 | 说明 | |:---:|:---|:---| | 🤖 | **AI 自然语言设计** | 一句话描述需求,AI 自动生成完整模板;兼容 DeepSeek / Kimi / GPT-4o / 通义千问等所有 OpenAI 协议模型 | | 🎨 | **拖拽可视化设计器** | 文本 / 表格 / 图片 / 条码 / 二维码 / 图表 / 辅助图形,WYSIWYG 所见即所得 | | 🗂️ | **Excel 式表格交互** | 📝 表单表格 + 数据表格均支持**列宽/行高拖拽**、**多级表头合并/拆分**、**Shift 矩形选区**,无需写代码 | | 🧩 | **自由格子多字段混排** | 一个单元格内放任意多个独立子字段(文本/图片/条码/二维码),每个子字段独立控制水平/垂直对齐、字体、颜色、条件格式、数字格式、条码文字显示 | | 📊 | **Excel 报表模式** | 集成 Jspreadsheet CE,类 Excel 编辑体验,支持公式、合并单元格、跨页,PDF + HTML 双通道输出 | | ⚡ | **HTTP + WebSocket 双通道** | 一个 POST 请求即可打印;WebSocket 长连接适合前端高频实时打印场景 | | 🌐 | **远程长连接** | 本机作为 WS 客户端主动连接远程服务端,穿透内网打印机、云端统一下发打印任务 | | 🖨️ | **静默打印无弹窗** | 针式 / 热敏 / 激光打印机全通吃,业务系统无感对接 | | 🏷️ | **原生条码/二维码** | CODE128、EAN13、PDF417、汉信码、DataMatrix 一应俱全 | | 📦 | **单文件部署** | 一个 `.exe` 双击即跑,不装任何运行时,托盘常驻开机自启 | | 🔄 | **批量 & 自动更新** | data 传数组一次多页打印;内置升级机制一键更新 | --- ## 🖼️ 效果预览

WMS 出库单

复杂报表

图表仪表盘

Excel 报表

条码/二维码标签

快递面单

带图表的订单

多页报表

👉 更多示例见下方「模板示例」章节(共 17 个场景模板)

--- ## 🚀 快速开始 只需 3 步,业务系统马上能打印: ```bash # ① 下载并启动(Windows 单文件,双击即跑) ./print-ok.exe # ② 在「设计器」里用 AI 一句话生成模板,或拖拽自行设计,保存拿到 templateId # ③ 业务系统一个 HTTP 请求,打印机直接出纸 curl -X POST http://localhost:12345/print \ -H "Content-Type: application/json; charset=utf-8" \ -d '{"templateId":"tpl_abc123","data":{"orderNo":"CK-001","customer":"张三"}}' ``` 前端需要在浏览器直接调?引入 15KB 的 SDK: ```html ``` --- ## 📥 下载 - **最新版下载:** [Gitee Releases](https://gitee.com/iotplc/print-ok/releases) · 单文件约 85MB - **项目主页:** [https://gitee.com/iotplc/print-ok](https://gitee.com/iotplc/print-ok) - **技术交流:** 扫码加微信(见文末 `wechat-qr.png`) > 💡 **免费使用策略**:个人和中小团队免费使用(打印结果带轻量水印,不影响日常使用);企业批量商用请扫码联系授权。 ---

↓ 下方为完整使用手册,包含设计器全功能、API 对接、模板示例、故障排查等 ↓

--- # Print-OK 打印设计器 — 用户使用手册 ## 一、产品简介 Print-OK 是一款所见即所得的打印模板设计器桌面应用。支持可视化拖拽设计打印模板,实时预览 PDF 效果,并提供 HTTP API、本机 WebSocket、远程长连接 三种接入方式供外部业务系统(如 WMS、ERP、云端主机)直接调用静默打印。 **核心特性:** - 可视化拖拽设计,支持文本、图片、条码、二维码、数据表格、图表、辅助图形等元素 - **AI 助手**:自然语言描述需求,AI 自动生成或优化打印模板(兼容 OpenAI API 协议) - 公式计算、条件格式、富文本标记、**系统变量**(页码/总页/打印时间/打印日期/模板名称等)等高级数据处理能力 - **页眉页脚**:支持将元素指定为页眉/页脚区域,每页自动重复渲染 - 实时 PDF 预览、下载、打印 - 模板持久化存储,支持导入导出 JSON - **Excel 报表模式**:集成 Jspreadsheet CE,支持类 Excel 编辑体验,双通道输出(PDF + HTML 打印) - HTTP API 接口,外部系统可通过网络请求直接静默打印 - **WebSocket 长连接打印**:支持 WebSocket 通道,适合需要保持长连接的前端应用或实时打印场景 - **远程长连接**:本机作为 WS 客户端主动连接远程服务端,穿透内网打印机,云端统一下发打印任务 - 单文件部署,无需安装 - 系统托盘常驻,关闭窗口自动最小化 - 单实例运行保护,避免重复启动 - 授权激活管理,试用版自动添加水印,激活后水印消失 - 自动检查更新,一键升级到最新版本 --- ## 二、安装与启动 ### 2.1 安装 将 `print-ok.exe` 复制到任意目录即可,无需安装。首次运行时会在同级目录自动生成 `print-ok.db` 数据库文件。 ### 2.2 启动 双击 `print-ok.exe` 启动应用。 - 应用窗口标题为「打印设计器」,默认大小 1280×800 像素 - 启动后会同时开启 HTTP 打印服务(默认端口 12345)和 WebSocket 打印服务(默认端口 12346) - 如果程序已在运行,再次双击会自动激活已有窗口并弹出提示 - 启动后自动检查更新(如已配置更新服务器),有新版本时弹出更新提示 ### 2.3 系统托盘 启动后,系统托盘区会出现 Print-OK 图标。 - **关闭窗口**:点击窗口关闭按钮不会退出程序,而是最小化到系统托盘 - **托盘右键菜单**: - 显示窗口 — 重新显示主窗口 - 隐藏窗口 — 隐藏主窗口 - 退出 — 彻底退出程序 --- ## 三、界面概览 应用包含两个主要页面: ### 3.1 模板列表页 启动后默认进入模板列表页,顶部有 **Tab 切换**: - **📄 打印模板**:传统 Schema 模板设计(拖拽式设计器) - **📊 Excel 报表**:Jspreadsheet CE 电子表格设计模式 功能包括: | 操作 | 说明 | |------|------| | 新建模板/报表 | 根据当前 Tab 创建空白模板或 Excel 报表 | | 打开模板/报表 | 双击或点击行进入对应设计器编辑 | | 删除 | 删除选中项(不可恢复,操作前会二次确认) | | JSON | 查看该模板/报表的打印请求 JSON 示例,含中文注释,支持一键复制纯净 JSON | | 打印机选择 | 下拉选择默认打印机,支持刷新列表;不选则使用系统默认打印机 | | HTTP 端口设置 | 配置 HTTP 打印 API 的监听端口(默认 12345) | | WebSocket 端口设置 | 配置 WebSocket 打印服务的监听端口(默认 12346) | | 远程长连接 | 本机作为 WebSocket 客户端主动连接远程服务端,适合内网打印机穿透或云端统一下发打印任务(见 6.7 节) | ### 3.2 打印模板设计器 设计器由四个区域组成: ``` ┌──────────────── 顶部工具栏 ────────────────┐ │ 缩放 | 对齐 | 撤销重做 | 导入导出 | 保存预览 | AI │ ├────┬──────────────────────┬────┤ │ │ │ 属 │ │ 元 │ │ 性 │ │ 素 │ 设计画布 │ 面 │ │ 工 │ │ 板 │ │ 具 │ │ │ │ 箱 │ │ 页 │ │ │ │ 面 │ │ │ │ / │ │ │ │ 元 │ │ │ │ 素 │ └────┴──────────────────────┴────┘ ``` > 点击工具栏右侧的「AI」按钮可打开 AI 助手侧边面板,用自然语言描述需求即可生成或优化模板。详见「4.8 AI 助手」章节。 ### 3.3 Excel 报表设计器 从模板列表页「📊 Excel 报表」Tab 进入,提供类 Excel 编辑体验: ``` ┌──────────── 工具栏 ────────────┐ │ 返回 | 纸张 | 保存 | 预览 | 打印 | 导入导出 | 数据预览 │ ├──────────────────────────────┤ │ 报表名称:[输入框] │ ├───────┬──────────────────────┤ │ 数据字段 │ │ │───────│ Jspreadsheet 编辑区 │ │ 客户名 │ (类 Excel 单元格编辑) │ │ 订单号 │ │ │ 金额 │ │ │ [+添加] │ │ └───────┴──────────────────────┘ ``` **Excel 报表支持的操作:** | 功能 | 说明 | |------|------| | 单元格编辑 | 直接输入文本/数字,支持合并单元格 | | 行列操作 | 插入/删除行列,拖拽调整列宽 | | 纸张设置 | A3/A4/A5/Letter,横向/纵向 | | 保存 | 保存到数据库,生成唯一 `ssId`(如 `ss3x8k9m`) | | PDF 预览 | 通过 pdfmake 转换后预览 PDF | | HTML 预览 | 生成 HTML 表格在新窗口预览 | | PDF 打印 | 生成 PDF 后发送到打印机静默打印 | | HTML 打印 | 通过浏览器打印对话框打印 | | 导入 | 支持 CSV 和 JSON 文件导入 | | 导出 | 导出为 JSON 文件 | | **数据绑定** | 左侧字段面板管理字段,点击插入 `${key}` 占位符到单元格 | | **数据预览** | 输入测试 JSON 数据,占位符替换后预览 PDF 效果 | > **数据绑定**:在单元格中使用 `${fieldKey}` 占位符,外部系统调用 API 打印时传入 data JSON,引擎自动替换占位符为实际值。例如单元格内容为 `${customerName}`,传入 `{"customerName": "张三"}` 后打印时自动显示为「张三」。 > > **双通道输出**:Excel 报表支持两种输出方式 — PDF(通过 pdfmake 引擎转换,适合精确排版)和 HTML(适合快速打印简单表格)。 --- ## 四、设计器操作 ### 4.1 工具栏 | 功能 | 说明 | |------|------| | 缩放 | 放大/缩小/重置,Ctrl+滚轮以鼠标为中心缩放 | | 对齐 | 选中多个元素后可左/右/顶/底对齐、居中、等间距分布 | | 撤销重做 | Ctrl+Z / Ctrl+Y,最多 50 步 | | 导入导出 | 导出/导入 JSON 文件,或粘贴 JSON 文本导入模板 | | 保存 | Ctrl+S 快捷保存到本地数据库,生成唯一 `tplId`(如 `tpl3x8k9m`) | | 预览 | 实时 PDF 预览、下载、打印 | ### 4.2 元素工具箱 从左侧拖拽元素到画布即可添加: | 分类 | 元素 | |------|------| | 常规 | 文本、长文本、图片 | | 数据 | 条形码(Code128/EAN13/Code39/ITF14)、二维码、GS1-128、PDF417、Data Matrix | | 图表 | 柱状图、折线图、饼图、散点图、雷达图、仪表盘、漏斗图 | | 表格 | 数据表格(支持列宽拖拽、多级表头合并/拆分、自动分页) | | 表单表格 | 📝 Excel 式网格边框容器,支持行高列宽拖拽、单元格合并/拆分、`${key}` 占位符数据绑定 | | 自由格子 | 🧩 单元格内可混排多个独立子字段(文本/图片/条码/二维码),每个子字段独立设置对齐/字体/颜色/条件格式/数字格式/条码文字显示等 | | 辅助 | 横线、竖线、矩形、圆/椭圆、电子签章 | | 页面 | 页码、打印时间、打印日期、记录序号、模板名称 | | WMS专用 | 订单号、客户名称、仓库、日期、单号条码/二维码、GS1追溯码、商品明细 | ### 4.3 画布操作 | 操作 | 方式 | |------|------| | 移动元素 | 拖拽(自动吸附对齐线),方向键微调 1pt,Shift+方向键 10pt | | 缩放元素 | 拖拽四角/四边控制点 | | 平移画布 | 按住鼠标右键拖拽 | | 右键菜单 | 删除、复制、粘贴、置顶/底层 | | 快捷键 | Delete 删除、Ctrl+C/V 复制粘贴、Ctrl+Z/Y 撤销重做、Ctrl+S 保存 | | 标尺 | 画布顶部/左侧显示毫米刻度标尺,`0` 刻度与纸张左上角对齐;滚动画布时标尺随画布联动 | ### 4.4 属性面板 **未选中元素时** — 显示页面属性: | 属性 | 说明 | |------|------| | 纸张 | A3/A4/A5/B4/B5/Letter/Legal 预设,或自定义尺寸(mm) | | 纸张方向 | 纵向 / 横向切换 | | 页边距 | 上/右/下/左四边独立设置(mm) | | 页眉高度 | 页眉区域高度(mm),设置后画布顶部显示页眉区域指示 | | 页脚高度 | 页脚区域高度(mm),设置后画布底部显示页脚区域指示 | > 页眉/页脚区域内的元素会在每页自动重复渲染(类似 Word 的页眉页脚)。将元素拖入页眉/页脚区域后,元素会自动标记为对应区域,设计画布中以条纹背景和角标区分。 **选中元素后** — 显示四个标签页: - **基础**:位置(X/Y)、尺寸(宽/高)、绑定字段、打印可见开关 - **样式**:字体、字号、加粗、斜体、对齐、颜色、背景色 - **边框**:四边独立控制(开关、实线/虚线、线宽、颜色) - **高级**:条码类型、二维码纠错、表格列定义、图表配置、条件格式等 ### 4.5 表格列定义 在高级标签中配置表格列: | 属性 | 说明 | |------|------| | 标题 | 表头显示名 | | 字段名 | 对应数据中的 key | | 宽度 | 数字为固定宽度,`*` 为自动分配剩余空间 | | 对齐 | left / center / right | | 合并 | 勾选后连续相同值自动合并单元格(类似 Excel 合并相同项) | | 显示 | 取消勾选后该列不渲染(可用于隐藏辅助数据列) | **表格高级设置:** | 属性 | 说明 | |------|------| | 每页固定行数 | 设置后每页固定显示指定行数,不足时自动补空行(适合财务单据) | | 自动行高 | 开启后单元格根据内容自动调整高度 | | 布局 | 网格线 / 浅横线 / 无边框 / 仅表头线 | 表格数据超出一页时自动分页,表头每页重复。 ### 4.6 自由格子(freeCell 元素) 🧩 **自由格子** 是一个"单元格即容器"的元素:一个格子里可以放多个互相独立的**子字段**(text / image / qrcode / barcode 任意混排),每个子字段都有自己完整的样式与数据绑定。 **数据模型(两级 fallback)**: - **列级**(freeCell 本体):`fontSize`、`bold`、`alignment`、`cellWidth`、`cellHeight` 等,作为所有子字段的默认值 - **子字段**(`content` 数组项):同名属性若填写则**覆盖**列级;未填写则继承列级。同一规则作用于设计画布 / PDF / 占位预览,保证设计态与打印效果一致 **子字段支持的属性**: | 属性 | 说明 | |------|------| | `type` | `text` / `image` / `qrcode` / `barcode` | | `field` / `text` | 数据绑定字段 key 或静态文本 | | `alignment` | 水平对齐:`left` / `center` / `right` | | `verticalAlign` | 垂直对齐:`top` / `middle` / `bottom`(**需先设置 `cellHeight` 才生效**) | | `fontSize` / `bold` / `italics` / `color` / `textDecoration` | 字号、加粗、斜体、颜色、下划线/删除线/上划线 | | `textFormat` | 数字/日期格式化模板(如 `¥0.00`、`yyyy-MM-dd`) | | `conditionalFormat` | 条件格式规则(与表格列同语法) | | `barcodeShowText` | 条码子字段:是否在条码下方显示文字,默认 `true` | | `barcodeType` | 条码子字段独立条码类型 | **属性面板操作(子字段选中态)**:点击选中自由格子后,再次点击某子字段切换到"子字段选中态",面板展示独立的水平/垂直对齐按钮组(⇠≡⇢ / ⇞≡⇟)、字号/加粗/颜色/下划线开关、数字格式向导、条件格式编辑器;barcode 类型额外显示 ☑ 显示条码文字。数字格式向导确认后**优先写入子字段 `textFormat`**,非子字段态才回落到列级 `summaryFormat`。 **复合选中 · 键盘快捷 · 拖拽调序**: - Ctrl/⌘ + 点击追加选中、Shift + 点击区间选中;批量改动会同步写入所有被选中子字段 - ↑ / ↓ 在子字段之间切换;Delete 删除;Esc 返回列级选中 - 按住子字段拖到同一格子内目标位置,自动调整 `content` 数组顺序 ### 4.7 数据绑定与高级功能 - **字段绑定**:元素通过 `field` 属性绑定数据字段,打印时自动替换为实际值;表格通过 `tableField` 绑定数组 - **公式计算**:文本中可用 `{SUM(items.qty)}`、`{AVG(...)}`、`{COUNT(...)}`、`{MAX(...)}`、`{MIN(...)}` 自动求值 - **系统变量**:文本内容支持以下占位符,打印时自动替换为实际值: - `{{pageNumber}}` — 当前页码(多页时每页动态更新) - `{{pageCount}}` — 总页数 - `{{printTime}}` — 打印时间(格式:2026-04-16 10:30:45) - `{{printDate}}` — 打印日期(格式:2026-04-16) - `{{recordIndex}}` — 当前记录序号(批量打印时,从 1 开始) - `{{recordCount}}` — 记录总数(批量打印时的数据条数) - `{{tplName}}` — 当前模板名称 - 组合示例:`第 {{pageNumber}} 页 / 共 {{pageCount}} 页 {{printTime}}` - **富文本标记**(段内混排):`**加粗**`、`*斜体*`、`__下划线__`、`~~删除线~~`、`{red:红色文字}`,可嵌套如 `**{red:紧急}**`。**整段**样式请用属性面板的「加粗/颜色/斜体」开关;仅「一句话里只有几个字要高亮」时才用标记 - **条件格式**:根据数据动态改变样式(如 `qty > 100` 时红色加粗) - **套打辅助线**:取消「打印可见」后元素仅在设计器显示,PDF 中跳过 ### 4.8 AI 助手 Print-OK 内置 AI 助手,可通过自然语言描述需求自动生成打印模板或优化现有模板,大幅提升模板设计效率。 #### AI 配置 首次使用前需在模板列表页配置 AI 参数: | 配置项 | 说明 | |--------|------| | API 地址 | OpenAI 兼容的 API 地址(如 `https://api.moonshot.cn/v1`) | | API Key | 对应 API 服务的密钥 | | 模型 | 模型名称(默认 `kimi-k2-0711-preview`,可改为其他兼容模型) | | Max Tokens | 最大输出 Token 数(默认 8192,复杂模板建议 16384) | > **兼容性**:支持所有遵循 OpenAI Chat Completions API 协议的服务,包括但不限于:Moonshot (Kimi)、OpenAI (GPT-4o)、通义千问、DeepSeek 等。只需填写对应服务的 API 地址和密钥即可。 #### 使用方式 1. 在设计器中点击工具栏右侧的「AI」按钮,打开 AI 助手侧边面板 2. 在输入框中用自然语言描述需求,按 Enter 发送 3. AI 返回模板后,点击「应用到设计器」按钮将模板加载到画布中 4. 可继续在输入框中追加指令进一步优化 **自动模式判断:** - **生成模式**:当画布为空时,AI 根据需求描述从零生成完整模板 - **优化模式**:当画布已有内容时,AI 在现有模板基础上进行修改优化 两种模式无需手动切换,系统自动判断。 #### 使用示例 | 输入 | 效果 | |------|------| | `设计一个A4出库单,包含单号、日期、客户、商品明细表格` | 生成完整出库单模板 | | `帮我做一个销售统计报表,要有柱状图和数据表格` | 生成带图表+表格的报表模板 | | `把标题字号改大一点,表格加上合计行` | 优化现有模板(修改标题和表格) | | `增加一个页脚,显示页码和打印时间` | 在现有模板上添加页脚元素 | | `改成横向A4纸` | 将现有模板切换为横向布局 | > **提示**:AI 生成的模板中表格元素会自带 `testData`(模拟数据),在设计器预览时自动填充,方便查看表格渲染效果。 --- ## 五、HTTP 打印 API Print-OK 提供 HTTP 接口供外部系统调用,实现静默打印(无需弹出打印对话框)。WMS、ERP 等业务系统只需发送一个 HTTP 请求即可完成打印,无需安装额外驱动或弹窗。 ### 5.1 打印机选择 在模板列表页右上角可以选择默认打印机: - **下拉列表**:自动读取系统已安装的所有打印机 - **刷新按钮**:新连接打印机后可点击刷新重新加载列表 - **清空选择**:可点击清除按钮恢复为系统默认打印机 - HTTP API 调用时,若未指定 `printer` 参数,则使用此处选择的默认打印机 ### 5.2 端口配置 在模板列表页配置 HTTP 端口(默认 12345)和 WebSocket 端口(默认 12346),修改后对应服务自动重启。 ### 5.3 接口说明 | 接口 | 方法 | 说明 | |------|------|------| | `/print` | POST | 主打印接口(schema/模板 + 数据 → 静默打印) | | `/printers` | GET | 获取系统打印机列表(含状态信息) | | `/status` | GET | 获取服务状态(版本号、授权状态) | | `/print-pdf` | POST | 直接打印 PDF 文件(传 base64 或 URL) | | `/print-image` | POST | 直接打印图片(传 base64 或 URL) | | `/print-html` | POST | 直接打印 HTML(通过 Edge/Chrome 转 PDF 后打印) | | `/spreadsheet/:ssId` | GET | 获取 Excel 报表内容(返回报表 JSON 数据) | | `/print-spreadsheet` | POST | Excel 报表数据绑定打印(模板 ID + 数据 → 替换占位符后打印) | 所有接口 Content-Type 为 `application/json; charset=utf-8`,超时 30 秒。 ### 5.4 /print 请求参数 | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `schema` | object | 与 templateId 二选一 | 完整模板 JSON(设计器导出的格式) | | `templateId` | string | 与 schema 二选一 | 已保存的模板 ID(如 `tpl3x8k9m`),优先级高于 schema | | `data` | object 或 array | 可选 | 业务数据;传数组时每条数据打一页(批量打印) | | `printer` | string | 可选 | 指定打印机名称,不传则使用全局默认打印机 | | `copies` | number | 可选 | 打印份数,默认 1 | | `offsetX` | number | 可选 | 水平偏移(mm),正值右移,用于套打微调 | | `offsetY` | number | 可选 | 垂直偏移(mm),正值下移,用于套打微调 | | `duplex` | number | 可选 | 双面打印模式(保留,依赖打印机驱动支持) | | `quality` | number | 可选 | 打印质量(保留) | | `color` | number | 可选 | 彩色/黑白(保留) | | `forcePaperSize` | boolean | 可选 | 强制按指定纸张尺寸打印。**通常无需传递**,程序会自动从 schema 的 `pageSize` 提取纸张尺寸并设置打印机 | | `paperWidthMM` | number | 可选 | 纸张宽度(mm),手动指定时需配合 `forcePaperSize=true` | | `paperHeightMM` | number | 可选 | 纸张高度(mm),手动指定时需配合 `forcePaperSize=true` | > **优先级**:`templateId` > `schema`。两个都传时以 `templateId` 为准。 > > **打印机优先级**:请求中的 `printer` > 模板列表页选择的默认打印机 > 系统默认打印机。 > > **纸张尺寸自动匹配**:程序会自动从 schema 的 `panels[0].pageSize`(pt 单位)提取纸张宽高并转换为 mm,通过 Windows DEVMODE API 临时修改打印机纸张尺寸,打印完成后自动恢复原始设置。**调用方通常无需传递 `forcePaperSize` 参数**,系统自动确保物理打印纸张与设计时一致。 > > 如需覆盖自动提取的值(例如设计 A4 但希望强制打印到自定义尺寸),可显式传 `forcePaperSize=true` + `paperWidthMM` + `paperHeightMM`,此时以手动指定值为准。 ### 5.5 schema 结构说明 `schema` 即设计器导出的模板 JSON,结构如下: ```json { "name": "模板名称", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "headerHeight": 28, "footerHeight": 28, "elements": [ ... ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } } ``` **pageSize 常用值(pt):** | 纸张 | width | height | |------|-------|--------| | A4 | 595.28 | 841.89 | | A5 | 419.53 | 595.28 | | A3 | 841.89 | 1190.55 | **元素类型与关键属性:** | 元素 type | 核心属性 | 说明 | |-----------|----------|------| | `text` | `text`, `field`, `fontSize`, `bold`, `alignment` | 文本,可绑定数据字段 | | `table` | `tableField`, `tableColumns`, `tableHeaderRows`, `tableRowsPerPage`, `tableSummary` | 数据表格,支持合并单元格、固定行数、统计行 | | `barcode` | `barcodeText`/`field`, `barcodeType` | 条形码(code128/ean13/code39/itf14/gs1-128/pdf417/datamatrix/hanxin) | | `qrcode` | `qr`/`field`, `eccLevel` | 二维码(纠错 L/M/Q/H) | | `image` | `image`/`field`, `imageFit`, `opacity` | 图片(dataURI 或 URL),支持透明度 | | `chart` | `chartType`, `chartDataField`, `chartValueField` | ECharts 图表(bar/line/pie/scatter/radar/gauge/funnel) | | `hline` | `lineWidth`, `lineColor` | 横线 | | `vline` | `lineWidth`, `lineColor` | 竖线 | | `rect` | `lineWidth`, `lineColor` | 矩形框 | | `ellipse` | `lineWidth`, `lineColor` | 圆/椭圆框 | 所有元素共有属性:`id`、`type`、`absolutePosition: {x, y}`、`width`、`height`。 可选通用属性: | 属性 | 说明 | |------|------| | `field` | 数据绑定,打印时自动用 `data` 中对应字段的值替换内容 | | `printVisible` | 设为 `false` 时元素仅在设计器中可见,不输出到 PDF(套打辅助线) | | `rotation` | 旋转角度(度),正数顺时针,如 `45` 表示顺时针旋转 45° | | `zIndex` | 层叠顺序,数值越大越靠前 | | `locked` | 设为 `true` 时元素在设计器中锁定,不可拖拽/缩放 | | `opacity` | 透明度(0~1),适用于图片/签章叠加 | | `conditionalRules` | 条件格式规则数组,根据数据动态覆盖样式 | | `region` | 元素所属区域:`"header"` 页眉 / `"footer"` 页脚 / 不设置为正文。页眉页脚元素每页重复渲染 | | `borderTop` / `borderRight` / `borderBottom` / `borderLeft` | 四边独立边框,每边包含 `enabled`、`style`(solid/dashed)、`width`、`color` | ### 5.6 响应格式 **成功:** ```json { "success": true, "msg": "打印成功", "status": 200, "data": { "licensed": true }, "lcRes": true, "timestamp": 1700000000000 } ``` > 响应中 `data.licensed` 字段表示当前授权状态,调用方可据此判断打印结果是否带水印。 **失败:** ```json { "success": false, "msg": "打印失败", "status": 200, "data": { "error": "具体错误信息" }, "lcRes": true, "timestamp": 1700000000000 } ``` **预览模式响应(界面开启预览开关时):** ```json { "success": true, "msg": "预览已展示", "status": 200, "data": { "preview": true, "licensed": true }, "lcRes": true, "timestamp": 1700000000000 } ``` > 预览模式由模板列表页的「预览模式」开关控制(参考 HttpPrinter 的 isPreview 配置),开启后所有打印接口均不发送到打印机,而是在客户端界面弹窗展示 PDF 预览,用户确认后可手动点击「打印」。 ### 5.7a 其他接口说明 #### GET /printers 获取系统打印机列表: ```json { "success": true, "data": [ { "name": "HP LaserJet Pro", "statusText": "ready", "isDefault": true }, { "name": "Canon iP7200", "statusText": "ready", "isDefault": false } ] } ``` #### GET /status 获取服务状态: ```json { "success": true, "data": { "version": "1.0.0", "licensed": true } } ``` #### POST /print-pdf 直接打印 PDF 文件: | 字段 | 类型 | 说明 | |------|------|------| | `base64` | string | PDF 的 base64 编码(与 url 二选一) | | `url` | string | PDF 的下载地址(与 base64 二选一) | | `printer` | string | 可选,指定打印机 | | `copies` | number | 可选,份数,默认 1 | | `forcePaperSize` | boolean | 可选,强制按指定纸张尺寸打印 | | `paperWidthMM` | number | 可选,纸张宽度(mm) | | `paperHeightMM` | number | 可选,纸张高度(mm) | #### POST /print-image 直接打印图片: | 字段 | 类型 | 说明 | |------|------|------| | `base64` | string | 图片的 base64 编码(与 url 二选一) | | `url` | string | 图片的下载地址(与 base64 二选一) | | `printer` | string | 可选,指定打印机 | | `width` | number | 可选,图片宽度(mm),默认 A4 宽 | | `height` | number | 可选,图片高度(mm),默认 A4 高 | | `copies` | number | 可选,份数,默认 1 | | `forcePaperSize` | boolean | 可选,强制按图片尺寸设置打印机纸张 | #### POST /print-html 打印 HTML 源码(通过 Edge/Chrome 浏览器 headless 模式转 PDF 后打印): | 字段 | 类型 | 说明 | |------|------|------| | `html` | string | 必填,HTML 源码内容 | | `paperWidth` | string | 可选,纸张宽度,如 `"75mm"`、`"21cm"`、`"8.5in"` | | `paperHeight` | string | 可选,纸张高度,如 `"130mm"`、`"29.7cm"` | | `margin` | string | 可选,页边距,如 `"5mm"`,默认 `"0"` | | `printer` | string | 可选,指定打印机 | | `copies` | number | 可选,份数,默认 1 | > **依赖**:需要系统安装 Microsoft Edge 或 Google Chrome 浏览器(优先使用 Edge)。程序自动查找浏览器路径,无需额外配置。 > > **中文支持**:自动注入 UTF-8 编码声明和 BOM,确保中文不乱码。 > > **纸张大小**:支持 `mm`、`cm`、`in` 单位,不带单位时默认当作 mm。同时会在 HTML 中注入 `@page` CSS 规则控制打印纸张大小。 #### GET /spreadsheet/:ssId 获取 Excel 报表内容(供外部系统获取报表 JSON 后自行渲染或打印): **请求示例:** ``` GET http://localhost:12345/spreadsheet/ss3x8k9m ``` **成功响应:** ```json { "success": true, "msg": "ok", "status": 200, "data": { "ssId": "ss3x8k9m", "content": { "data": [["..."]], "columns": [{"title": "A", "width": 100}], "mergeCells": {}, "style": {}, "meta": {"paper": {"width": 595.28, "height": 841.89}, "name": "报表名称"} } }, "timestamp": 1700000000000 } ``` > `content` 字段包含完整的电子表格数据,外部系统可据此自行渲染表格或填充数据后生成打印内容。 #### POST /print-spreadsheet Excel 报表数据绑定打印:通过报表 ID 加载模板,将 `data` 中的字段值替换模板中的 `${key}` 占位符后生成 PDF 并打印。 **请求参数:** | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | `ssId` | string | 是 | 报表 ID(如 `ss3x8k9m`) | | `data` | object | 可选 | 业务数据 JSON,用于替换占位符 | | `printer` | string | 可选 | 指定打印机名称 | | `copies` | number | 可选 | 打印份数,默认 1 | | `forcePaperSize` | boolean | 可选 | 强制按指定纸张尺寸打印。通常无需传递,程序自动从报表纸张配置提取 | | `paperWidthMM` | number | 可选 | 纸张宽度(mm),手动覆盖时配合 `forcePaperSize=true` | | `paperHeightMM` | number | 可选 | 纸张高度(mm),手动覆盖时配合 `forcePaperSize=true` | **请求示例:** ```json POST http://localhost:12345/print-spreadsheet Content-Type: application/json; charset=utf-8 { "ssId": "ss3x8k9m", "data": { "customerName": "张三", "orderNo": "CK-2025-001", "amount": "12800.00" }, "printer": "HP LaserJet", "copies": 1 } ``` **成功响应:** ```json { "success": true, "msg": "ok", "status": 200 } ``` > **工作原理**:服务端根据 `ssId` 加载报表模板,封装为 `{"type":"spreadsheet", "content": <报表JSON>}` 发送到前端渲染引擎。引擎遍历所有单元格,将 `${key}` 占位符替换为 `data` 中对应的值,然后生成 PDF 并发送到打印机。 ### 5.7 打印机设置 默认打印机在模板列表页下拉选择,也可通过 HTTP API 的 `printer` 参数每次请求单独指定。优先级规则: 1. 若 HTTP 请求中指定了 `printer` 参数,使用该打印机 2. 否则使用模板列表页选择的默认打印机 3. 若未选择任何打印机,使用系统默认打印机 ### 5.8 打印流程 ``` 外部系统 ──POST /print──▶ Print-OK 接收请求 │ 加载模板 → 生成 PDF → 静默打印 → 打印机 │ 外部系统 ◀──JSON 响应─────────┘ ``` 1. 外部系统发送 HTTP POST 请求到 `/print` 2. Print-OK 解析请求,如使用 `templateId` 则从数据库加载模板 3. 根据模板和数据自动生成 PDF 4. 调用打印工具执行静默打印(优先 PDFtoPrinter,失败自动回退 SumatraPDF) 5. 返回打印结果给调用方 超时时间为 30 秒,超时将返回错误。 > **打印工具说明**:程序内置两个打印工具(均嵌入在 exe 中,首次使用时自动释放): > - **PDFtoPrinter**(主):基于 Windows GDI 渲染,页眉页脚位置更准确 > - **SumatraPDF**(备):PDFtoPrinter 失败时自动回退使用,以 fit-to-page 模式打印 > > 用户无需手动干预,程序自动选择可用工具。 ### 5.9 调用示例 #### 示例 1:纯文本 — 简单标题 + 数据绑定 最基本的调用方式,使用文本元素和 `field` 数据绑定: ```json { "schema": { "name": "纯文本测试", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 180, "y": 50 }, "width": 240, "height": 40, "text": "出库单", "fontSize": 28, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "text", "absolutePosition": { "x": 50, "y": 120 }, "width": 200, "height": 20, "field": "orderNo", "text": "单号", "fontSize": 12, "id": "e_no" }, { "type": "text", "absolutePosition": { "x": 300, "y": 120 }, "width": 200, "height": 20, "field": "date", "text": "日期", "fontSize": 12, "id": "e_date" }, { "type": "text", "absolutePosition": { "x": 50, "y": 150 }, "width": 200, "height": 20, "field": "customer", "text": "客户", "fontSize": 12, "id": "e_cust" }, { "type": "text", "absolutePosition": { "x": 300, "y": 150 }, "width": 200, "height": 20, "field": "warehouse", "text": "仓库", "fontSize": 12, "id": "e_wh" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "orderNo": "CK-20250416-001", "date": "2025-04-16", "customer": "张三有限公司", "warehouse": "主仓库A区" } } ``` **渲染效果:** ![示例1渲染效果](images/example-1.png) #### 示例 2:表格 — WMS 出库单 演示表格元素(`type: table`)配合 `tableField` 绑定数组数据: ```json { "schema": { "name": "WMS出库单", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 200, "y": 40 }, "width": 200, "height": 35, "text": "WMS 出库单", "fontSize": 24, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "text", "absolutePosition": { "x": 50, "y": 90 }, "width": 250, "height": 18, "field": "orderNo", "text": "单号", "fontSize": 11, "id": "e_no" }, { "type": "text", "absolutePosition": { "x": 350, "y": 90 }, "width": 200, "height": 18, "field": "date", "text": "日期", "fontSize": 11, "id": "e_date" }, { "type": "table", "absolutePosition": { "x": 50, "y": 120 }, "width": 500, "height": 150, "tableField": "items", "tableHeaderRows": 1, "tableColumns": [ { "title": "序号", "field": "index", "width": 40, "alignment": "center" }, { "title": "商品名称", "field": "name", "width": "*" }, { "title": "SKU", "field": "sku", "width": 100 }, { "title": "数量", "field": "qty", "width": 60, "alignment": "center" }, { "title": "单位", "field": "unit", "width": 50, "alignment": "center" } ], "id": "e_table" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "orderNo": "CK-20250416-002", "date": "2025-04-16", "items": [ { "index": 1, "name": "苹果 iPhone 15 Pro Max 256GB", "sku": "SKU-IP15PM-256-BK", "qty": 10, "unit": "台" }, { "index": 2, "name": "华为 Mate 60 Pro", "sku": "SKU-HW-M60P", "qty": 5, "unit": "台" }, { "index": 3, "name": "USB-C 数据线 1.5m", "sku": "SKU-USBC-150", "qty": 100, "unit": "根" }, { "index": 4, "name": "蓝牙耳机 FreeBuds Pro 3", "sku": "SKU-FB-PRO3", "qty": 20, "unit": "副" }, { "index": 5, "name": "手机壳 透明硅胶", "sku": "SKU-CASE-CLR", "qty": 50, "unit": "个" } ] } } ``` > **表格列宽说明**:`width` 为数字时表示固定宽度(pt),为 `"*"` 时自动分配剩余空间。 **渲染效果:** ![示例2渲染效果](images/example-2.png) #### 示例 3:条形码 — 发货条码标签 演示条形码元素(`type: barcode`)通过 `field` 绑定数据: ```json { "schema": { "name": "条码标签", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 180, "y": 40 }, "width": 240, "height": 30, "text": "发货条码", "fontSize": 22, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "barcode", "absolutePosition": { "x": 50, "y": 130 }, "width": 300, "height": 80, "field": "orderNo", "barcodeText": "DEFAULT", "barcodeType": "code128", "id": "e_barcode" }, { "type": "text", "absolutePosition": { "x": 50, "y": 230 }, "width": 300, "height": 20, "field": "customer", "text": "客户", "fontSize": 12, "id": "e_cust" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "orderNo": "SF20250416003", "customer": "李四科技有限公司" } } ``` > 条码类型说明:`barcodeType` 支持 `code128`(默认)、`ean13`、`code39`、`itf14`、`gs1-128`、`pdf417`、`datamatrix`、`hanxin`。 **渲染效果:** ![示例3渲染效果](images/example-3.png) #### 示例 4:二维码 — 商品标签 演示二维码元素(`type: qrcode`)和辅助线元素(`type: hline`): ```json { "schema": { "name": "商品标签", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 50, "y": 40 }, "width": 200, "height": 24, "field": "name", "text": "商品名", "fontSize": 16, "bold": true, "id": "e_name" }, { "type": "text", "absolutePosition": { "x": 50, "y": 75 }, "width": 200, "height": 18, "field": "sku", "text": "SKU", "fontSize": 12, "color": "#666666", "id": "e_sku" }, { "type": "text", "absolutePosition": { "x": 50, "y": 100 }, "width": 200, "height": 24, "field": "price", "text": "价格", "fontSize": 20, "bold": true, "color": "#e53935", "id": "e_price" }, { "type": "qrcode", "absolutePosition": { "x": 350, "y": 40 }, "width": 100, "height": 100, "field": "url", "qr": "https://example.com", "id": "e_qr" }, { "type": "hline", "absolutePosition": { "x": 50, "y": 135 }, "width": 500, "height": 1, "lineWidth": 0.5, "lineColor": "#cccccc", "id": "e_line" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "name": "苹果 iPhone 15 Pro Max", "sku": "SKU-IP15PM-256-BK", "price": "¥9,999.00", "url": "https://shop.example.com/product/ip15pm" } } ``` **渲染效果:** ![示例4渲染效果](images/example-4.png) #### 示例 5:综合 — 完整出库单(文字+表格+条码+辅助线) 展示多种元素混合使用的完整单据: ```json { "schema": { "name": "完整出库单", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 180, "y": 30 }, "width": 240, "height": 40, "text": "出库通知单", "fontSize": 26, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "hline", "absolutePosition": { "x": 50, "y": 75 }, "width": 500, "height": 1, "lineWidth": 1, "lineColor": "#333333", "id": "e_topline" }, { "type": "text", "absolutePosition": { "x": 50, "y": 85 }, "width": 200, "height": 18, "field": "orderNo", "text": "单号", "fontSize": 11, "id": "e_no" }, { "type": "text", "absolutePosition": { "x": 300, "y": 85 }, "width": 200, "height": 18, "field": "date", "text": "日期", "fontSize": 11, "id": "e_date" }, { "type": "text", "absolutePosition": { "x": 50, "y": 108 }, "width": 200, "height": 18, "field": "customer", "text": "客户", "fontSize": 11, "id": "e_cust" }, { "type": "text", "absolutePosition": { "x": 300, "y": 108 }, "width": 200, "height": 18, "field": "warehouse", "text": "仓库", "fontSize": 11, "id": "e_wh" }, { "type": "table", "absolutePosition": { "x": 50, "y": 140 }, "width": 500, "height": 180, "tableField": "items", "tableHeaderRows": 1, "tableColumns": [ { "title": "#", "field": "index", "width": 30, "alignment": "center" }, { "title": "品名", "field": "name", "width": "*" }, { "title": "规格", "field": "spec", "width": 100 }, { "title": "数量", "field": "qty", "width": 50, "alignment": "center" }, { "title": "单位", "field": "unit", "width": 40, "alignment": "center" }, { "title": "备注", "field": "remark", "width": 80 } ], "id": "e_table" }, { "type": "barcode", "absolutePosition": { "x": 50, "y": 370 }, "width": 200, "height": 50, "field": "orderNo", "barcodeText": "DEFAULT", "barcodeType": "code128", "id": "e_barcode" }, { "type": "text", "absolutePosition": { "x": 300, "y": 370 }, "width": 200, "height": 16, "text": "制单人:________", "fontSize": 10, "id": "e_maker" }, { "type": "text", "absolutePosition": { "x": 300, "y": 395 }, "width": 200, "height": 16, "text": "审核人:________", "fontSize": 10, "id": "e_auditor" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "orderNo": "CK-20250416-088", "date": "2025-04-16", "customer": "深圳市星辰科技有限公司", "warehouse": "主仓库-B3区", "items": [ { "index": 1, "name": "苹果 iPhone 15 Pro", "spec": "256GB 黑钛", "qty": 10, "unit": "台", "remark": "" }, { "index": 2, "name": "华为 Mate 60 Pro+", "spec": "512GB 雅丹黑", "qty": 5, "unit": "台", "remark": "加急" }, { "index": 3, "name": "USB-C 数据线", "spec": "1.5m 白色", "qty": 200, "unit": "根", "remark": "" }, { "index": 4, "name": "AirPods Pro 2", "spec": "USB-C版", "qty": 30, "unit": "副", "remark": "" }, { "index": 5, "name": "iPad Air M2", "spec": "128GB 星光色", "qty": 8, "unit": "台", "remark": "" }, { "index": 6, "name": "MagSafe 充电器", "spec": "15W", "qty": 50, "unit": "个", "remark": "赠品" }, { "index": 7, "name": "手机钢化膜", "spec": "高清防指纹", "qty": 100, "unit": "张", "remark": "" } ] } } ``` **渲染效果:** ![示例5渲染效果](images/example-5.png) #### 示例 6:批量打印 — data 传数组(每条数据一页) `data` 传入数组时,每个数组元素生成独立一页 PDF,合并后一次性打印: ```json { "schema": { "name": "批量发货标签", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 50, "y": 50 }, "width": 300, "height": 28, "field": "orderNo", "text": "单号", "fontSize": 20, "bold": true, "id": "e_no" }, { "type": "barcode", "absolutePosition": { "x": 50, "y": 100 }, "width": 250, "height": 60, "field": "orderNo", "barcodeText": "DEFAULT", "barcodeType": "code128", "id": "e_bar" }, { "type": "text", "absolutePosition": { "x": 50, "y": 180 }, "width": 400, "height": 20, "field": "customer", "text": "客户", "fontSize": 14, "id": "e_cust" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": [ { "orderNo": "SF20250416-A01", "customer": "张三有限公司" }, { "orderNo": "SF20250416-A02", "customer": "李四科技集团" }, { "orderNo": "SF20250416-A03", "customer": "王五贸易公司" } ] } ``` > 上述示例会打印 3 页,每页使用相同模板但填充不同数据。 **渲染效果(第 1 页):** ![示例6渲染效果](images/example-6.png) #### 示例 7:矩形边框 + 竖线 — 套打模板 演示矩形(`type: rect`)、竖线(`type: vline`)以及套打辅助线(`printVisible: false`)的使用: ```json { "schema": { "name": "入库验收单", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "rect", "absolutePosition": { "x": 40, "y": 30 }, "width": 520, "height": 300, "lineWidth": 1.5, "lineColor": "#000000", "printVisible": false, "id": "e_border" }, { "type": "text", "absolutePosition": { "x": 180, "y": 35 }, "width": 240, "height": 30, "text": "入库验收单", "fontSize": 22, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "hline", "absolutePosition": { "x": 40, "y": 70 }, "width": 520, "height": 1, "lineWidth": 1, "lineColor": "#000000", "id": "e_h1" }, { "type": "text", "absolutePosition": { "x": 50, "y": 78 }, "width": 230, "height": 18, "field": "orderNo", "text": "单号", "fontSize": 11, "id": "e_no" }, { "type": "text", "absolutePosition": { "x": 310, "y": 78 }, "width": 230, "height": 18, "field": "date", "text": "日期", "fontSize": 11, "id": "e_date" }, { "type": "vline", "absolutePosition": { "x": 300, "y": 70 }, "width": 1, "height": 55, "lineWidth": 0.5, "lineColor": "#000000", "id": "e_v1" }, { "type": "text", "absolutePosition": { "x": 50, "y": 100 }, "width": 230, "height": 18, "field": "supplier", "text": "供应商", "fontSize": 11, "id": "e_supplier" }, { "type": "text", "absolutePosition": { "x": 310, "y": 100 }, "width": 230, "height": 18, "field": "warehouse", "text": "仓库", "fontSize": 11, "id": "e_wh" }, { "type": "table", "absolutePosition": { "x": 40, "y": 130 }, "width": 520, "height": 150, "tableField": "items", "tableHeaderRows": 1, "tableColumns": [ { "title": "#", "field": "index", "width": 30, "alignment": "center" }, { "title": "物料名称", "field": "name", "width": "*" }, { "title": "规格型号", "field": "spec", "width": 120 }, { "title": "数量", "field": "qty", "width": 50, "alignment": "center" }, { "title": "验收", "field": "check", "width": 50, "alignment": "center" } ], "id": "e_table" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "orderNo": "RK-20250416-005", "date": "2025-04-16", "supplier": "华强电子供应链", "warehouse": "原材料仓-C1", "items": [ { "index": 1, "name": "电阻 10kΩ 0603", "spec": "0603封装 ±1%", "qty": 5000, "check": "✓" }, { "index": 2, "name": "电容 100nF", "spec": "0805封装 X7R", "qty": 3000, "check": "✓" }, { "index": 3, "name": "LED灯珠 红色", "spec": "0805 20mA", "qty": 2000, "check": "✓" } ] } } ``` > 注意外边框矩形设置了 `printVisible: false`,它仅在设计画布中可见,打印时不输出——适合在已有印刷表单上套打定位。 **渲染效果:** ![示例7渲染效果](images/example-7.png) #### 示例 8:按模板 ID 打印 — 最简调用方式 模板已在设计器中保存后,调用方只需传 `templateId` + `data`,无需关心模板结构: ```json { "templateId": "tpl_abc123", "data": { "orderNo": "CK-20250416-100", "date": "2025-04-16", "customer": "深圳市星辰科技有限公司", "warehouse": "主仓库-A1区", "items": [ { "index": 1, "name": "苹果 iPhone 15 Pro", "sku": "SKU-IP15P", "qty": 10, "unit": "台" }, { "index": 2, "name": "USB-C 数据线 1.5m", "sku": "SKU-USBC", "qty": 200, "unit": "根" } ] } } ``` > `templateId` 可在设计器的模板列表中查看。按模板 ID 也支持 `data` 传数组实现批量打印。 > 此示例使用已保存模板 ID 调用,渲染效果取决于模板设计内容。 #### 示例 9:公式计算 — 自动求和、计数 演示文本元素中使用 `{SUM()}` 和 `{COUNT()}` 公式: ```json { "schema": { "name": "公式计算测试", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 180, "y": 40 }, "width": 240, "height": 30, "text": "出库汇总单", "fontSize": 22, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "table", "absolutePosition": { "x": 50, "y": 90 }, "width": 500, "height": 150, "tableField": "items", "tableHeaderRows": 1, "tableColumns": [ { "title": "品名", "field": "name", "width": "*" }, { "title": "数量", "field": "qty", "width": 60, "alignment": "center" }, { "title": "单价", "field": "price", "width": 80, "alignment": "right" } ], "id": "e_table" }, { "type": "text", "absolutePosition": { "x": 50, "y": 260 }, "width": 500, "height": 20, "text": "共 {COUNT(items)} 种商品,合计数量: {SUM(items.qty)} 件,均价: {AVG(items.price)} 元", "fontSize": 11, "id": "e_summary" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "items": [ { "name": "iPhone 15 Pro", "qty": 10, "price": 8999 }, { "name": "USB-C 数据线", "qty": 200, "price": 15 }, { "name": "AirPods Pro 2", "qty": 30, "price": 1799 } ] } } ``` > 公式会自动求值:“共 3 种商品,合计数量: 240 件,均价: 3604.33 元” **渲染效果:** ![示例9渲染效果](images/example-9.png) #### 示例 10:GS1-128 追溯码 + 条件格式 演示 GS1-128 追溯条码和条件格式(数量超过 50 时红色加粗): ```json { "schema": { "name": "GS1追溯标签", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 50, "y": 40 }, "width": 300, "height": 24, "field": "productName", "text": "商品名", "fontSize": 16, "bold": true, "id": "e_name" }, { "type": "barcode", "absolutePosition": { "x": 50, "y": 80 }, "width": 350, "height": 60, "field": "gs1String", "barcodeText": "(01)06901234567890(17)250101(10)ABC", "barcodeType": "gs1-128", "id": "e_gs1" }, { "type": "text", "absolutePosition": { "x": 50, "y": 160 }, "width": 200, "height": 20, "field": "qty", "text": "数量", "fontSize": 14, "conditionalRules": [ { "field": "qty", "operator": ">", "value": 50, "style": { "color": "#ff0000", "bold": true } } ], "id": "e_qty" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "productName": "苹果 iPhone 15 Pro Max 256GB", "gs1String": "(01)06901234567890(17)260101(10)LOT-A001", "qty": 100 } } ``` > 因为 `qty` 为 100,大于 50,数量字段会自动显示为红色加粗。 **渲染效果:** ![示例10渲染效果](images/example-10.png) #### 示例 11:图表 — 销售报表 演示柱状图、饼图、仪表盘、雷达图四种图表,以及图表标题、颜色主题、显示图例、数据标签等增强属性: ```json { "schema": { "name": "销售报表", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 150, "y": 30 }, "width": 300, "height": 35, "text": "月度销售报表", "fontSize": 24, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "chart", "absolutePosition": { "x": 50, "y": 80 }, "width": 500, "height": 220, "chartType": "bar", "chartTitle": "月销售额", "chartDataField": "monthlySales", "chartCategoryField": "month", "chartValueField": "amount", "chartShowLabel": true, "chartColorScheme": "business", "id": "e_barChart" }, { "type": "text", "absolutePosition": { "x": 50, "y": 310 }, "width": 500, "height": 20, "text": "总销售额: {SUM(monthlySales.amount)} 元", "fontSize": 12, "bold": true, "id": "e_total" }, { "type": "chart", "absolutePosition": { "x": 30, "y": 350 }, "width": 280, "height": 230, "chartType": "pie", "chartTitle": "分类占比", "chartDataField": "categorySales", "chartCategoryField": "category", "chartValueField": "amount", "chartPieInnerRadius": "40%", "chartShowLabel": true, "id": "e_pieChart" }, { "type": "chart", "absolutePosition": { "x": 320, "y": 350 }, "width": 250, "height": 230, "chartType": "gauge", "chartTitle": "目标达成率", "chartDataField": "kpi", "chartValueField": "rate", "chartGaugeMax": 100, "id": "e_gaugeChart" }, { "type": "chart", "absolutePosition": { "x": 100, "y": 600 }, "width": 400, "height": 210, "chartType": "radar", "chartTitle": "产品维度评分", "chartDataField": "radarData", "chartCategoryField": "dim", "chartValueField": "score", "chartColorScheme": "cool", "id": "e_radarChart" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "monthlySales": [ { "month": "1月", "amount": 12000 }, { "month": "2月", "amount": 19000 }, { "month": "3月", "amount": 15000 }, { "month": "4月", "amount": 22000 }, { "month": "5月", "amount": 18000 } ], "categorySales": [ { "category": "手机", "amount": 45000 }, { "category": "配件", "amount": 28000 }, { "category": "平板", "amount": 13000 } ], "kpi": [{ "rate": 78 }], "radarData": [ { "dim": "质量", "score": 85 }, { "dim": "价格", "score": 72 }, { "dim": "服务", "score": 90 }, { "dim": "物流", "score": 68 }, { "dim": "哥码", "score": 95 } ] } } ``` > 本示例展示了 4 种图表类型:柱状图(商务配色 + 数据标签)、饼图(环形图 `chartPieInnerRadius: "40%"`)、仪表盘(`chartGaugeMax: 100`)、雷达图(冷色主题)。图表在设计时显示示例数据预览,打印时自动绑定实际业务数据。 **渲染效果:** ![示例11渲染效果](images/example-11.png) #### 示例 12:折线图 — 趋势分析(平滑曲线 + 堆叠) 演示折线图的平滑曲线(`chartSmooth`)和堆叠模式(`chartStack`): ```json { "schema": { "name": "趋势分析", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 150, "y": 30 }, "width": 300, "height": 35, "text": "周度发货趋势", "fontSize": 24, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "chart", "absolutePosition": { "x": 40, "y": 80 }, "width": 520, "height": 250, "chartType": "line", "chartTitle": "每日发货量", "chartDataField": "dailyShipments", "chartCategoryField": "day", "chartValueField": "qty", "chartSmooth": true, "chartShowLabel": true, "chartShowLegend": true, "chartColorScheme": "cool", "id": "e_lineSmooth" }, { "type": "chart", "absolutePosition": { "x": 40, "y": 360 }, "width": 520, "height": 250, "chartType": "line", "chartTitle": "各仓库累计发货(堆叠)", "chartDataField": "warehouseShipments", "chartCategoryField": "day", "chartValueField": "qty", "chartStack": true, "chartSmooth": true, "chartColorScheme": "warm", "id": "e_lineStack" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "dailyShipments": [ { "day": "周一", "qty": 120 }, { "day": "周二", "qty": 200 }, { "day": "周三", "qty": 150 }, { "day": "周四", "qty": 280 }, { "day": "周五", "qty": 320 }, { "day": "周六", "qty": 180 }, { "day": "周日", "qty": 90 } ], "warehouseShipments": [ { "day": "周一", "qty": 80 }, { "day": "周二", "qty": 130 }, { "day": "周三", "qty": 100 }, { "day": "周四", "qty": 170 }, { "day": "周五", "qty": 210 }, { "day": "周六", "qty": 120 }, { "day": "周日", "qty": 60 } ] } } ``` > `chartSmooth: true` 使折线平滑过渡,`chartStack: true` 使多系列折线堆叠显示面积。 **渲染效果:** ![示例12渲染效果](images/example-12.png) #### 示例 13:散点图 + 漏斗图 — 数据分析 演示散点图(`scatter`)和漏斗图(`funnel`): ```json { "schema": { "name": "数据分析", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 150, "y": 30 }, "width": 300, "height": 35, "text": "数据分析报告", "fontSize": 24, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "chart", "absolutePosition": { "x": 40, "y": 80 }, "width": 520, "height": 260, "chartType": "scatter", "chartTitle": "订单金额与数量相关性", "chartDataField": "orderAnalysis", "chartCategoryField": "qty", "chartValueField": "amount", "chartShowLabel": false, "chartColorScheme": "business", "id": "e_scatter" }, { "type": "chart", "absolutePosition": { "x": 80, "y": 370 }, "width": 440, "height": 280, "chartType": "funnel", "chartTitle": "销售转化漏斗", "chartDataField": "funnel", "chartCategoryField": "stage", "chartValueField": "count", "chartShowLabel": true, "chartShowLegend": true, "chartColorScheme": "default", "id": "e_funnel" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "orderAnalysis": [ { "qty": 5, "amount": 1200 }, { "qty": 12, "amount": 3500 }, { "qty": 8, "amount": 2100 }, { "qty": 20, "amount": 6800 }, { "qty": 15, "amount": 4200 }, { "qty": 3, "amount": 800 }, { "qty": 25, "amount": 8500 }, { "qty": 18, "amount": 5600 }, { "qty": 10, "amount": 2900 }, { "qty": 30, "amount": 9200 } ], "funnel": [ { "stage": "访问", "count": 10000 }, { "stage": "咨询", "count": 5000 }, { "stage": "报价", "count": 2000 }, { "stage": "下单", "count": 800 }, { "stage": "成交", "count": 500 } ] } } ``` > 散点图适合分析两个数值字段的相关性(X 轴为 `qty`,Y 轴为 `amount`)。漏斗图适合展示流程各阶段的转化数据。 **渲染效果:** ![示例13渲染效果](images/example-13.png) #### 示例 14:仪表盘高级 — 分段颜色 + 自定义 Option 演示仪表盘分段颜色(`chartGaugeSegments`)和自定义 ECharts Option(`chartOption`): ```json { "schema": { "name": "设备监控", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 150, "y": 30 }, "width": 300, "height": 35, "text": "设备运行监控", "fontSize": 24, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "chart", "absolutePosition": { "x": 50, "y": 80 }, "width": 240, "height": 220, "chartType": "gauge", "chartTitle": "CPU 使用率", "chartDataField": "cpu", "chartValueField": "usage", "chartGaugeMax": 100, "chartGaugeSegments": "[[0.3,\"#3cbbb1\"],[0.7,\"#2e86c1\"],[1,\"#e74c3c\"]]", "id": "e_cpu" }, { "type": "chart", "absolutePosition": { "x": 310, "y": 80 }, "width": 240, "height": 220, "chartType": "gauge", "chartTitle": "内存使用率", "chartDataField": "memory", "chartValueField": "usage", "chartGaugeMax": 100, "chartGaugeSegments": "[[0.5,\"#27ae60\"],[0.8,\"#d4a017\"],[1,\"#e74c3c\"]]", "id": "e_memory" }, { "type": "chart", "absolutePosition": { "x": 40, "y": 330 }, "width": 520, "height": 280, "chartType": "bar", "chartTitle": "各产线产量", "chartDataField": "production", "chartCategoryField": "line", "chartValueField": "output", "chartStack": true, "chartShowLabel": true, "chartColorScheme": "warm", "id": "e_production" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "cpu": [{ "usage": 72 }], "memory": [{ "usage": 85 }], "production": [ { "line": "A线", "output": 1200 }, { "line": "B线", "output": 980 }, { "line": "C线", "output": 1500 }, { "line": "D线", "output": 760 } ] } } ``` > **仪表盘分段颜色**:`chartGaugeSegments` 接受 JSON 数组,格式为 `[[百分比, "颜色"], ...]`。上例中 CPU 仪表盘在 0~30% 为绿色、30~70% 为蓝色、70~100% 为红色,直观展示健康状态。 > **堆叠柱状图**:`chartStack: true` 使柱状图的多系列堆叠显示。 **渲染效果:** ![示例14渲染效果](images/example-14.png) #### 示例 15:柱状图堆叠 + 折线图组合 — 多维度对比 演示柱状图堆叠模式、折线平滑曲线与饼图组合布局: ```json { "schema": { "name": "多维度对比", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 150, "y": 25 }, "width": 300, "height": 30, "text": "季度综合报告", "fontSize": 22, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "chart", "absolutePosition": { "x": 30, "y": 65 }, "width": 540, "height": 230, "chartType": "bar", "chartTitle": "各仓库入库/出库对比", "chartDataField": "warehouseData", "chartCategoryField": "name", "chartValueField": "inbound", "chartStack": true, "chartShowLabel": true, "chartShowLegend": true, "chartColorScheme": "business", "id": "e_barStack" }, { "type": "chart", "absolutePosition": { "x": 30, "y": 310 }, "width": 300, "height": 230, "chartType": "line", "chartTitle": "每日处理量趋势", "chartDataField": "dailyProcess", "chartCategoryField": "date", "chartValueField": "count", "chartSmooth": true, "chartShowLabel": false, "chartColorScheme": "cool", "id": "e_lineTrend" }, { "type": "chart", "absolutePosition": { "x": 340, "y": 310 }, "width": 230, "height": 230, "chartType": "pie", "chartTitle": "异常类型分布", "chartDataField": "errorTypes", "chartCategoryField": "type", "chartValueField": "count", "chartShowLabel": true, "chartColorScheme": "warm", "id": "e_pieError" }, { "type": "text", "absolutePosition": { "x": 30, "y": 560 }, "width": 540, "height": 20, "text": "处理总量: {SUM(dailyProcess.count)} 单 | 异常总数: {SUM(errorTypes.count)} 件", "fontSize": 11, "bold": true, "id": "e_summary" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "warehouseData": [ { "name": "A仓", "inbound": 500 }, { "name": "B仓", "inbound": 380 }, { "name": "C仓", "inbound": 620 }, { "name": "D仓", "inbound": 290 } ], "dailyProcess": [ { "date": "4/10", "count": 120 }, { "date": "4/11", "count": 185 }, { "date": "4/12", "count": 150 }, { "date": "4/13", "count": 210 }, { "date": "4/14", "count": 190 }, { "date": "4/15", "count": 240 }, { "date": "4/16", "count": 175 } ], "errorTypes": [ { "type": "数量差异", "count": 15 }, { "type": "破损", "count": 8 }, { "type": "错发", "count": 5 }, { "type": "其他", "count": 3 } ] } } ``` > 本示例展示在一页内混合布局多种图表:堆叠柱状图(导入/出库对比)+ 平滑折线图(趋势)+ 饼图(异常分布),配合公式求和汇总数据。 **渲染效果:** ![示例15渲染效果](images/example-15.png) #### 示例 16:富文本 + 圆形 + 签章 — 合同确认单 演示富文本标记和圆形辅助元素: ```json { "schema": { "name": "合同确认单", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 150, "y": 40 }, "width": 300, "height": 35, "text": "合同确认单", "fontSize": 24, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "hline", "absolutePosition": { "x": 50, "y": 80 }, "width": 500, "height": 1, "lineWidth": 1.5, "lineColor": "#333333", "id": "e_line" }, { "type": "text", "absolutePosition": { "x": 50, "y": 95 }, "width": 500, "height": 20, "text": "甲方: **{red:深圳市星辰科技有限公司}** 乙方: **{blue:广州实创贸易有限公司}**", "fontSize": 11, "id": "e_parties" }, { "type": "text", "absolutePosition": { "x": 50, "y": 130 }, "width": 500, "height": 40, "text": "经双方协商确认,本批货物已验收合格。\n总金额: **{red:¥128,000.00}**,大写: *壹拾贰万零贰仟元整*", "fontSize": 11, "id": "e_content" }, { "type": "ellipse", "absolutePosition": { "x": 390, "y": 180 }, "width": 90, "height": 90, "lineWidth": 2, "lineColor": "#cc0000", "id": "e_seal_border" }, { "type": "text", "absolutePosition": { "x": 395, "y": 205 }, "width": 80, "height": 20, "text": "**{red:确认}**", "fontSize": 16, "alignment": "center", "id": "e_seal_text" }, { "type": "text", "absolutePosition": { "x": 395, "y": 228 }, "width": 80, "height": 16, "text": "{red:专用章}", "fontSize": 10, "alignment": "center", "id": "e_seal_sub" }, { "type": "text", "absolutePosition": { "x": 50, "y": 290 }, "width": 200, "height": 18, "field": "date", "text": "日期", "fontSize": 11, "id": "e_date" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "date": "2025-04-16" } } ``` > **富文本效果**:`**{red:深圳市星辰科技}**` 会渲染为红色加粗文字。圆形边框 + 红色文字组合模拟印章效果。 > **电子签章**:实际场景中可将椭圆内的文字替换为 `image` 元素(`field: "sealImage"`),传入透明 PNG 的 base64 叠加真实签章图片,并设置 `opacity: 0.8` 实现半透明效果。 **渲染效果:** ![示例16渲染效果](images/example-16.png) #### 示例 17:旋转元素 + 边框样式 — 品检标签 演示元素旋转(`rotation`)和四边独立边框样式: ```json { "schema": { "name": "品检标签", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "rect", "absolutePosition": { "x": 40, "y": 30 }, "width": 520, "height": 250, "lineWidth": 2, "lineColor": "#333333", "id": "e_frame" }, { "type": "text", "absolutePosition": { "x": 150, "y": 35 }, "width": 300, "height": 30, "text": "品质检验标签", "fontSize": 22, "bold": true, "alignment": "center", "id": "e_title" }, { "type": "text", "absolutePosition": { "x": 50, "y": 80 }, "width": 200, "height": 18, "field": "productName", "text": "产品名", "fontSize": 12, "borderBottom": { "enabled": true, "style": "dashed", "width": 0.5, "color": "#999999" }, "id": "e_product" }, { "type": "text", "absolutePosition": { "x": 300, "y": 80 }, "width": 200, "height": 18, "field": "batchNo", "text": "批号", "fontSize": 12, "borderBottom": { "enabled": true, "style": "dashed", "width": 0.5, "color": "#999999" }, "id": "e_batch" }, { "type": "text", "absolutePosition": { "x": 50, "y": 115 }, "width": 200, "height": 18, "field": "inspector", "text": "检验员", "fontSize": 12, "id": "e_inspector" }, { "type": "text", "absolutePosition": { "x": 300, "y": 115 }, "width": 200, "height": 18, "field": "date", "text": "日期", "fontSize": 12, "id": "e_date" }, { "type": "text", "absolutePosition": { "x": 380, "y": 140 }, "width": 120, "height": 80, "field": "result", "text": "合格", "fontSize": 36, "bold": true, "color": "#009900", "alignment": "center", "rotation": -15, "conditionalRules": [ { "field": "result", "operator": "==", "value": "不合格", "style": { "color": "#ff0000" } } ], "id": "e_result" }, { "type": "barcode", "absolutePosition": { "x": 50, "y": 160 }, "width": 250, "height": 55, "field": "batchNo", "barcodeText": "DEFAULT", "barcodeType": "code128", "id": "e_barcode" }, { "type": "text", "absolutePosition": { "x": 50, "y": 230 }, "width": 450, "height": 16, "text": "备注: {gray:此标签由系统自动打印,不可涂改}", "fontSize": 9, "id": "e_remark" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "productName": "USB-C 数据线 1.5m", "batchNo": "QC-20250416-B03", "inspector": "王工", "date": "2025-04-16", "result": "合格" } } ``` > **旋转效果**:「合格」文字旋转 -15° 斜置,模拟印章效果。同时通过条件格式判断结果为“不合格”时自动变为红色。 > **边框样式**:产品名和批号下方各有一条虚线底边框(`borderBottom`),四边边框可独立开关和配置样式。 **渲染效果:** ![示例17渲染效果](images/example-17.png) #### 示例 18:系统变量 — 页码 + 打印时间 演示在文本元素中使用 `{{pageNumber}}`、`{{pageCount}}`、`{{printTime}}` 系统变量。含页码变量的元素会在每页自动渲染并更新为实际值: ```json { "schema": { "name": "系统变量演示", "version": "1.0", "panels": [{ "index": 0, "pageSize": { "width": 595.28, "height": 841.89 }, "pageMargins": [0, 0, 0, 0], "elements": [ { "type": "text", "absolutePosition": { "x": 40, "y": 30 }, "width": 300, "height": 20, "text": "出库明细报表", "fontSize": 18, "bold": true, "id": "e_title" }, { "type": "text", "absolutePosition": { "x": 400, "y": 35 }, "width": 160, "height": 16, "text": "打印时间: {{printTime}}", "fontSize": 9, "color": "#666666", "alignment": "right", "id": "e_time" }, { "type": "text", "absolutePosition": { "x": 220, "y": 810 }, "width": 160, "height": 16, "text": "第 {{pageNumber}} 页 / 共 {{pageCount}} 页", "fontSize": 9, "color": "#999999", "alignment": "center", "id": "e_pager" }, { "type": "table", "absolutePosition": { "x": 40, "y": 60 }, "width": 515, "height": 400, "tableField": "items", "tableHeaderRows": 1, "tableColumns": [ { "title": "商品名称", "field": "name", "width": "*" }, { "title": "数量", "field": "qty", "width": 60, "alignment": "center" }, { "title": "单价", "field": "price", "width": 80, "alignment": "right" } ], "id": "e_table" } ] }], "defaultStyle": { "font": "NotoSansSC", "fontSize": 10 } }, "data": { "items": [ { "name": "商品A", "qty": 100, "price": 25.5 }, { "name": "商品B", "qty": 50, "price": 128 }, { "name": "商品C", "qty": 200, "price": 8.9 } ] } } ``` > **说明**: > - `{{printTime}}` 在 PDF 生成时替换为实际时间(如 `2026-04-16 10:30:45`) > - `{{pageNumber}}` 和 `{{pageCount}}` 在每页动态更新,表格数据较多跨页时自动显示正确页码 > - 含页码变量的元素会在所有页面重复渲染(类似页眉页脚效果) #### 示例 19:复杂 form — 货物验收确认单(9×5 网格 + 7 处合并 + 二维码 + 印章 + 签字分栏) 演示 📝 **表单表格(form)** 在真实单据中的深度能力:form 只画网格骨架,内容由叠加的 `text / qrcode / rect` 元素承载。完整示例请见 `doc/使用手册.md` 示例 22,此处给出核心 schema 片段以展示复杂度。 **网格预览:** ``` ┌─────────────────────────────────────────────┐ 行0 标题跨 5 列 │ 货 物 验 收 确 认 单(表头染色) │ ├──────┬──────────┬──────┬──────────┬─────────┤ │单号 │${orderNo}│业务 │${bizType}│ │ 行1 ├──────┼──────────┴──────┴──────────┤ 二维码 │ 行2 供应商跨 3 列 │供应商│${supplier} │ 合并 5 行│ ├──────┼──────────┬──────┬──────────┤ 1 列 │ 行3-5 │仓库 │${wh} │经办人│${handler}│ (竖向跨行)│ ├──────┴──────────┴──────┴──────────┴─────────┤ │ 备注:${remark}(跨 5 列 + 55pt 高行) │ 行6 ├──────┬──────────────────────────────────────┤ │结论 │{green:${conclusion}} [红色印章] │ 行7 值跨 4 列 ├──────┴──────────┬───────────────────────────┤ │甲方签字(2 列宽)│ 乙方签字(3 列宽,非对称分栏)│ 行8 └──────────────────┴───────────────────────────┘ ``` ```json { "type": "form", "absolutePosition": { "x": 50, "y": 60 }, "width": 495, "height": 288, "formRows": 9, "formCols": 5, "formHeaderRows": 1, "formColWidths": [65, "*", 65, "*", 95], "formRowHeights": [32, 26, 26, 26, 26, 26, 55, 26, 45], "formMerges": [ { "r": 0, "c": 0, "rs": 1, "cs": 5 }, { "r": 1, "c": 4, "rs": 5, "cs": 1 }, { "r": 2, "c": 1, "rs": 1, "cs": 3 }, { "r": 6, "c": 0, "rs": 1, "cs": 5 }, { "r": 7, "c": 1, "rs": 1, "cs": 4 }, { "r": 8, "c": 0, "rs": 1, "cs": 2 }, { "r": 8, "c": 2, "rs": 1, "cs": 3 } ], "formBorderColor": "#333333", "formBorderWidth": 0.8, "formHeaderBg": "#eef4fb" } ``` **7 处合并覆盖的核心场景:** | 合并 | 语义 | 现实用途 | |------|------|---------| | `{r:0, c:0, cs:5}` | 横跨 5 列 | 单据标题通栏 | | `{r:1, c:4, rs:5}` | **纵跨 5 行** | 右侧二维码 / LOGO 区 | | `{r:2, c:1, cs:3}` | 中间跨 3 列 | 长字段(供应商全名) | | `{r:6, c:0, cs:5}` | 整行 + 55pt 高 | 多行备注 | | `{r:7, c:1, cs:4}` | 保留标签列,值跨 4 列 | 结论 + 印章叠加 | | `{r:8, c:0, cs:2}` + `{r:8, c:2, cs:3}` | **非对称分栏** | 甲/乙签字 2:3 布局 | **叠加元素(共约 25 个):** - `1 个 form` 网格骨架 - `22 个 text` 提供标题、标签、值、备注、结论、签字 - `1 个 qrcode` 绑定 `{{orderNo}}`,自动生成二维码叠加到合并 5 行的右列中央 - `1 个 rect`(红边)+ `1 个 text`(红字"验 收 合 格")重叠出仿真圆章 **关键能力演示:** - 富文本段内混排(仅局部高亮):`合计:**{red:¥1580.00}**(含税)` — 金额红色加粗、前后黑色 - 条件格式:`urgent == true` 时"业务类型"自动变红加粗 - 多元素叠加:同一合并区内可同时放 text + rect + qrcode,`absolutePosition` 覆盖单元格即可 - 非对称分栏签字:通过 `{r:8, c:0, cs:2}` 与 `{r:8, c:2, cs:3}` 实现 2:3 宽度比 - 灵活混排:`formColWidths: [65, "*", 65, "*", 95]` 让标签列紧凑、内容自适应、二维码列固定宽 ### 5.10 快速测试 #### PowerShell 测试 ```powershell # 将上述任一 JSON 保存为文件,如 test.json,然后执行: $json = Get-Content -Path "test.json" -Raw Invoke-RestMethod -Uri "http://localhost:12345/print" ` -Method Post ` -ContentType "application/json; charset=utf-8" ` -Body ([System.Text.Encoding]::UTF8.GetBytes($json)) ``` #### curl 测试 ```bash curl -X POST http://localhost:12345/print \ -H "Content-Type: application/json; charset=utf-8" \ -d @test.json ``` #### 常见错误排查 | 错误信息 | 原因 | 解决方法 | |----------|------|----------| | 请提供 schema 或 templateId 参数 | 请求体缺少必要字段 | 确认 JSON 中包含 `schema` 或 `templateId` | | 模板 'xxx' 不存在 | templateId 无效 | 在设计器模板列表中确认正确的 templateId | | PDF 生成失败 | 模板格式有误 | 检查 schema JSON 格式是否正确 | | 等待生成 PDF 超时 (30s) | 程序未响应 | 确认程序窗口正常运行(可在托盘中显示窗口) | | 程序未就绪 | 程序刚启动尚未初始化完成 | 等待几秒后重试 | --- ## 六、WebSocket 打印 API Print-OK 同时提供 WebSocket 接口,适合需要长连接、实时双向通信的前端应用场景。WebSocket 接口与 HTTP API 功能完全一致,支持所有打印操作。 ### 6.1 连接地址 ``` ws://localhost:12346/ws ``` 默认端口 12346,可在模板列表页修改。支持跨域连接(已配置 CORS)。 ### 6.2 消息格式 所有消息均为 JSON 格式。每条请求必须包含 `action` 字段指定操作类型,可选 `requestId` 用于异步匹配响应。 **请求通用结构:** ```json { "action": "操作类型", "requestId": "自定义请求ID(可选,用于匹配响应)", ... 其他参数 } ``` **响应通用结构:** ```json { "action": "操作类型", "requestId": "对应请求的ID", "success": true, "msg": "操作结果描述", "status": 200, "data": {}, "lcRes": true, "timestamp": 1700000000000 } ``` ### 6.3 支持的操作 | action | 说明 | 对应 HTTP 接口 | |--------|------|----------------| | `print` | 主打印(schema/模板 + 数据 → 静默打印) | POST /print | | `printers` | 获取系统打印机列表 | GET /printers | | `status` | 获取服务状态(版本号、授权) | GET /status | | `print-pdf` | 直接打印 PDF 文件(base64 或 URL) | POST /print-pdf | | `print-image` | 直接打印图片(base64 或 URL) | POST /print-image | | `print-html` | 打印 HTML 源码 | POST /print-html | | `print-spreadsheet` | Excel 报表数据绑定打印 | POST /print-spreadsheet | 每个 action 的请求参数与对应 HTTP 接口完全相同(参见第五章),额外多一个 `requestId` 字段。 ### 6.4 调用示例 #### 模板打印 ```json { "action": "print", "requestId": "req-001", "templateId": "tpl_abc123", "data": { "orderNo": "CK-20250416-001", "customer": "张三有限公司" }, "printer": "HP LaserJet Pro", "copies": 2 } ``` #### 获取打印机列表 ```json { "action": "printers", "requestId": "req-002" } ``` #### 打印 PDF ```json { "action": "print-pdf", "requestId": "req-003", "base64": "JVBERi0xLjQg...", "printer": "HP LaserJet Pro" } ``` #### 打印图片 ```json { "action": "print-image", "requestId": "req-004", "base64": "/9j/4AAQSkZJ...", "width": 100, "height": 150 } ``` #### 打印 HTML ```json { "action": "print-html", "requestId": "req-005", "html": "

测试打印

Hello World

", "paperWidth": "210mm", "paperHeight": "297mm" } ``` #### Excel 报表打印 ```json { "action": "print-spreadsheet", "requestId": "req-006", "ssId": "ss3x8k9m", "data": { "customerName": "张三", "orderNo": "CK-2025-001" } } ``` ### 6.5 JavaScript 连接示例 ```javascript const ws = new WebSocket('ws://localhost:12346/ws') ws.onopen = () => { console.log('已连接到打印服务') // 发送打印请求 ws.send(JSON.stringify({ action: 'print', requestId: 'req-001', templateId: 'tpl_abc123', data: { orderNo: 'CK-001' } })) } ws.onmessage = (event) => { const resp = JSON.parse(event.data) console.log(`[${resp.requestId}] ${resp.success ? '成功' : '失败'}: ${resp.msg}`) } ws.onclose = () => console.log('连接已断开') ws.onerror = (err) => console.error('连接错误:', err) ``` ### 6.6 HTTP vs WebSocket 选择建议 | 场景 | 推荐通道 | 原因 | |------|----------|------| | 后端系统调用(WMS/ERP) | HTTP | 简单可靠,无需维护连接状态 | | 前端页面实时打印 | WebSocket | 长连接避免重复建连,响应更快 | | 批量高频打印 | WebSocket | 复用连接,减少 TCP 握手开销 | | 偶发性打印(一天几次) | HTTP | 无需维护长连接 | | 需要打印状态实时推送 | WebSocket | 双向通信,可主动推送 | > **说明**:两种通道可同时使用,互不干扰。WebSocket 最大消息大小为 64MB,足够传输 base64 编码的 PDF 和图片。 ### 6.7 远程长连接 除了本机监听 HTTP / WebSocket 服务外,Print-OK 还支持主动连接到远程 WebSocket 服务端,实现内网打印机穿透、云端统一下发打印任务。 **配置方式**:「系统设置 → 远程长连接」卡片 → 打开启用 → 填写 `ws://` 或 `wss://` URL → 点击应用。 **连接特性**: - 心跳:应用层 Ping 每 30s 一次,90s 无数据则认为断线 - 重连:指数退避 2s → 60s,断线自动重连 - 消息上限 64MB,协议格式与本机 WS 服务端完全一致 - 客户端库:coder/websocket v1.8.14 - 配置持久化到 SQLite settings,重启后自动恢复 **远程服务端只需发送与 6.3 节相同格式的 JSON 消息即可触发打印**,本机打印结果会通过同一条连接回传到远程服务端。 **适用场景**: | 场景 | 说明 | |------|------| | 连锁门店 统一打票 | 总部云端调度所有门店打印机 | | 库房 / 出货单 | 办公网与生产网隔离,不开放入站方向 | | SaaS 表单打印 | 用户电脑装 Print-OK 即可被云端调用,无需外网 IP | --- ## 七、授权与激活 Print-OK 分为**试用版**和**授权版**: | 状态 | 说明 | |------|------| | 试用版 | 功能完整可用,PDF 页面顶部和底部边缘会添加半透明水印(不遮挡核心内容) | | 授权版 | 激活后水印自动消失,无任何限制 | **激活步骤:** 1. 点击右下角授权状态按钮(红色⚠ = 试用 / 绿色✓ = 已授权) 2. 复制对话框中的**设备码**(16位),提供给管理员获取激活码 3. 填写激活码(`XXXXX-XXXXX-XXXXX-XXXXX`),点击「激活」即可 **注意事项:** - 一个激活码可绑定多台设备(数量由管理员设定) - 激活后支持离线使用,联网时程序会静默校验授权状态 - 管理员解绑设备后,下次联网校验时自动恢复试用版 - 重装系统后设备码可能变化,需联系管理员重新激活 --- ## 八、自动升级 程序内置自动更新,启动时自动检测新版本。 - 检测到新版本时弹窗提示,显示版本号、大小和更新日志 - 点击「立即更新」自动下载并替换,完成后手动重启即可 - 可选择「跳过此版本」或「稍后提醒」 - 更新前自动备份为 `.bak` 文件,失败可手动恢复 - 应用左下角可查看当前版本号 > 也可在模板列表页手动点击「检查更新」按钮。 --- ## 九、常见问题 ### Q1:关闭窗口后程序还在运行? 这是正常行为。关闭窗口只是隐藏到系统托盘,在托盘图标右键选择「退出」可完全退出。 ### Q2:再次打开程序提示已在运行? 程序只允许运行一个实例。请在系统托盘中找到已运行的实例,右键选择「显示窗口」。 ### Q3:表格数据太多超出一页怎么办? 表格支持自动分页,超出页面的数据会自动换到下一页,表头在每页顶部重复显示。 ### Q4:中文显示为方块或乱码? 请确保字体设置为「思源黑体」(默认字体)。字体已内置于程序中,正常情况下不会出现此问题。如有异常请尝试重启程序。 ### Q5:HTTP 打印接口无响应? - 确认程序正在运行(检查系统托盘) - 确认端口设置正确且未被其他程序占用 - 确认防火墙未阻止该端口 ### Q6:如何备份和迁移模板? - **方式一**:在设计器中使用「导出 JSON」功能,在目标设备使用「导入 JSON」恢复 - **方式二**:直接复制 `print-ok.db` 数据库文件到目标设备的 exe 同级目录 --- ## 附录:文件说明 | 文件 | 说明 | |------|------| | `print-ok.exe` | 主程序(包含所有资源,单文件即可运行) | | `print-ok.db` | 模板数据库(首次运行自动生成) | | `PDFtoPrinter.exe` | 主打印工具(首次运行自动释放到 exe 同级目录) | | `SumatraPDF.exe` | 备用打印工具(PDFtoPrinter 失败时自动回退,首次运行自动释放) | | `print-ok-sdk.js` | 前端 JavaScript SDK(零依赖,支持 WebSocket 和 HTTP 两种通信方式) | | `license.dat` | 授权证书文件(激活后自动生成,勿手动修改) | | `print-ok.exe.bak` | 更新备份文件(更新时自动生成,可用于回滚) | 所有文件均位于 `print-ok.exe` 同级目录,无需额外安装或配置。 --- ## 附录:JavaScript SDK Print-OK 提供轻量级 JavaScript SDK(`print-ok-sdk.js`,零依赖,约 15KB),支持 **WebSocket** 和 **HTTP** 两种通信方式,可在浏览器或 Node.js 中使用。 ### 引入方式 **浏览器 ` ``` **Node.js / CommonJS:** ```javascript const { PrintOK, PrintOKHttp } = require('./print-ok-sdk.js'); ``` **ES Module / 构建工具:** ```javascript import { PrintOK, PrintOKHttp } from './print-ok-sdk.js'; ``` ### WebSocket 客户端 — PrintOK 长连接方式,支持**自动重连**、**消息队列**(断线期间消息自动缓存,重连后发送)、**请求超时**和**事件系统**。 ```javascript // 1. 创建客户端 const client = new PrintOK('ws://localhost:12346/ws', { autoReconnect: true, // 自动重连(默认 true) reconnectInterval: 3000, // 重连间隔 ms(默认 3000) maxReconnect: 0, // 最大重连次数,0=无限 timeout: 30000 // 请求超时 ms(默认 30000) }); // 2. 监听事件 client.on('connected', () => console.log('已连接')); client.on('disconnected', () => console.log('已断开')); client.on('reconnecting', (n) => console.log('正在重连...', n)); client.on('error', (err) => console.error('错误', err)); // 3. 连接 await client.connect(); // 4. 获取打印机列表 const res = await client.getPrinters(); console.log(res.data); // [{name, isDefault, status, statusText, jobCount}, ...] // 5. 模板打印 await client.print({ templateId: 'tpl_abc123', data: { orderNo: 'CK-2024-001', customer: '张三', items: [{sku: 'A001', qty: 10}] }, printer: 'HP LaserJet', copies: 2 }); // 6. 打印 PDF await client.printPDF({ base64: 'JVBERi0xLjQ...' }); await client.printPDF({ url: 'https://example.com/invoice.pdf' }); // 7. 打印图片 await client.printImage({ base64: '/9j/4AAQ...', width: 100, height: 150 }); // 8. 打印 HTML await client.printHTML({ html: '

Hello

', paperWidth: '75mm', paperHeight: '130mm' }); // 9. 打印 Excel 报表 await client.printSpreadsheet({ ssId: 'report_001', data: { month: '2024-06' } }); // 10. 断开连接 client.disconnect(); ``` ### HTTP 客户端 — PrintOKHttp 基于 `fetch` 的短连接方式,无需维护连接状态,适合后端或简单场景。 ```javascript const client = new PrintOKHttp('http://localhost:12345', { timeout: 30000 // 请求超时 ms }); // 获取打印机列表 const printers = await client.getPrinters(); // 模板打印 await client.print({ templateId: 'tpl_abc123', data: { orderNo: 'CK-001' } }); // 打印 PDF / 图片 / HTML / 报表 await client.printPDF({ url: 'https://example.com/file.pdf' }); await client.printImage({ base64: '...' }); await client.printHTML({ html: '

测试

' }); await client.printSpreadsheet({ ssId: 'report_001' }); // 获取报表内容(不打印) const ss = await client.getSpreadsheet('report_001'); ``` ### API 方法速查 | 方法 | 说明 | PrintOK (WS) | PrintOKHttp | |------|------|:---:|:---:| | `print(params)` | 模板打印(schema/templateId + 数据绑定) | ✅ | ✅ | | `getPrinters()` | 获取可用打印机列表 | ✅ | ✅ | | `getStatus()` | 获取服务状态/版本 | ✅ | ✅ | | `printPDF(params)` | 直接打印 PDF(base64/url) | ✅ | ✅ | | `printImage(params)` | 打印图片 | ✅ | ✅ | | `printHTML(params)` | 打印 HTML 源码 | ✅ | ✅ | | `printSpreadsheet(params)` | 打印 Excel 报表 | ✅ | ✅ | | `getSpreadsheet(ssId)` | 获取报表内容(不打印) | — | ✅ | | `connect()` / `disconnect()` | 连接/断开 | ✅ | — | | `on(event, fn)` / `off(event)` | 事件监听 | ✅ | — | ### print 参数说明 | 参数 | 类型 | 说明 | |------|------|------| | `schema` | Object | 模板 JSON(与 templateId 二选一) | | `templateId` | string | 已保存的模板 ID | | `data` | Object | 数据绑定对象 | | `printer` | string | 打印机名称(空=使用默认) | | `copies` | number | 打印份数,默认 1 | | `duplex` | number | 1=单面(默认) 2=长边翻转 3=短边翻转 | | `quality` | number | 1=高(默认) 2=中 3=低 4=草稿 | | `color` | number | 1=单色(默认) 2=彩色 | | `offsetX` / `offsetY` | number | 水平/垂直偏移(mm) | | `forcePaperSize` | boolean | 是否强制纸张尺寸 | | `paperWidthMM` / `paperHeightMM` | number | 纸张宽高(mm) | ### 默认端口 | 通道 | 默认端口 | 地址 | |------|----------|------| | HTTP | 12345 | `http://localhost:12345` | | WebSocket | 12346 | `ws://localhost:12346/ws` | 端口可在 Print-OK「系统设置 → 接口配置」中修改。 --- ## 附录:业务集成指南 本章面向 WMS、ERP 等业务系统的开发人员,说明如何快速接入 Print-OK 实现静默打印。 ### 接入流程总览 ``` 1. 部署 Print-OK → 2. 设计模板并保存 → 3. 记录模板 ID → 4. 业务系统调用 HTTP API ``` **推荐工作流:** | 步骤 | 负责人 | 操作 | |------|--------|------| | 部署程序 | 运维/IT | 将 print-ok.exe 放置到打印工位电脑,双击运行 | | 设计模板 | 业务人员 | 在设计器中拖拽设计单据样式,保存后记录模板 ID | | 对接开发 | 开发人员 | 业务系统在需要打印时调用 `POST /print` 接口 | | 日常使用 | 操作员 | 无感知,业务系统触发打印后自动出纸 | ### 典型业务场景 #### 场景一:WMS 出库打单 业务系统在拣货完成后自动调用打印接口,打印出库单随货同行: ``` 业务系统(拣货完成)→ POST /print(templateId + 订单数据)→ Print-OK → 打印机出纸 ``` #### 场景二:批量发货贴标 每批发货需打印多张快递面单/条码标签,`data` 传数组一次搞定: ``` 业务系统(批量发货)→ POST /print(templateId + [包裹1, 包裹2, ...])→ 一次性打印多页 ``` #### 场景三:品检标签即时打印 质检员在系统中录入检验结果后,立即打印品检标签贴于产品上: ``` 质检系统(录入结果)→ POST /print(templateId + 检验数据)→ 条码标签打印机出标 ``` #### 场景四:入库验收单套打 在已有印刷表单上定位填充数据(利用 `printVisible: false` 辅助线对位): ``` WMS(入库确认)→ POST /print(套打模板 + 入库数据)→ 预印表单上精确打印 ``` ### 接入注意事项 | 事项 | 说明 | |------|------| | 网络可达 | 业务系统服务器需能访问打印工位的 IP:端口(默认 12345) | | 编码 | 请求体必须为 UTF-8 编码的 JSON | | 超时设置 | 建议业务系统 HTTP 客户端超时设为 30~60 秒 | | 打印机就绪 | 确保打印机已开机、有纸、无卡纸(程序会返回打印结果) | | 模板变更 | 模板修改保存后立即生效,无需重启服务或重新部署 | | 并发打印 | 支持并发请求,内部串行队列保证打印顺序不乱 | | 授权状态 | 试用版打印会带水印,响应中 `data.licensed` 字段可用于前端提示 | ### 最简对接代码示例 业务系统只需一个 HTTP POST 请求即可完成打印: **Java(OkHttp):** ```java String json = "{\"templateId\":\"tpl_abc123\",\"data\":{\"orderNo\":\"CK-001\",\"items\":[...]}}"; Request request = new Request.Builder() .url("http://打印工位IP:12345/print") .post(RequestBody.create(json, MediaType.parse("application/json; charset=utf-8"))) .build(); Response response = client.newCall(request).execute(); ``` **Python(requests):** ```python import requests resp = requests.post("http://打印工位IP:12345/print", json={ "templateId": "tpl_abc123", "data": {"orderNo": "CK-001", "items": [...]} }) print(resp.json()) ``` **JavaScript(fetch):** ```javascript const resp = await fetch('http://打印工位IP:12345/print', { method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8' }, body: JSON.stringify({ templateId: 'tpl_abc123', data: { orderNo: 'CK-001', items: [] } }) }) const result = await resp.json() ``` ### 多工位部署方案 当多个工位需要打印时,每个工位部署一套 Print-OK: ``` ┌── 工位A(192.168.1.10:12345)→ 打印机A 业务系统服务器 ────┼── 工位B(192.168.1.11:12345)→ 打印机B └── 工位C(192.168.1.12:12345)→ 打印机C ``` - 每个工位独立运行、独立选择打印机 - 业务系统根据工位/区域路由到对应 IP - 模板可统一设计后通过 JSON 导入分发到各工位 - 使用同一激活码(需确保设备数限额足够) --- ## 联系我们 如有使用问题、功能建议或商务合作,欢迎通过以下方式联系: **微信联系:** 扫描下方二维码添加好友 ![微信二维码](wechat-qr.png)