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

hprint-designer

v0.5.0

Published

Vue 2 print-template designer wrapping vue-plugin-hiprint — scenic tickets & invitations

Readme

hprint-designer

基于 vue-plugin-hiprint 封装的 Vue 2 打印模板设计器 + 打印运行时,专注于纸质景区票、邀请函等票据/卡片类模板。

vue-plugin-hiprint 依赖 hiprint

两个入口

| 入口 | 用途 | 依赖 | |------|------|------| | hprint-designer | 设计器 Vue 组件 — 设计模板、保存 JSON | Vue 2 | | hprint-designer/runtime | 打印运行时 — 静默打印、批量打印、预览 | 无 Vue 依赖 |

设计器只负责模板编辑,打印/预览/回执等全部通过 runtime 函数完成。两者通过模板 JSON 解耦:设计器产出 JSON,runtime 消费 JSON。

特性

  • 🎨 开箱即用<print-designer> 组件即完整设计器界面
  • 🚀 Runtime 独立使用hprint-designer/runtime 无需加载设计器即可打印/预览
  • 🧾 逐票回执batchPrintSilent + onTicket 回调,chunk 自选,支持落库与补打
  • 🧩 字段 Schema:模板字段以 Schema 声明,方便对接业务系统
  • 🔤 自定义字体:字体上传后自动注入 @font-face
  • 🔌 后端适配器RestAdapter / MockAdapter,也可自定义 BackendAdapter
  • 🎯 Vue 2 兼容:peer dependency vue@^2.6.0

安装

npm install hprint-designer

Peer dependencies:

npm install vue@^2.6.0 ant-design-vue@^1.7.2

设计器内部使用 Bootstrap 3 的 glyphicons。请在 index.html 中引入:

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" />

设计器

注册组件

// main.js
import Vue from 'vue'
import { HprintPlugin } from 'hprint-designer'
import 'hprint-designer/dist/style.css'

Vue.use(HprintPlugin)

new Vue({ render: h => h(App) }).$mount('#app')

使用设计器

<template>
  <div style="height: 100vh;">
    <print-designer
      ref="designer"
      :template-id="templateId"
      :adapter="adapter"
      @save="onSave"
    />
  </div>
</template>

<script>
import { RestAdapter, extractFields } from 'hprint-designer'

export default {
  data() {
    return {
      templateId: '',
      adapter: new RestAdapter({ baseURL: 'https://your-server/api' })
    }
  },
  methods: {
    onSave(template) {
      const fields = extractFields(template)
      console.log('模板已保存,字段:', fields)
    }
  }
}
</script>

Props

| 属性 | 类型 | 默认值 | 说明 | |------|------|--------|------| | templateId | string | '' | 编辑已有模板时传入 ID;空串新建 | | adapter | BackendAdapter | null | 后端适配器 | | readonly | boolean | false | 只读模式 | | lang | string | 'zh' | 语言 |

Events

| 事件 | 参数 | 说明 | |------|------|------| | save | PrintTemplate | 模板保存完成 | | data-change | { type, json } | 模板数据变化 |

Methods

| 方法 | 签名 | 说明 | |------|------|------| | getTemplateJson | () => PrintTemplate | 获取当前模板 JSON | | loadTemplate | (json: PrintTemplate) => void | 加载模板 JSON 到设计器 |

Runtime

hprint-designer/runtime 导入,无需加载设计器组件即可使用打印、预览等功能。

函数

| 函数 | 说明 | 返回值 | |------|------|--------| | previewFromTemplate(options) | 从模板生成预览 HTML | string | | silentPrint(options) | 单次静默打印 | Promise<{ success, templateId }> | | batchPrintSilent(options) | 批量静默打印 + 逐票回执 | Promise<BatchPrintCompleteSummary> | | retryFailed(options) | 重打失败票 | Promise<BatchPrintCompleteSummary> | | browserPrint(options) | 浏览器打印(弹出对话框) | void | | extractFields(template) | 提取模板字段列表 | Array<{ key, label, type }> |

