用户端小程序 个人中心 接口 开发设计文档

  • 模块:ruoyi-user(会员业务)+ ruoyi-gateway(路由/鉴权头注入)
  • 日期:2026-10-13
  • 需求来源:“个人中心页的接口功能实现,根据现在展示的字段实现对应的 java 后端业务”
  • 关联前端:hugray-user-miniapp(pages/profile/index.vue)
  • 关联文档:doc/design/用户端_登录注册_20261012.md(C 端会员落库与令牌载体方案)、doc/design/用户端_首页与导航_20261012.md(9.3 个人中心页规格)
  • 数据权威源:192.168.110.111:3306/hugray-account(实际表结构优先于本文档)

一、功能概述

个人中心页(pages/profile/index.vue)当前为本地 mock,需由后端下发以下字段,页面据此渲染:

展示字段 页面位置 现状 本次是否提供
姓名 nickname 头部文本 mock 辉煌G891 是(account_user.nickname;注册未采集姓名字段,落库为空,前端回退展示脱敏手机号)
手机号 phone(脱敏) 头部名称回退 无 是(account_user.phone,脱敏为 133****5555,不下发明文)
会员等级 memberLevel 等级胶囊 C/L1~L4 mock L4 是(复用既有 account_user.system_level)
头像 avatar 头部头像 相机图标占位(「我的资料」页已支持点击上传更换) 是(已存在字段,有值前端渲染图片,无值回退图标)
今日 / 本月 / 累计收益 收益玻璃卡三栏 mock 10.00 / 400.00 / 128000.00 是(新增收益流水表,实时聚合)
仓库订单角标数量 菜单角标 mock 1 否(见 2.5,无数据来源,本期不入接口)

展示规则(沿用已确认业务约定):isRestrictedView = !isLoggedIn || memberLevel === 'C';**未登录或 C 普通用户**仅展示「收货地址」「联系我们」两行菜单并隐藏收益卡;**L1~L4** 展示全部内容。该判定由前端完成,后端只负责下发 memberLevel 真实值。

本期只新增 一个 C 端查询接口:GET /miniapp/account/user/info(对应前端已预留的 getMemberInfo())。


二、现状与关键约束

2.1 表结构缺口

account_user(hugray-account 库)现有字段:user_id, username, phone, password, nickname, avatar, gender, birthday, status, del_flag, my_referral_code, system_level, referrer_id, referrer_bind_time, create_*, update_*, remark。

已有「会员等级」字段 system_level(varchar(8),默认 C),无任何「收益」相关表/字段 → 收益部分本次新增;等级复用既有列,不再新增重复列。

2.2 已有接口不足以支撑

ruoyi-user 现有控制器:

  • AccountUserController(/user,后台 CRUD,全部挂 @RequiresPermissions)——面向后端管理,不适合 C 端调用。
  • AccountMemberInnerController(/member,@InnerAuth)——仅服务间调用,按手机号查会员 / 注册。

无按当前登录会员返回个人中心数据的接口 → 本次新增。

2.3 登录态与取数来源(已定方案)

  • C 端令牌沿用 RuoYi TokenService,网关 AuthFilter 校验通过后向目标服务注入请求头 user_id、username(SecurityConstants.DETAILS_USER_ID/DETAILS_USERNAME)。
  • ruoyi-user 侧通过 SecurityUtils.getUserId() 读取 user_id,即当前登录会员 ID。
  • 该路径**不经过** /miniapp/system/user/getInfo(后者面向后台 sys_user,见 2.4)。

2.4 前端预留入口的取舍

hugray-user-miniapp/api/index.js 现有两个未接线函数:

函数 路径 处理
getMemberInfo() /miniapp/account/user/info 本期采用(指向 ruoyi-user)
getUserInfo() /miniapp/system/user/getInfo 误导:指向后台 sys_user,与 C 端会员不同源;全仓无调用点,建议删除

