23 KiB
多平台签署整合实现方案(e签宝 + 法大大)
基于现有企业入驻流程的改造设计,供评审后决定实施范围与优先级。
关联文档:企业入驻-e签宝功能分析.md
1. 背景与目标
1.1 现状
当前企业入驻的企业实名认证 + 合同签署全流程绑定在 e签宝 单一平台:
- 管理员审核通过后,直接调用 e签宝
/v3/org-auth-url生成auth_url - 企业认证、模板填单、签署流程、回调/轮询均硬编码在
CertificationApplicationServiceImpl+internal/shared/esign
1.2 目标
certifications主表新增sign_platform(签署平台) 字段- 管理员审核通过后,由用户选择签署平台(e签宝 / 法大大)
- 根据所选平台发放对应的企业认证链接与合同签署链接
- 尽量复用现有状态机,降低对已完成用户的影响
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 | fadada,NULL 表示尚未选择';
| 字段 | 类型 | 说明 |
|---|---|---|
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_url → info_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_submitted但sign_platform=NULL且auth_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 - 参考 SDK:
fasc-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-detail(task_finished/sign_completed=完成) |
| 下载已签文件 | GET /v3/sign-flow/{id}/file-download-url |
fadada.DownloadSignedFiles → /sign-task/owner/get-download-url |
| 回调 | AUTH_PASS 等 |
fadada.VerifyCallback + ParseCallback(X-FASC-* HMAC-SHA256) |
具体接口路径以法大大 v5.1 文档为准;上表为模块级映射,实施时按官方 SDK 方法名落地。
5.4 法大大合同模板控件
模板 ID:1784013372537192273(config.yaml → fadada.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_verify,iframe 加载返回的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 — 法大大 Provider(5~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签宝」,而是:
- 主表增加
sign_platform,记录用户选择的签署平台 - 抽象
SignPlatformProvider,将 e签宝 现有实现原样迁入 - 审核通过后增加平台选择步骤,再按平台发放认证/签署链接
- 新增法大大 Provider,与 e签宝 并行
这样对存量 e签宝 用户零影响,新用户可自由选择;后续若再接入第三方,只需新增 Provider 实现并加入 enabled 列表。
请确认第 11 节中的决策项后,可据此进入具体开发。