# 报告模板开发指南 | 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** 编码保存