vg-print
v1.1.317
Published
vg-print supports visual drag and drop design templates, with functions such as previewing and exporting PDFs/images. Silent printing can be achieved in conjunction with a dedicated client
Readme
vg-print
[开源免费]一个开箱即用的打印设计器组件库(Vue 3)。现在聚焦于单一组件 FullDesigner,同时暴露底层 hiprint 能力与客户端直连(hiwebSocket)配置,便于快速集成模板设计、预览、浏览器打印、导出 PDF/图片、直接打印、客户端生成pdf/图片、数据源管理、多语言支持等功能。
- 您可以直接安装引入体验功能.功能在不断完善中,请及时更新使用,欢迎反馈与建议,共同成长
- 没有域名限制,无网可用. 随时提供帮助和解决问题.
- npm搜索vg-print.
- 联系我加 QQ: 984239686 或使用首页有微信加入群聊解决问题.
Vue 2 版本: 如果你使用的是 Vue2+webpack4.0以上,请查看 vg-print-vue2
授权密钥(authKey)与默认水印
- 行为说明:
- 设计态(FullDesigner 设计界面):不自动注入默认水印;是否显示水印由面板中的“水印功能”设置项决定,与
authKey无关。 - 运行态(预览、浏览器打印、导出 PDF/图片、直连打印):
- 无授权(未注册
authKey):- 面板未填写内容 → 显示默认水印
- 面板填写了内容 → 显示面板内容 + "试用版" 后缀
- 有授权(已注册有效
authKey):- 面板未填写内容 → 不显示水印(默认水印被移除)
- 面板填写了内容 → 显示面板内容(无后缀)
- 无授权(未注册
- 设计态(FullDesigner 设计界面):不自动注入默认水印;是否显示水印由面板中的“水印功能”设置项决定,与
- 注册授权密钥(密钥添加除水印):
在项目入口(如
main.js或App.vue)尽早注册:
注册后,以下所有使用方式均会自动生效(移除默认水印):import { hiprint } from 'vg-print'; // 填入生成的 Key hiprint.register({ authKey: 'eyJrIjoiZ21jNTc2MDMzNyJ9' });- 完整设计器组件
FullDesigner - 核心类
new hiprint.PrintTemplate(...) - 轻量运行时 helper
createTemplate(...)
- 完整设计器组件
- 示例:轻量运行时使用授权
import { hiprint, createTemplate, printBrowser } from 'vg-print'
hiprint.register({ authKey: 'eyJrIjoiZ21jNTc2MDMzNyJ9' })
const tpl = createTemplate(tmplJson) // 不再自动注入默认水印
printBrowser(tpl, data)- 自定义或显式控制水印:
// 无授权时,库会注入默认水印;如需自定义水印样式/内容
const tpl = new hiprint.PrintTemplate({
template: {},
watermarkOptions: { content: 'your-brand', timestamp: true, rotate: 20 }
})
// 有授权时,运行态不会注入默认水印;若仍需水印,请显式传入
const tpl2 = createTemplate(tmplJson, {
watermarkOptions: { content: 'your-brand', timestamp: true }
})
// 设计态由面板设置项决定水印,不受 authKey 控制。
// 运行态的默认水印由授权控制,不建议通过传入空对象取消;如需取消,请注册有效 authKey。
const tpl3 = new hiprint.PrintTemplate({ template: {}, watermarkOptions: { content: 'your-brand', timestamp: true } })- 插件注册(可选):
import { hiprint } from 'vg-print'
// 两种形式的插件均支持
function pluginFn(h) { /* 扩展逻辑 */ }
const pluginObj = { install(h) { /* 扩展逻辑 */ } }
hiprint.register({
authKey: 'eyJrIjoiZ21jNTc2MDMzNyJ9',
plugins: [pluginFn, pluginObj]
})默认水印参数参考:
{ content: 'vg-print', timestamp: true }静默打印客户端工具安装包
特性
- 全功能页面组件
FullDesigner,直接使用,无需拼装子组件 - 支持预览、浏览器打印、导出 PDF/图片、直接打印(需客户端)
- 通过属性配置
hiwebSocket的host、token与自动连接 - 暴露实例方法:预览、打印、导出、客户端生成pdf/图片等,外部可直接调用
- 集成并导出
hiprint,可进行模板对象级的高级定制
安装
npm i vg-print可选依赖:直连打印/客户端连接(socket.io-client)
- 本库默认不内置
socket.io-client,以减少默认安装体积。 - 仅当你需要“直连打印/客户端连接(hiwebSocket)”能力(如
print()/print2()/ 自动连接)时,才需要安装并注入:
npm i socket.io-client在项目入口(如 main.ts)注入:
import { io } from 'socket.io-client'
import { setSocketIo } from 'vg-print'
setSocketIo(io)也可直接使用 window.io = io(等价)。
可选依赖:数据源(axios)
- 本库默认不内置
axios,以减少默认安装体积。 - 仅当你需要“数据源管理/接口取数/字段联动”能力时,才需要安装并注入:
npm i axios在项目入口(如 main.ts)注入:
import axios from 'axios'
import { setHttpClient } from 'vg-print'
setHttpClient(axios)未安装/未注入时,“数据源”入口会自动禁用;即使误触发也不会导致项目报错。
可选插件:条码/二维码(@vg-print/plugin-bwip-js)
- 本库默认不内置
bwip-js,以减少默认安装体积。 - 仅当你需要“条形码/二维码元素(barcode/qrcode)”能力时,才需要安装并注册插件:
npm i @vg-print/plugin-bwip-js在项目入口(如 main.ts)注册插件(与 authKey 一起或单独均可):
import { hiprint } from 'vg-print'
import pluginEleBwip from '@vg-print/plugin-bwip-js'
hiprint.register({
plugins: [
pluginEleBwip({
barcodeTypeList: [{ title: 'EAN-13', value: 'ean13' }],
qrcodeTypeList: [{ title: 'QR Code', value: 'qrcode' }]
})
]
})不传参数则使用插件内置的默认列表;你也可以按 { title, value, group } 的结构传入完整的分组列表(group: true 表示分组标题)。
Header 顶部工具栏组件
- 用于页面一级头部区域,内置常用操作按钮与打印机设置;支持通过
props与slots定制。 - 默认嵌入在
FullDesigner中;也可单独使用。
属性(Props)
logoHtml: string左侧 Logo 区自定义 HTML 片段title: string左侧标题文本printCount: number打印份数,默认1(支持v-model:printCount)printerName: string当前选择的打印机名称(支持v-model:printerName)printerList: Array<{ name: string; label: string }>打印机列表waitShowPrinter: boolean显示“浏览器打印”按钮的加载状态languages: Array<{ label: string; value: string }>语言切换下拉选项
事件(Emits)
preview打开预览print-view浏览器打印to-pdf导出 PDFto-image导出图片print直接打印(需客户端)clear-paper清空(带二次确认)save保存(拆分按钮的主键)edit-template打开“编辑模板数据”对话框edit-data打开“编辑打印数据”对话框lang-change语言切换(值为语言码:cn、en、de、es、fr、it、ja、ru、cn_tw)feedback反馈/帮助
插槽(Slots)
headerLeft左侧区域(默认:logo + 标题)headerCenter中间自定义区域(默认空)headerRight右侧操作区(默认:打印机与一组按钮)
如果发现外部调用安装过程页面样式有丢失情况, 可以引入打印样式重要提醒需要复制
【node_modules/@vg-print/hiprint/dist/css/print-lock.css】到开发资源目录。
例如: Vue 项目的 public 目录。
假如你部署的网站是: https://www.abcd.com/index.html
那么确保 https://www.abcd.com/print-lock.css
能够正常访问在你项目的 index.html 入口 添加 print-lock.css 打印样式【名称 print-lock.css】注意: media="print"
可以调整成相对链接/自有链接,但【重要】名称需要一致(print-lock.css):
<link rel="stylesheet" type="text/css" media="print" href="/print-lock.css" />使用示例:与 FullDesigner 配合
<template>
<FullDesigner
ref="designer"
:initial-template="tpl"
:initial-print-data="rows"
default-lang="cn"
:hi-host="host"
:hi-token="token"
:hi-auto-connect="true"
@save="onSave"
>
<!-- 顶部区域(Header 默认内置;也可通过 slot 定制) -->
<template #headerLeft>
<div style="display:flex;align-items:center;color:#fff;">
<img src="/logo.svg" style="height:24px;margin-right:8px;" />
<span>自定义标题</span>
</div>
</template>
<template #headerCenter>
<el-tag type="success">中间自定义区域</el-tag>
</template>
<!-- 保留默认按钮时无需提供 headerRight;若完全替换按钮则提供该插槽 -->
<template #headerRight>
<el-button size="small" @click="designer.value.preView()">预览</el-button>
<el-button size="small" @click="designer.value.printView()">浏览器打印</el-button>
<el-button type="primary" size="small" @click="designer.value.toPdf()">导出 PDF</el-button>
<el-button size="small" @click="designer.value.toImage()">导出图片</el-button>
<el-button size="small" @click="designer.value.print()">直接打印</el-button>
<el-button type="warning" size="small" @click="onClear()">清空</el-button>
<el-button type="success" size="small" @click="onSaveDirect()">保存</el-button>
</template>
</FullDesigner>
</template>
<script setup>
import { ref } from 'vue'
const designer = ref(null)
const host = ref('http://127.0.0.1:17521')
const token = ref('')
const tpl = { panels: [ /* ... */ ] }
const rows = [{ title: '病理图文报告', name: '东东' }]
const onSave = ({ template, data }) => { /* 保存到后端 */ }
const onClear = () => { /* 清空数据/元素 */ }
const onSaveDirect = () => designer.value?.save()
</script>使用示例:单独使用 Header
<template>
<Header
v-model:printCount="count"
v-model:printerName="printer"
:printerList="printers"
:waitShowPrinter="loading"
:languages="langs"
title="打印设计器"
@preview="onPreview"
@print-view="onPrintView"
@to-pdf="onToPdf"
@to-image="onToImage"
@print="onPrint"
@clear-paper="onClear"
@save="onSave"
@lang-change="onLangChange"
@feedback="onFeedback"
/>
</template>响应式策略(已内置)
- 窗口缩小时自动隐藏中间区域与次要按钮,保留右侧“保存”和“反馈”等关键操作;左侧 logo/标题不受影响。
- 断点规则:
≤1600px隐藏中间区域≤1400px隐藏打印份数、打印机选择、预览、浏览器打印、导出 PDF、导出图片≤1200px隐藏直接打印、语言切换≤992px隐藏清空≤768px隐藏标题文本(保留 Logo)
提示:如需完全自定义按钮,请提供
headerRight插槽实现自己的按钮布局。
Preview 预览组件
- 独立的预览弹窗组件,支持渲染模板 HTML、选择打印机、导出 PDF/图片、直接打印等。
- 可单独使用或与
FullDesigner搭配。
属性(Props)
printTemplate: object模板对象(hiprint.PrintTemplate或createTemplate返回值)printData: object | array打印数据printerList: Array<{ name: string; label: string }>打印机列表selectedPrinter: string选中的打印机名称dialogTitle: string弹窗标题,默认打印预览dialogTitleHtml: string弹窗标题 HTML 内容,默认''(支持 `弹窗标题)showTitle: boolean是否显示标题,默认trueshowPdf: boolean是否显示“导出 PDF”按钮,默认trueshowImg: boolean是否显示“导出图片”按钮,默认trueshowPrint2: boolean是否显示“直接打印”按钮,默认truepdfOptions: object导出 PDF 选项(参考toPdf)imageOptions: object导出图片 选项(参考toImage)directPrintOptions: object直接打印 选项(参考print)browserPrintOptions: object浏览器打印 选项(参考printView)showPrinterSelect: boolean是否显示“打印机选择”下拉区域,默认truemodalShow: boolean弹窗显隐(支持v-model:modalShow)width: string | number弹窗宽度(默认'80%')defaultLang: string组件内 i18n 语言(Standalone 时使用);支持cn、en、de、es、fr、it、ja、ru、cn_tw;默认cn
预览头部标题使用
- 传纯文本(原有方式):
- dialogTitle: '预览单据'
- 传带标签 HTML:
- dialogTitleHtml: '订单预览'
- 用插槽完全自定义(推荐,样式控制最灵活):
- <template #title="{ title, html }">...
事件(Emits)
update:modalShow双向绑定弹窗显隐update:selectedPrinter选中打印机变更close关闭弹窗
暴露方法(defineExpose)
show(template, data, width?)显示并渲染预览内容(兼容旧调用)show(template, data, options?)显示并渲染预览内容(推荐)show(template, data, width, options?)同时传入宽度与高级回调参数hideModal()关闭弹窗init()初始化(内部使用)getTarget()获取当前hiprintTemplate实例
show 方法高级参数(options)
- 始终回调 { type, message, payload }
- 但只有“异常/进度”场景才会带 message 或 payload
- 普通状态(如 show:start 、 render:done 、 image:done )没有额外信息,所以就是 undefined
type PreviewShowOptions = {
width?: string | number
dialogTitle?: string
dialogTitleHtml?: string
showPdf?: boolean
showImg?: boolean
showPrint2?: boolean
showPrinterSelect?: boolean
showTitle?: boolean
pdfOptions?: object
imageOptions?: object
directPrintOptions?: object
browserPrintOptions?: object
onClick?: (type: 'pdf' | 'img' | 'print' | 'print2' | 'close') => void
onClose?: () => void
onRender?: () => void
callBackOptions?: {
statusCallback?: (status: {
type:
| 'show:start' | 'show:ready'
| 'render:start' | 'render:done' | 'render:error'
| 'pdf:start' | 'pdf:progress' | 'pdf:done' | 'pdf:error'
| 'image:start' | 'image:progress' | 'image:done' | 'image:error'
| 'print:start' | 'print:done' | 'print:error'
| 'directPrint:start' | 'directPrint:progress' | 'directPrint:done' | 'directPrint:error'
| 'close'
message?: string
payload?: any
}) => void
}
}使用示例(单独使用)
<template>
<el-button @click="openPreview">显示预览</el-button>
<Preview
ref="previewRef"
:show-title="false"
dialog-title="自定义预览标题"
v-model:modalShow="visible"
default-lang="cn"
:printerList="printers"
:selectedPrinter="printer"
@update:selectedPrinter="printer = $event"
/>
</template>
<script setup>
import { ref } from 'vue'
import { Preview, createTemplate } from 'vg-print'
import 'vg-print/style.css'
const previewRef = ref(null)
const visible = ref(false)
const printers = ref([{ name: 'HP_001', label: 'HP 打印机' }])
const printer = ref('')
const tmplJson = { panels: [ /* ... */ ] }
const data = { title: '病理图文报告', name: '东东' }
// show(template, data, width?)
// 参数说明:
// 1) template: createTemplate(...) 返回的模板实例(或 hiprint.PrintTemplate)
// 2) data: 打印数据(对象或数组)
// 3) width: 弹窗宽度;支持百分比字符串(如 '80%')或数字(如 980,单位 px)
const openPreview = () => {
const tpl = createTemplate(tmplJson) // 也可传入 hiprint.PrintTemplate
// vue2方式:
previewRef.value?.show(tpl, data, '80%')
// 或
previewRef.value?.show(tpl, data)
// 或
previewRef.value?.show(tpl, data, {
width: '80%',
dialogTitle: '自定义预览',
dialogTitleHtml: '<h2>自定义预览标题</h2>',
showTitle: false,
showPdf: false,
showImg: false,
showPrint2: false,
showPrinterSelect: false,
pdfOptions: {
scale: 2,
paperWidth: 210,
paperHeight: 297,
perPage: 6
},
imageOptions: {
paperWidth: 210,
paperHeight: 297,
limit: 6,
isDownload: true,
name: 'A4排版',
type: 'image/jpeg',
pixelRatio: 2,
},
directPrintOptions: {
printer: printer.value,
title: '测试打印',
copies: 2
},
browserPrintOptions: {
applyPanelLayoutHtml: true
},
onClick: (type) => {
// 示例:点击导出 PDF 按钮
if (type === 'pdf') {
console.log('[Preview onClick] 导出 PDF')
return
}
console.log('[Preview onClick]', type)
},
onClose: () => {
// 示例:弹窗关闭
console.log('[Preview onClose] 弹窗已关闭')
},
onRender: () => {
// 示例:预览内容渲染完成
console.log('[Preview onRender] 预览内容渲染完成')
},
callBackOptions: {
statusCallback: (status) => {
// 示例:导出进度(PDF/图片)
if (status.type === 'pdf:progress' || status.type === 'image:progress') {
const cur = status?.payload?.cur ?? 0
const total = status?.payload?.total ?? 0
console.log('[Preview progress]', cur, total)
return
}
console.log('[Preview status]', status.type, status.message || '')
}
}
})
}
</script>使用示例(与 FullDesigner 搭配)
<template>
<FullDesigner ref="designer" default-lang="cn" />
<Preview ref="previewRef" v-model:modalShow="visible" />
<el-button @click="designer.value.preView()">直接使用 FullDesigner 的预览</el-button>
<el-button @click="showCustomPreview">用 Preview 展示当前模板</el-button>
</template>
<script setup>
import { ref } from 'vue'
const designer = ref(null)
const previewRef = ref(null)
const visible = ref(false)
const showCustomPreview = () => {
const tpl = designer.value.getTemplate() // 假设暴露了获取模板的方法
const data = designer.value.getPrintData() // 假设暴露了获取数据的方法
previewRef.value.show(tpl, data, '80%')
}
</script>注意
- 使用组件库时请引入
vg-print/style.css,其中包含自定义图标字体与预览/设计样式。 Preview内部会根据printTemplate与printData自动渲染内容;也支持通过show(...)主动传入。show(...)兼容原签名show(template, data, width?),建议新项目统一使用options写法,便于扩展和维护。- 若在外部项目未安装插件(未执行
app.use(vgPrint))而单独使用Preview,请通过default-lang显式设置语言;安装插件时无需设置,语言默认随全局 i18n。
样式引入(确保设计与打印样式生效):
// 全局样式(组件库样式)
import 'vg-print/style.css'<!-- 打印锁样式(推荐;保证打印时样式稳定) -->
<link rel="stylesheet" type="text/css" media="print" href="/css/print-lock.css" />环境要求:Vue 3、Node >= 18.18。无需单独安装 vue-plugin-hiprint,本库已内置并导出 hiprint 能力。
快速开始
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import vgPrint from 'vg-print'
import 'vg-print/style.css'
createApp(App).use(vgPrint).mount('#app')<template>
<FullDesigner
ref="designer"
:hi-host="'http://127.0.0.1:17521'"
:hi-token="'your-token'"
:hi-auto-connect="true"
/>
<el-button @click="preview">预览</el-button>
<el-button @click="printBrowser">浏览器打印</el-button>
<el-button @click="exportPdf">导出 PDF</el-button>
<el-button @click="exportImage">导出图片</el-button>
<el-button @click="directPrint">直接打印(需客户端)</el-button>
</template>
<script setup>
import { ref } from 'vue'
const designer = ref(null)
// 预览
const preview = () => designer.value.preView()
// 浏览器打印
const printBrowser = () => designer.value.printView()
// 导出 PDF
const exportPdf = () => designer.value.toPdf()
// 导出图片
const exportImage = () => designer.value.toImage()
// 直接打印(需客户端已连接)
const directPrint = () => designer.value.print()
// 连接控制与参数设置
const setHostToken = () => designer.value.setHiwebSocket('http://127.0.0.1:17521', 'token')
// 主动连接客户端
const connect = () => designer.value.connect()
// 断开客户端
const disconnect = () => designer.value.disconnect()
// 关闭自动连接策略
const disableAutoConnect = () => designer.value.disAutoConnect()
</script>API(FullDesigner)
属性(Props,含描述)
hi-host: string客户端服务地址;示例http://127.0.0.1:17521,用于直连打印hi-token: string客户端鉴权令牌;与客户端配置一致时方可直连打印hi-auto-connect: boolean是否自动连接客户端;默认true,为false时需手动调用connect()initial-template: object初始化模板 JSON;为空时使用内置示例模板initial-print-data: object | array初始化打印数据;支持对象或数组,运行时变更会即时生效default-lang: string默认语言;支持cn、en、de、es、fr、it、ja、ru、cn_tw;默认cnconfig: object设计器引擎配置;会在初始化前注入到hiprint.setConfig(config)(同时写入window.HIPRINT_CONFIG)。常用字段:showAdsorbLine: boolean是否显示吸附参考线(拖动/缩放时的对齐辅助线)showPosition: boolean是否显示元素坐标提示(移动元素时显示位置)showSizeBox: boolean是否显示元素尺寸提示框(缩放时显示宽高)adsorbMin: number吸附阈值(距离小于等于该值时触发吸附,单位:pt)adsorbLineMin: number吸附线阈值(参考线判定阈值,单位:pt)font-list: array自定义字体列表;兼容原生new hiprint.PrintTemplate({ fontList })用法,支持外部传入如[{ title: '微软雅黑', value: 'Microsoft YaHei' }],会在初始化和运行时变更时同步应用到设计器/打印模板design-options: object设计器 UI/行为配置(初始化时生效):grid: boolean是否显示网格线,默认trueactivePanel: boolean是否默认显示右侧属性面板,默认trueadaptToSize: boolean是否初始化时自动缩放以适配设计区可视范围,默认false
theme: string | object主题;支持内置主题名或传入自定义主题对象theme-list: Array<string | object>主题列表(用于顶部主题切换菜单),默认:light/dark/emerald/corporate/bumblebee/retro/cyberpunk/valentineshow-option: object区域显示控制(默认全部显示):showHeader: boolean是否显示顶部 Header,默认trueshowToolbar: boolean是否显示二级工具栏 Toolbar,默认trueshowFooter: boolean是否显示底部 Footer,默认true
footer-text: string底部默认文案(仅在未提供#footer插槽时展示)
以上属性支持运行时动态修改;组件内部已监听并应用。
示例(FullDesigner 直接传入 config / designOptions):
<template>
<FullDesigner
:config="{ showAdsorbLine: true, showPosition: true, showSizeBox: true }"
:design-options="{ grid: true, activePanel: true, adaptToSize: true }"
theme="light"
:show-option="{ showHeader: true, showToolbar: true, showFooter: true }"
footer-text="联系我:xxxx(这里可写联系信息)"
/>
</template>示例(主题切换:限制可选主题 + 自定义主题):
<template>
<FullDesigner
:theme-list="[
'light',
'dark',
{ name: '自定义1', colors: { accent: '#16a34a', headerBg: '#16a34a', toolbarBg: '#f0fdf4' } }
]"
:theme="{ name: '自定义1', colors: { accent: '#16a34a', headerBg: '#16a34a', toolbarBg: '#f0fdf4' } }"
/>
</template>自定义主题颜色字段说明(theme.colors):
accent: string主题强调色(影响:滚动条、选中态边框/高亮、部分 hover)accentSoft: string强调色浅背景(可选,建议rgba;用于选中态/hover 底色,默认由accent自动生成)headerBg: stringHeader/面板标题栏背景色(属性/结构/历史面板的标题栏也会使用)headerText: stringHeader/面板标题栏文字颜色toolbarBg: string二级工具栏背景色panelBg: string左侧模板面板背景色(不传则默认跟随toolbarBg)surfaceBg: string面板/弹窗主体背景色(属性/结构/历史面板、右键菜单等)text: string主文字颜色mutedText: string次级文字颜色(列表辅助信息、提示文字等)border: string边框/分割线颜色menuBg: string右键菜单背景色(可选,默认跟随surfaceBg)menuHoverBg: string菜单 hover 背景色(可选)footerBg: stringFooter 背景色(可选,默认跟随surfaceBg)footerText: stringFooter 文字颜色(可选,默认跟随mutedText)
示例(自定义 Footer 内容):
<template>
<FullDesigner :show-option="{ showFooter: true }">
<template #footer>
<div style="width:100%;display:flex;justify-content:space-between;">
<span>联系信息:xxx</span>
<span>QQ群:xxx</span>
</div>
</template>
</FullDesigner>
</template>方法(通过组件 ref 调用,含描述)
preView()打开预览弹窗;将当前模板与数据渲染为预览 HTMLprintView()浏览器打印;不依赖客户端,调起系统打印对话框print()直接打印;需客户端已连接,按当前选定打印机输出toPdf()导出 PDF;使用基于@zumer/snapdom的导出链路,支持缩放比例、页边距、纸张排版等参数toImage()导出图片;使用基于@zumer/snapdom的导出链路,支持缩放比例、页边距、纸张排版等参数setHiwebSocket(host: string, token?: string, cb?: Function)设置客户端地址与令牌并尝试重连;cb(status, msg)为连接回调connect(cb?: Function)主动连接客户端;cb(status, msg)为连接回调disconnect()断开客户端连接disAutoConnect()关闭自动连接策略;阻止自动重连
事件(Emits,含描述)
save保存模板与数据;回调参数结构:
{
template, // 模板 JSON
data, // 当前打印数据(对象或数组)
templateId // 模板标识(若存在)
}示例:
<template>
<FullDesigner
:initial-template="tpl"
:initial-print-data="rows"
default-lang="cn"
@save="onSave"
/>
</template>
<script setup>
const onSave = ({ template, data, templateId }) => {
// 调用接口持久化到数据库
// await api.saveTemplate({ template, data, templateId })
}
</script>语言与国际化
- 通过
default-lang设置初始语言(cn默认为中文);内部会同步vue-i18n与hiprint的语言。 - 运行时可在页面右上角语言切换菜单切换(无需刷新)。
数据源使用说明
FullDesigner 内置了数据源管理与字段绑定能力,可用于将接口字段自动映射到设计器组件字段下拉中。
入口与能力
- 入口:二级工具栏点击“数据源”打开管理弹窗
- 能力:数据源配置、测试获取、数据处理脚本、错误处理脚本、字段来源规则(全局/按组件类型)
使用流程(推荐)
- 新增数据源并填写基础信息:
- 唯一名称
- 请求地址(URL)
- 请求方法(GET/POST/PUT/DELETE)
- 按需配置请求头、参数、发送数据:
- 类型支持:
string、number、boolean、expression
- 类型支持:
- 编写“数据处理”脚本(
processCode)并点击“测试链接”:- 左侧显示原始返回(
rawResult) - 右侧显示处理结果(
processed)
- 左侧显示原始返回(
- 配置“字段来源规则”并保存:
- 看板全局:
manual或global - 组件规则:
manual/global/custom
- 看板全局:
- 规则生效后,组件字段下拉会按规则自动展示字段列表
processCode / errorProcessCode 约定
processCode函数形态:
// (result, isSandbox, DSV, VFR) => { ...; return processed; }
return resulterrorProcessCode函数形态:
// (error, isSandbox, DSV, $message, VFR) => { ... }
$message.error(error.message)字段结构约定
推荐返回以下结构,字段下拉识别最稳定:
[
{ text: '字段显示名', field: '字段路径' }
]如果返回的是对象或对象数组,系统也会自动递归提取字段路径(如 user.name、order.items)。
示例:将接口返回转换为字段列表
return (result.data || []).map(item => ({
field: item.column_name,
text: item.table_comment || item.column_name
}))缓存与持久化策略(当前实现)
- 数据源配置持久化:
KEY_VG_DATASOURCES - 字段绑定规则持久化:
KEY_VG_FIELD_BINDINGS - 数据源运行时缓存:
KEY_VG_DS_RUNTIME_CACHE- 仅缓存处理后数据(
processed) - 不缓存原始返回(
rawResult) - 默认 TTL:30 分钟
- 默认最大条目:20
- 仅缓存处理后数据(
常见问题
- 测试成功但没有字段:
- 检查
processCode返回值是否为对象或对象数组 - 检查数据集 path 是否命中处理结果
- 检查
- 字段下拉未更新:
- 先“测试链接”生成字段,再“保存规则”
- 表达式参数无效:
expression求值异常会被忽略,建议先用简单表达式验证
高级用法(hiprint)
本库导出 hiprint,可直接创建与操作模板对象(hiprint.PrintTemplate):
若需要使用“直连打印/客户端连接(hiwebSocket)”相关能力,请先按上文注入 io;否则会提示缺失并导致连接失败。
import { hiprint, defaultElementTypeProvider } from 'vg-print'
// 全局配置
hiprint.setConfig({ showAdsorbLine: true, showPosition: true, showSizeBox: true })
// 注册插件
hiprint.register({ authKey: '', plugins: [] })
// 初始化元素提供器 (默认元素提供器)
hiprint.init({
// providers: [new defaultElementTypeProvider()],
host: 'http://localhost:17521',
token: '',
lang: 'en'
})
// 创建模板对象
const tpl = new hiprint.PrintTemplate({ template: {} })
// 设计模板
tpl.design('#hiprint-printTemplate', { grid: true })
// 浏览器打印
tpl.print({ name: '示例' }, {}, {
callback: () => {
this.waitShowPrinter = false
},
})
// 直接打印(需客户端已连接)
tpl.print2({ name: '示例' }, {
// 方式1 如果你发现传了 paperWidth/paperHeight 仍然偏移,再加上:forceClientPageSize: true 让客户端更强制按这个尺寸出纸
//paperWidth: 210,
//paperHeight: 279,
// 方式2
//forceClientPageSize: true, // 强制使用客户端页面大小,:偏“强制客户端按模板纸张尺寸打印,尽量压过驱动默认设置”(更激进)
printer: '', // 打印机名称
title: '打印预览pdf'
});
// 导出 PDF(内置示例参数)
//模式1: 小模版需要在一页中排列的话,增加增加页面宽高参数(想把多订单放在一页中排列)----小模板拼到大纸张(例如 A4)
tpl.toPdf(this.printDataVar, '打印预览pdf', {
paperWidth: 210,
paperHeight: 297,
perPage: 6, // 每页模板数
leftOffset: -1, // 对齐偏移
topOffset: -1, // 对齐偏移
scale: 1, // 清晰度/性能权衡(也可用 pixelRatio)
pdfCompress: true, // 是否压缩PDF 默认 true
imageType: 'JPEG', // 图片类型 默认 JPEG 支持 JPEG、PNG
imageQuality: 0.92, // 图片质量 0-1 默认 0.92
imageCompression: 'FAST', // 图片压缩算法 默认 FAST 支持 FAST、MEDIUM、SLOW
onProgress: (cur, total) => {
// 导出进度100%的时候关闭等待
if (cur === total) {
this.loading = false
}
console.log('toPdf 进度', Math.floor((cur/total)*100))
}
})
// 模式2:普通模板,导出预览全部页:
tpl.toPdf(this.printDataVar, '打印预览pdf', {
onProgress: (cur, total) => {
// 导出进度100%的时候关闭等待
if (cur === total) {
this.loading = false
}
}
});
// 使用当前保留的 toPdf 导出链路(基于 @zumer/snapdom)
tpl.toPdf(this.printDataVar, '打印预览pdf', {
onProgress: (cur, total) => {
// 导出进度100%的时候关闭等待
if (cur === total) {
this.loading = false
}
}
});
// 导出图片(内置示例参数)
// 导出为多张图片,每张合成 6 页,自动下载 JPEG
tpl.toImage(this.printDataVar, {
isDownload: true,
name: '图片名称',
limit: 0,
type: 'image/jpeg',
pixelRatio: 2,
quality: 0.8,
toType: 'url',
onProgress: (cur, total) => {
// 导出进度100%的时候关闭等待
if (cur === total) {
this.loading = false;
}
}
})
//按 A4 纸张排版导出(把小模板排到 A4):
tpl.toImage(this.printDataVar, {
paperWidth: 210,
paperHeight: 297,
limit: 6,
isDownload: true,
name: 'A4排版',
type: 'image/jpeg',
pixelRatio: 2,
onProgress: (cur, total) => {
console.log('toImage 进度', Math.floor((cur/total)*100))
// 导出进度100%的时候关闭等待
if (cur === total) {
this.loading = false
}
}
})
// 使用当前保留的 toImage 导出链路(基于 @zumer/snapdom)
tpl.toImage(this.printDataVar, {
paperWidth: 210,
paperHeight: 297,
limit: 6,
isDownload: true,
name: 'A4排版',
type: 'image/jpeg',
pixelRatio: 2,
onProgress: (cur, total) => {
console.log('toImage 进度', Math.floor((cur/total)*100))
// 导出进度100%的时候关闭等待
if (cur === total) {
this.loading = false
}
}
})水印与授权行为说明:设计态与运行态分离。设计态不自动显示默认水印(由面板设置项决定);运行态按授权和面板内容合并控制。
轻量运行时 API(无需设计器 UI)
当你只想“拿模板 + 数据”直接做预览、浏览器打印、导出 PDF/图片或进行客户端直连打印,而不引入页面设计器时,使用以下 API:
import {
createTemplate,
getHtml,
printBrowser,
exportPdf,
exportImage,
getPrinterList,
refreshPrinterList,
getAddress,
getClientInfo,
getClients,
ippPrint,
ippRequest,
setHiwebSocket,
connect,
disconnect,
isClientConnected,
clientGenerate
} from 'vg-print'
// 连接客户端(需要先启动客户端)
connect()
// 检查客户端是否已连接
console.log(isClientConnected())
// 1) 创建模板实例(可复用)
const tpl = createTemplate(tmplJson)
// 2) 生成预览 HTML,自行渲染到容器
const preview = async () => {
visible.value = true // 弹出框容器显示
await nextTick() // 等容器渲染出来
const tpl = createTemplate(tmplJson)
const html = getHtml(tpl, printData) // 始终为字符串
const container = document.getElementById('preview_content_custom') // 显示内容的div的id
if (!container) {
console.warn('预览容器不存在')
return
}
container.innerHTML = html
}
// 3) 浏览器打印(不需要客户端)
printBrowser(tpl, printData)
// 4) 导出 PDF
// 原生方法
exportPdf(tpl, printData, '打印预览pdf', {
paperWidth: 210, // 纸张宽度 默认 210mm
paperHeight: 297, // 纸张高度 默认 297mm
perPage: 6, // 每页打印数量 默认 6
leftOffset:-1, // 对齐偏移
topOffset:-1, // 对齐偏移
scale: 1, // 清晰度/性能权衡(也可用 pixelRatio) 1:100% 2:200% 3:300%
pdfCompress: true, // 是否压缩PDF 默认 true
imageType: 'JPEG', // 图片类型 默认 JPEG 支持 JPEG、PNG
imageQuality: 0.92, // 图片质量 0-1 默认 0.92
imageCompression: 'FAST', // 图片压缩算法 默认 FAST 支持 FAST、MEDIUM、SLOW
onProgress: (cur: number, total: number) => {
console.log('toPdf 进度', Math.floor((cur/total)*100))
}
})
// 原生方法
await exportImage(tpl, printData, {
isDownload: true,
name: '图片名称',
limit: 1,
type: 'image/jpeg',
pixelRatio: 2,
quality: 0.8,
toType: 'url',
useCORS: true, // 开启跨域支持
onProgress: (cur: number, total: number) => {
console.log('toImage 进度', Math.floor((cur/total)*100))
}
})
// 6) 页面层次的重新设置链接 -使用下面前提是主程序main.js中注入的scoket的时候需要先取消自动连接
// a) 先关掉自动连接开关(防止又被拉起)
/* import { disAutoConnect, setSocketIo } from 'vg-print'
import { io } from 'socket.io-client'
disAutoConnect() // 关键:先把 window.autoConnect 置 false
setSocketIo(io) // 再注入 io(这一步不会触发连接了)*/
// b) 然后页面重新设置链接-页面里需要连接/切换端口时,需要重新设置链接
setHiwebSocket('http://127.0.0.1:8091', 'token') // 这里只设置并不会自动连(因为你 main.js 已经 disAutoConnect 了)
connect()
// c)或者使用标准 API(设置即连接)-页面层次的重新设置链接-这种一般会自动链接页面初始化的时候
setHost('http://127.0.0.1:17521', 'your-token') // setHost 内部会 stop + start(若你已 disAutoConnect,可改为 setHiwebSocket + connect)
// 6.1) 获取打印机列表
// 方式 A: 异步获取 (推荐) - 会触发刷新并等待返回
const printers = await refreshPrinterList();
console.log('打印机列表 (Async):', printers);
// 方式 B: 回调获取
getPrinterList((list) => {
console.log('打印机列表 (Callback):', list)
})
// 方式 C: 同步获取 (需确保已连接且已缓存) 这种方式可用于在连接成功后,点击按钮获取打印机列表
const cachedList = getPrinterList()
// 6.2) 其他客户端信息获取
// 获取 MAC/IP
const address = await getAddress();
// 获取客户端信息
const clientInfo = await getClientInfo();
// 获取连接的客户端 socket 信息
const clients = await getClients();
// 6.3) IPP 打印与请求
// ippPrint({ ...options });
ippPrint(options, callback, connectedCallback);
// ippRequest({ ...options });
ippRequest(options, callback);
// 使用模板对象直接发起直连打印
tpl.print2(printData, {
// 方式1
//forceClientPageSize: true, // 强制使用客户端页面大小,:偏“强制客户端按模板纸张尺寸打印,尽量压过驱动默认设置”(更激进)
// 方式2 如果你发现传了 paperWidth/paperHeight 仍然偏移,再加上:forceClientPageSize: true 让客户端更强制按这个尺寸出纸
//paperWidth: 210,
//paperHeight: 279,
printer: printers?.[0]?.name || '',
title: '打印预览pdf'
})
// 7) 客户端生成(返回客户端保存路径,便于上传到服务器)
const { pdfPath, imgPath } = await clientGenerate(tpl, printData, {
pdfName: 'reportPdf', // 不带后缀,内部自动生成 .pdf
imgName: 'reportJpg', // 不带后缀,内部自动生成 .jpg
timeout: 60000
})
// 例如:上传到后端
// await api.upload({ pdfPath, imgPath })
// 7) 断开连接
disconnect()导出 PDF(toPdf / exportPdf)
exportPdf(tpl, data, filename, options)本质调用的是模板实例的tpl.toPdf(data, filename, options);两者参数一致。
模式 A:普通导出(按模板自身纸张与分页)
- 特点:不传纸张宽高,导出结果与预览分页一致(每个
.hiprint-printPaper一页)。 - 适用:报告类、A4/A5 正常分页模板。
// 不传 paperWidth/paperHeight,使用模板的面板尺寸与分页配置
exportPdf(tpl, printData, '打印预览pdf', {
onProgress: (cur, total) => console.log('toPdf 进度', Math.floor((cur / total) * 100))
})模式 B:排版导出(把小模板拼到大纸张,例如 A4)
- 特点:传入
paperWidth/paperHeight(mm)后,会进入“平铺排版导出”。 - 适用:小标签、小票、多订单合并到一张纸导出。
// 传入纸张尺寸与排版参数,将多个“标签模板”平铺到一张 A4
exportPdf(tpl, printData, '打印预览pdf', {
paperWidth: 210, // mm
paperHeight: 297, // mm
perPage: 6, // 每页放 6 个(不够的到下一页)
leftOffset: -1, // -1 表示水平居中;>=0 表示左边距 mm
topOffset: -1, // -1 表示垂直居中;>=0 表示上边距 mm
scale: 1, // 清晰度/性能权衡(也可用 pixelRatio)
pdfCompress: true, // 是否压缩PDF 默认 true
imageType: 'JPEG', // 图片类型 默认 JPEG 支持 JPEG、PNG
imageQuality: 0.92, // 图片质量 0-1 默认 0.92
imageCompression: 'FAST', // 图片压缩算法 默认 FAST 支持 FAST、MEDIUM、SLOW
onProgress: (cur, total) => console.log('toPdf 进度', Math.floor((cur / total) * 100))
})
onProgress: (cur, total) => console.log('toPdf 进度', Math.floor((cur / total) * 100))
})排版规则(重点:perPage=0/不传的行为)
- 传入了纸张宽高(
paperWidth/paperHeight或usePaperType: true)时:perPage > 0:强制“每页 N 个”,例如perPage: 6就会 6 个一页。perPage = 0或不传perPage:自动计算“一页能放几个放几个”(由纸张尺寸 + 标签尺寸 + 行列间距决定)。
- 没有传纸张宽高时:
- 默认导出与预览一致(通常“一个模板一页”)。
perPage在该模式下不生效(因为不做平铺排版)。
导出图片(toImage / exportImage)
exportImage(tpl, data, options)本质调用的是模板实例的tpl.toImage(data, options);两者参数一致。
模式 A:普通导出(按模板分页导出图片)
// 不传 paperWidth/paperHeight:按模板分页导出
// splitPages: true 表示“每页一张图片”(推荐:避免长图占用太大内存)
await exportImage(tpl, printData, {
isDownload: true,
name: '图片',
splitPages: true,
type: 'image/png', // 含二维码/条码建议 png;纯文字/照片可 jpeg
pixelRatio: 2,
quality: 0.8, // 仅 JPEG 有效(0-1)
toType: 'blob', // 推荐 blob(避免大 dataURL 阻塞)
onProgress: (cur, total) => console.log('toImage 进度', Math.floor((cur / total) * 100))
})合成长图(可选)
// limit: N 表示每 N 页合成一张“长图”;limit<=0 表示全部页合成一张(可能很大,不推荐)
await exportImage(tpl, printData, {
isDownload: true,
name: '长图',
limit: 6,
type: 'image/jpeg',
pixelRatio: 2,
quality: 0.85
})模式 B:排版导出(把小模板拼到大纸张,例如 A4)
// 传入纸张尺寸后,图片导出也会进入“平铺排版导出”
// 注意:在排版模式下 limit 的语义等同于 perPage(每张纸放几个标签)
await exportImage(tpl, printData, {
paperWidth: 210, // mm
paperHeight: 297, // mm
limit: 6, // 每张“纸”放 6 个(不够的到下一张)
isDownload: true,
name: 'A4排版',
splitPages: true, // 每张纸输出一张图片(文件名自动追加 -1/-2/...)
type: 'image/png',
pixelRatio: 2
})排版规则(重点:limit=0/不传的行为)
- 传入了纸张宽高(
paperWidth/paperHeight)时:limit > 0:强制“每张纸 N 个”(等同于 PDF 的perPage)。limit = 0或不传limit:自动计算“一张纸能放几个放几个”。
- 没有传纸张宽高时:
splitPages: true:每页一张图(推荐)。splitPages: false且limit > 0:每 N 页合成长图。splitPages: false且limit <= 0:所有页合成一张超长图(不推荐)。
参数说明(PDF/图片通用,含描述)
paperWidth、paperHeight:纸张尺寸(mm);传入后启用“排版导出”(小模板拼到大纸张)。usePaperType:PDF/图片可用;为true时按模板的paperType(如 A4)设置页面尺寸。scale/pixelRatio:渲染缩放;pixelRatio优先级高于scale。值越大越清晰,但越耗时/耗内存。perPage:PDF 排版模式每页模板数量;0/不传表示自动填充。limit:图片普通模式下用于“每 N 页合成长图”;图片排版模式下等同于“每张纸 N 个”;0/不传表示自动填充(排版模式)或全量合成(普通模式,谨慎)。splitPages:图片每页/每张纸输出一张(推荐)。type:图片格式;'image/jpeg'或'image/png'(二维码/条码建议 png)。quality:图片质量(0-1,仅 JPEG 有效)。toType:返回类型(不下载时);'url'或'blob'。isDownload:是否自动触发下载。name:文件名(图片会自动追加页码后缀)。leftOffset、topOffset:排版对齐偏移(mm);-1表示居中,>=0表示边距。onProgress(cur, total):导出进度回调;以cur/total计算百分比。forcePng(PDF):强制使用 PNG 写入 PDF(条码/二维码建议开启)。maxCanvasPixels:单页最大画布像素上限;导出卡顿/崩溃时可调小(例如2e7)。debugPerf:输出每页渲染耗时到控制台,便于定位慢点。
导入说明(含描述)
- 所有运行时 API 由库入口直接导出;无需另装
vue-plugin-hiprint - 如需自定义元素提供器,在调用前执行
hiprint.init({ providers: [...] });默认已初始化内置提供器
适用场景(含描述)
- 后台页面、弹窗、任务流:仅需“模板 + 数据”的预览/打印/导出能力
- 脚本或批量任务:结合
exportPdf/exportImage实现批量导出
注意事项
- 建议在
index.html注入print-lock.css,保证打印样式稳定 - 直接打印需配套客户端(Electron 或服务端),跨域部署需启用 HTTPS
- 若使用自定义
host/token,确保客户端配置一致且网络可达 - SSR 兼容:插件安装仅在浏览器环境执行(
typeof window !== 'undefined'),在 SSR 框架中引入不会因window未定义报错。
完整示例
<template>
<FullDesigner
:initial-template="tpl"
:initial-print-data="rows"
default-lang="cn"
:hi-host="host"
:hi-token="token"
:hi-auto-connect="true"
@save="onSave"
/>
<div style="margin-top: 12px;">
<el-input v-model="host" placeholder="客户端地址,如 http://127.0.0.1:17521" style="width: 360px; margin-right: 8px;" />
<el-input v-model="token" placeholder="鉴权令牌" style="width: 200px; margin-right: 8px;" />
<el-button type="primary" @click="applyHostToken">应用连接参数</el-button>
<el-button style="margin-left:8px;" @click="preview">预览</el-button>
<el-button style="margin-left:8px;" @click="printBrowser">浏览器打印</el-button>
</div>
</template>
<script setup>
import { ref } from 'vue'
// 模板(示例)
const tpl = {
panels: [
{
index: 0,
paperType: 'A4',
width: 210,
height: 297,
printElements: [
{
options: { left: 20, top: 20, title: '标题', field: 'title', fontSize: 18 },
printElementType: { type: 'text' }
},
{
options: { left: 20, top: 50, title: '姓名', field: 'name' },
printElementType: { type: 'text' }
}
]
}
]
}
// 数据(对象或数组均可)
const rows = [{ title: '病理图文报告', name: '东东' }]
// 连接参数
const host = ref('http://127.0.0.1:17521')
const token = ref('')
// 组件引用
const designer = ref(null)
const applyHostToken = () => {
// 设置客户端地址与令牌,并尝试重连
designer.value?.setHiwebSocket(host.value, token.value)
}
// 预览与浏览器打印
const preview = () => designer.value?.preView()
const printBrowser = () => designer.value?.printView()
// 保存事件:拿到模板与数据入库
const onSave = ({ template, data, templateId }) => {
// 持久化示例
// await api.save({ template, data, templateId })
console.log('save payload:', { template, data, templateId })
}
</script>