主题
客户端小程序 — 个人中心
上级文档:客户端小程序
概述
对应主文档 §8.8
个人中心是用户管理个人信息、查看权益、使用功能的统一入口。同时承载运动日历和身体数据记录两大工具性功能,提升用户使用频率和粘性,让小程序不仅是消费工具,更是用户的健身助手。
页面路由
| 路由 | 页面 | 说明 |
|---|---|---|
/pages/profile/index | 个人中心 | 功能导航主页 |
/pages/profile/face-manage | 人脸管理 | 重新录入(从未入场成功时可见) |
/pages/profile/workout-calendar | 运动日历 | 健身打卡记录 + 日历视图 |
/pages/profile/badges | 我的勋章 | 勋章成就展示 |
/pages/profile/body-data | 身体数据 | 体重/体脂/围度等数据记录与趋势图 |
/pages/profile/body-data/add | 记录身体数据 | 新增一条身体数据记录 |
个人中心页要素
用户信息区
| 要素 | 说明 |
|---|---|
| 头像 | 微信头像或自定义头像 |
| 昵称 | 微信昵称或自定义昵称 |
| 手机号 | 脱敏展示(如 138****8888) |
| 会员卡摘要 | 当前有效会员卡:套餐名称 + 到期日期(如有) |
| 「编辑资料」入口 | 跳转资料编辑页 |
运动数据快览卡片
在用户信息区下方展示,吸引用户持续使用。
| 要素 | 说明 |
|---|---|
| 本月打卡 | 如「本月已练 8 天」 |
| 累计打卡 | 如「累计 45 天」 |
| 连续打卡 | 如「🔥 连续 3 天」 |
| 最新勋章 | 如「🏅 坚持达人」+ 勋章图标 |
| 「查看运动日历 >」 | 跳转运动日历页 |
功能菜单列表
| 菜单项 | 图标 | 跳转 | 说明 |
|---|---|---|---|
| 我的会员 | 🟢 | /pages/profile/membership | 查看有效/历史会员 |
| 我的订单 | 📋 | /pages/order/list | 订单列表 |
| 优惠券 | 🎫 | /pages/coupon/list | 我的优惠券(未纳入当前范围时隐藏) |
| 运动日历 | 📅 | /pages/profile/workout-calendar | 健身打卡记录 |
| 我的勋章 | 🏅 | /pages/profile/badges | 勋章成就展示 |
| 身体数据 | 📊 | /pages/profile/body-data | 体重/体脂/围度记录 |
| 人脸管理 | 📸 | /pages/profile/face-manage | 重新录入(从未入场成功时可见;入场成功后隐藏) |
| 兑换券码 | 🎁 | /pages/voucher/redeem | 外部平台券码兑换 |
| 淋浴控制 | 🚿 | /pages/shower/index | 启动/查看淋浴 |
| 联系客服 | 📞 | 客服方式 | 展示微信号/电话 |
| 语言切换 | 🌐 | 语言设置 | 中/EN 切换 |
| 关于我们 | ℹ️ | 关于页面 | 版本信息、隐私政策、用户协议 |
我的会员摘要区
在用户信息下方展示当前有效会员卡的快捷摘要:
| 要素 | 说明 |
|---|---|
| 会员卡名称 + 状态标签 | 如「月卡 · 有效」 |
| 到期时间或剩余天数 | 如「剩余 18 天」或具体到期日期 |
| 「查看全部会员 >」 | 跳转会员详情页 |
运动日历
定位:用户的健身打卡记录工具,通过可视化激励用户高频到店消费。
运动日历页要素
| 要素 | 说明 |
|---|---|
| 返回按钮 + 「运动日历」标题 | — |
| 月份切换 | 左右箭头切换月份,默认当前月 |
| 日历视图 | 月度日历,标记到店打卡日期 |
| 统计摘要 | 本月打卡天数、累计打卡天数、最长连续打卡 |
| 打卡详情 | 点击某天可查看当天的到店/离店时间、运动时长 |
日历视图规则
| 规则 | 说明 |
|---|---|
| 打卡标记 | 到店记录对应的日期用绿色圆点标记 |
| 今日 | 当前日期用蓝色高亮边框 |
| 运动时长 | 有多次进出的日期显示总时长(如「1.5h」) |
| 无记录 | 无打卡的日期为空白 |
| 月份范围 | 可查看最近 12 个月的记录 |
打卡数据来源
打卡数据基于刷脸进离店记录自动生成,用户无需手动打卡。
| 数据项 | 来源 | 说明 |
|---|---|---|
| 到店时间 | 刷脸进门记录 | faceLog.enteredAt |
| 离店时间 | 刷脸出门记录 | faceLog.exitedAt |
| 运动时长 | 离店时间 - 到店时间 | 自动计算 |
| 打卡天数 | 有到店记录的日期数 | 按日去重 |
统计指标
| 指标 | 计算规则 | 展示 |
|---|---|---|
| 本月打卡天数 | 当月有到店记录的日期数 | X 天 |
| 累计打卡天数 | 所有月份有到店记录的日期总数 | X 天 |
| 连续打卡 | 从今天往前连续有到店记录的天数 | 🔥 连续 X 天 |
| 本月运动总时长 | 当月所有运动时长之和 | X.X 小时 |
| 本月最长单次 | 当月最长单次运动时长 | X.X 小时 |
| 平均每次时长 | 总时长 / 到店次数 | X.X 小时 |
勋章成就体系
通过勋章系统激励用户持续到店健身,提升使用频率和粘性。勋章基于用户行为自动解锁,不可手动领取。
勋章定义
| 勋章 | 条件 | 图标建议 | 稀有度 |
|---|---|---|---|
| 初来乍到 | 首次刷脸成功入场 | 🌟 | 普通 |
| 连续 3 天 | 连续 3 天有到店记录 | 🔥 | 普通 |
| 连续 7 天 | 连续 7 天有到店记录 | 💪 | 稀有 |
| 连续 30 天 | 连续 30 天有到店记录 | 👑 | 传说 |
| 月度达人 | 单月打卡 ≥ 12 天 | 🏅 | 稀有 |
| 坚持不懈 | 累计打卡 ≥ 30 天 | 💎 | 稀有 |
| 百日打卡 | 累计打卡 ≥ 100 天 | 🏆 | 传说 |
| 晨练达人 | 累计 5 次在 8:00 前到店 | 🌅 | 普通 |
| 夜猫子 | 累计 5 次在 21:00 后到店 | 🌙 | 普通 |
| 健身老手 | 累计运动时长 ≥ 100 小时 | ⏱️ | 稀有 |
勋章页面要素
| 要素 | 说明 |
|---|---|
| 返回按钮 + 「我的勋章」标题 | — |
| 勋章统计 | 已解锁 X / 总计 Y 枚 |
| 勋章展示 | 网格布局,每枚勋章展示图标 + 名称 + 解锁条件 |
| 已解锁 | 彩色图标 + 「已获得 YYYY-MM-DD」 |
| 未解锁 | 灰色图标 + 解锁进度(如「3/7 天」) + 解锁条件文字 |
| 稀有度标签 | 普通(无标签)/ 稀有(蓝色)/ 传说(金色) |
勋章解锁规则
- 勋章由服务端在每次刷脸入场/离店时异步计算并更新
- 前端通过
GET /api/v1/user/badges获取当前勋章列表和解锁状态 - 新勋章解锁时,运动日历页顶部显示「🎉 恭喜获得 [勋章名]」横幅提示(3 秒后自动消失)
- 勋章数据仅展示用途,不涉及任何权益发放
运营配置
管理后台可动态增减勋章定义,无需发版。
| 配置项 | 说明 |
|---|---|
| 勋章列表 | 运营可在管理后台新增/编辑/停用勋章 |
| 解锁条件 | 支持的条件类型:打卡天数、连续天数、到店时段、运动时长 |
| 勋章图标 | 上传 SVG/PNG 图标 |
| 稀有度 | 普通 / 稀有 / 传说 |
运动日历异常处理
| 异常 | 处理 |
|---|---|
| 数据加载失败 | 展示错误态 + 「重试」 |
| 无打卡记录 | 展示空态插画 + 「还没有打卡记录,去门店开练吧!」 |
| 离店记录缺失 | 进店无离店时,运动时长显示「进行中」或取最新一次离店时间 |
| 时区问题 | 统一使用服务器时区(UTC+8),前端按本地时区展示日期 |
身体数据记录
定位:用户的身体数据管理工具,让小程序成为用户的健身数据仪表盘,提升工具属性和留存。
身体数据列表页要素
| 要素 | 说明 |
|---|---|
| 返回按钮 + 「身体数据」标题 | — |
| 当前数据卡片 | 最新一次记录的核心数据展示 |
| 趋势图 | 体重/体脂率的变化趋势折线图 |
| 数据维度 Tab | 体重 / 体脂率 / 身体围度 |
| 历史记录列表 | 按时间倒序展示所有记录 |
| 「记录数据」按钮 | 右下角悬浮按钮,跳转新增记录页 |
当前数据卡片
展示最新一条记录的核心数据:
| 数据项 | 单位 | 说明 |
|---|---|---|
| 体重 | kg | 最新记录体重 |
| 体脂率 | % | 最新记录体脂率 |
| BMI | — | 自动计算(体重 / 身高²) |
| 上次记录 | — | 与上次记录的变化(↑/↓/—) |
数据维度
| 维度 | 字段 key | 单位 | 说明 |
|---|---|---|---|
| 体重 | weight | kg | 手动录入 |
| 体脂率 | bodyFatRate | % | 手动录入 |
| 身高 | height | cm | 首次设置后通常不变 |
| 胸围 | chest | cm | 手动录入 |
| 腰围 | waist | cm | 手动录入 |
| 臀围 | hip | cm | 手动录入 |
| 大臂围 | arm | cm | 手动录入 |
| 大腿围 | thigh | cm | 手动录入 |
趋势图
| 要素 | 说明 |
|---|---|
| 图表类型 | 折线图 |
| 时间范围 | 近 30 天 / 近 90 天 / 近半年 / 全部 |
| 数据点 | 每个记录点在图上标注 |
| 变化标注 | 最新值与首值的变化(↑X.X kg / ↓X.X%) |
| 无数据 | 展示空态 + 「记录第一条数据吧」 |
新增记录页要素
| 要素 | 说明 |
|---|---|
| 返回按钮 + 「记录数据」标题 | — |
| 日期选择 | 默认今天,可选历史日期 |
| 数据输入表单 | 各维度输入框(带单位提示) |
| 备注 | 可选文本输入(如「今天做了力量训练」) |
| 「保存」按钮 | 校验后提交 |
输入校验规则:
| 字段 | 规则 |
|---|---|
| 体重 | 20.0 ~ 300.0 kg,保留 1 位小数 |
| 体脂率 | 3.0 ~ 60.0 %,保留 1 位小数 |
| 身高 | 100.0 ~ 250.0 cm,保留 1 位小数 |
| 围度 | 30.0 ~ 200.0 cm,保留 1 位小数 |
| 日期 | 不可选未来日期,最早可选 1 年前 |
历史记录列表
| 字段 | 说明 |
|---|---|
| 日期 | 记录日期 |
| 体重 | 体重值 |
| 体脂率 | 体脂率值 |
| 变化趋势 | 与上一条的差值(↑/↓) |
| 操作 | 「查看」跳转详情 / 「删除」二次确认 |
身体数据异常处理
| 异常 | 处理 |
|---|---|
| 数据加载失败 | 展示错误态 + 「重试」 |
| 无历史记录 | 展示空态 + 引导记录第一条数据 |
| 删除记录 | 二次确认「确定删除该条记录?」→ 确认后删除 |
| 同一天重复记录 | 允许,同一天可有多条记录(如晨起和睡前) |
| 输入异常值 | 前端校验拦截 + 提示合理范围 |
人脸管理页要素
隐私原则:用户不可查看自己已录入的人脸照片,避免不安感。
- 返回按钮 + 「人脸管理」标题
- 人脸状态卡片:已录入/未录入 + 录入时间(不展示人脸照片)
- 隐私说明:「人脸数据用于健身房刷脸进出验证,您的照片不会被展示给任何人」
- 「重新录入」按钮(仅在已录脸且从未入场成功时展示)
- 删除说明:「如需删除人脸数据,请联系客服」
- 「📞 联系客服」入口
- 入场成功后自动隐藏:如用户曾刷脸成功入场,整个人脸管理入口从个人中心菜单消失(前端通过
hasSuccessfulEntry字段判断)
客服与帮助
客服入口方案
- 个人中心和首页各保留一个固定客服入口
- 点击后展示客服微信号/电话号码
- 支持一键复制微信号
- 支持拨打电话(
wx.makePhoneCall)
帮助页要素
- 常见问题(FAQ)列表
- 每个问题可展开查看答案
- 底部固定「联系客服」入口
接口
text
# 用户资料
GET /api/v1/user/profile
Auth: JWT
Response: {
id, nickname, avatarUrl, phone,
faceEnrolled: boolean,
faceEnrolledAt: string | null,
locale: 'zh' | 'en',
tags: string[] // 用户标签(用于 Banner 分层)
}
PUT /api/v1/user/profile
Auth: JWT
Body: { nickname?: string, locale?: string }
Response: { success: boolean }
# 运动日历
GET /api/v1/user/workout-calendar
Auth: JWT
Query: { year, month } // 如 2026, 3
Response: {
monthDays: { // 当月打卡日期列表
'2026-03-15': {
enterAt: string, // 进店时间
exitAt: string | null, // 离店时间(null 表示未离店)
duration: number // 运动时长(分钟)
},
...
},
stats: {
monthDays: number, // 本月打卡天数
totalDays: number, // 累计打卡天数
currentStreak: number, // 连续打卡天数
monthDuration: number, // 本月总运动时长(分钟)
monthMaxSingle: number, // 本月最长单次(分钟)
avgDuration: number // 平均每次时长(分钟)
},
newBadges: string[] // 本次请求新增解锁的勋章 ID 列表
}
# 我的勋章
GET /api/v1/user/badges
Auth: JWT
Response: {
items: [{
id: string,
name: string, // 勋章名称
description: string, // 解锁条件描述
iconUrl: string, // 勋章图标 URL
rarity: 'common' | 'rare' | 'legendary',
unlocked: boolean,
unlockedAt: string | null, // 解锁时间(ISO 8601)
progress: { // 进度信息(未解锁时)
current: number, // 当前值
target: number, // 目标值
label: string // 进度描述,如「3/7 天」
}
}],
totalBadges: number, // 勋章总数
unlockedCount: number // 已解锁数量
}
# 身体数据
GET /api/v1/user/body-data
Auth: JWT
Query: { startDate?, endDate?, dimension? }
Response: {
items: [{
id, date, weight, bodyFatRate, height,
chest, waist, hip, arm, thigh,
note, createdAt
}],
latest: BodyDataRecord | null // 最新一条
}
POST /api/v1/user/body-data
Auth: JWT
Body: {
date: string, // YYYY-MM-DD
weight?: number,
bodyFatRate?: number,
height?: number,
chest?: number,
waist?: number,
hip?: number,
arm?: number,
thigh?: number,
note?: string
}
Response: { success: boolean, id: string }
DELETE /api/v1/user/body-data/:id
Auth: JWT
Response: { success: boolean }