Files
leaudit-platform-backend/docs/合同模板搜索合同起草/合同模板上传与地区隔离改造方案.md
T

11 KiB
Raw Blame History

合同模板上传与地区隔离改造方案

1. 背景

当前合同模板模块已具备以下只读能力:

  • /api/v3/contract-templates/categories
  • /api/v3/contract-templates
  • /api/v3/contract-templates/search
  • /api/v3/contract-templates/{id}

当前实现可以支撑模板分类、列表、搜索、详情展示,但还不具备正式的模板管理上传能力。现阶段新增需求包括:

  • /contract-template/list 页面支持上传合同模板
  • 新模板必须存入 leaudit_platform 主库,不再依赖旧项目库
  • 模板数据需要支持地区区分
  • 模板数据需要支持完整审计字段
  • 模板数据需要支持软删除
  • 前端与后端需统一按当前 LeAudit/FastAPI 风格实现

本方案仅覆盖“合同模板管理与上传”,不扩展“合同起草”独立业务模块。

2. 现状问题

2.1 数据表不足

当前 contract_templates 仅包含:

  • template_code
  • title
  • category_id
  • description
  • file_path
  • file_format
  • pdf_file_path
  • is_featured
  • created_at
  • updated_at

存在以下问题:

  • 没有 region,无法做地区隔离
  • 没有 created_by / updated_by,无法追踪操作者
  • 没有 deleted_at,无法软删除
  • 没有 original_file_name / mime_type / file_size,无法完整表达上传文件元数据
  • 当前唯一约束仅为 template_code 全局唯一,不适合多地区模板管理

2.2 读接口缺少统一数据范围控制

当前合同模板读接口没有套用平台现有“按用户地区可见”的规则,无法满足:

  • 省级管理员查看全部或指定地区
  • 地市管理员仅查看本地区及公共模板
  • 非管理用户限制可见范围

2.3 OSS 路径未带地区

当前 BuildContractTemplateKey() 只按:

  • 分类
  • 模板编码
  • 文件角色

生成路径,未带 region,多地区下会出现路径命名冲突与后期归档困难。

2.4 权限不足

当前仅具备读权限:

  • contract_template:list:read
  • contract_template:search:read
  • contract_template:detail:read

尚未具备:

  • 上传创建权限
  • 编辑权限
  • 删除权限

3. 设计目标

本次改造目标如下:

  1. 为合同模板模块补齐上传能力
  2. 按地区隔离模板数据
  3. 支持审计字段与软删除
  4. 保持与现有 govdoc / document 模块相同的权限和地区控制风格
  5. 新上传模板统一走新 OSS 路径规范
  6. 不影响现有搜索、列表、详情页面的继续使用

4. 数据模型设计

4.1 contract_categories

分类暂不做地区化,保留为全局字典表,但补齐审计与软删除字段。

建议字段:

  • id BIGSERIAL/SERIAL PRIMARY KEY
  • name VARCHAR(100) NOT NULL
  • icon VARCHAR(100) NULL
  • description TEXT NULL
  • sort_order INTEGER NOT NULL DEFAULT 0
  • created_by BIGINT NULL
  • created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
  • updated_by BIGINT NULL
  • updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
  • deleted_at TIMESTAMPTZ NULL

索引建议:

  • UNIQUE INDEX uq_contract_categories_name_active ON contract_categories(name) WHERE deleted_at IS NULL
  • INDEX idx_contract_categories_sort_active ON contract_categories(sort_order) WHERE deleted_at IS NULL

4.2 contract_templates

模板表补齐地区、上传元数据、审计字段、软删除字段。

建议字段:

  • id BIGSERIAL PRIMARY KEY
  • template_code VARCHAR(50) NOT NULL
  • title VARCHAR(200) NOT NULL
  • category_id INTEGER NOT NULL REFERENCES contract_categories(id)
  • region VARCHAR(50) NOT NULL DEFAULT '省级'
  • description TEXT NULL
  • file_path VARCHAR(500) NULL
  • pdf_file_path VARCHAR(500) NULL
  • file_format VARCHAR(10) NOT NULL
  • original_file_name VARCHAR(500) NOT NULL DEFAULT ''
  • mime_type VARCHAR(200) NULL
  • file_size BIGINT NOT NULL DEFAULT 0
  • pdf_file_size BIGINT NULL
  • is_featured BOOLEAN NOT NULL DEFAULT FALSE
  • created_by BIGINT NULL
  • created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
  • updated_by BIGINT NULL
  • updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
  • deleted_at TIMESTAMPTZ NULL

