依据: 《会员管理功能需求.md》v1.0
关联: 《订单管理功能需求.md》v1.0.1、《商品管理功能需求.md》v1.3.3、《店铺管理功能需求.md》v1.3.2、《关联需求分析.md》v1.2
范围: 本文以 会员主数据、收货地址、平台端查询/启用 及 订单只读聚合 为主;biz_order由订单模块维护,本文给出 ER、Facade 契约与会员侧接口;C 端注册/登录接口单列 §4(与平台共用表)。
原则: 会员与biz_merchant_account分表;手机号del_flag=0唯一;消费统计 O11 与订单一致。
| 项 | 选型 |
|---|---|
| 基础框架 | RuoYi v3.9.2(springboot2 分支) |
| 数据库 | MySQL 5.7.39 |
| ORM / 权限 / 响应 | MyBatis;@PreAuthorize;AjaxResult / TableDataInfo |
| 密码 | C 端 SecurityUtils.encryptPassword(BCrypt);存于 sys_user.password |
| 账号 | 与 sys_user 复用:member_id = user_id;会员角色 role_key=member |
| 脱敏 | 列表手机号中间 4 位 *(如 177****9136) |
| 日志 | 启用状态变更 @Log |
baqing-shop/src/main/java/com/ruoyi/web/modules/account/
├── controller/MemberController.java # 平台 /agri/member
├── controller/MemberAppController.java # C 端 /api/member
├── service/impl/MemberServiceImpl.java
├── service/impl/MemberAppServiceImpl.java
├── service/impl/MemberAddressServiceImpl.java
├── support/MemberRegistrationSupport.java # C 端注册 + 平台添加(共用)
├── support/MemberSysUserSupport.java # 解析 role_key=member
├── domain/BizMember.java、BizMemberAddress.java
└── mapper/BizMemberMapper.xml、BizMemberAddressMapper.xml
resources/mapper/account/BizMemberMapper.xml # JOIN sys_user;列表过滤 member 角色
sql/biz_member.sql # biz_member 扩展表 + member 角色初始化
sys_user(账号:user_name/phonenumber/nick_name/password/avatar/status)
└── biz_member(member_id = user_id;等级/消费统计/注册时间)
├── biz_member_address(1:N)
│
├── IMemberFacade ──► 订单模块
└── biz_order.member_id
| 字段映射 | sys_user | biz_member(业务层别名) |
|---|---|---|
| 主键 | user_id | member_id |
| 手机号 | phonenumber | mobile |
| 会员名称 | user_name | memberCode |
| 昵称 | nick_name | nickName |
| 密码 | password | password |
| 头像 | avatar | avatar |
| 状态 | status(0正常 1停用) | status |
注册(事务): insertUser(角色 member)→ insert biz_member(member_id = userId)。
| 模块 | 表/职责 |
|---|---|
| 会员(本文) | biz_member、biz_member_address;平台列表/详情/启用 |
| 订单管理 v1.0 | biz_order 等;履约写操作;向会员回写消费汇总 |
| 商户/店铺/商品 | 无会员表;经营账号 不关联 member_id |
| 接口 | 提供方 | 调用方 | 方法 |
|---|---|---|---|
IMemberFacade |
本模块 | 订单、C 端下单 | getMember、isMemberEnabled、existsByMobile、refreshConsumption |
IOrderFacade |
订单(目标包 com.ruoyi.web.modules.order,待实现) |
本模块 | pageOrdersByMember、getOrderDetail、hasUnfinishedOrdersByShop/Merchant(见《订单管理技术方案》§1.3) |
订单未实现前:
pageOrdersByMember由account.facade.DefaultOrderFacade桩返回空页;实现后迁入order.facade并以《订单管理技术方案》v1.0.2 为准。
消费统计(O11)实现二选一(推荐 A):
| 方案 | 说明 |
|---|---|
| A 冗余字段 | biz_member.order_count、total_amount;订单 已完成 时订单模块调用 IMemberFacade.refreshConsumption(memberId) 同事务 |
| B 实时聚合 | 列表/详情每次 SUM biz_order;数据量大时再改 A |
| 事件 | biz_member |
biz_order |
商户/店铺 |
|---|---|---|---|
| 禁用会员 | status=1 |
不变(M15) | 不变 |
| 订单已完成 | 刷新 order_count/total_amount |
状态→已完成 | — |
| 商户冻结/店停业 | 不变 | 仅禁 新 下单 | 各模块规则 |
| 表名 | 说明 |
|---|---|
biz_member |
C 端买家主档 |
biz_member_address |
收货地址簿 |
| 表名 | 说明 |
|---|---|
biz_order |
member_id FK;DDL 见《订单管理技术方案.md》v1.0 |
biz_member + sys_user权威 DDL:
sql/biz_member.sql。账号列在sys_user;查询通过biz_memberJOINsys_user。
biz_member(扩展表)
| 字段 | 类型 | 说明 |
|---|---|---|
| member_id | bigint PK | = sys_user.user_id(非自增) |
| member_level | tinyint | 选填;字典 biz_member_level |
| order_count | int | 已完成订单笔数 |
| total_amount | decimal(12,2) | 已完成实付合计 |
| register_time | datetime | 注册时间 |
| create_by/time, update_by/time, remark | 审计 |
sys_user(账号,注册时写入)
| 字段 | 说明 |
|---|---|
| user_name | 会员名称(C 端可随机生成) |
| nick_name | 昵称 |
| phonenumber | 手机号;del_flag=0 唯一 |
| password | BCrypt |
| avatar | 头像 URL |
| status | 0 启用 1 禁用 |
| 角色 | 注册时分配 role_key=member |
biz_member_address| 字段 | 类型 | 说明 |
|---|---|---|
| address_id | bigint PK | |
| member_id | bigint | FK |
| consignee_name | varchar(64) | 收货人 |
| mobile | varchar(20) | 联系电话 |
| region_code | varchar(64) | 省市区编码(区县级 code) |
| region_name | varchar(128) | 省市区名称(省/市/区 / 拼接) |
| detail_address | varchar(256) | 详细地址 |
| is_default | char(1) | 0 否 1 是;每会员至多一条默认 |
| del_flag | char(1) | 0 存在 2 删除 |
| create_time, update_time |
| 表 | 索引/约束 | 说明 |
|---|---|---|
| biz_member | PRIMARY (member_id) |
member_id 非自增,= sys_user.user_id |
| biz_member | KEY idx_register (register_time) |
列表默认排序 |
| sys_user | 应用层 checkPhoneUnique |
phonenumber 在 del_flag='0' 时唯一(M2) |
| sys_user | 应用层 checkUserNameUnique |
user_name(会员名称)唯一 |
| sys_user_role | — | 注册/平台添加时写入 role_id(role_key=member) |
| biz_member_address | PRIMARY、idx_member |
member_id, del_flag |
完整建表与 member 角色初始化 见
sql/biz_member.sql。
勿 在biz_member存mobile/password/status等账号列;查询通过biz_memberINNER JOINsys_user。
-- biz_member:仅扩展字段(账号在 sys_user)
CREATE TABLE `biz_member` (
`member_id` bigint(20) NOT NULL COMMENT '与 sys_user.user_id 一致',
`member_level` tinyint(4) DEFAULT NULL,
`order_count` int(11) NOT NULL DEFAULT '0',
`total_amount` decimal(12,2) NOT NULL DEFAULT '0.00',
`register_time` datetime NOT NULL,
`create_by` varchar(64) DEFAULT '',
`create_time` datetime DEFAULT NULL,
`update_by` varchar(64) DEFAULT '',
`update_time` datetime DEFAULT NULL,
`remark` varchar(500) DEFAULT NULL,
PRIMARY KEY (`member_id`),
KEY `idx_register` (`register_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='C端会员扩展表';
唯一约束(应用层): sys_user.phonenumber 在 del_flag='0' 时不可重复(M2);MemberRegistrationSupport / ISysUserService.checkPhoneUnique。
| dict_type | 用途 |
|---|---|
| biz_member_status | status:0 启用 / 1 禁用 |
| biz_member_level | member_level(tinyint;如 0=普通;选填) |
基路径: /agri/member
权限前缀: agri:member
| 方法 | 路径 | 权限 | 说明 |
|---|---|---|---|
| GET | /list |
list | 会员分页列表 |
| POST | / |
add | 平台添加会员(无需短信验证码) |
| GET | /{memberId} |
query | 会员详情(基本 + 地址列表) |
| PUT | /{memberId}/status |
edit | 启用/禁用 |
| GET | /{memberId}/orders |
query | 该会员订单分页(只读) |
| GET | /{memberId}/orders/{orderId} |
query | 订单详情(只读;校验 member_id) |
不提供 导入、改等级、余额积分(需求 §13)。
POST /| Body | 说明 |
|---|---|
| mobile | 必填;11 位手机号 |
| password | 必填;BCrypt 入库 |
| memberCode | 选填;sys_user.user_name;未填则 8 位随机唯一名 |
| nickName | 选填;未填同会员名称 |
| avatar | 选填;sys_user.avatar |
| memberLevel | 选填 |
| status | 选填;默认 0 启用 |
| remark | 选填 |
流程: 同事务 insertUser(角色 member)→ insert biz_member(member_id=user_id)。
成功: 返回 memberId。
GET /list| Query | 说明 |
|---|---|
| pageNum, pageSize | 分页 |
| keyword | 可选;会员名称、昵称或手机号 模糊(M11) |
| status | 可选;0/1 |
过滤: u.del_flag='0';EXISTS 子查询要求 sys_user_role + sys_role.role_key='member'(MemberServiceImpl 注入 memberRoleKey,排除仅平台/商户账号)。
排序: biz_member.register_time DESC。
实现: BizMemberMapper.selectList → selectVo JOIN sys_user,memberRoleExists 片段。
rows:
| 字段 | 说明 |
|---|---|
| memberId, memberCode, nickName | memberCode 为会员名称 |
| mobile | 脱敏 |
| memberLevel, memberLevelLabel | memberLevel 为 tinyint 字典值,可空;label 为展示文案 |
| status, statusLabel | 字典 |
| orderCount, totalAmount | 来自冗余字段(与 O11 一致) |
| registerTime |
GET /{memberId}{
"memberId": 1,
"memberCode": "用户A",
"nickName": "用户A",
"mobile": "17712349136",
"memberLevel": null,
"status": "0",
"orderCount": 3,
"totalAmount": 1280.50,
"registerTime": "2026-05-01 10:00:00",
"addressList": [
{
"addressId": 10,
"consigneeName": "张三",
"mobile": "17712349136",
"regionCode": "540622",
"regionName": "西藏自治区/那曲市/比如县",
"detailAddress": "某某路1号",
"isDefault": "1",
"fullAddress": "西藏自治区那曲市比如县某某路1号"
}
]
}
| 规则 | 说明 |
|---|---|
| 不存在 | code!=200,msg 会员不存在 |
| 手机号 | 平台 query 权限可看完整号(需求 §10 权限) |
PUT /{memberId}/status{ "status": "1" }
| 校验 | 说明 |
|---|---|
| status | 仅 0 / 1 |
| 禁用 | 记操作日志;不 调订单关闭 |
GET /{memberId}/orders委托 IOrderFacade.pageOrdersByMember;Query 对齐需求 §6.3:
| Query | 说明 |
|---|---|
| pageNum, pageSize | |
| orderNo | 订单编号 |
| goodsName | 商品名称 |
| payType, payStatus | 支付 |
| shipStatus | 发货/订单履约状态 |
| consigneeName, consigneeMobile, address | 收货 |
| logisticsCompany | 物流公司 |
| beginTime, endTime | 下单时间 |
rows: 与《订单管理》列表字段对齐子集;operateType=readonly(前端隐藏发货/关闭按钮,M6)。
GET /{memberId}/orders/{orderId}biz_order.member_id = memberId,否则 403/业务异常。| 场景 | msg |
|---|---|
| 会员不存在 | 会员不存在 |
| 订单不属于该会员 | 无权查看该订单 |
| 禁用成功 | 操作成功 |
统一包装:AjaxResult / TableDataInfo(code、msg、data/rows/total)。
MemberAppController)C 端专册: 注册/登录见 《会员注册登录技术方案》 v1.2;本节保留摘要。
基路径: /api/member
鉴权: MemberWebConfig + MemberAuthInterceptor;register/login/sms/send/serviceAgreement/** 匿名且不经拦截器;其余须会员 Token → MemberContext.getMemberId()。
MemberWebConfig: 拦截 /api/member/**(排除 login/register 等)、/api/merchant/entry/**(排除 agreement/status)、购物车/结算/订单等;详见 C 端《会员注册登录技术方案》§3.1。
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /sms/send |
发送验证码 |
| POST | /register |
手机号+密码+确认密码;无验证码 |
| POST | /login |
手机号或会员名称+密码;返回 Token |
| GET | /profile |
当前会员(密码脱敏) |
| PUT | /profile |
改 user_name/nick_name/avatar/password(updateAccount) |
| GET | /address/list |
地址列表 |
| POST | /address |
新增地址 |
| PUT | /address |
修改地址 |
| DELETE | /address/{addressId} |
删除地址 |
| PUT | /address/{addressId}/default |
设默认 |
协作接口(content 模块 · 同基路径前缀):
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /serviceAgreement |
买家服务协议(MallServiceAgreementAppController) |
| GET | /serviceAgreement/status |
注册/登录开放状态 |
| 规则 | 说明 |
|---|---|
| M2 | 注册/添加前 countByMobile(JOIN sys_user) |
| M4 | sys_user.status=1 禁止登录 |
| M7 | 不 校验 biz_merchant_account 绑定(分表、无 FK) |
| 注册事务 | insertUser(角色 member)→ insert biz_member(member_id=user_id) |
biz_order 字段(权威 DDL)完整定义见 sql/biz_order.sql 及《订单管理技术方案》§2(v1.0.1)。会员模块主要消费:
| 字段 | 说明 |
|---|---|
| order_id, order_no | 主键与展示编号 |
| member_id | 关联 biz_member.member_id |
| shop_id | 店铺归属 |
| order_status | 3=已完成(O11 统计);0/1/2=未完成 O10 |
| pay_amount | 实付;O11 SUM 字段 |
| del_flag | 固定 0;删单用 order_status=5 |
明细、物流见 biz_order_item、biz_order_logistics_trace。
订单状态 → 已完成
→ IOrderFacade 内或监听
→ IMemberFacade.refreshConsumption(memberId)
→ UPDATE biz_member SET order_count=?, total_amount=?
WHERE 统计条件 status=已完成 AND del_flag=0
refreshConsumption 建议 按 member_id 重算(避免并发漏加):
SELECT COUNT(1), IFNULL(SUM(pay_amount),0)
FROM biz_order
WHERE member_id = #{memberId} AND order_status = '3' AND del_flag = '0'
平台 会员管理 与 订单管理 共用 IOrderFacade.getOrderDetail;会员 Controller 禁止 暴露发货/关闭 URL(M6)。
| 菜单 | 权限标识 |
|---|---|
| 会员管理 | agri:member:list |
| 添加会员 | agri:member:add |
| 查看详情 | agri:member:query |
| 启用/禁用 | agri:member:edit |
订单只读挂在 query;不写 agri:member:remove(本期无删会员需求,逻辑删除预留)。
| 项 | 说明 |
|---|---|
| 余额、积分、标签、导入 | 需求 §13 |
| 商家端查会员 | 不做 |
| 会员等级自动升级 | 仅 member_level 展示 |
本期已实现: 平台
POST /agri/member添加会员(无短信验证码);C 端注册/登录/资料/地址;列表仅 role_key=member 用户。
| 需求规则 | 技术落点 |
|---|---|
| M1~M3 买家、只读订单 | §1.2、§3.5~3.6 |
| M2 手机号唯一 | sys_user.phonenumber + checkPhoneUnique / countByMobile |
| M4 启用 | sys_user.status + IMemberFacade.isMemberEnabled |
| M5/O11 消费统计 | biz_member.order_count/total_amount + §5.2 |
| M6 订单不写 | 无发货类接口 |
| M7 与经营账号隔离 | 分表、无 FK |
| M9 订单仅当前会员 | member_id 强制过滤 |
| M11 检索 | keyword 匹配 user_name / nick_name / phonenumber(API 字段仍为 memberCode 等) |
| 列表范围 | 仅 role_key=member(memberRoleExists) |
| M12 订单检索 | §3.5 Query |
| M14 地址只读(平台) | 详情 addressList;C 端 §4 维护 |
文档版本:v1.4 · MySQL 5.7.39 · RuoYi v3.9.2-springboot2 · 地址表 region_code/region_name · C 端注册/登录见《消费者APP/会员注册登录/会员注册登录技术方案.md》v1.2 · 关联《会员管理功能需求.md》v1.1、《会员管理测试用例.md》v1.1