doc/design/用户端_实名认证_20261013.md(个人实名认证,本期复用其提交/审核链路范式)192.168.110.111:3306/hugray-account(实际表结构优先于本文档)「我的资料」页(pages/profile/edit.vue)「企业/个体户认证」行当前点击仅弹占位 toast,本次改为**跳转到企业/个体认证四步向导页**:
pages/profile/company-certification.vue,顶部为**四段式步骤条**(企业信息 / 法人信息 / 收款信息 / 提交审核),已完成打勾、当前高亮,底部分步表单 + 「下一步 / 提交资料」按钮(原型见 4 张 UI 稿);account_certification_apply(subject_type 取 2 个体工商户 / 3 企业、audit_status='0' 待审核),并联动 account_user.company_auth_status='1'(企业认证中),使其出现在后台**主体认证审核列表**;companyAuthStatus 显示真实状态(未认证 / 认证中 / 已认证 / 认证失败),与「实名认证」徽标**相互独立**;后台「审」链路(列表 / 详情 / 通过 / 驳回)**已存在**,本次做两处增强:审核结果按主体类型分流回写 auth_status / company_auth_status;审核详情页补展示企业认证新增字段。
account_certification_apply.subject_type(char(1))取值语义已预置:**1个人 2个体工商户 3企业**,个人实名走 '1',企业/个体走 '2'/'3',**无需改类型语义,只需补列**。
account_certification_apply 与 account_certification 现有企业相关列仅到「营业执照」为止(company_name、credit_code、legal_person、registered_region、company_address、register_date、license_valid_period、license_image)。原型所需的**营业执照有效期类型、法人身份证正反面、法人身份证有效期、法人身份证详细地址、负责人姓名/电话/邮箱、收款类型、银行卡照片、银行卡号、开户城市**共 13 列缺失,需补。
account_user 当前只有一个 auth_status(个人实名认证状态),而个人中心需**两行独立徽标**(「实名认证」/「企业个体户认证」)。若企业认证复用 auth_status,提交企业认证会同时把「实名认证」徽标改成「认证中」,语义错误。故**新增 account_user.company_auth_status**,个人 / 企业互不覆盖(已确认)。
现有 selectLatestApplyByUserId / countPendingApplyByUserId 不区分主体类型,企业认证上线后会把企业申请当作个人申请回填/防重。本次为两者都加主体类型过滤:个人限 subject_type='1',企业限 subject_type in ('2','3')。
user_id;SecurityUtils.getUserId() 取会员身份,**C 端接口不接受前端传 userId**(防水平越权)。AccountProfileController(@RequestMapping("/user"),外部 /miniapp/account/user/**)上**新增**两条企业认证接口,与个人认证接口并列。AccountCertificationApplyController(外部 /account/user/certification/**)**前缀不同域**,无冲突;网关 /miniapp/account/** 路由已存在,**无需改网关**。account_certification_apply.id 为 bigint AUTO_INCREMENT,沿用既有 useGeneratedKeys="true" keyProperty="id";列按 <if> 动态拼,未填字段不落列。
统一响应体:C 端 R<T>(成功 code=200)。
POST /miniapp/account/user/company-certification(网关 StripPrefix=2 → 服务内 POST /user/company-certification)AuthFilter 直接 401;会员身份取自网关注入的 user_id 头,**不接受前端传 userId**。CompanyCertificationApplyDto),字段与校验见下表:| 步骤 | 字段 | 类型 | 必填 | 校验 | 说明(对应 DB 列) |
|---|---|---|---|---|---|
| 企业信息 | subjectType | String | 是 | @NotBlank + @Pattern(^[23]$) |
主体类型:2个体工商户 / 3企业(subject_type) |
| 企业信息 | companyName | String | 是 | @NotBlank+@Size(max=128) |
企业/个体名称(company_name) |
| 企业信息 | licenseImage | String | 是 | @NotBlank+@Size(max=500) |
营业执照图片地址(license_image) |
| 企业信息 | creditCode | String | 是 | @NotBlank+@Size(max=32) |
统一社会信用代码(credit_code) |
| 企业信息 | licenseValidType | String | 是 | @NotBlank+@Pattern(^[12]$) |
营业执照有效期类型:1长期 / 2短期(license_valid_type) |
| 企业信息 | licenseValidPeriod | String | 短期必填 | @Size(max=32);类型=2 时服务层必填 |
营业执照有效期起止(license_valid_period,存 2024-01-01~2034-01-01) |
| 企业信息 | registeredRegion | String | 是 | @NotBlank+@Size(max=128) |
营业执照注册地区(registered_region) |
| 企业信息 | companyAddress | String | 是 | @NotBlank+@Size(max=255) |
营业执照详细地址(company_address) |
| 法人信息 | legalPerson | String | 是 | @NotBlank+@Size(max=64) |
法人姓名(legal_person) |
| 法人信息 | legalIdCardFront | String | 是 | @NotBlank+@Size(max=500) |
法人身份证人像面图片(legal_id_card_front) |
| 法人信息 | legalIdCardBack | String | 是 | @NotBlank+@Size(max=500) |
法人身份证国徽面图片(legal_id_card_back) |
| 法人信息 | legalIdValidType | String | 是 | @NotBlank+@Pattern(^[12]$) |
法人身份证有效期类型(legal_id_valid_type) |
| 法人信息 | legalIdValidPeriod | String | 短期必填 | @Size(max=32);类型=2 时服务层必填 |
法人身份证有效期起止(legal_id_valid_period) |
| 法人信息 | legalIdAddress | String | 是 | @NotBlank+@Size(max=255) |
法人身份证详细地址(legal_id_address) |
| 法人信息 | contactName | String | 是 | @NotBlank+@Size(max=64) |
负责人姓名(contact_name) |
| 法人信息 | contactPhone | String | 是 | @NotBlank+@Size(max=20) |
负责人联系电话(contact_phone) |
| 法人信息 | contactEmail | String | 是 | @NotBlank+@Size(max=128) |
负责人邮箱(contact_email) |
| 收款信息 | payeeType | String | 是 | @NotBlank+@Size(max=16) |
收款类型(payee_type) |
| 收款信息 | bankCardImage | String | 是 | @NotBlank+@Size(max=500) |
银行卡号码面照片(bank_card_image) |
| 收款信息 | bankCardNo | String | 是 | @NotBlank+@Size(max=32) |
银行卡号(bank_card_no) |
| 收款信息 | bankCity | String | 是 | @NotBlank+@Size(max=128) |
开户城市(bank_city) |
R<Void>(成功即 code=200)@NotBlank/@Pattern 提示 + 业务提示「短期有效期必须填写起止日期」/「已有企业认证申请正在审核中,请勿重复提交」/「主体类型不合法」。GET /miniapp/account/user/company-certification(→ 服务内 GET /user/company-certification)subject_type in ('2','3'),del_flag='0',id desc limit 1),出参 CompanyCertificationStatusVo:| 字段 | 说明 |
|---|---|
| subjectType / companyName / licenseImage / creditCode / licenseValidType / licenseValidPeriod / registeredRegion / companyAddress | 企业信息回填 |
| legalPerson / legalIdCardFront / legalIdCardBack / legalIdValidType / legalIdValidPeriod / legalIdAddress | 法人信息回填 |
| contactName / contactPhone / contactEmail | 负责人信息回填 |
| payeeType / bankCardImage / bankCardNo / bankCity | 收款信息回填 |
| auditStatus | 0待审核 1已通过 2已驳回;**为空表示从未提交** |
| auditRemark | 驳回原因(audit_status='2' 时有值) |
无申请时返回**空字段对象**(各字段为 null),前端按「未认证」处理,不返回 404。
GET /miniapp/account/user/info(既有)AccountUserInfoVo 新增 companyAuthStatus 字段(account_user.company_auth_status 原值 0/1/2/3),供「我的资料」页「企业/个体户认证」徽标回显。GET /account/user/certification/list、GET /account/user/certification/detail/{id}、PUT /account/user/certification/audit(权限 member:certification:audit)**沿用**。企业申请同链路进入列表(subject_type='2'/'3'、待审核在前)。增强点:
apply.subjectType 写回——个人写 auth_status,企业/个体写 company_auth_status(通过时同步 account_user.subject_type);detail.vue 补展示企业/个体新增字段(见 7.3)。库:hugray-account。新增 DDL 脚本:hugray-server/sql/hugray_account_company_certification_20261013.sql(沿用既有幂等过程 hugray_add_column 风格;与代码同一次提交)。
account_certification_apply / account_certification 各新增 13 列| 列 | 类型 | 注释 |
|---|---|---|
| license_valid_type | varchar(16) | 营业执照有效期类型(1长期 2短期) |
| legal_id_card_front | varchar(500) | 法人身份证人像面图片 |
| legal_id_card_back | varchar(500) | 法人身份证国徽面图片 |
| legal_id_valid_type | varchar(16) | 法人身份证有效期类型(1长期 2短期) |
| legal_id_valid_period | varchar(32) | 法人身份证有效期(长期/起止文本) |
| legal_id_address | varchar(255) | 法人身份证详细地址 |
| contact_name | varchar(64) | 负责人姓名 |
| contact_phone | varchar(20) | 负责人联系电话 |
| contact_email | varchar(128) | 负责人邮箱 |
| payee_type | varchar(16) | 收款类型 |
| bank_card_image | varchar(500) | 银行卡号码面照片 |
| bank_card_no | varchar(32) | 银行卡号 |
| bank_city | varchar(128) | 开户城市 |
account_user 新增 1 列| 列 | 类型 | 注释 |
|---|---|---|
| company_auth_status | char(1) DEFAULT '0' | 企业/个体认证状态(0未认证 1审核中 2已认证 3认证失败) |
license_valid_period沿用既有varchar(32):2024-01-01~2034-01-01共 21 字符,够用,不改类型。
pages/profile/company-certification.vue)STEP 1: onShow 校验登录态(ensureLogin),未登录跳登录页
STEP 2: 调 GET /company-certification 拉取状态与资料
STEP 3: 按 auditStatus 决定首屏:
'' 未认证 → 停在第 1 步空表单
'2' 已驳回 → 停在第 1 步并回填资料,展示驳回原因
'0' 审核中 → 直接进入第 4 步「资料审核中」占位页
'1' 已通过 → 第 4 步展示「认证已通过」
STEP 4: 第 1~3 步表单填写,点「下一步」逐级校验当前步必填项,通过则 step+1,否则 toast 首个缺失项
STEP 5: 第 3 步(收款信息)按钮为「提交资料」,点后整表单再校验一次,通过则 POST 提交
STEP 6: 成功后进入第 4 步「您的资料正在审核中,请耐心等待」;失败提示后端信息
STEP 7: 步骤条已完成的步骤打勾,可点已完成步骤回退修改(未提交前)
交互细节(对齐原型):
- 有效期类型 = 长期 时,其**起止日期行隐藏**且不参与校验;= 短期 时显示且必填(已确认)。
- 「营业执照注册地区」「开户城市」用 <picker mode="region">(沿用 pages/address/add.vue 范式);「营业执照详细地址」「法人身份证详细地址」为文本输入。
- 图片项(营业执照 / 法人身份证人像面 / 法人身份证国徽面 / 银行卡号码面)统一走 uni.chooseImage + uploadAvatarFile(/file/upload)拿到 url 后存本地表单,**均为必填**(已确认)。
- 有效期起止日期用两个 <picker mode="date">(开始 / 截止)并列在同一行内展示,回填时拼为 起~止 文本;存储为 license_valid_period / legal_id_valid_period 文本。
submitCompanyCertification)STEP 1: 校验 userId 非空(未登录由网关拦截,此处兜底),为空抛业务异常
STEP 2: 校验 subjectType ∈ {2 个体工商户, 3 企业};非法抛「主体类型不合法」
STEP 3: 有效期类型=短期(2) 时,对应起止日期必填(服务层兜底,防绕过 Controller)
STEP 4: 防重闸门:该会员若存在 subject_type in ('2','3') 且 audit_status='0' 的未删除申请,
抛「已有企业认证申请正在审核中,请勿重复提交」
STEP 5: 组装申请快照:subject_type、各资料字段、audit_status='0'、create_by=登录用户名
STEP 6: insertCertificationApply 落 account_certification_apply(自增回填 id)
STEP 7: 联动 account_user.company_auth_status='1'(企业认证中,单列更新语句)
STEP 8: STEP 6/7 同事务(@Transactional),任一失败整体回滚
auditCertificationApply 增强)STEP 1: 既有并发闸门(where audit_status='0')+ 驳回必填意见 不变
STEP 2: 取 apply.subjectType 判断分支:
subject_type='1'(个人)→ 写 account_user.auth_status(2 通过 / 3 失败),行为同现状
subject_type∈{'2','3'} → 写 account_user.company_auth_status(2 通过 / 3 失败)
且通过时同步 account_user.subject_type = apply.subjectType
STEP 3: 通过分支继续 saveCertificationSnapshot(补全企业新增字段)
C 端提交 ─► account_certification_apply.audit_status='0' + account_user.company_auth_status='1'
│
后台「通过」─► audit_status='1' + company_auth_status='2' + subject_type 同步 + 落 account_certification
后台「驳回」─► audit_status='2' + company_auth_status='3' + 记审核意见
| 名称 | 取值 | 说明 |
|---|---|---|
subject_type 主体类型 |
1 个人 / 2 个体工商户 / 3 企业 |
企业向导页提交 2/3(页内选择);个人页提交 1 |
audit_status 审核状态 |
0 待审核 / 1 已通过 / 2 已驳回 |
提交置 0,审核改 1/2 |
auth_status 个人认证状态 |
0 未认证 / 1 审核中 / 2 已认证 / 3 认证失败 |
个人实名专用 |
company_auth_status 企业认证状态 |
0 未认证 / 1 审核中 / 2 已认证 / 3 认证失败 |
企业/个体专用(本期新增) |
license_valid_type / legal_id_valid_type 有效期类型 |
1 长期 / 2 短期 |
长期隐藏起止日期;短期必填 |
「我的资料」页徽标映射:auth_status →「实名认证」行;company_auth_status →「企业/个体户认证」行(0未认证、1认证中、2已认证、3认证失败)。
| 文件 | 说明 |
|---|---|
domain/dto/CompanyCertificationApplyDto.java |
企业/个体认证提交入参(含校验注解与字段注释) |
domain/vo/CompanyCertificationStatusVo.java |
企业/个体认证状态与资料回填出参 |
src/test/.../AccountCertificationApplyServiceImplTest.java |
追加提交/审核分流用例(正常、重复提交拒绝、短期缺日期、状态分流) |
| 文件 | 改动 |
|---|---|
domain/AccountCertificationApply.java |
新增 13 个企业/个体字段 + getter/setter + toString |
domain/AccountCertification.java |
同步新增 13 个字段 |
mapper/AccountCertificationApplyMapper.java |
新增 selectLatestCompanyApplyByUserId、countPendingCompanyApplyByUserId;selectLatestApplyByUserId→selectLatestPersonalApplyByUserId(加 subject_type='1')、countPendingApplyByUserId→countPendingPersonalApplyByUserId(加 subject_type='1') |
resources/mapper/user/AccountCertificationApplyMapper.xml |
resultMap / selectCertificationApplyVo / 列表 / insert 补新增列;主体类型过滤调整;新增企业两条查询 |
resources/mapper/user/AccountCertificationMapper.xml |
resultMap / selectCertificationVo / insert / update 补新增列 |
mapper/AccountUserMapper.java |
新增 updateUserCompanyAuthStatus(AccountUser) |
resources/mapper/user/AccountUserMapper.xml |
新增 updateUserCompanyAuthStatus(只写 company_auth_status,通过时带 <if> 同步 subject_type) |
service/IAccountCertificationApplyService.java |
新增 submitCompanyCertification(Long, CompanyCertificationApplyDto)、getCompanyCertificationStatus(Long) |
service/impl/AccountCertificationApplyServiceImpl.java |
常量补 SUBJECT_INDIVIDUAL='2'/SUBJECT_COMPANY='3';实现企业提交与状态查询;auditCertificationApply 按主体类型分流;saveCertificationSnapshot 补字段 |
controller/AccountProfileController.java |
新增 POST /user/company-certification、GET /user/company-certification |
domain/vo/AccountUserInfoVo.java |
新增 companyAuthStatus 字段 |
service/impl/AccountUserServiceImpl.java |
getAccountUserInfo 填充 companyAuthStatus |
| 文件 | 改动 |
|---|---|
views/member/certification/detail.vue |
「主体资料」区块补展示:主体类型、营业执照有效期类型/起止、法人身份证人像/国徽面(image-preview)、法人身份证有效期类型/起止、法人身份证详细地址、负责人姓名/电话/邮箱、收款类型、银行卡照片(image-preview)、银行卡号、开户城市 |
列表页
index.vue的主体类型/主体名称列已由subject_type与companyName \|\| realName覆盖,**无需改动**。
| 文件 | 说明 |
|---|---|
pages/profile/company-certification.vue |
企业/个体四步向导页(步骤条 + 分步表单 + 图片上传 + 地区/日期选择) |
| 文件 | 改动 |
|---|---|
pages.json |
注册 pages/profile/company-certification(navigationStyle: custom) |
api/index.js |
新增 getCompanyCertificationStatus()(→ GET)、submitCompanyCertification(data)(→ POST) |
pages/profile/edit.vue |
「企业/个体户认证」行由 handlePlaceholder 改为 uni.navigateTo 跳向导页;companyStatus 改按 /info 返回的 companyAuthStatus 映射回显 |
网关无需改动;无需新增菜单/权限。
| 文件 | 说明 |
|---|---|
hugray-server/sql/hugray_account_company_certification_20261013.sql |
两张认证表各补 13 列 + account_user 补 company_auth_status(幂等,含回滚注释) |
| # | 场景 | 处理 |
|---|---|---|
| 1 | 未登录访问 | 网关 AuthFilter 返回 401,前端跳登录页;后端不做分支 |
| 2 | user_id 头缺失/为空 |
服务内兜底判空,抛业务异常(不 NPE) |
| 3 | 必填项为空 / 纯空格 | DTO @NotBlank 拦截,返回字段级中文提示;前端「下一步」逐级预校验并 toast 首个缺失项 |
| 4 | 有效期类型=长期 | 起止日期行隐藏且不校验;短期时必填 |
| 5 | 有效期类型=短期但未填日期 | 服务层兜底抛「短期有效期必须填写起止日期」 |
| 6 | 图片未上传 | 按必填拦截(toast「请上传XX图片」) |
| 7 | 主体类型非法(非 2/3) | 服务层抛「主体类型不合法」 |
| 8 | 已有待审核企业申请再次提交 | 服务层企业防重闸门提示「已有企业认证申请正在审核中,请勿重复提交」 |
| 9 | 个人 / 企业申请互相干扰 | 状态查询与防重均按 subject_type 隔离;认证状态分列 auth_status / company_auth_status |
| 10 | 审核通过 / 驳回 | 按 subject_type 分流回写,通过时同步 subject_type 并落 account_certification |
| 11 | 落库或状态联动失败 | 同一事务回滚,返回统一错误,不产生半更新 |
| 12 | 越权 | 会员身份取自令牌注入头,不接受前端传 userId,天然防水平越权 |
| 13 | 三方核验 / 格式校验 | 本期明确不做,仅基础必填校验 |
| 14 | 图片上传失败 | 沿用 uploadAvatarFile 错误处理,toast 提示并可重试 |
submitCompanyCertification / getCompanyCertificationStatus / selectLatestCompanyApplyByUserId / countPendingCompanyApplyByUserId / updateUserCompanyAuthStatus 见名知意;DTO / VO / Entity 分离。// STEP x: 分步注释;实体新增字段附列名与取值注释。subject_type、audit_status、auth_status、company_auth_status、*_valid_type 取值抽为常量/枚举语义。insert + 状态联动 同事务;审核 更新申请 + 状态分流 + 落档 同事务。SELECT *;无 ${} 拼接;无循环查库;DDL 与代码同次提交。company_auth_status)。account_user.company_auth_status,个人 / 企业徽标各自独立,互不覆盖。subject_type 存 3 / 2(比原型多一个字段)。