索引建议:

  • UNIQUE INDEX uq_contract_templates_region_code_active ON contract_templates(region, template_code) WHERE deleted_at IS NULL
  • INDEX idx_contract_templates_region_active ON contract_templates(region) WHERE deleted_at IS NULL
  • INDEX idx_contract_templates_category_active ON contract_templates(category_id) WHERE deleted_at IS NULL
  • INDEX idx_contract_templates_updated_active ON contract_templates(updated_at DESC) WHERE deleted_at IS NULL

4.3 软删除策略

所有列表、搜索、详情查询统一增加:

  • deleted_at IS NULL

删除接口只做:

  • deleted_at = NOW()
  • updated_at = NOW()
  • updated_by = 当前用户

本期不执行物理删除 OSS 对象,避免误删无法恢复。

5. 地区隔离策略

5.1 用户上下文来源

复用现有用户上下文判断逻辑,基于:

  • sso_users.area
  • 用户角色 super_admin / provincial_admin / admin / 普通用户

参考现有实现:

  • documentServiceImpl._getCurrentUserContext
  • documentServiceImpl._buildDocumentScopeFilters
  • govdocServiceImpl._resolve_upload_region

5.2 模板可见性规则

采用“省级公共模板 + 地区私有模板”的一层可见性模型:

  • region = '省级':全局公共模板
  • region = 用户地区:当前地区私有模板

读取规则:

  • super_admin / provincial_admin
    • 默认可查看全部地区
    • 支持显式传 region 做筛选
  • admin
    • 默认可查看 ('省级', 自己地区) 模板
    • 若传入其他地区参数,返回空或直接拒绝
  • 普通用户
    • 默认可查看 ('省级', 自己地区) 模板
    • 不允许跨地区筛选

5.3 上传地区规则

上传接口中,region 使用以下规则解析:

  • super_admin / provincial_admin
    • 可选择上传到任意地区,含 省级
  • admin
    • 只能上传到自己地区
  • 普通用户
    • 默认不开放上传权限

5.4 为什么本期不做“地区模板覆盖省级模板”

本期不做同 template_code 的覆盖优先级逻辑,原因:

  • 列表/搜索会出现同编码多条模板
  • 详情页需要增加“实际命中版本”优先级
  • 后续还会影响起草、下载、预览引用

本期先做“地区隔离 + 独立模板记录”,后续若业务明确需要,再做二期“本地覆盖省级模板”。

6. OSS 存储设计

6.1 新路径规范

建议合同模板 OSS key 改为:

contract-templates/{region}/{category}/{template_code}/{role}__{filename}

例如:

  • contract-templates/省级/房屋租赁/HT-RL-001/source__房屋租赁合同.docx
  • contract-templates/梅州/房屋租赁/HT-RL-001/preview__房屋租赁合同.pdf

6.2 文件角色

  • 主模板文件:source
  • 预览 PDF 文件:preview

6.3 老数据策略

老数据短期不强制迁移到新地区路径:

  • 已有历史数据继续可读
  • 新上传统一走新路径

后续若需要统一整洁,再单独执行历史迁移脚本,将存量模板迁到 contract-templates/省级/...

7. 接口设计

7.1 新增接口

7.1.1 上传模板

  • POST /api/v3/contract-templates
  • 权限:contract_template:create
  • Content-Typemultipart/form-data

表单字段:

  • title: str
  • template_code: str
  • category_id: int
  • region: str
  • description: str | None
  • is_featured: bool
  • file: UploadFile
  • pdf_file: UploadFile | None

返回:

  • 模板基础信息
  • 文件路径
  • 地区信息
  • 审计时间

