完成模块2
This commit was merged in pull request #14.
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
# V10 团课预约业务场景测试数据
|
||||
|
||||
## 概述
|
||||
|
||||
本文档描述了 V10 版本新增的团课预约功能测试数据,覆盖了7种典型的预约业务场景,用于验证系统在不同会员卡状态下的正确处理逻辑。
|
||||
|
||||
**当前日期**: 2026-06-02
|
||||
|
||||
---
|
||||
|
||||
## 一、测试场景总览
|
||||
|
||||
| 场景 | 会员 | 会员卡状态 | 预约课程 | 预期结果 |
|
||||
|-----|------|----------|---------|---------|
|
||||
| 1 | 用户A | 无会员卡 | 次数卡团课 | 提示无可用会员卡 |
|
||||
| 2 | 用户B | 时长卡已过期 | 次数卡团课 | 提示会员卡已过期 |
|
||||
| 3 | 会员C | 时长卡有效 | 次数卡团课 | 预约成功 |
|
||||
| 4 | 会员D | 次数卡次数=0 | 次数卡团课 | 提示剩余次数不足 |
|
||||
| 5 | 会员E | 次数卡次数=5 | 次数卡团课 | 预约成功 |
|
||||
| 6 | 会员F | 储值卡余额=30元 | 储值卡团课(需50元) | 提示余额不足 |
|
||||
| 7 | 会员G | 储值卡余额=200元 | 储值卡团课(需50元) | 预约成功 |
|
||||
|
||||
---
|
||||
|
||||
## 二、测试会员数据
|
||||
|
||||
### 2.1 会员列表
|
||||
|
||||
| 会员编号 | 昵称 | 手机号 | 性别 | 创建时间 |
|
||||
|---------|------|--------|------|---------|
|
||||
| MEM_TEST_A | 用户A_无卡新用户 | 13800001001 | 男 | 2026-06-02 10:00:00 |
|
||||
| MEM_TEST_B | 用户B_过期时长卡 | 13800001002 | 男 | 2026-05-01 10:00:00 |
|
||||
| MEM_TEST_C | 会员C_有效时长卡 | 13800001003 | 女 | 2026-05-01 10:00:00 |
|
||||
| MEM_TEST_D | 会员D_次数用尽 | 13800001004 | 男 | 2026-05-01 10:00:00 |
|
||||
| MEM_TEST_E | 会员E_次数充足 | 13800001005 | 女 | 2026-05-01 10:00:00 |
|
||||
| MEM_TEST_F | 会员F_储值卡余额不足 | 13800001006 | 男 | 2026-05-01 10:00:00 |
|
||||
| MEM_TEST_G | 会员G_储值卡余额充足 | 13800001007 | 女 | 2026-05-01 10:00:00 |
|
||||
|
||||
### 2.2 会员场景说明
|
||||
|
||||
#### 场景1: 用户A - 无会员卡新用户
|
||||
- **会员编号**: MEM_TEST_A
|
||||
- **状态**: 2026-06-02 刚注册,尚未购买任何会员卡
|
||||
- **测试目标**: 验证无会员卡用户申请团课预约时的错误提示
|
||||
|
||||
#### 场景2: 用户B - 时长卡已过期
|
||||
- **会员编号**: MEM_TEST_B
|
||||
- **状态**: 持有30天时长卡,于 2026-05-31 23:59:59 到期
|
||||
- **测试目标**: 验证会员卡过期后的预约行为
|
||||
|
||||
#### 场景3: 会员C - 时长卡有效
|
||||
- **会员编号**: MEM_TEST_C
|
||||
- **状态**: 持有30天时长卡,到期时间 2026-07-02
|
||||
- **测试目标**: 验证有效期内的时长卡可以正常预约次数卡团课
|
||||
|
||||
#### 场景4: 会员D - 次数卡耗尽
|
||||
- **会员编号**: MEM_TEST_D
|
||||
- **状态**: 持有10次卡,剩余次数 = 0
|
||||
- **测试目标**: 验证次数耗尽后无法预约团课
|
||||
|
||||
#### 场景5: 会员E - 次数卡充足
|
||||
- **会员编号**: MEM_TEST_E
|
||||
- **状态**: 持有10次卡,剩余次数 = 5
|
||||
- **测试目标**: 验证次数充足时正常预约
|
||||
|
||||
#### 场景6: 会员F - 储值卡余额不足
|
||||
- **会员编号**: MEM_TEST_F
|
||||
- **状态**: 持有储值卡,余额 = 30.00 元
|
||||
- **测试目标**: 验证预约储值卡团课(需50元)时提示余额不足
|
||||
|
||||
#### 场景7: 会员G - 储值卡余额充足
|
||||
- **会员编号**: MEM_TEST_G
|
||||
- **状态**: 持有储值卡,余额 = 200.00 元
|
||||
- **测试目标**: 验证余额充足时正常预约储值卡团课
|
||||
|
||||
---
|
||||
|
||||
## 三、团课课程数据
|
||||
|
||||
### 3.1 团课列表
|
||||
|
||||
| 课程名称 | 教练ID | 课程类型 | 开始时间 | 结束时间 | 最大人数 | 当前人数 | 状态 | 点卡额度 | 储值额度 |
|
||||
|---------|-------|---------|---------|---------|---------|---------|------|---------|---------|
|
||||
| 燃脂搏击_次数卡课程 | 102 | 2 | 2026-06-10 19:30:00 | 2026-06-10 20:30:00 | 20 | 0 | 正常 | 1 | 0.00 |
|
||||
| 高端普拉提_储值卡课程 | 103 | 1 | 2026-06-11 19:00:00 | 2026-06-11 20:00:00 | 15 | 0 | 正常 | 0 | 50.00 |
|
||||
|
||||
### 3.2 课程说明
|
||||
|
||||
**燃脂搏击_次数卡课程**
|
||||
- **收费类型**: 次数卡
|
||||
- **消耗点数**: 1次
|
||||
- **适用会员**: 时长卡、次数卡用户
|
||||
- **课程描述**: 高强度间歇训练,配合音乐快速燃脂
|
||||
|
||||
**高端普拉提_储值卡课程**
|
||||
- **收费类型**: 储值卡
|
||||
- **消耗金额**: 50.00 元
|
||||
- **适用会员**: 储值卡用户
|
||||
- **课程描述**: 精准训练核心肌群
|
||||
|
||||
---
|
||||
|
||||
## 四、会员卡类型数据
|
||||
|
||||
| 卡名称 | 卡类型 | 价格 | 有效天数 | 总次数 | 面额 | 状态 |
|
||||
|-------|-------|------|---------|-------|------|------|
|
||||
| 30天时长卡 | TIME_CARD | 299.00 | 30 | - | - | 上架 |
|
||||
| 10次卡 | COUNT_CARD | 499.00 | - | 10 | - | 上架 |
|
||||
| 储值卡500 | STORED_VALUE_CARD | 500.00 | - | - | 500.00 | 上架 |
|
||||
|
||||
---
|
||||
|
||||
## 五、会员卡记录数据
|
||||
|
||||
### 5.1 记录列表
|
||||
|
||||
| 会员编号 | 卡名称 | 状态 | 剩余次数 | 剩余金额 | 过期时间 | 购买时间 |
|
||||
|---------|-------|------|---------|---------|---------|---------|
|
||||
| MEM_TEST_B | 30天时长卡 | EXPIRED | 0 | 0.00 | 2026-05-31 | 2026-05-01 |
|
||||
| MEM_TEST_C | 30天时长卡 | ACTIVE | 0 | 0.00 | 2026-07-02 | 2026-06-02 |
|
||||
| MEM_TEST_D | 10次卡 | ACTIVE | 0 | 0.00 | 2026-12-31 | 2026-05-01 |
|
||||
| MEM_TEST_E | 10次卡 | ACTIVE | 5 | 0.00 | 2026-12-31 | 2026-05-01 |
|
||||
| MEM_TEST_F | 储值卡500 | ACTIVE | 0 | 30.00 | 2027-06-02 | 2026-05-01 |
|
||||
| MEM_TEST_G | 储值卡500 | ACTIVE | 0 | 200.00 | 2027-06-02 | 2026-05-01 |
|
||||
|
||||
### 5.2 详细说明
|
||||
|
||||
**用户B - 时长卡已过期**
|
||||
```
|
||||
会员ID: MEM_TEST_B
|
||||
卡名称: 30天时长卡
|
||||
状态: EXPIRED (已过期)
|
||||
有效期: 2026-05-01 至 2026-05-31
|
||||
剩余次数: 0
|
||||
剩余金额: 0.00
|
||||
```
|
||||
|
||||
**会员C - 时长卡有效**
|
||||
```
|
||||
会员ID: MEM_TEST_C
|
||||
卡名称: 30天时长卡
|
||||
状态: ACTIVE (有效)
|
||||
有效期: 2026-06-02 至 2026-07-02
|
||||
剩余次数: 0
|
||||
剩余金额: 0.00
|
||||
```
|
||||
|
||||
**会员D - 次数卡耗尽**
|
||||
```
|
||||
会员ID: MEM_TEST_D
|
||||
卡名称: 10次卡
|
||||
状态: ACTIVE (有效)
|
||||
有效期: 2026-05-01 至 2026-12-31
|
||||
剩余次数: 0 (已用尽)
|
||||
剩余金额: 0.00
|
||||
```
|
||||
|
||||
**会员E - 次数卡充足**
|
||||
```
|
||||
会员ID: MEM_TEST_E
|
||||
卡名称: 10次卡
|
||||
状态: ACTIVE (有效)
|
||||
有效期: 2026-05-01 至 2026-12-31
|
||||
剩余次数: 5
|
||||
剩余金额: 0.00
|
||||
```
|
||||
|
||||
**会员F - 储值卡余额不足**
|
||||
```
|
||||
会员ID: MEM_TEST_F
|
||||
卡名称: 储值卡500
|
||||
状态: ACTIVE (有效)
|
||||
有效期: 2026-05-01 至 2027-06-02
|
||||
剩余次数: 0
|
||||
剩余金额: 30.00 (不足50.00)
|
||||
```
|
||||
|
||||
**会员G - 储值卡余额充足**
|
||||
```
|
||||
会员ID: MEM_TEST_G
|
||||
卡名称: 储值卡500
|
||||
状态: ACTIVE (有效)
|
||||
有效期: 2026-05-01 至 2027-06-02
|
||||
剩余次数: 0
|
||||
剩余金额: 200.00 (充足)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、SQL数据插入顺序
|
||||
|
||||
```sql
|
||||
-- 1. 先插入会员用户 (A-G)
|
||||
INSERT INTO member_user (member_no, nickname, phone, gender, is_deleted, created_at, updated_at) VALUES
|
||||
('MEM_TEST_A', '用户A_无卡新用户', '13800001001', 1, false, '2026-06-02 10:00:00', '2026-06-02 10:00:00'),
|
||||
('MEM_TEST_B', '用户B_过期时长卡', '13800001002', 1, false, '2026-05-01 10:00:00', '2026-05-01 10:00:00'),
|
||||
('MEM_TEST_C', '会员C_有效时长卡', '13800001003', 2, false, '2026-05-01 10:00:00', '2026-05-01 10:00:00'),
|
||||
('MEM_TEST_D', '会员D_次数用尽', '13800001004', 1, false, '2026-05-01 10:00:00', '2026-05-01 10:00:00'),
|
||||
('MEM_TEST_E', '会员E_次数充足', '13800001005', 2, false, '2026-05-01 10:00:00', '2026-05-01 10:00:00'),
|
||||
('MEM_TEST_F', '会员F_储值卡余额不足', '13800001006', 1, false, '2026-05-01 10:00:00', '2026-05-01 10:00:00'),
|
||||
('MEM_TEST_G', '会员G_储值卡余额充足', '13800001007', 2, false, '2026-05-01 10:00:00', '2026-05-01 10:00:00');
|
||||
|
||||
-- 2. 插入团课课程
|
||||
INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, point_card_amount, stored_value_amount, create_by, created_at, updated_at) VALUES
|
||||
('燃脂搏击_次数卡课程', 102, 2, '2026-06-10 19:30:00', '2026-06-10 20:30:00', 20, 0, '0', '综合训练区', '高强度间歇训练,配合音乐快速燃脂,消耗1次', 1, 0.00, 'admin', '2026-06-01 10:00:00', '2026-06-01 10:00:00');
|
||||
|
||||
INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, point_card_amount, stored_value_amount, create_by, created_at, updated_at) VALUES
|
||||
('高端普拉提_储值卡课程', 103, 1, '2026-06-11 19:00:00', '2026-06-11 20:00:00', 15, 0, '0', '普拉提教室', '精准训练核心肌群,消耗储值50元', 0, 50.00, 'admin', '2026-06-01 10:00:00', '2026-06-01 10:00:00');
|
||||
|
||||
-- 3. 插入会员卡类型
|
||||
INSERT INTO member_card (member_card_name, member_card_type, member_card_price, member_card_validity_days, member_card_total_times, member_card_amount, member_card_status, extra_config, created_at, updated_at) VALUES
|
||||
('30天时长卡', 'TIME_CARD', 299.00, 30, NULL, NULL, 1, '{}', '2026-01-01 00:00:00', '2026-01-01 00:00:00'),
|
||||
('10次卡', 'COUNT_CARD', 499.00, NULL, 10, NULL, 1, '{}', '2026-01-01 00:00:00', '2026-01-01 00:00:00'),
|
||||
('储值卡500', 'STORED_VALUE_CARD', 500.00, NULL, NULL, 500.00, 1, '{}', '2026-01-01 00:00:00', '2026-01-01 00:00:00');
|
||||
|
||||
-- 4. 插入会员卡记录
|
||||
INSERT INTO member_card_record (member_id, member_card_id, status, remaining_times, remaining_amount, expire_time, purchase_time, version, card_composition, created_at, updated_at) VALUES
|
||||
((SELECT id FROM member_user WHERE member_no = 'MEM_TEST_B'), (SELECT member_card_id FROM member_card WHERE member_card_name = '30天时长卡'), 'EXPIRED', 0, 0.00, '2026-05-31 23:59:59', '2026-05-01 10:00:00', 0, '{}', '2026-05-01 10:00:00', '2026-06-02 10:00:00');
|
||||
|
||||
INSERT INTO member_card_record (member_id, member_card_id, status, remaining_times, remaining_amount, expire_time, purchase_time, version, card_composition, created_at, updated_at) VALUES
|
||||
((SELECT id FROM member_user WHERE member_no = 'MEM_TEST_C'), (SELECT member_card_id FROM member_card WHERE member_card_name = '30天时长卡'), 'ACTIVE', 0, 0.00, '2026-07-02 23:59:59', '2026-06-02 10:00:00', 0, '{}', '2026-06-02 10:00:00', '2026-06-02 10:00:00');
|
||||
|
||||
INSERT INTO member_card_record (member_id, member_card_id, status, remaining_times, remaining_amount, expire_time, purchase_time, version, card_composition, created_at, updated_at) VALUES
|
||||
((SELECT id FROM member_user WHERE member_no = 'MEM_TEST_D'), (SELECT member_card_id FROM member_card WHERE member_card_name = '10次卡'), 'ACTIVE', 0, 0.00, '2026-12-31 23:59:59', '2026-05-01 10:00:00', 0, '{}', '2026-05-01 10:00:00', '2026-06-02 10:00:00');
|
||||
|
||||
INSERT INTO member_card_record (member_id, member_card_id, status, remaining_times, remaining_amount, expire_time, purchase_time, version, card_composition, created_at, updated_at) VALUES
|
||||
((SELECT id FROM member_user WHERE member_no = 'MEM_TEST_E'), (SELECT member_card_id FROM member_card WHERE member_card_name = '10次卡'), 'ACTIVE', 5, 0.00, '2026-12-31 23:59:59', '2026-05-01 10:00:00', 0, '{}', '2026-05-01 10:00:00', '2026-06-02 10:00:00');
|
||||
|
||||
INSERT INTO member_card_record (member_id, member_card_id, status, remaining_times, remaining_amount, expire_time, purchase_time, version, card_composition, created_at, updated_at) VALUES
|
||||
((SELECT id FROM member_user WHERE member_no = 'MEM_TEST_F'), (SELECT member_card_id FROM member_card WHERE member_card_name = '储值卡500'), 'ACTIVE', 0, 30.00, '2027-06-02 23:59:59', '2026-05-01 10:00:00', 0, '{}', '2026-05-01 10:00:00', '2026-06-02 10:00:00');
|
||||
|
||||
INSERT INTO member_card_record (member_id, member_card_id, status, remaining_times, remaining_amount, expire_time, purchase_time, version, card_composition, created_at, updated_at) VALUES
|
||||
((SELECT id FROM member_user WHERE member_no = 'MEM_TEST_G'), (SELECT member_card_id FROM member_card WHERE member_card_name = '储值卡500'), 'ACTIVE', 0, 200.00, '2027-06-02 23:59:59', '2026-05-01 10:00:00', 0, '{}', '2026-05-01 10:00:00', '2026-06-02 10:00:00');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、预期测试结果
|
||||
|
||||
### 7.1 成功场景
|
||||
|
||||
| 场景 | 会员 | 操作 | 预期结果 |
|
||||
|-----|------|-----|---------|
|
||||
| 3 | 会员C | 预约次数卡团课 | 预约成功,消耗时长卡1次 |
|
||||
| 5 | 会员E | 预约次数卡团课 | 预约成功,次数减1 (5→4) |
|
||||
| 7 | 会员G | 预约储值卡团课 | 预约成功,余额减50 (200→150) |
|
||||
|
||||
### 7.2 失败场景
|
||||
|
||||
| 场景 | 会员 | 操作 | 预期错误码 | 预期提示信息 |
|
||||
|-----|------|-----|----------|------------|
|
||||
| 1 | 用户A | 预约次数卡团课 | NO_CARD | 无可用会员卡 |
|
||||
| 2 | 用户B | 预约次数卡团课 | CARD_EXPIRED | 会员卡已过期 |
|
||||
| 4 | 会员D | 预约次数卡团课 | INSUFFICIENT_TIMES | 剩余次数不足 |
|
||||
| 6 | 会员F | 预约储值卡团课 | INSUFFICIENT_BALANCE | 余额不足,当前余额30.00元,需50.00元 |
|
||||
|
||||
---
|
||||
|
||||
## 八、数据清理
|
||||
|
||||
测试完成后,可通过以下 SQL 清理测试数据:
|
||||
|
||||
```sql
|
||||
-- 删除测试会员(会级联删除相关会员卡记录)
|
||||
DELETE FROM member_user WHERE member_no LIKE 'MEM_TEST_%';
|
||||
|
||||
-- 删除测试团课
|
||||
DELETE FROM group_course WHERE course_name LIKE '%_次数卡课程' OR course_name LIKE '%_储值卡课程';
|
||||
|
||||
-- 删除测试会员卡类型
|
||||
DELETE FROM member_card WHERE member_card_name IN ('30天时长卡', '10次卡', '储值卡500');
|
||||
```
|
||||
@@ -0,0 +1,204 @@
|
||||
# V11 团课预约取消测试数据文档
|
||||
|
||||
## 文档说明
|
||||
|
||||
本文档描述了用于测试团课预约取消功能的测试数据,包含三种会员卡类型的取消预约场景。
|
||||
|
||||
## 测试场景概览
|
||||
|
||||
| 序号 | 场景描述 | 用户 | 会员卡类型 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 1 | 使用时长卡预约后取消 | 张三 | 时长卡(30天) |
|
||||
| 2 | 使用次数卡预约后取消 | 李四 | 次数卡(10次) |
|
||||
| 3 | 使用储值卡预约后取消 | 王五 | 储值卡(500元) |
|
||||
|
||||
## 测试用户数据
|
||||
|
||||
### 1. 张三(时长卡用户)
|
||||
|
||||
| 字段 | 值 |
|
||||
| :--- | :--- |
|
||||
| 会员编号 | `MEM_TEST_ZHANG` |
|
||||
| 昵称 | 张三_时长卡用户 |
|
||||
| 手机号 | 13800002001 |
|
||||
| 性别 | 男(1) |
|
||||
|
||||
#### 会员卡信息
|
||||
|
||||
| 字段 | 值 |
|
||||
| :--- | :--- |
|
||||
| 卡类型 | 时长卡(TIME_CARD) |
|
||||
| 卡名称 | 30天时长卡 |
|
||||
| 状态 | ACTIVE(有效) |
|
||||
| 到期时间 | 2026-07-02 23:59:59 |
|
||||
| 购买时间 | 2026-06-02 10:00:00 |
|
||||
|
||||
---
|
||||
|
||||
### 2. 李四(次数卡用户)
|
||||
|
||||
| 字段 | 值 |
|
||||
| :--- | :--- |
|
||||
| 会员编号 | `MEM_TEST_LI` |
|
||||
| 昵称 | 李四_次数卡用户 |
|
||||
| 手机号 | 13800002002 |
|
||||
| 性别 | 男(1) |
|
||||
|
||||
#### 会员卡信息
|
||||
|
||||
| 字段 | 值 |
|
||||
| :--- | :--- |
|
||||
| 卡类型 | 次数卡(COUNT_CARD) |
|
||||
| 卡名称 | 10次卡 |
|
||||
| 状态 | ACTIVE(有效) |
|
||||
| 剩余次数 | 5次 |
|
||||
| 到期时间 | 2026-12-31 23:59:59 |
|
||||
|
||||
---
|
||||
|
||||
### 3. 王五(储值卡用户)
|
||||
|
||||
| 字段 | 值 |
|
||||
| :--- | :--- |
|
||||
| 会员编号 | `MEM_TEST_WANG` |
|
||||
| 昵称 | 王五_储值卡用户 |
|
||||
| 手机号 | 13800002003 |
|
||||
| 性别 | 女(2) |
|
||||
|
||||
#### 会员卡信息
|
||||
|
||||
| 字段 | 值 |
|
||||
| :--- | :--- |
|
||||
| 卡类型 | 储值卡(STORED_VALUE_CARD) |
|
||||
| 卡名称 | 储值卡500 |
|
||||
| 状态 | ACTIVE(有效) |
|
||||
| 剩余金额 | 200.00元 |
|
||||
| 到期时间 | 2027-06-02 23:59:59 |
|
||||
|
||||
---
|
||||
|
||||
## 测试课程数据
|
||||
|
||||
### 晚间瑜伽_取消测试
|
||||
|
||||
| 字段 | 值 |
|
||||
| :--- | :--- |
|
||||
| 课程名称 | 晚间瑜伽_取消测试 |
|
||||
| 教练ID | 101 |
|
||||
| 课程类型 | 1 |
|
||||
| 开始时间 | 2026-06-15 19:00:00 |
|
||||
| 结束时间 | 2026-06-15 20:00:00 |
|
||||
| 上课地点 | 瑜伽教室 |
|
||||
| 最大人数 | 20人 |
|
||||
| 当前人数 | 3人(三位测试用户) |
|
||||
| 状态 | 0(正常) |
|
||||
| 次数消耗 | 1次 |
|
||||
| 储值消耗 | 30.00元 |
|
||||
|
||||
---
|
||||
|
||||
## 预约记录数据
|
||||
|
||||
### 预约状态说明
|
||||
|
||||
| 状态码 | 含义 |
|
||||
| :--- | :--- |
|
||||
| `0` | 已预约(等待取消) |
|
||||
| `1` | 已取消 |
|
||||
| `2` | 已出席 |
|
||||
| `3` | 缺席 |
|
||||
|
||||
### 预约记录详情
|
||||
|
||||
| 用户 | 预约时间 | 状态 | 课程名称 |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| 张三 | 2026-06-02 11:00:00 | 0(已预约) | 晚间瑜伽_取消测试 |
|
||||
| 李四 | 2026-06-02 11:30:00 | 0(已预约) | 晚间瑜伽_取消测试 |
|
||||
| 王五 | 2026-06-02 12:00:00 | 0(已预约) | 晚间瑜伽_取消测试 |
|
||||
|
||||
---
|
||||
|
||||
## 测试用例设计
|
||||
|
||||
### 场景1:时长卡用户取消预约
|
||||
|
||||
**前置条件:**
|
||||
- 张三持有有效时长卡
|
||||
- 张三已成功预约课程
|
||||
- 当前时间 < 课程开始时间
|
||||
|
||||
**测试步骤:**
|
||||
1. 调用取消预约接口,传入张三的预约记录ID
|
||||
2. 验证预约状态变为 `1`(已取消)
|
||||
3. 验证课程当前人数减1
|
||||
4. 验证时长卡状态保持不变(时长卡取消预约不影响卡状态)
|
||||
|
||||
**预期结果:**
|
||||
- 预约记录状态更新为已取消
|
||||
- 课程剩余名额增加1
|
||||
- 时长卡有效期不受影响
|
||||
|
||||
---
|
||||
|
||||
### 场景2:次数卡用户取消预约
|
||||
|
||||
**前置条件:**
|
||||
- 李四持有次数卡,剩余5次
|
||||
- 李四已成功预约课程(已扣除1次)
|
||||
- 当前时间 < 课程开始时间
|
||||
|
||||
**测试步骤:**
|
||||
1. 调用取消预约接口,传入李四的预约记录ID
|
||||
2. 验证预约状态变为 `1`(已取消)
|
||||
3. 验证课程当前人数减1
|
||||
4. 验证次数卡剩余次数恢复为5次(返还1次)
|
||||
|
||||
**预期结果:**
|
||||
- 预约记录状态更新为已取消
|
||||
- 课程剩余名额增加1
|
||||
- 次数卡返还1次,剩余次数恢复为5次
|
||||
|
||||
---
|
||||
|
||||
### 场景3:储值卡用户取消预约
|
||||
|
||||
**前置条件:**
|
||||
- 王五持有储值卡,余额200元
|
||||
- 王五已成功预约课程(已扣除30元)
|
||||
- 当前时间 < 课程开始时间
|
||||
|
||||
**测试步骤:**
|
||||
1. 调用取消预约接口,传入王五的预约记录ID
|
||||
2. 验证预约状态变为 `1`(已取消)
|
||||
3. 验证课程当前人数减1
|
||||
4. 验证储值卡余额恢复为200元(返还30元)
|
||||
|
||||
**预期结果:**
|
||||
- 预约记录状态更新为已取消
|
||||
- 课程剩余名额增加1
|
||||
- 储值卡返还30元,余额恢复为200元
|
||||
|
||||
---
|
||||
|
||||
## 数据文件位置
|
||||
|
||||
```
|
||||
manage-db/src/main/resources/db/migration/V11__Insert_Cancel_Booking_Test_Data.sql
|
||||
```
|
||||
|
||||
## 数据依赖
|
||||
|
||||
| 依赖文件 | 说明 |
|
||||
| :--- | :--- |
|
||||
| `V6__Create_GroupCourse_table.sql` | 团课相关表结构 |
|
||||
| `V8__Create_Member_And_MemberCard.sql` | 会员和会员卡表结构 |
|
||||
| `V9__Add_GroupCourse_Booking_Snapshot_Fields.sql` | 预约快照字段 |
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. 测试数据中使用的日期均为未来日期,确保测试时课程尚未开始
|
||||
2. 会员卡状态均为 ACTIVE,确保可以正常预约
|
||||
3. 取消预约功能应在课程开始前24小时内允许操作(具体时间限制由业务逻辑决定)
|
||||
4. 取消预约后应记录操作日志和交易流水
|
||||
@@ -0,0 +1,400 @@
|
||||
# 团课预约场景测试数据文档
|
||||
|
||||
## 概述
|
||||
|
||||
本文档描述了团课预约功能的测试数据,覆盖了各种预约场景,用于验证系统在不同业务条件下的正确性和健壮性。
|
||||
|
||||
---
|
||||
|
||||
## 一、测试数据概览
|
||||
|
||||
| 数据类别 | 数量 | 说明 |
|
||||
|---------|------|------|
|
||||
| 测试会员 | 5个 | 覆盖不同会员卡状态 |
|
||||
| 会员卡类型 | 8种 | 次卡/时长卡/储值卡 |
|
||||
| 会员卡记录 | 5条 | 会员持有的实际卡 |
|
||||
| 团课预约记录 | 4条 | 不同状态的预约 |
|
||||
| 交易流水 | 27条 | 完整的消费记录 |
|
||||
|
||||
---
|
||||
|
||||
## 二、会员测试数据
|
||||
|
||||
### 2.1 会员列表
|
||||
|
||||
| 会员ID | 会员编号 | 昵称 | 手机号 | 性别 | 会员卡状态 |
|
||||
|--------|---------|------|--------|------|-----------|
|
||||
| 1001 | MEM202606001 | 新用户小张 | 13800138001 | 男 | 无会员卡 |
|
||||
| 1002 | MEM202606002 | 额度耗尽用户 | 13800138002 | 女 | 次卡已用完 |
|
||||
| 1003 | MEM202606003 | 额度充足用户 | 13800138003 | 男 | 次卡剩余8次 |
|
||||
| 1004 | MEM202606004 | 过期卡用户 | 13800138004 | 女 | 月卡已过期 |
|
||||
| 1005 | MEM202606005 | 多卡用户小李 | 13800138005 | 男 | 次卡+储值卡 |
|
||||
|
||||
### 2.2 会员详情
|
||||
|
||||
**会员1001 - 新用户小张**
|
||||
- 状态:新注册用户,尚未购买任何会员卡
|
||||
- 用途:测试无会员卡情况下的预约行为
|
||||
|
||||
**会员1002 - 额度耗尽用户**
|
||||
- 状态:持有10次团课卡,已全部用完
|
||||
- 用途:测试会员卡额度耗尽时的预约行为
|
||||
|
||||
**会员1003 - 额度充足用户**
|
||||
- 状态:持有20次团课卡,剩余8次
|
||||
- 用途:测试正常预约流程
|
||||
|
||||
**会员1004 - 过期卡用户**
|
||||
- 状态:持有月卡,已于2026-05-31过期
|
||||
- 用途:测试过期会员卡的预约行为
|
||||
|
||||
**会员1005 - 多卡用户小李**
|
||||
- 状态:持有50次团课卡(剩余45次) + 500元储值卡(剩余350元)
|
||||
- 用途:测试多会员卡用户选择支付方式的场景
|
||||
|
||||
---
|
||||
|
||||
## 三、会员卡类型数据
|
||||
|
||||
### 3.1 次卡类型
|
||||
|
||||
| 卡类型ID | 卡名称 | 类型 | 价格 | 有效天数 | 总次数 | 状态 |
|
||||
|---------|-------|------|------|---------|-------|------|
|
||||
| 101 | 10次团课卡 | COUNT_CARD | 299.00 | 90 | 10 | 上架 |
|
||||
| 102 | 20次团课卡 | COUNT_CARD | 499.00 | 180 | 20 | 上架 |
|
||||
| 103 | 50次团课卡 | COUNT_CARD | 999.00 | 365 | 50 | 上架 |
|
||||
|
||||
### 3.2 时长卡类型
|
||||
|
||||
| 卡类型ID | 卡名称 | 类型 | 价格 | 有效天数 | 状态 |
|
||||
|---------|-------|------|------|---------|------|
|
||||
| 201 | 月卡 | TIME_CARD | 399.00 | 30 | 上架 |
|
||||
| 202 | 季卡 | TIME_CARD | 899.00 | 90 | 上架 |
|
||||
| 203 | 年卡 | TIME_CARD | 2999.00 | 365 | 上架 |
|
||||
|
||||
### 3.3 储值卡类型
|
||||
|
||||
| 卡类型ID | 卡名称 | 类型 | 价格 | 面额 | 有效天数 | 状态 |
|
||||
|---------|-------|------|------|------|---------|------|
|
||||
| 301 | 500元储值卡 | STORED_VALUE_CARD | 500.00 | 500.00 | 365 | 上架 |
|
||||
| 302 | 1000元储值卡 | STORED_VALUE_CARD | 1000.00 | 1000.00 | 365 | 上架 |
|
||||
|
||||
---
|
||||
|
||||
## 四、会员卡记录数据(会员持有的卡)
|
||||
|
||||
| 记录ID | 会员ID | 卡类型ID | 状态 | 剩余次数 | 剩余金额 | 到期时间 | 购买时间 |
|
||||
|-------|--------|---------|------|---------|---------|---------|---------|
|
||||
| 2001 | 1002 | 101 | USED_UP | 0 | 0.00 | 2026-09-01 | 2026-06-01 |
|
||||
| 2002 | 1003 | 102 | ACTIVE | 8 | 0.00 | 2026-12-01 | 2026-06-01 |
|
||||
| 2003 | 1004 | 201 | EXPIRED | 0 | 0.00 | 2026-05-31 | 2026-05-01 |
|
||||
| 2004 | 1005 | 103 | ACTIVE | 45 | 0.00 | 2027-06-01 | 2026-06-01 |
|
||||
| 2005 | 1005 | 301 | ACTIVE | 0 | 350.00 | 2027-06-01 | 2026-05-15 |
|
||||
|
||||
---
|
||||
|
||||
## 五、团课预约记录数据
|
||||
|
||||
| 预约ID | 课程ID | 会员ID | 会员卡记录ID | 预约时间 | 状态 | 课程名称 |
|
||||
|-------|-------|--------|-------------|---------|------|---------|
|
||||
| 3001 | 1 | 1003 | 2002 | 2026-06-01 15:30 | 已预约(0) | 极速燃脂单车 |
|
||||
| 3002 | 2 | 1003 | 2002 | 2026-06-01 10:00 | 已取消(1) | 清晨流瑜伽 |
|
||||
| 3003 | 6 | 1003 | 2002 | 2026-05-28 19:00 | 已出席(2) | 蜜桃臀塑造 |
|
||||
| 3004 | 7 | 1002 | 2001 | 2026-05-30 10:00 | 缺席(3) | 午间冥想放松 |
|
||||
|
||||
### 状态说明
|
||||
|
||||
| 状态码 | 状态名称 | 说明 |
|
||||
|-------|---------|------|
|
||||
| 0 | 已预约 | 用户已成功预约,等待上课 |
|
||||
| 1 | 已取消 | 用户主动取消预约 |
|
||||
| 2 | 已出席 | 用户已按时参加课程 |
|
||||
| 3 | 缺席 | 用户预约后未出席 |
|
||||
|
||||
---
|
||||
|
||||
## 六、测试场景详解
|
||||
|
||||
### 场景1:新注册用户无会员卡预约
|
||||
|
||||
**测试目标**:验证系统对无会员卡用户的预约拦截
|
||||
|
||||
**测试数据**:
|
||||
- 用户ID:1001(新用户小张)
|
||||
- 目标课程:任意课程
|
||||
|
||||
**预期结果**:
|
||||
- 返回错误信息:"未绑定会员卡,请先购买会员卡"
|
||||
- HTTP状态码:400 Bad Request
|
||||
|
||||
---
|
||||
|
||||
### 场景2:会员卡额度耗尽预约
|
||||
|
||||
**测试目标**:验证系统对额度耗尽会员卡的预约拦截
|
||||
|
||||
**测试数据**:
|
||||
- 用户ID:1002(额度耗尽用户)
|
||||
- 会员卡记录ID:2001
|
||||
- 剩余次数:0
|
||||
|
||||
**预期结果**:
|
||||
- 返回错误信息:"会员卡余额不足"
|
||||
- HTTP状态码:400 Bad Request
|
||||
|
||||
---
|
||||
|
||||
### 场景3:会员卡额度充足预约
|
||||
|
||||
**测试目标**:验证正常预约流程
|
||||
|
||||
**测试数据**:
|
||||
- 用户ID:1003(额度充足用户)
|
||||
- 会员卡记录ID:2002
|
||||
- 剩余次数:8
|
||||
- 目标课程:课程ID=1(极速燃脂单车)
|
||||
|
||||
**预期结果**:
|
||||
- 预约成功
|
||||
- 会员卡剩余次数减1(变为7次)
|
||||
- 生成预约记录
|
||||
- HTTP状态码:200 OK
|
||||
|
||||
---
|
||||
|
||||
### 场景4:会员卡已过期预约
|
||||
|
||||
**测试目标**:验证系统对过期会员卡的预约拦截
|
||||
|
||||
**测试数据**:
|
||||
- 用户ID:1004(过期卡用户)
|
||||
- 会员卡记录ID:2003
|
||||
- 状态:EXPIRED
|
||||
- 到期时间:2026-05-31
|
||||
|
||||
**预期结果**:
|
||||
- 返回错误信息:"会员卡已过期"
|
||||
- HTTP状态码:400 Bad Request
|
||||
|
||||
---
|
||||
|
||||
### 场景5:课程已满员预约---------------
|
||||
|
||||
**测试目标**:验证系统对满员课程的预约拦截
|
||||
|
||||
**测试数据**:
|
||||
- 课程ID:3(燃脂搏击)
|
||||
- 当前人数:20/20
|
||||
|
||||
**预期结果**:
|
||||
- 返回错误信息:"课程已满员"
|
||||
- HTTP状态码:400 Bad Request
|
||||
|
||||
---
|
||||
|
||||
### 场景6:课程已取消预约
|
||||
|
||||
**测试目标**:验证系统对已取消课程的预约拦截
|
||||
|
||||
**测试数据**:
|
||||
- 课程ID:5(周末冥想修复)
|
||||
- 状态:1(已取消)
|
||||
|
||||
**预期结果**:
|
||||
- 返回错误信息:"课程已取消"
|
||||
- HTTP状态码:400 Bad Request
|
||||
|
||||
---
|
||||
|
||||
### 场景7:课程已结束预约
|
||||
|
||||
**测试目标**:验证系统对已结束课程的预约拦截
|
||||
|
||||
**测试数据**:
|
||||
- 课程ID:6(蜜桃臀塑造)或 7(午间冥想放松)
|
||||
- 状态:2(已结束)
|
||||
|
||||
**预期结果**:
|
||||
- 返回错误信息:"课程已结束"
|
||||
- HTTP状态码:400 Bad Request
|
||||
|
||||
---
|
||||
|
||||
### 场景8:超出预约时间预约
|
||||
|
||||
**测试目标**:验证系统对预约时间窗口的控制
|
||||
|
||||
**测试数据**:
|
||||
- 课程ID:4(哈他瑜伽)
|
||||
- 开始时间:2026-06-01 15:20:00
|
||||
- 测试时间:课程开始前30分钟内
|
||||
|
||||
**预期结果**:
|
||||
- 返回错误信息:"已过预约时间"
|
||||
- HTTP状态码:400 Bad Request
|
||||
|
||||
---
|
||||
|
||||
### 场景9:重复预约同一课程
|
||||
|
||||
**测试目标**:验证系统对重复预约的拦截
|
||||
|
||||
**测试数据**:
|
||||
- 用户ID:1003(额度充足用户)
|
||||
- 课程ID:1(极速燃脂单车)
|
||||
- 已有预约记录:booking_id=3001
|
||||
|
||||
**预期结果**:
|
||||
- 返回错误信息:"已预约该课程"
|
||||
- HTTP状态码:400 Bad Request
|
||||
|
||||
---
|
||||
|
||||
### 场景10:多会员卡用户选择支付方式
|
||||
|
||||
**测试目标**:验证多卡用户的支付方式选择功能
|
||||
|
||||
**测试数据**:
|
||||
- 用户ID:1005(多卡用户小李)
|
||||
- 可用卡1:次卡(记录ID=2004,剩余45次)
|
||||
- 可用卡2:储值卡(记录ID=2005,剩余350元)
|
||||
|
||||
**预期结果**:
|
||||
- 系统列出用户所有可用会员卡
|
||||
- 用户可选择使用次卡或储值卡支付
|
||||
- 根据选择的卡类型扣减相应额度
|
||||
|
||||
---
|
||||
|
||||
## 七、交易流水说明
|
||||
|
||||
### 7.1 会员1002(额度耗尽用户)消费记录
|
||||
|
||||
| 操作顺序 | 操作类型 | 变动次数 | 剩余次数 | 备注 |
|
||||
|---------|---------|---------|---------|------|
|
||||
| 1 | PURCHASE | +10 | 10 | 购买10次团课卡 |
|
||||
| 2-11 | DEDUCT | -1×10 | 0 | 10次课程消费 |
|
||||
|
||||
### 7.2 会员1003(额度充足用户)消费记录
|
||||
|
||||
| 操作顺序 | 操作类型 | 变动次数 | 剩余次数 | 备注 |
|
||||
|---------|---------|---------|---------|------|
|
||||
| 1 | PURCHASE | +20 | 20 | 购买20次团课卡 |
|
||||
| 2-12 | DEDUCT | -12 | 8 | 12次课程消费 |
|
||||
|
||||
### 7.3 会员1005(多卡用户)消费记录
|
||||
|
||||
| 会员卡记录ID | 操作类型 | 变动次数 | 变动金额 | 备注 |
|
||||
|-------------|---------|---------|---------|------|
|
||||
| 2004 | PURCHASE | +50 | 0 | 购买50次团课卡 |
|
||||
| 2004 | DEDUCT | -5 | 0 | 预约5节课程 |
|
||||
| 2005 | PURCHASE | 0 | +500 | 购买500元储值卡 |
|
||||
| 2005 | DEDUCT | 0 | -150 | 私教课消费150元 |
|
||||
|
||||
---
|
||||
|
||||
## 八、API测试示例
|
||||
|
||||
### 8.1 预约接口
|
||||
|
||||
```http
|
||||
POST /api/group-course/bookings
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"courseId": 1,
|
||||
"memberCardRecordId": 2002
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 取消预约接口
|
||||
|
||||
```http
|
||||
PUT /api/group-course/bookings/{bookingId}/cancel
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"reason": "临时有事无法参加"
|
||||
}
|
||||
```
|
||||
|
||||
### 8.3 查询用户预约列表
|
||||
|
||||
```http
|
||||
GET /api/group-course/bookings?memberId=1003
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、测试数据对应关系图
|
||||
|
||||
```
|
||||
会员表 (member_user)
|
||||
│
|
||||
├── 1001 ──→ (无会员卡)
|
||||
├── 1002 ──→ 会员卡记录 2001 (USED_UP)
|
||||
├── 1003 ──→ 会员卡记录 2002 (ACTIVE, 8次)
|
||||
├── 1004 ──→ 会员卡记录 2003 (EXPIRED)
|
||||
└── 1005 ──→ 会员卡记录 2004 (ACTIVE, 45次)
|
||||
└── 会员卡记录 2005 (ACTIVE, 350元)
|
||||
│
|
||||
↓
|
||||
预约记录表 (group_course_booking)
|
||||
│
|
||||
├── 3001: 已预约
|
||||
├── 3002: 已取消
|
||||
├── 3003: 已出席
|
||||
└── 3004: 缺席
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、数据初始化
|
||||
|
||||
测试数据通过 Flyway 迁移脚本 `V10__Insert_Booking_Test_Data.sql` 初始化,需在数据库初始化时执行。
|
||||
|
||||
**执行顺序**:
|
||||
1. V1__Create_all_tables.sql - 创建基础表结构
|
||||
2. V2__Insert_initial_data.sql - 插入初始数据
|
||||
3. V6__Create_GroupCourse_table.sql - 创建团课表
|
||||
4. V7__Insert_GroupCourse_test_data.sql - 插入团课测试数据
|
||||
5. V8__Create_Member_And_MemberCard.sql - 创建会员和会员卡表
|
||||
6. V9__Add_GroupCourse_Booking_Snapshot_Fields.sql - 添加冗余字段
|
||||
7. V10__Insert_Booking_Test_Data.sql - 插入预约测试数据(本文件)
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.1
|
||||
**创建时间**: 2026-06-02
|
||||
**更新时间**: 2026-06-02
|
||||
**适用场景**: 团课预约功能测试
|
||||
|
||||
---
|
||||
|
||||
## 十一、重要说明
|
||||
|
||||
### 11.1 字段说明
|
||||
|
||||
`member_card_record` 表包含两个ID字段:
|
||||
- `id` - 数据库主键(BIGSERIAL PRIMARY KEY)
|
||||
- `member_card_record_id` - 业务ID(BIGSERIAL),代码中使用此字段作为查询和更新条件
|
||||
|
||||
### 11.2 测试数据修复记录
|
||||
|
||||
**v1.1 修复内容**:
|
||||
- 修复了 `member_card_record` 表测试数据缺失 `member_card_record_id` 字段的问题
|
||||
- 原问题:测试数据只插入了 `id` 字段,导致 `member_card_record_id` 为 NULL
|
||||
- 影响:代码使用 `member_card_record_id` 作为WHERE条件时无法匹配到记录,导致扣减权益失败
|
||||
- 解决:在INSERT语句中添加 `member_card_record_id` 字段,值与 `id` 相同
|
||||
|
||||
**修复前**:
|
||||
```sql
|
||||
INSERT INTO member_card_record (id, member_id, member_card_id, ...) VALUES
|
||||
(2001, 1002, 101, ...);
|
||||
```
|
||||
|
||||
**修复后**:
|
||||
```sql
|
||||
INSERT INTO member_card_record (id, member_card_record_id, member_id, member_card_id, ...) VALUES
|
||||
(2001, 2001, 1002, 101, ...);
|
||||
```
|
||||
@@ -0,0 +1,728 @@
|
||||
# 团课管理模块 API 文档
|
||||
|
||||
> **文档版本**: v1.0
|
||||
> **创建日期**: 2026-06-02
|
||||
> **作者**: 张翔
|
||||
> **状态**: 正式发布
|
||||
|
||||
---
|
||||
|
||||
## 📋 目录
|
||||
|
||||
1. [概述](#概述)
|
||||
2. [基础路径](#基础路径)
|
||||
3. [团课管理接口](#团课管理接口)
|
||||
- [获取所有团课](#获取所有团课)
|
||||
- [分页获取团课](#分页获取团课)
|
||||
- [根据ID获取团课详情](#根据ID获取团课详情)
|
||||
- [创建团课](#创建团课)
|
||||
- [更新团课](#更新团课)
|
||||
- [取消团课](#取消团课)
|
||||
- [团课签到](#团课签到)
|
||||
- [删除团课](#删除团课)
|
||||
4. [团课预约接口](#团课预约接口)
|
||||
- [预约团课](#预约团课)
|
||||
- [取消预约](#取消预约)
|
||||
- [查询会员预约记录](#查询会员预约记录)
|
||||
- [查询预约详情](#查询预约详情)
|
||||
- [查询课程预约记录](#查询课程预约记录)
|
||||
5. [数据模型](#数据模型)
|
||||
- [GroupCourse(团课)](#GroupCourse团课)
|
||||
- [GroupCourseBooking(团课预约)](#GroupCourseBooking团课预约)
|
||||
6. [状态码说明](#状态码说明)
|
||||
7. [业务规则](#业务规则)
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
团课管理模块提供团课的创建、编辑、查询、取消和签到功能,以及团课预约相关操作。采用 Spring WebFlux 响应式编程,支持高并发场景。
|
||||
|
||||
## 基础路径
|
||||
|
||||
所有接口的基础路径为: `http://{host}:{port}/api/groupCourse`
|
||||
|
||||
---
|
||||
|
||||
## 团课管理接口
|
||||
|
||||
### 获取所有团课
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | GET |
|
||||
| **接口路径** | `/api/groupCourse/list` |
|
||||
| **所属文件** | `GroupCourseHandler.java` |
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|------|
|
||||
| includeDeleted | boolean | 否 | false | 是否包含已删除的团课 |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"courseName": "瑜伽入门",
|
||||
"coachId": 1,
|
||||
"courseType": 1,
|
||||
"startTime": "2026-06-02T09:00:00",
|
||||
"endTime": "2026-06-02T10:00:00",
|
||||
"maxMembers": 20,
|
||||
"currentMembers": 15,
|
||||
"status": 0,
|
||||
"location": "健身房A区",
|
||||
"coverImage": "https://example.com/yoga.jpg",
|
||||
"description": "适合初学者的瑜伽课程",
|
||||
"createdAt": "2026-06-01T10:00:00",
|
||||
"updatedAt": "2026-06-01T10:00:00"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 分页获取团课
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | POST |
|
||||
| **接口路径** | `/api/groupCourse/page` |
|
||||
| **所属文件** | `GroupCourseHandler.java` |
|
||||
|
||||
**请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"page": 0,
|
||||
"size": 10,
|
||||
"sort": "id",
|
||||
"order": "asc",
|
||||
"keyword": "瑜伽"
|
||||
}
|
||||
```
|
||||
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|------|
|
||||
| page | int | 否 | 0 | 页码,从0开始 |
|
||||
| size | int | 否 | 10 | 每页数量,最大100 |
|
||||
| sort | string | 否 | id | 排序字段 |
|
||||
| order | string | 否 | asc | 排序方式(asc/desc) |
|
||||
| keyword | string | 否 | - | 搜索关键词 |
|
||||
|
||||
**请求参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
|
||||
|--------|------|------|--------|------|
|
||||
| includeDeleted | boolean | 否 | false | 是否包含已删除的团课 |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"data": [...],
|
||||
"totalPages": 5,
|
||||
"totalElements": 45,
|
||||
"page": 0,
|
||||
"size": 10
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 根据ID获取团课详情
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | GET |
|
||||
| **接口路径** | `/api/groupCourse/{id}` |
|
||||
| **所属文件** | `GroupCourseHandler.java` |
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | Long | 是 | 团课ID |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"courseName": "瑜伽入门",
|
||||
"coachId": 1,
|
||||
"courseType": 1,
|
||||
"startTime": "2026-06-02T09:00:00",
|
||||
"endTime": "2026-06-02T10:00:00",
|
||||
"maxMembers": 20,
|
||||
"currentMembers": 15,
|
||||
"status": 0,
|
||||
"location": "健身房A区",
|
||||
"coverImage": "https://example.com/yoga.jpg",
|
||||
"description": "适合初学者的瑜伽课程",
|
||||
"pointCardAmount": 1,
|
||||
"storedValueAmount": 50.00,
|
||||
"createdAt": "2026-06-01T10:00:00",
|
||||
"updatedAt": "2026-06-01T10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应** (404 Not Found):
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 创建团课
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | POST |
|
||||
| **接口路径** | `/api/groupCourse` |
|
||||
| **所属文件** | `GroupCourseHandler.java` |
|
||||
|
||||
**请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"courseName": "动感单车",
|
||||
"coachId": 2,
|
||||
"courseType": 2,
|
||||
"startTime": "2026-06-05T18:00:00",
|
||||
"endTime": "2026-06-05T19:00:00",
|
||||
"maxMembers": 25,
|
||||
"location": "健身房B区",
|
||||
"coverImage": "https://example.com/spinning.jpg",
|
||||
"description": "高强度有氧运动课程",
|
||||
"pointCardAmount": 1,
|
||||
"storedValueAmount": 50.00
|
||||
}
|
||||
```
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| courseName | String | **是** | 课程名称 |
|
||||
| coachId | Long | 否 | 教练ID |
|
||||
| courseType | Long | 否 | 课程类型 |
|
||||
| startTime | LocalDateTime | 否 | 开始时间 |
|
||||
| endTime | LocalDateTime | 否 | 结束时间 |
|
||||
| maxMembers | Integer | 否 | 最大参与人数,默认20 |
|
||||
| location | String | 否 | 上课地点 |
|
||||
| coverImage | String | 否 | 封面图URL |
|
||||
| description | String | 否 | 课程描述 |
|
||||
| pointCardAmount | Integer | 否 | 点卡额度(消耗次数),默认1 |
|
||||
| storedValueAmount | BigDecimal | 否 | 储值卡额度(消耗金额),默认0 |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "团课创建成功",
|
||||
"data": {
|
||||
"id": 2,
|
||||
"courseName": "动感单车",
|
||||
"coachId": 2,
|
||||
"courseType": 2,
|
||||
"startTime": "2026-06-05T18:00:00",
|
||||
"endTime": "2026-06-05T19:00:00",
|
||||
"maxMembers": 25,
|
||||
"currentMembers": 0,
|
||||
"status": 0,
|
||||
"location": "健身房B区",
|
||||
"coverImage": "https://example.com/spinning.jpg",
|
||||
"description": "高强度有氧运动课程",
|
||||
"pointCardAmount": 1,
|
||||
"storedValueAmount": 50.00
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应** (400 Bad Request):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "课程名称不能为空"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 更新团课
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | PUT |
|
||||
| **接口路径** | `/api/groupCourse/{id}` |
|
||||
| **所属文件** | `GroupCourseHandler.java` |
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | Long | 是 | 团课ID |
|
||||
|
||||
**请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"courseName": "动感单车升级版",
|
||||
"coachId": 2,
|
||||
"maxMembers": 30,
|
||||
"description": "升级版高强度有氧运动课程",
|
||||
"pointCardAmount": 2,
|
||||
"storedValueAmount": 80.00
|
||||
}
|
||||
```
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| courseName | String | 否 | 课程名称 |
|
||||
| coachId | Long | 否 | 教练ID |
|
||||
| courseType | Long | 否 | 课程类型 |
|
||||
| startTime | LocalDateTime | 否 | 开始时间 |
|
||||
| endTime | LocalDateTime | 否 | 结束时间 |
|
||||
| maxMembers | Integer | 否 | 最大参与人数 |
|
||||
| location | String | 否 | 上课地点 |
|
||||
| coverImage | String | 否 | 封面图URL |
|
||||
| description | String | 否 | 课程描述 |
|
||||
| pointCardAmount | Integer | 否 | 点卡额度(消耗次数) |
|
||||
| storedValueAmount | BigDecimal | 否 | 储值卡额度(消耗金额) |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "团课更新成功",
|
||||
"data": {
|
||||
"id": 2,
|
||||
"courseName": "动感单车升级版",
|
||||
"coachId": 2,
|
||||
"maxMembers": 30,
|
||||
"description": "升级版高强度有氧运动课程",
|
||||
"pointCardAmount": 2,
|
||||
"storedValueAmount": 80.00
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应** (400 Bad Request):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "团课不存在"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 取消团课
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | POST |
|
||||
| **接口路径** | `/api/groupCourse/{id}/cancel` |
|
||||
| **所属文件** | `GroupCourseHandler.java` |
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | Long | 是 | 团课ID |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "团课取消成功",
|
||||
"data": {
|
||||
"id": 2,
|
||||
"status": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应** (400 Bad Request):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "课程取消需提前24小时"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 团课签到
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | POST |
|
||||
| **接口路径** | `/api/groupCourse/{courseId}/signin` |
|
||||
| **所属文件** | `GroupCourseHandler.java` |
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| courseId | Long | 是 | 团课ID |
|
||||
|
||||
**请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"memberId": 1001
|
||||
}
|
||||
```
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| memberId | Long | **是** | 会员ID |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "签到成功",
|
||||
"data": {
|
||||
"id": 2,
|
||||
"currentMembers": 16
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应** (400 Bad Request):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "课程已满员"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 删除团课
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | DELETE |
|
||||
| **接口路径** | `/api/groupCourse/{id}` |
|
||||
| **所属文件** | `GroupCourseHandler.java` |
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| id | Long | 是 | 团课ID |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "团课删除成功"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 团课预约接口
|
||||
|
||||
### 预约团课
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | POST |
|
||||
| **接口路径** | `/api/groupCourse/book` |
|
||||
| **所属文件** | `GroupCourseBookingHandler.java` |
|
||||
|
||||
**请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"courseId": 1,
|
||||
"memberId": 1001,
|
||||
"memberCardRecordId": 5001
|
||||
}
|
||||
```
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| courseId | Long | **是** | 团课ID |
|
||||
| memberId | Long | **是** | 会员ID |
|
||||
| memberCardRecordId | Long | **是** | 会员卡记录ID |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "预约成功",
|
||||
"data": {
|
||||
"id": 100,
|
||||
"courseId": 1,
|
||||
"memberId": 1001,
|
||||
"memberCardRecordId": 5001,
|
||||
"bookingTime": "2026-06-02T08:00:00",
|
||||
"status": "0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 取消预约
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | POST |
|
||||
| **接口路径** | `/api/groupCourse/booking/{bookingId}/cancel` |
|
||||
| **所属文件** | `GroupCourseBookingHandler.java` |
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| bookingId | Long | 是 | 预约ID |
|
||||
|
||||
**请求体**:
|
||||
|
||||
```json
|
||||
{
|
||||
"memberId": 1001
|
||||
}
|
||||
```
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| memberId | Long | **是** | 会员ID |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "取消成功",
|
||||
"data": {
|
||||
"id": 100,
|
||||
"status": "1",
|
||||
"cancelTime": "2026-06-02T09:00:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 查询会员预约记录
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | GET |
|
||||
| **接口路径** | `/api/groupCourse/bookings/member/{memberId}` |
|
||||
| **所属文件** | `GroupCourseBookingHandler.java` |
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| memberId | Long | 是 | 会员ID |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 100,
|
||||
"courseId": 1,
|
||||
"courseName": "瑜伽入门",
|
||||
"memberId": 1001,
|
||||
"memberCardRecordId": 5001,
|
||||
"bookingTime": "2026-06-02T08:00:00",
|
||||
"status": "0",
|
||||
"courseStartTime": "2026-06-02T09:00:00",
|
||||
"location": "健身房A区"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 查询预约详情
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | GET |
|
||||
| **接口路径** | `/api/groupCourse/bookings/{bookingId}` |
|
||||
| **所属文件** | `GroupCourseBookingHandler.java` |
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| bookingId | Long | 是 | 预约ID |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 100,
|
||||
"courseId": 1,
|
||||
"courseName": "瑜伽入门",
|
||||
"memberId": 1001,
|
||||
"memberCardRecordId": 5001,
|
||||
"bookingTime": "2026-06-02T08:00:00",
|
||||
"status": "0",
|
||||
"courseStartTime": "2026-06-02T09:00:00",
|
||||
"courseEndTime": "2026-06-02T10:00:00",
|
||||
"location": "健身房A区"
|
||||
}
|
||||
```
|
||||
|
||||
**失败响应** (404 Not Found):
|
||||
|
||||
```json
|
||||
{}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 查询课程预约记录
|
||||
|
||||
| 属性 | 值 |
|
||||
|------|-----|
|
||||
| **HTTP方法** | GET |
|
||||
| **接口路径** | `/api/groupCourse/bookings/course/{courseId}` |
|
||||
| **所属文件** | `GroupCourseBookingHandler.java` |
|
||||
|
||||
**路径参数**:
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| courseId | Long | 是 | 团课ID |
|
||||
|
||||
**成功响应** (200 OK):
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 100,
|
||||
"courseId": 1,
|
||||
"courseName": "瑜伽入门",
|
||||
"memberId": 1001,
|
||||
"bookingTime": "2026-06-02T08:00:00",
|
||||
"status": "0"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 数据模型
|
||||
|
||||
### GroupCourse(团课)
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| id | Long | 主键ID |
|
||||
| courseName | String | 课程名称 |
|
||||
| coachId | Long | 教练ID |
|
||||
| courseType | Long | 课程类型 |
|
||||
| startTime | LocalDateTime | 开始时间 |
|
||||
| endTime | LocalDateTime | 结束时间 |
|
||||
| maxMembers | Integer | 最大参与人数 |
|
||||
| currentMembers | Integer | 当前参与人数 |
|
||||
| status | Long | 状态(0-正常,1-已取消,2-已结束) |
|
||||
| location | String | 上课地点 |
|
||||
| coverImage | String | 封面图URL |
|
||||
| description | String | 课程描述 |
|
||||
| pointCardAmount | Integer | 点卡额度(消耗次数),默认1 |
|
||||
| storedValueAmount | BigDecimal | 储值卡额度(消耗金额),默认0 |
|
||||
| createdBy | String | 创建人 |
|
||||
| updatedBy | String | 更新人 |
|
||||
| createdAt | LocalDateTime | 创建时间 |
|
||||
| updatedAt | LocalDateTime | 更新时间 |
|
||||
| deletedAt | LocalDateTime | 删除时间(软删除) |
|
||||
|
||||
### GroupCourseBooking(团课预约)
|
||||
|
||||
| 字段名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| id | Long | 主键ID |
|
||||
| courseId | Long | 团课ID |
|
||||
| courseName | String | 团课名称 |
|
||||
| memberId | Long | 会员ID |
|
||||
| memberCardRecordId | Long | 会员卡记录ID |
|
||||
| bookingTime | LocalDateTime | 预约时间 |
|
||||
| status | String | 状态(0-已预约,1-已取消,2-已出席,3-缺席) |
|
||||
| cancelTime | LocalDateTime | 取消时间 |
|
||||
| courseStartTime | LocalDateTime | 课程开始时间 |
|
||||
| courseEndTime | LocalDateTime | 课程结束时间 |
|
||||
| location | String | 上课地点 |
|
||||
| createdBy | String | 创建人 |
|
||||
| updatedBy | String | 更新人 |
|
||||
| createdAt | LocalDateTime | 创建时间 |
|
||||
| updatedAt | LocalDateTime | 更新时间 |
|
||||
| deletedAt | LocalDateTime | 删除时间(软删除) |
|
||||
|
||||
---
|
||||
|
||||
## 状态码说明
|
||||
|
||||
### 团课状态
|
||||
|
||||
| 状态码 | 含义 |
|
||||
|--------|------|
|
||||
| 0 | 正常 |
|
||||
| 1 | 已取消 |
|
||||
| 2 | 已结束 |
|
||||
|
||||
### 预约状态
|
||||
|
||||
| 状态码 | 含义 |
|
||||
|--------|------|
|
||||
| 0 | 已预约 |
|
||||
| 1 | 已取消 |
|
||||
| 2 | 已出席 |
|
||||
| 3 | 缺席 |
|
||||
|
||||
---
|
||||
|
||||
## 业务规则
|
||||
|
||||
### 团课管理
|
||||
1. **创建团课**:课程名称为必填项
|
||||
2. **取消团课**:需提前24小时通知,否则拒绝操作
|
||||
3. **团课签到**:验证课程状态必须为正常,且未达最大人数限制
|
||||
4. **删除团课**:采用软删除机制,数据保留可恢复
|
||||
|
||||
### 团课预约
|
||||
1. **预约团课**:需验证会员卡有效性和课程名额
|
||||
2. **取消预约**:需在课程开始前至少2小时取消
|
||||
|
||||
---
|
||||
|
||||
## 附录:错误响应格式
|
||||
|
||||
所有接口的错误响应统一格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "错误描述信息"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
*文档结束*
|
||||
Reference in New Issue
Block a user