Files
flowable_management/base-fast/Word模板配置说明.md
2026-01-31 15:51:23 +08:00

244 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Word合同模板配置说明
## 📋 问题原因
Word模板中的动态列表数据渲染失败主要原因是
1. 没有配置 `LoopRowTableRenderPolicy` 循环行渲染策略
2. 数据格式不匹配直接传JSONArray而不是List<Map>
3. 模板语法使用不正确
## ✅ 解决方案
### 1. Word模板正确语法
在Word模板的表格中需要使用以下格式
```
┌─────────┬──────────┬──────────┬──────┬──────┬──────────┬──────────┬──────┐
│ 序号 │ 产品名称 │ 型号 │ 数量 │ 单位 │ 单价(元) │ 总价(元) │ 备注 │
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{#rows}}│ │ │ │ │ │ │ │
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{seq}} │{{materialName}}│{{materialSpec}}│{{qty}}│{{unitName}}│{{salePrice}}│{{amount}}│{{remark}}│
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{/rows}}│ │ │ │ │ │ │ │
└─────────┴──────────┴──────────┴──────┴──────┴──────────┴──────────┴──────┘
```
**重要说明**
- `{{#rows}}` 必须单独占一行(表格的一行)
- 数据行包含所有字段:`{{seq}}`, `{{materialName}}`
- `{{/rows}}` 必须单独占一行(表格的一行)
- 这三行构成一个完整的循环结构
### 2. 模板文件位置
将模板文件放在以下位置之一:
**方式1放在resources目录推荐**
```
src/main/resources/templates/contract_template.docx
```
**方式2使用绝对路径**
```java
/Users/mima0000/Desktop/合同.docx
```
### 3. 后端代码关键点
#### 3.1 配置循环行策略
```java
LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy();
Configure config = Configure.builder()
.bind("rows", policy) // 绑定rows标签
.build();
```
#### 3.2 数据格式转换
```java
// 错误方式 ❌
dataMap.put("rows", JSONArray.parseArray(materialJson));
// 正确方式 ✅
List<Map<String, Object>> rowsList = new ArrayList<>();
for (int i = 0; i < materialArray.size(); i++) {
JSONObject item = materialArray.getJSONObject(i);
Map<String, Object> rowData = new HashMap<>();
rowData.put("seq", i + 1);
rowData.put("materialName", item.getString("materialName"));
// ... 其他字段
rowsList.add(rowData);
}
dataMap.put("rows", rowsList);
```
#### 3.3 使用配置渲染
```java
XWPFTemplate template = XWPFTemplate.compile(templateStream, config)
.render(dataMap);
```
## 🎯 完整的Word模板示例
### 模板结构
```
服务合同
需方:{{clientName}} 合同编号:{{contractCode}}
供方:上海诺力智能科技有限公司 签订时间:{{effectiveDate}}
一、产品明细单
┌─────────┬──────────┬──────────┬──────┬──────┬──────────┬──────────┬──────┐
│ 序号 │ 产品名称 │ 型号 │ 数量 │ 单位 │ 单价(元) │ 总价(元) │ 备注 │
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{#rows}}│ │ │ │ │ │ │ │
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{seq}} │{{materialName}}│{{materialSpec}}│{{qty}}│{{unitName}}│{{salePrice}}│{{amount}}│{{remark}}│
├─────────┼──────────┼──────────┼──────┼──────┼──────────┼──────────┼──────┤
│{{/rows}}│ │ │ │ │ │ │ │
├─────────┴──────────┴──────────┴──────┴──────┴──────────┼──────────┼──────┤
│ 共计: │{{totalPrice}}│ │
└──────────────────────────────────────────────┴──────────┴──────┘
二、质量要求:{{qc}}
三、交货时间、地点:货期:{{delivery}},交货地:{{place}}
四、运输方式:{{transport}}
五、包装标准:{{packaging}}
六、结算方式:{{pay}},付款方式:{{payment}}
七、违约责任:{{breach}}
八、解决合同纠纷的方式:{{solve_dispute}}
九、其它约定事项:{{supplement}}
┌──────────────────────────────┬──────────────────────────────┐
│ 需方: │ 供方: │
├──────────────────────────────┼──────────────────────────────┤
│单位名称:{{clientName}} │单位名称:上海诺力智能科技有限公司│
│地址:{{clientAdd}} │地址:上海青浦区徐泾镇... │
│委托代理人:{{juridicalPerson}}│委托代理人: │
│电话:{{clientTel}} │电话: │
│传真:{{clientFax}} │传真: │
│开户银行:{{clientBank}} │开户银行:招商银行虹桥支行 │
│帐号:{{clientCard}} │帐号12191702501091 │
└──────────────────────────────┴──────────────────────────────┘
```
## 📝 字段说明
### 基本信息字段
| 字段名 | 说明 | 示例 |
|--------|------|------|
| clientName | 客户名称 | XX公司 |
| contractCode | 合同编号 | HT20250101 |
| effectiveDate | 生效日期 | 2025年01月01日 |
| totalPrice | 总价 | 100000.00 |
### 列表字段rows
| 字段名 | 说明 | 示例 |
|--------|------|------|
| seq | 序号 | 1, 2, 3... |
| materialName | 产品名称 | 叉车 |
| materialSpec | 型号 | CPD15 |
| qty | 数量 | 10 |
| unitName | 单位 | 台 |
| salePrice | 单价 | 50000.00 |
| amount | 总价 | 500000.00 |
| remark | 备注 | 含税 |
### 合同条款字段
| 字段名 | 说明 |
|--------|------|
| qc | 质量要求 |
| delivery | 交货时间 |
| place | 交货地点 |
| transport | 运输方式 |
| packaging | 包装标准 |
| pay | 结算方式 |
| payment | 付款方式 |
| breach | 违约责任 |
| solve_dispute | 解决纠纷方式 |
| supplement | 其它约定 |
### 客户信息字段
| 字段名 | 说明 |
|--------|------|
| clientAdd | 客户地址 |
| juridicalPerson | 法人代表 |
| clientTel | 客户电话 |
| clientFax | 客户传真 |
| clientBank | 客户开户行 |
| clientCard | 客户账号 |
## 🔧 常见问题
### 1. 列表数据不显示
**原因**:没有配置 `LoopRowTableRenderPolicy`
**解决**:在代码中添加配置
```java
Configure config = Configure.builder()
.bind("rows", policy)
.build();
```
### 2. 列表只显示一行
**原因**:模板中 `{{#rows}}``{{/rows}}` 没有单独占一行
**解决**:确保循环标签单独占表格的一行
### 3. 数据格式错误
**原因**直接传JSONArray而不是List<Map>
**解决**转换为List<Map<String, Object>>格式
### 4. 中文乱码
**原因**:文件名编码问题
**解决**使用URLEncoder编码文件名
```java
String fileName = java.net.URLEncoder.encode("合同.docx", "UTF-8");
```
## 🎉 测试步骤
1. **准备模板文件**
- 按照上述格式创建Word模板
- 保存为 `contract_template.docx`
- 放到 `src/main/resources/templates/` 目录
2. **测试导出**
- 访问:`GET /flow/contract/export?contractId=1`
- 检查下载的Word文档
- 验证列表数据是否正确显示
3. **验证数据**
- 打开导出的Word文档
- 检查产品明细表是否有多行数据
- 检查所有字段是否正确填充
## 💡 最佳实践
1. **模板管理**
- 将模板文件放在resources目录
- 使用版本控制管理模板
- 为不同类型合同创建不同模板
2. **错误处理**
- 添加try-catch捕获异常
- 记录详细的错误日志
- 返回友好的错误提示
3. **性能优化**
- 缓存模板对象
- 使用流式处理大文件
- 异步处理导出任务
## 📚 参考资料
- poi-tl官方文档http://deepoove.com/poi-tl/
- 循环行表格http://deepoove.com/poi-tl/#_loop-row-table
- GitHub示例https://github.com/Sayi/poi-tl
---
**更新时间**: 2026-01-30
**版本**: v1.0