# 标签模板

> 标签库里的一个打印机指令文件：它的名称和编码、打印机指令编辑器和文件导入、标记的写法、已安装的 Windows 队列，以及测试发送。

一个标签模板是**标签**库（Process > 模板 > 标签）里的一行：一个打印机指令文件（ZPL、EPL、CPCL 或者别的任何 RAW 指令语言），在该填运行值的地方带着 `{{NAME}}` 标记。Ganter Lab 把这些字节送给一个 Windows RAW 队列，并替换掉那些标记；它从不解析、渲染或者预览打印机语言，因此版面本身是在打印机厂商的工具里设计的。编辑它需要**管理 Process**；有单元正在运行时整页都是死的，运行时已停止时发送测试会被拒绝。新模板生下来是空的，名叫“标签”（“标签 2”，依此类推），在它装上指令之前什么也打不出来：每一条渲染或者发送的路径都会拒绝一个空模板。

这一页是五张卡片，按干活的顺序排列：标识与编码、那些指令、在指令里找到的标记、怎么在设计软件里准备一个文件，以及测试发送。

## 模板 {#template}

| 字段 | 是什么 | 取值 / 默认 | 效果 |
| --- | --- | --- | --- |
| 名称 | 库和每一条标签命令所显示的那个名称。 | 文本；离开这个字段时提交。 | 空名称会被拒绝（“标签模板必须有名称。”），仍保留原来的名称。 |
| 编码 | 保存下来的字节按什么读回成文本，以及每一个被替换进去的值怎么编码。 | UTF-8（默认）、Latin-1、ASCII。 | 改动它会用新编码重写可编辑的指令；新编码表示不了的字符会被拒绝（“这些指令仍然用 UTF-8。第 3 行含有‘é’，ASCII 表示不了它。”），编码保持不变。不透明的指令保留自己的字节，只是按新的声明重新读一遍。 |

## 打印机指令 {#printer-commands}

| 控件 | 做什么 |
| --- | --- |
| 编辑器 | 一个等宽文本字段，装着那些指令，占位文字是一段 ZPL 的样子。边打边校验（标记列表和任何一条拒绝都跟着文字走）；离开这个字段就保存。被拒绝的草稿连同理由留在屏幕上，不会保存；打开另一个模板就把它丢掉。保存一段和已存字节完全相同的文字，什么也不会改变。 |
| 导入文件…… / 替换文件…… | 把一个打印机指令文件拿进来（`.zpl`、`.epl`、`.epl2`、`.cpcl`、`.prn`、`.lbl`、`.txt`）。字节被复制进配置里，文件名保留下来以便追溯：移动或者删除原文件都不影响这个模板。空文件和超过 2 MB 的文件会被拒绝，标记写错的文件也一样。 |

指令只有在逐字节走完一个来回还完好无损时才能当文本编辑：它们按声明的编码解码得开，再编码回同样的字节，每一行用同样的方式结束（全是 LF 或者全是 CR LF；导入进来的 CR LF 风格在每次保存时都放回去），而且除了制表符和行结束符之外不带任何控制字符。任何一项过不了的指令就一直是**不透明的**：编辑器被换成理由（“偏移 12 处的字节 0x1B 不是 UTF-8 文本。”“行尾混用：有的行以 CR LF 结束，有的行只以 LF 结束。”），那些字节只有靠替换文件才会变。卡片下面有一行说明保存下来的是什么：“还没有保存任何东西。”、“导入自 labels.zpl · 1.2 KB · 保留 CR LF 换行”或者“在这里写的 · 240 B”。

## 检测到的标记 {#detected-markers}

在保存下来的指令里找到的那些标记，按第一次出现的顺序排列。一个标记是严格的 ASCII `{{NAME}}`：名称以 A 到 Z 开头，接下去可以是 A 到 Z、0 到 9 或者下划线，最长 64 个字符，并以 `}}` 收尾。凡是以 `{{` 开头却不守这套写法的，都会连同它的字节偏移量和它违反的那条规则一起被拒绝（“字节偏移 40 处的标签标记写法有误：名称只能含 A-Z、0-9 或者下划线。”）。标记之外的每一个字节都原样保留，替换只做一次，绝不递归。

