五、设计器·HTML 模板模式
HTML 模板模式(mode = html)面向有版式要求的场景:模板内容是一段 HTML 源码,用 {{}} 占位符引用变量,由前端渲染引擎替换成真实数据。
5.1 语法总览
设计器顶部固定语法提示(代码块):
{{bill.字段}} {{#each items}} {{this.字段}} {{__index__}} {{/each}} {{fmtPrice bill.totalPrice}} {{chinese bill.totalPrice}}| 语法 | 作用 | 示例 |
|---|---|---|
{{bill.字段}} | 输出单头变量 | {{bill.no}}、{{bill.supplierName}} |
{{#each items}} ... {{/each}} | 遍历明细行(支持嵌套) | 见 5.5 骨架 |
{{this.字段}} | each 循环内引用当前行字段 | {{this.productName}} |
{{__index__}} | each 循环内当前行号(从 1 开始) | 序号列 |
{{system.字段}} | 系统变量 | {{system.tenantName}} |
{{helper 路径}} | 格式化函数 | {{fmtPrice bill.totalPrice}} |
模板必须写闭合合法的 HTML 片段(不需要 html/head/body 外壳,写正文即可);
{{#each}}未闭合保存时会报语法错误。
5.2 变量从哪来:变量面板
源码编辑区下方是「变量清单(点击插入)」面板,按三组展示标签,点击即把占位符追加到源码末尾(注意:不是光标处,插入后请自行剪切到目标位置):
| 组 | 标签样式 | 生成占位符 |
|---|---|---|
| 单头变量 | 凭证号 {{bill.voucherNo}} | {{bill.voucherNo}} |
| 明细变量(each 内用 this.) | 金额 {{this.totalPrice}} | {{this.totalPrice}} |
| 系统变量 | 租户名称 {{system.tenantName}} | {{system.tenantName}} |
变量清单按 billType 实时拉取(/infra/print/variables),每个单据类型可用变量不同,切换类型后清单随之变化。
5.3 格式化函数(helper)
| 函数 | 作用 | 示例 → 输出 |
|---|---|---|
fmtPrice | 金额千分位 + 两位小数 | {{fmtPrice bill.totalPrice}} → 1,234.56 |
fmtNum | 数值格式化 | {{fmtNum this.count}} → 12 |
fmtDate | 日期 → yyyy-MM-dd | {{fmtDate bill.createTime}} → 2026-09-05 |
fmtDateTime | 日期时间 → yyyy-MM-dd HH:mm:ss | {{fmtDateTime bill.auditTime}} → 2026-09-05 10:30:00 |
chinese | 人民币大写 | {{chinese bill.totalPrice}} → 壹仟贰佰叁拾肆元伍角陆分 |
helper 内路径与普通占位符一致(bill./this./system. 均可)。
5.4 系统变量(5 个)
| 变量 | 含义 | 说明 |
|---|---|---|
system.tenantName | 租户/公司名称 | 自动取当前登录租户 |
system.printTime | 打印时间 | 预览/打印时刻,yyyy-MM-dd HH:mm:ss |
system.printUser | 打印人 | 当前登录用户昵称 |
system.qrCode | 单号二维码 | <img src="{{system.qrCode}}"> 即可显示,扫码得单号 |
system.chineseAmount | 大写金额 | 按价税合计自动转换,兜底使用 |
5.5 标准模板骨架
点【插入标准模板骨架】一键填入完整示例,覆盖抬头/二维码/信息表/明细循环/合计大写/签字栏/页脚。在此基础上改比自己从零写快得多:
html
<div class="bill-header">
<div class="company-info">
<div class="company-name">{{system.tenantName}}</div>
<div class="bill-sub">{单据副标题}</div>
</div>
<div class="bill-title">{单据标题}</div>
<div class="qr-box"><img src="{{system.qrCode}}" alt="单号二维码"/><div class="qr-no">{{bill.no}}</div></div>
</div>
<table class="info-table">
<tr>
<td class="label">单据编号</td><td>{{bill.no}}</td>
<td class="label">单据日期</td><td>{{fmtDate bill.createTime}}</td>
</tr>
</table>
<table class="items-table">
<thead>
<tr><th>#</th><th>名称</th><th>数量</th><th>单价(元)</th><th>金额(元)</th></tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td class="center">{{__index__}}</td>
<td>{{this.productName}}</td>
<td class="right">{{fmtNum this.count}}</td>
<td class="right">{{fmtPrice this.price}}</td>
<td class="right">{{fmtPrice this.totalPrice}}</td>
</tr>
{{/each}}
</tbody>
</table>
<table class="summary-table"><tbody><tr class="grand-total">
<td class="label" style="width:90px;">价税合计</td>
<td class="right grand-price" style="width:170px;">¥ {{fmtPrice bill.totalPrice}}</td>
<td class="label" style="width:60px;">大写</td>
<td class="grand-cn">{{chinese bill.totalPrice}}</td>
</tr></tbody></table>
<div class="sign-bar"><span>制单人:{{system.printUser}}</span><span>审核:________</span><span>日期:________</span></div>
<div class="print-footer">本单据由 {{system.tenantName}} 系统生成,打印时间:{{system.printTime}}</div>使用步骤:插入骨架 → 对照变量面板把 {{bill.no}}、{{this.productName}} 等替换成该单据类型的真实变量名 → 删掉多余列/加需要的列 → 看右侧预览 → 保存。
5.6 可用的内置样式类
渲染引擎为打印页内置了一整套单据风格样式,HTML 里直接用 class 即可,无需写 CSS:
| class | 作用 |
|---|---|
bill-header / company-info / company-name / bill-title | 抬头区(大标题 26px、字距 10px) |
qr-box / qr-no | 右上角二维码区 |
info-table + td.label | 单头信息表(label 灰底) |
items-table | 明细表格(黑边框、表头灰底) |
td.right / td.center | 右对齐 / 居中单元格 |
summary-table / grand-total / grand-price / grand-cn | 合计行(加粗红价、大写) |
sign-bar | 签字栏 |
print-footer | 页脚(公司名 + 打印时间) |
需要微调时可用内联 style(如 style="width:90px"),或写 <style> 标签整体覆盖。
5.7 编辑与保存
- 源码区为等宽字体多行编辑器(22 行高,Menlo/Consolas),粘贴外部 HTML 同样支持;
- 顶部实时语法错误提示(如 each 未闭合);
- 【保存模板】会校验:模板名称、纸张宽高、HTML 语法;通过后源码整体存入 content。
5.8 常见坑
- 占位符没替换:变量名拼错(对照变量面板的 key,区分大小写);或用了其他单据类型的变量;
- 明细空:
{{#each items}}写在表格外面了——循环标签必须包住<tr>行; - 想显示序号:用
{{__index__}},不是数组下标; - 样式丢失:打印页只渲染模板片段 + 内置样式,外部 CDN 样式不会加载;
- 图片:只支持 dataURL 或系统内可访问的 URL;
{{system.qrCode}}本身就是 dataURL,直接放src。
