Files
hyapi-server/docs/企业入驻-e签宝功能分析.md
2026-07-21 15:53:29 +08:00

444 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 企业入驻 × e签宝 功能分析
> 文档基于 `hyapi-server` 与 `hyapi-consoleweb` 代码梳理最后更新2026-07-13
## 1. 功能概述
企业入驻是独立的**认证域certification**,通过自研 Go SDK`internal/shared/esign`)对接 e签宝 OpenAPI引导企业用户完成
1. 填写并提交企业信息(含人工审核)
2. e签宝机构实名认证
3. 基于模板生成合作协议并电子签署
4. 入驻完成激活钱包、API 用户等)
**核心实现文件:**
| 层级 | 路径 |
|------|------|
| 业务编排 | `internal/application/certification/certification_application_service_impl.go` |
| 状态机实体 | `internal/domains/certification/entities/certification.go` |
| e签宝 SDK | `internal/shared/esign/` |
| HTTP 路由 | `internal/infrastructure/http/routes/certification_routes.go` |
| 前端主流程 | `hyapi-consoleweb/src/pages/certification/` |
---
## 2. 涉及数据表
表结构通过 GORM `AutoMigrate` 自动创建(`internal/app/app.go`),无独立 SQL migration。
### 2.1 认证域(核心)
#### `certifications` — 认证主表(聚合根)
每个用户最多一条认证记录(`user_id` 唯一),贯穿全流程并存储 e签宝 关键 ID/链接。
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | varchar(64) | 认证申请 ID |
| `user_id` | varchar(36) | 用户 ID唯一 |
| `status` | varchar(50) | 认证状态(见第 3 节) |
| `info_submitted_at` | datetime | 企业信息审核通过时间 |
| `enterprise_verified_at` | datetime | e签宝 企业认证完成时间 |
| `contract_applied_at` | datetime | 申请签署时间 |
| `contract_signed_at` | datetime | 签署完成时间 |
| `completed_at` | datetime | 入驻完成时间 |
| `contract_file_created_at` | datetime | 合同文件生成时间(用于 50 分钟过期判断) |
| `auth_flow_id` | varchar(500) | e签宝 企业认证流程 ID |
| `auth_url` | varchar(500) | e签宝 企业认证页面链接 |
| `contract_code` | varchar(100) | 合作协议编号(如 `HYDATA-20260713-R123456` |
| `contract_file_id` | varchar(500) | e签宝 合同文件 ID |
| `esign_flow_id` | varchar(500) | e签宝 签署流程 ID |
| `contract_url` | varchar(500) | 合同预览/下载 URL |
| `contract_sign_url` | varchar(500) | 合同签署链接 |
| `failure_reason` / `failure_message` | varchar/text | 失败原因与详情 |
| `retry_count` | int | 重试次数(上限 3 |
| `last_transition_*` | — | 状态转换审计字段 |
#### `enterprise_info_submit_records` — 企业信息提交与人工审核
用户每次提交企业信息时写入,承载审核材料与审核结果。
| 字段分组 | 主要字段 | 说明 |
|----------|----------|------|
| 企业四要素 | `company_name``unified_social_code``legal_person_*``enterprise_address` | 企业基本信息 |
| 授权代表 | `authorized_rep_name/id/phone``authorized_rep_id_image_urls` | 授权代表信息(身份证图片为 JSON 数组) |
| 资质材料 | `business_license_image_url``office_place_image_urls``api_usage``scenario_attachment_urls` | 营业执照、办公场地、业务场景说明及附件 |
| 前置校验 | `status` | `submitted` / `verified` / `failed`(西部数据三真等) |
| 人工审核 | `manual_review_status` | `pending` / `approved` / `rejected` |
| 审核人 | `manual_reviewer_id``manual_review_remark``manual_reviewed_at` | 管理员审核信息 |
#### `esign_contract_generate_records` — 合同生成记录
| 字段 | 说明 |
|------|------|
| `certification_id``user_id` | 关联认证与用户 |
| `template_id` | e签宝 模板 ID |
| `contract_file_id``contract_url``contract_name` | 生成结果 |
| `status` | `success` / `failed` |
| `fill_time` | 填单时间 |
#### `esign_contract_sign_records` — 合同签署记录
| 字段 | 说明 |
|------|------|
| `esign_flow_id``contract_file_id` | e签宝 流程与文件 |
| `sign_url``sign_short_url` | 签署链接 |
| `signed_file_url` | 已签署文件 URL |
| `status` | `pending` / `signing` / `success` / `failed` / `expired` |
| `signer_name/phone/id_card` | 签署人信息 |
| `request_at``signed_at``expired_at` | 时间戳(默认 7 天过期) |
### 2.2 用户域(认证完成后写入)
#### `enterprise_infos` — 已认证企业信息
认证通过后从提交记录同步供充值、开票、API 调用等使用;与用户一对一。
| 字段 | 说明 |
|------|------|
| `user_id` | 用户 ID唯一索引 |
| `company_name` | 企业名称 |
| `unified_social_code` | 统一社会信用代码 |
| `legal_person_name/id/phone` | 法人信息 |
| `enterprise_address` | 企业地址 |
#### `contract_infos` — 已签署合同
签署完成后写入,一个企业可有多份合同。
| 字段 | 说明 |
|------|------|
| `enterprise_info_id``user_id` | 关联企业与用户 |
| `contract_code` | 合同编号(唯一) |
| `contract_name` | 合同名称 |
| `contract_type` | `cooperation`(入驻)/ `resign`(补签) |
| `contract_file_id` | e签宝 文件 ID |
| `contract_file_url` | 七牛云永久存储链接 |
### 2.3 入驻完成后关联表(非 e签宝 直接写入,但属完成动作)
| 表名 | 说明 |
|------|------|
| `wallets` | 创建用户钱包 |
| `api_users` | 创建 API 调用身份 |
| `users` | 标记用户已完成认证(`CompleteCertification` |
---
## 3. 认证状态机
```
pending
└─► info_pending_review提交企业信息等待人工审核
├─► info_rejected审核拒绝 / e签宝 认证失败)
└─► info_submitted审核通过持有 auth_url
└─► enterprise_verifiede签宝 机构实名成功,已生成合同)
└─► contract_applied已申请签署持有 contract_sign_url
├─► contract_signed ──► completed入驻完成
├─► contract_rejected拒签可重试
└─► contract_expired超时可重试
```
| 状态值 | 中文 | 进度 | 用户操作 |
|--------|------|------|----------|
| `pending` | 待认证 | 0% | 填写企业信息 |
| `info_pending_review` | 企业信息待审核 | 15% | 等待管理员 |
| `info_submitted` | 已提交企业信息 | 25% | 完成 e签宝 企业认证 |
| `enterprise_verified` | 已企业认证 | 50% | 申请签署合同 |
| `contract_applied` | 已申请签署 | 75% | 在 iframe 中签署 |
| `contract_signed` | 已签署合同 | 100% | 等待系统处理 |
| `completed` | 认证完成 | 100% | 可使用全部功能 |
| `info_rejected` | 企业信息被拒绝 | — | 修正后重新提交 |
| `contract_rejected` | 合同被拒签 | — | 重新申请 |
| `contract_expired` | 合同签署超时 | — | 重新申请 |
---
## 4. 主要业务流程
### 4.1 流程总览
```mermaid
flowchart TD
A[用户注册/登录] --> B[POST /enterprise-info 提交企业信息]
B --> C[短信验证 + 西部数据三真校验]
C --> D[状态: info_pending_review]
D --> E{管理员审核}
E -->|拒绝| F[info_rejected]
E -->|通过| G[调用 e签宝 /v3/org-auth-url]
G --> H[状态: info_submitted<br/>写入 auth_url]
H --> I[iframe 完成机构实名]
I --> J{确认方式}
J -->|回调 AUTH_PASS| K[enterprise_verified]
J -->|轮询 GET /details 或 POST /confirm-auth| K
K --> L[模板填单生成合同 PDF]
L --> M[POST /apply-contract 申请签署]
M --> N[状态: contract_applied]
N --> O[iframe 签署合同]
O --> P{确认方式}
P -->|POST /confirm-sign 轮询| Q[contract_signed → completed]
Q --> R[下载已签文件 → 七牛 → contract_infos]
R --> S[创建钱包 + API 用户]
```
### 4.2 步骤一:提交企业信息
**接口:** `POST /api/v1/certifications/enterprise-info`JWT + 日限流)
**处理逻辑(`SubmitEnterpriseInfo`**
1. 防重复:若已有 `info_pending_review` 记录则拒绝重复提交
2. 短信验证码校验(场景 `SMSSceneCertification`
3. 统一社会信用代码唯一性检查(`enterprise_infos` + `enterprise_info_submit_records`
4. 字段格式校验 + **西部数据三真**`ValidateWithWestdex`
5. 写入 `enterprise_info_submit_records`(状态 `verified`
6. 认证状态转为 `info_pending_review`
7. 企业微信通知管理员待审核
> **此阶段不调用 e签宝。**
**辅助接口:**
- `POST /ocr/business-license` — 营业执照 OCR
- `POST /upload` — 认证材料上传七牛云
### 4.3 步骤二:管理员人工审核
**接口:**
- `GET /api/v1/certifications/admin/submit-records` — 列表
- `GET /api/v1/certifications/admin/submit-records/:id` — 详情
- `POST /api/v1/certifications/admin/submit-records/:id/approve` — 通过
- `POST /api/v1/certifications/admin/submit-records/:id/reject` — 拒绝
**审核通过(`AdminApproveSubmitRecord`**
1. 调用 `esignClient.GenerateEnterpriseAuth()` → e签宝 `POST /v3/org-auth-url`
2. 若企业已在 e签宝 实名(错误含「已实名」),则 `QueryOrgIdentityInfo` 后直接 `completeEnterpriseVerification`
3. 否则状态 → `info_submitted`,写入 `auth_flow_id``auth_url`
4. 提交记录 `manual_review_status``approved`
**经办人信息:** 当前使用**法人**作为 e签宝 经办人(`TransactorName = LegalPersonName`),未使用授权代表字段。
### 4.4 步骤三e签宝 企业实名认证
**前端:** `EnterpriseVerify.vue` 通过 iframe 加载 `metadata.auth_url`
**完成确认(双路径):**
| 路径 | 触发 | 处理 |
|------|------|------|
| 服务端回调 | `POST /api/v1/certifications/callbacks/esign``action=AUTH_PASS``authType=ORG` | `HandleEsignCallback``completeEnterpriseVerification` |
| 前端轮询 | `GET /details``POST /confirm-auth` | 查询 `GET /v3/organizations/identity-info``realnameStatus==1` 时推进 |
**Redirect** 用户完成后跳转 `auth.redirect_url`(如 `/certification/callback/auth``IframeCallback.vue` 通过 `postMessage` 通知父页面刷新状态。
**`completeEnterpriseVerification` 动作:**
1. 状态 → `enterprise_verified`
2. 企业信息写入 `enterprise_infos`
3. 调用 `FillTemplate` 填控件生成合同(见 4.5
4. 保存 `contract_file_id``contract_url``contract_code`
### 4.5 步骤四:生成合作协议
**e签宝 API** `POST /v3/files/create-by-doc-template`
**模板控件映射:**
| 控件 key | 填入内容 |
|----------|----------|
| `jfqym` / `jfqym2` | 企业名称 |
| `jfsqdb` | 授权代表姓名(无则用法人的) |
| `jftyshxydm` | 统一社会信用代码 |
| `jflxdz` | 企业地址 |
| `xybh` | 协议编号 |
| `qsrq1` / `qsrq2` / `qsrq3` | 签署日期 |
**合同编号规则:** `HYDATA-YYYYMMDD-R{6位随机数}`R = 入驻)
**过期策略:** 合同文件生成后 **50 分钟**过期,`GET /details` 时会自动重新生成(`IsContractFileNeedUpdate`)。
### 4.6 步骤五:申请并签署合同
**接口:** `POST /api/v1/certifications/apply-contract`
**前置条件:** 状态为 `enterprise_verified`
**处理逻辑:**
1. `CreateSignFlow``POST /v3/sign-flow/create-by-file`(甲方手动签 + 乙方自动盖章)
2. `GetSignURL``POST /v3/sign-flow/{id}/sign-url`
3. 状态 → `contract_applied`,保存 `esign_flow_id``contract_sign_url`
**签署确认:**
- 前端 iframe 加载 `contract_sign_url`,完成后 redirect 到 `sign.redirect_url`
- `POST /confirm-sign``GET /details` 轮询 `QuerySignFlowDetail`
**签署状态码(业务使用):**
| SignFlowStatus | 含义 | 系统动作 |
|----------------|------|----------|
| `2` | 签署完成 | → `contract_signed``completed` |
| `7` | 拒签 | → `contract_rejected` |
| `5` | 过期 | → `contract_expired` |
| 其他 | 签署中 | 继续轮询 |
### 4.7 步骤六:入驻完成
**`handleContractAfterSignComplete`**
1. `DownloadSignedFile` 从 e签宝 下载已签 PDF
2. 上传七牛云获取永久 URL
3. 写入 `contract_infos`
4. `completeUserActivationWithoutContract`
- 创建 `wallets`
- 创建 `api_users`
- 用户域标记认证完成
- 企业微信通知「企业认证成功」
---
## 5. API 端点汇总
### 5.1 本系统 REST API
前缀:`/api/v1/certifications`
| 方法 | 路径 | 认证 | 说明 |
|------|------|------|------|
| GET | `/details` | JWT | 获取/创建认证详情,自动同步 e签宝 状态 |
| POST | `/enterprise-info` | JWT + 日限流 | 提交企业信息 |
| POST | `/ocr/business-license` | JWT | 营业执照 OCR |
| POST | `/upload` | JWT | 认证材料上传 |
| POST | `/confirm-auth` | JWT | 轮询确认企业实名 |
| POST | `/apply-contract` | JWT | 申请合同签署 |
| POST | `/confirm-sign` | JWT | 轮询确认签署状态 |
| POST | `/callbacks/esign` | 无 | e签宝 服务端回调 |
| GET | `` | JWT 管理员 | 认证列表 |
| POST | `/admin/complete-without-contract` | 管理员 | 跳过合同直接完成认证 |
| POST | `/admin/transition-status` | 管理员 | 手动变更状态 |
| GET/POST | `/admin/submit-records[...]` | 管理员 | 提交记录 CRUD + 审核 |
### 5.2 e签宝 OpenAPISDK 封装)
| 方法 | 路径 | 用途 |
|------|------|------|
| POST | `/v3/org-auth-url` | 获取机构认证页面链接 |
| GET | `/v3/organizations/identity-info` | 查询机构是否已实名 |
| POST | `/v3/files/create-by-doc-template` | 模板填单生成 PDF |
| POST | `/v3/sign-flow/create-by-file` | 创建签署流程 |
| POST | `/v3/sign-flow/{id}/sign-url` | 获取签署链接 |
| GET | `/v3/sign-flow/{id}/detail` | 查询签署状态 |
| GET | `/v3/sign-flow/{id}/file-download-url` | 下载已签署文件 |
### 5.3 前端路由
| 路由 | 说明 |
|------|------|
| `/profile/certification` | 企业入驻主流程5 步) |
| `/certification/callback/auth` | e签宝 认证完成 redirect |
| `/certification/callback/sign` | e签宝 签署完成 redirect |
| `/admin/certification-reviews` | 管理端审核列表 |
---
## 6. e签宝 配置项
配置文件:`config.yaml` / `configs/env.{development,production}.yaml`
```yaml
esign:
app_id: "..." # 应用 ID
app_secret: "..." # 应用密钥API 签名)
server_url: "..." # 沙箱: https://smlopenapi.esign.cn
# 生产: https://openapi.esign.cn
template_id: "..." # 合作协议模板 ID
contract:
name: "海宇数据-合作协议"
expire_days: 7 # 签署链接有效期(天)
retry_count: 3
auth:
org_auth_modes: ["PSN_MOBILE3"]
default_auth_mode: "PSN_MOBILE3"
psn_auth_modes: ["PSN_MOBILE3", "PSN_IDCARD"]
willingness_auth_modes: ["CODE_SMS"]
redirect_url: "https://console.haiyudata.com/certification/callback/auth"
sign:
auto_finish: true
sign_field_style: 1
client_type: "ALL"
redirect_url: "https://console.haiyudata.com/certification/callback/sign"
```
Go 结构:`config.EsignConfig` → 注入为 `esign.Config``container.go`)。
---
## 7. 架构与代码组织
```
hyapi-server/
├── internal/
│ ├── application/certification/ # 应用服务(主业务编排)
│ ├── domains/certification/ # 领域模型、状态机、枚举
│ ├── domains/user/entities/ # enterprise_infos, contract_infos
│ ├── infrastructure/
│ │ ├── http/handlers/certification_handler.go
│ │ ├── http/routes/certification_routes.go
│ │ └── database/repositories/certification/
│ └── shared/esign/ # e签宝 SDK
│ ├── client.go # 统一入口
│ ├── orgauth_service.go # 机构认证
│ ├── org_identity.go # 实名查询
│ ├── template_service.go # 模板填单
│ ├── signflow_service.go # 签署流程
│ └── fileops_service.go # 文件下载/状态查询
hyapi-consoleweb/
└── src/pages/certification/
├── index.vue # 主流程容器
├── IframeCallback.vue # e签宝 redirect 回调
└── components/
├── EnterpriseInfo.vue # 填写企业信息
├── ManualReviewPending.vue # 人工审核等待
├── EnterpriseVerify.vue # e签宝 认证 iframe
├── ContractPreview.vue / ContractSign.vue
└── CertificationComplete.vue
```
---
## 8. 注意事项与已知问题
1. **回调验签未启用**
`HandleEsignCallback` 中 `esign.VerifySignature` 已被注释,生产环境存在安全风险。
2. **遗留代码未接入**
`internal/infrastructure/external/esign/certification_esign_service.go` 为模拟实现,未注册到 DI`CertificationWorkflowOrchestrator` 部分方法为 stub。
3. **双路径状态同步**
企业认证支持「e签宝 回调」与「前端轮询」两条路径;合同签署主要依赖 `confirm-sign` / `GET /details` 主动查询,回调仅处理 `AUTH_PASS`。
4. **经办人默认法人**
生成认证链接时经办人使用法人信息,授权代表字段仅用于合同模板 `jfsqdb` 控件。
5. **签署状态码注释不一致**
SDK 注释与业务代码对 `SignFlowStatus` 的含义存在差异,排查问题时以 `checkAndUpdateSignStatus` 中的判断为准(`2`=成功,`7`=拒签,`5`=过期)。
6. **与 API 实名产品无关**
`IVYZSQ0E` / `IVYZFO5K` 等数据 API 的身份证实名校验属于 API 调用产品,与本入驻流程无关。
---
## 9. 入驻完成后的系统能力
认证状态为 `completed` 后,用户可使用:
- 钱包充值(`Wallet.vue`
- 开票申请(`Invoice.vue`
- API 调用(需 `api_users`
- IP 白名单等需认证页面(`useCertification` / `CertificationBanner` 检查 `isCertified`