Files
hyapi-server/docs/多平台签署整合实现方案.md
2026-07-21 15:53:29 +08:00

23 KiB
Raw Blame History

多平台签署整合实现方案e签宝 + 法大大)

基于现有企业入驻流程的改造设计,供评审后决定实施范围与优先级。
关联文档:企业入驻-e签宝功能分析.md


1. 背景与目标

1.1 现状

当前企业入驻的企业实名认证 + 合同签署全流程绑定在 e签宝 单一平台:

  • 管理员审核通过后,直接调用 e签宝 /v3/org-auth-url 生成 auth_url
  • 企业认证、模板填单、签署流程、回调/轮询均硬编码在 CertificationApplicationServiceImpl + internal/shared/esign

1.2 目标

  1. certifications 主表新增 sign_platform(签署平台) 字段
  2. 管理员审核通过后,由用户选择签署平台e签宝 / 法大大)
  3. 根据所选平台发放对应的企业认证链接合同签署链接
  4. 尽量复用现有状态机,降低对已完成用户的影响

1.3 非目标(本期可不做)

  • 同一用户在不同平台各签一份合同
  • 签署中途切换平台(选定后锁定,除非管理员重置)
  • 替换掉 e签宝 的全部历史数据

2. 改造后流程设计

2.1 新增步骤:选择签署平台

在「人工审核通过」与「企业认证 iframe」之间插入一步

填写企业信息
  → 人工审核info_pending_review
  → 【新增】选择签署平台info_submitted 前/后,见 2.2
  → 企业实名认证info_submitted
  → 合同预览与签署enterprise_verified → contract_applied → completed

2.2 平台选择时机(推荐方案)

方案 时机 优点 缺点
A推荐 审核通过后、生成认证链接前,用户主动选择 符合需求;认证与签署同一平台;不浪费第三方调用 多一个前端步骤
B 提交企业信息时一并选择 步骤少 审核拒绝后需重选;用户尚不清楚平台差异
C 仅合同阶段选择,认证仍固定 e签宝 改动小 法大大合同要求法大大侧企业实名,链路不完整

推荐采用方案 A,状态流转如下:

flowchart TD
    A[info_pending_review] --> B[管理员审核通过]
    B --> C{sign_platform 已选择?}
    C -->|否| D[前端展示平台选择页<br/>POST /select-sign-platform]
    D --> E[写入 sign_platform]
    E --> F[按平台生成 auth_url]
    C -->|是| F
    F --> G[info_submitted + auth_url]
    G --> H[iframe 企业认证]
    H --> I[enterprise_verified + 生成合同]
    I --> J[apply-contract 按平台发起签署]
    J --> K[completed]

2.3 平台锁定规则