辅助:createPrintConnection({ host, token? })waitForPrint2(tplId, timeoutMs?),以及所有批量打印类型。

完整示例

import {
  batchPrintSilent,
  retryFailed,
  browserPrint,
  extractFields,
  createPrintConnection
} from 'hprint-designer/runtime'

// 1. 创建连接
const connect = createPrintConnection({
  host: 'http://localhost:17521',
  token: 'hprint-designer'
})

// 2. 从后端获取模板
const template = await api.getTemplate('ticket-001')

// 3. 提取字段(可选)
const fields = extractFields(template)

// 4. 批量静默打印
const result = await batchPrintSilent({
  template,
  dataList: orders,
  pageSize: { widthMm: 80, heightMm: 120 },
  connect,
  chunkSize: 10,
  ticketKeyField: 'orderNo',
  onTicket: (r) => api.post('/print-receipts', r)
})

// 5. 重打失败票
if (result.failedTicketKeys.length > 0) {
  await retryFailed({
    template,
    failedReceipts: result.receipts.filter(r => r.status === 'failed' || r.status === 'timeout'),
    pageSize: { widthMm: 80, heightMm: 120 },
    connect
  })
}

// 6. 浏览器打印(无需客户端)
browserPrint({ template, dataList: orders, pageSize: { widthMm: 80, heightMm: 120 } })

函数签名

silentPrint(options)

| 选项 | 类型 | 说明 | |------|------|------| | template | PrintTemplate \| object | 模板 JSON | | data | Record<string, any> | 打印数据 | | connect | { host: string, token?: string } | 客户端连接配置 | | printer | string? | 打印机名称,空=默认 | | pageSize | { widthMm, heightMm } | 纸张尺寸(必传) | | fonts | PrintFont[]? | 自定义字体 | | hiprint | any? | hiprint 实例 | | connection | PrintConnection? | 复用已有连接 |

batchPrintSilent(options)

| 选项 | 类型 | 说明 | |------|------|------| | template | PrintTemplate \| object | 模板 JSON | | dataList | Record<string, any>[] | 打印数据数组 | | pageSize | { widthMm, heightMm } | 纸张尺寸(必传) | | connect | { host: string, token?: string } | 客户端连接配置 | | printer | string? | 打印机名称 | | chunkSize | number? | 每作业票数,默认 20 | | ticketKeyField | string? | 业务主键字段,默认 orderNo | | stopOnError | boolean? | 失败后是否中止 | | includeTicketData | boolean? | 回执是否携带完整数据 | | onTicket | (receipt) => void \| Promise<void> | 逐票回调 | | onProgress | (report) => void | 进度回调 | | fonts | PrintFont[]? | 自定义字体 | | hiprint | any? | hiprint 实例 | | connection | PrintConnection? | 复用已有连接 |

retryFailed(options)

| 选项 | 类型 | 说明 | |------|------|------| | template | PrintTemplate \| object | 模板 JSON | | failedReceipts | TicketPrintReceipt[] | 失败回执列表(需含 ticketData) | | pageSize | { widthMm, heightMm } | 纸张尺寸(必传) | | connect | { host: string, token?: string } | 客户端连接配置 | | printer | string? | 打印机名称 | | onTicket | (receipt) => void \| Promise<void>? | 逐票回调 |

browserPrint(options)

| 选项 | 类型 | 说明 | |------|------|------| | template | PrintTemplate \| object | 模板 JSON | | dataList | Record<string, any>[] | 打印数据数组 | | pageSize | { widthMm, heightMm } | 纸张尺寸(必传) | | fonts | PrintFont[]? | 自定义字体 | | hiprint | any? | hiprint 实例 |

previewFromTemplate(options)

| 选项 | 类型 | 说明 | |------|------|------| | template | PrintTemplate \| object | 模板 JSON | | data | Record<string, any>? | 打印数据 | | pageSize | { widthMm, heightMm } | 纸张尺寸(必传) | | fonts | PrintFont[]? | 自定义字体 | | hiprint | any? | hiprint 实例 |

