npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

vg-print开发者文档

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

  • 行为说明:
    • 设计态(FullDesigner 设计界面):不自动注入默认水印;是否显示水印由面板中的“水印功能”设置项决定,与 authKey 无关。
    • 运行态(预览、浏览器打印、导出 PDF/图片、直连打印):
      • 无授权(未注册 authKey):
        • 面板未填写内容 → 显示默认水印
        • 面板填写了内容 → 显示面板内容 + "试用版" 后缀
      • 有授权(已注册有效 authKey):
        • 面板未填写内容 → 不显示水印(默认水印被移除)
        • 面板填写了内容 → 显示面板内容(无后缀)
  • 注册授权密钥(密钥添加除水印): 在项目入口(如 main.jsApp.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/图片、直接打印(需客户端)
  • 通过属性配置 hiwebSockethosttoken 与自动连接
  • 暴露实例方法:预览、打印、导出、客户端生成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 顶部工具栏组件

  • 用于页面一级头部区域,内置常用操作按钮与打印机设置;支持通过 propsslots 定制。
  • 默认嵌入在 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 导出 PDF
  • to-image 导出图片
  • print 直接打印(需客户端)
  • clear-paper 清空(带二次确认)
  • save 保存(拆分按钮的主键)
  • edit-template 打开“编辑模板数据”对话框
  • edit-data 打开“编辑打印数据”对话框
  • lang-change 语言切换(值为语言码:cnendeesfritjarucn_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.PrintTemplatecreateTemplate 返回值)
  • 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 弹窗显隐(支持 v-model:modalShow
  • width: string | number 弹窗宽度(默认 '80%'
  • defaultLang: string 组件内 i18n 语言(Standalone 时使用);支持 cnendeesfritjarucn_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 内部会根据 printTemplateprintData 自动渲染内容;也支持通过 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 默认语言;支持 cnendeesfritjarucn_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() 关闭自动连接策略;阻止自动重连

事件(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-i18nhiprint 的语言。
  • 运行时可在页面右上角语言切换菜单切换(无需刷新)。

数据源使用说明

FullDesigner 内置了数据源管理与字段绑定能力,可用于将接口字段自动映射到设计器组件字段下拉中。

入口与能力

  • 入口:二级工具栏点击“数据源”打开管理弹窗
  • 能力:数据源配置、测试获取、数据处理脚本、错误处理脚本、字段来源规则(全局/按组件类型)

使用流程(推荐)

  1. 新增数据源并填写基础信息:
    • 唯一名称
    • 请求地址(URL)
    • 请求方法(GET/POST/PUT/DELETE)
  2. 按需配置请求头、参数、发送数据:
    • 类型支持:stringnumberbooleanexpression
  3. 编写“数据处理”脚本(processCode)并点击“测试链接”:
    • 左侧显示原始返回(rawResult
    • 右侧显示处理结果(processed
  4. 配置“字段来源规则”并保存:
    • 看板全局:manualglobal
    • 组件规则:manual / global / custom
  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.nameorder.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/paperHeightusePaperType: 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: falselimit > 0:每 N 页合成长图。
    • splitPages: falselimit <= 0:所有页合成一张超长图(不推荐)。

参数说明(PDF/图片通用,含描述)

  • paperWidthpaperHeight:纸张尺寸(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:文件名(图片会自动追加页码后缀)。
  • leftOffsettopOffset:排版对齐偏移(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>