manifest-label-print
v0.1.7
Published
Label print engine (browser & CLodop), template mapper and CLodop setup utilities for manifest-design
Readme
manifest-label-print
manifest-design 的标签打印引擎 — 提供模板标准化、浏览器截图打印与 CLodop 打印能力,可与 manifest-label-designer 配套使用。
- GitHub:ymf-930/manifest-design
- npm:manifest-label-print
- 配套设计器:manifest-label-designer
- 集成示例:examples/verify-npm-package
目录
安装
npm install manifest-label-print若需可视化设计器,请同时安装 manifest-label-designer:
npm install manifest-label-designer manifest-label-print与 manifest-label-designer 联用
两个包的分工如下:
| 包 | 职责 |
|----|------|
| manifest-label-designer | 可视化标签设计器 UI,产出 { components, canvasConfig } 模板 JSON |
| manifest-label-print(本包) | 将模板 JSON 转为打印任务,执行浏览器或 CLodop 打印 |
典型流程:
设计器编辑模板 → 导出/读取 JSON → toPrintTemplate() → executePrint()设计器内部已依赖本包完成打印;若你不使用设计器 UI,只需本包 + 自建的标签预览 DOM 即可完成打印集成。
快速开始
import { toPrintTemplate, executePrint } from 'manifest-label-print'
const designJson = {
components: [
{
id: 'text-1',
type: 'text',
x: 5,
y: 8,
width: 50,
height: 10,
content: '商品名称:示例',
fontSize: 14,
color: '#333'
}
],
canvasConfig: { width: 60, height: 40, unit: 'mm' }
}
const template = toPrintTemplate(designJson)
const target = document.querySelector('.preview-canvas') as HTMLElement | null
const result = await executePrint(template, {
engine: 'browser',
target
})
if (!result.success) {
console.error(result.message)
}使用前准备
浏览器打印
无需额外依赖。页面上需有一个与标签尺寸一致的预览 DOM,作为截图目标传入 options.target。
CLodop 打印
- 在本机安装并启动 CLodop 打印服务(默认端口
8000/18000) - 将官方
LodopFuncs.js放到业务项目静态资源目录,例如public/LodopFuncs.js - 打印前调用
ensureClodopReady({ scriptUrl: '/LodopFuncs.js' })
说明:本包不包含
LodopFuncs.js文件,也不包含可视化设计器 UI。设计器场景见 manifest-label-designer(内置 helper 脚本)。
使用方式
浏览器截图打印
适合快速集成、无 CLodop 环境时使用。对预览 DOM 截图后调用系统打印对话框。
import { toPrintTemplate, executePrint } from 'manifest-label-print'
const template = toPrintTemplate(designJson)
const target = document.querySelector('.preview-canvas') as HTMLElement | null
const result = await executePrint(template, {
engine: 'browser',
target,
copies: 1 // 可选,默认 1
})要点
target必填- 固定为截图打印,无
mode选项 - 截图时会自动忽略
.grid-background、.selection-handles等设计器辅助元素(若 DOM 中存在)
CLodop 原生模式打印
适合标签机场景。按组件 JSON 下发 CLodop 指令,打印精度高、速度快。
import {
toPrintTemplate,
executePrint,
ensureClodopReady,
formatClodopDiagnostics
} from 'manifest-label-print'
const diagnostics = await ensureClodopReady({ scriptUrl: '/LodopFuncs.js' })
if (!diagnostics.ready) {
alert(formatClodopDiagnostics(diagnostics))
throw new Error(diagnostics.message)
}
const template = toPrintTemplate(designJson)
const result = await executePrint(template, {
engine: 'clodop',
mode: 'native',
preview: true // true=预览,false=直接打印
})原生模式支持的组件类型
| 类型 | 说明 |
|------|------|
| text | 文本,支持字号、字体、颜色、加粗、对齐 |
| barcode | 条形码,format 如 Code128 会自动映射为 128Auto |
| qrcode | 二维码,支持 errorCorrectionLevel |
| horizontal-line / vertical-line | 横线 / 竖线 |
| rectangle | 矩形边框 |
| image | 图片,需有非空 src |
原生模式不支持时会自动降级
以下情况会降级为截图模式(此时 target 必填):
- 组件类型为
table、input、date、price、circle等 - 组件
rotation !== 0或opacity !== 1 - 组件
visible === false
CLodop 截图模式打印
适合复杂布局或原生模式无法渲染的模板。对 DOM 截图后通过 CLodop 打印图片。
import {
toPrintTemplate,
executePrint,
ensureClodopReady,
formatClodopDiagnostics
} from 'manifest-label-print'
const diagnostics = await ensureClodopReady({ scriptUrl: '/LodopFuncs.js' })
if (!diagnostics.ready) {
throw new Error(formatClodopDiagnostics(diagnostics))
}
const template = toPrintTemplate(designJson)
const target = document.querySelector('.preview-canvas') as HTMLElement | null
const result = await executePrint(template, {
engine: 'clodop',
mode: 'image',
target,
preview: true,
printerName: '标签打印机' // 可选,指定 CLodop 打印机名称
})要点
target必填mode默认为'image'
Vue 3 组件内集成
<script setup lang="ts">
import { ref } from 'vue'
import {
toPrintTemplate,
executePrint,
ensureClodopReady,
formatClodopDiagnostics,
type PrintEngine,
type PrintMode
} from 'manifest-label-print'
const props = defineProps<{
designJson: { components: unknown[]; canvasConfig: Record<string, unknown> }
}>()
const canvasRef = ref<HTMLElement | null>(null)
const engine = ref<PrintEngine>('browser')
const mode = ref<PrintMode>('native')
const handlePrint = async () => {
if (engine.value === 'clodop') {
const diagnostics = await ensureClodopReady({ scriptUrl: '/LodopFuncs.js' })
if (!diagnostics.ready) {
window.alert(formatClodopDiagnostics(diagnostics))
return
}
}
const template = toPrintTemplate(props.designJson)
const result = await executePrint(template, {
engine: engine.value,
mode: mode.value,
target: canvasRef.value,
preview: engine.value === 'clodop'
})
if (!result.success) {
window.alert(result.message || '打印失败')
}
}
</script>
<template>
<div ref="canvasRef" class="preview-canvas">
<!-- 根据 designJson 渲染标签内容 -->
</div>
<button type="button" @click="handlePrint">打印</button>
</template>兼容旧版模板数据
toPrintTemplate / normalizeTemplateInput 支持多种输入格式:
import { normalizeTemplateInput, toPrintTemplate } from 'manifest-label-print'
// 标准格式
toPrintTemplate({
components: [],
canvasConfig: { width: 60, height: 40, unit: 'mm' }
})
// 旧版 { data } 字段
toPrintTemplate({
data: components,
canvasConfig: { width: 60, height: 40, unit: 'mm' }
})
// 仅组件数组(使用默认 60×40mm 画布)
toPrintTemplate(components)
// 仅标准化,不包装 schemaVersion
normalizeTemplateInput(designJson)标准化后的 PrintTemplate 结构:
interface PrintTemplate {
schemaVersion: '1.0'
source: 'manifest-design'
components: PrintComponent[]
canvasConfig: PrintCanvasConfig
}默认画布配置(缺省时):
| 字段 | 默认值 |
|------|--------|
| width | 60 |
| height | 40 |
| unit | 'mm' |
| zoom | 1 |
| showGrid | true |
| showRuler | true |
| showGuides | true |
适配器与偏好存储
import {
BrowserPrintAdapter,
ClodopPrintAdapter,
executePrint,
getPreferredPrintEngine,
setPreferredPrintEngine,
getPreferredPrintMode,
setPreferredPrintMode,
isClodopRuntimeReady
} from 'manifest-label-print'
setPreferredPrintEngine('clodop')
setPreferredPrintMode('native')
if (getPreferredPrintEngine() === 'clodop' && !isClodopRuntimeReady()) {
await ensureClodopReady({ scriptUrl: '/LodopFuncs.js' })
}
const adapters = [new BrowserPrintAdapter(), new ClodopPrintAdapter()]
await executePrint(template, {
engine: getPreferredPrintEngine(),
mode: getPreferredPrintMode(),
target: previewElement
}, adapters)偏好写入 localStorage,并自动迁移旧键名:print_engine、label_print_engine、print_mode、label_print_mode。
| 存储键 | 说明 |
|--------|------|
| manifest-print-engine | 当前首选引擎 |
| manifest-print-mode | 当前首选 CLodop 模式 |
API 参考
模板转换
| 方法 | 说明 |
|------|------|
| toPrintTemplate(input) | 转为带 schemaVersion: '1.0' 的打印模板 |
| normalizeTemplateInput(input) | 标准化为 { components, canvasConfig } |
打印入口
| 方法 / 类 | 说明 |
|-----------|------|
| executePrint(template, options, adapters?) | 统一打印入口 |
| resolvePrintAdapter(engine, adapters?, fallbackToBrowser?) | 解析可用打印引擎 |
| getDefaultPrintAdapters() | 获取默认适配器列表 |
| BrowserPrintAdapter | 浏览器截图打印适配器 |
| ClodopPrintAdapter | CLodop 打印适配器 |
PrintJobOptions 字段
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| engine | 'browser' \| 'clodop' | — | 打印引擎(必填) |
| mode | 'image' \| 'native' | 'image' | CLodop 打印模式 |
| target | HTMLElement \| null | — | 截图目标 DOM |
| preview | boolean | — | CLodop 是否预览(PREVIEW / PRINT) |
| copies | number | 1 | 打印份数(浏览器引擎有效) |
| printerName | string | — | CLodop 打印机名称 |
| fallbackToBrowser | boolean | 见说明 | 引擎不可用时是否回退浏览器 |
PrintJobResult 字段
| 字段 | 类型 | 说明 |
|------|------|------|
| success | boolean | 是否成功 |
| message | string | 结果描述(含降级提示) |
| error | unknown | 异常对象 |
CLodop 环境工具
| 方法 | 说明 |
|------|------|
| ensureClodopReady(options?) | 注入 helper 脚本并等待 CLodop 就绪,返回诊断信息 |
| ensureClodopHelperLoaded(options?) | 同上,返回 boolean |
| isClodopRuntimeReady() | 同步检测 CLodopJsState === 'complete' 且实例可用 |
| formatClodopDiagnostics(diagnostics) | 格式化诊断信息为可读字符串 |
ClodopSetupOptions 字段
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| scriptUrl | string | — | LodopFuncs.js 地址,如 '/LodopFuncs.js' |
| timeoutMs | number | 8000 | 等待超时(毫秒) |
| scriptId | string | 'manifest-clodop-helper' | 注入的 <script> 标签 id |
ClodopDiagnosticCode 枚举
| 值 | 含义 |
|----|------|
| ready | 已就绪 |
| helper_script_load_failed | helper 脚本加载失败 |
| helper_not_injected | helper 未注入(未传 scriptUrl) |
| helper_loading_timeout | 加载超时或服务不可达 |
| clodop_instance_unavailable | 脚本已加载但无可用实例 |
偏好存储
| 方法 | 说明 |
|------|------|
| getPreferredPrintEngine() | 读取首选引擎,默认 'browser' |
| setPreferredPrintEngine(engine) | 写入首选引擎 |
| getPreferredPrintMode() | 读取首选 CLodop 模式,默认 'image' |
| setPreferredPrintMode(mode) | 写入首选 CLodop 模式 |
| getStoredPrintEngine() | 读取存储值,无则 null |
| getStoredPrintMode() | 读取存储值,无则 null |
类型定义
本包导出以下 TypeScript 类型:
export type {
DesignTemplateSnapshot,
PrintAdapter,
PrintCanvasConfig,
PrintComponent,
PrintEngine,
PrintMode,
PrintJobOptions,
PrintJobResult,
PrintTemplate
} from 'manifest-label-print'
export type {
ClodopDiagnosticCode,
ClodopDiagnostics,
ClodopSetupOptions
} from 'manifest-label-print'行为说明
- 浏览器引擎固定为截图打印,必须提供
options.target - CLodop
native模式在不支持时会自动降级为image模式(message会提示Native mode fallback to image mode) - 坐标与尺寸单位为毫米(mm),CLodop 内部转换为 0.1mm
- 截图使用
html2canvas,默认scale: 2,背景色#ffffff - 设计器 UI 不在本包范围内,请配合 manifest-label-designer 或自建渲染层
完整示例
从设计器 JSON 到 CLodop 原生打印
import {
toPrintTemplate,
executePrint,
ensureClodopReady,
formatClodopDiagnostics
} from 'manifest-label-print'
// 通常来自 manifest-label-designer 导出的 JSON
const exportedJson = {
components: [
{ id: 't1', type: 'text', x: 5, y: 5, width: 50, height: 8, content: '示例商品', fontSize: 14, fontWeight: 'bold' },
{ id: 'b1', type: 'barcode', x: 8, y: 20, width: 44, height: 10, content: '123456789012', format: 'Code128' }
],
canvasConfig: { width: 60, height: 40, unit: 'mm', zoom: 1, showGrid: true, showRuler: true, showGuides: true }
}
const diagnostics = await ensureClodopReady({ scriptUrl: '/LodopFuncs.js' })
if (!diagnostics.ready) {
throw new Error(formatClodopDiagnostics(diagnostics))
}
const template = toPrintTemplate(exportedJson)
const result = await executePrint(template, {
engine: 'clodop',
mode: 'native',
preview: true
})
console.log(result.message) // "Printed with CLodop native mode"含表格模板(自动降级截图)
const template = toPrintTemplate({
components: [
{ id: 'tbl', type: 'table', x: 2, y: 2, width: 56, height: 36 /* ... */ }
],
canvasConfig: { width: 60, height: 40, unit: 'mm' }
})
// table 不支持 native,需提供 target
const result = await executePrint(template, {
engine: 'clodop',
mode: 'native',
target: document.querySelector('.preview-canvas'),
preview: true
})
// result.message === 'Native mode fallback to image mode'常见问题
CLodop 无法打印
- 确认本机 CLodop 服务已启动(
localhost:8000或localhost:18000) - 确认
LodopFuncs.js路径正确,且打印前已调用ensureClodopReady({ scriptUrl: '...' }) - 使用
formatClodopDiagnostics(diagnostics)查看详细诊断
浏览器打印空白
- 确认
target元素已渲染且尺寸与canvasConfig一致 - 跨域图片可能导致截图失败,需配置 CORS 或使用同源资源
原生模式意外变成截图
- 检查模板是否含
table、date、price、input、circle等类型 - 检查组件是否有旋转(
rotation !== 0)或透明度(opacity !== 1)
只想用设计器,还要装本包吗?
manifest-label-designer 将本包列为 peerDependency,宿主项目需同时安装。
完整集成示例
本仓库提供可运行的最小集成示例,演示设计器 + 打印引擎的完整接入:
源码:examples/verify-npm-package
git clone https://github.com/ymf-930/manifest-design.git
cd manifest-design
# 先构建两个 npm 包
npm run build:print-package
npm run build --prefix packages/manifest-label-designer
cd examples/verify-npm-package
npm install
npm run dev示例 main.ts 核心配置:
import { createPinia } from 'pinia'
import Antd from 'ant-design-vue'
import 'ant-design-vue/dist/reset.css'
import 'manifest-label-designer/style.css'
app.use(createPinia())
app.use(Antd)若仅使用本包(不用设计器 UI),可参考上文 Vue 3 组件内集成,并将 public/LodopFuncs.js 用于 CLodop 联调(示例目录已包含该文件)。
开发与发布
# 在 monorepo 根目录
npm run build:print-package
# 在 packages/manifest-label-print
npm version patch
npm publish --access public --registry https://registry.npmjs.org/License
MIT
