doc/design/用户端_个人中心_20261013.md(入口所在页)、doc/design/用户端_登录注册_20261012.md(注册链路、扫码回填)192.168.110.111:3306/hugray-account(实际表结构优先于本文档)个人中心「我的邀请码」行当前点击仅弹占位 toast,本次改为**跳转到「我的邀请」页**(pages/profile/invite.vue):
account_user.my_referral_code)与**真实微信小程序码**,底部绿色「分享邀请码」按钮;scene = 邀请码,扫码直达注册页并**自动填入邀请码**(补 register.vue 的 onLoad scene 解析);「分享邀请码」分享注册页链接(?referralCode=xxx),同样自动填入。无订单模块,故「合计消费」直接用预留列
buy_amount_total(决策见 2.2);
等级徽标直接展示system_level原值,不扩展MemberLevelEnum(决策见 2.3)。
account_user 已具备本期所需列,**无需新增 DDL**:
| 列 | 类型 | 用途 |
|---|---|---|
referrer_id |
bigint | 上级(推荐人)会员ID,自连接 account_user.user_id;已有索引 idx_account_user_referrer |
referrer_bind_time |
datetime | 绑定时间,列表/详情「绑定日」来源 |
my_referral_code |
varchar(32) | 本人邀请码,唯一索引 uk_account_user_referral_code |
system_level |
char(1) | 等级原值(C / L1~L4),等级徽标来源 |
buy_amount_total |
decimal(16,2) | 购买金额合计(单位:元,现恒为 0,待订单模块回填) |
buy_amount_total(已确认)无订单表,暂用 account_user.buy_amount_total(单位:元,与列定义一致,前端加 ¥ 前缀展示)。当前恒为 0,待订单模块上线后回填,**前端无需改动**。
system_level 原值(已确认)MemberLevelEnum 仅到 L4,原型出现 L6(设计稿示意)。本期**不做 normalize**,将 system_level 原样下发(C / L1~L4 / 其它历史值),避免把非法值改写。前端空值兜底为 C。
wechat.miniapp 配置与 WeChatMiniappService(access_token 获取、缓存)**均在 ruoyi-auth**;ruoyi-user 无 wechat 配置、无 ruoyi-api-system 依赖。为避免重复实现 access_token 逻辑(DRY),**小程序码生成放在 ruoyi-auth**,新增 C 端接口,入参邀请码、返回 base64 图片。
scene 解析(关键缺口)pages/login/register.vue 当前无 onLoad(仅 onUnload),form.referralCode 仅支持手动输入。小程序码扫码后微信会把 scene 放入页面 options,需补 onLoad(options) 解码回填,否则「扫码自动填邀请码」不成立。
my_referral_code 在注册时生成(generateUniqueReferralCode),C 端会员必有,故「邀请码」Tab 无须空态;而 referrer_id 可为空(命中通用推荐码注册、或历史数据),故「邀请我的」Tab 必须有空态。
user_id;SecurityUtils.getUserId() 取会员身份,**C 端接口不接受前端传 userId**(防水平越权)。AccountProfileController(@RequestMapping("/user"),外部 /miniapp/account/user/**),网关路由已存在,**无需改网关**。AccountAuthController(外部 /miniapp/auth/invite-qrcode),**不在网关白名单**,需登录态。列表/详情中的手机号一律脱敏下发(复用 AccountUserServiceImpl.maskPhone,形如 136****6666),**不下发明文**。
统一响应体:C 端 R<T>(成功 code=200)。
GET /miniapp/account/user/invite-code(网关 StripPrefix=2 → 服务内 GET /user/invite-code)InviteCodeVo:| 字段 | 类型 | 说明 |
|---|---|---|
| referralCode | String | 本人邀请码(account_user.my_referral_code) |
GET /miniapp/auth/invite-qrcode?code={邀请码}(服务内 GET /invite-qrcode)| 参数 | 类型 | 必填 | 校验 | 说明 |
|---|---|---|---|---|
| code | String | 是 | @NotBlank + @Pattern(^[A-Z0-9]{8}$) |
邀请码,作为小程序码 scene |
InviteQrcodeVo:| 字段 | 类型 | 说明 |
|---|---|---|
| qrcode | String | 小程序码 PNG 的 base64 DataURI(data:image/png;base64,...),前端直接作为 <image src> |
getUnlimited 日配额。GET /miniapp/account/user/invitees(→ 服务内 GET /user/invitees)pageNum(默认 1)、pageSize(默认 10,与 TableSupport 默认一致)— 标准分页。account_user 中 referrer_id = 当前用户ID 且 del_flag='0',**按 referrer_bind_time 倒序**(最新在最前;referrer_bind_time 为空的历史行排最后)。TableDataInfo,即 { code, msg, rows, total }(**数据在顶层 rows,非 data 包裹**;total 为总数)。rows 元素 AccountInviteeVo:| 字段 | 类型 | 说明 |
|---|---|---|
| userId | Long | 下级会员ID |
| nickname | String | 昵称(为空前端回退脱敏手机号) |
| avatar | String | 头像地址(为空前端回退默认图标) |
| phone | String | 脱敏手机号(如 136****6666) |
| systemLevel | String | 等级原值(C / L1~L4) |
| bindDate | String | 绑定日(yyyy-MM-dd,源自 referrer_bind_time;为空不展示) |
| buyAmountTotal | BigDecimal | 合计消费(元,源自 buy_amount_total) |
GET /miniapp/account/user/referrer(→ 服务内 GET /user/referrer)referrer_id → 查该会员(del_flag='0')。AccountReferrerVo(无上级时各字段为 null,前端渲染空态):| 字段 | 类型 | 说明 |
|---|---|---|
| userId | Long | 上级会员ID |
| nickname | String | 昵称 |
| avatar | String | 头像地址 |
| phone | String | 脱敏手机号 |
| systemLevel | String | 等级原值(C / L1~L4) |
| bindDate | String | 绑定日(yyyy-MM-dd) |
本期无 DDL 变更,仅复用 account_user 既有列(见 2.1)。查询 SQL 遵循规范:
referrer_id 过滤 + referrer_bind_time 排序,命中 idx_account_user_referrer;**不挂 join**(避免干扰 PageHelper 的 count SQL)。user_id 主键查(复用 selectAccountUserById),不额外建方法。SELECT *:新增查询显式列出所需列。WeChatMiniappService.getAccessToken(access_token 获取 + Redis 缓存 7000s)。当前为 private,在**同类内新增小程序码方法**即可调用,无需改可见性。doPost 用 BodyHandlers.ofString() 仅适配 JSON;小程序码返回**二进制图片**,新增一个 doPostForBytes(BodyHandlers.ofByteArray())。wxacode.getUnlimited)POST https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN
Body: {
"scene": "{邀请码}", // 8 位 A-Z0-9,符合 scene 字符集与长度限制
"page": "pages/login/register", // 扫码直达注册页
"check_path": false, // 跳过页面存在性校验(体验版/开发版可扫码)
"env_version": "release", // 正式版;体验/开发调试可改 trial/develop
"width": 430
}
errcode/errmsg)。先按 Content-Type 判断:非图片 → 解析 JSON 记日志并抛业务异常。scene 缓存到 Redis(TTL 30 天),命中缓存直接返回。page 需为已发布页面;正式环境扫码前,小程序需先发布含 pages/login/register 的版本。pages/profile/invite.vue)琥歌瑞0928.pen)| 用途 | 取值 |
|---|---|
| 页面底色 | #F8FAFC(pen 根底色) |
| 主色(草绿) | #10B981(pen 强调色);按钮渐变 #34D399 → #10B981 |
| 等级/状态徽标 | 实心绿胶囊:底 #10B981、字 #FFFFFF,圆角 6rpx(原型 L1/L6 徽标) |
| 卡片 | 白底 #FFFFFF,圆角 16rpx,描边 #E2E8F0,阴影 0 6rpx 16rpx rgba(15,23,42,0.06) |
| 主文本 / 次文本 / 弱文本 | #0F172A / #64748B / #94A3B8 |
| 导航 | 自定义,返回箭头黑色 #0F172A,标题居中 #0F172A 34rpx 加粗 |
| Tab | 高亮 #10B981 + 底部 4rpx 绿色指示条;未选中 #64748B |
说明:个人中心页等级胶囊为金色渐变,本页**按原型用绿色胶囊**(更贴合 pen 的
#10B981 / #ECFDF5状态徽标体系)。
<image>(base64);下方文案「我的邀请码」+ 邀请码原值(可点击复制);底部整宽绿色胶囊按钮「分享邀请码」(open-type="share")。onShareAppMessage 返回 { title, path: '/pages/login/register?referralCode={邀请码}', imageUrl: {小程序码} },分享小程序注册页。wxacode.getUnlimited 的 scene 落到 pages/login/register 的 options.scene,由 register.vue 的 onLoad 解码回填。| 文件 | 改动 |
|---|---|
pages/profile/invite.vue |
新增:我的邀请页(三 Tab + 分享 + 空态) |
pages.json |
新增页面注册 pages/profile/invite(navigationStyle: "custom") |
pages/profile/index.vue |
handleMenuTap 中 invite 分支由「敬请期待」改为 uni.navigateTo({ url: '/pages/profile/invite' }) |
api/index.js |
新增 getInviteCode / getInviteQrcode(code) / getInvitees(params) / getReferrer |
pages/login/register.vue |
新增 onLoad(options):读 options.referralCode(分享链接)与 options.scene(扫码,需 decodeURIComponent)回填 form.referralCode |
referrer_bind_time 为空的历史行排序不报错;未登录访问由网关 401 拦截。/miniapp/account/**,需在 ruoyi-user 补 wechat 配置与 WeChat 客户端(会引入重复实现),请确认取舍。env_version / page 取值(默认 release + pages/login/register)。