规则 说明
可选时机 info_pending_review 审核通过后 ~ info_submitted 之前(sign_platform 为空)
锁定时机 用户确认平台后写入 sign_platform,并生成该平台认证链接
不可变更 进入 info_submitted 后不允许用户自行切换
管理员重置 仅管理员可将 sign_platform 置空并重置到待选平台状态(见 4.3

3. 数据库变更

3.1 certifications 主表

新增字段:

ALTER TABLE certifications
  ADD COLUMN sign_platform VARCHAR(20) DEFAULT NULL
    COMMENT '签署平台: esign | fadadaNULL 表示尚未选择';
字段 类型 说明
sign_platform varchar(20), nullable esign / fadada / NULL

现有 e签宝 字段复用策略(推荐不重命名):

现有字段 多平台语义
auth_flow_id 第三方企业认证流程 ID平台无关
auth_url 第三方企业认证页面 URL
contract_file_id 第三方合同文件 ID
esign_flow_id 第三方签署流程 ID建议后续迭代改名为 sign_flow_id
contract_sign_url 第三方签署页面 URL

首期可保留 esign_flow_id 列名不动,避免大面积迁移;在代码层用 SignFlowID 别名理解即可。

3.2 子记录表(建议同步加平台字段)

变更
esign_contract_generate_records 新增 sign_platform varchar(20);后期可重命名为 contract_generate_records
esign_contract_sign_records 新增 sign_platform varchar(20);后期可重命名为 contract_sign_records
contract_infos 新增 sign_platform varchar(20),便于历史合同溯源

3.3 枚举定义Go

// internal/domains/certification/enums/sign_platform.go
type SignPlatform string

const (
    SignPlatformEsign   SignPlatform = "esign"
    SignPlatformFadada  SignPlatform = "fadada"
)

func IsValidSignPlatform(p SignPlatform) bool { ... }

3.4 历史数据迁移

-- 已有认证记录默认归属 e签宝
UPDATE certifications SET sign_platform = 'esign' WHERE sign_platform IS NULL;

UPDATE esign_contract_generate_records SET sign_platform = 'esign' WHERE sign_platform IS NULL;
UPDATE esign_contract_sign_records SET sign_platform = 'esign' WHERE sign_platform IS NULL;
UPDATE contract_infos SET sign_platform = 'esign' WHERE sign_platform IS NULL;

对于进行中sign_platform IS NULL 的记录:迁移后视为已选 e签宝与当前行为一致。


4. 后端架构改造

4.1 核心思路签署平台抽象层Strategy + Registry

将 e签宝 特有逻辑从 CertificationApplicationServiceImpl 中抽离,定义统一接口:

internal/domains/certification/ports/sign_platform_provider.go   # 接口(端口)
internal/infrastructure/external/esign/esign_provider.go       # e签宝 实现
internal/infrastructure/external/fadada/fadada_provider.go       # 法大大 实现
internal/infrastructure/external/signplatform/registry.go      # 按 sign_platform 路由

接口草案:

type SignPlatformProvider interface {
    Platform() enums.SignPlatform

    // 企业实名
    GenerateEnterpriseAuth(ctx context.Context, req *EnterpriseAuthRequest) (*AuthLinkResult, error)
    QueryOrgVerified(ctx context.Context, req *OrgIdentityQuery) (bool, error)

    // 合同
    GenerateContractFile(ctx context.Context, req *ContractGenerateRequest) (*ContractFileResult, error)
    CreateSignFlow(ctx context.Context, req *SignFlowCreateRequest) (*SignFlowResult, error)
    QuerySignStatus(ctx context.Context, flowID string) (*SignStatusResult, error)
    DownloadSignedFiles(ctx context.Context, flowID string) ([]*SignedFile, error)

    // 回调
    ParseCallback(ctx context.Context, raw []byte, headers map[string]string) (*CallbackEvent, error)
    VerifyCallback(ctx context.Context, raw []byte, headers map[string]string) error
}

CertificationApplicationServiceImpl 中所有 s.esignClient.XXX() 改为:

provider := s.platformRegistry.Get(cert.SignPlatform)
provider.GenerateEnterpriseAuth(...)

4.2 需改造的后端触点(按优先级)

方法 现状 改造
AdminApproveSubmitRecord 直接 esignClient.GenerateEnterpriseAuth 审核通过后不立即生成链接;仅将状态保持在「待选平台」或新增中间状态
新增 SelectSignPlatform 用户选择平台 → 写 sign_platform → 调 provider 生成 auth_urlinfo_submitted
ConfirmAuth / checkAndCompleteEnterpriseVerification 查 e签宝 identity 调当前 provider 的 QueryOrgVerified
generateAndAddContractFile e签宝 FillTemplate 调 provider 的 GenerateContractFile
ApplyContract / generateContractAndSignURL e签宝 SignFlow 调 provider 的 CreateSignFlow
checkAndUpdateSignStatus e签宝 QuerySignFlowDetail 调 provider 的 QuerySignStatus
handleContractAfterSignComplete e签宝 DownloadSignedFile 调 provider 的 DownloadSignedFiles
HandleEsignCallback 仅处理 e签宝 拆为 /callbacks/esign + /callbacks/fadada,或统一入口按 header/字段分发

4.3 状态机微调(可选两种做法)

做法 1最小改动推荐不新增状态

  • 管理员审核通过后,认证状态仍为 info_pending_review 或新增语义:info_submittedsign_platform=NULLauth_url 为空
  • 前端根据 metadata.need_select_platform=true 展示平台选择页
  • 用户选完平台后才进入 info_submitted(有 auth_url

做法 2新增状态 platform_pending

  • 语义更清晰,但需改 certification_status.go、前端步骤映射、管理端筛选
  • 适合后续平台数量继续增加时

推荐做法 1,通过 metadata 驱动前端,避免状态机膨胀:

{
  "status": "info_pending_review",
  "metadata": {
    "manual_review_status": "approved",
    "need_select_platform": true,
    "available_platforms": ["esign", "fadada"]
  }
}

或审核通过后直接将状态推到 info_submitted,但 auth_url 为空、need_select_platform=true

4.4 新增 API

方法 路径 说明
GET /api/v1/certifications/sign-platforms 返回可选平台列表(名称、图标、说明、是否可用)
POST /api/v1/certifications/select-sign-platform 用户选择平台,生成认证链接
POST /api/v1/certifications/callbacks/fadada 法大大回调(与 esign 并列)
POST /api/v1/certifications/admin/reset-sign-platform 管理员重置平台选择(可选)

SelectSignPlatform 请求体:

{
  "sign_platform": "fadada"
}

响应(与现有 details 结构对齐):

{
  "status": "info_submitted",
  "sign_platform": "fadada",
  "metadata": {
    "auth_url": "https://...",
    "next_action": "请完成企业认证"
  }
}

apply-contract / confirm-sign / confirm-auth:无需改路径,内部按 cert.SignPlatform 路由。

4.5 管理员审核逻辑调整

当前 AdminApproveSubmitRecord 审核通过后会立即调用 e签宝。改造后

审核通过 → 仅更新 submit_record.manual_review_status = approved
         → 认证状态:保持 info_pending_review或推到 info_submitted 但无 auth_url
         → 不调用任何第三方
用户选择平台 → SelectSignPlatform → 调对应 provider → 写入 auth_url → info_submitted

管理员后台可展示 sign_platform 列,便于客服排查。


5. 法大大接入方案

5.1 平台与文档

  • 产品:法大大 FASC OpenAPI v5.1(公有云)
  • 开放平台:https://cloud.fadada.com / 开发文档 https://dev.fadada.com
  • 参考 SDKfasc-openapi-go-sdk(官方 Go SDK建议优先使用

5.2 需准备的法大大侧资源

资源 用途
AppID / AppSecret API 鉴权
openCorpId 接入企业(海宇数据自身)在法大大侧的企业 ID
应用模板 / 签署模板 对应合作协议 PDF 模板
测试环境域名 沙箱联调
回调地址 https://{domain}/api/v1/certifications/callbacks/fadada

5.3 法大大 API 与 e签宝 映射

业务步骤 e签宝现有 法大大 FASC待接
获取企业认证链接 POST /v3/org-auth-url Corp 模块 - 获取企业认证/授权 URL
查询企业是否已实名 GET /v3/organizations/identity-info Corp 模块 - 查询企业认证状态
模板生成合同文件 POST /v3/files/create-by-doc-template AppTemplate + Doc 模块 - 填写模板生成文档
创建签署流程 POST /v3/sign-flow/create-by-file fadada.CreateSignFlow/sign-task/create/sign-task/create-with-template
获取签署链接 POST /v3/sign-flow/{id}/sign-url fadada.GetSignURL/sign-task/actor/get-url
查询签署状态 GET /v3/sign-flow/{id}/detail fadada.QuerySignStatus/sign-task/app/get-detailtask_finished/sign_completed=完成)
下载已签文件 GET /v3/sign-flow/{id}/file-download-url fadada.DownloadSignedFiles/sign-task/owner/get-download-url
回调 AUTH_PASS fadada.VerifyCallback + ParseCallbackX-FASC-* HMAC-SHA256

具体接口路径以法大大 v5.1 文档为准;上表为模块级映射,实施时按官方 SDK 方法名落地。

5.4 法大大合同模板控件

模板 ID1784013372537192273config.yamlfadada.template_id

业务字段 e签宝 控件 key 法大大控件编码 (fieldId) 配置键
协议编号 xybh 多控件同值(见 config.yaml agreement_no 列表) agreement_no
签订日期 (系统) 2039326319 contract_date
甲方企业名 jfqym / jfqym2 6920634255 party_a_name
甲方统一信用代码 jftyshxydm 8702060291 party_a_uscc
甲方联系地址 jflxdz 4557539440 party_a_address
甲方授权代表/法人 jfsqdb 8627432823 party_a_rep
甲方签署日期 qsrq1 / qsrq3 6047306418 party_a_sign_date
乙方签署日期 qsrq2 3849218908 party_b_sign_date

日期格式与现网一致:2006年01月02日。实现:fadada.Client.FillTemplate / FillSignTaskFields

5.5 法大大 SDK 目录规划

hyapi-server/internal/shared/fadada/          # 或 infrastructure/external/fadada/
├── client.go           # 封装官方 SDK Client
├── config.go
├── corp_service.go     # 企业认证
├── signtask_service.go # 签署任务
├── template_service.go # 模板/文档
├── callback.go         # 回调解析与验签
└── provider.go         # 实现 SignPlatformProvider

6. 配置变更

6.1 config.yaml 新增法大大段

# 签署平台全局开关
sign_platform:
  enabled: ["esign", "fadada"]   # 前端可选列表
  default: ""                   # 空=强制用户选择

esign:
  # 保持现有配置不变
  ...

fadada:
  app_id: ""
  app_secret: ""
  server_url: "https://api.fadada.com"    # 以官方文档为准
  open_corp_id: ""                         # 海宇数据在法大大的企业 ID
  template_id: ""                          # 应用签署模板 ID
  contract:
    name: "海宇数据-合作协议"
    expire_days: 7
  auth:
    redirect_url: "https://console.haiyudata.com/certification/callback/fadada/auth"
  sign:
    redirect_url: "https://console.haiyudata.com/certification/callback/fadada/sign"
  callback:
    enabled: true

6.2 Go Config 结构

type SignPlatformConfig struct {
    Enabled []string `mapstructure:"enabled"`
    Default string   `mapstructure:"default"`
}

type FadadaConfig struct {
    AppID      string         `mapstructure:"app_id"`
    AppSecret  string         `mapstructure:"app_secret"`
    ServerURL  string         `mapstructure:"server_url"`
    OpenCorpID string         `mapstructure:"open_corp_id"`
    TemplateID string         `mapstructure:"template_id"`
    Contract   ContractConfig `mapstructure:"contract"`
    Auth       AuthConfig     `mapstructure:"auth"`
    Sign       SignConfig     `mapstructure:"sign"`
    Callback   CallbackConfig `mapstructure:"callback"`
}

7. 前端改造

7.1 新增步骤与组件

certification/components/
├── PlatformSelect.vue      # 【新增】签署平台选择
├── EnterpriseVerify.vue    # 改造:支持不同平台 iframe / 跳转方式
├── ContractSign.vue        # 改造:按平台展示签署页
└── ...

步骤条调整:

const certificationSteps = [
  { key: 'enterprise_info', title: '填写企业信息', ... },
  { key: 'manual_review', title: '人工审核', ... },
  { key: 'platform_select', title: '选择签署平台', ... },  // 新增
  { key: 'enterprise_verify', title: '企业认证', ... },
  { key: 'contract_sign', title: '签署合同', ... },
  { key: 'completed', title: '完成', ... },
]

7.2 步骤路由逻辑(setCurrentStepByStatus

// 审核已通过,但未选平台
if (status === 'info_pending_review' && metadata.manual_review_status === 'approved' && !data.sign_platform) {
  currentStep.value = 'platform_select'
  return
}
// 或status === 'info_submitted' && !metadata.auth_url && metadata.need_select_platform

7.3 PlatformSelect.vue 交互

  • 调用 GET /sign-platforms 获取可选平台卡片e签宝 / 法大大)
  • 每张卡片展示:平台名称、说明、预计耗时、合规提示
  • 用户点击「确认选择」→ POST /select-sign-platform
  • 成功后跳转 enterprise_verifyiframe 加载返回的 auth_url

7.4 API 封装(src/api/index.js

export const certificationApi = {
  // ...existing
  getSignPlatforms: () => request.get('/certifications/sign-platforms'),
  selectSignPlatform: (data) => request.post('/certifications/select-sign-platform', data),
}

7.5 回调路由扩展

现有:

  • /certification/callback/auth
  • /certification/callback/sign

建议扩展(便于各平台 redirect_url 分离统计):

  • /certification/callback/esign/auth
  • /certification/callback/esign/sign
  • /certification/callback/fadada/auth
  • /certification/callback/fadada/sign

IframeCallback.vue 可增加 platform 路由参数,回调后 postMessage 携带 { type: 'CHECK_STATUS', scene, platform }

7.6 管理端

certification-reviews/index.vue 列表增加「签署平台」列;详情展示平台与第三方 flow ID方便客服排查。


8. 回调与轮询策略

环节 e签宝现有 法大大(新增) 统一策略
企业认证完成 回调 AUTH_PASS + 轮询 identity 法大大认证回调 + 轮询认证状态 两平台均保留「回调 + 轮询」双保险
合同签署完成 主要依赖 confirm-sign 轮询 同上 GET /details 时按平台自动同步
验签 当前已注释 必须实现 生产环境两个平台都开启验签

9. 实施分期建议

Phase 0 — 准备1~2 天)

  • 法大大开放平台开户、创建应用、获取 AppID/AppSecret/openCorpId
  • 在法大大创建合作协议模板(控件与海宇业务字段对齐)
  • 确认沙箱环境与回调公网可达

Phase 1 — 抽象层 + 数据字段3~5 天)

  • certifications.sign_platform 及子表字段
  • SignPlatform 枚举 + SignPlatformProvider 接口
  • 将现有 e签宝 逻辑迁入 EsignProvider(行为不变)
  • PlatformRegistry 注入容器
  • 历史数据迁移脚本AutoMigrate 已加列;存量可按需刷 esign
  • 回归测试:现有 e签宝 全流程无回归

Phase 2 — 平台选择流程2~3 天)

  • 后端 SelectSignPlatform + GetSignPlatforms
  • 调整 AdminApproveSubmitRecord(审核后不立即调第三方)
  • 前端 PlatformSelect.vue + 步骤条改造
  • 仅 e签宝 模式下验证「先选平台 → 再认证 → 再签署」

