diff --git a/docs/architecture/详细设计/供应商招标报名模块.md b/docs/architecture/详细设计/供应商招标报名模块.md new file mode 100644 index 0000000..0a41895 --- /dev/null +++ b/docs/architecture/详细设计/供应商招标报名模块.md @@ -0,0 +1,232 @@ +# 供应商招标报名模块 + +## 总体流程概述 + +供应商从获知招标公告到完成报名并获取投标资格,涉及**公告浏览 → 身份认证 → 报名申请 → 资质审核 → 费用缴纳 → 文件获取 → 投标文件上传**七大环节。本设计覆盖全流程的**页面交互**、**系统跳转**与**内部处理逻辑**,并充分复用现有 SRM 供应商库与统一认证体系。 + +## 页面流转与跳转设计 + +```mermaid +graph TD + A[招标公告详情页] -->|点击“立即报名”| B{登录检查} + B -->|未登录| C[登录/注册选择页] + C -->|选择“STP账号登录”| D[STP登录表单] + C -->|选择“SRM账号登录”| E[SRM登录表单(无感验证)] + D --> F[验证通过 → 跳转报名页] + E -->|调用SRM验证接口| F + C -->|选择“新用户注册”| G[注册表单] + G -->|提交注册| H[注册成功 → 自动登录 → 跳转报名页] + F --> I[报名信息填写页] + I -->|填写基本信息+上传资质| J[预览确认页] + J -->|提交| K[报名提交成功页(等待审核)] + K -->|审核通过(邮件通知)| L[缴费通知页] + L -->|选择支付方式| M[在线支付/上传凭证] + M -->|支付完成| N[缴费确认中] + N -->|财务确认到账| O[招标文件下载页] + O -->|下载文件| P[投标文件上传页] + P -->|加密上传| Q[上传成功页] + Q -->|等待开标| R[我的项目列表(状态已报名)] + + style A fill:#fce4ec,stroke:#c2185b,stroke-width:2px + style K fill:#e8f5e9,stroke:#388e3c + style Q fill:#e8f5e9,stroke:#388e3c + style R fill:#e3f2fd,stroke:#1565c0 +``` + + +## 系统交互时序图 + +```mermaid +sequenceDiagram + participant U as 供应商浏览器 + participant STP as STP平台 + participant SRM as SRM系统 + participant OA as OA审批 + participant Pay as 支付网关 + participant AI as AI审核服务 + + U->>STP: 访问招标公告页面 + STP-->>U: 展示公告内容 + U->>STP: 点击“报名” + STP-->>U: 检测未登录,跳转登录页 + U->>STP: 选择“使用SRM账号登录” + STP->>SRM: POST /api/v1/auth/login/for-stp {username, password} + SRM-->>SRM: 验证账号密码 + SRM-->>STP: 200 { srmId, name, taxId, ... } + STP-->>STP: 建立本地会话,关联SRM ID + STP-->>U: 自动跳转至报名页 + + U->>STP: 填写报名表单 + 上传资质文件 + STP->>AI: 启动AI初审(资质/风险/关联) + AI-->>STP: 初审意见(通过/警告/不通过) + alt 需要人工评审 + STP->>STP: 生成待办任务 + STP-->>U: 进入人工评审阶段 + STP->>OA: 通知评审人员(站内/邮件) + OA-->>STP: 评审完成回调 + else AI直接通过 + STP-->>STP: 报名状态更新为“审核通过” + end + STP-->>U: 发送审核结果通知(邮件+站内信) + + U->>STP: 查看缴费通知 + STP-->>U: 展示缴费金额及支付方式 + U->>Pay: 在线支付 / 上传银行凭证 + Pay-->>STP: 异步通知支付结果(或凭证待确认) + STP->>OA: 发起财务确认审批(含凭证) + OA-->>STP: 审批通过(确认到账) + STP-->>U: 解锁招标文件下载权限 + + U->>STP: 下载招标文件 + STP-->>U: 返回文件(加水印/加密) + U->>STP: 加密上传投标文件 + STP->>STP: 文件哈希存证(区块链/哈希链) + STP->>SRM: 记录供应商投标状态(可选) + STP->>Archive: 归档报名材料 + STP-->>U: 投标成功 +``` + + +## 页面原型设计 + +下面以**报名信息填写页**为例,展示核心表单与操作区。 + +```svg + + + + + + + 智慧招标平台 + 欢迎,XX科技公司 + + 退出 + + + + ① 阅读公告 + ② 报名信息 + ③ 资质审核 + ④ 缴纳费用 + ⑤ 投标文件 + + + + + + + + + + 报名信息填写 + 项目:2026年生产用原材料采购(标段A) + + + + 联系人姓名 * + + 请输入联系人 + + 手机号 * + + 请输入手机号 + + 投标标段(可多选) + + ☑ 标段A ☐ 标段B ☐ 标段C + + 上传营业执照 * + + 点击或拖拽上传(支持 PDF/JPG,≤10MB) + 已上传:0个文件 + + 业绩证明材料(可选) + + 点击上传合同/业绩报告 + + + + 返回 + + 提交报名 + + * 提交后不可修改,请仔细核对 + + + + + + + + +``` + + +## 状态机与内部处理逻辑 + +| 状态码 | 状态名称 | 描述 | 触发动作 | +| -------------------- | ------ | ------------------- | --------------------- | +| `DRAFT` | 草稿 | 供应商正在填写报名表单,尚未提交 | 保存草稿,允许修改 | +| `PENDING_REVIEW` | 待审核 | 提交报名后,等待AI初审或人工评审 | 触发AI审核;若需人工,则生成评审任务 | +| `AI_PASS` | AI自动通过 | 资质齐全,无风险,直接通过 | 发送审核通过通知,生成缴费单 | +| `MANUAL_REVIEW` | 人工评审中 | 需采购部门/供应商管理专员人工确认 | 推送待办至相关人员,超时催办 | +| `REJECTED` | 审核不通过 | 资质不符或存在风险,被驳回 | 发送拒绝原因,允许重新提交(在报名截止前) | +| `PENDING_PAYMENT` | 待缴费 | 审核通过,等待缴纳标书费/保证金 | 生成缴费单,发送缴费通知 | +| `PAYMENT_CONFIRMING` | 缴费确认中 | 供应商已上传凭证,等待财务确认 | 发起OA审批,财务确认到账 | +| `PAYMENT_FAILED` | 缴费失败 | 超时未缴或财务确认为未到账 | 取消报名资格,释放名额 | +| `PAID` | 已缴费 | 缴费成功,招标文件已解锁 | 开放文件下载权限,记录缴费信息 | +| `BID_SUBMITTED` | 已投标 | 投标文件加密上传完成 | 存证哈希,报名流程结束 | +| `CANCELLED` | 已取消 | 供应商主动取消报名,或项目废标导致失效 | 退回保证金(如有),归档取消记录 | + +## 关键业务规则与异常处理 + +| 场景 | 处理方式 | +| ------------------------ | ------------------------------------------------------------------ | +| **标书费/保证金支付超时** | 系统在截止时间前24h/12h/1h 三级催办;超时自动取消报名资格并释放名额。 | +| **同一供应商重复报名** | 系统检测到同一税号或统一信用代码的供应商已报名,提示“已报名,不能重复提交”。 | +| **资质文件大小/格式不符** | 前端限制 + 后端二次校验,不符合时返回明确错误提示。 | +| **报名截止时间已过** | 按钮置灰,提示“报名已截止”,不允许新提交。 | +| **==联合体投标(待确定,留扩展接口)==** | 允许在报名时添加联合体成员(需分别提供资质),系统自动校验成员关联关系。 | +| **无感登录票据过期** | 跳转时若票据超时,提示“登录状态已过期,请重新登录”,跳转至登录页。 | +| **财务确认超时** | 系统自动催办财务审批人;若超时,支持招标专员手动确认(需备注理由)。 | +| **==投标文件加密方式(待确定)==** | 沿用系统统一加密方案(平台端加解密),同时为供应商提供“个人加密”选项(开关),若选个人加密则生成独立密钥,开标时需供应商在线解密。 | + +## 通知与提醒策略 + +| 触发事件 | 通知方式 | 接收方 | +| --------------- | ----------------- | ----- | +| 审核通过/不通过 | 站内信 + 邮件 | 供应商 | +| 缴费提醒(含截止时间) | 站内信 + 邮件 + 短信(可选) | 供应商 | +| 财务确认到账 | 站内信 | 供应商 | +| 招标文件可下载 | 站内信 + 邮件 | 供应商 | +| 投标截止前24h/1h | 站内信 + 邮件 | 供应商 | +| 人工评审任务待办 | 站内信 + 邮件 | 评审人员 | +| 财务审批待办 | 站内信 + 邮件 | 财务人员 | +| 系统异常告警(支付回调失败等) | 飞书/短信 | 系统管理员 | + +## 性能与安全要求 + +- **并发报名**:支持单项目100+供应商同时报名,响应时间≤3秒。 + +- **文件上传**:支持断点续传,单个文件≤500MB,总大小≤2GB。 + +- **数据加密**:报名表单中的联系人手机号、身份证号采用字段级加密存储 + +- **防机器人**:报名提交时增加图形验证码或行为验证,防止恶意刷单。 + +- **日志审计**:所有报名操作(登录、提交、审核、缴费)均记录审计日志,保留≥7年。 + +## 附录:报名表单字段定义 + +| 字段名 | 类型 | 必填 | 说明 | +| --------------------- | ------ | --- | --------------------------------- | +| `projectId` | String | 是 | 招标项目ID,自动带入 | +| `bidSection` | Array | 是 | 投标标段(多选) | +| `contactName` | String | 是 | 联系人姓名 | +| `contactPhone` | String | 是 | 手机号,需短信验证(可选) | +| `contactEmail` | String | 是 | 邮箱 | +| `qualificationFiles` | Array | 是 | 资质文件列表(营业执照、资质证书、授权书等),每个文件需有类型标签 | +| `performanceFiles` | Array | 否 | 业绩证明文件 | +| `jointVentureMembers` | Array | 否 | 联合体成员列表(供应商ID+名称+税号) | +| `remarks` | String | 否 | 备注 | diff --git a/docs/architecture/详细设计/供应商注册模块.md b/docs/architecture/详细设计/供应商注册模块.md new file mode 100644 index 0000000..d1afbb2 --- /dev/null +++ b/docs/architecture/详细设计/供应商注册模块.md @@ -0,0 +1,1074 @@ +# 智慧招标平台(STP)供应商注册模块详细设计说明书 + +| 文档名称 | 供应商注册模块详细设计说明书 | +| :------- | :--------------------------------- | +| **文档版本** | V1.0 | +| **编制日期** | 2026-06-30 | +| **关联文档** | 《需求分析说明书 V1.4》《供应商报名详细设计》《SRM接口方案》 | + + +## 目录 +1. [模块概述](#1-模块概述) +2. [用户角色与权限](#2-用户角色与权限) +3. [页面UI详细设计](#3-页面ui详细设计) +4. [字段级校验规则](#4-字段级校验规则) +5. [AI自动审核详细设计](#5-ai自动审核详细设计) +6. [完整业务流程(含状态机)](#6-完整业务流程含状态机) +7. [时序图(含外部系统交互)](#7-时序图含外部系统交互) +8. [数据模型完整定义](#8-数据模型完整定义) +9. [API接口详细规范](#9-api接口详细规范) +10. [业务规则与约束](#10-业务规则与约束) +11. [异常处理矩阵](#11-异常处理矩阵) +12. [通知策略](#12-通知策略) +13. [SRM双向同步机制](#13-srm双向同步机制) +14. [供应商联系人变更(注册后维护)](#14-供应商联系人变更注册后维护) +15. [安全与合规](#15-安全与合规) +16. [附录](#16-附录) + +--- + +## 1. 模块概述 + +### 1.1 建设目标 +建立面向潜在投标供应商的**轻量化、全自动、即时生效**的注册机制。注册阶段仅做**主体身份认证**(营业执照有效性核验),不进行人工资格审核。通过即开通平台登录权限和投标报名资格,**深度资质审核后移至投标报名环节按项目要求执行**。 + +### 1.2 核心设计理念:注册与审核分离 + +| 阶段 | 审核内容 | 审核方式 | 通过标准 | +| :--- | :--- | :--- | :--- | +| **注册阶段** | 营业执照有效性、企业存续状态、基础信息一致性、严重违法筛查 | **全自动AI**(无人工) | 所有一票否决项通过 | +| **投标报名阶段** | 项目特定资质、业绩、财务能力、技术能力 | AI初审 + 人工复核 | 满足具体项目资格要求 | + +### 1.3 设计原则 +- **极简快速**:提交即审核,5秒内出结果,无等待队列。 +- **AI全自动**:OCR + 工商API + 风险图谱全链路自动化。 +- **一次注册,双平台通用**:自动同步至SRM,建立统一供应商身份(`srm_id`双向绑定)。 +- **审核后置**:深度资质审核下沉至报名环节,降低准入门槛。 +- **安全合规**:敏感字段(信用代码、手机号)AES-256-GCM加密存储,全量审计。 + +### 1.4 适用范围 +- **适用对象**:所有拟参与滨化集团招标项目的潜在供应商(含工程、货物、服务类)。 +- **与SRM关系**:新供应商自动在SRM创建档案(状态:待认证);已存续SRM供应商通过“无感登录”直接绑定,无需重复注册。 + +--- + +## 2. 用户角色与权限 + +| 角色 | 权限范围 | +| :--- | :--- | +| **供应商申请人(未注册)** | 访问注册页面、提交申请、查看审核结果。 | +| **已注册供应商(ACTIVE)** | 登录平台、浏览公告、投标报名、维护企业信息(含联系人变更)。 | +| **供应商管理专员** | 查看注册统计、处理注册异常申诉、执行黑名单管理(冻结/解封)。 | +| **系统管理员** | 配置AI审核阈值、管理工商API密钥、查看系统日志。 | +| **合规/审计** | 查阅注册审计日志(只读)。 | + +--- + +## 3. 页面UI详细设计 + +### 3.1 注册步骤导航条 + +```svg + + + + + + 1 + 企业信息 + + + + 2 + 联系人 + + + + 3 + 提交/自动审核 + + + ⚡ AI即时审核 · 秒级通过 + +``` + +### 3.2 步骤一:企业信息 + +```svg + + + + + + + + + + + + + + + + + 供应商注册 + 请填写企业真实信息,上传营业执照,系统将自动识别并回填 + + + + + 📄 上传营业执照(JPG/PNG/PDF,≤10MB) + 支持拖拽或点击上传,AI 将自动识别企业信息并填充表单 + + + + ✅ 已识别:营业执照信息提取成功(统一信用代码:91370100XXXXXXXXXX) + + + + 企业全称 * + + 系统自动识别或手动输入 + + 统一社会信用代码 * + + 18位代码 + + + 注册资本(万元) * + + 数字 + + 法定代表人 * + + 姓名 + + 行业分类 * + + 请选择/输入行业 + + + 注册地址 * + + 请填写详细地址 + + + 经营范围 * + + 系统识别或手动输入,建议不超过200字 + + + 主要产品 * + + 如:工业阀门、管道 + + + 添加 + + + 工业阀门 ✕ + + 管道配件 ✕ + + + + + + 上一步 + + + 下一步 → + + + + 📌 注册须知 + 1. 请确保信息与营业执照一致 + 2. 统一社会信用代码将作为唯一标识 + 3. 提交后由供应商管理专员审核 + 4. 审核通过后可参与投标报名 + 5. 已有SRM账号请直接登录 + +``` + +**布局说明**:采用左右结构,左侧为表单(占比70%),右侧为“注册须知”浮窗(占比30%)。 + +**表单字段明细**(按顺序): + +| 字段 | 组件类型 | 占位提示 | 备注 | +| :----------- | :------- | :------------------------------- | :-------------------- | +| **营业执照上传** | 拖拽/点击上传区 | “点击或拖拽上传营业执照(JPG/PNG/PDF,≤10MB)” | **AI识别触发点**,上传即自动OCR | +| **企业全称** | 文本输入框 | “**系统自动识别**或手动输入” | 最大长度128字符 | +| **统一社会信用代码** | 文本输入框 | “18位统一社会信用代码”自动识别 | 自动转大写,格式校验 | +| **注册资本(万元)** | 数字输入框 | “请输入数字” | 保留2位小数,≥0 | +| **法定代表人** | 文本输入框 | “请输入法定代表人姓名” | 最大长度64字符 | +| **行业分类** | 下拉框+搜索 | “请选择或搜索行业” | 基于GB/T 4754-2017,三级分类 | +| **注册地址** | 文本输入框 | “请填写详细地址” | 最大长度256字符 | +| **经营范围** | 多行文本域 | “系统自动识别或手动输入,不超过500字” | 最大500字符 | +| **主要产品** | 标签输入组件 | “输入产品名称,回车添加” | 最多添加20个,每个≤30字符 | + +**OCR识别状态条**(实时反馈): +- 识别中:`⏳ 正在识别营业执照...` +- 成功:`✅ 识别完成,已自动回填以下字段:[企业全称]、[信用代码]、[法人]、[地址]、[经营范围]` +- 失败:`❌ 识别失败,请手动填写(或检查图片是否清晰)` + +### 3.3 步骤二:联系人信息 + +```svg + + + + + + + + + + + + + + + + + + + + + + + + 联系人信息 + + + 联系人姓名 + * + + 请输入联系人姓名 + 必填,最大64字符 + + + 联系电话 + * + + + 13800138000 + 必填,格式校验,全局唯一 + + + 电子邮箱 + * + + 请输入常用邮箱 + 必填,格式校验,全局唯一 + + + 短信验证码 + * + + 点击发送验证码 + + 发送验证码 + 用于验证手机号真实性(注册必验) + + + 输入密码 + + + + + + + + + + + + + + + 确认密码 + + + + + + + + + + + + + + + + 密码复杂度要求 + + + + 长度 8~20 位 + + + + 至少包含 1 个大写字母(A-Z)和 1 个小写字母(a-z) + + + + 至少包含 1 个数字(0-9)和 1 个特殊字符(!@#$%^&*()_+-=) + + + + 禁止连续/重复字符(如 12345678, aaaaaaaa) + + + + 禁止常见弱口令(内置弱密码字典) + + + 密码强度 + + + + + + + + + + + + + + + + + + + + + 提交 + + +``` + +| 字段 | 组件类型 | 占位提示 | 备注 | +| :------------ | :------- | :---------- | :--------------- | +| **联系人姓名** | 文本输入框 | “请输入联系人姓名” | 必填,最大64字符 | +| **联系电话(手机号)** | 文本输入框 | “请输入11位手机号” | 必填,格式校验,**全局唯一** | +| **电子邮箱** | 文本输入框 | “请输入常用邮箱” | 必填,格式校验,**全局唯一** | +| **短信验证码** | 输入框+发送按钮 | “点击发送验证码” | 用于验证手机号真实性(注册必验) | +| 输入密码 | 密码输入框 | | | +| 确认密码 | 密码输入框 | | | + +**密码复杂度要求**: +- 长度 8~20 位 +- 至少包含 1 个大写字母(A-Z) +- 至少包含 1 个小写字母(a-z) +- 至少包含 1 个数字(0-9) +- 至少包含 1 个特殊字符(!@#$%^&*()_+-=) +- 禁止使用连续/重复字符(如 `12345678`、`aaaaaaaa`) +- 禁止使用常见弱口令(内置弱密码字典,如 `password`、`admin123`) + + +**密码强度实时指示器**: + +- 弱(红色):< 3 项满足 +- 中(橙色):≥ 4 项满足 +- 强(绿色):全部满足 + 长度≥12 + +### 3.4 步骤三:SRM存量引导弹窗 + +**当检测到SRM存量时,弹出如下引导窗(模态框):** + +```svg + + + + + + + + 🔍 检测到SRM存量供应商 + 该企业已在SRM系统中注册,您可以选择: + + + 使用SRM账号登录 + + + 继续注册 + + 选择“继续注册”将跳过资质审核,直接绑定SRM账号 + 选择“登录”将跳转至登录页,使用SRM账号密码登录 + + + 取消 + +``` + +**选择“继续注册”后的处理**: + +- 前端重新提交注册请求,携带参数 `confirmSrmBinding: true`。 +- 后端跳过AI审核,直接创建STP账号并绑定SRM ID,返回成功(自动登录)。 + +**选择“使用SRM账号登录”**: + +- 前端跳转至登录页,并自动填充企业名称/信用代码(可选),引导用户使用SRM账号密码登录(利用统一登录接口)。 + +### 3.5 步骤四:提交 & 自动审核 + +**审核中(等待 3~8 秒)** : + +```svg + + + + + + + + + + + + ⏳ AI 正在审核企业信息... + 预计 3~8 秒,请勿关闭页面 + ✓ 工商信息核验 ✓ 风险扫描 ✓ 唯一性检查 + +``` + +**审核通过(自动登录跳转)** : + +```svg + + + + + + + + + + + + + + + 🎉 注册成功! + 您的供应商账号已激活,正在自动登录... + + + + 供应商编号:SUP_20260630_0158 + 登录账号:138****8001 + + + + 📌 温馨提示:参与具体项目投标时,需按招标公告要求提交资质审核材料 + +``` + +**审核不通过**: + +```svg + + + + + + + + + + 审核未通过 + + + + • 统一社会信用代码与工商登记信息不匹配 + • 企业状态为“注销”,不符合注册条件 + 💡 请核对信息后重新提交,如有疑问请联系客服 + + + + 修改后重新提交 + +``` + +--- + +## 4. 字段级校验规则(前后端双重校验) +|字段|前端校验|后端校验|错误码| +|---|---|---|---| +|**营业执照文件**|格式(JPEG/PNG/PDF)、大小≤10MB|文件病毒扫描、图片清晰度检测|`ERR_FILE_001`| +|**企业全称**|非空,长度≤128|与OCR结果一致性比对|`ERR_PARAM_001`| +|**统一社会信用代码**|非空,格式正则`^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$`,自动转大写|唯一性校验;与工商API比对|`ERR_PARAM_002` / `ERR_REG_002`| +|**注册资本**|数字,≥0,最多2位小数|数据类型校验|`ERR_PARAM_003`| +|**法定代表人**|非空,长度≤64|与OCR结果一致性比对|`ERR_PARAM_004`| +|**行业分类**|非空,必须为GB/T 4754叶子节点|枚举校验|`ERR_PARAM_005`| +|**注册地址**|非空,长度≤256|-|`ERR_PARAM_006`| +|**经营范围**|非空,长度≤500|-|`ERR_PARAM_007`| +|**主要产品**|数组非空,每个≤30字符,最多20个|-|`ERR_PARAM_008`| +|**联系人姓名**|非空,长度≤64|-|`ERR_PARAM_009`| +|**联系电话**|非空,格式`^1[3-9]\d{9}$`|唯一性校验(`contact_phone`不可重复)|`ERR_PARAM_010` / `ERR_REG_003`| +|**电子邮箱**|非空,邮箱格式正则|唯一性校验|`ERR_PARAM_011` / `ERR_REG_003`| +|**短信验证码**|非空,6位数字|匹配Redis缓存,有效期5分钟|`ERR_AUTH_001`| +|**登录密码**|非空,长度8-20|强度校验(大小写+数字+特殊字符+弱口令字典)|`ERR_PARAM_012`| +|**确认密码**|非空,与密码一致|与密码字段比对|`ERR_PARAM_013`| + +--- + +## 5. AI自动审核详细设计 + +### 5.1 审核前置:SRM存量检查 + +```mermaid +graph TD + A[接收注册请求] --> B{请求中是否包含
confirmSrmBinding=true?} + B -->|是| C[跳过所有AI检查,直接执行SRM绑定流程] + B -->|否| D[调用SRM查询接口
根据信用代码查询供应商] + D --> E{SRM中存在?} + E -->|是| F[返回特殊错误码ERR_SRM_EXISTS
附带SRM供应商基本信息] + E -->|否| G[进入AI审核流程(原有7项检查)] + C --> H[创建STP供应商记录status=ACTIVE
绑定srm_id] + G --> I{综合仲裁} + I -->|通过| H + I -->|不通过| J[驳回] +``` + + +### 5.2 各项检查详细规则 + +| 检查项 | 调用源 | 通过条件 | 硬性拒绝条件 | 超时处理 | +| :------------- | :----------- | :----------------------- | :------------------------ | :--------------------- | +| **OCR完整性** | 内部OCR服务 | 成功提取「企业全称+信用代码+法人」 | 三项任一缺失 | 超时3s → 降级允许手动输入,但不自动通过 | +| **工商验真** | 天眼查/企查查API | 输入名称与信用代码匹配,且置信度≥95% | 不匹配 | 超时5s → 返回“服务繁忙,请稍后重试” | +| **企业存续状态** | 天眼查API | 状态为“存续(在营)” | 注销/吊销/清算 | 使用缓存数据(缓存≤24h) | +| **严重违法** | 国家企业信用信息公示系统 | 不在“严重违法失信名单” | 在名单中 | 若API不可用,默认通过(记录告警) | +| **经营异常** | 天眼查API | 不在“经营异常名录” | **不硬性拒绝**,仅标记 `risk_tags` | 若API不可用,默认无异常 | +| **信用代码唯一性** | 本地DB | 未注册(含ACTIVE/REJECTED/锁定) | 已存在(不论状态) | N/A | +| **手机号唯一性** | 本地DB | 未被其他ACTIVE供应商绑定 | 已绑定 | N/A | +| **SRM 存量供商应商** | | | | | +| | | | | | +### 5.3 SRM存量绑定跳过项 + +当 `confirmSrmBinding=true` 时,跳过以下检查: + +- OCR完整性 +- 工商验真 +- 企业状态 +- 严重违法 +- 经营异常 + +仍保留的检查: +- 信用代码唯一性(STP内) +- 手机号/邮箱唯一性 + + +### 5.3 综合仲裁逻辑(伪代码) + +```python +def audit_register(request): + results = parallel_run([ + ocr_check(request.file), + business_verify(request.credit_code, request.company_name), + status_check(request.credit_code), + fraud_check(request.credit_code), + exception_check(request.credit_code), + uniqueness_check(request.credit_code, request.phone, request.email) + ]) + + # 一票否决项 + fatal_checks = ['ocr', 'verify', 'status', 'fraud', 'uniqueness'] + for check in fatal_checks: + if not results[check].passed: + return reject(results[check].reason) + + # 经营异常仅标记,不阻止 + if results['exception'].has_exception: + mark_risk_tag(request.supplier_id, '经营异常') + + return approve() +``` + +--- + +## 6. 完整业务流程(含状态机) + +### 6.1 状态定义(精简) + +| 状态码 | 名称 | 说明 | 可执行操作 | +| :--- | :--- | :--- | :--- | +| `DRAFT` | 草稿 | 用户正在填写,尚未提交 | 编辑、提交 | +| `SUBMITTED` | 提交审核中 | AI正在执行检查(瞬时状态,<5s) | 无(轮询等待) | +| `ACTIVE` | 已激活/正常 | AI全部通过,可登录报名 | 登录、报名、修改信息、变更联系人 | +| `REJECTED` | 审核驳回 | 至少一项一票否决未通过 | 查看原因、修改后重新提交(30天内) | +| `LOCKED` | 已锁定 | 违规操作/被管理员冻结 | 联系管理员解封 | +| `ARCHIVED` | 已归档 | 长期未使用或主动注销 | 只读(不可登录) | + +### 6.2 状态流转图 + +```mermaid +stateDiagram-v2 + [*] --> DRAFT: 开始注册 + DRAFT --> SUBMITTED: 提交(不含SRM绑定确认) + SUBMITTED --> SRM_EXISTS: 检测到SRM存量(返回ERR_SRM_EXISTS) + SRM_EXISTS --> DRAFT: 用户取消/关闭弹窗 + SRM_EXISTS --> ACTIVE: 用户选择“继续注册”(带confirmSrmBinding=true) + SRM_EXISTS --> [*]: 用户选择“使用SRM账号登录”(跳转登录) + SUBMITTED --> ACTIVE: AI全部通过(新供应商) + SUBMITTED --> REJECTED: AI不通过 + REJECTED --> DRAFT: 修改重提 + ACTIVE --> LOCKED: 管理员冻结 + LOCKED --> ACTIVE: 解封 +``` + +> **注意**:由于审核是实时的,`SUBMITTED`状态在数据库层面几乎不持久化(前端展示加载态即可)。 + +### 6.3 完整业务流程 + +```mermaid +flowchart TD + subgraph 供应商端 + A[访问注册页] --> B[填写完整信息并提交] + B --> C[等待审核结果(3-8秒)] + C --> D{前端收到响应} + D -->|成功(新供应商通过)| E[显示成功页+自动登录] + D -->|错误码ERR_SRM_EXISTS| F[弹出SRM存量引导窗] + F --> G{用户选择} + G -->|“继续注册”| H[重新提交请求带confirmSrmBinding=true] + G -->|“使用SRM账号登录”| I[跳转登录页] + G -->|取消| J[返回注册页修改] + D -->|其他驳回| K[显示驳回原因+修改] + H --> L[立即成功+自动登录] + end +``` + +```mermaid +flowchart TD +subgraph STP后端 + STP1[接收注册请求] --> STP2{是否有confirmSrmBinding=true?} + STP2 -->|是| STP3[跳过AI审核,查询SRM获取srmId] + STP2 -->|否| STP4[调用SRM查询接口检测存量] + STP4 --> STP5{SRM存在?} + STP5 -->|存在| STP6[返回ERR_SRM_EXISTS(含srmId+名称)] + STP5 -->|不存在| STP7[执行AI审核(7项检查)] + STP7 --> STP8{AI通过?} + STP8 -->|通过| STP9[创建供应商status=ACTIVE] + STP8 -->|不通过| STP10[创建供应商status=REJECTED] + STP3 --> STP9 + STP9 --> STP11[创建用户账号+密码哈希] + STP11 --> STP12[生成JWT Token] + STP12 --> STP13[同步SRM(若已有srmId则更新绑定)] + STP13 --> STP14[发送成功通知] + STP10 --> STP15[发送驳回通知] + end + subgraph 外部系统 + EXT1[SRM查询接口] + EXT2[SRM注册/绑定接口] + EXT3[通知网关] + end + STP4 -.-> EXT1 + STP3 -.-> EXT2 + STP14 -.-> EXT3 +``` + +--- + +## 7. 时序图 + +```mermaid +sequenceDiagram + participant U as 供应商 + participant FE as 前端 + participant GW as API网关 + participant RegSvc as 注册服务 + participant AISvc as AI审核服务 + participant BizAPI as 天眼查API + participant SRM as SRM系统 + participant DB as STP数据库 + participant Notify as 通知服务 + + U->>FE: 填写完整信息(含密码)并提交 + FE->>GW: POST /register(无confirmSrmBinding) + GW->>RegSvc: 转发 + + RegSvc->>DB: 校验信用代码是否已在STP注册 + alt 已注册 + DB-->>RegSvc: 已存在 + RegSvc-->>FE: 409 ERR_REG_002(已注册) + else 未注册 + RegSvc->>SRM: GET /query/by-tax-id(查询存量) + SRM-->>RegSvc: 返回结果(存在或不存在) + alt SRM存在 + RegSvc-->>FE: 200 但 code=ERR_SRM_EXISTS,附带srmId和supplierName + FE-->>U: 弹出引导窗 + U->>FE: 点击“继续注册” + FE->>GW: POST /register + confirmSrmBinding=true + GW->>RegSvc: 转发(携带srmId) + RegSvc->>DB: 创建供应商 status=ACTIVE,绑定srmId + RegSvc->>RegSvc: 创建用户账号,密码哈希 + RegSvc->>RegSvc: 生成JWT Token + RegSvc->>Notify: 发送成功通知(无需激活) + RegSvc-->>FE: 200 成功 + accessToken + FE->>FE: 存储Token + FE-->>U: 自动跳转工作台 + else SRM不存在(新供应商) + RegSvc->>AISvc: 执行AI审核(7项并行) + AISvc->>BizAPI: 工商验真/状态/违法等 + BizAPI-->>AISvc: 结果 + AISvc-->>RegSvc: 审核结论 + alt 通过 + RegSvc->>DB: 创建供应商 status=ACTIVE + RegSvc->>RegSvc: 创建用户账号、生成Token + RegSvc->>SRM: POST /register(同步注册至SRM) + SRM-->>RegSvc: srmId + RegSvc->>DB: 更新srmId + RegSvc->>Notify: 发送成功通知 + RegSvc-->>FE: 200 成功 + Token + FE-->>U: 自动登录 + else 不通过 + RegSvc->>DB: 创建供应商 status=REJECTED + RegSvc->>Notify: 发送驳回通知 + RegSvc-->>FE: 400 失败(含原因) + FE-->>U: 显示驳回页 + end + end + end +``` + +--- + +## 8. 数据模型完整定义 + +### 8.1 供应商主表 `t_supplier_profile` + +| 字段名 | 类型 | 约束 | 说明 | +| ---------------------- | ------------- | ---------------- | -------------------------------------- | +| `id` | BIGINT | PK | 自增主键 | +| `supplier_id` | VARCHAR(32) | UNIQUE, NOT NULL | 业务编号 | +| `user_id` | VARCHAR(32) | INDEX | 关联用户账号 | +| `srm_id` | VARCHAR(32) | INDEX | SRM系统ID(存量绑定或新注册同步后回填) | +| `company_name` | VARCHAR(128) | NOT NULL | 企业全称 | +| `credit_code` | VARCHAR(128) | NOT NULL, UNIQUE | 信用代码(加密) | +| `credit_code_md5` | CHAR(32) | UNIQUE | MD5盲索引 | +| `registered_capital` | DECIMAL(15,2) | | 注册资本 | +| `legal_representative` | VARCHAR(64) | | 法定代表人 | +| `industry_code` | VARCHAR(16) | | 行业代码 | +| `industry_name` | VARCHAR(64) | | 行业名称 | +| `address` | VARCHAR(256) | | 注册地址 | +| `business_scope` | TEXT | | 经营范围 | +| `main_products` | JSON | | 主要产品 | +| `contact_name` | VARCHAR(64) | NOT NULL | 联系人姓名 | +| `contact_phone` | VARCHAR(128) | NOT NULL, UNIQUE | 手机号(加密) | +| `contact_phone_md5` | CHAR(32) | UNIQUE | MD5 | +| `contact_email` | VARCHAR(128) | NOT NULL | 邮箱 | +| `license_file_url` | VARCHAR(512) | | 营业执照URL | +| `license_ocr_result` | JSON | | OCR结果 | +| `audit_result` | JSON | | AI审核报告(新供应商) | +| **`source_type`** | VARCHAR(20) | NOT NULL | **NEW / SRM_BINDING**(标识注册来源) | +| **`srm_bind_time`** | DATETIME | | **SRM绑定时间(存量绑定)** | +| `status` | VARCHAR(20) | NOT NULL | DRAFT/SUBMITTED/ACTIVE/REJECTED/LOCKED | +| `risk_tags` | JSON | | 风险标签 | +| `reject_reasons` | JSON | | 驳回原因 | +| `activated_at` | DATETIME | | 激活时间(即注册成功时间) | +| `created_at` | DATETIME(3) | | 创建时间 | +| `updated_at` | DATETIME(3) | | 更新时间 | + +### 8.2 用户账号表 `t_user`(新增字段) + +| 字段名 | 类型 | 说明 | +| --------------- | ------------ | ----------- | +| `user_id` | VARCHAR(32) | PK | +| `supplier_id` | VARCHAR(32) | FK | +| `login_name` | VARCHAR(64) | UNIQUE(手机号) | +| `password_hash` | VARCHAR(128) | Argon2id哈希 | +| `user_type` | VARCHAR(20) | 'SUPPLIER' | +| `status` | VARCHAR(20) | 'ACTIVE' | +| `last_login_at` | DATETIME | | + +--- + +## 9. API接口详细规范 + +### 9.1 提交供应商注册(支持SRM存量检测) + +|项目|内容| +|---|---| +|**路径**|`/api/v1/supplier/register`| +|**方法**|`POST`| + +**请求体(第一次提交,无confirmSrmBinding)** + +```json +{ + "companyName": "滨化新材料有限公司", + "creditCode": "91370100MA3XXXXXXX", + "registeredCapital": 5000.00, + "legalRepresentative": "张伟", + "industryCode": "C2614", + "address": "山东省滨州市黄河五路888号", + "businessScope": "化工产品、新材料技术研发...", + "mainProducts": ["聚丙烯", "环氧丙烷"], + "contactName": "李强", + "contactPhone": "13800138001", + "contactEmail": "liqiang@example.com", + "licenseFileUrl": "https://oss.stp.com/xxx.pdf", + "smsCode": "123456", + "password": "Abcd@2026#", + "confirmPassword": "Abcd@2026#", + "agreeTerms": true +} +``` + +**特殊响应(检测到SRM存量)** + +```json +{ + "code": "ERR_SRM_EXISTS", + "message": "检测到该供应商已在SRM系统中注册", + "data": { + "srmId": "SRM_12345", + "companyName": "滨化新材料有限公司", + "creditCode": "91370100MA3XXXXXXX", + "hint": "您可以选择继续注册(跳过资质审核)或使用SRM账号登录" + } +} +``` + +**第二次提交(用户选择继续注册)** + +```json +{ + ...(同第一次请求), + "confirmSrmBinding": true, + "srmId": "SRM_12345" // 可选,后端也可再次查询 +} +``` + +**成功响应(无论新注册还是存量绑定,均一致)** + +```json +{ + "code": "0", + "data": { + "supplierId": "SUP_20260630_0158", + "srmId": "SRM_12345", + "userId": "U_...", + "status": "ACTIVE", + "accessToken": "eyJ...", + "tokenType": "Bearer", + "expiresIn": 1800, + "sourceType": "NEW" 或 "SRM_BINDING", + "message": "注册成功,账号已激活" + } +} +``` + +### 9.2 营业执照OCR(预填) + +| 项目 | 内容 | +| :--------- | :------------------------------------------------------------------------------------------------------------------------------------------------- | +| **路径** | `/api/v1/ocr/business-license` | +| **方法** | `POST` | +| **请求** | `multipart/form-data`,字段 `file` | +| **响应(成功)** | `{"code":"0","data":{"companyName":"...","creditCode":"...","legalPerson":"...","registeredCapital":"...","address":"...","businessScope":"..."}}` | +| **响应(失败)** | `{"code":"ERR_OCR_001","message":"图片识别失败,请确认图片清晰"}` | + +### 9.3 发送短信验证码 + +| 项目 | 内容 | +| :--- | :--- | +| **路径** | `/api/v1/auth/sms/send` | +| **方法** | `POST` | +| **请求** | `{"phone":"13800138000","captchaToken":"图形验证码"}` | +| **响应** | `{"code":"0","data":{"expireSeconds":300,"resendAfterSeconds":60}}` | + +**其他错误码** +- `ERR_REG_002`:信用代码已注册(409) +- `ERR_REG_003`:手机号已被占用(409) +- `ERR_REG_004`:邮箱已被占用(409) +- `ERR_REG_005`:短信验证码错误或过期(401) +- `ERR_REG_006`:工商API服务繁忙,请稍后重试(503) + +### 9.4 首次登录激活(设置密码) + +| 项目 | 内容 | +| :--- | :--- | +| **路径** | `/api/v1/supplier/activate` | +| **方法** | `POST` | +| **请求** | `{"supplierId":"SUP_...","password":"Abcd@1234","confirmPassword":"Abcd@1234"}` | +| **成功** | `{"code":"0","message":"激活成功"}` | + +--- + +## 10. 业务规则与约束 + +| ID | 规则 | 说明 | +| --- | ---------------- | ------------------------------------------------------- | +| R01 | **信用代码唯一性** | 无论来源,STP内信用代码唯一。 | +| R02 | **SRM存量检测优先** | 每次注册请求首先查询SRM,除非已带`confirmSrmBinding`参数。 | +| R03 | **存量绑定跳过AI** | 当`confirmSrmBinding=true`时,跳过OCR、工商验真、状态、违法检查,仅保留唯一性校验。 | +| R04 | **存量绑定的SRM账号状态** | 不要求SRM账号必须激活,只要存在记录即可绑定。 | +| R05 | **密码设置要求** | 存量绑定同样需要设置密码(与正常注册相同)。 | +| R06 | **存量绑定后SRM同步** | 若srmId已存在,则无需再次调用SRM注册接口,只需在STP记录绑定关系。若srmId为空(异常),需补录。 | +| R07 | **引导弹窗后取消** | 用户取消则回到注册页,可修改信息后再次提交(会再次触发SRM检测)。 | +| R08 | **重复检测** | 若STP已存在同信用代码,直接返回已注册,不查询SRM。 | + +--- + +## 11. 异常处理矩阵 + +|异常场景|处理方式|用户侧表现|后端动作| +|---|---|---|---| +|**SRM查询接口超时**|降级:视为新供应商,进入AI审核|正常AI审核流程(可能延迟)|记录告警,超时5s后转AI| +|**SRM查询返回错误**|降级:视为新供应商|正常AI审核|记录错误日志| +|**存量绑定后SRM绑定失败**|异步重试,STP仍激活|用户无感知|标记同步失败,告警管理员| +|**用户选择“继续注册”但信用代码已在STP注册**|返回已注册错误|提示“该企业已注册”|返回ERR_REG_002| + +--- + +## 12. 通知策略 + +|触发事件|通知方式|接收方|文案| +|---|---|---|---| +|**新供应商注册成功**|邮件+短信|联系人|“恭喜X公司注册成功!已自动激活,请直接登录。”| +|**SRM存量绑定成功**|邮件+短信|联系人|“恭喜X公司完成STP账号绑定,您已是滨化供应商,可直接登录参与投标。”| +|**注册驳回**|邮件+短信|联系人|“注册未通过,原因:...”| + +--- + +## 13. SRM双向同步机制 + +### 13.1 注册时正向同步(STP → SRM) + +- **触发时机**:AI审核通过,`INSERT`成功后立即执行。 +- **接口**:`POST /api/v1/supplier/register`(见接口方案3.2) +- **映射关系**: + +| STP字段 | SRM字段 | +| :--- | :--- | +| `company_name` | `supplierName` | +| `credit_code` | `taxId` | +| `contact_name` | `contactInfo.name` | +| `contact_phone` | `contactInfo.phone` | +| `contact_email` | `contactInfo.email` | +| `address` | `address` | + +- **状态映射**:STP `ACTIVE` → SRM `PENDING_CERTIFICATION`(需后续补充资质文件完成认证)。 + +### 13.2 SRM存量供应商绑定(无需同步,仅获取srmId) + +- 调用SRM查询接口获取srmId,存入本地,不调用注册接口。 +- 如果SRM供应商状态为“未激活”等,不影响STP绑定。 + +### 13.3 反向同步(SRM → STP) +若SRM侧修改供应商信息,通过定时增量同步接口更新STP(联系人等),与本注册模块无关。 + +--- + +## 14. 供应商联系人变更(注册后维护) + +> 本模块为注册流程的**必要延伸**,确保企业联系人信息变更时账户安全与业务通知可达。 + +### 14.1 自助变更(旧手机号可用) + +```mermaid +flowchart LR + A[登录工作台] --> B[进入企业信息页] + B --> C[点击修改联系人] + C --> D[验证旧手机号/邮箱] + D --> E[填写新联系人信息] + E --> F[验证新手机号/邮箱] + F --> G[提交变更] + G --> H[即时生效 + 同步SRM] +``` + +### 14.2 人工辅助变更(旧手机号不可用) + +```mermaid +flowchart LR + A[点击“旧手机无法接收验证码?”] --> B[下载《变更申请函》模板] + B --> C[填写+加盖公章] + C --> D[上传盖章扫描件] + D --> E[提交人工申请] + E --> F[管理员审核(4h内)] + F --> G[后台执行变更] +``` + +### 14.3 接口与数据(简略) + +- **变更接口**:`PUT /api/v1/supplier/contact` +- **审计日志**:写入`t_supplier_contact_change_log`(含旧值/新值/变更人/IP/哈希链)。 +- **SRM同步**:调用`POST /api/v1/supplier/contact/update`。 + +> 详细设计参考《联系人变更补充设计》,此处仅作概要嵌入,确保完整性。 + +--- + +## 15. 安全与合规 + +| 安全维度 | 具体措施 | +| :--- | :--- | +| **传输安全** | 强制 HTTPS + TLS 1.3,HSTS 头部强制。 | +| **敏感字段加密** | `credit_code`、`contact_phone` 使用 **AES-256-GCM** 应用层加密,密钥由KMS托管,内存动态漂移(参见全局安全方案4.2)。 | +| **可搜索加密** | 唯一性校验使用字段的 **MD5/SHA-256** 盲索引(不可逆),不直接对密文进行`SELECT`。 | +| **数据脱敏展示** | 后台展示信用代码为 `913701**********`,手机号为 `138****8001`。 | +| **审计防篡改** | 所有审计日志采用 **哈希链+数字签名**(参见需求说明书4.8.1),保留≥7年。 | +| **防机器人** | 注册提交需验证图形验证码(极验),手机验证码发送每日限5次。 | +| **密码安全** | 首次激活密码强度≥8位,含大小写+数字+特殊字符,不得为弱口令(密码字典检测)。 | +| **合规性** | 满足《个人信息保护法》第13条(告知同意)、第17条(隐私政策),注册前勾选同意《用户协议》与《隐私政策》。 | + +--- + +## 16. 附录 + +### 16.1 统一社会信用代码正则(前端+后端) + +```regex +^[0-9A-HJ-NPQRTUWXY]{2}\d{6}[0-9A-HJ-NPQRTUWXY]{10}$ +``` + +### 16.2 行业分类示例(GB/T 4754-2017 三级) + +| 一级 | 二级 | 三级代码 | 三级名称 | +| :--- | :--- | :--- | :--- | +| C 制造业 | 26 化学原料和化学制品制造业 | 2614 | 有机化学原料制造 | +| C 制造业 | 29 橡胶和塑料制品业 | 2926 | 塑料包装箱及容器制造 | +| E 建筑业 | 48 土木工程建筑业 | 4813 | 市政道路工程建筑 | + +### 16.3 错误码速查表 + +| 错误码 | HTTP状态 | 含义 | +| :--- | :--- | :--- | +| `0` | 200 | 成功 | +| `ERR_PARAM_001~011` | 400 | 参数校验失败(具体见第4章) | +| `ERR_REG_001` | 400 | 注册审核不通过 | +| `ERR_REG_002` | 409 | 信用代码已注册 | +| `ERR_REG_003` | 409 | 手机号/邮箱已被占用 | +| `ERR_REG_004` | 503 | 工商API服务繁忙 | +| `ERR_AUTH_001` | 401 | 验证码错误/过期 | +| `ERR_FILE_001` | 400 | 文件格式/大小不符 | +| `ERR_OCR_001` | 400 | OCR识别失败 | +| `ERR_SYS_001` | 500 | 系统内部异常 | diff --git a/docs/architecture/详细设计/外部专家注册模块.md b/docs/architecture/详细设计/外部专家注册模块.md new file mode 100644 index 0000000..1f9b0f0 --- /dev/null +++ b/docs/architecture/详细设计/外部专家注册模块.md @@ -0,0 +1,527 @@ +# 外部专家注册模块 + +| 文档名称 | 智慧招标平台(STP)外部专家注册模块详细设计 | +| :--- | :--- | +| **文档版本** | V1.1 | +| **编制日期** | 2026-06-29 | +| **关联文档** | 《需求分析说明书 V1.4》《评委管理规定》《SRM 与 STP 数据交换接口方案说明书》 | + +--- + +## 1. 模块概述 + +### 1.1 建设目标 +建立面向**社会外部评标专家**的在线注册、准入审核与档案管理体系,实现专家信息的结构化采集、AI辅助资质核验,并与后续的**专家抽取、智能匹配、在线评标、劳务报酬结算**全流程贯通。 + + +### 1.2 设计原则 +| 原则 | 说明 | +| :------- | :--------------------------------------- | +| **准入严控** | 严格遵循《评委管理规定》4.1/4.2要求,设置多级审核(AI初筛+人工复核)。 | +| **信息完备** | 采集字段覆盖专业能力、执业资格、收款账户等全维度。 | +| **隐私保护** | 身份证号、手机号、银行账户等敏感信息采用**字段级加密**存储(内存级密钥)。 | +| **智能提效** | AI自动识别证件、校验真伪、关联风险图谱,大幅降低人工审核成本。 | +| **统一身份** | 注册完成后自动生成STP平台账号,支持手机号/邮箱登录,无需二次注册。 | + +### 1.3 适用角色与场景 +| 角色 | 场景 | +| :--- | :--- | +| **外部专家申请人** | 通过招标门户“专家注册”入口提交申请,查询审核进度。 | +| **专家管理员(招标专员)** | 在后台审核专家资料、激活/驳回/冻结专家账户。 | +| **合规审计人员** | 查阅专家注册审计轨迹、关联关系图谱。 | +| **AI 审核服务** | 自动执行OCR识别、证件验真、利益冲突初筛(仅作后台参考,不要求专家主动声明)。 | + +--- + +## 2. 页面布局与 UI 设计 + +### 2.1 整体注册流程步骤条(SVG 线框图 - 顶部引导) + +```svg + + + + + + + + + 1 + 基本信息 + + + + + + + 2 + 专业资质 + + + + + + + 3 + 收款账户 + + + + + + + 4 + 提交审核 + + + * 带红色星号均为必填项 + +``` + +### 2.2 注册主表单页面(SVG 线框图 - 以“基本信息”页为例) + +```svg + + + + + + + + + + + + + + + + + + + 外部专家注册 + 请完整填写以下信息,所有数据将受到严格加密保护 + + + + 真实姓名 * + + 请输入中文姓名 + + 性别 * + + 请选择 + + + + 身份证号码 * + + 请输入18位身份证号 + 🔒 将使用AES-256加密存储 + + + 出生日期 + + 由身份证自动识别 + 年龄 + + 自动计算 + + + 手机号码 * + + 请输入手机号 + + 电子邮箱 * + + 请输入常用邮箱 + + + 工作单位 + + 请输入单位全称 + + 现从事专业 * + + 如:化工工艺、设备管理 + + + 技术职称 * + + 高级/副高级/中级/初级 + + 职称专业(如:化工工程) + + + 职称/资质证书扫描件 * + + 📄 点击上传或拖拽文件(支持 PDF/JPG/PNG,≤20MB) + 已上传:职称证.pdf (2.3MB) ✅ 识别完成 + + + + + + 上一步 + + + 下一步 → + + + + 📌 注册须知 + 1. 所有信息须与身份证及职称证书一致 + 2. 集团公司将对信息进行真实性核验 + 3. 入库专家须遵守《评委管理规定》 + 4. 个人信息变更需及时在线更新 + +``` + + +--- + +## 3. 详细业务流程 + +```mermaid +%%{init: {'theme':'base', 'themeVariables': { 'primaryColor':'#c2185b','primaryTextColor':'#fff','primaryBorderColor':'#880e4f','lineColor':'#555','secondaryColor':'#fce4ec'}}}%% +flowchart TD + subgraph 专家申请人端 + A[访问招标门户] --> B[点击“专家注册”] + B --> C[填写基本信息
(姓名/身份证/手机/邮箱等)] + C --> D[填写专业资质
(职称/执业资格/工作经历)] + D --> E[签署评标纪律承诺书] + E --> F[填写收款账户信息] + F --> G[提交注册申请] + G --> H[查看审核状态] + H -- 驳回 --> I[根据驳回原因修改信息] + I --> G + H -- 通过 --> J[收到激活通知邮件/短信] + J --> K[首次登录设置密码] + K --> L[进入专家工作台] + end + + subgraph STP平台后端 + STP1[接收注册申请] --> STP2[触发AI初审] + STP2 --> STP3{AI检查项} + STP3 -->|OCR识别证件| STP4[提取姓名/身份证号/有效期] + STP3 -->|真伪核验| STP5[对接公安部/学信网/天眼查] + STP3 -->|利益冲突图谱(参考)| STP6[扫描与黑名单/关联企业关系] + STP4 --> STP7[生成AI审核报告] + STP5 --> STP7 + STP6 --> STP7 + STP7 --> STP8{AI评估结果} + STP8 -->|高风险/不通过| STP9[自动驳回 + 发送原因] + STP8 -->|中风险/待人工| STP10[推送至专家管理员待办] + STP8 -->|低风险/通过| STP11[自动进入人工抽检池] + + STP10 --> STP12[人工复核资料] + STP11 --> STP12 + STP12 --> STP13{复核决定} + STP13 -->|驳回| STP14[记录驳回原因 + 通知专家] + STP13 -->|需补充材料| STP15[发起补充通知] + STP13 -->|通过| STP16[生成专家档案编号] + + STP16 --> STP17[写入专家库主数据] + STP17 --> STP18[自动创建STP登录账号] + STP18 --> STP19[发送激活通知] + STP19 --> STP20[记录全流程审计日志] + end + + subgraph 外部系统 + EXT1[公安身份认证库] + EXT2[学信网/职称系统] + EXT3[天眼查/企查查] + EXT4[邮件短信网关] + end + + STP5 -.-> EXT1 + STP5 -.-> EXT2 + STP6 -.-> EXT3 + STP19 -.-> EXT4 + + H -- 补充材料 --> STP15 + STP14 --> H +``` + +--- + +## 4. 核心流程时序图 + +```mermaid +sequenceDiagram + participant U as 专家申请人 + participant FE as STP前端 + participant GW as API网关 + participant RegSvc as 注册服务 + participant AISvc as AI审核服务 + participant IDSvc as 身份认证服务(外部) + participant DB as 专家库数据库 + participant Admin as 专家管理员 + participant Notify as 通知服务 + + U->>FE: 填写注册表单 + 上传证件 + FE->>FE: 前端校验(非空/手机格式/身份证校验位) + FE->>GW: POST /api/v1/expert/register + GW->>RegSvc: 转发请求 + + RegSvc->>DB: 校验身份证号是否已注册(防重) + alt 已存在 + DB-->>RegSvc: 记录已存在 + RegSvc-->>FE: 409 Conflict { message: "该身份证已注册" } + else 未注册 + RegSvc->>AISvc: 异步启动AI审核任务(OCR+验真+图谱) + RegSvc-->>FE: 202 Accepted { applicationId: "EXP_2024001" } + FE-->>U: 显示“提交成功,审核中...” + + AISvc->>IDSvc: 调用公安接口校验身份证号与姓名 + IDSvc-->>AISvc: 实名验证通过/失败 + + AISvc->>AISvc: OCR识别职称证书关键字段 + AISvc->>AISvc: 扫描企业关联图谱(作为利益冲突参考,不要求专家声明) + + AISvc-->>RegSvc: 返回AI审核结论(Pass/Review/Reject) + + alt AI高风险或敏感 + RegSvc->>DB: 状态更新为 PENDING_MANUAL + RegSvc->>Admin: 推送待办任务(站内+邮件) + Admin->>RegSvc: POST /api/v1/expert/audit { action: approve/reject } + else AI低风险 + RegSvc->>DB: 状态更新为 APPROVED(自动) + end + + RegSvc->>DB: 生成专家档案(EXP_XXXXX) + RegSvc->>RegSvc: 创建STP登录账号(默认手机号+随机密码) + RegSvc->>Notify: 发送激活通知(含账号及首次登录链接) + Notify-->>U: 短信+邮件 + U->>FE: 点击激活链接 + FE->>RegSvc: POST /api/v1/expert/activate { password } + RegSvc->>DB: 更新密码哈希(Argon2id) + RegSvc-->>FE: 激活成功,跳转至专家工作台 + end +``` + +--- + +## 5. 专家激活流程 +以下是专家激活设置密码的详细流程图,清晰展示了从审核通过到账号激活的全过程: + +```mermaid +flowchart TD + A[人工/AI审核通过] --> B[系统自动创建STP账号] + B --> C[生成随机临时密码(仅系统内部占位)] + C --> D[发送激活通知邮件/短信
(内含激活链接,不含密码)] + D --> E[专家收到通知,点击激活链接] + E --> F[跳转至激活页面] + F --> G[专家填写新密码及确认密码] + G --> H{前端校验} + H -->|格式不符| I[提示密码不满足安全策略
(长度≥8,含大小写、数字、特殊字符)] + I --> G + H -->|通过| J[提交激活请求
POST /api/v1/expert/activate] + J --> K[后端校验链接有效性及过期时间] + K -->|无效/过期| L[提示链接失效,重新发送] + L --> E + K -->|有效| M[对密码进行Argon2id哈希加密] + M --> N[更新数据库:
密码哈希 + 状态ACTIVATED + 激活时间] + N --> O[记录审计日志] + O --> P[返回激活成功] + P --> Q[专家跳转至专家工作台] + Q --> R[流程结束] + + style A fill:#e8f5e9,stroke:#388e3c + style R fill:#e0e0e0,stroke:#616161 + style C fill:#fff3e0,stroke:#ff9800 + style M fill:#fce4ec,stroke:#c2185b +``` + +**流程要点说明:** +- **随机密码未告知专家**:系统生成后仅用于初始化账户,专家通过激活链接自行设置密码,全程无需接触该临时密码。 +- **密码安全策略**:前端校验密码复杂度(长度、字符类型),后端再次校验并哈希存储(Argon2id)。 +- **链接安全性**:激活链接包含唯一token,后端校验其有效性与过期时间(通常24小时内有效),防止重放攻击。 +- **审计追踪**:所有操作(创建账号、发送通知、激活成功)均有日志记录。 + +## 6. 数据模型设计 + +### 6.1 外部专家主表 `t_expert_profile` + +| 字段名 | 类型 | 约束 | 说明 | +| :--------------------- | :----------- | :--------------- | :----------------------------------------------------------------- | +| `expert_id` | VARCHAR(32) | PK | 专家档案编号(EXP_YYYYMMDD_XXX) | +| `user_id` | VARCHAR(32) | FK | 关联STP用户账号表(登录凭证) | +| `real_name` | VARCHAR(64) | NOT NULL | 真实姓名 | +| `id_card_no` | VARCHAR(256) | NOT NULL, UNIQUE | 身份证号(**字段级加密存储**) | +| `gender` | TINYINT | | 1-男,2-女 | +| `birth_date` | DATE | | 出生日期(由身份证提取) | +| `phone` | VARCHAR(256) | NOT NULL | 手机号(字段级加密) | +| `email` | VARCHAR(128) | NOT NULL | 电子邮箱 | +| `company` | VARCHAR(128) | | 工作单位 | +| `profession` | VARCHAR(64) | NOT NULL | 从事专业 | +| `title` | VARCHAR(32) | NOT NULL | 职称等级(高级/副高/中级) | +| `title_major` | VARCHAR(64) | | 职称专业 | +| `qualification_files` | JSON | | 资质证书文件URL列表(含OCR元数据) | +| `bank_name` | VARCHAR(64) | | 开户银行 | +| `bank_account` | VARCHAR(256) | | 银行账号(字段级加密) | +| `expertise_tags` | JSON | | 擅长领域标签(用于智能匹配) | +| `status` | VARCHAR(20) | NOT NULL | DRAFT/PENDING_AI/PENDING_MANUAL/REJECTED/APPROVED/ACTIVATED/LOCKED | +| `ai_audit_report` | JSON | | AI审核报告(含评分、风险点) | +| `manual_audit_comment` | TEXT | | 人工审核备注 | +| `discipline_signed` | BOOLEAN | DEFAULT 0 | 是否签署评标纪律承诺书 | +| `created_at` | DATETIME | | 注册时间 | +| `updated_at` | DATETIME | | 更新时间 | +| `activated_at` | DATETIME | | 首次激活时间 | + + +### 6.3 审核记录表 `t_expert_audit_log` + +| 字段名 | 类型 | 约束 | 说明 | +| :------------ | :---------- | :-- | :-------------------------- | +| `audit_id` | VARCHAR(32) | PK | | +| `expert_id` | VARCHAR(32) | FK | | +| `auditor` | VARCHAR(64) | | 审核人(AI/人工) | +| `action` | VARCHAR(20) | | APPROVE/REJECT/REQUEST_INFO | +| `reason` | TEXT | | 原因 | +| `attachments` | JSON | | 附件URL | +| `created_at` | DATETIME | | | + +--- + +## 7. 接口详细定义 + +### 7.1 提交注册申请 +| 项目 | 内容 | +| :--- | :--- | +| **路径** | `/api/v1/expert/register` | +| **方法** | `POST` | +| **认证** | 否(公开接口,需图形验证码) | + +**请求体(部分字段)** +```json +{ + "realName": "王建国", + "idCardNo": "110101199003074477", + "gender": 1, + "phone": "13800138000", + "email": "wangjianguo@example.com", + "company": "清华大学化工系", + "profession": "化学工程", + "title": "SENIOR", // SENIOR/VICE_SENIOR/MIDDLE/JUNIOR + "titleMajor": "化学工程", + "expertiseTags": ["石油化工", "反应工程", "分离技术"], + "bankName": "中国银行北京分行", + "bankAccount": "6217850000000000", + "qualificationFiles": [ + { + "fileName": "professor_cert.pdf", + "fileUrl": "https://oss.stp.com/...", + "ocrResult": { "title": "教授", "issueDate": "2018-06" } + } + ], + "disciplineAccepted": true, // 是否同意评标纪律 + "captchaToken": "a1b2c3d4" +} +``` + +**成功响应(异步)** +```json +{ + "code": "0", + "data": { + "applicationId": "EXP_20260628_001", + "status": "PENDING_AI", + "estimatedTime": "预计24小时内完成初审" + } +} +``` + +### 7.2 查询审核进度 +| 项目 | 内容 | +| :----- | :---------------------------------- | +| **路径** | `/api/v1/expert/application/status` | +| **方法** | `GET` | +| **参数** | `applicationId` | + +### 7.3 专家激活 + +| 项目 | 内容 | +| :----- | :------------------------ | +| **路径** | `/api/v1/expert/activate` | +| **方法** | `POST` | + +**请求体** +```json +{ + "applicationId": "EXP_20260628_001", + "password": "Abcd@2026#", + "confirmPassword": "Abcd@2026#" +} +``` + +### 7.4 后台专家审核(管理员) +| 项目 | 内容 | +| :--- | :--- | +| **路径** | `/api/v1/admin/expert/audit` | +| **方法** | `POST` | +| **认证** | 需 ADMIN/EXPERT_MANAGER 角色 | + +**请求体** +```json +{ + "applicationId": "EXP_20260628_001", + "action": "APPROVE", // APPROVE / REJECT / REQUEST_INFO + "reason": "职称证书已验证,资质符合要求", + "notifyExpert": true +} +``` + +--- + +## 8. AI 赋能详细设计 + +| AI 能力 | 实现方式 | 输出 | 优先级 | +| :------------- | :---------------------------------------- | :----- | :-- | +| **身份证 OCR 解析** | 调用OCR服务(如百度/阿里)提取姓名、号码、有效期,自动回填表单。 | 结构化字段 | P0 | +| **实名认证** | ==对接公安部CTID接口核验身份证号与姓名一致性。== | 通过/不通过 | P0 | +| **职称证书验真** | ==对接人社部/学信网接口(或基于图像防伪特征识别)验证证书真伪。== | 可信度评分 | P1 | +| **专业标签智能推荐** | 根据专家填写的从事专业与历史项目品类,自动匹配并推荐擅长的采购品类标签。 | 标签列表 | P1 | +| **AI初审报告生成** | 汇总各项检查结果,生成带评分(0-100)的建议结论(自动通过/人工复核/拒绝)。 | 审核报告 | P0 | + +--- + +## 9. 业务规则与异常处理 + +| 场景 | 规则/处理方式 | +| :------------ | :------------------------------------------------------- | +| **身份证号唯一性** | 系统全局唯一,已注册或审核中的身份证不得重复提交。 | +| **手机号/邮箱唯一性** | 同一手机号或邮箱仅能注册一次(支持找回账号)。 | +| **职称等级门槛** | 至少具备**中级及以上**职称方可入库(《评委管理规定》4.2.1)。 | +| **驳回后重提** | 允许在 30 天内修改后重新提交,保留历史审核记录供查。 | +| **虚假信息处理** | 一经发现虚假注册,永久拉入黑名单,并通报集团内各单位。 | +| **评标纪律签署** | 注册时须同意《评标纪律承诺书》,否则无法提交。 | +| **敏感信息脱敏展示** | 后台管理中,身份证号显示为 `110101********4477`,银行账号显示为 `******0000`。 | +| **数据导出** | 支持按专家状态、专业分类、注册时间段导出加密Excel(需二次审批)。 | + +--- + +## 10. 安全与合规设计 + +| 安全维度 | 落地措施 | +| :--------- | :------------------------------------------------------------ | +| **传输安全** | 全链路 HTTPS + TLS 1.3,文件上传使用预签名URL直传OSS。 | +| **敏感字段加密** | 身份证、手机号、银行账号使用 **AES-256-GCM** 应用层字段级加密,DEK内存漂移(见《需求说明书》4.2)。 | +| **防机器人** | 注册提交需通过图形验证码 + 滑动验证(极验/人机识别)。 | +| **密码策略** | 首次激活强制设置密码(长度≥8,含大写、小写、数字、特殊字符)。 | +| **审计日志** | 记录每次提交、审核、激活操作的IP、设备指纹、操作人,写入哈希链防篡改(见《需求说明书》4.8.1)。 | +| **个人信息保护** | 遵循《个人信息保护法》,注册前弹出《隐私政策》与《用户协议》,须勾选同意。 | + +--- + +## 11. 通知策略矩阵 + +| 触发事件 | 通知方式 | 通知对象 | 文案要点 | +| :--- | :--- | :--- | :--- | +| 提交注册成功 | 站内信 | 申请人 | 已收到申请,预计24小时反馈 | +| AI 审核不通过 | 邮件+短信 | 申请人 | 详细说明不通过原因及修改指引 | +| 转入人工审核 | 站内信+邮件 | 专家管理员 | 新专家待审核,附AI报告摘要 | +| 人工审核通过 | 邮件+短信 | 申请人 | 恭喜通过审核,请点击链接激活账号 | +| 账号激活成功 | 站内信 | 申请人 | 欢迎成为STP评标专家,可开始接受评标任务 | +| 补充材料通知 | 邮件+短信 | 申请人 | 请于X月X日前补充如下材料... | + diff --git a/docs/architecture/详细设计/新用户注册模块.md b/docs/architecture/详细设计/新用户注册模块.md new file mode 100644 index 0000000..1421ba1 --- /dev/null +++ b/docs/architecture/详细设计/新用户注册模块.md @@ -0,0 +1,483 @@ +# 新用户注册模块 + +新用户注册包含了[[供应商注册模块]]和[[外部专家注册模块]] 。 + +### 供应商注册页面要素: +- 企业全称 +- 统一社会信用代码 +- 注册资本(万元) +- 法定代表人 +- 行业 +- 地址 +- 经营范围 +- 主要产品 +- 联系人姓名 +- 联系电话(手机号) +- 电子邮箱 +- 营业执照 + +## 供应商注册模块 + + +## 外部专家注册模块 + +## 1. 模块概述 + +### 1.1 建设目标 +建立面向**社会外部评标专家**的在线注册、准入审核与档案管理体系,实现专家信息的结构化采集、AI辅助资质核验、回避关系预审,并与后续的**专家抽取、智能匹配、在线评标、劳务报酬结算**全流程贯通。 + +### 1.2 设计原则 +| 原则 | 说明 | +| :------- | :-------------------------------------- | +| **信息完备** | 采集字段覆盖专业能力、执业资格、回避关系、收款账户等全维度。 | +| **隐私保护** | 身份证号、手机号、银行账户等敏感信息采用**字段级加密**存储(内存级密钥)。 | +| **统一身份** | 注册完成后自动生成STP平台账号,支持手机号/邮箱登录,无需二次注册。 | + +### 1.3 适用角色与场景 +| 角色 | 场景 | +| :-------------- | :----------------------------- | +| **外部专家申请人** | 通过招标门户“专家注册”入口提交申请,查询审核进度。 | +| **专家管理员(招标专员)** | 在后台审核专家资料、处理回避申报、激活/驳回/冻结专家账户。 | +| **合规审计人员** | 查阅专家注册审计轨迹、关联关系图谱。 | +| **AI 审核服务** | 自动执行OCR识别、证件验真。 | + +--- + +## 2. 页面布局与 UI 设计 + +### 2.1 整体注册流程步骤条 + +```svg + + + + + + + + + 1 + 基本信息 + + + + + + + 2 + 专业资质 + + + + + + + 5 + 提交审核 + + + * 带红色星号均为必填项 + +``` + +### 2.2 注册主表单页面 + +```svg + + + + + + + + + + + + + + + + + + + 外部专家注册 + 请完整填写以下信息,所有数据将受到严格加密保护 + + + + 真实姓名 * + + 请输入中文姓名 + + 性别 * + + 请选择 + + + + 身份证号码 * + + 请输入18位身份证号 + 🔒 将使用AES-256加密存储 + + + 出生日期 + + 由身份证自动识别 + 年龄 + + 自动计算 + + + 手机号码 * + + 请输入手机号 + + 电子邮箱 * + + 请输入常用邮箱 + + + 工作单位 + + 请输入单位全称 + + 现从事专业 * + + 如:化工工艺、设备管理 + + + 技术职称 * + + 高级/副高级/中级/初级 + + 职称专业(如:化工工程) + + + 职称/资质证书扫描件 * + + 📄 点击上传或拖拽文件(支持 PDF/JPG/PNG,≤20MB) + 已上传:职称证.pdf (2.3MB) ✅ 识别完成 + + + + + + 上一步 + + + 下一步 → + + + + 📌 注册须知 + 1. 所有信息须与身份证及职称证书一致 + 2. 集团公司将对信息进行真实性核验 + 3. 入库专家须遵守《评委管理规定》 + 4. 个人信息变更需及时在线更新 + 5. 评审回避要求详见本章程4.7条 + +``` + + + +--- + +## 4. 核心流程时序图 + +```mermaid +sequenceDiagram + participant U as 专家申请人 + participant FE as STP前端 + participant GW as API网关 + participant RegSvc as 注册服务 + participant AISvc as AI审核服务 + participant IDSvc as 身份认证服务(外部) + participant DB as 专家库数据库 + participant Admin as 专家管理员 + participant Notify as 通知服务 + + U->>FE: 填写注册表单 + 上传证件 + FE->>FE: 前端校验(非空/手机格式/身份证校验位) + FE->>GW: POST /api/v1/expert/register + GW->>RegSvc: 转发请求 + + RegSvc->>DB: 校验身份证号是否已注册(防重) + alt 已存在 + DB-->>RegSvc: 记录已存在 + RegSvc-->>FE: 409 Conflict { message: "该身份证已注册" } + else 未注册 + RegSvc->>AISvc: 异步启动AI审核任务(OCR+验真+图谱) + RegSvc-->>FE: 202 Accepted { applicationId: "EXP_2024001" } + FE-->>U: 显示“提交成功,审核中...” + + AISvc->>IDSvc: 调用公安接口校验身份证号与姓名 + IDSvc-->>AISvc: 实名验证通过/失败 + + AISvc->>AISvc: OCR识别职称证书关键字段 + AISvc->>AISvc: 扫描企业关联图谱(回避关系) + + AISvc-->>RegSvc: 返回AI审核结论(Pass/Review/Reject) + + alt AI高风险或敏感 + RegSvc->>DB: 状态更新为 PENDING_MANUAL + RegSvc->>Admin: 推送待办任务(站内+邮件) + Admin->>RegSvc: POST /api/v1/expert/audit { action: approve/reject } + else AI低风险 + RegSvc->>DB: 状态更新为 APPROVED(自动) + end + + RegSvc->>DB: 生成专家档案(EXP_XXXXX) + RegSvc->>RegSvc: 创建STP登录账号(默认手机号+随机密码) + RegSvc->>Notify: 发送激活通知(含账号及首次登录链接) + Notify-->>U: 短信+邮件 + U->>FE: 点击激活链接 + FE->>RegSvc: POST /api/v1/expert/activate { password } + RegSvc->>DB: 更新密码哈希(Argon2id) + RegSvc-->>FE: 激活成功,跳转至专家工作台 + end +``` + +--- + +## 5. 数据模型设计 + +### 5.1 外部专家主表 `t_expert_profile` + +| 字段名 | 类型 | 约束 | 说明 | +| :--- | :--- | :--- | :--- | +| `expert_id` | VARCHAR(32) | PK | 专家档案编号(EXP_YYYYMMDD_XXX) | +| `user_id` | VARCHAR(32) | FK | 关联STP用户账号表(登录凭证) | +| `real_name` | VARCHAR(64) | NOT NULL | 真实姓名 | +| `id_card_no` | VARCHAR(256) | NOT NULL, UNIQUE | 身份证号(**字段级加密存储**) | +| `gender` | TINYINT | | 1-男,2-女 | +| `birth_date` | DATE | | 出生日期(由身份证提取) | +| `phone` | VARCHAR(256) | NOT NULL | 手机号(字段级加密) | +| `email` | VARCHAR(128) | NOT NULL | 电子邮箱 | +| `company` | VARCHAR(128) | | 工作单位 | +| `profession` | VARCHAR(64) | NOT NULL | 从事专业 | +| `title` | VARCHAR(32) | NOT NULL | 职称等级(高级/副高/中级) | +| `title_major` | VARCHAR(64) | | 职称专业 | +| `qualification_files` | JSON | | 资质证书文件URL列表(含OCR元数据) | +| `bank_name` | VARCHAR(64) | | 开户银行 | +| `bank_account` | VARCHAR(256) | | 银行账号(字段级加密) | +| `expertise_tags` | JSON | | 擅长领域标签(用于智能匹配) | +| `status` | VARCHAR(20) | NOT NULL | DRAFT/PENDING_AI/PENDING_MANUAL/REJECTED/APPROVED/ACTIVATED/LOCKED | +| `ai_audit_report` | JSON | | AI审核报告(含评分、风险点) | +| `manual_audit_comment` | TEXT | | 人工审核备注 | +| `declaration_signed` | BOOLEAN | DEFAULT 0 | 是否签署回避声明 | +| `created_at` | DATETIME | | 注册时间 | +| `updated_at` | DATETIME | | 更新时间 | +| `activated_at` | DATETIME | | 首次激活时间 | + +### 5.2 回避声明表 `t_expert_declaration` + +| 字段名 | 类型 | 约束 | 说明 | +| :--- | :--- | :--- | :--- | +| `declaration_id` | VARCHAR(32) | PK | 声明编号 | +| `expert_id` | VARCHAR(32) | FK | 专家ID | +| `declaration_type` | VARCHAR(32) | | 定期声明/项目专项声明 | +| `content` | JSON | | 逐项勾选记录 | +| `signed_at` | DATETIME | | 签署时间 | +| `ip_address` | VARCHAR(64) | | 签署IP | +| `valid_until` | DATETIME | | 有效期(通常1年) | + +### 5.3 审核记录表 `t_expert_audit_log` + +| 字段名 | 类型 | 约束 | 说明 | +| :--- | :--- | :--- | :--- | +| `audit_id` | VARCHAR(32) | PK | | +| `expert_id` | VARCHAR(32) | FK | | +| `auditor` | VARCHAR(64) | | 审核人(AI/人工) | +| `action` | VARCHAR(20) | | APPROVE/REJECT/REQUEST_INFO | +| `reason` | TEXT | | 原因 | +| `attachments` | JSON | | 附件URL | +| `created_at` | DATETIME | | | + +--- + +## 6. 接口详细定义 + +### 6.1 提交注册申请 +| 项目 | 内容 | +| :--- | :--- | +| **路径** | `/api/v1/expert/register` | +| **方法** | `POST` | +| **认证** | 否(公开接口,需图形验证码) | + +**请求体(部分字段)** +```json +{ + "realName": "王建国", + "idCardNo": "110101199003074477", + "gender": 1, + "phone": "13800138000", + "email": "wangjianguo@example.com", + "company": "清华大学化工系", + "profession": "化学工程", + "title": "SENIOR", // SENIOR/VICE_SENIOR/MIDDLE/JUNIOR + "titleMajor": "化学工程", + "expertiseTags": ["石油化工", "反应工程", "分离技术"], + "bankName": "中国银行北京分行", + "bankAccount": "6217850000000000", + "qualificationFiles": [ + { + "fileName": "professor_cert.pdf", + "fileUrl": "https://oss.stp.com/...", + "ocrResult": { "title": "教授", "issueDate": "2018-06" } + } + ], + "declarations": { + "noAffiliation": true, + "noInvestment": true, + "noConsulting": true, + "acceptDiscipline": true + }, + "captchaToken": "a1b2c3d4" +} +``` + +**成功响应(异步)** +```json +{ + "code": "0", + "data": { + "applicationId": "EXP_20260628_001", + "status": "PENDING_AI", + "estimatedTime": "预计24小时内完成初审" + } +} +``` + +### 6.2 查询审核进度 +| 项目 | 内容 | +| :--- | :--- | +| **路径** | `/api/v1/expert/application/status` | +| **方法** | `GET` | +| **参数** | `applicationId` / `idCardNo`(二选一) | + +### 6.3 专家激活(首次设置密码) +| 项目 | 内容 | +| :--- | :--- | +| **路径** | `/api/v1/expert/activate` | +| **方法** | `POST` | + +**请求体** +```json +{ + "applicationId": "EXP_20260628_001", + "password": "Abcd@2026#", + "confirmPassword": "Abcd@2026#" +} +``` + +### 6.4 后台专家审核(管理员) +| 项目 | 内容 | +| :--- | :--- | +| **路径** | `/api/v1/admin/expert/audit` | +| **方法** | `POST` | +| **认证** | 需 ADMIN/EXPERT_MANAGER 角色 | + +**请求体** +```json +{ + "applicationId": "EXP_20260628_001", + "action": "APPROVE", // APPROVE / REJECT / REQUEST_INFO + "reason": "职称证书已验证,资质符合要求", + "notifyExpert": true +} +``` + +--- + +## 7. AI 赋能详细设计 + +| AI 能力 | 实现方式 | 输出 | 优先级 | +| :--- | :--- | :--- | :--- | +| **身份证 OCR 解析** | 调用OCR服务(如百度/阿里)提取姓名、号码、有效期,自动回填表单。 | 结构化字段 | P0 | +| **实名认证** | 对接公安部CTID接口核验身份证号与姓名一致性。 | 通过/不通过 | P0 | +| **职称证书验真** | 对接人社部/学信网接口(或基于图像防伪特征识别)验证证书真伪。 | 可信度评分 | P1 | +| **利益冲突图谱** | 利用知识图谱匹配专家任职企业是否与集团供应商库/黑名单关联,输出风险等级(绿/黄/红)。 | 风险报告 | P0 | +| **专业标签智能推荐** | 根据专家填写的从事专业与历史项目品类,自动匹配并推荐擅长的采购品类标签。 | 标签列表 | P1 | +| **AI初审报告生成** | 汇总各项检查结果,生成带评分(0-100)的建议结论(自动通过/人工复核/拒绝)。 | 审核报告 | P0 | + +--- + +## 8. 业务规则与异常处理 + +| 场景 | 规则/处理方式 | +| :--- | :--- | +| **身份证号唯一性** | 系统全局唯一,已注册或审核中的身份证不得重复提交。 | +| **手机号/邮箱唯一性** | 同一手机号或邮箱仅能注册一次(支持找回账号)。 | +| **职称等级门槛** | 至少具备**中级及以上**职称方可入库(《评委管理规定》4.2.1)。 | +| **AI自动通过阈值** | AI评分 ≥ 90 分且无高风险项 → 自动通过;60~89分 → 人工复核;<60分 → 自动驳回。 | +| **驳回后重提** | 允许在 30 天内修改后重新提交,保留历史审核记录供查。 | +| **虚假信息处理** | 一经发现虚假注册,永久拉入黑名单,并通报集团内各单位。 | +| **回避声明有效期** | 每年需重新签署一次,到期前30天系统自动催办。 | +| **敏感信息脱敏展示** | 后台管理中,身份证号显示为 `110101********4477`,银行账号显示为 `******0000`。 | +| **数据导出** | 支持按专家状态、专业分类、注册时间段导出加密Excel(需二次审批)。 | + +--- + +## 9. 安全与合规设计 + +| 安全维度 | 落地措施 | +| :--- | :--- | +| **传输安全** | 全链路 HTTPS + TLS 1.3,文件上传使用预签名URL直传OSS。 | +| **敏感字段加密** | 身份证、手机号、银行账号使用 **AES-256-GCM** 应用层字段级加密,DEK内存漂移(见《需求说明书》4.2)。 | +| **防机器人** | 注册提交需通过图形验证码 + 滑动验证(极验/人机识别)。 | +| **密码策略** | 首次激活强制设置密码(长度≥8,含大写、小写、数字、特殊字符)。 | +| **审计日志** | 记录每次提交、审核、激活操作的IP、设备指纹、操作人,写入哈希链防篡改(见《需求说明书》4.8.1)。 | +| **个人信息保护** | 遵循《个人信息保护法》,注册前弹出《隐私政策》与《用户协议》,须勾选同意。 | + +--- + +## 10. 通知策略矩阵 + +| 触发事件 | 通知方式 | 通知对象 | 文案要点 | +| :--- | :--- | :--- | :--- | +| 提交注册成功 | 站内信 | 申请人 | 已收到申请,预计24小时反馈 | +| AI 审核不通过 | 邮件+短信 | 申请人 | 详细说明不通过原因及修改指引 | +| 转入人工审核 | 站内信+邮件 | 专家管理员 | 新专家待审核,附AI报告摘要 | +| 人工审核通过 | 邮件+短信 | 申请人 | 恭喜通过审核,请点击链接激活账号 | +| 账号激活成功 | 站内信 | 申请人 | 欢迎成为STP评标专家,可开始接受评标任务 | +| 回避声明临期 | 邮件 | 专家 | 请及时重新签署回避声明,否则无法参与评标 | +| 补充材料通知 | 邮件+短信 | 申请人 | 请于X月X日前补充如下材料... | + +--- + +## 11. 与整体架构的集成衔接 + +```mermaid +graph LR + subgraph 专家生命周期 + A[注册申请] --> B[AI/人工审核] + B --> C[生成账号] + C --> D[激活登录] + D --> E[专家抽取匹配] + E --> F[在线评标] + F --> G[劳务报酬结算] + end + + subgraph 外围系统 + H[(专家库)] + I[IAM/认证中心] + J[支付系统] + K[电子档案] + end + + C --> I + G --> J + B --> K + E --> H + F --> H + + style A fill:#fce4ec,stroke:#c2185b + style D fill:#e8f5e9,stroke:#388e3c +``` + +--- + +本详细设计已完整覆盖外部专家从注册入口、信息填报、AI+人工双轨审核、账号激活到后续业务衔接的全链路,严格遵循《评委管理规定》的准入标准,并深度集成平台现有安全体系与AI能力。如需调整字段或审核流层级,可进一步展开讨论。 + diff --git a/docs/architecture/详细设计/登录模块.md b/docs/architecture/详细设计/登录模块.md new file mode 100644 index 0000000..8566181 --- /dev/null +++ b/docs/architecture/详细设计/登录模块.md @@ -0,0 +1,411 @@ +# 登录模块 + +## 1. 模块概述 + +### 1.1 设计原则 + +| 原则 | 说明 | +| -------- | ----------------------------- | +| **安全优先** | 传输全程加密,防暴力破解。 | +| **角色分流** | 通过“内部员工登录”开关明确区分认证路由,杜绝权限越界。 | +| **存量兼容** | 无缝兼容 SRM 存量供应商账号,降低用户迁移成本。 | +| **体验极简** | 支持账号/手机双因子登录,并提供“记住我”与智能异常提示。 | + +### 1.2 角色与认证路由映射 + +| 用户类型 | 开关状态 | 认证目标 | 说明 | +| ---------- | --------- | -------------------- | ------------------------------------------------- | +| **集团内部员工** | 开启(员工模式) | IAM(集团统一身份认证) | 跳转至 IAM 登录页或调用 OAuth2/OIDC 接口,不校验平台本地密码。 | +| **外部供应商** | 关闭(供应商模式) | STP 本地用户表 / SRM 回退认证 | 优先校验 STP 本地账号;若不存在,自动路由至 SRM 验证(满足 SRM 存量用户无感登录)。 | + +## 2. 页面布局与 UI 设计 + +### 2.1 整体布局 + +```svg + + + + + + + + + + + + + + + + + + + + + + + + + + 智慧招标平台 + Smart Tendering Platform + + + + + + + + + + + AI 原生 · 全流程线上闭环 · 主动式智能 + 覆盖公开招标 · 邀请招标 · 竞争性谈判 · 单一来源 + + + + + + 欢迎登录 + 登录您的账户,开始智能招采之旅 + + + + + 👤 内部员工 + 🏢 外部账号 + 当前:内部员工模式(走 IAM 认证) + + + + + 账号登录 + 手机验证码 + + + 账号 / 手机号 + + 请输入您的账号 + + ! + + + 密码 + + 请输入您的密码 + 👁️ + + + + + 记住我 + 忘记密码? + + + + 登 录 + + + 还没有账号? + 立即注册 + + + + 温馨提示 + + + 💡 原 SRM 注册用户,可直接使用 SRM 账号密码登录,无需重复注册。 + + + © 2026 滨化集团 | 智慧招标平台 V1.0 + + +``` + +### 2.2 账号登录页面 +关键元素: +* 账号输入框 +* 密码输入框 +* `记住我`选择框。 +* `忘记密码`链接 +* `登录`按钮 +* `内部员工登录`选择框,选择后将走集团 IAM 路由进行身份认证,否则走平台账号路由进行身认证。 +* `立即注册`链接 +* 登录说明:原 SRM 注册用户,可直接使用 SRM账号密码登录,无需重复注册。 + +### 2.3 手机验证码登录页面 +关键元素: +* 手机号输出框 +* 验证码输出框 +* 发送验证码按钮 +* 登录按钮 + + +### 2.4 页面状态与元素交互说明 + +| UI 元素 | 交互行为 | 状态变化 | +| ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | +| **内部员工 / 供应商 切换滑块** | 点击滑块或文字,滑块滑动至对应位置,下方提示文字切换,表单保持不变,但认证逻辑改变。 | 员工模式:下方显示`当前:内部员工模式(IAM 认证)`,且“忘记密码”链接跳转至 IAM 密码找回页;“立即注册”置灰或隐藏(员工由 HR 系统同步)。供应商模式:恢复常规提示。 | +| **账号登录 / 手机登录 Tab** | 点击切换 Tab,下方表单内容切换。 | 账号登录:显示账号+密码框。手机登录:显示手机号+验证码框+发送验证码按钮。 | +| **记住我** | 勾选后,登录成功时将 `refresh_token` 存入浏览器本地(Secure Storage),有效期为 7 天。 | 复选框状态持久化(基于本地 Cookie 记忆偏好)。 | +| **忘记密码** | 供应商模式:跳转至“重置密码”页(需短信/邮箱验证)。员工模式:跳转至 IAM 统一认证的密码重置页面。 | 页面跳转。 | +| **立即注册** | 供应商模式:跳转至供应商注册页(含 SRM 存量账号绑定引导)。员工模式:不可用(灰色)。 | 页面跳转 / 按钮置灰。 | + +## 3.详细交互流程 +### 3.1 登录主流程 +```mermaid +graph TD + A[供应商访问STP门户] --> B{检测登录态?} + B -->|有有效Token| C[无感跳转至工作台] + B -->|无Token| D[展示登录页面] + + D --> E[输入账号/密码] + E --> F{账号来源检测} + + F -->|STP本地账号| G[STP身份认证] + F -->|SRM存量账号| H[调用Vendor SSO鉴权] + + G --> I{认证成功?} + H --> I + + I -->|失败| J[显示错误信息
记录失败日志] + J --> K{失败次数≥5?} + K -->|是| L[锁定账号30分钟
触发安全告警] + K -->|否| E + + I -->|成功| M{是否MFA启用?} + M -->|是| N[发送短信验证码] + N --> O[验证码校验] + O -->|失败| N + O -->|成功| P[生成JWT令牌] + M -->|否| P + + P --> Q[更新最后登录信息] + Q --> R[记录审计日志] + R --> S[跳转至供应商工作台] +``` + + +### 3.2 时序图:多认证源详细交互 + +```mermaid +sequenceDiagram + participant U as 用户/浏览器 + participant FE as STP 前端 + participant GW as API 网关 + participant Auth as 认证服务 + participant IAM as 集团 IAM + participant LocalDB as STP 用户库 + participant SRM as SRM 系统 + + U->>FE: 输入账号/密码,点击登录 + FE->>FE: 前端基础校验(非空/格式) + FE->>GW: POST /api/v1/auth/login { loginType, account, password, mode } + + alt 员工模式 (mode=employee) + GW->>Auth: 转发至 IAM 认证处理器 + Auth->>IAM: OAuth2/OIDC 密码模式 / LDAP 验证 + IAM-->>Auth: 返回用户信息 (employeeId, dept, roles) + Auth-->>Auth: 若成功,生成 STP 内部 Session + Auth-->>FE: 200 OK { token, redirectUrl } + else 供应商模式 (mode=vendor) + GW->>Auth: 转发至本地认证处理器 + Auth->>LocalDB: 查询 account + alt 本地用户存在 + LocalDB-->>Auth: 返回用户实体(含 salt, hash) + Auth->>Auth: 校验密码(BCrypt/Argon2) + else 本地用户不存在 + Auth->>SRM: 调用 /api/v1/auth/login/for-stp { username, password } + SRM-->>Auth: 200 { srmId, name, taxId, ... } + Auth->>LocalDB: 创建影子用户(绑定 srmId) + LocalDB-->>Auth: 返回新用户实体 + end + Auth-->>FE: 200 OK { token, vendorId, srmId, redirectUrl } + end + + FE->>FE: 存储 Token 至 LocalStorage/Session + FE-->>U: 302 重定向至工作台 +``` + +### 3.3 手机验证码登录详细流程 + +```mermaid +sequenceDiagram + participant U as 用户 + participant FE as 前端 + participant Auth as 认证服务 + participant SMS as 短信网关 + participant Cache as Redis 缓存 + + U->>FE: 输入手机号,点击“发送验证码” + FE->>FE: 校验手机号格式(11位/国际格式) + FE->>Auth: POST /api/v1/auth/sms/send { phone, captchaToken } + Auth->>Auth: 校验图形验证码(防机器人) + Auth->>Cache: 查询该手机号发送频率(60s内是否已发) + alt 频率过高 + Cache-->>Auth: 已发送,拒绝 + Auth-->>FE: 429 Too Many Requests { remainSeconds: 45 } + else 频率正常 + Auth->>Auth: 生成6位随机验证码(如 882345) + Auth->>Cache: 存储验证码至 Redis(Key: sms:login:{phone}, TTL: 5min) + Auth->>SMS: 调用短信发送接口 + SMS-->>Auth: 发送成功 + Auth-->>FE: 200 OK { expireSeconds: 300 } + FE-->>U: 开始倒计时(60s) + end + + U->>FE: 输入验证码,点击“登录” + FE->>Auth: POST /api/v1/auth/login/mobile { phone, code } + Auth->>Cache: 读取验证码并比对 + alt 验证码匹配 + Cache-->>Auth: 匹配成功 + Auth->>Auth: 查询或创建用户(若不存在则自动注册/绑定SRM) + Auth-->>FE: 200 { token, isNewUser } + else 验证码错误或过期 + Auth-->>FE: 401 { code: "ERR_SMS_001", message: "验证码错误或已过期" } + end +``` + + + + +## 4. 接口详细定义 + +### 4.1 账号密码登录接口 + +|项目|内容| +|---|---| +|**路径**|`/api/v1/auth/login`| +|**方法**|`POST`| +|**是否认证**|否(公开接口)| +**请求体** +```json +{ + "account": "zhangli@binhai.com", // 账号/邮箱/手机号 + "password": "abcsdfg", + "mode": "vendor", // "employee" 或 "vendor" + "back_url":"/index" //返回的链接,可省略 + "rememberMe": true // 是否记住我 +} +``` + +**成功响应(200)** +```json +{ + "code": "0", + "data": { + "accessToken": "eyJhbGciOiJSUzI1NiIs...", + "refreshToken": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...", + "expiresIn": 1800, + "userInfo": { + "userId": "U_20240001", + "userType": "VENDOR", // EMPLOYEE / VENDOR + "name": "张立", + "srmId": "SRM_12345", // 若存在关联 + "roles": ["SUPPLIER"], + "redirectUrl": "/dashboard/vendor" + } + } +} +``` + +**失败响应(401)** +```json +{ + "code": "ERR_AUTH_001", + "message": "账号或密码错误", + "remainingAttempts": 4 +} +``` + +### 4.2 手机验证码发送接口 + +|项目|内容| +|---|---| +|**路径**|`/api/v1/auth/sms/send`| +|**方法**|`POST`| + +**请求体** + +```json +{ + "phone": "13800138000", + "captchaToken": "a1b2c3d4" // 图形验证码 token + "mode": "vendor", // "employee" 或 "vendor" + "back_url":"/index" //返回的链接,可省略 + "rememberMe": true // 是否记住我 +} +``` + +**成功响应** + +```json + +{ + "code": "0", + "data": { + "expireSeconds": 300, + "resendAfterSeconds": 60 + } +} +``` + +## 5. 安全设计细项 + +| 维度 | 具体策略 | +| -------------- | ----------------------------------------------------------------------------------------------------- | +| **传输加密** | 强制 HTTPS/TLS 1.3,禁用弱加密套件。 | +| **密码存储** | 使用 **Argon2id** 或 **BCrypt(cost≥10)** 加盐哈希存储。 | +| **防暴力破解** | 单账号 5 次失败后锁定 30 分钟(IP 维度 20 次失败后全局验证码强制)。 | +| **JWT 安全** | 算法使用 RS256(私钥签名,公钥验签);Access Token 有效期 30 分钟;Refresh Token 有效期 7 天,存储于 HTTPOnly Secure Cookie(防 XSS)。 | +| **验证码安全** | 手机验证码 6 位数字,有效期 5 分钟;发送间隔限制 60 秒;单日单号码上限 10 条。 | +| **登录审计** | 记录:用户 ID、登录时间、IP、User-Agent、设备指纹(Canvas Fingerprint)、认证源(IAM/Local/SRM)。审计日志写入哈希链(见《需求说明书》4.8.1)。 | +| **多因素认证(MFA)** | 预留扩展接口。敏感操作(修改密码、更换手机)强制二次验证。 | +| **会话并发** | 默认允许同一账号多设备登录,==但可在管理后台启用“单点登录互踢”策略(保留配置项)==。 | +## 6. 异常场景与错误码矩阵 + +| 异常场景 | 错误码 | HTTP 状态码 | 用户提示 | 后端处理 | +| --------------- | --------------- | -------- | ----------------- | ---------- | +| 账号为空 | `ERR_PARAM_001` | 400 | 请输入账号 | 无 | +| 密码为空 | `ERR_PARAM_002` | 400 | 请输入密码 | 无 | +| 账号/密码不匹配(本地) | `ERR_AUTH_001` | 401 | 账号或密码错误 | 失败计数 + 1 | +| 账号不存在且 SRM 验证失败 | `ERR_AUTH_002` | 401 | 账号不存在,请检查或注册 | 记录未注册尝试 | +| 账号已锁定 | `ERR_AUTH_003` | 403 | 账号已被锁定,请 30 分钟后重试 | 告警(若为频繁攻击) | +| 手机号格式错误 | `ERR_PARAM_003` | 400 | 请输入正确的手机号 | 无 | +| 验证码发送频率过高 | `ERR_SMS_001` | 429 | 发送过于频繁,请 60 秒后重试 | 返回剩余秒数 | +| 验证码错误/过期 | `ERR_SMS_002` | 401 | 验证码错误或已过期 | 清除已用验证码 | +| IAM 认证超时 | `ERR_IAM_001` | 504 | 集团认证服务繁忙,请稍后重试 | 熔断降级,记录日志 | + +## 7. 登录成功后的路由与权限门控 + +登录成功后,前端根据 `userType` 和 `roles` 决定跳转目标,同时后端在后续请求中通过 **JWT** 持续校验权限。 + +| 用户类型 | 默认跳转页面 | 可访问范围 | +| ------------------ | --------------------- | ------------------------------------- | +| **供应商(VENDOR)** | `/portal/dashboard` | 招标公告列表、报名管理、我的投标、中标通知、保证金管理。 | +| **评审专家(EXPERT)** | `/expert/dashboard` | 评标任务列表、回避申报、承诺书签署、历史评审记录。 | +| **内部员工(EMPLOYEE)** | `/employee/dashboard` | 根据子角色(需求人员/招标专员/审批人/管理员)展示对应工作台。 | +| **系统管理员(ADMIN)** | `/admin/console` | 用户管理、流程配置、审计日志、系统监控。
(管理员不在普通页面登录) | + +```mermaid +graph LR + A[登录成功] --> B{UserType} + B -->|VENDOR| C[供应商工作台] + B -->|EXPERT| D[专家工作台] + B -->|EMPLOYEE| E{子角色} + E -->|需求人员| F[需求工作台] + E -->|招标专员| G[招标管理工作台] + E -->|审批人| H[审批待办中心] + E -->|管理员| I[系统管理后台] + + style A fill:#e8f5e9,stroke:#388e3c + style C fill:#e3f2fd,stroke:#1565c0 + style D fill:#fff3e0,stroke:#e65100 + style I fill:#fce4ec,stroke:#c2185b +``` + +## 8. 与 SRM 无感登录的集成衔接 + +登录页下方的 **“原 SRM 注册用户,可直接使用 SRM账号密码登录”** 提示对应后端自动回退逻辑(详见 3.2 时序图)。此外,登录成功后,前端页面内嵌的指向 SRM 的所有链接,将自动携带 **跳转票据(Ticket)** 实现无感跳转(技术方案详见《SRM 与 STP 数据交换接口方案说明书》3.4.2 节)。 + diff --git a/docs/architecture/需求分析说明书.md b/docs/architecture/需求分析说明书.md index 2beb434..553a9b5 100644 --- a/docs/architecture/需求分析说明书.md +++ b/docs/architecture/需求分析说明书.md @@ -760,4 +760,5 @@ Agent 在调用任何业务数据前,必须通过统一数据网关验证请 * **标书费配置** 1. 收费节点定于标书发放前,付费后解锁招标文件查看权限; 2. 招标方案制定时可选择是否收取标书费; +* **是否需要英文版本**