vue3-clodop
v0.1.0
Published
C-Lodop 云打印 Vue 3 插件 - 提供类型安全的响应式打印能力
Maintainers
Readme
vue3-clodop
C-Lodop 云打印 Vue 3 插件 — 类型安全的 Builder 模式封装,提供响应式组合式 API。
目录
安装
npm install vue3-clodop需要本机安装并启动 C-Lodop 云打印服务(默认端口 8000 / 18000)。
快速开始
1. 注册插件
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { CLodopPlugin } from 'vue3-clodop';
const app = createApp(App);
app.use(CLodopPlugin, {
timeout: 10000,
debug: true,
// license: { companyName: '', license: '' },
});
app.mount('#app');2. 在组件中使用
<script setup lang="ts">
import { useCLodop, Orientation, BarcodeType } from 'vue3-clodop';
const { printer, isReady, isLoading, error, version, reload } = useCLodop();
function doPrint() {
if (!printer.value) return;
printer.value
.init('订单打印')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.addText({ top: 50, left: 50, width: 500, height: 40, content: '你好,世界' })
.setItemStyle(0, 'FontSize', 18)
.addBarcode({ top: 120, left: 50, width: 200, height: 200, type: BarcodeType.QRCode, value: 'https://vuejs.org' })
.preview();
}
</script>
<template>
<div v-if="isLoading">正在连接打印服务...</div>
<div v-else-if="error">{{ error.message }}</div>
<button v-else :disabled="!isReady" @click="doPrint">打印预览</button>
</template>插件配置
CLodopPlugin 的 options 参数类型为 CLodopPluginOptions:
| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| scriptUrls | string[] | HTTP: localhost:8000/18000HTTPS: localhost:8443/18443 | C-Lodop 脚本地址列表,按优先级降级 |
| timeout | number | 10000 | 脚本加载超时(毫秒) |
| autoLoad | boolean | true | 是否在插件安装时自动加载脚本 |
| license | LicenseOptions | — | 许可证配置 |
| onReady | (clodop) => void | — | 加载成功回调 |
| onError | (error) => void | — | 加载失败回调 |
| debug | boolean | false | 启用调试日志 |
组合式函数 useCLodop
import { useCLodop } from 'vue3-clodop';
const {
printer, // ShallowRef<CLodopPrinter | null>
rawCLodop, // ShallowRef<CLodopRaw | null>
status, // Ref<CLodopStatus>
isReady, // Ref<boolean>
isLoading, // Ref<boolean>
error, // Ref<Error | null>
version, // Ref<string>
reload, // () => Promise<void>
} = useCLodop(options?);返回值
| 属性 | 类型 | 说明 |
|------|------|------|
| printer | ShallowRef<CLodopPrinter \| null> | 打印类实例(使用 shallowRef 避免 Proxy 干扰 CLODOP 内部序列化) |
| rawCLodop | ShallowRef<CLodopRaw \| null> | 原始 CLODOP 对象 |
| status | Ref<CLodopStatus> | 连接状态:idle / loading / ready / error |
| isReady | Ref<boolean> | 是否已就绪 |
| isLoading | Ref<boolean> | 是否正在加载 |
| error | Ref<Error \| null> | 错误信息 |
| version | Ref<string> | C-Lodop 版本号 |
| reload | () => Promise<void> | 手动重新加载 |
局部选项(覆盖插件配置)
| 属性 | 类型 | 说明 |
|------|------|------|
| scriptUrls | string[] | 自定义脚本 URL |
| timeout | number | 超时时间 |
| license | LicenseOptions | 许可证 |
| autoLoad | boolean | 是否自动加载(默认 true) |
| debug | boolean | 调试日志 |
CLodopPrinter API
所有返回 this 的方法支持链式调用(Builder 模式)。
属性访问
| 属性 | 类型 | 对应原始 API | 说明 |
|------|------|-------------|------|
| raw | CLodopRaw | — | 获取原始 CLODOP 实例 |
| version | string | CLODOP.VERSION | C-Lodop 版本号 |
| cVersion | string | CLODOP.CVERSION | C-Lodop 扩展版本号 |
| lastResult | any | CLODOP.Result | 最后一次操作结果 |
| lastItemIndex | number | — | 最后添加的打印项序号(从 1 开始) |
连接状态
| 属性/方法 | 类型 | 对应原始 API | 说明 |
|-----------|------|-------------|------|
| isSocketOpened | boolean (getter) | CLODOP.SocketOpened | WebSocket 是否已连接 |
| isSocketEnabled | boolean (getter) | CLODOP.SocketEnable | WebSocket 是否启用 |
| isLocal | boolean (getter) | CLODOP.blIslocal | 是否本地模式 |
| isBusy | boolean (getter) | CLODOP.blWorking | 是否正在执行任务 |
| hostURI | string (getter) | CLODOP.strHostURI | 服务地址 |
| isIdle() | boolean | !CLODOP.blWorking | 是否空闲 |
| reconnectWebSocket() | void | CLODOP.OpenWebSocket() | 手动触发 WebSocket 重连 |
打印机管理
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| getPrinterCount() | number | GET_PRINTER_COUNT() | 打印机数量 |
| getPrinterName(index) | string | GET_PRINTER_NAME(index) | 按序号获取打印机名称 |
| getPrinterProperty(index, property) | string | GET_PRINTER_NAME('index:property') | 获取打印机指定属性 |
| getPrinters() | PrinterInfo[] | CLODOP.Printers | 所有打印机详情列表 |
| getDefaultPrinter() | PrinterInfo \| undefined | CLODOP.Printers | 默认打印机信息 |
| findPrinter(keyword) | PrinterInfo \| undefined | CLODOP.Printers | 按名称模糊搜索打印机 |
| getPageSizes(printerIndex?) | string[] | GET_PAGESIZES_LIST() | 获取指定打印机支持的纸张列表 |
| fillPrinterSelect(element) | this | Create_Printer_List() | 将打印机填充到 <select> |
| fillPageSizeSelect(element, printerIndex?) | this | Create_PageSize_List() | 将纸张列表填充到 <select> |
初始化
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| init(taskName?) | this | PRINT_INIT(taskName) | 初始化打印任务 |
| initWithMargin(top, left, width, height, taskName?) | this | PRINT_INITA(top, left, width, height, taskName) | 初始化打印任务(带纸张边距) |
页面设置
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| setPageSize(options) | this | SET_PRINT_PAGESIZE(orient, width, height, name) | 设置纸张大小 |
| setPrinter(nameOrIndex) | this | SET_PRINTER_INDEX(nameOrIndex) | 设置当前打印机 |
| setFallbackPrinter(nameOrIndex) | this | SET_PRINTER_INDEXA(nameOrIndex) | 设置备用打印机 |
| setCopies(copies) | this | SET_PRINT_COPIES(copies) | 设置打印份数 |
| setLicenses(options) | this | SET_LICENSES(company, license, licenseA, licenseB) | 设置许可证 |
添加打印项
每次调用 add* 方法后 lastItemIndex 自动 +1,可立即用 setItemStyle(0, ...) 设置当前项样式。
| 方法 | 参数类型 | 对应原始 API | 说明 |
|------|---------|-------------|------|
| addText(options) | TextItemOptions | ADD_PRINT_TEXT / ADD_PRINT_TEXTA | 添加文本(有 name 时用 A 版本) |
| addHtml(options) | HtmlItemOptions | ADD_PRINT_HTML / ADD_PRINT_HTMLA | 添加 HTML(自动分页) |
| addHtm(options) | HtmlItemOptions | ADD_PRINT_HTM | 添加 HTML(不自动分页,超出截断) |
| addImage(options) | ImageItemOptions | ADD_PRINT_IMAGE | 添加图片(自动识别 URL / Base64 / HTML / 本地路径) |
| addImageFromUrl(url, rect, fetchOptions?) | string, Rect, RequestInit? | fetch + ADD_PRINT_IMAGE | 下载远程图片转 data URI 后添加(异步,解决跨域) |
| addImageFromFile(file, rect) | File, Rect | FileReader + ADD_PRINT_IMAGE | 读取 File 对象转 data URI 后添加(异步) |
| addBarcode(options) | BarcodeItemOptions | ADD_PRINT_BARCODE / ADD_PRINT_BARCODEA | 添加条码/二维码 |
| addRect(options) | RectItemOptions | ADD_PRINT_RECT / ADD_PRINT_RECTA | 添加矩形(有 color 时用 A 版本) |
| addEllipse(options) | RectItemOptions | ADD_PRINT_ELLIPSE / ADD_PRINT_ELLIPSEA | 添加椭圆 |
| addLine(options) | LineItemOptions | ADD_PRINT_LINE | 添加线条(两点坐标) |
| addDnLine(options) | DiagonalLineItemOptions | ADD_PRINT_DNLINE / ADD_PRINT_DNLINEA | 添加下对角线(左上→右下) |
| addUpLine(options) | DiagonalLineItemOptions | ADD_PRINT_UPLINE / ADD_PRINT_UPLINEA | 添加上对角线(左下→右上) |
| addShape(options) | ShapeItemOptions | ADD_PRINT_SHAPE | 添加通用图形 |
| addTable(options) | TableItemOptions | ADD_PRINT_TABLE | 添加表格(HTML 内容) |
| addTableUrl(options) | UrlItemOptions | ADD_PRINT_TBURL | 添加表格(URL 方式) |
| addUrl(options) | UrlItemOptions | ADD_PRINT_URL | 添加 URL 页面 |
| addPdf(options) | PdfItemOptions | ADD_PRINT_PDF | 添加 PDF(本地路径或 Base64) |
| addPdfFromUrl(url, rect) | string, Rect | fetch + ADD_PRINT_PDF | 下载远程 PDF 转 Base64 后添加(异步) |
| addPdfFromFile(file, rect) | File, Rect | FileReader + ADD_PRINT_PDF | 读取 File 对象转 Base64 后添加(异步) |
| addChart(options) | ChartItemOptions | ADD_PRINT_CHART | 添加图表 |
样式设置
| 方法 | 参数 | 对应原始 API | 说明 |
|------|------|-------------|------|
| setDefaultStyle(styleName, value) | string, any | SET_PRINT_STYLE | 设置默认样式(影响后续所有项) |
| setItemStyle(itemNo, key, value) | number\|string, string, any | SET_PRINT_STYLEA | 设置指定项样式(0=最后一项) |
| setItemStyles(itemNo, styles) | number\|string, ItemStyleOptions | SET_PRINT_STYLEA (批量) | 批量设置样式 |
| setTextStyle(itemNo, style) | number\|string, TextStyleOptions | SET_PRINT_TEXT_STYLE / SET_PRINT_TEXT_STYLEA | 快捷文本样式设置 |
| setItemProperty(itemNo, pageType, hOrient, vOrient) | number\|string, number, number, number | SET_PRINT_PROPERTY | 设置页面属性(页眉/页脚) |
setItemStyles 属性映射表
setItemStyles 接受 ItemStyleOptions 对象,内部自动映射为 SET_PRINT_STYLEA 的 key/value 调用:
| JS 属性 | CLODOP Key | 类型 | 说明 |
|---------|------------|------|------|
| fontName | FontName | string | 字体名称 |
| fontSize | FontSize | number | 字号 |
| bold | Bold | boolean \| number | 加粗 |
| italic | Italic | boolean \| number | 斜体 |
| underline | Underline | boolean \| number | 下划线 |
| alignment | Alignment | Alignment | 对齐方式 |
| fontColor | FontColor | string \| number | 字体颜色 |
| itemType | ItemType | ItemPageType | 项类型(页眉/页脚) |
| hOrient | HOrient | HorizontalOrient | 水平位置 |
| vOrient | VOrient | VerticalOrient | 垂直位置 |
| disabled | Disabled | boolean \| number | 是否禁用 |
| angle | Angle | number | 旋转角度 |
| autoWrap | AutoWrap | boolean | 自动换行 |
| leftMargin | LeftMargin | number | 左内边距 |
| rightMargin | RightMargin | number | 右内边距 |
| topMargin | TopMargin | number | 上内边距 |
| bottomMargin | BottomMargin | number | 下内边距 |
| penStyle | PenStyle | PenStyle | 线条样式 |
| penWidth | PenWidth | number | 线条宽度 |
| stretch | Stretch | number | 拉伸模式 |
| readOnly | ReadOnly | boolean \| number | 只读 |
| linked | Linked | string | 关联 |
| contentVName | ContentVName | string | 内容变量名 |
| linePosition | LinePosition | number | 线条位置 |
| qrCodeVersion | QRCodeVersion | number | QR 码版本 |
| qrCodeErrorLevel | QRCodeErrorLevel | string | QR 码纠错等级 |
打印模式
| 方法 | 参数 | 对应原始 API | 说明 |
|------|------|-------------|------|
| setMode(modeType, modeValue) | string, any | SET_PRINT_MODE | 设置打印模式 |
| setPageRange(start, end) | number, number | SET_PRINT_MODE('PRINT_START_PAGE/END_PAGE') | 设置打印页码范围 |
| setPreviewWindow(options) | PreviewWindowOptions | SET_PREVIEW_WINDOW | 设置预览窗口参数 |
| setPreviewMode(value) | any | SET_PREVIEW_MODE | 设置预览模式 |
| setShowMode(type, value) | string, any | SET_SHOW_MODE | 设置显示模式 |
| setSaveMode(type, value) | string, any | SET_SAVE_MODE | 设置保存模式 |
| setBackgroundImage(content) | string | ADD_PRINT_SETUP_BKIMG | 设置背景图 |
| addProgramData(value) | any | ADD_PRINT_DATA('ProgramData', value) | 添加程序数据 |
PrintModeType 常用值
SET_PRINT_MODE是通用键值透传接口。modeType 转小写后存入PageData,随打印数据一起发送到 C-Lodop 服务端。print.js客户端仅特殊处理NOCLEAR_AFTER_PRINT(同步属性)、含WINDOW_DEF/CONTROL_PRINTER的类型(立即发送),其余均为服务端解析。
| 枚举值 | 原始字符串 | 来源 | 说明 |
|--------|-----------|------|------|
| PrintModeType.NoClearAfterPrint | NOCLEAR_AFTER_PRINT | print.js:1141 | 打印后不清除数据(客户端同步设置属性) |
| PrintModeType.PrintStartPage | PRINT_START_PAGE | print.js:1899 | 起始页码(PRINTAOK 内部调用) |
| PrintModeType.PrintEndPage | PRINT_END_PAGE | print.js:1901 | 结束页码(PRINTAOK 内部调用) |
以上为 print.js 源码中有据可查的值。其他 modeType 由 C-Lodop 服务端解析,可直接传字符串:
printer.setMode('DOUBLE_SIDED_PRINT', 1)
分页
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| newPage() | this | NEWPAGE() | 强制分页(继承当前页面设置) |
| newPageA() | this | NEWPAGEA() | 强制分页(独立页码序列) |
输出操作(同步)
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| print() | string \| null | PRINT() | 直接打印(静默) |
| preview(target?, width?, height?, option?) | string \| null | PREVIEW(target, width, height, option) | 打印预览 |
| printWithDialog() | string \| null | PRINTA() | 弹出打印对话框 |
| printSilent() | string \| null | PRINTB() | 后台静默打印 |
| printDesign() | string \| null | PRINT_DESIGN() | 打印设计(仅本地) |
| printSetup() | string \| null | PRINT_SETUP() | 打印维护/设置(仅本地) |
| selectPrinter() | boolean | SELECT_PRINTER(false) | 弹出打印机选择框(仅选择) |
| selectPrinterAndPrint() | boolean | SELECT_PRINTER(true) | 弹出打印机选择框并打印 |
| printAfterSelect(printerIndex, copies, startPage?, endPage?) | void | PRINTAOK(...) | 选择后执行打印 |
| saveToFile(fileName) | string \| null | SAVE_TO_FILE(fileName) | 保存为文件(仅本地) |
输出操作(异步)
所有异步方法返回 Promise<TaskResult>,其中 TaskResult = { taskId: string; value: any }。
| 方法 | 对应原始 API | 说明 |
|------|-------------|------|
| printAsync() | PRINT() + On_Return | 直接打印 |
| previewAsync(target?, width?, height?, option?) | PREVIEW() + On_Return | 打印预览 |
| printWithDialogAsync() | PRINTA() + On_Return | 弹出打印对话框 |
| printSilentAsync() | PRINTB() + On_Return | 后台静默打印 |
| printDesignAsync() | PRINT_DESIGN() + On_Return | 打印设计 |
| printSetupAsync() | PRINT_SETUP() + On_Return | 打印维护/设置 |
| saveToFileAsync(fileName) | SAVE_TO_FILE() + On_Return | 保存为文件 |
| sendRawDataAsync(rawData) | SEND_PRINT_RAWDATA() + On_Return | 发送原始打印指令 |
| writeFileAsync(fileName, text, mode?) | WRITE_FILE_TEXT() + On_Return | 写入本地文件 |
| getFileTimeAsync(fileName) | GET_FILE_TIME() + On_Return | 获取文件修改时间 |
| writePortAsync(portName, data) | WRITE_PORT_DATA() + On_Return | 向端口写入数据 |
| readPortAsync(portName) | READ_PORT_DATA() + On_Return | 从端口读取数据 |
| getSystemInfoAsync(infoType) | GET_SYSTEM_INFO() + On_Return | 获取系统信息 |
| getDialogValueAsync(type, preValue) | GET_DIALOG_VALUE() + On_Return | 弹出对话框获取输入 |
| getValueAsync(valueType, valueIndex) | GET_VALUE() + On_Return | 获取打印参数值 |
| doActionAsync(actionName, actionValue) | DO_ACTION() + On_Return | 执行动作 |
| formatAsync(type, value) | FORMAT() + On_Return | 通用格式化 |
| getIniFileNameAsync(taskName) | GET_PRINT_INIFFNAME() + On_Return | 获取 INI 配置文件名 |
| readFileAsync(fileName) | GET_FILE_TEXT() + On_Return | 读取文件 |
| fileExistsAsync(fileName) | IS_FILE_EXIST() + On_Return | 检查文件是否存在 |
回调注册
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| onReturn(callback) | this | On_Return + On_Return_Remain=true | 注册打印结果回调(持久监听) |
| onBroadcast(callback) | this | On_Broadcast + On_Broadcast_Remain=true | 注册广播消息回调 |
| offReturn() | this | On_Return=null | 移除打印结果回调 |
| offBroadcast() | this | On_Broadcast=null | 移除广播消息回调 |
文件操作
仅限 C-Lodop 本地服务。
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| readFile(fileName) | string \| null | GET_FILE_TEXT(fileName) | 读取本地文件内容 |
| writeFile(fileName, text, mode?) | string \| null | WRITE_FILE_TEXT(mode, fileName, text) | 写入本地文件 |
| fileExists(fileName) | string \| null | IS_FILE_EXIST(fileName) | 检查文件是否存在 |
| getFileTime(fileName) | string \| null | GET_FILE_TIME(fileName) | 获取文件修改时间 |
端口操作
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| writePort(portName, data) | string \| null | WRITE_PORT_DATA(portName, data) | 向端口写入数据 |
| readPort(portName) | string \| null | READ_PORT_DATA(portName) | 从端口读取数据 |
工具方法
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| formatDate(format, value) | any | FORMAT('Time:' + format, value) | 格式化日期 |
| format(type, value) | any | FORMAT(type, value) | 通用格式化 |
| sendRawData(rawData) | string \| null | SEND_PRINT_RAWDATA(rawData) | 发送原始打印指令(ESC/POS 等) |
| getSystemInfo(infoType) | string \| null | GET_SYSTEM_INFO(infoType) | 获取系统信息 |
| getDialogValue(type, preValue) | string \| null | GET_DIALOG_VALUE(type, preValue) | 弹出对话框获取用户输入 |
| getValue(valueType, valueIndex) | string \| null | GET_VALUE(valueType, valueIndex) | 获取打印参数值 |
| getIniFileName(taskName) | string \| null | GET_PRINT_INIFFNAME(taskName) | 获取打印任务 INI 配置文件名 |
| doAction(actionName, actionValue) | string \| null | DO_ACTION(actionName, actionValue) | 执行动作 |
PDF / 二进制工具函数
独立导出的工具函数,不依赖 CLodopPrinter 实例。
PDF 相关
| 函数 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| fetchPdfAsBase64(url, fetchOptions?) | string, RequestInit? | Promise<string> | 下载 PDF 转 Base64(需同源或已配 CORS) |
| blobToBase64(blob) | Blob | Promise<string> | Blob 转 Base64(适合后端 API 返回的文件流) |
| readFileAsBase64(file) | File | Promise<string> | 读取本地 File 对象转 Base64 |
图片相关
| 函数 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| fetchImageAsDataUri(url, fetchOptions?) | string, RequestInit? | Promise<string> | 下载图片转 data:image/xxx;base64,...(自动推断 MIME) |
| readFileAsDataUri(file) | File | Promise<string> | 本地 File 转 data URI |
通用
| 函数 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| arrayBufferToBase64(data) | Uint8Array | string | 二进制数据转 Base64(底层工具) |
以上基于 C-Lodop 官方示例
demoDownloadPDF/demoOpenLocalPDFfile/demoGetBASE64的逻辑。
AO 桥接打印
用于通过 AO(ActiveX Object)桥接方式连接远程打印机。
| 方法 | 返回值 | 对应原始 API | 说明 |
|------|--------|-------------|------|
| setBridgeIndex(bridgeValue) | boolean | SET_BRIDGE_INDEX(value) | 设置 AO 桥接打印机 |
| getAOPrintersList(driver, listName?, split?) | string[] | Get_AOPrinters_List(...) | 获取 AO 打印机列表 |
| getAOBridgesList(driver, listName?, split?) | string[] | Get_AOBridges_List(...) | 获取 AO 桥接列表 |
| getAOBridgeList(listName?, split?) | string[] | Get_AOBridge_List(...) | 获取默认驱动的桥接列表 |
| getAOBridgeSubPrintersList(bridge, listName?, split?, driver?) | string[] | Get_AOBridge_SubPrinters_List(...) | 获取桥接下的子打印机列表 |
| getAOBridgeSubPrintersPageSizeList(bridge, subPrinter, split?, driver?) | string[] | Get_AOBridge_SubPrinters_PageSize_List(...) | 获取桥接子打印机支持的纸张 |
静态方法
| 方法 | 返回值 | 说明 |
|------|--------|------|
| CLodopPrinter.isAvailable(checkSocket?) | boolean | 检查 C-Lodop 服务是否可用 |
| CLodopPrinter.onCLodopOpened(callback) | void | 注册全局 On_CLodop_Opened 回调 |
枚举参考
Orientation — 纸张方向
| 枚举值 | 值 | 说明 |
|--------|---|------|
| Portrait | 1 | 纵向 |
| Landscape | 2 | 横向 |
| PortraitFixed | 3 | 纵向,固定纸张 |
PenStyle — 线条样式
| 枚举值 | 值 | 说明 |
|--------|---|------|
| Solid | 0 | 实线 |
| Dash | 1 | 虚线 |
| Dot | 2 | 点线 |
| DashDot | 3 | 点划线 |
| DashDotDot | 4 | 双点划线 |
Alignment — 文本对齐
| 枚举值 | 值 | 说明 |
|--------|---|------|
| Left | 1 | 左对齐 |
| Center | 2 | 居中 |
| Right | 3 | 右对齐 |
BarcodeType — 条码类型
| 枚举值 | 值 | 说明 |
|--------|---|------|
| Code128A | 128A | 128A 编码 |
| Code128B | 128B | 128B 编码 |
| Code128C | 128C | 128C 编码(纯数字) |
| Code128Auto | 128Auto | 128 自动编码 |
| EAN8 | EAN8 | EAN-8 |
| EAN13 | EAN13 | EAN-13(商品条码) |
| EAN128A | EAN128A | EAN-128A |
| EAN128B | EAN128B | EAN-128B |
| EAN128C | EAN128C | EAN-128C |
| Code39 | 39 | Code 39 |
| Code39Extended | 39Extended | Code 39 扩展 |
| Interleaved25 | 2_5interleaved | 交叉 25 码 |
| Code93 | 93 | Code 93 |
| Code93Extended | 93Extended | Code 93 扩展 |
| Codabar | Codabar | Codabar |
| QRCode | QRCode | QR 二维码 |
| PDF417 | PDF417 | PDF417 |
| DataMatrix | DataMatrix | DataMatrix |
ShapeType — 图形类型
| 枚举值 | 值 | 说明 |
|--------|---|------|
| UpLine | 0 | 上对角线(左下→右上) |
| DownLine | 1 | 下对角线(左上→右下) |
| Rectangle | 2 | 矩形 |
| Ellipse | 3 | 椭圆 |
ItemPageType — 打印项页面类型
| 枚举值 | 值 | 说明 |
|--------|---|------|
| Normal | 0 | 普通项 |
| HeaderFooter | 1 | 页眉页脚 |
| Header | 2 | 页眉 |
| Footer | 3 | 页脚 |
HorizontalOrient — 水平对齐
| 枚举值 | 值 | 说明 |
|--------|---|------|
| Left | 0 | 左 |
| Center | 1 | 居中 |
| Right | 2 | 右 |
| Full | 3 | 铺满 |
VerticalOrient — 垂直对齐
| 枚举值 | 值 | 说明 |
|--------|---|------|
| Top | 0 | 上 |
| Center | 1 | 居中 |
| Bottom | 2 | 下 |
| Full | 3 | 铺满 |
PreviewDispMode — 预览显示模式
| 枚举值 | 值 | 说明 |
|--------|---|------|
| FullScreen | 0 | 全屏 |
| Windowed | 1 | 窗口模式 |
| Auto | 2 | 自适应 |
FileWriteMode — 文件写入模式
| 枚举值 | 值 | 说明 |
|--------|---|------|
| Overwrite | 1 | 覆盖 |
| Append | 2 | 追加 |
CLodopStatus — 连接状态
| 枚举值 | 值 | 说明 |
|--------|---|------|
| Idle | idle | 未初始化 |
| Loading | loading | 正在加载 |
| Ready | ready | 已就绪 |
| Error | error | 加载失败 |
类型/接口参考
Rect — 位置和尺寸基础接口
interface Rect {
top: number | string; // 距顶部距离(px 或 '10%')
left: number | string; // 距左侧距离
width: number | string; // 宽度
height: number | string; // 高度
}TextItemOptions
interface TextItemOptions extends Rect {
content: string; // 文本内容
name?: string; // 打印项名称(有值时调用 A 版本 API)
}HtmlItemOptions
interface HtmlItemOptions extends Rect {
content: string; // HTML 内容
name?: string;
}ImageItemOptions
interface ImageItemOptions extends Rect {
content: string;
// content 自动识别格式(addImage 内部处理):
// - "data:image/jpg;base64,..." → Base64 图片,生成 <img src="data:...">
// - "http(s)://..." → URL 图片,生成 <img src="..." crossOrigin="anonymous">
// - "<img ..." → HTML 标签直接透传
// - 其他(如 "C:\test.jpg") → 本地文件路径,直接传给 ADD_PRINT_IMAGE
}Base64 格式要点:
data:image/jpg;base64,XXXX中,逗号前是编码描述,逗号后是内容。image/后的格式标识(如jpg)必须与生成编码时的实际图片格式一致。支持的图片格式:bmp、jpg、jpeg、gif、png、ico、emf、wmf
跨域说明:
addImage传入 URL 时自动加crossOrigin="anonymous", 但 C-Lodop 服务端渲染<img>时仍可能受限。 对于第三方跨域图片,推荐使用addImageFromUrl+ 后端代理彻底绕过 CORS。
BarcodeItemOptions
interface BarcodeItemOptions extends Rect {
type: BarcodeType | string; // 条码类型
value: string; // 条码值
name?: string;
}RectItemOptions
interface RectItemOptions extends Rect {
penStyle?: PenStyle; // 线条样式(默认 Solid)
penWidth?: number; // 线条宽度(默认 1)
color?: string | number; // 颜色(有值时调用 A 版本 API)
}LineItemOptions
interface LineItemOptions {
top1: number | string; // 起点 Y
left1: number | string; // 起点 X
top2: number | string; // 终点 Y
left2: number | string; // 终点 X
penStyle?: PenStyle;
penWidth?: number;
}DiagonalLineItemOptions
interface DiagonalLineItemOptions extends Rect {
penStyle?: PenStyle;
penWidth?: number;
color?: string | number;
}ShapeItemOptions
interface ShapeItemOptions extends Rect {
shapeType: ShapeType; // 图形类型
penStyle?: PenStyle;
penWidth?: number;
color?: string | number;
}PageSizeOptions
interface PageSizeOptions {
orientation?: Orientation; // 纸张方向
width?: number; // 宽度(单位:0.1mm,2100 = 210mm)
height?: number; // 高度(单位:0.1mm,2970 = 297mm)
name?: string; // 纸张名称(如 'A4',优先于宽高)
}PreviewWindowOptions
interface PreviewWindowOptions {
dispMode?: PreviewDispMode | number; // 显示模式
toolMode?: number; // 工具栏模式(按位标志)
directPrint?: boolean; // 是否默认直接打印
width?: number; // 窗口宽度
height?: number; // 窗口高度
buttonCaption?: string; // 打印按钮文字
}TextStyleOptions
interface TextStyleOptions {
fontName?: string;
fontSize?: number;
bold?: boolean;
italic?: boolean;
underline?: boolean;
alignment?: Alignment;
color?: string | number; // 有值时调用 A 版本 API
}ItemStyleOptions
interface ItemStyleOptions {
fontName?: string;
fontSize?: number;
bold?: number | boolean;
italic?: number | boolean;
underline?: number | boolean;
alignment?: Alignment;
fontColor?: string | number;
itemType?: ItemPageType;
hOrient?: HorizontalOrient;
vOrient?: VerticalOrient;
disabled?: number | boolean;
angle?: number;
autoWrap?: boolean;
leftMargin?: number;
rightMargin?: number;
topMargin?: number;
bottomMargin?: number;
penStyle?: PenStyle;
penWidth?: number;
stretch?: number;
readOnly?: number | boolean;
linked?: string;
contentVName?: string;
linePosition?: number;
qrCodeVersion?: number;
qrCodeErrorLevel?: string;
[key: string]: any; // 支持任意自定义属性
}PrinterInfo
interface PrinterInfo {
index: number; // 打印机序号
name: string; // 打印机名称
driverName: string; // 驱动名称
portName: string; // 端口名称
orientation: number; // 默认方向
paperSize: number; // 纸张代码
paperLength: number; // 纸张长度(0.1mm)
paperWidth: number; // 纸张宽度(0.1mm)
copies: number; // 默认份数
printQuality: number; // 打印质量(DPI)
isColor: boolean; // 是否彩色
isDuplex: boolean; // 是否支持双面
formName: string; // 当前纸张名称
pageSizes: string[]; // 支持的纸张列表
isDefault: boolean; // 是否为默认打印机
}LicenseOptions
interface LicenseOptions {
companyName: string;
license: string;
licenseA?: string;
licenseB?: string;
}TaskResult
interface TaskResult {
taskId: string; // 任务 ID
value: any; // 返回值
}脚本加载器
loader.ts 导出的底层加载函数,通常通过插件或 useCLodop 自动调用:
| 函数 | 返回值 | 说明 |
|------|--------|------|
| loadCLodopScript(urls?, timeout?) | Promise<CLodopRaw> | 从多个 URL 依次尝试加载脚本 |
| unloadCLodopScript() | void | 卸载已加载的脚本(用于重新加载) |
| getDefaultUrls() | string[] | 获取默认脚本 URL(自动区分 HTTP/HTTPS) |
| checkServiceAvailable(host?, port?, timeout?) | Promise<boolean> | 检查 C-Lodop 服务端口连通性 |
| getLoadState() | LoadState | 获取当前加载状态 |
| isHttpsEnv() | boolean | 检测当前页面是否 HTTPS |
完整示例
商品标签打印
import { useCLodop, Orientation, BarcodeType, PenStyle } from 'vue3-clodop';
const { printer, isReady } = useCLodop();
function printLabel(product: { name: string; price: number; sku: string }) {
if (!printer.value) return;
printer.value
.init('商品标签')
.setPageSize({ orientation: Orientation.Portrait, width: 1000, height: 500 })
.addRect({ top: 5, left: 5, width: '96%', height: '92%', penStyle: PenStyle.Solid, penWidth: 1 })
.addText({ top: 10, left: 15, width: 180, height: 20, content: `商品:${product.name}` })
.setItemStyles(0, { fontSize: 11, bold: true })
.addText({ top: 35, left: 15, width: 100, height: 18, content: `价格:${product.price.toFixed(2)}` })
.addBarcode({ top: 60, left: 15, width: 180, height: 50, type: BarcodeType.Code128Auto, value: product.sku })
.addBarcode({ top: 15, left: 215, width: 120, height: 120, type: BarcodeType.QRCode, value: product.sku })
.preview();
}异步打印并等待结果
async function printAndWait() {
if (!printer.value) return;
printer.value
.init('报表')
.setPageSize({ orientation: Orientation.Landscape, width: 2970, height: 2100, name: 'A4' })
.addHtml({ top: 20, left: 20, width: '100%', height: '100%', content: reportHtml });
try {
const result = await printer.value.printAsync();
console.log(`打印完成: taskId=${result.taskId}, value=${result.value}`);
} catch (e) {
console.error('打印失败:', e);
}
}多页打印
printer.value
.init('多页报告')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.addText({ top: 50, left: 50, width: 500, height: 40, content: '第一页' })
.newPage()
.addText({ top: 50, left: 50, width: 500, height: 40, content: '第二页' })
.setPageRange(1, 2)
.preview();PDF 文件打印
两层限制:
- C-Lodop 限制:
ADD_PRINT_PDF(print.js:1487-1491)仅接受本地路径或 Base64 字符串,远程 URL 直接传入会空白页- 浏览器 CORS 限制:
fetchPdfAsBase64使用浏览器 fetch API,受同源策略约束。第三方跨域 URL(目标服务器未设Access-Control-Allow-Origin头)会被浏览器拦截解决方案对照表:
| 场景 | 方案 | |------|------| | 本地文件路径 |
addPdf({ content: 'C:\\...' })| | 同源 / 已配 CORS 的 URL |fetchPdfAsBase64(url)或addPdfFromUrl(url, rect)| | 第三方跨域 URL | 后端代理中转 →fetchPdfAsBase64('/api/proxy/pdf?url=...')| | 后端 API 返回 Blob |blobToBase64(blob)→addPdf({ content: base64 })| |<input type="file">|readFileAsBase64(file)或addPdfFromFile(file, rect)|
import { fetchPdfAsBase64, readFileAsBase64, blobToBase64 } from 'vue3-clodop';
// 方式一:本地文件路径(仅限本地 C-Lodop 服务)
printer.value
.init('PDF 打印')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.addPdf({ top: 0, left: 0, width: '100%', height: '100%', content: 'C:\\Documents\\report.pdf' })
.preview();
// 方式二:同源或已配 CORS 的远程 URL
async function printRemotePdf(url: string) {
const base64 = await fetchPdfAsBase64(url);
printer.value!
.init('远程 PDF')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.addPdf({ top: 0, left: 0, width: '100%', height: '100%', content: base64 })
.preview();
}
// 方式三:跨域 PDF — 通过后端代理中转(推荐)
async function printCrossOriginPdf(thirdPartyUrl: string) {
// 后端代理接口示例:GET /api/proxy/pdf?url=xxx → 返回 PDF 文件流
const base64 = await fetchPdfAsBase64(`/api/proxy/pdf?url=${encodeURIComponent(thirdPartyUrl)}`);
printer.value!
.init('跨域 PDF')
.addPdf({ top: 0, left: 0, width: '100%', height: '100%', content: base64 })
.preview();
}
// 方式四:后端 API 直接返回 Blob(如 axios responseType: 'blob')
async function printBlobPdf(orderId: string) {
const resp = await fetch(`/api/orders/${orderId}/pdf`);
const blob = await resp.blob();
const base64 = await blobToBase64(blob);
printer.value!
.init(`订单${orderId}`)
.addPdf({ top: 0, left: 0, width: '100%', height: '100%', content: base64 })
.preview();
}
// 方式五:addPdfFromUrl 异步链式调用
async function printRemotePdfChained(url: string) {
const p = printer.value!
.init('远程 PDF')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' });
await p.addPdfFromUrl(url, { top: 0, left: 0, width: '100%', height: '100%' });
p.preview();
}
// 方式六:<input type="file"> 本地文件选择
async function printFromFileInput(file: File) {
const base64 = await readFileAsBase64(file);
printer.value!
.init('本地文件 PDF')
.addPdf({ top: 0, left: 0, width: '100%', height: '100%', content: base64 })
.preview();
}图片打印
两层限制(与 PDF 类似):
- C-Lodop 限制:
ADD_PRINT_IMAGE(print.js:1459)接受 HTML<img>标签或本地路径- 浏览器 CORS 限制:跨域
<img>可能被 C-Lodop 服务端拒绝加载addImage 自动处理:传入 URL 时自动生成
<img crossOrigin="anonymous">, 但对于严格跨域场景,推荐addImageFromUrl+ 后端代理彻底绕过。解决方案对照表:
| 场景 | 方案 | |------|------| | 同域 URL |
addImage({ content: 'http://localhost:8000/photo.jpg' })| | Base64 data URI |addImage({ content: 'data:image/png;base64,...' })| | 自定义 HTML |addImage({ content: '<img src="..." crossOrigin="anonymous" width="200px" />' })| | 本地文件路径 |addImage({ content: 'C:\\Photos\\banner.png' })| | 第三方跨域 URL |addImageFromUrl('/api/proxy/image?url=...', rect)| |<input type="file">|addImageFromFile(file, rect)| | 后端返回 Blob |fetchImageAsDataUri或readFileAsDataUri→addImage|
import { fetchImageAsDataUri, readFileAsDataUri } from 'vue3-clodop';
// 方式一:URL 图片(addImage 自动生成 <img crossOrigin="anonymous">)
printer.value
.init('图片打印')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.addImage({ top: 50, left: 50, width: 500, height: 375, content: 'https://example.com/photo.jpg' })
.preview();
// 等效于: ADD_PRINT_IMAGE(50,50,500,375, '<img border="0" src="https://..." crossOrigin="anonymous" width="500px" height="375px" />')
// 方式二:Base64 图片(格式标识须与实际一致)
const canvas = document.getElementById('myCanvas') as HTMLCanvasElement;
const dataUri = canvas.toDataURL('image/png'); // data:image/png;base64,...
printer.value
.init('Canvas 截图打印')
.addImage({ top: 20, left: 20, width: '96%', height: '94%', content: dataUri })
.preview();
// 方式三:本地文件路径
printer.value
.init('本地图片')
.addImage({ top: 0, left: 0, width: '100%', height: '100%', content: 'C:\\Photos\\banner.png' })
.preview();
// 方式四:自定义 HTML img 标签(完全控制属性)
printer.value
.init('自定义 img')
.addImage({
top: 60, left: 50, width: 300, height: 300,
content: '<img border="0" src="http://127.0.0.1:18000/CLodopDemos/PrintSample8.jpg" crossOrigin="anonymous" width="200px" height="200px"/>',
})
.preview();
// 方式五:跨域图片 — 通过后端代理 + addImageFromUrl(推荐)
async function printCrossOriginImage(thirdPartyUrl: string) {
const proxyUrl = `/api/proxy/image?url=${encodeURIComponent(thirdPartyUrl)}`;
const p = printer.value!.init('跨域图片');
await p.addImageFromUrl(proxyUrl, { top: 50, left: 50, width: 500, height: 375 });
p.preview();
}
// 方式六:<input type="file"> 选择本地图片
async function printFromFileInput(file: File) {
const p = printer.value!.init('本地文件图片');
await p.addImageFromFile(file, { top: 50, left: 50, width: 500, height: 400 });
p.preview();
}
// 方式七:后端 API 返回图片 Blob → 手动转 data URI
async function printImageFromApi(url: string) {
const dataUri = await fetchImageAsDataUri(url);
// dataUri = "data:image/jpeg;base64,/9j/4AAQ..."(MIME 自动推断)
printer.value!.init('API 图片')
.addImage({ top: 50, left: 50, width: 500, height: 375, content: dataUri })
.preview();
}
// 方式八:证件照排版打印(多张图片网格)
function printIdPhotos(photoBase64: string) {
const p = printer.value!;
p.init('证件照打印')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' });
const photoW = 250, photoH = 350, gap = 20;
const cols = 4, rows = 6;
const startX = 100, startY = 80;
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
const x = startX + col * (photoW + gap);
const y = startY + row * (photoH + gap);
p.addImage({ top: y, left: x, width: photoW, height: photoH, content: photoBase64 });
}
}
p.preview();
}对角线与交叉表格
import { PenStyle } from 'vue3-clodop';
// 绘制带斜线表头的表格
printer.value
.init('斜线表头')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
// 外边框
.addRect({ top: 50, left: 50, width: 500, height: 300, penStyle: PenStyle.Solid, penWidth: 2 })
// 斜线表头单元格
.addRect({ top: 50, left: 50, width: 120, height: 60, penStyle: PenStyle.Solid, penWidth: 1 })
.addDnLine({ top: 50, left: 50, width: 120, height: 60, penStyle: PenStyle.Solid, penWidth: 1 })
// 斜线左下角文字(行标题)
.addText({ top: 80, left: 55, width: 50, height: 20, content: '姓名' })
.setItemStyle(0, 'FontSize', 9)
// 斜线右上角文字(列标题)
.addText({ top: 55, left: 100, width: 60, height: 20, content: '科目' })
.setItemStyle(0, 'FontSize', 9)
// 列标题
.addText({ top: 65, left: 180, width: 80, height: 30, content: '语文' })
.addText({ top: 65, left: 270, width: 80, height: 30, content: '数学' })
.addText({ top: 65, left: 360, width: 80, height: 30, content: '英语' })
// 横线分隔
.addLine({ top1: 110, left1: 50, top2: 110, left2: 550, penStyle: PenStyle.Solid, penWidth: 1 })
.addLine({ top1: 170, left1: 50, top2: 170, left2: 550, penStyle: PenStyle.Solid, penWidth: 1 })
// 竖线分隔
.addLine({ top1: 50, left1: 170, top2: 350, left2: 170, penStyle: PenStyle.Solid, penWidth: 1 })
.addLine({ top1: 50, left1: 260, top2: 350, left2: 260, penStyle: PenStyle.Solid, penWidth: 1 })
.addLine({ top1: 50, left1: 350, top2: 350, left2: 350, penStyle: PenStyle.Solid, penWidth: 1 })
.preview();套打(在预印表单上精确定位打印)
// 套打的关键:精确控制每个打印项的 top/left 坐标,配合预印表单
printer.value
.init('快递面单套打')
.setPageSize({ orientation: Orientation.Portrait, width: 1000, height: 1800 })
.setPrinter('针式打印机')
// 寄件人信息(坐标需根据实际面单调整)
.addText({ top: 120, left: 80, width: 300, height: 25, content: '张三' })
.setItemStyle(0, 'FontSize', 10)
.addText({ top: 150, left: 80, width: 400, height: 25, content: '13800138000' })
.addText({ top: 180, left: 80, width: 400, height: 40, content: '上海市浦东新区陆家嘴环路 1000 号' })
.setItemStyles(0, { fontSize: 9, autoWrap: true })
// 收件人信息(大号字体突出显示)
.addText({ top: 300, left: 80, width: 300, height: 35, content: '李四' })
.setItemStyles(0, { fontSize: 14, bold: true })
.addText({ top: 340, left: 80, width: 400, height: 25, content: '18900189000' })
.setItemStyle(0, 'FontSize', 12)
.addText({ top: 370, left: 80, width: 400, height: 50, content: '北京市朝阳区建国路 88 号 SOHO 现代城 A 座 2001' })
.setItemStyles(0, { fontSize: 11, autoWrap: true })
// 大头笔区域(分拣码)
.addText({ top: 450, left: 100, width: 200, height: 60, content: '010-朝阳' })
.setItemStyles(0, { fontSize: 28, bold: true })
// 快递单号条码
.addBarcode({ top: 550, left: 80, width: 350, height: 80, type: BarcodeType.Code128Auto, value: 'SF1234567890123' })
.addText({ top: 635, left: 80, width: 350, height: 20, content: 'SF1234567890123' })
.setItemStyles(0, { fontSize: 10, alignment: 2 })
.print(); // 套打通常直接打印,不预览ESC/POS 热敏小票打印
// 通过 sendRawData 直接发送 ESC/POS 指令到小票打印机
function printReceipt(items: Array<{ name: string; qty: number; price: number }>) {
const ESC = '\x1B';
const GS = '\x1D';
const LF = '\x0A';
let cmds = '';
cmds += ESC + '@'; // 初始化
cmds += ESC + 'a' + '\x01'; // 居中
cmds += GS + '!' + '\x11'; // 放大一倍
cmds += '我的小店' + LF;
cmds += GS + '!' + '\x00'; // 恢复正常大小
cmds += ESC + 'a' + '\x00'; // 左对齐
cmds += '================================' + LF;
cmds += '商品名称 数量 金额' + LF;
cmds += '--------------------------------' + LF;
let total = 0;
for (const item of items) {
const amount = item.qty * item.price;
total += amount;
const line = item.name.padEnd(16) +
String(item.qty).padStart(4) +
amount.toFixed(2).padStart(8);
cmds += line + LF;
}
cmds += '================================' + LF;
cmds += ESC + 'a' + '\x02'; // 右对齐
cmds += GS + '!' + '\x01'; // 字体加宽
cmds += `合计: ${total.toFixed(2)}` + LF;
cmds += GS + '!' + '\x00'; // 恢复
cmds += ESC + 'a' + '\x00'; // 左对齐
cmds += LF;
cmds += ESC + 'a' + '\x01'; // 居中
cmds += '谢谢惠顾,欢迎下次光临!' + LF;
cmds += LF + LF + LF;
cmds += GS + 'V' + '\x00'; // 切纸
printer.value!
.init('小票')
.setPrinter('POS-58')
.sendRawData(cmds);
}图形绘制综合示例
import { PenStyle, ShapeType } from 'vue3-clodop';
printer.value
.init('图形综合示例')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
// 标题
.addText({ top: 30, left: 50, width: 500, height: 40, content: '图形绘制综合演示' })
.setItemStyles(0, { fontSize: 20, bold: true, fontColor: '#1e293b' })
// 实线矩形
.addRect({ top: 100, left: 50, width: 200, height: 120, penStyle: PenStyle.Solid, penWidth: 2 })
.addText({ top: 150, left: 90, width: 120, height: 20, content: '实线矩形' })
.setItemStyle(0, 'FontSize', 10)
// 虚线矩形(带颜色)
.addRect({ top: 100, left: 300, width: 200, height: 120, penStyle: PenStyle.Dash, penWidth: 1, color: '#4f46e5' })
.addText({ top: 150, left: 340, width: 120, height: 20, content: '虚线矩形' })
.setItemStyles(0, { fontSize: 10, fontColor: '#4f46e5' })
// 椭圆
.addEllipse({ top: 260, left: 50, width: 200, height: 120, penStyle: PenStyle.Solid, penWidth: 2, color: '#10b981' })
.addText({ top: 310, left: 110, width: 80, height: 20, content: '椭圆' })
.setItemStyle(0, 'FontSize', 10)
// 通用图形 — 下对角线
.addShape({ shapeType: ShapeType.DownLine, top: 260, left: 300, width: 200, height: 120, penStyle: PenStyle.Solid, penWidth: 2, color: '#ef4444' })
.addText({ top: 390, left: 340, width: 120, height: 20, content: 'Shape 下对角线' })
.setItemStyle(0, 'FontSize', 10)
// 专用对角线 API — X 形交叉
.addRect({ top: 420, left: 50, width: 200, height: 200, penStyle: PenStyle.Solid, penWidth: 1 })
.addDnLine({ top: 420, left: 50, width: 200, height: 200, penStyle: PenStyle.Solid, penWidth: 2, color: '#4f46e5' })
.addUpLine({ top: 420, left: 50, width: 200, height: 200, penStyle: PenStyle.Solid, penWidth: 2, color: '#10b981' })
.addText({ top: 505, left: 100, width: 100, height: 20, content: 'X 交叉' })
.setItemStyle(0, 'FontSize', 10)
// 各种线型演示
.addLine({ top1: 440, left1: 300, top2: 440, left2: 550, penStyle: PenStyle.Solid, penWidth: 2 })
.addText({ top: 445, left: 560, width: 60, height: 15, content: '实线' })
.setItemStyle(0, 'FontSize', 8)
.addLine({ top1: 475, left1: 300, top2: 475, left2: 550, penStyle: PenStyle.Dash, penWidth: 2 })
.addText({ top: 480, left: 560, width: 60, height: 15, content: '虚线' })
.setItemStyle(0, 'FontSize', 8)
.addLine({ top1: 510, left1: 300, top2: 510, left2: 550, penStyle: PenStyle.Dot, penWidth: 2 })
.addText({ top: 515, left: 560, width: 60, height: 15, content: '点线' })
.setItemStyle(0, 'FontSize', 8)
.addLine({ top1: 545, left1: 300, top2: 545, left2: 550, penStyle: PenStyle.DashDot, penWidth: 2 })
.addText({ top: 550, left: 560, width: 60, height: 15, content: '点划线' })
.setItemStyle(0, 'FontSize', 8)
.addLine({ top1: 580, left1: 300, top2: 580, left2: 550, penStyle: PenStyle.DashDotDot, penWidth: 2 })
.addText({ top: 585, left: 560, width: 80, height: 15, content: '双点划线' })
.setItemStyle(0, 'FontSize', 8)
.preview();双面打印
printer.value
.init('双面打印')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.setMode('DOUBLE_SIDED_PRINT', 1) // 开启双面打印
.addText({ top: 50, left: 50, width: 500, height: 40, content: '正面内容' })
.newPage()
.addText({ top: 50, left: 50, width: 500, height: 40, content: '背面内容' })
.newPage()
.addText({ top: 50, left: 50, width: 500, height: 40, content: '第二张正面' })
.newPage()
.addText({ top: 50, left: 50, width: 500, height: 40, content: '第二张背面' })
.print();页眉页脚
import { ItemPageType, HorizontalOrient, VerticalOrient } from 'vue3-clodop';
printer.value
.init('带页眉页脚的文档')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
// 页眉 — 每页顶部自动重复
.addText({ top: 15, left: 50, width: 500, height: 20, content: '公司机密文件 — 内部资料' })
.setItemStyles(0, { fontSize: 9, fontColor: '#999', itemType: ItemPageType.Header })
.addLine({ top1: 38, left1: 50, top2: 38, left2: 550, penStyle: PenStyle.Solid, penWidth: 1 })
.setItemStyle(0, 'ItemType', ItemPageType.Header)
// 页脚 — 每页底部自动重复,#页号# 会被替换为实际页码
.addText({ top: '285mm', left: 50, width: 500, height: 20, content: '第 #页号# 页 / 共 #总页数# 页' })
.setItemStyles(0, { fontSize: 9, fontColor: '#999', alignment: 2, itemType: ItemPageType.Footer })
// 正文
.addText({ top: 60, left: 50, width: 500, height: 40, content: '第一页正文内容' })
.setItemStyle(0, 'FontSize', 14)
.newPage()
.addText({ top: 60, left: 50, width: 500, height: 40, content: '第二页正文内容' })
.setItemStyle(0, 'FontSize', 14)
.preview();水印效果
printer.value
.init('水印文档')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
// 水印文字 — 旋转 45 度、半透明灰色、大号字体
.addText({ top: 350, left: 80, width: 500, height: 60, content: '仅供内部使用' })
.setItemStyles(0, {
fontSize: 40,
fontColor: '#dddddd',
bold: true,
angle: -45,
itemType: ItemPageType.HeaderFooter, // 每页重复
})
// 正常内容
.addText({ top: 50, left: 50, width: 500, height: 40, content: '合同文档正文' })
.setItemStyle(0, 'FontSize', 14)
.addHtml({ top: 100, left: 50, width: '90%', height: '80%', content: contractHtml })
.preview();批量连续打印(不清除数据)
import { PrintModeType } from 'vue3-clodop';
async function batchPrint(orders: Array<{ id: string; content: string }>) {
if (!printer.value) return;
for (let i = 0; i < orders.length; i++) {
const order = orders[i];
printer.value
.init(`订单-${order.id}`)
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.addText({ top: 50, left: 50, width: 500, height: 30, content: `订单号: ${order.id}` })
.setItemStyles(0, { fontSize: 16, bold: true })
.addHtml({ top: 100, left: 50, width: '90%', height: '80%', content: order.content });
// 使用异步打印,等每份完成后再打下一份
const result = await printer.value.printAsync();
console.log(`订单 ${order.id} 打印完成: ${result.value}`);
}
}自定义预览窗口
import { PreviewDispMode } from 'vue3-clodop';
printer.value
.init('自定义预览')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.setPreviewWindow({
dispMode: PreviewDispMode.Windowed, // 窗口模式(非全屏)
toolMode: 0, // 显示全部工具栏
directPrint: false, // 不默认直接打印
width: 900, // 窗口宽度
height: 700, // 窗口高度
buttonCaption: '确认打印', // 打印按钮文字
})
.setMode('AUTO_CLOSE_PREWINDOW', 1) // 打印后自动关闭预览窗口
.addText({ top: 50, left: 50, width: 500, height: 40, content: '自定义预览窗口示例' })
.preview();保存为文件(PDF / 图片)
// 保存为 PDF 文件
printer.value
.init('导出 PDF')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.addText({ top: 50, left: 50, width: 500, height: 40, content: '这份文档将被保存为 PDF' })
.setItemStyle(0, 'FontSize', 16)
.addHtml({ top: 120, left: 50, width: '90%', height: '80%', content: reportHtml })
.saveToFile('C:\\Documents\\report.pdf');
// 保存为图片并设置格式
printer.value
.init('导出图片')
.setPageSize({ orientation: Orientation.Portrait, width: 2100, height: 2970, name: 'A4' })
.setSaveMode('SAVEAS_IMGFILETYPE', 'jpg') // 指定图片格式
.addText({ top: 50, left: 50, width: 500, height: 40, content: '这份文档将被保存为图片' })
.saveToFile('C:\\Documents\\page.jpg');
// 异步保存并等待结果
const result = await printer.value
.init('异步导出')
.addHtml({ top: 0, left: 0, width: '100%', height: '100%', content: reportHtml })
.saveToFileAsync('C:\\Documents\\output.pdf');
console.log(`保存完成: ${result.value}`);串口/端口通信
// 向 COM 串口写入数据(适用于电子秤、扫码枪等设备)
printer.value!.writePort('COM1', 'R'); // 发送读取指令
// 异步读取串口返回数据
const portResult = await printer.value!.readPortAsync('COM1');
console.log('串口返回:', portResult.value);
// 获取系统信息
const machineId = printer.value!.getSystemInfo('MachineID');
console.log('机器码:', machineId);文件对话框选择文件
// 弹出文件选择对话框
const filePath = await printer.value!.getDialogValueAsync('ChooseFile', '');
console.log('用户选择的文件:', filePath.value);
// 弹出保存对话框
const savePath = await printer.value!.getDialogValueAsync('SaveFile', 'output.pdf');
console.log('用户选择的保存路径:', savePath.value);
// 弹出文件夹选择
const folder = await printer.value!.getDialogValueAsync('ChooseFolder', '');
console.log('用户选择的文件夹:', folder.value);连接状态监控
import { CLodopPrinter } from 'vue3-clodop';
// 静态方法 — 检查服务是否可用
if (CLodopPrinter.isAvailable()) {
console.log('C-Lodop 服务已启动');
}
// 含 WebSocket 连接检查
if (CLodopPrinter.isAvailable(true)) {
console.log('WebSocket 已连接,可使用全部功能');
}
// 实例方法 — 查看详细状态
if (printer.value) {
console.log('版本:', printer.value.version);
console.log('扩展版本:', printer.value.cVersion);
console.log('WebSocket:', printer.value.isSocketOpened ? '已连接' : '未连接');
console.log('空闲:', printer.value.isIdle() ? '是' : '否');
console.log('服务地址:', printer.value.hostURI);
// 手动重连 WebSocket
if (!printer.value.isSocketOpened) {
printer.value.reconnectWebSocket();
}
}
// 注册全局就绪回调
CLodopPrinter.onCLodopOpened((clodop) => {
console.log('C-Lodop WebSocket 已连接,版本:', clodop.VERSION);
});