commit e7c0c8a1c2195b60ca044577519af0ab018cfba8 Author: 张翔 Date: Sat Feb 28 13:36:07 2026 +0800 docs: 添加健身房管理系统产品设计文档 - 系统架构设计(多租户、响应式、事件驱动) - 会员权益引擎(时长/次数/储值/等级) - 预约服务模块(团课/私教/场地/线上) - 签到服务模块(扫码/刷脸/NFC/教练代签) - 计划中心模块(训练计划/课程排期/会员目标/教练排班) - 会员端与管理后台功能设计 - 数据库设计(PostgreSQL + R2DBC + Flyway) - 前端技术架构(uniapp + Vue3) - 项目实施规划与里程碑~ diff --git a/docs/plans/2026-02-28-gym-manage-design.md b/docs/plans/2026-02-28-gym-manage-design.md new file mode 100644 index 0000000..e44aec5 --- /dev/null +++ b/docs/plans/2026-02-28-gym-manage-design.md @@ -0,0 +1,1509 @@ +# 健身房管理系统产品设计文档 + +> 版本: v1.0 +> 日期: 2026-02-28 +> 作者: 张翔 + +--- + +## 一、项目概述 + +### 1.1 项目背景 + +打造一款全场景覆盖的健身房管理系统,支持综合型健身俱乐部、精品工作室、连锁品牌等多种业态,实现会员端便捷预约签到、管理后台数据洞察的核心需求。 + +### 1.2 核心目标 + +- **会员端**:一站式查看个人所有信息(会员卡、权益、预约、签到、训练数据) +- **管理后台**:全维度数据整理与分析,支撑运营决策 +- **便捷体验**:约课、签到流程简单高效 + +### 1.3 适用场景 + +| 场景类型 | 说明 | +|---------|------| +| 综合型健身俱乐部 | 多种团课 + 私教 + 器械区,会员规模 500-2000 人 | +| 精品工作室 | 专注某一类课程,会员规模 100-300 人 | +| 连锁品牌 | 多门店运营,跨店约课,统一数据管理 | + +--- + +## 二、系统架构 + +### 2.1 整体架构图 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 客户端层 │ +├─────────────┬─────────────┬─────────────┬─────────────────────────┤ +│ 会员小程序 │ 教练端App │ 管理后台PC │ 硬件设备(人脸/NFC) │ +│ (uniapp) │ (uniapp) │ (Vue3) │ │ +└──────┬──────┴──────┬──────┴──────┬──────┴────────────┬────────────┘ + │ │ │ │ + └─────────────┴──────┬──────┴───────────────────┘ + │ + ┌───────▼───────┐ + │ API Gateway │ + │ (统一网关) │ + └───────┬───────┘ + │ + ┌────────────────────┼────────────────────┐ + │ │ │ +┌──────▼──────┐ ┌───────▼───────┐ ┌──────▼──────┐ +│ 会员服务 │ │ 预约服务 │ │ 数据服务 │ +│ (会员/卡券) │ │ (课程/场地) │ │ (报表/分析) │ +└──────┬──────┘ └───────┬───────┘ └──────┬──────┘ + │ │ │ + └────────────────────┼────────────────────┘ + │ + ┌───────▼───────┐ + │ PostgreSQL │ + │ + Caffeine │ + └───────────────┘ +``` + +### 2.2 核心设计理念 + +- **多租户架构**:支持连锁多门店,数据隔离,统一管理 +- **资源抽象**:团课名额、教练时段、场地、线上课程统一为"可预约资源" +- **响应式编程**:WebFlux处理高并发预约请求,JDK 21虚拟线程优化阻塞操作 +- **事件驱动**:签到、预约、消费等行为触发事件,驱动数据统计和通知推送 + +### 2.3 技术栈 + +| 层级 | 技术选型 | +|------|---------| +| 前端-会员端 | uniapp + Vue3 + TypeScript + Pinia | +| 前端-管理后台 | Vue3 + TypeScript + Vite + Element Plus | +| 后端框架 | Spring Boot 3 + WebFlux + JDK 21 | +| 数据库 | PostgreSQL + R2DBC + Flyway | +| 缓存 | Caffeine(本地)+ Redis(可选扩展) | +| 部署 | Docker + CI/CD | + +--- + +## 三、会员权益引擎 + +### 3.1 会员体系数据模型 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 会员体系 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ 会员 │────▶│ 会员卡实例 │◀────│ 卡模板 │ │ +│ │ Member │ │ MemberCard │ │ CardTemplate│ │ +│ └─────────┘ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ 权益包实例 │ │ 权益包模板 │ │ +│ │ BenefitPack │ │BenefitDef │ │ +│ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────────────────────────┐ │ +│ │ 权益明细 │ │ +│ │ - 时长权益 (有效期) │ │ +│ │ - 次数权益 (剩余次数) │ │ +│ │ - 储值权益 (余额) │ │ +│ │ - 等级权益 (等级+特权) │ │ +│ └─────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 3.2 四种权益类型 + +| 权益类型 | 数据结构 | 消费逻辑 | 典型场景 | +|---------|---------|---------|---------| +| **时长权益** | `validFrom`, `validTo` | 签到时校验有效期 | 月卡、年卡 | +| **次数权益** | `totalCount`, `usedCount` | 预约/签到时扣减 | 10次卡、私教课时包 | +| **储值权益** | `balance` | 消费时扣减金额 | 预充值账户 | +| **等级权益** | `level`, `exp`, `privileges` | 消费累计经验值 | VIP会员体系 | + +### 3.3 权益校验优先级 + +``` +校验顺序(可配置): +1. 次数权益 → 2. 时长权益 → 3. 储值权益 → 4. 等级折扣 + +示例场景: +会员预约私教课 → 优先扣减私教课时包(次数) → 无则检查年卡是否有效(时长) +→ 无则使用储值余额支付 → 根据VIP等级享受折扣 +``` + +### 3.4 会员等级升级逻辑 + +``` +升级条件(满足任一): +- 累计消费金额达到阈值 +- 累计签到次数达到阈值 +- 储值余额保持N元以上 + +等级特权(可配置): +- 课程预约优先权(提前N小时开放) +- 专属课程解锁 +- 消费折扣 +- 免费储物柜 +``` + +--- + +## 四、预约服务模块 + +### 4.1 统一预约资源模型 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 预约资源抽象层 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ BookableResource (可预约资源) │ │ +│ ├─────────────────────────────────────────────────────────┤ │ +│ │ id, type, name, capacity, status │ │ +│ │ availableSlots[] // 可预约时段 │ │ +│ │ pricingRules[] // 定价规则 │ │ +│ │ constraints[] // 预约约束 │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ △ │ +│ ┌──────────┬──────────┼──────────┬──────────┐ │ +│ │ │ │ │ │ │ +│ ┌─────▼─────┐┌───▼───┐┌─────▼─────┐┌───▼───┐┌────▼────┐ │ +│ │ 团课课程 ││ 私教课 ││ 场地 ││线上课程││ 教练时段 │ │ +│ │ GroupClass││Private││ Venue ││Online ││CoachSlot│ │ +│ └───────────┘└───────┘└───────────┘└───────┘└─────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 4.2 四种预约类型对比 + +| 类型 | 库存单位 | 预约窗口 | 取消规则 | 确认流程 | +|------|---------|---------|---------|---------| +| **团课** | 课程名额(如20人) | 开课前N小时截止 | 开课前2小时免费取消 | 系统自动确认 | +| **私教** | 教练时段(1对1) | 需提前预约 | 需提前24小时取消 | 教练确认/系统自动 | +| **场地** | 场地时段(如1小时) | 可预约未来7天 | 开始前1小时免费取消 | 系统自动确认 | +| **线上** | 观看权限(无限) | 随时可预约 | 无需取消 | 付款即开通 | + +### 4.3 预约状态流转 + +``` +┌─────────┐ 预约请求 ┌─────────┐ 确认/自动 ┌─────────┐ +│ 初始 │──────────────▶│ 待确认 │─────────────▶│ 已确认 │ +│ PENDING │ │PENDING │ │CONFIRMED│ +└─────────┘ └────┬────┘ └────┬────┘ + │ │ + 拒绝│ 签到/开始 + ▼ ▼ + ┌─────────┐ ┌─────────┐ + │ 已取消 │ │ 已完成 │ + │CANCELLED│ │COMPLETED│ + └─────────┘ └─────────┘ + ▲ │ + │ 未签到 │ + └────────────────────────┘ + │ │ + │ 已签到 │ + │ ▼ + ┌─────────┐ ┌─────────┐ + │ 缺席 │ │ 已签到 │ + │NO_SHOW │ │CHECKED_IN│ + └─────────┘ └─────────┘ +``` + +### 4.4 预约冲突检测 + +``` +冲突检测维度: +1. 时间冲突: 会员同一时段已有其他预约 +2. 名额冲突: 团课已满员 +3. 权益冲突: 会员无对应权益或次数不足 +4. 资源冲突: 场地/教练时段已被占用 + +并发处理: +- 使用PostgreSQL行级锁 + 乐观锁 +- WebFlux响应式处理高并发抢课 +- Caffeine缓存热点课程库存 +``` + +### 4.5 预约提醒机制 + +``` +提醒节点: +- 预约成功 → 即时推送 +- 课程开始前2小时 → 提醒推送 +- 课程开始前30分钟 → 最后提醒 +- 课程结束后 → 邀请评价 + +推送渠道: +- 微信模板消息(小程序) +- 站内消息中心 +- 短信(可选,付费功能) +``` + +--- + +## 五、签到服务模块 + +### 5.1 统一签到网关架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 签到网关 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ 扫码签到 │ │ 刷脸签到 │ │ NFC签到 │ │教练代签 │ │ +│ │ QR │ │ Face │ │ NFC │ │ Manual │ │ +│ └────┬────┘ └────┬────┘ └────┬────┘ └────┬────┘ │ +│ │ │ │ │ │ +│ └────────────┴─────┬──────┴────────────┘ │ +│ ▼ │ +│ ┌─────────────────┐ │ +│ │ 签到请求解析 │ │ +│ │ - 会员身份识别 │ │ +│ │ - 签到类型判断 │ │ +│ └────────┬────────┘ │ +│ ▼ │ +│ ┌─────────────────┐ │ +│ │ 签到规则引擎 │ │ +│ │ - 权益校验 │ │ +│ │ - 时段校验 │ │ +│ │ - 防重复签到 │ │ +│ └────────┬────────┘ │ +│ ▼ │ +│ ┌─────────────────┐ │ +│ │ 签到结果处理 │ │ +│ │ - 扣减权益 │ │ +│ │ - 记录日志 │ │ +│ │ - 触发事件 │ │ +│ └─────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 5.2 四种签到方式 + +| 签到方式 | 硬件需求 | 验证流程 | 适用场景 | +|---------|---------|---------|---------| +| **扫码签到** | 门店展示二维码 | 会员扫码 → 验证门店/时段 → 签到成功 | 团课入场、日常健身 | +| **刷脸签到** | 人脸识别终端 | 人脸采集 → 1:N比对 → 签到成功 | 高端健身房、无感通行 | +| **NFC签到** | 读卡器/手环 | 刷卡/手环 → 读取会员ID → 签到成功 | 传统健身房、存物柜联动 | +| **教练代签** | 教练端App | 教练选择学员 → 确认签到 → 记录教练ID | 私教课、小班课 | + +### 5.3 签到业务场景 + +``` +场景一:团课签到 +┌──────────────────────────────────────────────────────┐ +│ 会员预约团课 → 课程开始前30分钟开放签到入口 │ +│ ↓ │ +│ 会员扫码/刷脸 → 校验预约记录 → 签到成功 │ +│ ↓ │ +│ 更新预约状态(CHECKED_IN) → 记录签到时间 │ +└──────────────────────────────────────────────────────┘ + +场景二:日常健身签到(无预约) +┌──────────────────────────────────────────────────────┐ +│ 会员直接到店 → 扫码/刷脸 → 校验会员卡有效性 │ +│ ↓ │ +│ 有效 → 签到成功 → 扣减次数/记录入场时间 │ +│ 无效 → 提示续费/购卡 │ +└──────────────────────────────────────────────────────┘ + +场景三:私教课签到 +┌──────────────────────────────────────────────────────┐ +│ 教练端查看今日私教预约列表 │ +│ ↓ │ +│ 学员到场 → 教练点击"签到" → 扣减私教课时 │ +│ ↓ │ +│ 同步更新会员端状态 → 记录教练+学员双向确认 │ +└──────────────────────────────────────────────────────┘ +``` + +### 5.4 防作弊机制 + +``` +1. 地理位置校验 + - 扫码签到时验证GPS是否在门店范围内 + - 允许误差范围可配置(如500米) + +2. 时间窗口限制 + - 团课签到:开课前30分钟 ~ 开课后15分钟 + - 日常签到:门店营业时间内 + - 单日签到次数上限(防止恶意刷次数) + +3. 设备绑定 + - 刷脸设备需在后台注册绑定门店 + - NFC设备MAC地址白名单 + +4. 异常行为检测 + - 短时间内多次签到尝试 → 触发风控 + - 同一设备多账号签到 → 标记异常 +``` + +### 5.5 离线签到处理 + +``` +网络故障场景: +1. 签到设备本地缓存会员基础信息(Caffeine本地缓存) +2. 签到记录存入本地队列 +3. 网络恢复后自动同步到服务器 +4. 后台标记"离线签到"供人工核对 +``` + +--- + +## 六、计划中心模块 + +### 6.1 计划体系架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 计划中心 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ +│ │ 训练计划 │ │ 课程排期 │ │ 会员目标 │ │ +│ │TrainingPlan │ │ClassSchedule│ │MemberGoal │ │ +│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │ +│ │ │ │ │ +│ │ ┌───────────┴───────────┐ │ │ +│ │ │ │ │ │ +│ ▼ ▼ ▼ ▼ │ +│ ┌─────────────────────────────────────────────────┐ │ +│ │ 教练工作计划 (CoachSchedule) │ │ +│ │ - 排班管理 │ │ +│ │ - 可预约时段生成 │ │ +│ │ - 工作量统计 │ │ +│ └─────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 6.2 四种计划类型 + +#### 6.2.1 训练计划(教练→会员) + +``` +┌─────────────────────────────────────────────────────┐ +│ 训练计划结构 │ +├─────────────────────────────────────────────────────┤ +│ TrainingPlan │ +│ ├─ 基本信息: 名称、目标、周期、教练ID │ +│ ├─ 适用会员: 单人/多人/公开模板 │ +│ ├─ 训练阶段[]: │ +│ │ ├─ 阶段名称: "适应期"、"增肌期"、"塑形期" │ +│ │ ├─ 持续周数: 2-4周 │ +│ │ └─ 每周训练[]: │ +│ │ ├─ 训练日: 周一/三/五 │ +│ │ ├─ 训练内容[]: 动作、组数、次数、重量 │ +│ │ └─ 预计时长: 60分钟 │ +│ └─ 进度追踪: 完成率、训练日志、效果评估 │ +└─────────────────────────────────────────────────────┘ + +会员端展示: +- 今日训练任务提醒 +- 训练动作视频指导 +- 训练记录打卡 +- 阶段完成进度可视化 +``` + +#### 6.2.2 课程排期(管理员→系统) + +``` +┌─────────────────────────────────────────────────────┐ +│ 课程排期结构 │ +├─────────────────────────────────────────────────────┤ +│ ClassSchedule │ +│ ├─ 课程信息: 课程名、类型、教练、门店 │ +│ ├─ 排期规则: │ +│ │ ├─ 单次排期: 指定日期时间 │ +│ │ └─ 周期排期: 每周一/三 19:00,持续N周 │ +│ ├─ 容量设置: 最大人数、预约开始时间、截止时间 │ +│ ├─ 价格规则: 会员价、非会员价、VIP折扣 │ +│ └─ 特殊设置: 取消政策、签到窗口、等待队列 │ +└─────────────────────────────────────────────────────┘ + +智能排课功能: +- 教练时间冲突检测 +- 场地占用检测 +- 历史上座率参考 +- 批量复制排期 +``` + +#### 6.2.3 会员目标(会员自主) + +``` +┌─────────────────────────────────────────────────────┐ +│ 会员目标结构 │ +├─────────────────────────────────────────────────────┤ +│ MemberGoal │ +│ ├─ 目标类型: 减重/增肌/塑形/体能提升/康复 │ +│ ├─ 目标指标: │ +│ │ ├─ 目标体重: 70kg │ +│ │ ├─ 目标体脂率: 15% │ +│ │ └─ 目标日期: 2024-06-30 │ +│ ├─ 系统推荐: │ +│ │ ├─ 推荐课程: 基于目标的课程匹配 │ +│ │ ├─ 推荐计划: 关联训练计划模板 │ +│ │ └─ 每周建议: 训练频率、饮食建议 │ +│ └─ 进度记录: │ +│ ├─ 体重曲线图 │ +│ ├─ 体测数据记录 │ +│ └─ 目标达成预测 │ +└─────────────────────────────────────────────────────┘ +``` + +#### 6.2.4 教练工作计划 + +``` +┌─────────────────────────────────────────────────────┐ +│ 教练排班结构 │ +├─────────────────────────────────────────────────────┤ +│ CoachSchedule │ +│ ├─ 排班规则: │ +│ │ ├─ 固定班次: 周一至周五 10:00-20:00 │ +│ │ └─ 弹性时段: 可预约私教的时间窗口 │ +│ ├─ 时段状态: │ +│ │ ├─ 可预约: 会员可预约私教 │ +│ │ ├─ 已预约: 显示预约会员信息 │ +│ │ ├─ 团课时间: 不可预约私教 │ +│ │ └─ 休息时间: 不可预约 │ +│ └─ 统计看板: │ +│ ├─ 本月课时数 │ +│ ├─ 私教收入 │ +│ └─ 会员评分 │ +└─────────────────────────────────────────────────────┘ + +联动机制: +- 排班变更 → 自动更新可预约时段 +- 请假申请 → 已有预约自动通知改约 +- 课时统计 → 自动生成绩效报表 +``` + +### 6.3 计划间联动关系 + +``` +┌──────────────────────────────────────────────────────────────┐ +│ │ +│ 课程排期 ──────▶ 生成团课预约资源 │ +│ │ │ +│ └──────────▶ 教练工作计划(团课时段自动占用) │ +│ │ +│ 教练工作计划 ──▶ 生成私教可预约时段 │ +│ │ +│ 训练计划 ──────▶ 关联推荐课程 ──▶ 课程排期 │ +│ │ │ +│ └──────────▶ 会员目标(训练计划作为达成路径) │ +│ │ +│ 会员目标 ──────▶ 系统推荐 ──▶ 训练计划模板 │ +│ └─▶ 推荐课程预约 │ +│ │ +└──────────────────────────────────────────────────────────────┘ +``` + +--- + +## 七、会员端功能设计 + +### 7.1 信息架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 会员小程序/App │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ 首页 │ │ +│ │ - 今日待办(预约课程、训练任务) │ │ +│ │ - 快捷入口(预约、签到、我的卡券) │ │ +│ │ - 推荐课程/活动 │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │ +│ │ 预约 │ │ 我的 │ │ 训练 │ │ 个人 │ │ +│ │ 课程 │ │ 卡券 │ │ 计划 │ │ 中心 │ │ +│ └────────┘ └────────┘ └────────┘ └────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 7.2 四大核心模块 + +#### 7.2.1 预约课程模块 + +``` +┌─────────────────────────────────────────────────────┐ +│ 预约课程 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 筛选条件: │ +│ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ +│ │门店 │ │类型 │ │教练 │ │时间 │ │ +│ └─────┘ └─────┘ └─────┘ └─────┘ │ +│ │ +│ 课程列表: │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 🧘 瑜伽基础课 周一 19:00-20:00 │ │ +│ │ 教练: 张教练 | 剩余: 5/20人 │ │ +│ │ [预约] [加入候补] │ │ +│ └─────────────────────────────────────────────┘ │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 💪 私教-增肌训练 可选时段 │ │ +│ │ 教练: 李教练 | ¥200/课时 │ │ +│ │ [查看时段] [立即预约] │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +│ 我的预约: │ +│ - 待参加课程 │ +│ - 历史记录 │ +│ - 取消记录 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +#### 7.2.2 我的卡券模块 + +``` +┌─────────────────────────────────────────────────────┐ +│ 我的卡券 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 会员卡: │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 💳 年卡会员 VIP2 │ │ +│ │ 有效期: 2024.01.01 - 2024.12.31 │ │ +│ │ 状态: ✅ 正常使用 │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +│ 权益明细: │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 时长权益: 剩余 286 天 │ │ +│ │ 私教课时: 剩余 8/10 次 │ │ +│ │ 储值余额: ¥1,280.00 │ │ +│ │ 会员等级: VIP2 (距VIP3还需消费¥2000) │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +│ 消费记录: │ +│ - 2024.03.15 私教课扣费 -¥200 │ +│ - 2024.03.10 储值充值 +¥1000 │ +│ - 2024.03.01 月卡续费 -¥299 │ +│ │ +│ 快捷操作: │ +│ [续费] [充值] [购课] [转赠] │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +#### 7.2.3 训练计划模块 + +``` +┌─────────────────────────────────────────────────────┐ +│ 训练计划 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 我的目标: │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 🎯 目标: 减重5kg │ │ +│ │ 当前进度: 72kg → 目标 67kg │ │ +│ │ [████████░░░░░░░░] 60% │ │ +│ │ 预计达成: 2024.05.30 │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +│ 今日训练: │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 📋 增肌计划 - 第3周 第1天 │ │ +│ │ 胸部训练日 │ │ +│ │ │ │ +│ │ □ 平板卧推 4组×12次 │ │ +│ │ □ 上斜哑铃飞鸟 3组×15次 │ │ +│ │ □ 绳索夹胸 3组×12次 │ │ +│ │ │ │ +│ │ [开始训练] [查看动作演示] │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +│ 训练记录: │ +│ - 本周训练: 3/4 次 │ +│ - 本月打卡: 12 天 │ +│ - 连续训练: 5 天 🔥 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +#### 7.2.4 个人中心模块 + +``` +┌─────────────────────────────────────────────────────┐ +│ 个人中心 │ +├─────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────────────────────────────────────┐ │ +│ │ 👤 张三 VIP2 会员 │ │ +│ │ 会员号: GYM2024010001 │ │ +│ │ 注册门店: XX健身·中关村店 │ │ +│ └─────────────────────────────────────────────┘ │ +│ │ +│ 我的数据: │ +│ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ +│ │ 签到 │ │ 预约 │ │ 消费 │ │ 评价 │ │ +│ │ 56次 │ │ 23次 │ │¥3.2k │ │ 12条 │ │ +│ └───────┘ └───────┘ └───────┘ └───────┘ │ +│ │ +│ 功能列表: │ +│ ├── 📊 体测记录 │ +│ ├── 📋 签到记录 │ +│ ├── 💰 消费明细 │ +│ ├── ⭐ 我的评价 │ +│ ├── 🎁 邀请好友 │ +│ ├── 📞 联系客服 │ +│ ├── ⚙️ 账号设置 │ +│ └── ❓ 帮助中心 │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +### 7.3 会员端信息汇总 + +| 信息类别 | 具体内容 | 入口位置 | +|---------|---------|---------| +| **会员身份** | 会员号、等级、注册门店、有效期 | 个人中心 | +| **权益状态** | 时长/次数/储值/等级权益明细 | 我的卡券 | +| **预约信息** | 待参加/历史/取消的预约记录 | 预约课程 | +| **签到记录** | 签到时间、签到方式、关联课程 | 个人中心 | +| **训练数据** | 训练计划进度、打卡记录、体测数据 | 训练计划 | +| **消费明细** | 充值、消费、退款流水 | 我的卡券/个人中心 | +| **评价反馈** | 已评价课程、教练评分记录 | 个人中心 | + +--- + +## 八、管理后台功能设计 + +### 8.1 角色与权限体系 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 管理后台角色体系 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────────┐ │ +│ │ 超级管理员 │ 全平台权限,多门店管理,系统配置 │ +│ └──────┬──────┘ │ +│ │ │ +│ ┌──────┴──────────────────────────────────┐ │ +│ │ │ │ +│ ▼ ▼ │ +│ ┌─────────────┐ ┌─────────────┐ │ +│ │ 门店店长 │ │ 运营管理员 │ │ +│ │ 单店全权限 │ │ 营销活动配置 │ │ +│ └──────┬──────┘ └─────────────┘ │ +│ │ │ +│ ┌──────┼──────────────────────────┐ │ +│ │ │ │ │ +│ ▼ ▼ ▼ │ +│ ┌────────┐ ┌────────┐ ┌─────────────┐ │ +│ │ 前台 │ │ 教练 │ │ 财务专员 │ │ +│ │ 接待签到│ │ 排课签到│ │ 账单报表 │ │ +│ └────────┘ └────────┘ └─────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 8.2 功能模块架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 管理后台 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ 数据看板 │ │ 会员管理 │ │ 课程管理 │ │ 教练管理 │ │ 财务管理 │ │ +│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ +│ │ +│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │ +│ │ 门店管理 │ │ 签到管理 │ │ 营销中心 │ │ 系统设置 │ │ 硬件管理 │ │ +│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 8.3 核心模块详解 + +#### 8.3.1 数据看板 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 数据看板 门店: 全部 ▼ │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 今日概览: │ +│ ┌───────────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐ │ +│ │ 今日签到 │ │ 今日预约 │ │ 今日收入 │ │ 新增会员 │ │ +│ │ 128 │ │ 86 │ │ ¥12,580 │ │ 15 │ │ +│ │ ↑ 12% │ │ ↑ 8% │ │ ↑ 23% │ │ ↓ 5% │ │ +│ └───────────┘ └───────────┘ └───────────┘ └───────────┘ │ +│ │ +│ ┌─────────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 签到趋势(近7天) │ │ 课程上座率排行 │ │ +│ │ 📊 折线图 │ │ 1. 瑜伽课 95% │ │ +│ │ │ │ 2. 动感单车 88% │ │ +│ │ │ │ 3. 搏击课 82% │ │ +│ └─────────────────────────────┘ └─────────────────────────┘ │ +│ │ +│ ┌─────────────────────────────┐ ┌─────────────────────────┐ │ +│ │ 会员活跃度分布 │ │ 即将到期会员预警 │ │ +│ │ 🥧 饼图 │ │ 本月到期: 45人 │ │ +│ │ 高活跃 35% │ │ 已续费: 12人 │ │ +│ │ 中活跃 40% │ │ 待跟进: 33人 │ │ +│ │ 低活跃 25% │ │ [一键发送续费提醒] │ │ +│ └─────────────────────────────┘ └─────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +#### 8.3.2 会员管理 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 会员管理 │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 筛选: [门店▼] [会员等级▼] [卡类型▼] [状态▼] [注册时间] │ +│ 搜索: [会员号/姓名/手机号________________] [查询] [导出] │ +│ │ +│ ┌─────────────────────────────────────────────────────────┐ │ +│ │ 会员号 │ 姓名 │ 等级 │ 卡类型 │ 状态 │ 签到 │ 消费 │ │ +│ ├───────────┼─────┼─────┼───────┼─────┼─────┼───────┤ │ +│ │ GYM001234 │ 张三 │ VIP2│ 年卡 │ 正常 │ 56次│ ¥3.2k │ │ +│ │ GYM001235 │ 李四 │ VIP1│ 次卡 │ 正常 │ 23次│ ¥1.5k │ │ +│ │ GYM001236 │ 王五 │ 普通│ 月卡 │ 过期 │ 12次│ ¥299 │ │ +│ └─────────────────────────────────────────────────────────┘ │ +│ │ +│ 批量操作: [发送通知] [批量续费] [导出数据] [标签管理] │ +│ │ +│ 会员详情页: │ +│ ├── 基本信息: 个人资料、注册信息、绑定设备 │ +│ ├── 会员卡券: 持有卡列表、权益明细、消费记录 │ +│ ├── 预约记录: 历史预约、取消记录、爽约记录 │ +│ ├── 签到记录: 签到明细、签到趋势图 │ +│ ├── 训练数据: 体测记录、训练计划、目标进度 │ +│ └── 跟进记录: 销售跟进、客服记录、备注 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +#### 8.3.3 其他模块概览 + +| 模块 | 核心功能 | +|------|---------| +| **课程管理** | 课程类型管理、课程排期(日历视图)、场地管理、私教课程配置 | +| **教练管理** | 教练列表、排班管理、课时统计、会员评价、私教会员绑定 | +| **财务管理** | 营收概览、收入明细、财务报表、账单管理、退款管理 | +| **门店管理** | 门店信息、营业时间、门店配置、跨店规则 | +| **签到管理** | 签到记录查询、异常签到处理、签到设备绑定 | +| **营销中心** | 优惠券、活动配置、会员通知、短信推送 | +| **系统设置** | 角色权限、字典配置、操作日志、参数设置 | +| **硬件管理** | 人脸设备、NFC设备、扫码设备绑定与状态监控 | + +--- + +## 九、数据库设计 + +### 9.1 核心实体关系 + +``` +┌─────────────────────────────────────────────────────────────────────────┐ +│ 核心数据模型 │ +├─────────────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌─────────┐ 1:N ┌───────────┐ N:M ┌─────────┐ │ +│ │ Tenant │─────────────▶│ Store │◀─────────────│ Coach │ │ +│ │ (租户) │ │ (门店) │ │ (教练) │ │ +│ └─────────┘ └─────┬─────┘ └────┬────┘ │ +│ │ │ │ +│ 1:N │ 1:N │ │ +│ ▼ ▼ │ +│ ┌─────────┐ N:M ┌───────────┐ 1:N ┌─────────┐ │ +│ │ Member │◀────────────▶│ Card │◀─────────────│CardTmpl │ │ +│ │ (会员) │ │ (会员卡) │ │(卡模板) │ │ +│ └────┬────┘ └─────┬─────┘ └─────────┘ │ +│ │ │ │ +│ │ 1:N │ 1:N │ +│ ▼ ▼ │ +│ ┌──────────┐ ┌───────────┐ │ +│ │Booking │ │ Benefit │ │ +│ │(预约记录) │ │ (权益明细) │ │ +│ └────┬─────┘ └───────────┘ │ +│ │ │ +│ │ 1:1 │ +│ ▼ │ +│ ┌──────────┐ ┌───────────┐ N:M ┌─────────┐ │ +│ │CheckIn │◀───────────│ Course │◀─────────────│ Venue │ │ +│ │(签到记录) │ 1:N │ (课程) │ │ (场地) │ │ +│ └──────────┘ └───────────┘ └─────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────────────┘ +``` + +### 9.2 基础字段规范 + +所有业务表统一包含以下基础字段: + +```sql +created_at TIMESTAMP DEFAULT NOW(), -- 创建时间 +updated_at TIMESTAMP DEFAULT NOW(), -- 更新时间 +created_by BIGINT, -- 创建人ID +updated_by BIGINT, -- 更新人ID +deleted_at TIMESTAMP DEFAULT NULL -- 软删除时间(NULL表示未删除) +``` + +### 9.3 核心表结构 + +#### 9.3.1 会员相关表 + +```sql +-- 租户表 +CREATE TABLE tenant ( + id BIGSERIAL PRIMARY KEY, + name VARCHAR(128) NOT NULL, + code VARCHAR(32) NOT NULL UNIQUE, + status SMALLINT DEFAULT 1, + config JSONB, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + deleted_at TIMESTAMP DEFAULT NULL +); + +-- 门店表 +CREATE TABLE store ( + id BIGSERIAL PRIMARY KEY, + tenant_id BIGINT NOT NULL REFERENCES tenant(id), + name VARCHAR(128) NOT NULL, + code VARCHAR(32) NOT NULL, + address VARCHAR(256), + longitude DECIMAL(10,6), + latitude DECIMAL(10,6), + phone VARCHAR(20), + business_hours JSONB, + status SMALLINT DEFAULT 1, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + created_by BIGINT, + updated_by BIGINT, + deleted_at TIMESTAMP DEFAULT NULL +); + +-- 会员表 +CREATE TABLE member ( + id BIGSERIAL PRIMARY KEY, + tenant_id BIGINT NOT NULL REFERENCES tenant(id), + store_id BIGINT NOT NULL REFERENCES store(id), + member_no VARCHAR(32) NOT NULL, + name VARCHAR(64), + phone VARCHAR(20) NOT NULL, + avatar VARCHAR(512), + gender SMALLINT, + birthday DATE, + level SMALLINT DEFAULT 0, + exp INT DEFAULT 0, + status SMALLINT DEFAULT 1, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + created_by BIGINT, + updated_by BIGINT, + deleted_at TIMESTAMP DEFAULT NULL +); + +-- 会员卡实例表 +CREATE TABLE member_card ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, + template_id BIGINT NOT NULL, + card_no VARCHAR(32) NOT NULL, + status SMALLINT DEFAULT 1, + valid_from DATE, + valid_to DATE, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + created_by BIGINT, + updated_by BIGINT, + deleted_at TIMESTAMP DEFAULT NULL +); + +-- 权益明细表 +CREATE TABLE member_benefit ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, + card_id BIGINT NOT NULL, + benefit_type SMALLINT NOT NULL, -- 1时长 2次数 3储值 4等级 + benefit_name VARCHAR(64), + total_value DECIMAL(12,2), + used_value DECIMAL(12,2) DEFAULT 0, + remaining_value DECIMAL(12,2), + valid_from DATE, + valid_to DATE, + status SMALLINT DEFAULT 1, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + created_by BIGINT, + updated_by BIGINT, + deleted_at TIMESTAMP DEFAULT NULL +); +``` + +#### 9.3.2 预约相关表 + +```sql +-- 可预约资源表 +CREATE TABLE bookable_resource ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + store_id BIGINT NOT NULL, + resource_type SMALLINT NOT NULL, -- 1团课 2私教 3场地 4线上 + resource_name VARCHAR(128) NOT NULL, + capacity INT DEFAULT 1, + status SMALLINT DEFAULT 1, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + created_by BIGINT, + updated_by BIGINT, + deleted_at TIMESTAMP DEFAULT NULL +); + +-- 预约时段表 +CREATE TABLE booking_slot ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + resource_id BIGINT NOT NULL, + coach_id BIGINT, + venue_id BIGINT, + start_time TIMESTAMP NOT NULL, + end_time TIMESTAMP NOT NULL, + capacity INT NOT NULL, + booked_count INT DEFAULT 0, + waitlist_count INT DEFAULT 0, + status SMALLINT DEFAULT 1, + price DECIMAL(10,2), + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + created_by BIGINT, + updated_by BIGINT, + deleted_at TIMESTAMP DEFAULT NULL +); + +-- 预约记录表 +CREATE TABLE booking_record ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, + slot_id BIGINT NOT NULL, + booking_no VARCHAR(32) NOT NULL, + status SMALLINT DEFAULT 1, + check_in_time TIMESTAMP, + cancel_time TIMESTAMP, + cancel_reason VARCHAR(256), + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + created_by BIGINT, + updated_by BIGINT, + deleted_at TIMESTAMP DEFAULT NULL +); +``` + +#### 9.3.3 签到相关表 + +```sql +-- 签到记录表 +CREATE TABLE check_in_record ( + id BIGINT PRIMARY KEY, + tenant_id BIGINT NOT NULL, + store_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, + booking_id BIGINT, + check_in_type SMALLINT NOT NULL, -- 1扫码 2刷脸 3NFC 4教练代签 + check_in_time TIMESTAMP NOT NULL, + device_id VARCHAR(64), + operator_id BIGINT, + latitude DECIMAL(10,6), + longitude DECIMAL(10,6), + benefit_deducted JSONB, + created_at TIMESTAMP DEFAULT NOW(), + updated_at TIMESTAMP DEFAULT NOW(), + created_by BIGINT, + updated_by BIGINT, + deleted_at TIMESTAMP DEFAULT NULL +); +``` + +### 9.4 索引设计 + +```sql +-- 部分索引:仅索引未删除数据 +CREATE INDEX idx_member_phone ON member(tenant_id, phone) +WHERE deleted_at IS NULL; + +CREATE INDEX idx_member_card_member ON member_card(member_id, status) +WHERE deleted_at IS NULL; + +CREATE INDEX idx_booking_slot_time ON booking_slot(tenant_id, start_time, status) +WHERE deleted_at IS NULL; + +CREATE INDEX idx_booking_record_member ON booking_record(member_id, status, created_at) +WHERE deleted_at IS NULL; + +CREATE INDEX idx_check_in_member_time ON check_in_record(member_id, check_in_time) +WHERE deleted_at IS NULL; + +-- 唯一约束:部分索引确保删除后可重用 +CREATE UNIQUE INDEX idx_member_no_unique ON member(tenant_id, member_no) +WHERE deleted_at IS NULL; + +CREATE UNIQUE INDEX idx_member_phone_unique ON member(tenant_id, phone) +WHERE deleted_at IS NULL; +``` + +### 9.5 缓存策略 + +``` +┌─────────────────────────────────────────────────────────────┐ +│ 缓存分层设计 │ +├─────────────────────────────────────────────────────────────┤ +│ │ +│ L1 - 本地缓存 (Caffeine) │ +│ ├── 会员基础信息: 5分钟过期 │ +│ ├── 课程库存: 30秒过期(热点课程) │ +│ └── 系统配置: 30分钟过期 │ +│ │ +│ L2 - 分布式缓存(Redis,可选扩展) │ +│ ├── 分布式锁: 预约库存扣减 │ +│ ├── Session: 用户登录态 │ +│ └── 验证码: 短信验证码 │ +│ │ +│ 缓存更新策略: │ +│ ├── 写穿透: 数据变更时同步更新缓存 │ +│ ├── 延迟双删: 高一致性场景 │ +│ └── 订阅Binlog: 异步同步(后期扩展) │ +│ │ +└─────────────────────────────────────────────────────────────┘ +``` + +--- + +## 十、后端技术实现 + +### 10.1 项目依赖 + +```xml + + + + + org.springframework.boot + spring-boot-starter-webflux + + + + + org.springframework.boot + spring-boot-starter-data-r2dbc + + + org.postgresql + r2dbc-postgresql + + + + + org.flywaydb + flyway-core + + + org.postgresql + postgresql + runtime + + + + + com.github.ben-manes.caffeine + caffeine + + +``` + +### 10.2 Flyway 迁移脚本组织 + +``` +src/main/resources/db/migration/ +├── V1.0.0__init_schema.sql # 初始化表结构 +├── V1.0.1__init_member_tables.sql # 会员相关表 +├── V1.0.2__init_booking_tables.sql # 预约相关表 +├── V1.0.3__init_checkin_tables.sql # 签到相关表 +├── V1.0.4__init_coach_tables.sql # 教练相关表 +├── V1.0.5__init_course_tables.sql # 课程相关表 +├── V1.0.6__init_finance_tables.sql # 财务相关表 +├── V1.0.7__init_indexes.sql # 索引创建 +└── ... +``` + +### 10.3 R2DBC Repository 示例 + +```java +// MemberRepository.java +public interface MemberRepository extends ReactiveCrudRepository { + + @Query("SELECT * FROM member WHERE tenant_id = :tenantId AND phone = :phone AND deleted_at IS NULL") + Mono findByPhone(Long tenantId, String phone); + + @Query("SELECT * FROM member WHERE tenant_id = :tenantId AND member_no = :memberNo AND deleted_at IS NULL") + Mono findByMemberNo(Long tenantId, String memberNo); + + @Query("UPDATE member SET deleted_at = NOW() WHERE id = :id AND deleted_at IS NULL") + Mono softDeleteById(Long id); +} + +// BookingSlotRepository.java +public interface BookingSlotRepository extends ReactiveCrudRepository { + + @Query("UPDATE booking_slot SET booked_count = booked_count + 1 WHERE id = :id AND booked_count < capacity AND deleted_at IS NULL") + Mono incrementBookedCount(Long id); + + @Query("UPDATE booking_slot SET booked_count = booked_count - 1 WHERE id = :id AND booked_count > 0 AND deleted_at IS NULL") + Mono decrementBookedCount(Long id); +} +``` + +### 10.4 响应式事务管理 + +```java +@Service +public class BookingService { + + private final BookingRecordRepository bookingRecordRepository; + private final BookingSlotRepository bookingSlotRepository; + private final MemberBenefitRepository benefitRepository; + private final ReactiveTransactionManager transactionManager; + + public Mono createBooking(BookingRequest request) { + TransactionalOperator rxtx = TransactionalOperator.create(transactionManager); + + return Mono.defer(() -> + // 1. 检查时段库存 + bookingSlotRepository.findById(request.getSlotId()) + .filter(slot -> slot.getBookedCount() < slot.getCapacity()) + .switchIfEmpty(Mono.error(new BusinessException("课程已满"))) + + // 2. 扣减权益 + .flatMap(slot -> benefitRepository.deductBenefit( + request.getMemberId(), + slot.getPrice() + )) + + // 3. 创建预约记录 + .flatMap(benefit -> { + BookingRecord record = new BookingRecord(); + record.setMemberId(request.getMemberId()); + record.setSlotId(request.getSlotId()); + record.setStatus(BookingStatus.CONFIRMED); + return bookingRecordRepository.save(record); + }) + + // 4. 增加预约人数 + .flatMap(record -> bookingSlotRepository + .incrementBookedCount(request.getSlotId()) + .thenReturn(record) + ) + ).as(rxtx::transactional); + } +} +``` + +### 10.5 配置文件 + +```yaml +# application.yml +spring: + r2dbc: + url: r2dbc:postgresql://localhost:5432/gym_manage + username: gym_user + password: ${DB_PASSWORD} + pool: + enabled: true + initial-size: 5 + max-size: 20 + max-idle-time: 30m + + flyway: + url: jdbc:postgresql://localhost:5432/gym_manage + username: gym_user + password: ${DB_PASSWORD} + locations: classpath:db/migration + baseline-on-migrate: true + + cache: + type: caffeine + caffeine: + spec: maximumSize=10000,expireAfterWrite=5m +``` + +--- + +## 十一、前端技术架构 + +### 11.1 项目结构 + +``` +gym-manage/ +├── apps/ +│ ├── member-app/ # 会员端 uniapp +│ │ ├── src/ +│ │ │ ├── pages/ # 页面 +│ │ │ ├── components/ # 组件 +│ │ │ ├── stores/ # Pinia 状态管理 +│ │ │ ├── api/ # 接口请求 +│ │ │ ├── utils/ # 工具函数 +│ │ │ └── styles/ # 样式 +│ │ ├── manifest.json +│ │ └── pages.json +│ │ +│ ├── coach-app/ # 教练端 uniapp +│ │ └── ... +│ │ +│ └── admin-web/ # 管理后台 Vue3 +│ ├── src/ +│ │ ├── views/ +│ │ ├── components/ +│ │ ├── stores/ +│ │ ├── api/ +│ │ ├── router/ +│ │ └── styles/ +│ └── vite.config.ts +│ +├── packages/ # 共享包 +│ ├── shared-types/ # TypeScript 类型定义 +│ ├── shared-utils/ # 共享工具函数 +│ └── ui-components/ # 共享UI组件 +│ +└── package.json +``` + +### 11.2 状态管理示例 + +```typescript +// stores/member.ts +import { defineStore } from 'pinia'; +import type { Member, MemberCard, MemberBenefit } from '@shared-types'; + +export const useMemberStore = defineStore('member', { + state: () => ({ + member: null as Member | null, + cards: [] as MemberCard[], + benefits: [] as MemberBenefit[], + token: '', + }), + + getters: { + isLoggedIn: (state) => !!state.token && !!state.member, + currentLevel: (state) => state.member?.level ?? 0, + activeCards: (state) => state.cards.filter(c => c.status === 1), + + validBenefits: (state) => { + const now = new Date(); + return state.benefits.filter(b => + b.status === 1 && + (!b.validTo || new Date(b.validTo) > now) + ); + }, + }, + + actions: { + async login(phone: string, code: string) {}, + async fetchMemberInfo() {}, + logout() {}, + }, + + persist: { + key: 'gym-member', + paths: ['token'], + }, +}); +``` + +### 11.3 共享类型定义 + +```typescript +// packages/shared-types/src/index.ts + +export interface Member { + id: number; + tenantId: number; + storeId: number; + memberNo: string; + name: string; + phone: string; + avatar: string; + gender: number; + birthday: string; + level: number; + exp: number; + status: number; + createdAt: string; + updatedAt: string; +} + +export interface MemberBenefit { + id: number; + memberId: number; + cardId: number; + benefitType: 1 | 2 | 3 | 4; + benefitName: string; + totalValue: number; + usedValue: number; + remainingValue: number; + validFrom: string; + validTo: string; + status: number; +} + +export enum BookingStatus { + PENDING = 1, + CONFIRMED = 2, + CANCELLED = 3, + COMPLETED = 4, + NO_SHOW = 5, + CHECKED_IN = 6, +} + +export interface ApiResponse { + code: number; + message: string; + data: T; +} +``` + +--- + +## 十二、项目实施规划 + +### 12.1 MVP版本功能范围 + +``` +P0 - 核心功能(必须) +├── 会员端 +│ ├── 微信授权登录 +│ ├── 会员卡展示 & 权益查看 +│ ├── 团课预约 & 取消 +│ ├── 扫码签到 +│ └── 预约记录查看 +│ +├── 管理后台 +│ ├── 数据看板(基础统计) +│ ├── 会员管理(增删改查) +│ ├── 课程排期(日历视图) +│ ├── 签到记录查询 +│ └── 门店管理 +│ +└── 后端服务 + ├── 会员服务(注册、登录、信息管理) + ├── 预约服务(团课预约、库存管理) + ├── 签到服务(扫码签到) + └── 基础数据服务 + +P1 - 重要功能(第二阶段) +├── 私教预约 & 教练端 +├── 会员等级体系 +├── 储值 & 次卡管理 +├── 训练计划模块 +└── 财务报表 + +P2 - 增强功能(第三阶段) +├── 多门店连锁 +├── 刷脸签到硬件集成 +├── 营销活动模块 +├── App版本 +└── 数据分析高级功能 +``` + +### 12.2 开发里程碑 + +``` +阶段一:基础搭建(2周) +├── Week 1 +│ ├── 后端项目初始化(Spring Boot 3 + WebFlux) +│ ├── 数据库设计 & Flyway迁移脚本 +│ ├── 前端项目初始化(uniapp + Vue3 admin) +│ └── 开发环境配置(Docker、CI/CD) +│ +└── Week 2 + ├── 用户认证服务(JWT + 微信登录) + ├── 基础CRUD框架搭建 + └── 前端登录页面 & 路由守卫 + +阶段二:核心功能(4周) +├── Week 3-4: 会员模块 +│ ├── 会员注册、信息管理 +│ ├── 会员卡 & 权益管理 +│ └── 会员端个人中心 +│ +└── Week 5-6: 预约 & 签到 + ├── 课程排期管理 + ├── 团课预约功能 + ├── 扫码签到功能 + └── 管理后台数据看板 + +阶段三:测试 & 上线(2周) +├── Week 7 +│ ├── 集成测试 +│ ├── 性能测试 & 优化 +│ └── Bug修复 +│ +└── Week 8 + ├── 生产环境部署 + ├── 小程序审核提交 + └── 运维文档编写 +``` + +### 12.3 技术风险与应对 + +| 风险 | 影响 | 应对措施 | 优先级 | +|------|------|---------|--------| +| 高并发预约抢课 | 热门课程开抢时系统压力 | PostgreSQL行级锁 + Caffeine缓存 + WebFlux响应式 + 候补机制 | 高 | +| 微信小程序审核 | 上线时间不可控 | 提前了解审核规范、预留修改时间、准备H5备选 | 中 | +| 硬件设备集成 | 刷脸/NFC设备对接复杂 | MVP仅支持扫码、签到网关预留扩展接口 | 低(P2) | +| 多租户数据隔离 | 连锁门店数据安全 | tenant_id强制过滤 + 数据库RLS策略 | 中(P2) | + +--- + +## 十三、总结 + +### 13.1 设计方案总览 + +**业务范围** +- 支持综合俱乐部、精品工作室、连锁品牌全场景 +- 会员体系:时长卡 + 次卡 + 储值 + 等级体系 +- 预约类型:团课 + 私教 + 场地 + 线上课程 +- 签到方式:扫码 + 刷脸 + NFC + 教练代签 +- 计划体系:训练计划 + 课程排期 + 会员目标 + 教练排班 + +**技术架构** +- 前端: uniapp(Vue3+TS) + Vue3管理后台 +- 后端: Spring Boot 3 + WebFlux + JDK 21 +- 数据库: PostgreSQL + R2DBC + Flyway +- 缓存: Caffeine(本地)+ Redis(可选扩展) +- 部署: Docker + CI/CD + +**核心设计理念** +- 多租户架构支持连锁扩展 +- 资源抽象统一预约模型 +- 响应式编程应对高并发 +- 软删除保证数据可追溯 +- 模块化设计支持渐进式开发 + +--- + +*文档结束*