一个没有指令的模板读作“还没有指令。请在上面写下打印机指令，或者导入一个从标签设计软件导出的文件。在那之前，这个模板什么也打不出来。”；一个有指令却没有标记的模板读作“没有找到标记：这个固定标签每次都发送相同的字节，不使用任何运行数据。”，它也是一个有效的模板。每一个不同的标记，在每一条用到这个模板的标签命令里都需要一个来源；重复出现的标记拿到同一个值。这张卡片以那条常设规则收尾：Ganter Lab 只校验标记的写法，不校验厂商指令。只保存你信得过的指令；它们可能改变打印机的行为。

## 在标签设计软件里准备一个模板 {#prepare-a-template-in-a-label-designer}

一段折叠起来的流程提醒：

1. 在打印机厂商的工具里做好标签版面，例如 ZebraDesigner。
2. 在文本或条码内容里放上 Ganter Lab 的标记，例如 `{{SERIAL}}` 或 `{{RESULT}}`。
3. 导出可直接送打印机的指令文件，例如 ZPL。不要导入设计软件的工程文件。
4. 把那个文件导入到这里（或者把它的内容粘贴到指令字段里），并核对检测到的标记。
5. 在下面填入有代表性的值，对着一个已安装的 Windows 队列测试。

EPL、CPCL 和别的打印机指令语言也是同样的流程。

## 测试发送 {#test-send}

| 控件 | 做什么 |
| --- | --- |
| 刷新队列 | 重新读取为当前交互式 Windows 用户安装的那些打印队列。读不到时会在选择器旁边说出来。 |
| 每个标记一个取值框 | 只在这一次发送里替换到那个标记处的示例文字。固定模板读作“这个固定模板不需要示例值。”；空模板读作“这个模板有打印机指令之前，没有可发送的东西。”。 |
| 已安装的 Windows 队列 | 这次测试送到哪个队列（“（请选一个队列）”或者“（没有已安装的队列）”）。 |
| 发送测试 | 用那些示例值渲染保存下来的指令，并作为一份名叫 `Ganter Lab test · <模板名>` 的 RAW 文档提交。不会创建任何运行记录，也不会创建任何存档件。结果落在操作记录条上（“测试标签已送到‘Q’。”或者“测试发送失败：理由”）。 |

没有保存指令时、没有选定队列时、正在发送时，以及整页是死的时候，发送测试变灰。声明的编码里装不下的值会被渲染器拒绝。成功只表示 Windows 队列接受了这份 RAW 文档，并不确认真的打出了一张实体标签。

## 这些值从哪里来 {#where-the-values-come-from}

上面那些示例值只用于测试。在一次运行记录里，模板的每一个不同标记，都在用到它的那条标签命令上映射到唯一一个有限的来源（[动作](process-actions)）：冻结下来的元数据、模型名称和修订号、单元名称和代号、流程名称和代号、运行记录标识、开始时刻、运行状态，而在完成时还有结束时刻、时长、结论、结束原因，以及带明确循环号的某一条具名判据的结果。日期和时间来源带一个格式（工作站日期和时间、工作站日期、工作站时间、ISO 8601 格式），数值来源带一个可选的固定小数位数（0 到 9）。数字是写给读它的机器看的，不按工作站在屏幕上显示数字的方式：绝不带千位分隔符，因为那在条码里会把接收方的系统弄坏，永远用不变的小数点，而整数，比如一个计数或者一个以秒计的时长，就写成整数。带控制字符（含换行）的值，或者带打印机指令起始字符（`^`、`~`）的值，会被点名它的标记拒绝：那会把它所在的那一行切开，或者打出一张不一样的标签。每一个时机提供什么、存档件怎么冻结、一次发送怎么记录，写在[产出标签与报告][emission]里；对着一条已记录的运行记录手工映射一个模板，写在[标签与报告][documents]里。

[emission]: process-emission
[documents]: histories-documents#labels

## 这一页不做的事 {#what-this-page-does-not-do}

它不画标签的任何预览，也不校验打印机语言的任何东西。它不把任何标记映射到值：那是标签命令的活。它不为一次运行记录打印标签：一次运行记录的那些存档件是从它在历史里的档案打印出来的。而删掉这个模板（命令栏上的**删除标签**）不会触动任何一件已记录的存档件；只有那些仍然指名它的命令不再生成。