7.1.2 更新模板

  • PUT /api/v3/contract-templates/{id}
  • 权限:contract_template:update

本期先可只支持元数据更新,文件替换可选一起补。

7.1.3 删除模板

  • DELETE /api/v3/contract-templates/{id}
  • 权限:contract_template:delete

行为:

  • 软删除,不物理删 OSS

7.2 既有接口增强

7.2.1 分类接口

  • 过滤 deleted_at IS NULL
  • 返回 template_count 时只统计当前用户可见地区且未删除模板

7.2.2 列表接口

新增可选参数:

  • region

逻辑:

  • 仅返回当前用户可见模板
  • 默认按 updated_at DESC

7.2.3 搜索接口

新增可选参数:

  • region

逻辑:

  • 仅搜索当前用户可见模板

7.2.4 详情接口

逻辑:

  • 校验模板存在
  • 校验模板未删除
  • 校验当前用户对模板所在地区可见

8. 权限设计

新增权限:

  • contract_template:create
  • contract_template:update
  • contract_template:delete

保留权限:

  • contract_template:list:read
  • contract_template:search:read
  • contract_template:detail:read

角色建议:

  • super_admin
    • 全部读写删
  • provincial_admin
    • 全部读写删
  • admin
    • 上传
    • 编辑本地区模板
    • 删除本地区模板
  • 普通用户
    • 仅按需开放读权限

9. 前端设计

9.1 列表页入口

/contract-template/list 页面右上角增加:

  • “上传模板”按钮

仅有 contract_template:create 权限时展示。

9.2 上传弹窗字段

  • 模板标题
  • 模板编码
  • 模板分类
  • 所属地区
  • 模板简介
  • 是否推荐
  • 模板主文件
  • 预览 PDF 文件(可选)

9.3 前端交互规则

  • admin 用户地区默认锁定为自己地区
  • provincial_admin 可选择地区
  • 上传成功后:
    • 提示成功
    • 关闭弹窗
    • 刷新当前列表
  • 上传失败时:
    • 表单级错误走 toast
    • 403 需给出明确无权限提示

9.4 API 封装

lib/api/contract-template/index.ts 增加:

  • createContractTemplate
  • updateContractTemplate
  • deleteContractTemplate

上传使用 FormData 直接请求后端,不走多余代理语义。

10. 数据迁移方案

10.1 老表扩展

通过增量 SQL

  • 新增缺失列
  • 回填默认值
  • 修正索引
  • 增加 updated_at 触发器

10.2 老数据回填

建议回填:

  • region = '省级'
  • original_file_name = '' 或按旧路径推导
  • file_size = 0
  • deleted_at = NULL

10.3 回滚策略

若上传接口上线后发现问题:

  • 可先关闭前端上传入口
  • 已有新字段与索引保持兼容,不影响只读能力

11. 开发步骤

阶段 1:基础设施

  1. 扩展合同模板 SQL
  2. 扩展 RBAC seed
  3. 更新 OSS 路径工具

阶段 2:后端接口

  1. 增加 DTO/VO
  2. 扩展 Service 接口
  3. 实现上传、更新、删除
  4. 为列表、搜索、详情补地区过滤

阶段 3:前端页面

  1. 扩展 API 客户端
  2. 在列表页增加上传按钮和弹窗
  3. 接地区选择与权限控制

阶段 4:验证

  1. 省级管理员上传省级模板
  2. 地市管理员上传本地区模板
  3. 非本地区参数校验
  4. 403 提示
  5. 列表、搜索、详情联调

12. 本期明确不做

  • 合同起草模块重构
  • 模板占位符自动解析
  • docx 自动转 pdf
  • 地区模板覆盖省级模板优先级
  • 模板版本管理
  • OSS 历史模板统一搬迁

13. 推荐本期交付范围

建议本期落地以下完整闭环:

  1. 合同模板表完成地区化、审计化、软删除改造
  2. 合同模板后端新增上传接口
  3. 合同模板列表页新增上传弹窗
  4. 合同模板读接口支持地区可见性控制
  5. 权限种子补齐

这套范围足以让合同模板模块从“只读展示”升级为“可管理上传的地区化模板库”。