# 报表打印系统架构与使用说明

本文档详细介绍了当前报表打印系统的架构设计、核心组件及其使用方法。

## 1. 架构设计概览

本系统采用 **Provider 模式** 与 **流式任务构建 (Builder Pattern)** 相结合的设计，旨在实现报表生成的解耦、灵活配置与高扩展性。

### 核心组件

1. **IReportDataProvider (报表数据提供者)**
    * **职责**：定义单一报表的元数据（模版、标题、类型）和数据准备逻辑。
    * **优势**：将业务逻辑从 Service 层剥离，每个报表对应一个 Provider，互不干扰，易于维护。
    * **关键方法**：
        * `getReportType()`: 唯一标识（如 `APPLICATION_FORM`）。
        * `prepareData(params)`: 准备模版所需的数据。
        * `getCoverProviderType()`: 定义关联的封面类型（支持自动封面）。

2. **ReportPrintJob (打印任务构建器)**
    * **职责**：负责组装打印任务。它像一条流水线，可以按需添加封面、报表片段、设置公章/水印等。
    * **特性**：
        * **链式调用**：`createJob().addCover().addBatch().render()`。
        * **混合布局**：自动处理横向 (Landscape) 与纵向 (Portrait) 页面的合并。
        * **上下文注入**：支持注入 CompanyId 用于公章/水印生成。

3. **ReportRenderService (渲染服务)**
    * **职责**：底层的渲染引擎。
    * **功能**：
        * 解析 Velocity 模版。
        * 调用 Gotenberg 进行 HTML 转 PDF。
        * 处理水印 (Watermark) 和电子公章 (Seal)。
        * 合并多个 PDF 片段。

## 2. 现有报表类型

目前系统已实现的 Provider 如下：

| 报表类型 (Type) | Provider 类 | 描述 |
| :--- | :--- | :--- |
| `APPLICATION_FORM` | `DriverApplicationFormProvider` | 驾驶员应聘申请表 |
| `ID_CARD_SCAN` | `IdCardScanProvider` | 身份证扫描件 |
| `DRIVER_LICENSE_COPY` | `DriverLicenseCopyProvider` | 驾驶证复印件 |
| `QUALIFICATION_CERTIFICATE_COPY` | `QualificationCertificateCopyProvider` | 从业资格证复印件 |
| `QUALIFICATION_REVIEW` | `QualificationReviewProvider` | 资格审查及技能考核登记表 |
| `ACCIDENT_RECORD` | `AccidentRecordProvider` | 安全行车事故记录 (横向) |
| `VIOLATION_RECORD` | `ViolationRecordProvider` | 违章记录 (横向) |
| `ANNUAL_ASSESSMENT_RECORD` | `AnnualAssessmentRecordProvider` | 年度考核记录 |
| `MEDICAL_EXAMINATION_REPORT` | `MedicalExaminationReportProvider` | 体检报告 |
| `REWARD_PUNISHMENT_RECORD` | `RewardPunishmentRecordProvider` | 奖惩记录表 |

## 3. 使用方法 (开发指南)

### 3.1 创建新报表

1. **定义 Provider**：
   新建一个类实现 `IReportDataProvider`，并注册为 Spring Bean (`@Component`)。
   ```java
   @Component
   public class MyReportProvider implements IReportDataProvider {
       @Override
       public String getReportType() { return "MY_REPORT"; }
       
       @Override
       public String getTemplateCode() { return "templates/my/report.html.vm"; }
       
       @Override
       public Map<String, Object> prepareData(Map<String, Object> params) {
           // 准备数据...
           return Map.of("data", "value");
       }
   }
   ```

2. **创建 Velocity 模版**：
   在 `src/main/resources/templates/my/report.html.vm` 中编写 HTML。

### 3.2 调用打印服务

在业务 Service 中注入 `ReportRenderService` 和 `providerMap`，然后使用链式调用：

#### 场景 A：单个报表打印 (带自动封面)

```java
public byte[] printMyReport(List<String> ids) {
    // 1. 获取 Provider
    IReportDataProvider provider = providerMap.get("MY_REPORT");

    // 2. 构建任务
    return reportRenderService.createJob(providerMap::get) // 传入查找器以支持自动封面
            .withCompanyId(companyId)       // 设置公司ID（用于公章）
            .addCover(provider)             // 自动添加关联封面
            .addBatch(provider, ids, "id")  // 批量添加报表内容
            .useSeal(true)                  // 启用公章
            .render();                      // 渲染并返回 PDF
}
```

#### 场景 B：一键打印 (多报表合并)

```java
public byte[] printAll(List<String> driverIds, List<String> types) {
    var job = reportRenderService.createJob(providerMap::get)
            .withCompanyId(companyId)
            .useSeal(false); // 全局公章开关

    for (String id : driverIds) {
        // 1. 为每个驾驶员添加一个独立封面
        job.addCover("COMMON_COVER", Map.of(
                "title", "驾驶员档案",
                "subtitle", "张三"
        ));

        // 2. 依次添加选中的报表
        for (String type : types) {
            job.add(providerMap.get(type), Map.of("driverId", id));
        }
    }
    return job.render();
}
```

### 3.3 进阶配置

* **横向布局**：在 Provider 中重写 `isLandscape()` 返回 `true`，或者在 Job 中调用 `.isLandscape(true)` (通常由 Provider
  决定)。
* **自定义封面**：Provider 可重写 `getCoverProviderType()` 指定特定封面，或重写 `getCoverData()` 自定义封面参数。
* **水印控制**：`job.useWatermark(true).watermarkText("自定义水印")`。

## 4. 模版工具支持

模版中内置了 `$tool` 工具类 (`ReportVelocityTool`)，提供常用功能：

* `$tool.getDictLabel('type', value)`: 字典翻译
* `$tool.formatDate(date, 'yyyy-MM-dd')`: 日期格式化
* `$tool.getOssUrls(urlStr)`: 解析 OSS 图片链接
* `$tool.numberToChinese(num)`: 数字转中文大写

---
*文档生成日期：2026-03-01*
