This commit is contained in:
2025-12-05 00:09:32 +08:00
parent bb3d22eabf
commit 3d1dbb3f97
214 changed files with 113060 additions and 1232 deletions
+371
View File
@@ -0,0 +1,371 @@
# 合同起草功能实施方案
## 功能概述
基于合同模板创建新合同,通过占位符替换和在线编辑实现合同起草。
---
## 方案对比
### 方案Adocxtemplater + 服务端生成
**技术栈**
- `docxtemplater` - DOCX 模板引擎
- 服务端处理(Node.js
- 生成新文档后上传到 MinIO
**工作流程**
1. 模板中预先定义占位符:`{甲方名称}``{合同金额}`
2. 用户填写表单
3. 服务端使用 docxtemplater 替换占位符
4. 生成新 DOCX 文件
5. 上传到 MinIO
6. 前端加载新文件用 Collabora 展示和编辑
**优点**
- ✅ 模板语法强大(支持循环、条件、表格等)
- ✅ 替换精确可控
- ✅ 可以在服务端验证数据
- ✅ 支持复杂的模板逻辑
**缺点**
- ❌ 需要安装新依赖
- ❌ 需要开发服务端 API
- ❌ 模板需要预先制作占位符
- ❌ 生成→上传→加载流程较长
- ❌ 无法实时预览替换效果
---
### 方案BCollaboraViewer 实时替换(推荐)
**技术栈**
- 现有的 `CollaboraViewer` 组件
- `replaceTextInPage` / `unoReplaceAll` 功能
- Collabora Online 编辑模式
**工作流程**
1. 模板中约定占位符格式:`{{甲方名称}}``{{合同金额}}`
2. 用户点击"起草合同",复制模板文件
3. 在 Collabora 中以编辑模式打开复制的文件
4. 用户填写右侧表单
5. 实时调用 `replaceTextInPage``unoReplaceAll` 替换占位符
6. 用户可以继续手动编辑文档
7. 保存生成的新合同
**优点**
- ✅ 无需新依赖,复用现有代码
- ✅ 实时预览替换效果
- ✅ 用户可以继续手动编辑
- ✅ 开发速度快
- ✅ 所见即所得
**缺点**
- ❌ 依赖 Collabora Online 服务
- ❌ 替换逻辑相对简单(基于查找替换)
- ❌ 需要处理异步替换
---
### 方案C:混合方案
**技术栈**
- 简单模板:使用 CollaboraViewer 实时替换
- 复杂模板:使用 docxtemplater 服务端生成
**工作流程**
1. 模板元数据标记是否为"复杂模板"
2. 简单模板走方案B流程
3. 复杂模板走方案A流程
**优点**
- ✅ 灵活性最高
- ✅ 简单场景快速响应
- ✅ 复杂场景功能完整
**缺点**
- ❌ 开发成本高
- ❌ 维护两套逻辑
---
## 推荐方案:方案BCollaboraViewer 实时替换)
### 理由
1. **快速落地**:复用现有代码,开发周期短
2. **用户体验好**:所见即所得,实时预览
3. **灵活性高**:替换后用户可以继续编辑
4. **维护成本低**:不引入新依赖
### 技术细节
#### 占位符约定
使用双花括号格式,便于识别和替换:
```
{{甲方名称}}
{{甲方地址}}
{{甲方法定代表人}}
{{甲方联系电话}}
{{乙方名称}}
{{乙方地址}}
{{乙方法定代表人}}
{{乙方联系电话}}
{{合同金额}}
{{签订日期}}
{{合同编号}}
```
#### 替换实现
使用 CollaboraViewer 的 `unoReplaceAll` 方法:
```typescript
// 批量替换所有占位符
async function replacePlaceholders(
collaboraRef: CollaboraViewerHandle,
values: Record<string, string>
) {
for (const [key, value] of Object.entries(values)) {
const placeholder = `{{${key}}}`;
await collaboraRef.unoCommands.replaceAll(placeholder, value);
}
}
```
#### 文件复制策略
**选项1:服务端复制**(推荐)
- API: `POST /api/contracts/draft`
- 请求参数: `{ templateId: string }`
- 返回: `{ newFileId: string, newFilePath: string }`
- 服务端将模板文件复制为新文件
**选项2:客户端复制**
- 下载模板文件 Blob
- 重命名后重新上传
- 成本高,不推荐
---
## 数据库设计
### 新增表:`drafted_contracts` (起草的合同)
```sql
CREATE TABLE drafted_contracts (
id SERIAL PRIMARY KEY,
template_id INTEGER REFERENCES contract_templates(id),
file_path TEXT NOT NULL, -- 起草后的文件路径
title TEXT NOT NULL, -- 合同标题
placeholder_values JSONB, -- 占位符填充值
status TEXT DEFAULT 'draft', -- draft | completed | archived
created_by INTEGER REFERENCES auth.users(id),
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
```
---
## API 设计
### 1. 创建起草合同
```
POST /api/contracts/draft
```
**请求体**
```json
{
"templateId": 123,
"title": "智慧法务平台采购合同-草稿"
}
```
**响应**
```json
{
"id": 456,
"filePath": "drafts/contract_456_20250104.docx",
"title": "智慧法务平台采购合同-草稿",
"templateId": 123
}
```
### 2. 保存占位符值
```
PUT /api/contracts/draft/:id/placeholders
```
**请求体**
```json
{
"placeholders": {
"甲方名称": "广东省烟草专卖局",
"合同金额": "500000"
}
}
```
### 3. 完成起草
```
POST /api/contracts/draft/:id/complete
```
将草稿标记为已完成,可选地移动到正式合同目录。
---
## UI/UX 设计
### 页面结构
```
/contract-template/draft/:templateId
├── 左侧(60%):FilePreviewCollabora 编辑模式)
└── 右侧(40%):占位符表单
├── 基本信息
│ ├── 合同标题
│ └── 合同编号
├── 甲方信息
│ ├── 甲方名称
│ ├── 甲方地址
│ ├── 法定代表人
│ └── 联系电话
├── 乙方信息
│ ├── 乙方名称
│ ├── 乙方地址
│ ├── 法定代表人
│ └── 联系电话
├── 合同条款
│ ├── 合同金额
│ ├── 签订日期
│ └── 其他自定义字段
└── 操作按钮
├── 一键替换
├── 保存草稿
└── 完成起草
```
### 交互流程
1. 用户在模板详情页点击"起草合同"
2. 系统复制模板文件,创建草稿记录
3. 跳转到起草页面
4. 左侧加载文档(Collabora 编辑模式)
5. 右侧显示占位符表单(从模板中提取或预定义)
6. 用户填写表单
7. 点击"一键替换"批量替换所有占位符
8. 用户可以继续手动编辑文档
9. 点击"保存草稿"保存当前状态
10. 点击"完成起草"将合同标记为完成
---
## 占位符提取方案
### 方案1:预定义字段(推荐)
在模板表中增加字段:
```sql
ALTER TABLE contract_templates
ADD COLUMN placeholder_schema JSONB;
```
示例数据:
```json
{
"fields": [
{
"key": "甲方名称",
"label": "甲方名称",
"type": "text",
"required": true,
"group": "甲方信息"
},
{
"key": "合同金额",
"label": "合同金额(元)",
"type": "number",
"required": true,
"group": "合同条款"
},
{
"key": "签订日期",
"label": "签订日期",
"type": "date",
"required": true,
"group": "合同条款"
}
]
}
```
### 方案2:动态提取
从 DOCX 文件中提取所有 `{{xxx}}` 占位符:
- 需要解析 DOCX 文件
- 服务端实现
- 成本较高
---
## 技术风险与应对
### 风险1Collabora 替换性能
**风险**:多个占位符替换可能耗时较长
**应对**
- 使用 `unoReplaceAll` 而不是逐个替换
- 显示替换进度提示
- 考虑批量替换 API
### 风险2:并发编辑冲突
**风险**:用户同时编辑和替换可能冲突
**应对**
- 替换前提示用户
- 替换时禁用编辑
- 使用防抖避免频繁替换
### 风险3:占位符未完全替换
**风险**:用户忘记填写某些字段
**应对**
- 完成前检查是否还有 `{{}}` 占位符
- 高亮显示未替换的占位符
- 必填字段验证
---
## 扩展功能(可选)
1. **模板变量管理**:管理员可以配置模板的占位符字段
2. **历史记录**:记录每次替换的历史
3. **模板版本**:支持模板版本管理
4. **审批流程**:起草完成后进入审批流程
5. **电子签名**:集成电子签名功能
---
## 总结
推荐使用 **方案BCollaboraViewer 实时替换)**,理由:
- 开发成本低,复用现有代码
- 用户体验好,所见即所得
- 灵活性高,支持后续手动编辑
- 维护成本低,不引入新依赖
如果未来需要支持复杂模板逻辑(循环、条件等),可以再引入 docxtemplater 作为补充。