巴青农资商城

商户入驻审核技术方案.md 18KB

商户入驻审核 — 技术方案

依据: 《商户入驻审核功能需求.md》v1.2
关联: 《商户管理技术方案.md》v1.5、《店铺管理技术方案.md》v1.2.5、《商城入驻协议技术方案.md》v1.0、《会员管理技术方案.md》v1.0.1、《关联需求分析.md》v1.2
范围: C 端 完整字段 申请提交;平台 审核→公示→完成入驻;公示完成后落库商户+首店+经营账号;站内消息。
原则: 申请状态与商户 cert_status 分离;平台 POST /agri/merchant 不写 申请单。
v1.1: apply_status 增加 3公示中approve 仅进公示;completePublicity/processExpiredPublicity 建档;校验类 EntryApplyFormValidator;DDL 见 sql/ 目录。
v1.2: GET /api/merchant/entry/context;已有商户管理员 仅开店铺 提交与公示完成 复用商户 建档分支;form_json 扩展 shopOnlyModeexistingMerchantId


1. 技术架构

选型
基础框架 RuoYi v3.9.2springboot2 分支)
数据库 MySQL 5.7.39
ORM / 权限 MyBatis;@PreAuthorizeAjaxResult / TableDataInfo
申请状态 apply_status char(1):0 待审 1 已完成入驻 2 未通过 3 公示中
校验 EntryApplyFormValidator.validateMobileSubmit(新主体);validateShopOnlySubmit(已有商户管理员)
表单快照 form_json LONGTEXT(详情展示 + 审核落库映射)
日志 审核 @Log

1.1 模块落位

baqing-shop
├── com.ruoyi.web.modules.entry
│   ├── controller.MerchantEntryApplyController        # 平台审核
│   ├── controller.MerchantEntryApplyAppController     # C 端提交/我的申请
│   ├── domain.BizMerchantEntryApply
│   ├── mapper.BizMerchantEntryApplyMapper
│   ├── service.IMerchantEntryApplyService
│   ├── dto.EntryApplySubmitDTO / EntryApplyRejectDTO
│   ├── vo.EntryApplyListVO / EntryApplyDetailVO / EntryApplyContextVO
│   ├── constant.MerchantEntryApplyConstants
│   ├── support.EntryApplyFormMapper                   # JSON ↔ 商户/店铺 DTO
│   ├── support.EntryApplyFormValidator                # C 端完整字段校验
│   ├── task.MerchantEntryPublicityTask                # 公示期满自动建档(每 30 分钟)
│   └── support.MemberEntryMessageSupport              # 站内消息
sql/
├── biz_merchant_entry_apply.sql
├── biz_merchant_entry_form_json说明.sql               # form_json 字段对照
└── biz_member_message.sql                             # 可选:会员站内消息

包名 entrycontent 下「入驻协议」区分:协议=配置;本模块=申请单

1.2 业务链

biz_member
    └── biz_merchant_entry_apply(apply_status)
            ├── C 端 GET /api/merchant/entry/context(是否仅开店铺)
            ├── C 端 POST /api/merchant/entry/apply
            │       └── IMerchantEntryAgreementFacade.assertAccepted
            │       └── 新主体:EntryApplyFormValidator.validateMobileSubmit
            │       └── 仅开店铺:validateShopOnlySubmit + EntryApplyFormMapper.buildSubmitFromExistingMerchant
            │
            ├── 平台 GET list/detail、PUT approve/reject/completePublicity
            │
            ├── approve(事务)
            │       └── apply_status=3;写 publicity_*;发「公示中」消息
            │
            └── completePublicity / processExpiredPublicity(事务)
                    ├── shopOnlyMode=false:insert biz_merchant + bindAccount + createShop
                    ├── shopOnlyMode=true:复用 existingMerchantId;bindAccount(若无);createShop
                    ├── apply_status=1;回填 merchant_id/shop_id
                    └── biz_member_message(入驻完成通知)
模块 关系
商城入驻协议 C 端提交前 assertAccepted
商户管理 公示完成后 insert 商户;insertMerchant 平台表单接口
店铺管理 公示完成后 createShop
会员管理 member_id;消息收件人
商品/订单 无直接依赖

1.3 跨模块 Facade