前提:页面已引入 hiprint.bundle.js<script src="/vendor/hiprint/hiprint.bundle.js">),或通过 hiprint 参数显式传入。

逐票回执与 chunk

业务系统通过 onTicket 回调实时落库,无需 CSV 导出

| chunk | 200 票作业数 | 精度 | 场景 | |-------|------------|------|------| | 1 | 200 | 每张独立 ACK | 热敏机、强对账 | | 10 | 20 | 10 张同批联动 | 平衡 | | 20 | 10 | 较粗 | 办公机 / PDF 虚拟 |

优先级:batchPrintSilent({ chunkSize }) 参数 > 默认值 20

const result = await batchPrintSilent({
  template,
  dataList: orders,
  pageSize: { widthMm: 80, heightMm: 120 },
  connect,
  chunkSize: 10,
  ticketKeyField: 'orderNo',
  onTicket: (r) => api.post('/print-receipts', r)
})

完整调用实例见 docs/examples/batch-print-demo.ts
设计说明见 docs/hiprint/13-批量打印逐票回执设计.md
第三方接入与库表设计见 docs/hiprint/14-第三方接入与数据库设计.md

前置条件

electron-hiprint 客户端

静默打印需要 electron-hiprint 客户端。本仓库在 electron-hiprint/ 提供了含热敏机大批量优化补丁的客户端源码,必须使用此修改版(官方 releases 缺少 waitPrinterIdle、HTML 按页拆分、clearPrintDomAfterJob 等优化,批量打印逐票回执等功能将无法正常工作)。

本地调试与打包(内置客户端):

npm run client:install
npm run client:start

# 打包 Windows x64 安装包(输出到 electron-hiprint/out/)
npm run client:build

客户端设置 → 打印优化 页签可配置「等待打印机空闲」「HTML 拆页上限」等;热敏机可点「应用一票一作业预设」。

print-lock.css

index.html 中引入 print-lock.css必须,否则静默打印输出空白):

<link rel="stylesheet" type="text/css" media="print" href="/print-lock.css" />

使用 Vite 时推荐 ?url 导入自动生成正确的 href。本库 HprintPlugin.install() 会自动调用 injectPrintLockCss(),通常无需手动添加。

生产环境无需手动复制文件injectPrintLockCss() 内置 Blob URL 回退——当 /print-lock.css 不可达时自动用内联 CSS 创建 Blob URL,hiprint XHR 仍可正常获取。如需指定自定义地址(如 CDN),可通过 printLockCssUrl 选项:

// Vue 插件方式
Vue.use(HprintPlugin, { printLockCssUrl: '/cdn/print-lock.css' })

// 编程式调用
const designer = new HPrintDesigner({ printLockCssUrl: '/cdn/print-lock.css' })

后端适配器

RestAdapter

import { HprintPlugin, RestAdapter } from 'hprint-designer'
import 'hprint-designer/dist/style.css'

Vue.use(HprintPlugin, { adapter: new RestAdapter({ baseURL: 'https://your-server/api' }) })

MockAdapter(零后端)

import { HprintPlugin, MockAdapter } from 'hprint-designer'
import 'hprint-designer/dist/style.css'

Vue.use(HprintPlugin, { adapter: new MockAdapter() })

自定义 BackendAdapter

import type { BackendAdapter } from 'hprint-designer'

class MyAdapter implements BackendAdapter {
  async listTemplates(filter?) { /* ... */ }
  async getTemplate(id) { /* ... */ }
  async createTemplate(input) { /* ... */ }
  async updateTemplate(id, patch, ifVersion?) { /* ... */ }
  async deleteTemplate(id) { /* ... */ }

  async listFonts() { /* ... */ }
  async uploadFont(file, meta) { /* ... */ }
  async updateFont(id, patch) { /* ... */ }
  async deleteFont(id) { /* ... */ }

  async getClientRelease() { /* ... */ }

