# 报告模板开发指南 | Template Development Guide
## 1. 概述
XP.ReportEngine 使用 JSON 格式定义报告模板。模板描述了 PDF 报告的页面结构、元素布局、数据绑定和样式定义。
模板文件存放在 `XP.ReportEngine/Templates/` 目录下,通过 `App.config` 中的 `Report:TemplatePath` 配置项指定使用哪个模板。
## 2. 新增模板步骤
### 2.1 创建模板文件
1. 在 `Templates/` 目录下创建新的 JSON 文件,如 `CustomReportTemplate.json`
2. 在 `.csproj` 中确认模板文件会被复制到输出目录(已有通配规则):
```xml
PreserveNewest
```
3. 修改 `App.config` 中的 `Report:TemplatePath` 指向新模板:
```xml
```
### 2.2 模板验证规则
模板加载后会自动验证,必须满足以下条件:
- 包含 `document` 顶层字段(页面设置)
- 包含 `pages` 顶层字段(至少一个页面定义)
- 包含 `styles` 顶层字段(样式字典)
验证失败时报告生成会返回错误,不会生成 PDF。
## 3. 模板 JSON 结构
```json
{
"document": { ... }, // 必需:文档级设置(页面尺寸、边距、页眉页脚)
"pages": [ ... ], // 必需:页面定义数组
"styles": { ... } // 必需:样式定义字典
}
```
## 4. document 配置
```json
{
"document": {
"pageSize": "A4",
"orientation": "Portrait",
"margins": { "top": 40, "bottom": 20, "left": 20, "right": 20 },
"header": {
"enabled": true,
"left": ["标题文本", "第二行文本"],
"right": ["右侧文本"],
"rightImageKey": "companyLogo",
"leftImageKey": "softwareLogo",
"fontSize": 7,
"color": "#666666",
"showLine": true
},
"footer": {
"enabled": true,
"left": ["公司名称"],
"right": ["{currentPage} / {totalPages}"],
"fontSize": 8,
"color": "#666666",
"showLine": true
}
}
}
```
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `pageSize` | string | `"A4"` | 页面尺寸 |
| `orientation` | string | `"Portrait"` | 方向:Portrait / Landscape |
| `margins` | object | `{top:20, bottom:20, left:20, right:20}` | 边距(mm) |
| `header` | object | null | 页眉配置(首页不显示) |
| `footer` | object | null | 页脚配置(首页不显示) |
### 页眉/页脚字段
| 字段 | 类型 | 说明 |
|------|------|------|
| `enabled` | bool | 是否启用 |
| `left` | string[] | 左侧文本行(支持 `${}` 绑定) |
| `right` | string[] | 右侧文本行(支持 `${}` 绑定) |
| `leftImageKey` | string | 左侧图像的 dataKey |
| `rightImageKey` | string | 右侧图像的 dataKey |
| `fontSize` | float | 字体大小 |
| `color` | string | 字体颜色(十六进制) |
| `showLine` | bool | 是否显示分隔线 |
页脚特殊占位符:
- `{currentPage}` — 当前页码
- `{totalPages}` — 总页数
## 5. pages 页面定义
```json
{
"pages": [
{
"type": "homepage",
"elements": [ ... ]
},
{
"type": "customPage",
"elements": [ ... ]
}
]
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `type` | string | 页面类型标识(`homepage` 类型不显示页眉页脚) |
| `elements` | array | 页面内的元素列表 |
### 内置页面类型
| 类型 | 说明 | 特殊行为 |
|------|------|---------|
| `homepage` | 首页 | 不显示页眉页脚 |
| `summary` | 汇总页 | 无 |
| `metricData` | 距离测量页 | 无 |
| `bgaInspection` | BGA 检测页 | 无 |
| `voidInspection` | 空隙检测页 | 无 |
| `viaFillInspection` | 通孔填锡页 | 无 |
你可以自定义任意 `type` 名称,只有 `homepage` 有特殊行为(不显示页眉页脚)。
## 6. 元素类型
### 6.1 text — 文本元素
```json
{
"type": "text",
"content": "${loc:Report_Title}",
"style": "heading",
"positioning": "flow",
"align": "center",
"colorRules": { "Pass": "#008000", "Fail": "#FF0000" }
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `content` | string | 文本内容,支持 `${}` 绑定表达式 |
| `style` | string | 引用 `styles` 中定义的样式名 |
| `align` | string | 对齐:left / center / right |
| `colorRules` | object | 条件颜色规则(内容包含关键词时变色) |
### 6.2 image — 图像元素
```json
{
"type": "image",
"dataKey": "workpieceImage",
"size": [160, 110],
"border": true,
"align": "center",
"style": "imageDefault",
"positioning": "flow"
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `dataKey` | string | 图像数据键(对应 `ReportContext.Images` 中的键) |
| `size` | float[2] | [宽, 高](mm),图像会等比缩放适应 |
| `border` | bool | 是否显示边框 |
| `align` | string | 对齐:left / center / right |
图像缺失时会渲染灰色占位矩形,不会中断报告生成。
### 6.3 table — 表格元素
```json
{
"type": "table",
"dataKey": "bgaBallsTable",
"positioning": "flow",
"size": [170, 0],
"style": "tableDefault",
"columns": [
{ "header": "序号", "field": "index", "width": 25, "align": "center" },
{ "header": "气泡率", "field": "voidRate", "width": 40, "align": "center" },
{ "header": "面积", "field": "area", "width": 40, "align": "center" },
{
"header": "分类",
"field": "classification",
"width": 35,
"align": "center",
"colorRules": { "Pass": "#008000", "Fail": "#FF0000" }
}
]
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `dataKey` | string | 表格数据键(对应 `ReportContext.Properties` 中的 `List>` 数据) |
| `size` | float[2] | [宽, 高](mm),高度为 0 表示自动 |
| `columns` | array | 列定义数组 |
#### 列定义(ColumnDefinition)
| 字段 | 类型 | 说明 |
|------|------|------|
| `header` | string | 表头文本(支持 `${}` 绑定) |
| `field` | string | 数据字段名(对应行数据字典中的键) |
| `width` | float | 列宽(mm) |
| `align` | string | 对齐:left / center / right |
| `colorRules` | object | 条件颜色规则(单元格值匹配时变色) |
### 6.4 row — 水平布局容器
```json
{
"type": "row",
"size": [170, 100],
"widths": [6, 4],
"positioning": "flow",
"children": [
{
"type": "column", "align": "left",
"children": [
{ "type": "image", "dataKey": "myImage", "size": [110, 90] }
]
},
{
"type": "column", "align": "left",
"children": [
{ "type": "text", "content": "文本内容", "style": "body" }
]
}
]
}
```
| 字段 | 类型 | 说明 |
|------|------|------|
| `size` | float[2] | [总宽, 总高](mm) |
| `widths` | float[] | 列宽比例数组(如 `[6, 4]` 表示 60%:40%) |
| `children` | array | 子列元素(`type: "column"`) |
### 6.5 spacer — 间距元素
```json
{ "type": "spacer", "size": [170, 10], "positioning": "flow" }
```
用于在元素之间添加垂直间距。`size[1]` 为间距高度(mm)。
### 6.6 divider — 分隔线
```json
{ "type": "divider", "positioning": "flow" }
```
渲染一条水平分隔线。
### 6.7 pagebreak — 强制分页
```json
{ "type": "pagebreak" }
```
在当前位置强制插入分页符。
## 7. 样式定义
```json
{
"styles": {
"heading": {
"font": "auto",
"size": 16,
"bold": true,
"italic": false,
"color": "#333333",
"align": "left",
"marginTop": 0,
"marginBottom": 3,
"paddingLeft": 0,
"lineHeight": 0,
"backgroundColor": ""
}
}
}
```
| 字段 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `font` | string | `"auto"` | 字体(`auto` 根据语言自动选择) |
| `size` | float | 12 | 字体大小(pt) |
| `bold` | bool | false | 粗体 |
| `italic` | bool | false | 斜体 |
| `color` | string | `"#000000"` | 字体颜色(十六进制) |
| `align` | string | `"left"` | 对齐:left / center / right |
| `backgroundColor` | string | — | 背景色(十六进制) |
| `marginTop` | float | 0 | 上边距(mm) |
| `marginBottom` | float | 0 | 下边距(mm) |
| `paddingLeft` | float | 0 | 左缩进(mm) |
| `lineHeight` | float | 0 | 行高倍数(0 = 默认) |
元素引用未定义的样式名时,会使用默认样式(12pt、黑色、左对齐),不会报错。
## 8. 数据绑定表达式
模板中的 `content`、`header` 等文本字段支持 `${}` 绑定表达式:
| 语法 | 说明 | 示例 |
|------|------|------|
| `${key}` | 从 Properties 中取值 | `${sampleName}` |
| `${metadata.field}` | 从 Metadata 中取值 | `${metadata.reportId}` |
| `${loc:Key}` | 多语言资源键 | `${loc:Report_Title}` |
| `${formatDate(value)}` | 格式化日期 | `${formatDate(metadata.inspectionDate)}` |
| `${formatNumber(value, decimals)}` | 格式化数字 | `${formatNumber(totalArea, 2)}` |
| `${formatPercent(value)}` | 格式化百分比 | `${formatPercent(voidRate)}` |
### 数据来源
绑定表达式从 `ReportContext` 中查找数据:
- `Properties` 字典 — 扁平化的键值对(由 `ProcessorDataAdapter` 从处理器输出转换而来)
- `Metadata` — 报告元数据对象
- `Images` 字典 — 图像数据(通过 `dataKey` 引用)
### ProcessorDataAdapter 输出的键名
| 处理器类型 | Properties 中的键 | Images 中的键 | 表格 dataKey |
|-----------|------------------|--------------|-------------|
| LineMeasurementProcessor | measurementType, point1, point2, pixelDistance, actualDistance, unit, angle | lineMeasurementImage | — |
| BgaVoidRateProcessor | bgaCount, voidRate, fillRate, totalBgaArea, totalVoidArea, voidLimit, classification | bgaInspectionImage | bgaBallsTable |
| VoidMeasurementProcessor | roiArea, totalVoidArea, voidRate, voidLimit, voidCount, maxVoidArea, classification | voidInspectionImage | voidsTable |
| FillRateProcessor | fillRate, voidRate, fullDistance, fillDistance, thtLimit, classification, e1-e4 | viaFillImage | — |
### ReportService 自动注入的键
| 键 | 来源 | 说明 |
|----|------|------|
| `CompanyName` | ReportConfig | 公司名称 |
| `SoftwareName` | ReportConfig | 软件名称 |
| `companyLogo` | ReportConfig.CompanyLogo | 公司 Logo(Images) |
| `softwareLogo` | ReportConfig.SoftwareLogo | 软件 Logo(Images) |
| `summaryTable` | 自动生成 | 首页汇总表数据 |
## 9. 定位方式
| 值 | 说明 |
|----|------|
| `"flow"` | 流式布局,元素按顺序从上到下排列(推荐) |
| `"absolute"` | 绝对定位,使用 `position` 坐标(不推荐,兼容性差) |
建议所有元素使用 `"positioning": "flow"`。
## 10. 完整模板示例(最小化)
```json
{
"document": {
"pageSize": "A4",
"orientation": "Portrait",
"margins": { "top": 20, "bottom": 20, "left": 20, "right": 20 }
},
"pages": [
{
"type": "homepage",
"elements": [
{ "type": "text", "content": "检测报告", "style": "title", "positioning": "flow" },
{ "type": "text", "content": "报告编号:${metadata.reportId}", "style": "body", "positioning": "flow" },
{ "type": "text", "content": "检测日期:${formatDate(metadata.inspectionDate)}", "style": "body", "positioning": "flow" }
]
},
{
"type": "dataPage",
"elements": [
{ "type": "text", "content": "检测数据", "style": "heading", "positioning": "flow" },
{ "type": "image", "dataKey": "inspectionImage", "size": [150, 100], "positioning": "flow" }
]
}
],
"styles": {
"title": { "size": 24, "bold": true, "align": "center" },
"heading": { "size": 16, "bold": true },
"body": { "size": 12 }
}
}
```
## 11. 注意事项
1. **尺寸单位**:所有尺寸(size、margins、width)单位为 **mm**(毫米)
2. **颜色格式**:使用十六进制格式 `#RRGGBB`(如 `#FF0000` 为红色)
3. **表格自动跨页**:当表格数据行超出当前页面剩余空间时,排版引擎会自动分页
4. **图像缺失容错**:图像 dataKey 对应的数据不存在时,渲染占位矩形,不中断生成
5. **样式缺失容错**:引用未定义的样式名时使用默认样式,不中断生成
6. **绑定表达式缺失**:`${}` 表达式对应的数据不存在时,替换为空字符串
7. **首页特殊处理**:`type: "homepage"` 的页面不显示页眉页脚
8. **JSON 编码**:模板文件必须使用 **UTF-8** 编码保存