接口 提供方 方法 用途
IMerchantEntryAgreementFacade content assertAccepted(boolean) C 端提交
IMerchantAccountBindService merchant bindAccountOnMerchantCreate(...) 会员→经营账号
IShopService store createShop(ShopCreateDTO) 首家店
IMerchantFacade merchant 唯一性校验可复用 Mapper 证件/信用代码

1.4 状态联动

事件 biz_merchant_entry_apply biz_merchant
approve status=3(公示中) 新增
completePublicity status=1;回填 merchant_id/shop_id 新增复用(shopOnlyMode)
reject status=2 新增
改入驻协议 不变 不变
平台代录入商户 无申请行 直接新增

2. 数据库设计

2.1 本模块表 biz_merchant_entry_apply

权威 DDL 与 COMMENT 见 sql/biz_merchant_entry_apply.sql

字段 类型 说明
apply_id bigint PK 申请 ID
apply_no varchar(32) UK 申请编号,如 EA+日期+序号
apply_status char(1) 0 待审 1 已完成入驻 2 未通过 3 公示中
merchant_type char(1) 1 个人 2 企业
member_id bigint 申请人会员 ID
member_code varchar(64) 冗余检索:会员名称
subject_label varchar(128) 列表「申请信息」:姓名/企业名
contact_name varchar(64) 联系人
contact_phone varchar(20) 联系人手机
id_card_no varchar(32) 个人证件号(唯一校验)
credit_code varchar(32) 企业信用代码(唯一校验)
merchant_name varchar(128) 申请中商户名称(唯一校验)
shop_name varchar(128) 申请中店铺名称(唯一校验)
form_json longtext 完整表单 JSON 快照
reject_reason varchar(500) 驳回原因
merchant_id bigint 公示完成 后回填
shop_id bigint 公示完成 后回填
apply_time datetime 提交时间
audit_by varchar(64) 审核人(进入公示或驳回时)
audit_time datetime 审核时间
publicity_start_time datetime 公示开始(approve 时)
publicity_end_time datetime 公示结束(默认 start+7 天)
del_flag char(1) 0 存在 2 删
create_by/time, update_by/time 审计

索引:

索引 用途
uk_apply_no 编号
idx_status_time (apply_status, apply_time) 待审列表
idx_member_status (member_id, apply_status) 同会员待审校验
idx_member_code (member_code) 关键词检索
idx_id_card (id_card_no) 个人唯一
idx_credit_code (credit_code) 企业唯一

2.2 会员站内消息 biz_member_message(建议)

字段 类型 说明
message_id bigint PK
member_id bigint 收件会员
biz_type varchar(32) ENTRY_AUDIT
biz_id bigint apply_id
title varchar(128) 如「入驻审核通过」
content varchar(1000) 含驳回原因摘要
read_flag char(1) 0 未读 1 已读
create_time datetime

若已有统一消息中心,可替换本表;接口契约不变。

2.3 form_json 结构(约定)

{
  "subject": { },
  "biz": { },
  "shop": { "shopName", "shopAvatar", "shopPhone", "shopDesc" },
  "agreementAccepted": true
}
  • subject / biz 字段名与 biz_merchant、商户管理 DTO 一致,便于 EntryApplyFormMapper.toMerchantFromJson() / toShopCreateDTO()
  • C 端必填字段清单见 sql/biz_merchant_entry_form_json说明.sql;提交时由 EntryApplyFormValidator 校验。
  • 详情接口解析 JSON 填 EntryApplyDetailVO 各分区。

2.4 与既有表关系

关系
biz_merchant completePublicity 后 insert;merchant_id 回写 apply
biz_shop completePublicity 后 insert;shop_id 回写
biz_merchant_account 绑定会员时 insert
biz_member member_id FK 逻辑

平台 biz_merchantapply_id 字段:代录入商户 source_type 可选扩展(1 平台 / 2 C 端),非本期必做。


3. 状态机(Service)

操作 前置 结果 副作用
submit 无 blocking(0/3);协议已勾选;完整字段+唯一性通过 apply_status=0
approve status=0 status=3 写 publicity_*;「公示中」消息
completePublicity status=3 且 now>=publicity_end_time status=1 商户+店+账号+完成消息
processExpiredPublicity 定时扫描 status=3 且已到期 同上 批量 completePublicity
reject status=0;rejectReason 非空 status=2 驳回消息

4. 接口设计

4.0 C 端 — 入驻上下文 GET /api/merchant/entry/context(v1.2)

