Files
leaudit-platform-frontend/docs/contract-drafting-solution.md
2025-12-05 00:09:32 +08:00

8.2 KiB
Raw Permalink Blame History

合同起草功能实施方案

功能概述

基于合同模板创建新合同,通过占位符替换和在线编辑实现合同起草。


方案对比

方案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. 实时调用 replaceTextInPageunoReplaceAll 替换占位符
  6. 用户可以继续手动编辑文档
  7. 保存生成的新合同

优点

  • 无需新依赖,复用现有代码
  • 实时预览替换效果
  • 用户可以继续手动编辑
  • 开发速度快
  • 所见即所得

缺点

  • 依赖 Collabora Online 服务
  • 替换逻辑相对简单(基于查找替换)
  • 需要处理异步替换

方案C:混合方案

技术栈

  • 简单模板:使用 CollaboraViewer 实时替换
  • 复杂模板:使用 docxtemplater 服务端生成

工作流程

  1. 模板元数据标记是否为"复杂模板"
  2. 简单模板走方案B流程
  3. 复杂模板走方案A流程

优点

  • 灵活性最高
  • 简单场景快速响应
  • 复杂场景功能完整

缺点

  • 开发成本高
  • 维护两套逻辑

推荐方案:方案BCollaboraViewer 实时替换)

理由

  1. 快速落地:复用现有代码,开发周期短
  2. 用户体验好:所见即所得,实时预览
  3. 灵活性高:替换后用户可以继续编辑
  4. 维护成本低:不引入新依赖

技术细节

占位符约定

使用双花括号格式,便于识别和替换:

{{甲方名称}}
{{甲方地址}}
{{甲方法定代表人}}
{{甲方联系电话}}
{{乙方名称}}
{{乙方地址}}
{{乙方法定代表人}}
{{乙方联系电话}}
{{合同金额}}
{{签订日期}}
{{合同编号}}

替换实现

使用 CollaboraViewer 的 unoReplaceAll 方法:

// 批量替换所有占位符
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 (起草的合同)

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

请求体

{
  "templateId": 123,
  "title": "智慧法务平台采购合同-草稿"
}

响应

{
  "id": 456,
  "filePath": "drafts/contract_456_20250104.docx",
  "title": "智慧法务平台采购合同-草稿",
  "templateId": 123
}

2. 保存占位符值

PUT /api/contracts/draft/:id/placeholders

请求体

{
  "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:预定义字段(推荐)

在模板表中增加字段:

ALTER TABLE contract_templates
ADD COLUMN placeholder_schema JSONB;

示例数据:

{
  "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 作为补充。