结论:个人中心统一走 getMemberInfo();getUserInfo() 予以移除(避免后续误用)。

2.5 仓库订单角标数量:本期不提供

角标数量应来源于「仓库订单」,但 ruoyi-product 模块**当前仅有一个启动类**(无订单/仓库任何表与接口),无数据来源。本期接口不返回该字段,前端保持现状(withBadge 已登录展示,值仍为本地 mock 1),待订单模块就绪后由订单服务提供独立接口,不在本次范围。

2.6 金额单位约定

用户规范要求“金额用分(long)”。故接口 earnings 三值均以 分 返回(如 1000 = 10.00 元),前端新增 分→元 格式化后再展示为两位小数。


三、接口设计

统一响应体:R<T>(code=200 成功),与 C 端 /miniapp/** 既有约定一致;前端 utils/request.js 按 successCode=200 / unauthorizedCode=401 解包,调用方取 res.data。

规范说明:用户规则中的“Result<T>、code=0 成功、错误码分段”为通用模板;本工程实际框架为 RuoYi R/AjaxResult(200 成功)+ @RestControllerAdvice 全局异常。按“与现有工程保持一致”优先,采用框架既有约定。

3.1 查询当前会员个人中心信息

  • 外部路径:GET /miniapp/account/user/info(网关 StripPrefix=2 → 服务内 /user/info)
  • 鉴权:需登录。路径不在网关白名单内,未登录由 AuthFilter 直接返回 401,前端 request.js 自动跳登录页;**后端不做未登录分支**。
  • 入参:无(会员身份取自网关注入的 user_id 头)
  • 出参:R<AccountUserInfoVo>
{
  "code": 200,
  "msg": "操作成功",
  "data": {
    "userId": 100,
    "nickname": null,
    "phone": "133****5555",
    "avatar": null,
    "memberLevel": "L4",
    "earnings": { "today": 1000, "month": 40000, "total": 12800000 }
  }
}
字段 类型 说明
userId Long 会员ID
nickname String 姓名/昵称(注册未采集,可为空;为空时前端回退展示脱敏手机号)
phone String 手机号(**脱敏**,形如 133****5555,不下发明文)
avatar String 头像地址,可为空
memberLevel String 会员等级 C/L1~L4(空或非法兜底为 C;对外字段名沿用 memberLevel,数据源为 account_user.system_level)
earnings.today Long 今日收益(单位:分)
earnings.month Long 本月收益(单位:分)
earnings.total Long 累计收益(单位:分)
  • 错误提示:获取会员信息失败(会员不存在或查询异常)
  • 说明:手机号仅下发**脱敏**值(133****5555),不下发明文;userName(C 端即手机号)不下发,避免敏感信息外泄。

四、数据库设计

库:hugray-account(权威库 192.168.110.111:3306)。脚本:sql/hugray_account_20261013.sql(与代码同一次提交,含变更 + 回滚)。

4.1 会员等级:复用既有 account_user.system_level(无 DDL)

权威库 account_user 已存在 system_level varchar(8) DEFAULT 'C'(取值 C<L1<L2<L3<L4,从低到高),故**不再新增 member_level 重复列**。代码统一读写既有 system_level,对外出参仍为 memberLevel。

4.2 变更:新增收益流水表 account_earning_record

CREATE TABLE `account_earning_record` (
  `record_id`   bigint(20)   NOT NULL AUTO_INCREMENT COMMENT '收益记录ID',
  `user_id`     bigint(20)   NOT NULL                COMMENT '会员ID(关联 account_user.user_id)',
  `amount`      bigint(20)   NOT NULL DEFAULT 0      COMMENT '收益金额(单位:分,可正可负)',
  `source`      char(1)      NOT NULL                COMMENT '收益来源(1订单收益 2邀请奖励 3等级差价 9其他)',
  `biz_no`      varchar(64)  DEFAULT NULL            COMMENT '业务单号(同来源幂等去重)',
  `remark`      varchar(255) DEFAULT NULL            COMMENT '备注',
  `create_time` datetime     DEFAULT NULL            COMMENT '发生时间',
  `update_time` datetime     DEFAULT NULL            COMMENT '更新时间',
  PRIMARY KEY (`record_id`),
  KEY `idx_earning_user_time` (`user_id`, `create_time`),
  UNIQUE KEY `uk_earning_source_biz` (`source`, `biz_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员收益流水表';
  • 采用**流水 + 实时聚合**而非三个汇总结算字段:今日 / 本月随日期自然滚动,无需定时归零;同时天然支撑菜单「收入明细」页(后续)。
  • idx_earning_user_time 覆盖 WHERE user_id=? AND create_time>=? 聚合,避免全表扫描。
  • uk_earning_source_biz 由 (source, biz_no) 保证业务幂等;biz_no 为 NULL 时 MySQL 唯一索引不冲突(手工补录场景允许)。

回滚:

DROP TABLE IF EXISTS `account_earning_record`;

五、流程设计

5.1 查询个人中心信息(AccountUserServiceImpl.getAccountUserInfo)

STEP 1: 校验 userId 非空(未登录由网关拦截,此处兜底),为空抛「获取会员信息失败」
STEP 2: 按 userId 查 account_user(del_flag='0');为空抛「获取会员信息失败」
STEP 3: 查收益汇总(单条 SQL,单位分),无流水返回 0
STEP 4: 组装 AccountUserInfoVo:nickname/avatar 直取;phone 脱敏(`133****5555`);memberLevel 取 system_level,空或非法兜底 MemberLevelEnum.C
STEP 5: 返回 VO

收益汇总 SQL(一次查询出三值):

SELECT
  IFNULL(SUM(CASE WHEN create_time >= CURDATE() THEN amount END), 0)                        AS today,
  IFNULL(SUM(CASE WHEN create_time >= DATE_FORMAT(CURDATE(), '%Y-%m-01') THEN amount END), 0) AS month,
  IFNULL(SUM(amount), 0)                                                                     AS total
FROM account_earning_record
WHERE user_id = #{userId}

六、枚举与状态

名称 取值 说明
会员等级 memberLevel(源 system_level) C / L1 / L2 / L3 / L4 MemberLevelEnum:C=普通用户(受限展示);L1~L4=会员;含 code + desc + getByCode + normalize
会员状态 status 0 正常 / 1 停用 复用现有语义
删除标志 delFlag 0 存在 / 2 删除 复用现有语义
收益来源 source 1 订单收益 / 2 邀请奖励 / 3 等级差价 / 9 其他 EarningSourceEnum(本期仅建枚举,写入方待订单/邀请模块接入)

等级升降级规则(何种行为升到 L1~L4)属于会员体系策略,尚未定义。本期 system_level 由后台维护(AccountUserController 编辑),接口只负责读取下发;后续等级规则确定后新增独立升级流程。


七、影响范围与文件清单

新增(ruoyi-user)

文件 说明
enums/MemberLevelEnum.java 会员等级枚举(C/L1~L4,含 getByCode + normalize)
enums/EarningSourceEnum.java 收益来源枚举(1/2/3/9)
domain/AccountEarningRecord.java 收益流水实体(含字段注释)
domain/vo/AccountUserInfoVo.java 个人中心信息出参 VO(含脱敏手机号 phone)
domain/vo/EarningSummaryVo.java 收益汇总出参(today/month/total,单位分)
mapper/AccountEarningRecordMapper.java + resources/mapper/user/AccountEarningRecordMapper.xml 收益汇总查询
controller/AccountProfileController.java C 端接口 GET /user/info

修改

文件 改动
ruoyi-user domain/AccountUser.java 复用既有 systemLevel(源 system_level)字段;推荐关系字段为 referrerId(源 referrer_id)+ getter/setter + toString
ruoyi-user mapper/AccountUserMapper.xml system_level / referrer_id 纳入 resultMap / 列 / insert / update
ruoyi-user service/IAccountUserService.java + service/impl/AccountUserServiceImpl.java 新增 getAccountUserInfo(Long userId);注册不再以手机号填充姓名(nickname 留空);出参手机号脱敏
sql/hugray_account_20261013.sql 新增 DDL(变更 + 回滚)
前端 hugray-user-miniapp/api/index.js 删除误导且无调用的 getUserInfo()
前端 hugray-user-miniapp/utils/(新增格式化方法) 分→元 两位小数格式化
前端 hugray-user-miniapp/pages/profile/index.vue onShow 调 getMemberInfo() 替换 mock;头部名称优先姓名、为空回退脱敏手机号
doc/design/用户端_首页与导航_20261012.md 9.3 / 9.5 标注 mock 已由接口替换

网关无需改动:/miniapp/account/** → ruoyi-user 路由已存在。


八、边界与异常清单

# 场景 处理
1 未登录访问 网关 AuthFilter 返回 401,前端跳登录页;后端不做分支
2 user_id 头缺失/为空 服务内兜底判空,抛「获取会员信息失败」(不 NPE)
3 会员不存在 / 已逻辑删除 抛「获取会员信息失败」
4 system_level 为空或非法(历史脏数据) 兜底为 C,不影响页面渲染
5 无任何收益流水 三值均返回 0(分),前端展示 0.00
6 收益为负(退款冲正) amount 支持负数,聚合自然抵扣
7 金额单位一致性 接口统一返回分;前端统一格式化,禁止后端直接返回字符串金额
8 敏感信息 接口下发**脱敏**手机号(133****5555),不下发明文与 userName;日志手机号脱敏
9 越权 会员身份取自令牌注入头,不接受前端传入 userId,天然防水平越权
10 姓名未采集(注册未填) nickname 为空,前端头部回退展示脱敏手机号,不报错

九、规范符合性说明

  • 分层:Controller 只做取身份 + 转发,业务在 Service,SQL 在 Mapper;Controller 不直接调 Mapper。
  • 命名:getAccountUserInfo / selectEarningSummary 等见名知意;Entity / VO 分离。
  • 注释:类注释、字段注释(含取值与单位说明)、Javadoc、核心流程 // STEP x: 注释。
  • 魔法值:等级、收益来源收口枚举;CUCRATE 等 SQL 表达式内聚在 Mapper。
  • 异常:统一 ServiceException + 全局处理器,不散落 try-catch 拼返回值。
  • 日志:@Slf4j 占位符 + [业务标记] 前缀,敏感字段脱敏。
  • 数据库:字段显式长度 + COMMENT;聚合列有索引;无 SELECT *;无 ${} 拼接;无循环查库。
  • 单测:getAccountUserInfo(正常 / 会员不存在 / 无流水 / 等级空兜底 / 等级非法兜底)补充单测,Mockito Mock Mapper。
  • 说明(与现有工程一致优先):account_earning_record 主键沿用自增(与同库 account_user 及全工程 RuoYi 风格一致),未采用雪花 ID,作为已知项记录。

十、已确认决策

  1. 等级存储方式:**已定** —— 复用既有 account_user.system_level(C/L1~L4,默认 C),不新增 member_level 重复列。
  2. 收益数据模型:**已定** —— 新建流水表 account_earning_record + 实时聚合。
  3. 金额单位:**已定** —— 接口返回分(long),前端格式化为两位小数。
  4. 仓库订单角标:**已定** —— 本期不提供(ruoyi-product 尚无订单实现)。
  5. 数据库连接:**已定** —— ruoyi-user-dev.yml master 已由 localhost 改为权威库 192.168.110.111:3306/hugray-account(与 ruoyi-system/ruoyi-product 一致)。