  // 可选:逐票回执自动落库
  async savePrintReceipt?(receipt) { /* POST 业务 API */ }
  async getPrintReceipts?(sessionId) { /* GET 按 session 查询 */ }
}

REST 路由映射

| 资源 | 方法 | 路径 | 说明 | |------|------|------|------| | 模板 | GET | /templates | 列表,支持 filter | | 模板 | GET | /templates/:id | 详情 | | 模板 | POST | /templates | 创建 | | 模板 | PUT | /templates/:id | 更新(If-Match 乐观锁) | | 模板 | DELETE | /templates/:id | 删除 | | 字体 | GET | /fonts | 字体列表 | | 字体 | POST | /fonts | 上传(multipart) | | 字体 | PUT | /fonts/:id | 修改 | | 字体 | DELETE | /fonts/:id | 删除 | | 客户端 | GET | /client-release | 下载信息 | | 回执 | POST | /print-receipts | 保存回执 | | 回执 | GET | /print-receipts?sessionId= | 按会话查询 |

常见问题

页面没有样式 / 布局错乱

import 'hprint-designer/dist/style.css'

ant-design-vue 样式由设计器自动注入,无需手动引入。

左侧拖拽图标显示为方框或文字

设计器使用 Bootstrap 3 的 glyphicons。在 index.html 中添加:

<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" />

静默打印无响应

  • 确认已安装并运行 electron-hiprint 客户端(必须使用本仓库内置修改版
  • 确认 createPrintConnection 中的 host / token 与客户端配置一致

静默打印出来是空白页

hiprint 的 print2() 通过 XHR 请求 link[media=print][href*="print-lock"] 的 CSS。请求失败则打印空白。

  1. index.html 中必须引入 print-lock.css,且 <link media="print">href 必须包含 print-lock
  2. href 必须是可被 XHR 请求的真实 HTTP 地址,不能用 data URI
  3. /print-lock.css 必须返回 Content-Type: text/css。Vite 推荐用 ?url 导入
  4. 本库已自动处理注入(HprintPlugin.install() 调用 injectPrintLockCss()),通常无需手动添加
  5. 如果 /print-lock.css 不可达,库会自动回退到 Blob URL,无需手动复制文件;也可通过 printLockCssUrl 选项指定自定义地址

静默打印纸张尺寸不对

所有 runtime 函数的 pageSize 参数为必传,需根据模板纸张尺寸显式指定:

// 从模板 JSON 中获取纸张尺寸
const pageSize = template.paper
  ? { widthMm: template.paper.widthMm, heightMm: template.paper.heightMm }
  : { widthMm: 210, heightMm: 297 }  // fallback A4

await batchPrintSilent({ template, dataList, pageSize, /* ... */ })

如需直接调用 hiprint 的 print2

// 标准纸张
template.print2(data, { pageSize: 'A4' })

// 自定义纸张(80mm × 200mm)
template.print2(data, {
  pageSize: { width: 80000, height: 200000 },  // 单位 microns
  margins: { marginType: 'none' },
  printBackground: true,
  silent: true
})

浏览器打印多出一页 / 出现页码

本库通过 styleHandler 注入 @page { margin: 0 }.hiprint-paperNumber { display: none }。如仍出现,检查:

  1. styleHandler 返回值必须用 <style> 标签包裹
  2. 宿主项目 index.html 中添加 @media print 样式隐藏非打印区域

开发

npm install
npm run dev             # 本地 demo(含回执调试面板)
npm run client:start    # 可选:启动内置 electron-hiprint
npm run build           # 构建库产物(designer + runtime 双 bundle)
npm run typecheck       # TypeScript 类型检查
npm test                # 运行测试

本地调试示例:dev/batch-print-demo.tsdev/App.vue

协议

MIT. 本库依赖 vue-plugin-hiprint(hiprint 2.5.4,LGPL)。 本库以类库引用方式使用 hiprint,未修改其源码,符合 LGPL 类库引用豁免。 详见 hiprint 的 LICENSE。