vg-print-vue2

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
10,430
Install
npm install vg-print-vue2
Latest Version:1.0.519
Vue:2
License:MIT
Last Updated:Oct 18, 2026
Links: npm
Maintainer: gao110

vg-print-vue2

[开源免费]一个开箱即用的打印设计器组件库(Vue 2)。现在聚焦于单一组件 FullDesigner,同时暴露底层 hiprint 能力与客户端直连(hiwebSocket)配置,便于快速集成模板设计、预览、浏览器打印、导出 PDF/图片、直接打印、客户端生成pdf/图片、数据源管理、多语言支持等功能。

  • 您可以直接安装引入体验功能.功能在不断完善中,请及时更新使用,欢迎反馈与建议,共同成长
  • 没有域名限制,无网可用. 随时提供帮助和解决问题.
  • npm 搜索 vg-print-vue2。
  • 联系我加 QQ: 984239686 或使用首页有微信加入群聊解决问题.

Vue 3 版本: 如果你使用的是 Vue3,请查看 vg-print

vg-print开发者文档

授权密钥(authKey)与默认水印

  • 行为说明:
    • 设计态(FullDesigner 设计界面):不自动注入默认水印;是否显示水印由面板中的“水印功能”设置项决定,与 authKey 无关。
    • 运行态(预览、浏览器打印、导出 PDF/图片、直连打印):
      • 无授权(未注册 authKey):
        • 面板未填写内容 → 显示默认水印
        • 面板填写了内容 → 显示面板内容 + "试用版" 后缀
      • 有授权(已注册有效 authKey):
        • 面板未填写内容 → 不显示水印(默认水印被移除)
        • 面板填写了内容 → 显示面板内容(无后缀)
  • 注册授权密钥(密钥添加除水印): 在项目入口(如 main.js 或 App.vue)尽早注册:
    import { hiprint } from 'vg-print-vue2';
    
    // 填入生成的 Key
    hiprint.register({ authKey: 'eyJrIjoiZ21jNTc2MDMzNyJ9' });
    
    注册后,以下所有使用方式均会自动生效(移除默认水印):
    • 完整设计器组件 FullDesigner
    • 核心类 new hiprint.PrintTemplate(...)
    • 轻量运行时 helper createTemplate(...)
  • 示例:轻量运行时使用授权
import { hiprint, createTemplate, printBrowser } from 'vg-print-vue2'

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-vue2'

// 两种形式的插件均支持
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-vue2

可选依赖:直连打印/客户端连接(socket.io-client)

  • 本库默认不内置 socket.io-client,以减少默认安装体积。
  • 仅当你需要“直连打印/客户端连接(hiwebSocket)”能力(如 print() / print2() / 自动连接)时,才需要安装并注入:
npm i socket.io-client

在项目入口(如 main.js)注入:

import { io } from 'socket.io-client'
import { setSocketIo } from 'vg-print-vue2'

setSocketIo(io)

也可直接使用 window.io = io(等价)。

可选依赖:请求型数据源(axios)

  • 本库默认不内置 axios,以减少默认安装体积。
  • 仅当你需要通过数据源配置发起接口请求、测试链接或执行数据处理时,才需要安装并注入:
npm i axios

在项目入口(如 main.js)注入:

import axios from 'axios'
import { setHttpClient } from 'vg-print-vue2'

setHttpClient(axios)

如果只使用 data-sources 外部传入数据,不需要安装 axios;未传外部数据源且未注入 axios 时,请求型“数据源”入口会自动提示依赖缺失,不会影响设计器其他功能。

可选依赖:ECharts 图表

  • 本库默认不内置 ECharts,以减少默认安装体积。
  • 仅当你需要折线图、柱状图、饼图、漏斗图、仪表盘、雷达图或散点图时,才需要安装并注入:
npm i echarts

在项目入口(如 main.js)注入:

import * as echarts from 'echarts'
import { setEcharts } from 'vg-print-vue2'

setEcharts(echarts)

未安装或未注入 ECharts 时,图表元素仍可拖入设计器,但会显示依赖提示,不影响其他元素使用。