Phase 3 — 法大大 Provider5~8 天)

  • 接入 HTTP/SDK 封装,实现 FadadaProvider(骨架 + OpenAPI 封装)
  • 企业认证链接、实名查询(代码层)
  • 模板填单、签署任务、状态查询、文件下载(代码层)
  • /callbacks/fadada + 验签钩子
  • 法大大沙箱端到端联调(需有效凭证与模板)

Phase 4 — 收尾2~3 天)

  • 管理端展示 sign_platform / 待选平台
  • 启用 e签宝 回调验签(安全债补齐)
  • 文档与 Swagger 更新
  • 生产配置与灰度发布

预估总工期12~18 个工作日1 人全职,含联调;法大大审核/模板配置时间另计)


10. 风险与注意事项

风险 说明 缓解
两平台企业实名不互通 选法大大则必须在法大大完成企业认证 平台选择页明确提示;选定后锁定
模板不一致 两份模板需法务分别审核 上线前做法务对齐检查清单
签署状态码差异 e签宝 2=完成;法大大状态码不同 封装在各自 Provider 内,对外统一 SignStatusResult
经办人信息 当前 e签宝 用法人作经办人 法大大侧同步规则;授权代表字段映射需确认
合同文件过期 e签宝 50 分钟过期重生成 法大大侧确认是否有过期策略,在 Provider 实现
进行中的用户 迁移时默认 esign 仅新用户或管理员重置后才出现平台选择

