# 多平台签署整合实现方案(e签宝 + 法大大) > 面向 **tyapi**(天远数据)企业入驻流程的改造设计,供评审后决定实施范围与优先级。 > 关联代码:`tyapi-server`(认证域 + `internal/shared/esign`)、`tyapi-frontend`(`pages/certification`)。 > **本文档仅方案,未改代码;确认后按分期实施。** --- ## 0. 本平台可行性结论(tyapi) ### 0.1 结论摘要 | 维度 | 结论 | 说明 | |------|------|------| | 整体可行性 | **可行** | 入驻状态机、审核→认证→签署链路与文档假设一致,具备抽象多平台的条件 | | 抽象层改造 | **高可行** | `CertificationApplicationServiceImpl` 已集中调用 `esignClient`,适合抽 `SignPlatformProvider` | | 法大大接入 | **可行,依赖外部准备** | 需 AppID/模板/沙箱/回调公网;技术映射清晰,联调工期独立 | | e签宝前端隐藏 | **可行且推荐** | 后端保留 e签宝 Provider(存量/兜底);前端不展示 e签宝选项,新用户走法大大 | | 存量影响 | **可控** | 历史与进行中记录默认 `sign_platform=esign`,行为与现网一致 | ### 0.2 与文档原稿的差异(重要) 原稿部分内容来自 **hyapi / 海宇** 语境,**不能直接当作 tyapi 已完成项**: | 项 | 原稿表述 | tyapi 实际 | |----|----------|------------| | Phase 1~4 勾选 | 多项已打勾 | **均未落地**(无 `sign_platform` 字段、无 Fadada、无 PlatformSelect、无 SelectSignPlatform API) | | 包路径 | `hyapi-server/...` | `tyapi-server/...` | | 合同名 / 回调域名 | 海宇 / `haiyudata.com` | 天远 / `console.tianyuanapi.com` | | e签宝包位置 | 文中写 `infrastructure/external/esign` | 现网为 `internal/shared/esign`(另有 `infrastructure/external/esign/certification_esign_service.go`) | 实施时以 **本节 + 下文路径** 为准,不以原稿勾选状态为准。 ### 0.3 现网关键触点(改造锚点) **后端(已绑定 e签宝):** - `AdminApproveSubmitRecord`:审核通过后**立即** `esignClient.GenerateEnterpriseAuth`,写入 `auth_url` → `info_submitted` - `ConfirmAuth` / 企业认证轮询:`QueryOrgIdentityInfo` - `ApplyContract` / 合同生成与签署:`FillTemplate` / `CreateSignFlow` / `GetSignURL` - 签署完成:`QuerySignFlowDetail` / `DownloadSignedFile` - 配置:`config.yaml` → `esign.*`(沙箱 `smlopenapi.esign.cn`,模板与合同名已是天远业务) **前端:** - 步骤:`enterprise_info` → `manual_review` → `enterprise_verify` → `contract_sign` → `completed` - **无**平台选择步;`auth_url` / `contract_sign_url` 直接 iframe **数据模型:** - `certifications` 有 `auth_flow_id` / `auth_url` / `contract_file_id` / `esign_flow_id` / `contract_sign_url` - **无** `sign_platform` 字段 ### 0.4 产品决策(已定) | 决策项 | 结论 | |--------|------| | 平台选择时机 | **A**:审核通过后、生成认证链接前(见 2.2) | | 是否新增 `platform_pending` | **否**:用 metadata 驱动(见 4.3 做法 1) | | e签宝 是否保留 | **后端保留,前端隐藏**(见 0.5、7.7) | | 审核通过后行为 | **不立即调第三方**;等用户完成平台确认(对用户侧可自动确认法大大,见 0.5) | | 法大大接入 | 优先官方 Go SDK;若 SDK 不适配再自研 HTTP(与现 esign 包风格一致) | ### 0.5 e签宝「前端隐藏」含义(本期落地口径) **目标:** 新用户入驻流程中**看不到、选不到 e签宝**;对外只走法大大。e签宝代码与配置保留,用于: 1. 存量 / 进行中且已是 e签宝链路的用户继续完成 2. 管理端排查、必要时管理员重置后内部指定平台 3. 后续若需临时打开双平台,只改配置与前端可见列表,无需重写 Provider **推荐交互(隐藏后「单可见平台」):** ``` 审核通过 → GET /sign-platforms 返回可见列表(仅 fadada;esign 标记 hidden 或不下发) → 可见平台仅 1 个时:前端不展示 PlatformSelect 步骤,自动 POST select-sign-platform=fadada → 直接进入企业认证 iframe(法大大 auth_url) ``` | 规则 | 说明 | |------|------| | `sign_platform.enabled` | 配置仍可含 `esign`(后端可用) | | `sign_platform.visible` / `frontend_hidden` | 控制前端是否展示;本期 `esign` 隐藏 | | `GET /sign-platforms` | 默认只返回 **可见** 平台;管理端或内部调试可另开参数看全部 | | `POST /select-sign-platform` | 拒绝用户选择 `hidden` 平台(除非管理员接口) | | 步骤条 | 单可见平台时:**不增加**「选择签署平台」步骤,用户感知与现网一致(审核后直接认证) | | 双可见平台时 | 才展示 `PlatformSelect.vue`(预留能力,本期不启用) | > 这样「多平台架构」一次到位,但 **本期用户体验 ≈ 只接法大大**,改动面主要在后端抽象 + 法大大联调,前端几乎无新增步骤。 --- ## 1. 背景与目标 ### 1.1 现状 当前企业入驻的**企业实名认证 + 合同签署**全流程绑定在 **e签宝** 单一平台: - 管理员审核通过后,直接调用 e签宝 `/v3/org-auth-url` 生成 `auth_url` - 企业认证、模板填单、签署流程、回调/轮询均硬编码在 `CertificationApplicationServiceImpl` + `internal/shared/esign` ### 1.2 目标 1. `certifications` 主表新增 **`sign_platform`(签署平台)** 字段 2. 审核通过后按配置完成平台确认(本期:**自动法大大**;预留多平台选择) 3. 根据 `sign_platform` 发放对应的**企业认证链接**与**合同签署链接** 4. 复用现有状态机;存量 e签宝用户零感迁移 5. e签宝 **前端隐藏**,后端 Provider 保留 ### 1.3 非目标(本期可不做) - 同一用户在不同平台各签一份合同 - 签署中途切换平台(选定后锁定,除非管理员重置) - 替换掉 e签宝 的全部历史数据 - 向普通用户展示 e签宝 选项(本期明确不做) --- ## 2. 改造后流程设计 ### 2.1 主流程(本期:自动法大大) ``` 填写企业信息 → 人工审核(info_pending_review) → 【内部】确认 sign_platform=fadada(前端无选择页,或静默 select) → 企业实名认证(info_submitted + auth_url) → 合同预览与签署(enterprise_verified → contract_applied → completed) ``` 若未来 `visible` 含多个平台,再插入「选择签署平台」步骤(见 7.1)。 ### 2.2 平台确认时机(推荐方案 A) | 方案 | 时机 | 优点 | 缺点 | |------|------|------|------| | **A(推荐)** | 审核通过后、生成认证链接前确认平台 | 认证与签署同一平台;不浪费第三方调用 | 若多平台可见则多一步 | | B | 提交企业信息时一并选择 | 步骤少 | 审核拒绝后需重选;用户尚不清楚平台差异 | | C | 仅合同阶段选平台,认证仍固定 e签宝 | 改动小 | 法大大合同要求法大大侧企业实名,链路不完整 | **推荐采用方案 A**,状态流转如下: ```mermaid flowchart TD A[info_pending_review] --> B[管理员审核通过] B --> C{sign_platform 已选择?} C -->|否| D{可见平台数量} D -->|仅 1 个| E[前端静默 POST select-sign-platform] D -->|多个| F[展示 PlatformSelect] E --> G[写入 sign_platform] F --> G G --> H[按平台生成 auth_url] C -->|是| H H --> I[info_submitted + auth_url] I --> J[iframe 企业认证] J --> K[enterprise_verified + 生成合同] K --> L[apply-contract 按平台发起签署] L --> M[completed] ``` ### 2.3 平台锁定规则 | 规则 | 说明 | |------|------| | 可选/可确认时机 | 审核通过后 ~ `info_submitted` 之前(`sign_platform` 为空) | | 锁定时机 | 写入 `sign_platform` 并生成该平台认证链接后 | | 不可变更 | 进入 `info_submitted` 后用户不可自行切换 | | 管理员重置 | 可将 `sign_platform` 置空并回到待确认状态(见 4.4) | | 前端隐藏 | 普通用户不可选 `esign`;存量 `sign_platform=esign` 仍按 e签宝 Provider 跑完 | --- ## 3. 数据库变更 ### 3.1 `certifications` 主表 ```sql 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) ```go // tyapi-server/internal/domains/certification/enums/sign_platform.go type SignPlatform string const ( SignPlatformEsign SignPlatform = "esign" SignPlatformFadada SignPlatform = "fadada" ) func IsValidSignPlatform(p SignPlatform) bool { /* ... */ } ``` ### 3.4 历史数据迁移 ```sql -- 已有认证记录默认归属 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; -- contract_infos 若存在同理 ``` > 注意:若采用「全表 NULL→esign」迁移,则**新用户在审核通过前**也会被刷成 esign。更稳妥做法: > - 迁移只刷 **已进入 `info_submitted` 及之后** 的记录;或 > - 迁移后审核通过且仍为 NULL 的走「待确认平台」逻辑(本期自动 fadada)。 > **推荐:仅迁移「已有 auth_url / esign_flow_id / 已完成链路」的记录为 esign;其余保持 NULL。** --- ## 4. 后端架构改造 ### 4.1 核心思路:签署平台抽象层(Strategy + Registry) 将 e签宝 特有逻辑从 `CertificationApplicationServiceImpl` 中抽离: ``` internal/domains/certification/ports/sign_platform_provider.go # 接口 internal/infrastructure/external/esign/esign_provider.go # e签宝 Provider(封装 shared/esign) internal/infrastructure/external/fadada/fadada_provider.go # 法大大 Provider internal/infrastructure/external/signplatform/registry.go # 按 sign_platform 路由 ``` > 现有 HTTP/业务封装继续放在 `internal/shared/esign`;Provider 是薄适配层,避免一次性搬迁全部 esign 包。 **接口草案:** ```go 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 } ``` 调用改为: ```go provider := s.platformRegistry.Get(cert.SignPlatform) provider.GenerateEnterpriseAuth(...) ``` ### 4.2 需改造的后端触点(按优先级) | 方法 | 现状 | 改造 | |------|------|------| | `AdminApproveSubmitRecord` | 立即 `esignClient.GenerateEnterpriseAuth` | 审核通过后**不立即**生成链接;仅更新审核态,等平台确认 | | **新增** `SelectSignPlatform` | 无 | 写 `sign_platform` → provider 生成 `auth_url` → `info_submitted`;拒绝普通用户选 hidden 平台 | | `ConfirmAuth` / 企业认证完成检查 | 查 e签宝 identity | `QueryOrgVerified` | | `generateAndAddContractFile` | e签宝 FillTemplate | `GenerateContractFile` | | `ApplyContract` / 签署 URL | e签宝 SignFlow | `CreateSignFlow` | | `checkAndUpdateSignStatus` | e签宝 QuerySignFlowDetail | `QuerySignStatus` | | `handleContractAfterSignComplete` | e签宝 DownloadSignedFile | `DownloadSignedFiles` | | e签宝回调 | 现有回调入口 | 保留 `/callbacks/esign`;新增 `/callbacks/fadada` | ### 4.3 状态机微调(推荐做法 1:不新增状态) - 管理员审核通过后:保持 `info_pending_review`,或进入 `info_submitted` 但 `auth_url` 为空 - `details` metadata 驱动前端: ```json { "status": "info_pending_review", "metadata": { "manual_review_status": "approved", "need_select_platform": true, "available_platforms": ["fadada"], "auto_select_platform": "fadada" } } ``` | 字段 | 含义 | |------|------| | `need_select_platform` | 是否还需确认平台(`sign_platform` 为空) | | `available_platforms` | **前端可见**平台列表(本期仅 `fadada`) | | `auto_select_platform` | 可见仅 1 个时下发,前端可静默提交 | **不推荐**本期新增 `platform_pending` 状态(改状态机、步骤映射、管理端筛选成本高)。 ### 4.4 新增 API | 方法 | 路径 | 说明 | |------|------|------| | GET | `/api/v1/certifications/sign-platforms` | 返回**可见**平台列表;可带 `include_hidden`(仅管理员) | | POST | `/api/v1/certifications/select-sign-platform` | 确认平台并生成认证链接 | | POST | `/api/v1/certifications/callbacks/fadada` | 法大大回调 | | POST | `/api/v1/certifications/admin/reset-sign-platform` | 管理员重置平台(可选) | | POST | `/api/v1/certifications/admin/select-sign-platform` | 管理员可指定含 esign 的平台(可选,运维用) | **`SelectSignPlatform` 请求体:** ```json { "sign_platform": "fadada" } ``` **响应(与现有 details 对齐):** ```json { "status": "info_submitted", "sign_platform": "fadada", "metadata": { "auth_url": "https://...", "next_action": "请完成企业认证" } } ``` `apply-contract` / `confirm-sign` / `confirm-auth`:**路径不变**,内部按 `cert.SignPlatform` 路由。 ### 4.5 管理员审核逻辑调整 ``` 审核通过 → 仅更新 submit_record.manual_review_status = approved → 认证状态:保持 info_pending_review(或 info_submitted 无 auth_url) → 不调用任何第三方 用户侧确认平台(本期自动 fadada)→ SelectSignPlatform → provider → auth_url → info_submitted ``` 管理端列表建议展示 `sign_platform` 列(含存量 `esign`),便于客服排查。 --- ## 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 | | 应用模板 / 签署模板 | 对应《天远数据API合作协议》 | | 测试环境域名 | 沙箱联调 | | 回调地址 | `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` | `/sign-task/create` 或 create-with-template | | 获取签署链接 | `POST /v3/sign-flow/{id}/sign-url` | `/sign-task/actor/get-url` | | 查询签署状态 | `GET /v3/sign-flow/{id}/detail` | `/sign-task/app/get-detail` | | 下载已签文件 | `GET /v3/sign-flow/{id}/file-download-url` | `/sign-task/owner/get-download-url` | | 回调 | 现有 e签宝回调 | `X-FASC-*` HMAC-SHA256 验签 + ParseCallback | > 具体路径以法大大 v5.1 文档为准;实施时按官方 SDK 方法名落地。 ### 5.4 法大大合同模板控件 模板 ID、控件 fieldId 以法大大控制台实际创建为准,写入 `config.yaml` → `fadada.contract_fields`(或等价结构)。 业务字段应对齐现网 e签宝 控件语义(协议编号、甲乙方信息、签署日期等),日期格式与现网一致:`2006年01月02日`。 > 原稿中的法大大 fieldId 示例来自他站模板,**不可直接用于 tyapi**;上线前需在法大大新建天远模板并回填配置。 ### 5.5 法大大 SDK 目录规划 ``` tyapi-server/internal/shared/fadada/ # 或 infrastructure/external/fadada/ ├── client.go ├── config.go ├── corp_service.go ├── signtask_service.go ├── template_service.go ├── callback.go └── provider.go # 实现 SignPlatformProvider ``` --- ## 6. 配置变更 ### 6.1 config.yaml ```yaml # 签署平台全局开关 sign_platform: enabled: ["esign", "fadada"] # 后端已注册、可路由的平台 visible: ["fadada"] # 前端可见(本期隐藏 e签宝) default: "fadada" # 可见仅 1 个或自动确认时使用 esign: # 保持现有配置不变(存量链路) ... fadada: app_id: "" app_secret: "" server_url: "https://api.fadada.com" # 以官方文档为准 open_corp_id: "" template_id: "" contract: name: "天远数据API合作协议" expire_days: 7 auth: redirect_url: "https://console.tianyuanapi.com/certification/callback/fadada/auth" sign: redirect_url: "https://console.tianyuanapi.com/certification/callback/fadada/sign" callback: enabled: true ``` ### 6.2 Go Config 结构 ```go type SignPlatformConfig struct { Enabled []string `mapstructure:"enabled"` Visible []string `mapstructure:"visible"` // 前端可见;空则等同 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 / Auth / Sign / Callback 与 esign 段对称 } ``` **可见性规则:** - `visible` 必须是 `enabled` 的子集 - 用户 `SelectSignPlatform`:只能选 `visible` 中的值 - 管理员接口:可选 `enabled` 中的任意值(含隐藏的 esign) --- ## 7. 前端改造 ### 7.1 组件与步骤 ``` certification/components/ ├── PlatformSelect.vue # 预留:仅当 available_platforms.length > 1 时使用 ├── EnterpriseVerify.vue # 改造:兼容不同平台 iframe / 跳转 ├── ContractSign.vue # 改造:按平台展示签署页(多数情况仍为 iframe) └── ... ``` **本期步骤条(与现网一致,不增加平台选择步):** ```javascript const certificationSteps = [ { key: 'enterprise_info', title: '填写企业信息' }, { key: 'manual_review', title: '人工审核' }, // 不展示 platform_select(单可见平台自动确认) { key: 'enterprise_verify', title: '企业认证' }, { key: 'contract_sign', title: '签署合同' }, { key: 'completed', title: '完成' }, ] ``` 多平台可见时再插入: ```javascript { key: 'platform_select', title: '选择签署平台' } ``` ### 7.2 步骤路由逻辑(`setCurrentStepByStatus`) ```javascript // 审核已通过,尚未确认平台 if ( status === 'info_pending_review' && metadata.manual_review_status === 'approved' && !data.sign_platform ) { const platforms = metadata.available_platforms || [] if (platforms.length <= 1 && metadata.auto_select_platform) { // 静默确认,不进入 platform_select await certificationApi.selectSignPlatform({ sign_platform: metadata.auto_select_platform, }) await getCertificationDetails() return } currentStep.value = 'platform_select' return } ``` ### 7.3 PlatformSelect.vue(仅多可见平台) - 调用 `GET /sign-platforms`(仅可见项) - 卡片:名称、说明、合规提示 - 确认 → `POST /select-sign-platform` → 跳转 `enterprise_verify` ### 7.4 API 封装 ```javascript 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` 建议扩展: - `/certification/callback/esign/auth` | `.../sign`(兼容旧 redirect,可 301/同组件) - `/certification/callback/fadada/auth` | `.../sign` `IframeCallback.vue` 可增加 `platform` 参数,`postMessage` 携带 `{ type: 'CHECK_STATUS', scene, platform }`。 ### 7.6 管理端 `certification-reviews/index.vue` 增加「签署平台」列;详情展示平台与第三方 flow ID。 管理员重置/指定平台时可看到 **含 e签宝** 的完整 `enabled` 列表。 ### 7.7 e签宝前端隐藏清单(验收标准) | 检查项 | 期望 | |--------|------| | 用户步骤条 | 无「e签宝」文案、无平台二选一(单可见时) | | `GET /sign-platforms` | 不含 esign(或 `hidden: true` 且前端过滤) | | 用户误传 `sign_platform=esign` | 后端 4xx,提示平台不可用 | | 存量 esign 用户 | 仍能打开 e签宝认证/签署 iframe,流程可完成 | | 文案 | 企业认证/签署页不出现「e签宝」品牌(可选:统一写「完成企业认证」) | --- ## 8. 回调与轮询策略 | 环节 | e签宝(存量) | 法大大(新用户) | 统一策略 | |------|---------------|------------------|----------| | 企业认证完成 | 回调 + 轮询 identity | 认证回调 + 轮询 | 双保险 | | 合同签署完成 | `confirm-sign` / details 轮询 | 同左 | `GET /details` 按平台同步 | | 验签 | 现网若未开须补齐 | **必须实现** | 生产两平台均开启验签 | --- ## 9. 实施分期建议(tyapi 现状:全部未做) ### Phase 0 — 准备(1~2 天) - [ ] 法大大开户、应用、AppID/AppSecret/openCorpId - [ ] 创建天远合作协议模板,控件与业务字段对齐 - [ ] 确认沙箱与回调公网可达 ### Phase 1 — 抽象层 + 数据字段(3~5 天) - [ ] `certifications.sign_platform` 及子表字段 - [ ] `SignPlatform` 枚举 + `SignPlatformProvider` 接口 - [ ] 现有 e签宝 逻辑迁入 / 适配为 `EsignProvider`(行为不变) - [ ] `PlatformRegistry` 注入容器 - [ ] 历史数据迁移(仅存量链路刷 `esign`,见 3.4) - [ ] 回归:e签宝全流程无回归 ### Phase 2 — 平台确认流程 + 前端隐藏(2~3 天) - [ ] `SelectSignPlatform` + `GetSignPlatforms`(visible / auto_select) - [ ] 调整 `AdminApproveSubmitRecord`(审核后不调第三方) - [ ] 前端:单可见平台静默 select;**不展示 e签宝** - [ ] 预留 `PlatformSelect.vue`(多平台时再用) - [ ] 配置 `enabled` / `visible` / `default` ### Phase 3 — 法大大 Provider(5~8 天) - [ ] HTTP/SDK 封装 + `FadadaProvider` - [ ] 企业认证链接、实名查询 - [ ] 模板填单、签署任务、状态查询、文件下载 - [ ] `/callbacks/fadada` + 验签 - [ ] 沙箱端到端联调 ### Phase 4 — 收尾(2~3 天) - [ ] 管理端展示 `sign_platform` / 重置能力 - [ ] e签宝回调验签补齐(安全债) - [ ] Swagger / 运维文档 - [ ] 生产配置与灰度(建议先灰度新用户自动 fadada) **预估总工期:12~18 个工作日**(1 人全职,含联调;法大大审核/模板配置时间另计)。 因本期前端不展示选择页,**Phase 2 前端工作量低于原稿**。 --- ## 10. 风险与注意事项 | 风险 | 说明 | 缓解 | |------|------|------| | 两平台企业实名不互通 | 选法大大必须在法大大完成企业认证 | 新用户统一法大大;存量继续 e签宝 | | 模板不一致 | 天远需在法大大单独建模板 | 上线前法务对齐检查清单 | | 签署状态码差异 | e签宝与法大大状态码不同 | 封装在 Provider 内,对外统一 `SignStatusResult` | | 经办人信息 | 现网 e签宝用法人作经办人 | 法大大侧同步规则并确认字段映射 | | 合同文件过期 | e签宝约 50 分钟过期重生成 | 法大大侧确认过期策略并在 Provider 实现 | | 误迁移把新单刷成 esign | 全表 UPDATE 过宽 | 按 3.4 推荐:只刷已进入签署链路的记录 | | 前端隐藏但配置仍开 esign | 用户直接调 API 选 esign | `SelectSignPlatform` 校验 `visible` | | 静默 auto-select 失败 | 审核通过后卡在待确认 | details 重试 + 明确错误提示 + 客服可管理员指定 | --- ## 11. 决策记录 | 编号 | 议题 | 结论 | |------|------|------| | Q1 | 平台确认时机 | **A** 审核通过后、生成链接前 | | Q2 | 是否新增 `platform_pending` | **否**,metadata 驱动 | | Q3 | e签宝是否保留 | **后端保留 + 前端隐藏**;新用户默认/仅可见法大大 | | Q4 | 审核通过后行为 | **不生成链接**,等平台确认(可自动) | | Q5 | 法大大接入方式 | **优先官方 Go SDK**,不适配则自研 HTTP | | Q6 | 合同模板 | **法大大新建天远等价模板**(不可复用他站 fieldId) | --- ## 12. 文件改动清单(实施时参考) ### 后端(tyapi-server) | 文件 | 改动类型 | |------|----------| | `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` | 新增(适配 `shared/esign`) | | `shared/fadada/*` 或 `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` | `sign_platform` + `fadada` | | `container/container.go` | 注册 Provider + Registry | ### 前端(tyapi-frontend) | 文件 | 改动类型 | |------|----------| | `pages/certification/index.vue` | 审核通过后静默 select;步骤映射 | | `pages/certification/components/PlatformSelect.vue` | 预留(多可见平台) | | `pages/certification/IframeCallback.vue` | 支持多平台 callback path | | `src/api/index.js` | 新增 API | | `src/router/index.js` | 扩展 callback 路由 | | `pages/admin/certification-reviews/index.vue` | 展示 / 可选重置 sign_platform | --- ## 13. 总结 本次改造的核心不是「立刻砍掉 e签宝」,而是: 1. **主表增加 `sign_platform`**,区分存量 e签宝与新用户法大大 2. **抽象 `SignPlatformProvider`**,e签宝现网实现迁入/适配为 Provider 3. **审核通过后确认平台再发链接**;本期通过配置 **前端隐藏 e签宝 + 自动法大大**,用户无感多一步 4. **新增法大大 Provider**,与 e签宝并行于后端 对存量 e签宝用户零影响;新用户只走法大大;后续若要双平台可选,只需把 `esign` 加入 `visible` 并启用 `PlatformSelect`。 --- ## 14. 待你拍板后再改代码的事项 确认本方案后,建议按下列顺序开工(仍等你明确说「开始改代码」): 1. Phase 0:法大大账号与天远模板是否已就绪? 2. Phase 1:是否先只做抽象 + e签宝 Provider 回归,再看法大大? 3. 迁移策略是否采用 **3.4 推荐(只刷存量链路)**? 4. 回调域名是否继续用 `console.tianyuanapi.com`? *文档已按 tyapi 现状与「e签宝前端隐藏」决策修订;确认后进入开发。* )