可选插件:条码/二维码(@vg-print/plugin-bwip-js)

  • 本库默认不内置 bwip-js,以减少默认安装体积。
  • 仅当你需要“条形码/二维码元素(barcode/qrcode)”能力时,才需要安装并注册插件:
npm i @vg-print/plugin-bwip-js

在项目入口(如 main.js)注册插件(与 authKey 一起或单独均可):

import { hiprint } from 'vg-print-vue2'
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 左侧标题文本
  • waitShowPrinter: boolean 显示“浏览器打印”按钮的加载状态
  • languages: Array<{ label: string; value: string }> 语言切换下拉选项

事件(Emits)

  • preview 打开预览
  • print-view 浏览器打印
  • to-pdf 导出 PDF
  • to-image 导出图片
  • clear-paper 清空(带二次确认)
  • save 保存(拆分按钮的主键)
  • edit-template 打开“编辑模板数据”对话框
  • edit-data 打开“编辑打印数据”对话框
  • lang-change 语言切换(值为语言码:cn、en、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="$refs.designer && $refs.designer.preView()">预览</el-button>
      <el-button size="small" @click="$refs.designer && $refs.designer.printView()">浏览器打印</el-button>
      <el-button type="primary" size="small" @click="$refs.designer && $refs.designer.toPdf()">导出 PDF</el-button>
      <el-button size="small" @click="$refs.designer && $refs.designer.toImage()">导出图片</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>
export default {
  data() {
    return {
      host: 'http://127.0.0.1:17521',
      token: '',
      tpl: { panels: [ /* ... */ ] },
      rows: [{ title: '病理图文报告', name: '东东' }]
    }
  },
  methods: {
    onSave({ template, data }) { /* 保存到后端 */ },
    onClear() { /* 清空数据/元素 */ },
    onSaveDirect() { this.$refs.designer && this.$refs.designer.save() }
  }
}
</script>

使用示例:单独使用 Header

<template>
  <Header
    :waitShowPrinter="loading"
    :languages="langs"
    title="打印设计器"
    @preview="onPreview"
    @print-view="onPrintView"
    @to-pdf="onToPdf"
    @to-image="onToImage"
    @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 是否显示标题,默认 true
  • showPdf: boolean 是否显示“导出 PDF”按钮,默认 true
  • showImg: boolean 是否显示“导出图片”按钮,默认 true
  • showPrint2: boolean 是否显示“直接打印”按钮,默认 true
  • pdfOptions: object 导出 PDF 选项(参考 toPdf)
  • imageOptions: object 导出图片 选项(参考 toImage)
  • directPrintOptions: object 直接打印 选项(参考 print)
  • browserPrintOptions: object 浏览器打印 选项(参考 printView)
  • showPrinterSelect: boolean 是否显示“打印机选择”下拉区域,默认 true
  • modalShow: boolean 弹窗显隐(支持 :modalShow.sync)
  • width: string | number 弹窗宽度(默认 '80%')
  • defaultLang: string 组件内 i18n 语言(Standalone 时使用);支持 cn、en、cn_tw;默认 cn

预览头部标题使用

  • 传纯文本(原有方式):
  • dialogTitle: '预览单据'
  • 传带标签 HTML:
  • dialogTitleHtml: '订单预览'
  • 用插槽完全自定义(推荐,样式控制最灵活):
  • <template #title="{ title, html }">...

事件(Emits)

  • update:modalShow 双向绑定弹窗显隐
  • update:selectedPrinter 选中打印机变更
  • close 关闭弹窗

暴露方法(通过 ref 调用)

  • 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

使用示例(单独使用)

<template>
  <el-button @click="openPreview">显示预览</el-button>
  <Preview
    ref="previewRef"
    :show-title="false"
    dialog-title="自定义预览标题"
    :modalShow.sync="visible"
    default-lang="cn"
    :printerList="printers"
    :selectedPrinter.sync="printer"
  />
</template>

<script>
import { Preview, createTemplate } from 'vg-print-vue2'
import 'vg-print-vue2/style.css'

export default {
  components: { Preview },
  data() {
    return {
      visible: false,
      printers: [{ name: 'HP_001', label: 'HP 打印机' }],
      printer: '',
      tmplJson: { panels: [ /* ... */ ] },
      dataObj: { title: '病理图文报告', name: '东东' }
    }
  },
  methods: {
    openPreview() {
      const tpl = createTemplate(this.tmplJson)
      this.$refs.previewRef && this.$refs.previewRef.show(tpl, this.dataObj, {
        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: this.printer,
          title: '测试打印',
          copies: 2
        },
        browserPrintOptions: {
          applyPanelLayoutHtml: true
        },
        onClick: (type) => {
          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) => {
            if (status.type === 'pdf:progress' || status.type === 'image:progress') {
              const cur = (status && status.payload && status.payload.cur) || 0
              const total = (status && status.payload && 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" :modalShow.sync="visible" />
  <el-button @click="$refs.designer && $refs.designer.preView()">直接使用 FullDesigner 的预览</el-button>
  <el-button @click="showCustomPreview">用 Preview 展示当前模板</el-button>
</template>

<script>
export default {
  data() {
    return { visible: false }
  },
  methods: {
    showCustomPreview() {
      const designer = this.$refs.designer
      const preview = this.$refs.previewRef
      if (!designer || !preview) return
      const tpl = designer.getTemplate && designer.getTemplate()
      const data = designer.getPrintData && designer.getPrintData()
      preview.show(tpl, data, '80%')
    }
  }
}
</script>

注意

  • 使用组件库时请引入 vg-print-vue2/style.css,其中包含自定义图标字体与预览/设计样式。
  • Preview 内部会根据 printTemplate 与 printData 自动渲染内容;也支持通过 show(...) 主动传入。
  • show(...) 兼容原签名 show(template, data, width?),建议新项目统一使用 options 写法,便于扩展和维护。
  • 若在外部项目未安装插件(未执行 Vue.use(vgPrint))而单独使用 Preview,请通过 default-lang 显式设置语言;安装插件时无需设置,语言默认随全局 i18n。

样式引入(确保设计与打印样式生效):

// 全局样式(组件库样式)
import 'vg-print-vue2/style.css'
<!-- 打印锁样式(推荐;保证打印时样式稳定) -->
<link rel="stylesheet" type="text/css" media="print" href="/css/print-lock.css" />

环境要求:Vue 2.7、Node >= 16.14。无需单独安装 vue-plugin-hiprint,本库已内置并导出 hiprint 能力。

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 初始化打印数据;支持对象或数组,运行时变更会即时生效
  • data-sources: Array | object 外部传入的数据源字段元数据;支持直接传入字段列表、表结构字段列表或带 dataSets/fields 的完整结构,用于设计器字段选择器;不传时继续使用数据源配置中的请求方式
  • default-lang: string 默认语言;支持 cn、en、cn_tw;默认 cn
  • config: 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 是否显示网格线,默认 true
    • activePanel: boolean 是否默认显示右侧属性面板,默认 true
    • adaptToSize: boolean 是否初始化时自动缩放以适配设计区可视范围,默认 false
  • theme: string | object 主题;支持内置主题名或传入自定义主题对象
  • theme-list: Array<string | object> 主题列表(用于顶部主题切换菜单),默认:light/dark/emerald/corporate/bumblebee/retro/cyberpunk/valentine
  • show-option: object 区域显示控制(默认全部显示):
    • showHeader: boolean 是否显示顶部 Header,默认 true
    • showToolbar: boolean 是否显示二级工具栏 Toolbar,默认 true
    • showFooter: 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: string Header/面板标题栏背景色(属性/结构/历史面板的标题栏也会使用)
  • headerText: string Header/面板标题栏文字颜色
  • toolbarBg: string 二级工具栏背景色
  • panelBg: string 左侧模板面板背景色(不传则默认跟随 toolbarBg)
  • surfaceBg: string 面板/弹窗主体背景色(属性/结构/历史面板、右键菜单等)
  • text: string 主文字颜色
  • mutedText: string 次级文字颜色(列表辅助信息、提示文字等)
  • border: string 边框/分割线颜色
  • menuBg: string 右键菜单背景色(可选,默认跟随 surfaceBg)
  • menuHoverBg: string 菜单 hover 背景色(可选)
  • footerBg: string Footer 背景色(可选,默认跟随 surfaceBg)
  • footerText: string Footer 文字颜色(可选,默认跟随 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() 打开预览弹窗;将当前模板与数据渲染为预览 HTML
  • printView() 浏览器打印;不依赖客户端,调起系统打印对话框
  • 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() 关闭自动连接策略;阻止自动重连

示例:

<template>
  <FullDesigner
    :initial-template="tpl"
    :initial-print-data="rows"
    default-lang="cn"
    @onDesigned="onDesigned"
    @save="onSave"
  />
</template>

<script>
export default {
  methods: {
    /*  保存方法
      template,   // 模板 JSON
      data,       // 当前打印数据(对象或数组)
      templateId  // 模板标识(若存在)
    */
    onSave({ template, data, templateId }) {
      // 调用接口持久化到数据库
      // await api.saveTemplate({ template, data, templateId })
    },
    /*  设计器渲染完成后执行自定义逻辑
      designer,    // hiprint.PrintTemplate 实例
      template,    // 当前模板 JSON
      source       // initial / incoming / library / json
    */
    onDesigned({ designer, template, source }) {
      // 设计器已完成首次页面渲染,可在这里执行后续操作
    }
  }
}
</script>

语言与国际化

  • 通过 default-lang 设置初始语言(cn 默认为中文);内部会同步 vue-i18n 与 hiprint 的语言。
  • 运行时可在页面右上角语言切换菜单切换(无需刷新)。

数据源使用说明

FullDesigner 内置了数据源管理与字段选择能力,可将接口返回字段集中整理,并在设计器字段属性中快速选择。

外部传入数据源字段元数据(无需请求接口)

如果业务系统已经取得表结构信息,或已经拿到一份运行时业务数据,不希望由 vg-print-vue2 再次请求接口,可以通过 data-sources 直接传入字段名/字段描述元数据或 data 数据。组件会根据这些内容生成字段树,供设计器属性面板中的字段选择器使用;这种方式不依赖 axios,也不会把外部数据写入本地数据源配置。

<template>
  <FullDesigner
    :data-sources="designerDataSources"
  />
</template>

<script>
export default {
  data() {
    return {
      // data-sources 用于设计态字段选择器,只传字段元数据
      designerDataSources: [
        {
          id: 'patient-info',
          name: '患者信息',
          groupName: '业务数据',
          desc: '患者基本信息',
          fields: [
            { text: '主键', field: 'id' },
            { text: '病人姓名', field: 'patientName' },
            { text: '病人年龄', field: 'patientAge' },
            { text: '科室名称', field: 'department.name' }
          ]
        },
        {
          id: 'fee-details',
          name: '费用明细',
          groupName: '业务数据',
          desc: '患者费用明细',
          fields: [
            { text: '收费项目', field: 'itemName' },
            { text: '金额', field: 'amount' }
          ]
        }
      ]
    }
  }
}
</script>

字段选择器中会按“业务数据 → 患者基本信息/患者费用明细 → 字段”展示。外层分类使用 groupName,默认数据集名称优先使用 desc;字段元数据变化后,字段树会随组件属性更新。

如果需要自定义字段显示名称或多个数据集,可以直接传入完整数据集结构:

const designerDataSources = [
  {
    id: 'patient-info',
    name: '患者信息',
    groupName: '业务数据',
    desc: '患者基本信息',
    dataSets: [
      {
        id: 'patient',
        name: '患者资料',
        fields: [
          { text: '病人姓名', field: 'patientName' },
          { text: '科室名称', field: 'department.name' }
        ]
      }
    ]
  }
]

如果后端返回的是表结构记录,转换为可绑定字段:

const designerDataSources = [
  {
    id: 'patient-info',
    name: '患者信息',
    groupName: '业务数据',
    desc: '患者信息表',
    data: [
      { column_name: 'id', column_comment: '主键' },
      { column_name: 'patientName', column_comment: '病人姓名' }
    ]
  }
]

入口与能力

  • 入口:二级工具栏点击“数据源”打开管理弹窗
  • 能力:数据源配置、分类管理、测试获取、数据处理脚本、错误处理脚本、字段树选择

使用流程(推荐)

  1. 新增数据源并填写基础信息:
    • 唯一名称
    • 请求地址(URL)
    • 请求方法(GET/POST/PUT/DELETE)
  2. 按需配置请求头、参数、发送数据:
    • 类型支持:string、number、boolean、expression
  3. 编写“数据处理”脚本(processCode)并点击“测试链接”:
    • 左侧显示原始返回(rawResult)
    • 右侧显示处理结果(processed)
  4. 为数据源填写“分类名称”(不填写时使用唯一名称),便于在字段选择器中归类查找。
  5. 在设计器组件的“字段名”输入框后点击选择按钮,按“分类 → 数据集 → 字段”的树结构选取字段,选中后会自动回填。

processCode / errorProcessCode 约定

  • processCode 函数形态:
// (result, isSandbox, DSV, VFR) => { ...; return processed; }
return result
  • errorProcessCode 函数形态:
// (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
}))

高级用法(hiprint)

本库导出 hiprint,可直接创建与操作模板对象(hiprint.PrintTemplate):

若需要使用“直连打印/客户端连接(hiwebSocket)”相关能力,请先按上文注入 io;否则会提示缺失并导致连接失败。

import { hiprint, defaultElementTypeProvider } from 'vg-print-vue2'
// 全局配置
hiprint.setConfig({ showAdsorbLine: true, showPosition: true, showSizeBox: true })
// 注册插件
hiprint.register({ authKey: '', plugins: [] })
// 初始化元素提供器 (默认元素提供器)
hiprint.init({ 
  // providers: [new defaultElementTypeProvider()],
  host: 'http://127.0.0.1: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-vue2'

// 连接客户端(需要先启动客户端)
connect()

// 检查客户端是否已连接
console.log(isClientConnected())


// 1) 创建模板实例(可复用)
const tpl = createTemplate(tmplJson)

// 2) 生成预览 HTML,自行渲染到容器
const preview = async () => {
  // 先让承载预览内容的 DOM 容器显示出来(例如打开弹窗)
  // 再确保容器已渲染完成(Vue2 可用 this.$nextTick / Vue.nextTick;非 Vue 项目可跳过)

  const tpl = createTemplate(tmplJson)
  const html = getHtml(tpl, printData) // 建议始终 await(兼容 beforeGetHtml 返回 Promise)

  const container = document.getElementById('preview_content_custom') // 显示内容的div的id
  if (!container) {
    console.warn('预览容器不存在')
    return
  }
  container.innerHTML = html
}

#### beforeGetHtml(获取 HTML 前处理)

用于在生成 HTML 后、返回/打印/直连发送前,对 HTML 字符串做二次处理;支持返回 Promise。

回调签名:


beforeGetHtml: ({ template, html }) => html

- `template`:当前 `hiprint.PrintTemplate` 实例
- `html`:生成的 HTML 字符串(可返回新字符串替换;返回 `undefined/null` 则保持不变)

示例:
const tpl = createTemplate(tmplJson)

const html = await getHtml(tpl, printData, {
  beforeGetHtml: async ({ template, html }) => {
    return html
  }
})

await tpl.getHtml(printData, {
  beforeGetHtml: ({ template, html }) => 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-vue2'
    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))
})
排版规则(重点: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:输出每页渲染耗时到控制台,便于定位慢点。

License

LGPL

开源使用须知

  1. 请自觉遵守 LGPL 协议,其他用途可联系作者;

  2. 允许用于个人学习、毕业设计、教学案例、公益事业、商业使用;

  3. 如果商用必须保留版权信息,请自觉遵守;

  4. 禁止将本开源的代码和资源进行任何形式任何名义的出售,否则产生的一切任何后果责任由侵权者自负;

  5. 商用请仔细审查代码和漏洞,不得用于任一国家许可范围之外的商业应用,产生的一切任何后果责任自负;

Related Packages

vg-print

vg-print supports visual drag and drop design templates, with functions such as...

36,183
npool-cli-v4

Npool Client SDK

8,226 0
bridgecore

供Weex开发者调用的core接口

1,275
tribiani-vue-tools

数据结构 OrgTree 说明

778

Version History

Version Released License
1.0.519 MIT
1.0.518 MIT
1.0.517 MIT
1.0.516 MIT
1.0.515 MIT