11. 待你决策的问题

在动手写代码前,建议确认以下事项:

Q1. 平台选择时机

  • A. 审核通过后由用户选择(推荐)
  • B. 提交企业信息时选择
  • C. 其他___________

Q2. 是否新增状态 platform_pending

  • A. 不新增,用 metadata 驱动(推荐,改动小)
  • B. 新增独立状态

Q3. e签宝 是否继续保留

  • A. 双平台并存,用户可选(推荐)
  • B. 新用户仅法大大e签宝 仅维护存量
  • C. 全量迁移到法大大

Q4. 管理员审核后行为

  • A. 审核通过不生成链接,等用户选平台(推荐)
  • B. 审核通过默认 e签宝 并生成链接,用户可在认证前改选法大大

Q5. 法大大接入方式

  • A. 官方 Go SDK(推荐)
  • B. 自研 HTTP 封装(与 esign 包一致)

Q6. 合同模板

  • A. 法大大新建一份等价模板
  • B. 非法大大模板,改用上传 PDF 方式发起签署

12. 文件改动清单(实施时参考)

后端

文件 改动类型
domains/certification/entities/certification.go 新增 SignPlatform 字段
domains/certification/enums/sign_platform.go 新增
domains/certification/ports/sign_platform_provider.go 新增接口
infrastructure/external/esign/esign_provider.go 从 service_impl 抽取
infrastructure/external/fadada/* 新增
application/certification/certification_application_service_impl.go 改为调 registry
application/certification/dto/commands/ 新增 SelectSignPlatformCommand
infrastructure/http/routes/certification_routes.go 新增路由
infrastructure/http/handlers/certification_handler.go 新增 handler
config/config.go + config.yaml 新增 fadada / sign_platform 配置
container/container.go 注册 FadadaProvider + Registry

前端

文件 改动类型
pages/certification/index.vue 步骤与状态映射
pages/certification/components/PlatformSelect.vue 新增
pages/certification/IframeCallback.vue 支持多平台
src/api/index.js 新增 API
src/router/index.js 扩展 callback 路由
pages/admin/certification-reviews/index.vue 展示 sign_platform

13. 总结

本次改造的核心不是「替换 e签宝」而是

  1. 主表增加 sign_platform,记录用户选择的签署平台
  2. 抽象 SignPlatformProvider,将 e签宝 现有实现原样迁入
  3. 审核通过后增加平台选择步骤,再按平台发放认证/签署链接
  4. 新增法大大 Provider,与 e签宝 并行

这样对存量 e签宝 用户零影响,新用户可自由选择;后续若再接入第三方,只需新增 Provider 实现并加入 enabled 列表。


请确认第 11 节中的决策项后,可据此进入具体开发。