说明
鉴权 会员 Token(MemberAuthInterceptorMemberContext/api/merchant/entry/** 已纳入 MemberWebConfig,排除 agreement/status)
用途 进入申请页前判断是否 仅开店铺 模式

响应 EntryApplyContextVO

字段 说明
shopOnlyMode 当前会员是否已是某商户 商户管理员
canShopOnlyApply shopOnlyMode=true 且商户 可开店 时为 true
blockReason 不可仅开店铺原因(经营未完善/冻结/注销)
merchantId、merchantType 已有商户 ID、类型
subjectLabel、merchantName 列表/页头展示
subject、biz 主体/经营快照(BizMerchant 结构,供 C 端只读展示)

canShopOnlyApply 条件: cert_status=正常biz_complete=1

4.1 C 端 — 提交申请 POST /api/merchant/entry/apply

说明
鉴权 会员 Token(MemberAuthInterceptor
Body EntryApplySubmitDTO:subject + biz + shop + agreementAccepted仅开店铺 时 Body 可仅含 shop + agreementAccepted)
分支 校验 说明
新主体 validateMobileSubmit + 全量唯一性 同 v1.1
仅开店铺 会员已是商户管理员;assertMerchantEligibleForShopOnlyvalidateShopOnlySubmitbuildSubmitFromExistingMerchant 合并 DB form_jsonshopOnlyMode=trueexistingMerchantId;唯一性 跳过 本商户证件/信用代码/商户名称
校验 说明
协议 IMerchantEntryAgreementFacade.assertAccepted
待审/公示中 member_id 无 status in (0,3)(countBlockingByMemberId
完整字段 新主体:EntryApplyFormValidator.validateMobileSubmit;仅开店铺:validateShopOnlySubmit
唯一性 证件/信用代码/merchant_name/shop_name(仅开店铺时 exclude existingMerchantId
会员昵称 绑定路径须 nick_name 非空

成功: { applyId, applyNo, applyStatus: "0" }

4.2 C 端 — 我的申请 GET /api/merchant/entry/my(可选)

说明
鉴权 会员 Token
响应 当前会员最近 N 条申请摘要(状态、时间、驳回原因)

4.3 平台 — 列表 GET /agri/merchantEntryApply/list

说明
权限 agri:merchantEntryApply:list
Query keyword(member_code)、applyStatuspageNum/pageSize
排序 status=0 → apply_time ASC;否则 apply_time DESC

4.4 平台 — 待审数量 GET /agri/merchantEntryApply/pendingCount

| 响应 | { "pendingCount": n } |

4.5 平台 — 详情 GET /agri/merchantEntryApply/{applyId}

| 权限 | agri:merchantEntryApply:query | | 响应 | EntryApplyDetailVO:基础信息 + 解析 form_json 各分区 + 公示时间 + canApprove/canReject/canCompletePublicity |

4.6 平台 — 审核通过(进入公示) PUT /agri/merchantEntryApply/approve/{applyId}

| 权限 | agri:merchantEntryApply:audit | | 日志 | title=商户入驻审核通过 | | Body | 可选 { "confirmed": true } 二次确认 |

成功: { applyStatus: "3", publicityEndTime } 返回 merchantId/shopId。

4.7 平台 — 完成公示 PUT /agri/merchantEntryApply/completePublicity/{applyId}

| 权限 | agri:merchantEntryApply:audit | | 前置 | status=3 且公示期已满(publicity_end_time <= now) | | 日志 | title=商户入驻公示完成 |

成功: { merchantId, shopId };申请 status=1。

定时任务 MerchantEntryPublicityTask(默认每 30 分钟)调用 processExpiredPublicity(),对到期公示单自动执行与 4.7 相同的建档逻辑(操作人 system)。

4.8 平台 — 审核驳回 PUT /agri/merchantEntryApply/reject

| 权限 | agri:merchantEntryApply:audit | | Body | { "applyId", "rejectReason" } |

| 校验 | rejectReason 必填 |

4.9 C 端 — 消息 GET /api/member/message/list(可选独立模块)

| 说明 | 读取 biz_member_message;本方案可由 MemberEntryMessageSupport 写入 |


5. Service 要点

5.1 submitApply(memberId, dto)

assertAgreement → assertNoBlockingApply(memberId)
→ findMerchantByMemberAdmin(memberId)
    ├── 非空(仅开店铺)
    │     → assertMerchantEligibleForShopOnly
    │     → validateShopOnlySubmit(dto)
    │     → buildSubmitFromExistingMerchant(merchant, dto.shop)
    │     → assertUnique(..., existingMerchantId)
    └── 空(新主体)
          → validateMobileSubmit(dto)
          → assertUnique(...)
→ build BizMerchantEntryApply + form_json(shopOnlyMode, existingMerchantId)
→ insert

5.2 resolveEntryContext(memberId)(v1.2)

findMerchantByMemberAdmin → 无则 shopOnlyMode=false
→ 有则 shopOnlyMode=true;填充 subject/biz 快照
→ resolveShopOnlyBlockReason → canShopOnlyApply / blockReason

5.3 approve(applyId, dto, operator)@Transactional

load apply(status=0) → re-validate unique
→ update apply: status=3, publicity_start/end, audit_*
→ memberMessageSupport.sendPublicity(...)
→ return { applyStatus, publicityEndTime }

5.4 completePublicity(applyId, operator) / finalizeEntry@Transactional

load apply(status=3) → assert publicity_end <= now
→ re-validate unique(含 existingMerchantId 排除)
→ 若 shopOnlyMode 或会员已是商户管理员
    → reconcileWithExistingMerchant(复用商户 + createShop)
→ 否则
    → validateMobileSubmit → insert merchant → bindAccount → createShop
→ update apply: status=1, merchant_id, shop_id
→ memberMessageSupport.sendPass(...)

5.5 reject(dto, operator)

load apply(status=0) → update status=2, reject_reason
→ memberMessageSupport.sendReject(memberId, reason)

5.6 公示配置

配置键 说明 默认
agri.merchant.entry.publicityDays 公示天数 7

5.7 经营账号(会员路径)

规则
关联行 account_id=member_id(= sys_user.user_id),merchant_idshop_id=NULL
登录凭证 沿用会员既有 sys_useruser_name=会员名称,nick_name=会员昵称)
角色 grantRoleIfAbsent(memberId, merchant)

6. 业务规则映射(EA)

编号 实现
EA1 仅 C 端 submitApply 写 apply 表
EA2 apply_status 独立字段
EA3 approve/reject 校验 status=0
EA4 reject 校验 rejectReason
EA5 completePublicity 事务内商户+店+消息
EA5a approve 进公示,不 insert merchant/shop
EA6 reject 不 insert merchant/shop
EA7 EntryApplyFormMapper 字段对齐商户/店铺
EA8 IMerchantEntryAgreementFacade
EA9 list 支持 applyStatus 筛选
EA10 list keyword → member_code like
EA11 countBlockingByMemberId(status 0 或 3)> 0 阻断 submit
EA12 唯一:merchant 表 + apply 表 status in (0,1,3)
EA13 驳回后可新 apply_id
EA14 biz_member_message
EA15 不调用商品/订单 Service
EA16 resolveEntryContext + 仅开店铺 submit 分支
EA17 form_json.shopOnlyMode / existingMerchantId
EA18 finalizeEntryreconcileWithExistingMerchant 复用商户

7. 菜单权限(建议)

菜单 权限
商户入驻审核 agri:merchantEntryApply:list
查看详情 agri:merchantEntryApply:query
审核 agri:merchantEntryApply:audit

8. 非本期实现

申请批量审核、审核 SLA、申请单修改、短信通知、游客免会员提交、申请单导出。


9. 文档索引

文档 版本
商户入驻审核功能需求.md v1.2
商户管理技术方案.md v1.5
店铺管理技术方案.md v1.2.5
商城入驻协议技术方案.md v1.0

10. 修订记录

版本 说明
v1.0 首版:申请单表、平台/C 端接口、审核落库
v1.0.1 曾用 shopEntryApply / biz_shop_entry_apply 命名
v1.0.2 定名 商户入驻审核/agri/merchantEntryApplybiz_merchant_entry_apply;规则 EA1~EA15
v1.1 审核→公示→完成入驻;apply_status=3completePublicity/定时任务;EntryApplyFormValidator;公示字段 DDL
v1.2 GET /contextvalidateShopOnlySubmitbuildSubmitFromExistingMerchantreconcileWithExistingMerchant;EA16~EA18

文档版本:v1.2 · MySQL 5.7.39 · RuoYi v3.9.2-springboot2 · 关联《商户入驻审核功能需求.md》v1.2