新增XP.ReportEngine空项目
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,328 @@
|
|||||||
|
# XP.ReportEngine 模板定义规范
|
||||||
|
|
||||||
|
## **一、模板结构总览**
|
||||||
|
|
||||||
|
模板使用JSON格式定义,分为以下几个核心部分:
|
||||||
|
|
||||||
|
1.
|
||||||
|
|
||||||
|
`document`:文档基础配置(页面尺寸、边距等)。
|
||||||
|
|
||||||
|
2.
|
||||||
|
|
||||||
|
`pages`:页面列表,每个页面包含元素列表。
|
||||||
|
|
||||||
|
3.
|
||||||
|
|
||||||
|
`elements`:页面中的具体元素(文本、表格、图片等)。
|
||||||
|
|
||||||
|
4.
|
||||||
|
|
||||||
|
`styles`:预定义的样式,可复用。
|
||||||
|
|
||||||
|
5.
|
||||||
|
|
||||||
|
`dataKey`:数据绑定字段,关联业务数据。
|
||||||
|
|
||||||
|
## **二、首页布局规范**
|
||||||
|
|
||||||
|
**模板路径**:`Templates/Homepage.json`
|
||||||
|
|
||||||
|
代码<title>图标/24_new/复制</title>
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"document": {
|
||||||
|
"pageSize": "A4",
|
||||||
|
"orientation": "Portrait",
|
||||||
|
"margins": { "top": 30, "right": 20, "bottom": 20, "left": 20 }
|
||||||
|
},
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "homepage",
|
||||||
|
"elements": [
|
||||||
|
{ "type": "text", "content": "平面CT检测报告", "style": "title", "position": [10, 10] },
|
||||||
|
{ "type": "text", "content": "报告编号:${reportId}", "style": "subtitle", "position": [10, 40] },
|
||||||
|
{ "type": "text", "content": "检测日期:${inspectionDate}", "style": "subtitle", "position": [10, 60] },
|
||||||
|
{ "type": "text", "content": "样品名称:${sampleName}", "style": "subtitle", "position": [10, 80] },
|
||||||
|
{ "type": "divider", "position": [10, 100], "width": 190 },
|
||||||
|
{ "type": "table", "dataKey": "summaryData", "columns": [...], "position": [10, 120], "size": [190, 60] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": {
|
||||||
|
// ... 样式定义(见下文)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键要素说明**:
|
||||||
|
|
||||||
|
1.
|
||||||
|
|
||||||
|
**标题与元数据**:顶部显示报告标题、编号、日期和样品名称。
|
||||||
|
|
||||||
|
2.
|
||||||
|
|
||||||
|
**摘要表格**:显示关键统计信息(如缺陷数量、合格率等),通过`summaryData`绑定数据。
|
||||||
|
|
||||||
|
3.
|
||||||
|
|
||||||
|
**分隔线**:视觉分隔标题与主体内容。
|
||||||
|
|
||||||
|
## **三、测量数据布局规范**
|
||||||
|
|
||||||
|
**模板路径**:`Templates/MetricData.json`
|
||||||
|
|
||||||
|
代码<title>图标/24_new/复制</title>
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "metricData",
|
||||||
|
"elements": [
|
||||||
|
{ "type": "text", "content": "测量数据详情", "style": "sectionTitle", "position": [10, 10] },
|
||||||
|
{ "type": "table", "dataKey": "measurements", "columns": [
|
||||||
|
{ "header": "参数名称", "field": "parameter" },
|
||||||
|
{ "header": "测量值", "field": "value" },
|
||||||
|
{ "header": "单位", "field": "unit" }
|
||||||
|
], "position": [10, 30], "size": [190, 100] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": {
|
||||||
|
// ... 样式定义(见下文)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键要素说明**:
|
||||||
|
|
||||||
|
●
|
||||||
|
|
||||||
|
表格绑定`measurements`数据,列通过`field`属性绑定数据字段。
|
||||||
|
|
||||||
|
●
|
||||||
|
|
||||||
|
支持动态行数,自动调整表格高度。
|
||||||
|
|
||||||
|
## **四、缺陷检测布局规范**
|
||||||
|
|
||||||
|
**模板路径**:`Templates/DefectDetails.json`
|
||||||
|
|
||||||
|
代码<title>图标/24_new/复制</title>
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "defectDetails",
|
||||||
|
"elements": [
|
||||||
|
{ "type": "text", "content": "缺陷检测结果", "style": "sectionTitle", "position": [10, 10] },
|
||||||
|
{
|
||||||
|
"type": "grid", "dataKey": "defects",
|
||||||
|
"columns": [
|
||||||
|
{ "type": "image", "dataKey": "imagePath", "size": [90, 90], "border": true },
|
||||||
|
{ "type": "text", "content": "缺陷类型:${type}", "style": "gridText", "width": 100 },
|
||||||
|
{ "type": "text", "content": "位置:X=${x}, Y=${y}", "style": "gridText", "width": 100 }
|
||||||
|
],
|
||||||
|
"position": [10, 30], "colWidth": 100, "rowHeight": 100
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": {
|
||||||
|
"gridText": { "font": "Arial", "size": 10, "align": "left" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键要素说明**:
|
||||||
|
|
||||||
|
1.
|
||||||
|
|
||||||
|
**网格布局**:每行显示缺陷图片、类型和位置信息。
|
||||||
|
|
||||||
|
2.
|
||||||
|
|
||||||
|
使用`grid`元素自动排版多缺陷数据,支持水平滚动或分页。
|
||||||
|
|
||||||
|
3.
|
||||||
|
|
||||||
|
图片路径通过`imagePath`字段绑定,文本使用数据绑定语法(如`X=${x}`)。
|
||||||
|
|
||||||
|
## **五、BGA检测布局规范**
|
||||||
|
|
||||||
|
**模板路径**:`Templates/BGAInspection.json`
|
||||||
|
|
||||||
|
代码<title>图标/24_new/复制</title>
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "bgaDetails",
|
||||||
|
"elements": [
|
||||||
|
{ "type": "text", "content": "BGA焊点检测结果", "style": "sectionTitle", "position": [10, 10] },
|
||||||
|
{
|
||||||
|
"type": "image", "dataKey": "bgaTopViewImage", "position": [10, 30], "size": [190, 150], "border": true,
|
||||||
|
"annotations": [
|
||||||
|
{ "type": "point", "x": ${defectX}, "y": ${defectY}, "color": "red", "size": 5 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "table", "dataKey": "bgaMetrics",
|
||||||
|
"columns": [ "引脚编号", "焊锡高度", "偏移量" ],
|
||||||
|
"position": [10, 190], "size": [190, 80]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键要素说明**:
|
||||||
|
|
||||||
|
1.
|
||||||
|
|
||||||
|
**图片标注**:在BGA俯视图上标记缺陷位置(通过`annotations`)。
|
||||||
|
|
||||||
|
2.
|
||||||
|
|
||||||
|
**表格显示参数**:焊锡高度、偏移量等数据。
|
||||||
|
|
||||||
|
3.
|
||||||
|
|
||||||
|
支持动态标注点,绑定缺陷坐标数据。
|
||||||
|
|
||||||
|
## **六、气泡检测布局规范**
|
||||||
|
|
||||||
|
**模板路径**:`Templates/VoidInspection.json`
|
||||||
|
|
||||||
|
代码<title>图标/24_new/复制</title>
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "voidDetails",
|
||||||
|
"elements": [
|
||||||
|
{ "type": "text", "content": "气泡检测结果", "style": "sectionTitle", "position": [10, 10] },
|
||||||
|
{
|
||||||
|
"type": "image", "dataKey": "voidImage", "position": [10, 30], "size": [190, 150], "border": true,
|
||||||
|
"annotations": [
|
||||||
|
{ "type": "circle", "x": ${bubbleX}, "y": ${bubbleY}, "radius": ${bubbleRadius}, "color": "blue" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ "type": "text", "content": "总气泡数:${voidCount}", "style": "resultText", "position": [10, 190] },
|
||||||
|
{ "type": "text", "content": "最大气泡体积:${maxVoidVolume} mm³", "style": "resultText", "position": [10, 210] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": {
|
||||||
|
"resultText": { "font": "Arial", "size": 14, "bold": true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键要素说明**:
|
||||||
|
|
||||||
|
1.
|
||||||
|
|
||||||
|
**气泡可视化**:在图像上用圆形标注气泡位置、半径。
|
||||||
|
|
||||||
|
2.
|
||||||
|
|
||||||
|
**统计结果**:显示总数量、最大体积等关键指标。
|
||||||
|
|
||||||
|
3.
|
||||||
|
|
||||||
|
支持多气泡标注,数据绑定气泡坐标和尺寸。
|
||||||
|
|
||||||
|
## **七、通孔填锡率检测布局规范**
|
||||||
|
|
||||||
|
**模板路径**:`Templates/ViaFillInspection.json`
|
||||||
|
|
||||||
|
代码<title>图标/24_new/复制</title>
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "viaFillDetails",
|
||||||
|
"elements": [
|
||||||
|
{ "type": "text", "content": "通孔填锡率检测结果", "style": "sectionTitle", "position": [10, 10] },
|
||||||
|
{
|
||||||
|
"type": "image", "dataKey": "viaImage", "position": [10, 30], "size": [190, 150], "border": true,
|
||||||
|
"annotations": [
|
||||||
|
{ "type": "rectangle", "x": ${viaX}, "y": ${viaY}, "width": ${viaWidth}, "height": ${viaHeight}, "color": "green" }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{ "type": "text", "content": "平均填锡率:${avgFillRate}%", "style": "resultText", "position": [10, 190] },
|
||||||
|
{ "type": "progressBar", "value": ${avgFillRate}, "position": [10, 220], "size": [190, 20], "color": "${fillRateColor(avgFillRate)}" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"functions": {
|
||||||
|
"fillRateColor(value)": "return value >= 90 ? 'green' : value >= 70 ? 'orange' : 'red';"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键要素说明**:
|
||||||
|
|
||||||
|
1.
|
||||||
|
|
||||||
|
**填锡率图示**:用矩形标注通孔位置,进度条显示填锡率。
|
||||||
|
|
||||||
|
2.
|
||||||
|
|
||||||
|
**颜色条件绑定**:通过函数`fillRateColor`根据数值动态设置颜色。
|
||||||
|
|
||||||
|
3.
|
||||||
|
|
||||||
|
支持多通孔标注,绑定位置和尺寸数据。
|
||||||
|
|
||||||
|
## **八、样式定义示例**
|
||||||
|
|
||||||
|
代码<title>图标/24_new/复制</title>
|
||||||
|
|
||||||
|
```
|
||||||
|
"styles": {
|
||||||
|
"title": { "font": "Arial", "size": 24, "bold": true, "color": "#000000" },
|
||||||
|
"subtitle": { "font": "Arial", "size": 16, "italic": true, "color": "#666666" },
|
||||||
|
"gridText": { "font": "Arial", "size": 10, "align": "left" },
|
||||||
|
"resultText": { "font": "Arial", "size": 14, "bold": true }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**关键要素说明**:
|
||||||
|
|
||||||
|
●
|
||||||
|
|
||||||
|
样式可复用,通过`style`属性引用。
|
||||||
|
|
||||||
|
●
|
||||||
|
|
||||||
|
支持字体、大小、颜色、对齐等属性配置。
|
||||||
|
|
||||||
|
**# 总结**
|
||||||
|
|
||||||
|
●
|
||||||
|
|
||||||
|
**模块化设计**:各检测模块独立为单独模板文件,可灵活组合。
|
||||||
|
|
||||||
|
●
|
||||||
|
|
||||||
|
**数据绑定**:通过`${}`语法绑定业务数据(如`measurements`、`defects`等对象)。
|
||||||
|
|
||||||
|
●
|
||||||
|
|
||||||
|
**动态布局**:支持表格自适应高度、图片标注、条件样式等高级功能。
|
||||||
|
|
||||||
|
●
|
||||||
|
|
||||||
|
**可扩展性**:新增检测类型只需定义对应模板文件即可。
|
||||||
|
|
||||||
|
**备注**:实际使用时,需根据具体业务数据模型调整`dataKey`和字段名称,确保模板与输入数据匹配。
|
||||||
@@ -0,0 +1,422 @@
|
|||||||
|
# XP.ReportEngine 项目规划
|
||||||
|
|
||||||
|
## 一、项目结构优化
|
||||||
|
|
||||||
|
**1. 完整目录结构**
|
||||||
|
|
||||||
|
```
|
||||||
|
XP.ReportEngine/
|
||||||
|
├── Interfaces/
|
||||||
|
│ ├── IReportGenerator.cs // 报告生成器核心接口
|
||||||
|
│ ├── ITemplateEngine.cs // 模板引擎接口
|
||||||
|
│ └── IDataBinder.cs // 数据绑定接口
|
||||||
|
├── Models/
|
||||||
|
│ ├── ReportContext.cs // 报告上下文(包含测量数据、图片列表)
|
||||||
|
│ ├── ReportTemplate.cs // 报告模板定义
|
||||||
|
│ ├── TemplateElement.cs // 模板元素定义
|
||||||
|
│ └── LayoutSettings.cs // 布局配置参数
|
||||||
|
├── Services/
|
||||||
|
│ ├── MeasurementReportBuilder.cs // 测量报告构建器
|
||||||
|
│ ├── ImageLayoutService.cs // 图片排版服务(计算坐标、缩放)
|
||||||
|
│ ├── TemplateEngine.cs // 模板引擎实现
|
||||||
|
│ ├── DataBinder.cs // 数据绑定实现
|
||||||
|
│ └── PdfGenerationService.cs // PDF生成核心服务
|
||||||
|
├── Templates/
|
||||||
|
│ └── StandardReportTemplate.json // 标准报告模板配置
|
||||||
|
└── Extensions/
|
||||||
|
└── ImageExtensions.cs // 图像处理扩展方法
|
||||||
|
```
|
||||||
|
|
||||||
|
## 二、核心模块设计
|
||||||
|
|
||||||
|
### 1. 报告模板引擎
|
||||||
|
|
||||||
|
**1.1 模板定义规范**
|
||||||
|
|
||||||
|
- **JSON模板结构**:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"document": {
|
||||||
|
"pageSize": "A4",
|
||||||
|
"margins": { "top": 20, "bottom": 20, "left": 20, "right": 20 }
|
||||||
|
},
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"type": "title",
|
||||||
|
"elements": [
|
||||||
|
{ "type": "text", "content": "工业CT检测报告", "style": "title", "position": [10, 10] },
|
||||||
|
{ "type": "text", "content": "报告日期: ${reportDate}", "style": "subtitle", "position": [10, 30] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "measurement",
|
||||||
|
"elements": [
|
||||||
|
{ "type": "table", "dataKey": "measurements", "position": [10, 10], "size": [190, 100] },
|
||||||
|
{ "type": "image", "dataKey": "overviewImage", "position": [10, 120], "size": [190, 100] }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "defectDetail",
|
||||||
|
"elements": [
|
||||||
|
{ "type": "image", "dataKey": "defectImage", "position": [10, 10], "size": [90, 90] },
|
||||||
|
{ "type": "text", "content": "缺陷类型: ${defectType}", "style": "normal", "position": [10, 100] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"styles": {
|
||||||
|
"title": { "font": "Arial", "size": 24, "bold": true, "color": "#000000" },
|
||||||
|
"subtitle": { "font": "Arial", "size": 16, "italic": true, "color": "#666666" },
|
||||||
|
"normal": { "font": "Arial", "size": 12, "color": "#000000" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**1.2 模板引擎实现**
|
||||||
|
|
||||||
|
- **模板加载与解析**:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class TemplateEngine : ITemplateEngine
|
||||||
|
{
|
||||||
|
public ReportTemplate LoadTemplate(string templatePath)
|
||||||
|
{
|
||||||
|
var json = File.ReadAllText(templatePath);
|
||||||
|
return JsonConvert.DeserializeObject<ReportTemplate>(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<PageElement> ParseTemplate(ReportTemplate template, ReportContext context)
|
||||||
|
{
|
||||||
|
var elements = new List<PageElement>();
|
||||||
|
|
||||||
|
foreach (var page in template.Pages)
|
||||||
|
{
|
||||||
|
foreach (var element in page.Elements)
|
||||||
|
{
|
||||||
|
// 处理数据绑定
|
||||||
|
var boundElement = BindData(element, context);
|
||||||
|
elements.Add(boundElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageElement BindData(PageElement element, ReportContext context)
|
||||||
|
{
|
||||||
|
// 实现数据绑定逻辑
|
||||||
|
if (element.Type == "text" && element.Content.Contains("${"))
|
||||||
|
{
|
||||||
|
element.Content = DataBinder.Bind(element.Content, context);
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 数据绑定系统
|
||||||
|
|
||||||
|
**2.1 数据绑定机制**
|
||||||
|
|
||||||
|
- **支持的绑定语法**:
|
||||||
|
- `${propertyName}` - 基本属性绑定
|
||||||
|
- `${object.property}` - 对象属性绑定
|
||||||
|
- `${list[index]}` - 列表索引访问
|
||||||
|
- `${function(param)}` - 函数调用(如日期格式化)
|
||||||
|
|
||||||
|
**2.2 数据绑定实现**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class DataBinder : IDataBinder
|
||||||
|
{
|
||||||
|
public string Bind(string template, ReportContext context)
|
||||||
|
{
|
||||||
|
// 使用正则表达式匹配绑定表达式
|
||||||
|
var pattern = @"\$\{([^\}]+)\}";
|
||||||
|
return Regex.Replace(template, pattern, match =>
|
||||||
|
{
|
||||||
|
var expression = match.Groups[1].Value;
|
||||||
|
return EvaluateExpression(expression, context);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private string EvaluateExpression(string expression, ReportContext context)
|
||||||
|
{
|
||||||
|
// 解析表达式并获取值
|
||||||
|
if (expression.Contains("."))
|
||||||
|
{
|
||||||
|
// 处理对象属性
|
||||||
|
var parts = expression.Split('.');
|
||||||
|
var obj = context.GetType().GetProperty(parts[0])?.GetValue(context);
|
||||||
|
return obj?.GetType().GetProperty(parts[1])?.GetValue(obj)?.ToString() ?? string.Empty;
|
||||||
|
}
|
||||||
|
else if (expression.Contains("["))
|
||||||
|
{
|
||||||
|
// 处理列表索引
|
||||||
|
var index = int.Parse(expression.Split('[')[1].TrimEnd(']'));
|
||||||
|
return context.Images.Count > index ? "Image" : string.Empty;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 处理基本属性
|
||||||
|
return context.GetType().GetProperty(expression)?.GetValue(context)?.ToString() ?? string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 自动排版功能
|
||||||
|
|
||||||
|
**3.1 布局引擎设计**
|
||||||
|
|
||||||
|
- **核心功能**:
|
||||||
|
- **页面分隔**: 当内容超出一页时自动创建新页
|
||||||
|
- **元素定位**: 根据模板定义计算元素在页面上的精确位置
|
||||||
|
- **尺寸计算**: 自动调整元素大小以适应内容
|
||||||
|
- **响应式布局**: 根据页面尺寸动态调整元素位置
|
||||||
|
|
||||||
|
**3.2 排版服务实现**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class ImageLayoutService
|
||||||
|
{
|
||||||
|
public LayoutResult CalculateLayout(ReportTemplate template, ReportContext context)
|
||||||
|
{
|
||||||
|
var result = new LayoutResult();
|
||||||
|
var currentPage = 0;
|
||||||
|
var currentY = template.Document.Margins.Top;
|
||||||
|
|
||||||
|
foreach (var page in template.Pages)
|
||||||
|
{
|
||||||
|
foreach (var element in page.Elements)
|
||||||
|
{
|
||||||
|
// 计算元素位置
|
||||||
|
var position = new Point(
|
||||||
|
template.Document.Margins.Left + element.Position[0],
|
||||||
|
currentY + element.Position[1]
|
||||||
|
);
|
||||||
|
|
||||||
|
// 计算元素尺寸
|
||||||
|
var size = new Size(element.Size[0], element.Size[1]);
|
||||||
|
|
||||||
|
// 检查是否需要换页
|
||||||
|
if (position.Y + size.Height > PageSize.A4.Height - template.Document.Margins.Bottom)
|
||||||
|
{
|
||||||
|
currentPage++;
|
||||||
|
currentY = template.Document.Margins.Top;
|
||||||
|
position = new Point(
|
||||||
|
template.Document.Margins.Left + element.Position[0],
|
||||||
|
currentY + element.Position[1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加到布局结果
|
||||||
|
result.Elements.Add(new LayoutElement
|
||||||
|
{
|
||||||
|
Page = currentPage,
|
||||||
|
Element = element,
|
||||||
|
Position = position,
|
||||||
|
Size = size
|
||||||
|
});
|
||||||
|
|
||||||
|
// 更新当前Y位置
|
||||||
|
currentY = position.Y + size.Height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 图表嵌入实现
|
||||||
|
|
||||||
|
**4.1 WPF图表转PDF图像**
|
||||||
|
|
||||||
|
- **实现方案**:
|
||||||
|
- 使用`RenderTargetBitmap`将WPF控件渲染为位图
|
||||||
|
- 支持高质量图像输出(300 DPI)
|
||||||
|
- 提供图像压缩选项,平衡质量与文件大小
|
||||||
|
|
||||||
|
**4.2 图像转换服务**
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public static class ImageExtensions
|
||||||
|
{
|
||||||
|
public static byte[] ToPdfImage(this ImageSource image, double width, double height)
|
||||||
|
{
|
||||||
|
var renderTarget = new RenderTargetBitmap(
|
||||||
|
(int)width, (int)height,
|
||||||
|
96, 96, PixelFormats.Pbgra32);
|
||||||
|
|
||||||
|
renderTarget.Render(image);
|
||||||
|
|
||||||
|
using (var stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
var encoder = new PngBitmapEncoder();
|
||||||
|
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
|
||||||
|
encoder.Save(stream);
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] ToPdfImage(this FrameworkElement element, double width, double height)
|
||||||
|
{
|
||||||
|
var renderTarget = new RenderTargetBitmap(
|
||||||
|
(int)width, (int)height,
|
||||||
|
96, 96, PixelFormats.Pbgra32);
|
||||||
|
|
||||||
|
renderTarget.Render(element);
|
||||||
|
|
||||||
|
using (var stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
var encoder = new PngBitmapEncoder();
|
||||||
|
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
|
||||||
|
encoder.Save(stream);
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 三、PDF生成核心流程
|
||||||
|
|
||||||
|
### 1. 生成步骤
|
||||||
|
|
||||||
|
1. **加载模板**: 从Templates目录加载JSON模板
|
||||||
|
2. **解析上下文**: 将MeasurementData和图片列表转换为ReportContext
|
||||||
|
3. **数据绑定**: 将上下文数据绑定到模板中的占位符
|
||||||
|
4. **计算布局**: 确定每个元素在PDF页面上的精确位置
|
||||||
|
5. **生成PDF**: 使用iTextSharp绘制内容到PDF文档
|
||||||
|
6. **输出结果**: 返回MemoryStream或保存为文件
|
||||||
|
|
||||||
|
### 2. 核心生成服务
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
public class PdfGenerationService
|
||||||
|
{
|
||||||
|
public MemoryStream GeneratePdf(ReportContext context, string templatePath)
|
||||||
|
{
|
||||||
|
// 1. 加载模板
|
||||||
|
var templateEngine = new TemplateEngine();
|
||||||
|
var template = templateEngine.LoadTemplate(templatePath);
|
||||||
|
|
||||||
|
// 2. 解析模板元素
|
||||||
|
var elements = templateEngine.ParseTemplate(template, context);
|
||||||
|
|
||||||
|
// 3. 计算布局
|
||||||
|
var layoutService = new ImageLayoutService();
|
||||||
|
var layout = layoutService.CalculateLayout(template, context);
|
||||||
|
|
||||||
|
// 4. 创建PDF文档
|
||||||
|
var document = new Document(PageSize.A4,
|
||||||
|
template.Document.Margins.Left,
|
||||||
|
template.Document.Margins.Right,
|
||||||
|
template.Document.Margins.Top,
|
||||||
|
template.Document.Margins.Bottom);
|
||||||
|
|
||||||
|
var stream = new MemoryStream();
|
||||||
|
var writer = PdfWriter.GetInstance(document, stream);
|
||||||
|
document.Open();
|
||||||
|
|
||||||
|
// 5. 绘制内容
|
||||||
|
DrawContent(document, layout, context);
|
||||||
|
|
||||||
|
// 6. 关闭文档
|
||||||
|
document.Close();
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawContent(Document document, LayoutResult layout, ReportContext context)
|
||||||
|
{
|
||||||
|
// 实现内容绘制逻辑
|
||||||
|
foreach (var element in layout.Elements)
|
||||||
|
{
|
||||||
|
switch (element.Element.Type)
|
||||||
|
{
|
||||||
|
case "text":
|
||||||
|
DrawText(document, element);
|
||||||
|
break;
|
||||||
|
case "image":
|
||||||
|
DrawImage(document, element, context);
|
||||||
|
break;
|
||||||
|
case "table":
|
||||||
|
DrawTable(document, element, context);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawText(Document document, LayoutElement element)
|
||||||
|
{
|
||||||
|
var paragraph = new Paragraph(element.Element.Content);
|
||||||
|
paragraph.SetLocation(element.Position.X, document.PageSize.Height - element.Position.Y);
|
||||||
|
document.Add(paragraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawImage(Document document, LayoutElement element, ReportContext context)
|
||||||
|
{
|
||||||
|
// 获取图像数据
|
||||||
|
var imageData = context.Images.FirstOrDefault();
|
||||||
|
if (imageData == null) return;
|
||||||
|
|
||||||
|
// 创建iTextSharp图像对象
|
||||||
|
var image = Image.GetInstance(imageData);
|
||||||
|
image.SetAbsolutePosition(element.Position.X, document.PageSize.Height - element.Position.Y - element.Size.Height);
|
||||||
|
image.ScaleToFit(element.Size.Width, element.Size.Height);
|
||||||
|
|
||||||
|
document.Add(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawTable(Document document, LayoutElement element, ReportContext context)
|
||||||
|
{
|
||||||
|
// 创建表格
|
||||||
|
var table = new PdfPTable(3); // 假设3列
|
||||||
|
table.WidthPercentage = 100;
|
||||||
|
|
||||||
|
// 添加表头
|
||||||
|
table.AddCell(new PdfPCell(new Phrase("参数", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD))));
|
||||||
|
table.AddCell(new PdfPCell(new Phrase("测量值", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD))));
|
||||||
|
table.AddCell(new PdfPCell(new Phrase("标准值", new Font(Font.FontFamily.HELVETICA, 12, Font.BOLD))));
|
||||||
|
|
||||||
|
// 添加数据行
|
||||||
|
foreach (var measurement in context.Measurements)
|
||||||
|
{
|
||||||
|
table.AddCell(new PdfPCell(new Phrase(measurement.Parameter)));
|
||||||
|
table.AddCell(new PdfPCell(new Phrase(measurement.Value.ToString())));
|
||||||
|
table.AddCell(new PdfPCell(new Phrase(measurement.StandardValue.ToString())));
|
||||||
|
}
|
||||||
|
|
||||||
|
document.Add(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 四、最佳实践与建议
|
||||||
|
|
||||||
|
### 1. 性能优化
|
||||||
|
|
||||||
|
- **图像处理**: 对大尺寸图像进行**压缩和缩放**,避免PDF文件过大
|
||||||
|
- **内存管理**: 使用`using`语句确保资源及时释放
|
||||||
|
- **批量处理**: 对大量数据采用**分批处理**策略,避免UI冻结
|
||||||
|
|
||||||
|
### 2. 错误处理
|
||||||
|
|
||||||
|
- 实现**完善的异常捕获**机制,特别是图像转换和PDF生成环节
|
||||||
|
- 提供**友好的错误提示**,便于问题排查
|
||||||
|
- 添加**日志记录**功能,跟踪报告生成过程
|
||||||
|
|
||||||
|
### 3. 样式管理
|
||||||
|
|
||||||
|
- 创建**样式库**,统一字体、颜色、间距等
|
||||||
|
- 支持**主题切换**,适应不同客户的品牌要求
|
||||||
|
- 确保**打印友好**,考虑黑白打印时的可读性
|
||||||
|
|
||||||
|
### 4. 扩展性考虑
|
||||||
|
|
||||||
|
- **插件架构**: 设计可扩展的插件系统,便于添加新功能
|
||||||
|
- **多格式输出**: 基于相同架构,扩展支持Word、Excel等格式输出
|
||||||
|
- **云服务集成**: 考虑与云存储集成,自动上传生成的报告
|
||||||
|
|
||||||
|
通过以上设计,XP.ReportEngine将成为一个**灵活、高效、可维护**的PDF报告生成系统,满足工业CT检测报告的专业需求,同时保持系统的扩展性和易用性。
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using Prism.Ioc;
|
||||||
|
using Prism.Modularity;
|
||||||
|
using XP.ReportEngine.Views;
|
||||||
|
|
||||||
|
namespace XP.ReportEngine
|
||||||
|
{
|
||||||
|
public class ReportEngineModule : IModule
|
||||||
|
{
|
||||||
|
public void OnInitialized(IContainerProvider containerProvider)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RegisterTypes(IContainerRegistry containerRegistry)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
using Prism.Commands;
|
||||||
|
using Prism.Mvvm;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace XP.ReportEngine.ViewModels
|
||||||
|
{
|
||||||
|
public class ViewAViewModel : BindableBase
|
||||||
|
{
|
||||||
|
private string _message;
|
||||||
|
public string Message
|
||||||
|
{
|
||||||
|
get { return _message; }
|
||||||
|
set { SetProperty(ref _message, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ViewAViewModel()
|
||||||
|
{
|
||||||
|
Message = "View A from your Prism Module";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<UserControl x:Class="XP.ReportEngine.Views.ViewA"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:XP.ReportEngine.Views"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="300" d:DesignWidth="300"
|
||||||
|
xmlns:prism="http://prismlibrary.com/"
|
||||||
|
prism:ViewModelLocator.AutoWireViewModel="True" >
|
||||||
|
<Grid>
|
||||||
|
<TextBlock Text="{Binding Message}"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace XP.ReportEngine.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ViewA.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ViewA : UserControl
|
||||||
|
{
|
||||||
|
public ViewA()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0-windows7.0</TargetFramework>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Prism.Wpf" Version="9.0.537" />
|
||||||
|
<PackageReference Include="Telerik.UI.for.Wpf.NetCore.Xaml" Version="2024.1.408" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\XP.Common\XP.Common.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Documents\" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
+16
-2
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 18
|
||||||
VisualStudioVersion = 17.14.36811.4
|
VisualStudioVersion = 18.5.11723.231 stable
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XplorePlane", "XplorePlane\XplorePlane.csproj", "{07978DB9-4B88-4F42-9054-73992742BD6A}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XplorePlane", "XplorePlane\XplorePlane.csproj", "{07978DB9-4B88-4F42-9054-73992742BD6A}"
|
||||||
EndProject
|
EndProject
|
||||||
@@ -66,6 +66,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "XP.Calibration", "XP.Calibr
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XP.Calibration", "XP.Calibration", "{D4E5F6A7-B8C9-0123-4567-89ABCDEF0123}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "XP.Calibration", "XP.Calibration", "{D4E5F6A7-B8C9-0123-4567-89ABCDEF0123}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "XP.ReportEngine", "XP.ReportEngine\XP.ReportEngine.csproj", "{809A8588-F64C-4738-8827-CFBC59943DBF}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -268,6 +270,18 @@ Global
|
|||||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|Any CPU
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|Any CPU
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|Any CPU
|
{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{809A8588-F64C-4738-8827-CFBC59943DBF}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
Reference in New Issue
Block a user