diff --git a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/dao/GroupCourseDao.java b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/dao/GroupCourseDao.java index dc0f318..c2473b3 100644 --- a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/dao/GroupCourseDao.java +++ b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/dao/GroupCourseDao.java @@ -40,6 +40,10 @@ public interface GroupCourseDao extends R2dbcRepository @Query("UPDATE group_course SET deleted_at = :deletedAt WHERE id = :id") Mono softDelete(Long id, LocalDateTime deletedAt); + @Modifying + @Query("UPDATE group_course SET status = '2', updated_at = :updatedAt WHERE status = '0' AND end_time <= NOW() AND deleted_at IS NULL") + Mono completeExpiredCourses(LocalDateTime updatedAt); + Flux findByCourseTypeAndDeletedAtIsNull(Long courseType); /** @@ -49,8 +53,9 @@ public interface GroupCourseDao extends R2dbcRepository StringBuilder sql = new StringBuilder("SELECT * FROM group_course WHERE deleted_at IS NULL"); List conditions = new ArrayList<>(); - // 默认不查询不可预约的团课(仅查询 status = '0') + // 默认不查询可预约团课(status = '0' 且未过期) conditions.add("status = '0'"); + conditions.add("end_time > NOW()"); // 1. 团课名称模糊查询 if (query.getCourseName() != null && !query.getCourseName().isEmpty()) { @@ -154,7 +159,6 @@ public interface GroupCourseDao extends R2dbcRepository entity.setLocation(row.get("location", String.class)); entity.setCoverImage(row.get("cover_image", String.class)); entity.setDescription(row.get("description", String.class)); - entity.setPointCardAmount(row.get("point_card_amount", Integer.class)); entity.setStoredValueAmount(row.get("stored_value_amount", java.math.BigDecimal.class)); entity.setCreateBy(row.get("create_by", String.class)); entity.setUpdateBy(row.get("update_by", String.class)); @@ -173,6 +177,7 @@ public interface GroupCourseDao extends R2dbcRepository List conditions = new ArrayList<>(); conditions.add("status = '0'"); + conditions.add("end_time > NOW()"); if (query.getCourseName() != null && !query.getCourseName().isEmpty()) { conditions.add("course_name ILIKE :courseName"); diff --git a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/domain/GroupCourse.java b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/domain/GroupCourse.java index f059d36..2369e2d 100644 --- a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/domain/GroupCourse.java +++ b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/domain/GroupCourse.java @@ -52,10 +52,6 @@ public class GroupCourse extends BaseDomain{ @Schema(description = "课程描述", example = "从入门到入土") private String description; - //点卡额度(消耗次数) - @Schema(description = "点卡额度(消耗次数)", example = "1") - private Integer pointCardAmount; - //储值卡额度(消耗金额) @Schema(description = "储值卡额度(消耗金额)", example = "50.00") private java.math.BigDecimal storedValueAmount; @@ -152,14 +148,6 @@ public class GroupCourse extends BaseDomain{ this.description = description; } - public Integer getPointCardAmount() { - return pointCardAmount; - } - - public void setPointCardAmount(Integer pointCardAmount) { - this.pointCardAmount = pointCardAmount; - } - public java.math.BigDecimal getStoredValueAmount() { return storedValueAmount; } diff --git a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/domain/GroupCourseDetail.java b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/domain/GroupCourseDetail.java index 9ca0202..bd693c9 100644 --- a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/domain/GroupCourseDetail.java +++ b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/domain/GroupCourseDetail.java @@ -48,9 +48,6 @@ public class GroupCourseDetail extends BaseDomain { @Schema(description = "课程描述", example = "适合初学者的瑜伽课程") private String description; - @Schema(description = "点卡额度(消耗次数)", example = "1") - private Integer pointCardAmount; - @Schema(description = "储值卡额度(消耗金额)", example = "50.00") private BigDecimal storedValueAmount; @@ -174,14 +171,6 @@ public class GroupCourseDetail extends BaseDomain { this.description = description; } - public Integer getPointCardAmount() { - return pointCardAmount; - } - - public void setPointCardAmount(Integer pointCardAmount) { - this.pointCardAmount = pointCardAmount; - } - public BigDecimal getStoredValueAmount() { return storedValueAmount; } diff --git a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/entity/GroupCourseEntity.java b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/entity/GroupCourseEntity.java index 9e4d98c..5ef3fa7 100644 --- a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/entity/GroupCourseEntity.java +++ b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/entity/GroupCourseEntity.java @@ -54,10 +54,6 @@ public class GroupCourseEntity extends BaseEntity { @Column("description") private String description; - //点卡额度(消耗次数) - @Column("point_card_amount") - private Integer pointCardAmount; - //储值卡额度(消耗金额) @Column("stored_value_amount") private java.math.BigDecimal storedValueAmount; @@ -154,14 +150,6 @@ public class GroupCourseEntity extends BaseEntity { this.description = description; } - public Integer getPointCardAmount() { - return pointCardAmount; - } - - public void setPointCardAmount(Integer pointCardAmount) { - this.pointCardAmount = pointCardAmount; - } - public java.math.BigDecimal getStoredValueAmount() { return storedValueAmount; } diff --git a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/handler/BookingSagaHandler.java b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/handler/BookingSagaHandler.java index b62032d..17249b3 100644 --- a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/handler/BookingSagaHandler.java +++ b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/handler/BookingSagaHandler.java @@ -109,8 +109,8 @@ public class BookingSagaHandler { switch (cardType) { case COUNT_CARD: - // 次卡扣除次数 - return deductCardUsage(recordId, 1, 0.0); + // 次数卡不再支持团课预约 + return Mono.error(new RuntimeException("团课预约仅支持储值卡支付")); case STORED_VALUE_CARD: // 储值卡扣除金额 return deductCardUsage(recordId, 0, DEFAULT_GROUP_COURSE_PRICE); @@ -168,7 +168,8 @@ public class BookingSagaHandler { switch (cardType) { case COUNT_CARD: - return restoreCardUsage(recordId, 1, 0.0); + // 次数卡不再支持团课预约,无需恢复 + return Mono.empty(); case STORED_VALUE_CARD: return restoreCardUsage(recordId, 0, DEFAULT_GROUP_COURSE_PRICE); case TIME_CARD: diff --git a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/scheduler/GroupCourseExpireScheduler.java b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/scheduler/GroupCourseExpireScheduler.java new file mode 100644 index 0000000..da4a5f1 --- /dev/null +++ b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/scheduler/GroupCourseExpireScheduler.java @@ -0,0 +1,46 @@ +package cn.novalon.gym.manage.groupcourse.scheduler; + +import cn.novalon.gym.manage.groupcourse.dao.GroupCourseDao; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; + +/** + * 团课过期状态自动更新定时任务 + * + * 功能:定期检查已过期的团课(end_time <= NOW()),自动将 status 从 0 更新为 2(已结束) + * + * @date 2026-06-24 + */ +@Component +public class GroupCourseExpireScheduler { + + private static final Logger logger = LoggerFactory.getLogger(GroupCourseExpireScheduler.class); + + private final GroupCourseDao groupCourseDao; + + public GroupCourseExpireScheduler(GroupCourseDao groupCourseDao) { + this.groupCourseDao = groupCourseDao; + } + + /** + * 每分钟检查一次,将已过期但状态仍为 0 的团课标记为已结束(status = 2) + */ + @Scheduled(fixedRate = 60000) + public void completeExpiredCourses() { + logger.debug("定时任务开始检查已过期团课,更新状态为已结束"); + + groupCourseDao.completeExpiredCourses(LocalDateTime.now()) + .subscribe( + count -> { + if (count > 0) { + logger.info("定时任务完成,更新了 {} 条过期团课状态为已结束", count); + } + }, + error -> logger.error("过期团课状态更新定时任务执行失败:{}", error.getMessage(), error) + ); + } +} diff --git a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/service/impl/GroupCourseService.java b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/service/impl/GroupCourseService.java index 91b871d..bf1b7e0 100644 --- a/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/service/impl/GroupCourseService.java +++ b/gym-manage-api/gym-groupCourse/src/main/java/cn/novalon/gym/manage/groupcourse/service/impl/GroupCourseService.java @@ -155,7 +155,6 @@ public class GroupCourseService implements IGroupCourseService { detail.setLocation(course.getLocation()); detail.setCoverImage(course.getCoverImage()); detail.setDescription(course.getDescription()); - detail.setPointCardAmount(course.getPointCardAmount()); detail.setStoredValueAmount(course.getStoredValueAmount()); detail.setQrCodePath(course.getQrCodePath()); detail.setCreatedAt(course.getCreatedAt()); @@ -342,9 +341,6 @@ public class GroupCourseService implements IGroupCourseService { if (groupCourse.getDescription() != null) { existing.setDescription(groupCourse.getDescription()); } - if (groupCourse.getPointCardAmount() != null) { - existing.setPointCardAmount(groupCourse.getPointCardAmount()); - } if (groupCourse.getStoredValueAmount() != null) { existing.setStoredValueAmount(groupCourse.getStoredValueAmount()); } @@ -400,12 +396,11 @@ public class GroupCourseService implements IGroupCourseService { return groupCourseRepository.findByIdAndDeletedAtIsNull(courseId) .switchIfEmpty(Mono.error(new RuntimeException("课程不存在"))) .flatMap(course -> { - Integer pointCardAmount = course.getPointCardAmount() != null ? course.getPointCardAmount() : 1; Double storedValueAmount = course.getStoredValueAmount() != null ? course.getStoredValueAmount().doubleValue() : DEFAULT_GROUP_COURSE_PRICE; - logger.info("课程权益信息: courseId={}, pointCardAmount={}, storedValueAmount={}", - courseId, pointCardAmount, storedValueAmount); + logger.info("课程权益信息: courseId={}, storedValueAmount={}", + courseId, storedValueAmount); return bookingRepository.findByCourseId(courseId) .filter(booking -> "0".equals(booking.getStatus())) // 只处理已预约状态的记录 @@ -416,8 +411,8 @@ public class GroupCourseService implements IGroupCourseService { return Mono.empty(); } - // 根据会员卡类型返还权益 - return refundCardUsage(booking.getId(), memberCardRecordId, pointCardAmount, storedValueAmount) + // 根据会员卡类型返还权益(仅储值卡返还金额) + return refundCardUsage(booking.getId(), memberCardRecordId, storedValueAmount) .doOnSuccess(unused -> logger.info("会员权益返还成功: bookingId={}, memberId={}", booking.getId(), booking.getMemberId())) .doOnError(error -> logger.error("会员权益返还失败: bookingId={}, memberId={}, error={}", @@ -433,11 +428,10 @@ public class GroupCourseService implements IGroupCourseService { * * @param bookingId 预约ID * @param recordId 会员卡记录ID - * @param pointCardAmount 次卡返还次数 * @param storedValueAmount 储值卡返还金额 * @return 空Mono */ - private Mono refundCardUsage(Long bookingId, Long recordId, Integer pointCardAmount, Double storedValueAmount) { + private Mono refundCardUsage(Long bookingId, Long recordId, Double storedValueAmount) { return memberCardRecordService.findById(recordId) .switchIfEmpty(Mono.error(new RuntimeException("会员卡记录不存在"))) .flatMap(record -> { @@ -448,10 +442,9 @@ public class GroupCourseService implements IGroupCourseService { Mono refundOperation; switch (cardType) { case COUNT_CARD: - // 次卡返还次数(基于课程设置的pointCardAmount) - logger.debug("返还次卡次数: recordId={}, amount={}", recordId, pointCardAmount); - refundOperation = memberCardRecordService.renewCard(recordId, pointCardAmount, 0.0, record.getExpireTime()) - .then(Mono.empty()); + // 次卡不再支持团课预约,无需返还 + logger.debug("次卡不返还权益: bookingId={}", bookingId); + refundOperation = Mono.empty(); break; case STORED_VALUE_CARD: // 储值卡返还金额(基于课程设置的storedValueAmount) diff --git a/gym-manage-api/manage-db/src/main/resources/db/migration/V13__Consolidated_Test_Data.sql b/gym-manage-api/manage-db/src/main/resources/db/migration/V13__Consolidated_Test_Data.sql index b109d7b..e785261 100644 --- a/gym-manage-api/manage-db/src/main/resources/db/migration/V13__Consolidated_Test_Data.sql +++ b/gym-manage-api/manage-db/src/main/resources/db/migration/V13__Consolidated_Test_Data.sql @@ -151,39 +151,39 @@ INSERT INTO member_card_record (member_id, member_card_id, status, remaining_tim ((SELECT id FROM member_user WHERE member_no = 'MEM_TIME_CONFLICT'), (SELECT member_card_id FROM member_card WHERE member_card_name = '10次卡'), 'ACTIVE', 10, 0.00, '2026-12-31 23:59:59', '2026-06-16 10:00:00', 0, '{}', '2026-06-16 10:00:00', '2026-06-16 10:00:00'); -- ============================================================ --- Section G: 团课课程(来源 V7 / V10 / V11 / V12 / V14) +-- Section G: 团课课程(来源 V7 / V10 / V11 / V12 / V14,基于 2026-06-24) -- ============================================================ -- G1: V7 - 7种场景团课 -INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, cover_image, description, create_by, created_at, updated_at) VALUES -('极速燃脂单车', 104, 2, '2026-06-17 16:45:00', '2026-06-17 20:20:00', 25, 0, 0, '单车房', '/images/spinning.jpg', '跟随音乐节奏变换阻力和速度,体验爬坡与冲刺的快感。', 'admin', '2026-06-15 11:00:00', '2026-06-15 11:00:00'), -('清晨流瑜伽', 101, 1, '2026-06-20 09:00:00', '2026-06-20 10:30:00', 15, 5, 0, 'A座3楼瑜伽教室', '/images/yoga_flow.jpg', '适合有一定基础的学员,通过流畅的体式连接呼吸。', 'admin', '2026-06-15 10:00:00', '2026-06-15 10:00:00'), -('燃脂搏击', 102, 2, '2026-06-18 18:30:00', '2026-06-18 19:30:00', 20, 20, 0, '综合训练区', '/images/kickboxing.jpg', '高强度间歇训练,名额已满。', 'coach_zhang', '2026-06-15 14:30:00', '2026-06-15 14:30:00'), -('哈他瑜伽', 101, 1, '2026-06-16 17:45:00', '2026-06-16 18:50:00', 12, 3, 0, '瑜伽教室B', '/images/hatha_yoga.jpg', '基础哈他瑜伽,距开始不足30分钟,已停止预约。', 'coach_li', '2026-06-16 08:00:00', '2026-06-16 08:00:00'), -('周末冥想修复', 101, 1, '2026-06-28 15:00:00', '2026-06-28 16:00:00', 12, 3, 1, '冥想室', '/images/meditation.jpg', '通过呼吸和正念冥想,该课程已被取消。', 'coach_wang', '2026-06-10 08:00:00', '2026-06-10 08:00:00'), -('蜜桃臀塑造', 103, 3, '2026-06-10 19:00:00', '2026-06-10 20:00:00', 10, 8, 2, '私教专区', '/images/glute.jpg', '针对性训练臀部肌肉群,课程已结束。', 'coach_li', '2026-05-30 09:15:00', '2026-05-30 09:15:00'), -('午间冥想放松', 101, 1, '2026-06-12 12:00:00', '2026-06-12 13:00:00', 15, 6, 2, '冥想室', '/images/meditation_noon.jpg', '午间冥想课程,已结束。', 'admin', '2026-06-05 09:00:00', '2026-06-05 09:00:00'); +INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, cover_image, description, stored_value_amount, create_by, created_at, updated_at) VALUES +('极速燃脂单车', 104, 2, '2026-06-25 16:45:00', '2026-06-25 20:20:00', 25, 0, 0, '单车房', '/images/spinning.jpg', '跟随音乐节奏变换阻力和速度,体验爬坡与冲刺的快感。', 50.00, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'), +('清晨流瑜伽', 101, 1, '2026-06-28 09:00:00', '2026-06-28 10:30:00', 15, 5, 0, 'A座3楼瑜伽教室', '/images/yoga_flow.jpg', '适合有一定基础的学员,通过流畅的体式连接呼吸。', 50.00, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'), +('燃脂搏击', 102, 2, '2026-06-26 18:30:00', '2026-06-26 19:30:00', 20, 20, 0, '综合训练区', '/images/kickboxing.jpg', '高强度间歇训练,名额已满。', 50.00, 'coach_zhang', '2026-06-24 14:30:00', '2026-06-24 14:30:00'), +('哈他瑜伽', 101, 1, '2026-06-24 17:45:00', '2026-06-24 18:50:00', 12, 3, 0, '瑜伽教室B', '/images/hatha_yoga.jpg', '基础哈他瑜伽,距开始不足30分钟,已停止预约。', 50.00, 'coach_li', '2026-06-24 08:00:00', '2026-06-24 08:00:00'), +('周末冥想修复', 101, 1, '2026-07-06 15:00:00', '2026-07-06 16:00:00', 12, 3, 1, '冥想室', '/images/meditation.jpg', '通过呼吸和正念冥想,该课程已被取消。', 50.00, 'coach_wang', '2026-06-24 08:00:00', '2026-06-24 08:00:00'), +('蜜桃臀塑造', 103, 3, '2026-06-18 19:00:00', '2026-06-18 20:00:00', 10, 8, 2, '私教专区', '/images/glute.jpg', '针对性训练臀部肌肉群,课程已结束。', 50.00, 'coach_li', '2026-06-18 09:15:00', '2026-06-18 09:15:00'), +('午间冥想放松', 101, 1, '2026-06-20 12:00:00', '2026-06-20 13:00:00', 15, 6, 2, '冥想室', '/images/meditation_noon.jpg', '午间冥想课程,已结束。', 50.00, 'admin', '2026-06-20 09:00:00', '2026-06-20 09:00:00'); --- G2: V10 预约场景 -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-18 19:30:00', '2026-06-18 20:30:00', 20, 0, 0, '综合训练区', '消耗1次', 1, 0.00, 'admin', '2026-06-15 10:00:00', '2026-06-15 10:00:00'), -('高端普拉提_储值卡课程', 103, 1, '2026-06-19 19:00:00', '2026-06-19 20:00:00', 15, 0, 0, '普拉提教室', '消耗储值20元', 0, 20.00, 'admin', '2026-06-15 10:00:00', '2026-06-15 10:00:00'); +-- G2: V10 预约场景(已取消次数卡支付,仅保留储值卡) +INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, stored_value_amount, create_by, created_at, updated_at) VALUES +('燃脂搏击_储值测试', 102, 2, '2026-06-26 19:30:00', '2026-06-26 20:30:00', 20, 0, 0, '综合训练区', '消耗储值50元', 50.00, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'), +('高端普拉提_储值卡课程', 103, 1, '2026-06-27 19:00:00', '2026-06-27 20:00:00', 15, 0, 0, '普拉提教室', '消耗储值20元', 20.00, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'); -- G3: V11 取消预约场景 -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 -('晚间瑜伽_取消测试', 101, 1, '2026-06-19 19:00:00', '2026-06-19 20:00:00', 20, 0, 0, '瑜伽教室', '用于测试取消预约功能', 1, 30.00, 'admin', '2026-06-15 10:00:00', '2026-06-15 10:00:00'); +INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, stored_value_amount, create_by, created_at, updated_at) VALUES +('晚间瑜伽_取消测试', 101, 1, '2026-06-27 19:00:00', '2026-06-27 20:00:00', 20, 0, 0, '瑜伽教室', '用于测试取消预约功能', 30.00, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'); -- G4: V12 时间冲突场景 -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 -('时间冲突测试_A_13点-15点', 102, 2, '2026-06-18 13:00:00', '2026-06-18 15:00:00', 20, 0, 0, '综合训练区', '测试用团课A', 1, 0.00, 'admin', '2026-06-15 10:00:00', '2026-06-15 10:00:00'), -('时间冲突测试_B_14点-16点', 103, 1, '2026-06-18 14:00:00', '2026-06-18 16:00:00', 15, 0, 0, '普拉提教室', '与团课A时间重叠', 1, 0.00, 'admin', '2026-06-15 10:00:00', '2026-06-15 10:00:00'), -('时间冲突测试_C_10点-12点', 101, 1, '2026-06-18 10:00:00', '2026-06-18 12:00:00', 15, 0, 0, '瑜伽教室', '与A/B不冲突', 1, 0.00, 'admin', '2026-06-15 10:00:00', '2026-06-15 10:00:00'); +INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, stored_value_amount, create_by, created_at, updated_at) VALUES +('时间冲突测试_A_13点-15点', 102, 2, '2026-06-26 13:00:00', '2026-06-26 15:00:00', 20, 0, 0, '综合训练区', '测试用团课A', 50.00, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'), +('时间冲突测试_B_14点-16点', 103, 1, '2026-06-26 14:00:00', '2026-06-26 16:00:00', 15, 0, 0, '普拉提教室', '与团课A时间重叠', 50.00, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'), +('时间冲突测试_C_10点-12点', 101, 1, '2026-06-26 10:00:00', '2026-06-26 12:00:00', 15, 0, 0, '瑜伽教室', '与A/B不冲突', 50.00, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'); --- G5: V14 数据统计场景(今天) -INSERT INTO group_course (id, course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, cover_image, description, created_at, updated_at) VALUES -(3001, '瑜伽入门', 1, 1, '2026-06-16 08:00:00', '2026-06-16 09:00:00', 20, 15, 0, '健身房A区', 'https://example.com/yoga.jpg', '适合初学者的瑜伽课程', '2026-06-15 10:00:00', '2026-06-15 10:00:00'), -(3002, '动感单车', 2, 2, '2026-06-16 09:30:00', '2026-06-16 10:30:00', 25, 20, 0, '健身房B区', 'https://example.com/spinning.jpg', '高强度有氧运动', '2026-06-15 11:00:00', '2026-06-15 11:00:00'), -(3003, '普拉提', 3, 1, '2026-06-16 14:00:00', '2026-06-16 15:00:00', 15, 10, 0, '健身房C区', 'https://example.com/pilates.jpg', '核心力量训练', '2026-06-15 12:00:00', '2026-06-15 12:00:00'); +-- G5: V14 数据统计场景(今天 2026-06-24) +INSERT INTO group_course (id, course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, cover_image, description, stored_value_amount, created_at, updated_at) VALUES +(3001, '瑜伽入门', 1, 1, '2026-06-24 08:00:00', '2026-06-24 09:00:00', 20, 15, 0, '健身房A区', 'https://example.com/yoga.jpg', '适合初学者的瑜伽课程', 50.00, '2026-06-24 10:00:00', '2026-06-24 10:00:00'), +(3002, '动感单车', 2, 2, '2026-06-24 09:30:00', '2026-06-24 10:30:00', 25, 20, 0, '健身房B区', 'https://example.com/spinning.jpg', '高强度有氧运动', 50.00, '2026-06-24 11:00:00', '2026-06-24 11:00:00'), +(3003, '普拉提', 3, 1, '2026-06-24 14:00:00', '2026-06-24 15:00:00', 15, 10, 0, '健身房C区', 'https://example.com/pilates.jpg', '核心力量训练', 50.00, '2026-06-24 12:00:00', '2026-06-24 12:00:00'); -- ============================================================ -- Section H: 团课预约记录 @@ -191,116 +191,116 @@ INSERT INTO group_course (id, course_name, coach_id, course_type, start_time, en -- H1: V11 取消预约测试 INSERT INTO group_course_booking (course_id, member_id, member_card_id, booking_time, status, course_name, course_start_time, course_end_time, location, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '晚间瑜伽_取消测试'), (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_ZHANG'), (SELECT id FROM member_card_record WHERE member_id = (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_ZHANG')), '2026-06-16 11:00:00', '0', '晚间瑜伽_取消测试', '2026-06-19 19:00:00', '2026-06-19 20:00:00', '瑜伽教室', '2026-06-16 11:00:00', '2026-06-16 11:00:00'), -((SELECT id FROM group_course WHERE course_name = '晚间瑜伽_取消测试'), (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_LI'), (SELECT id FROM member_card_record WHERE member_id = (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_LI')), '2026-06-16 11:30:00', '0', '晚间瑜伽_取消测试', '2026-06-19 19:00:00', '2026-06-19 20:00:00', '瑜伽教室', '2026-06-16 11:30:00', '2026-06-16 11:30:00'), -((SELECT id FROM group_course WHERE course_name = '晚间瑜伽_取消测试'), (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_WANG'), (SELECT id FROM member_card_record WHERE member_id = (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_WANG')), '2026-06-16 12:00:00', '0', '晚间瑜伽_取消测试', '2026-06-19 19:00:00', '2026-06-19 20:00:00', '瑜伽教室', '2026-06-16 12:00:00', '2026-06-16 12:00:00'); +((SELECT id FROM group_course WHERE course_name = '晚间瑜伽_取消测试'), (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_ZHANG'), (SELECT id FROM member_card_record WHERE member_id = (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_ZHANG')), '2026-06-24 11:00:00', '0', '晚间瑜伽_取消测试', '2026-06-27 19:00:00', '2026-06-27 20:00:00', '瑜伽教室', '2026-06-24 11:00:00', '2026-06-24 11:00:00'), +((SELECT id FROM group_course WHERE course_name = '晚间瑜伽_取消测试'), (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_LI'), (SELECT id FROM member_card_record WHERE member_id = (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_LI')), '2026-06-24 11:30:00', '0', '晚间瑜伽_取消测试', '2026-06-27 19:00:00', '2026-06-27 20:00:00', '瑜伽教室', '2026-06-24 11:30:00', '2026-06-24 11:30:00'), +((SELECT id FROM group_course WHERE course_name = '晚间瑜伽_取消测试'), (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_WANG'), (SELECT id FROM member_card_record WHERE member_id = (SELECT id FROM member_user WHERE member_no = 'MEM_TEST_WANG')), '2026-06-24 12:00:00', '0', '晚间瑜伽_取消测试', '2026-06-27 19:00:00', '2026-06-27 20:00:00', '瑜伽教室', '2026-06-24 12:00:00', '2026-06-24 12:00:00'); UPDATE group_course SET current_members = current_members + 3 WHERE course_name = '晚间瑜伽_取消测试'; --- H2: V14 数据统计预约 - 今天(6月16日) +-- H2: V14 数据统计预约 - 今天(6月24日) INSERT INTO group_course_booking (id, member_id, member_card_id, course_id, booking_time, status, created_at, updated_at) VALUES -(4001, 1001, 1, 3001, '2026-06-16 08:00:00', '2', '2026-06-15 20:00:00', '2026-06-16 08:30:00'), -(4002, 1002, 2, 3001, '2026-06-16 08:00:00', '2', '2026-06-15 21:00:00', '2026-06-16 08:30:00'), -(4003, 1003, 3, 3001, '2026-06-16 08:00:00', '3', '2026-06-15 22:00:00', '2026-06-16 09:00:00'), -(4004, 1004, 4, 3002, '2026-06-16 09:30:00', '2', '2026-06-15 19:00:00', '2026-06-16 09:30:00'), -(4005, 1005, 5, 3002, '2026-06-16 09:30:00', '1', '2026-06-15 20:30:00', '2026-06-16 09:00:00'), -(4006, 1006, 6, 3002, '2026-06-16 09:30:00', '2', '2026-06-15 21:30:00', '2026-06-16 09:30:00'), -(4007, 1007, 7, 3003, '2026-06-16 14:00:00', '2', '2026-06-15 22:30:00', '2026-06-16 14:00:00'), -(4008, 1008, 8, 3003, '2026-06-16 14:00:00', '3', '2026-06-16 08:00:00', '2026-06-16 14:00:00'), -(4009, 1009, 9, 3003, '2026-06-16 14:00:00', '2', '2026-06-16 09:00:00', '2026-06-16 14:00:00'), -(4010, 1010, 10, 3001, '2026-06-16 08:00:00', '2', '2026-06-16 07:00:00', '2026-06-16 08:00:00'), -(4011, 1011, 11, 3002, '2026-06-16 09:30:00', '1', '2026-06-16 08:30:00', '2026-06-16 09:00:00'), -(4012, 1012, 12, 3003, '2026-06-16 14:00:00', '2', '2026-06-16 10:00:00', '2026-06-16 14:00:00'); +(4001, 1001, 1, 3001, '2026-06-24 08:00:00', '2', '2026-06-23 20:00:00', '2026-06-24 08:30:00'), +(4002, 1002, 2, 3001, '2026-06-24 08:00:00', '2', '2026-06-23 21:00:00', '2026-06-24 08:30:00'), +(4003, 1003, 3, 3001, '2026-06-24 08:00:00', '3', '2026-06-23 22:00:00', '2026-06-24 09:00:00'), +(4004, 1004, 4, 3002, '2026-06-24 09:30:00', '2', '2026-06-23 19:00:00', '2026-06-24 09:30:00'), +(4005, 1005, 5, 3002, '2026-06-24 09:30:00', '1', '2026-06-23 20:30:00', '2026-06-24 09:00:00'), +(4006, 1006, 6, 3002, '2026-06-24 09:30:00', '2', '2026-06-23 21:30:00', '2026-06-24 09:30:00'), +(4007, 1007, 7, 3003, '2026-06-24 14:00:00', '2', '2026-06-23 22:30:00', '2026-06-24 14:00:00'), +(4008, 1008, 8, 3003, '2026-06-24 14:00:00', '3', '2026-06-24 08:00:00', '2026-06-24 14:00:00'), +(4009, 1009, 9, 3003, '2026-06-24 14:00:00', '2', '2026-06-24 09:00:00', '2026-06-24 14:00:00'), +(4010, 1010, 10, 3001, '2026-06-24 08:00:00', '2', '2026-06-24 07:00:00', '2026-06-24 08:00:00'), +(4011, 1011, 11, 3002, '2026-06-24 09:30:00', '1', '2026-06-24 08:30:00', '2026-06-24 09:00:00'), +(4012, 1012, 12, 3003, '2026-06-24 14:00:00', '2', '2026-06-24 10:00:00', '2026-06-24 14:00:00'); --- H3: V14 数据统计预约 - 昨天(6月15日) +-- H3: V14 数据统计预约 - 昨天(6月23日) INSERT INTO group_course_booking (id, member_id, member_card_id, course_id, booking_time, status, created_at, updated_at) VALUES -(4013, 1001, 1, 3001, '2026-06-15 08:00:00', '2', '2026-06-14 20:00:00', '2026-06-15 08:30:00'), -(4014, 1002, 2, 3001, '2026-06-15 08:00:00', '2', '2026-06-14 21:00:00', '2026-06-15 08:30:00'), -(4015, 1003, 3, 3002, '2026-06-15 09:30:00', '3', '2026-06-14 22:00:00', '2026-06-15 09:30:00'), -(4016, 1004, 4, 3002, '2026-06-15 09:30:00', '2', '2026-06-14 19:00:00', '2026-06-15 09:30:00'), -(4017, 1005, 5, 3003, '2026-06-15 14:00:00', '1', '2026-06-14 20:30:00', '2026-06-15 13:00:00'), -(4018, 1006, 6, 3003, '2026-06-15 14:00:00', '2', '2026-06-14 21:30:00', '2026-06-15 14:00:00'); +(4013, 1001, 1, 3001, '2026-06-23 08:00:00', '2', '2026-06-22 20:00:00', '2026-06-23 08:30:00'), +(4014, 1002, 2, 3001, '2026-06-23 08:00:00', '2', '2026-06-22 21:00:00', '2026-06-23 08:30:00'), +(4015, 1003, 3, 3002, '2026-06-23 09:30:00', '3', '2026-06-22 22:00:00', '2026-06-23 09:30:00'), +(4016, 1004, 4, 3002, '2026-06-23 09:30:00', '2', '2026-06-22 19:00:00', '2026-06-23 09:30:00'), +(4017, 1005, 5, 3003, '2026-06-23 14:00:00', '1', '2026-06-22 20:30:00', '2026-06-23 13:00:00'), +(4018, 1006, 6, 3003, '2026-06-23 14:00:00', '2', '2026-06-22 21:30:00', '2026-06-23 14:00:00'); --- H4: V14 数据统计预约 - 前天(6月14日) +-- H4: V14 数据统计预约 - 前天(6月22日) INSERT INTO group_course_booking (id, member_id, member_card_id, course_id, booking_time, status, created_at, updated_at) VALUES -(4019, 1001, 1, 3002, '2026-06-14 09:30:00', '2', '2026-06-13 20:00:00', '2026-06-14 09:30:00'), -(4020, 1002, 2, 3002, '2026-06-14 09:30:00', '2', '2026-06-13 21:00:00', '2026-06-14 09:30:00'), -(4021, 1003, 3, 3003, '2026-06-14 14:00:00', '2', '2026-06-13 22:00:00', '2026-06-14 14:00:00'), -(4022, 1004, 4, 3003, '2026-06-14 14:00:00', '3', '2026-06-13 19:00:00', '2026-06-14 14:00:00'); +(4019, 1001, 1, 3002, '2026-06-22 09:30:00', '2', '2026-06-21 20:00:00', '2026-06-22 09:30:00'), +(4020, 1002, 2, 3002, '2026-06-22 09:30:00', '2', '2026-06-21 21:00:00', '2026-06-22 09:30:00'), +(4021, 1003, 3, 3003, '2026-06-22 14:00:00', '2', '2026-06-21 22:00:00', '2026-06-22 14:00:00'), +(4022, 1004, 4, 3003, '2026-06-22 14:00:00', '3', '2026-06-21 19:00:00', '2026-06-22 14:00:00'); -- ============================================================ --- Section I: 签到记录(来源 V14,基于 2026-06-16) +-- Section I: 签到记录(来源 V14,基于 2026-06-24) -- ============================================================ INSERT INTO sign_in_record (id, member_id, sign_in_time, sign_in_type, sign_in_status, source, is_delete) VALUES -(2001, 1001, '2026-06-16 08:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2002, 1002, '2026-06-16 08:15:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), -(2003, 1003, '2026-06-16 08:30:00', 'FACE', 'SUCCESS', 'MINI_PROGRAM', false), -(2004, 1004, '2026-06-16 09:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2005, 1005, '2026-06-16 09:15:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), -(2006, 1006, '2026-06-16 09:30:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2007, 1007, '2026-06-16 10:00:00', 'FACE', 'SUCCESS', 'MINI_PROGRAM', false), -(2008, 1008, '2026-06-16 10:15:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2009, 1009, '2026-06-16 10:30:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), -(2010, 1010, '2026-06-16 11:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2011, 1011, '2026-06-16 11:15:00', 'FACE', 'FAIL', 'MINI_PROGRAM', false), -(2012, 1012, '2026-06-16 11:30:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false); +(2001, 1001, '2026-06-24 08:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2002, 1002, '2026-06-24 08:15:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), +(2003, 1003, '2026-06-24 08:30:00', 'FACE', 'SUCCESS', 'MINI_PROGRAM', false), +(2004, 1004, '2026-06-24 09:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2005, 1005, '2026-06-24 09:15:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), +(2006, 1006, '2026-06-24 09:30:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2007, 1007, '2026-06-24 10:00:00', 'FACE', 'SUCCESS', 'MINI_PROGRAM', false), +(2008, 1008, '2026-06-24 10:15:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2009, 1009, '2026-06-24 10:30:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), +(2010, 1010, '2026-06-24 11:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2011, 1011, '2026-06-24 11:15:00', 'FACE', 'FAIL', 'MINI_PROGRAM', false), +(2012, 1012, '2026-06-24 11:30:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false); INSERT INTO sign_in_record (id, member_id, sign_in_time, sign_in_type, sign_in_status, source, is_delete) VALUES -(2013, 1001, '2026-06-15 07:30:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2014, 1002, '2026-06-15 08:00:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), -(2015, 1003, '2026-06-15 08:30:00', 'FACE', 'SUCCESS', 'MINI_PROGRAM', false), -(2016, 1004, '2026-06-15 09:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2017, 1005, '2026-06-15 09:30:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), -(2018, 1006, '2026-06-15 10:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2019, 1007, '2026-06-15 10:30:00', 'FACE', 'SUCCESS', 'MINI_PROGRAM', false), -(2020, 1008, '2026-06-15 11:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false); +(2013, 1001, '2026-06-23 07:30:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2014, 1002, '2026-06-23 08:00:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), +(2015, 1003, '2026-06-23 08:30:00', 'FACE', 'SUCCESS', 'MINI_PROGRAM', false), +(2016, 1004, '2026-06-23 09:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2017, 1005, '2026-06-23 09:30:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), +(2018, 1006, '2026-06-23 10:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2019, 1007, '2026-06-23 10:30:00', 'FACE', 'SUCCESS', 'MINI_PROGRAM', false), +(2020, 1008, '2026-06-23 11:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false); INSERT INTO sign_in_record (id, member_id, sign_in_time, sign_in_type, sign_in_status, source, is_delete) VALUES -(2021, 1001, '2026-06-14 07:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2022, 1002, '2026-06-14 07:30:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), -(2023, 1003, '2026-06-14 08:00:00', 'FACE', 'FAIL', 'MINI_PROGRAM', false), -(2024, 1004, '2026-06-14 08:30:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), -(2025, 1005, '2026-06-14 09:00:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false); +(2021, 1001, '2026-06-22 07:00:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2022, 1002, '2026-06-22 07:30:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false), +(2023, 1003, '2026-06-22 08:00:00', 'FACE', 'FAIL', 'MINI_PROGRAM', false), +(2024, 1004, '2026-06-22 08:30:00', 'QR_CODE', 'SUCCESS', 'MINI_PROGRAM', false), +(2025, 1005, '2026-06-22 09:00:00', 'MANUAL', 'SUCCESS', 'PC_BACKEND', false); -- ============================================================ --- Section J: 团课推荐测试数据(来源 V18,基于 2026-06-16) +-- Section J: 团课推荐测试数据(来源 V18,基于 2026-06-24) -- ============================================================ INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '极速燃脂单车'), '本周热门推荐', '极速燃脂单车课程,跟随音乐节奏变换阻力和速度,体验爬坡与冲刺的快感,一节课消耗800大卡!', '教练专业,课程内容丰富,深受学员喜爱,燃脂效果显著', 20, true, 'admin', '2026-06-16 10:00:00', '2026-06-16 10:00:00'); +((SELECT id FROM group_course WHERE course_name = '极速燃脂单车'), '本周热门推荐', '极速燃脂单车课程,跟随音乐节奏变换阻力和速度,体验爬坡与冲刺的快感,一节课消耗800大卡!', '教练专业,课程内容丰富,深受学员喜爱,燃脂效果显著', 20, true, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'); INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '清晨流瑜伽'), '新手友好推荐', '清晨流瑜伽课程,适合有一定基础的学员,通过流畅的体式连接呼吸,唤醒身体能量。', '适合新手入门,教练耐心指导,课程节奏适中', 15, true, 'admin', '2026-06-16 11:00:00', '2026-06-16 11:00:00'); +((SELECT id FROM group_course WHERE course_name = '清晨流瑜伽'), '新手友好推荐', '清晨流瑜伽课程,适合有一定基础的学员,通过流畅的体式连接呼吸,唤醒身体能量。', '适合新手入门,教练耐心指导,课程节奏适中', 15, true, 'admin', '2026-06-24 11:00:00', '2026-06-24 11:00:00'); INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '燃脂搏击'), '高强度燃脂', '燃脂搏击课程,高强度间歇训练,配合音乐快速燃脂,释放压力。', '高强度训练,适合进阶学员,快速燃脂塑形', 10, false, 'admin', '2026-06-16 12:00:00', '2026-06-16 12:00:00'); +((SELECT id FROM group_course WHERE course_name = '燃脂搏击'), '高强度燃脂', '燃脂搏击课程,高强度间歇训练,配合音乐快速燃脂,释放压力。', '高强度训练,适合进阶学员,快速燃脂塑形', 10, false, 'admin', '2026-06-24 12:00:00', '2026-06-24 12:00:00'); INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '哈他瑜伽'), '基础瑜伽推荐', '基础哈他瑜伽课程,适合所有级别学员,通过基础体式练习提升身体柔韧性和平衡能力。', '零基础友好,适合所有健身水平,放松身心', 12, true, 'coach_li', '2026-06-16 13:00:00', '2026-06-16 13:00:00'); +((SELECT id FROM group_course WHERE course_name = '哈他瑜伽'), '基础瑜伽推荐', '基础哈他瑜伽课程,适合所有级别学员,通过基础体式练习提升身体柔韧性和平衡能力。', '零基础友好,适合所有健身水平,放松身心', 12, true, 'coach_li', '2026-06-24 13:00:00', '2026-06-24 13:00:00'); INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '蜜桃臀塑造'), '塑形热门课程', '蜜桃臀塑造课程,针对性训练臀部肌肉群,打造完美曲线。', '专业私教指导,动作标准,效果显著,深受女性学员喜爱', 18, true, 'coach_li', '2026-06-10 09:15:00', '2026-06-10 09:15:00'); +((SELECT id FROM group_course WHERE course_name = '蜜桃臀塑造'), '塑形热门课程', '蜜桃臀塑造课程,针对性训练臀部肌肉群,打造完美曲线。', '专业私教指导,动作标准,效果显著,深受女性学员喜爱', 18, true, 'coach_li', '2026-06-24 09:15:00', '2026-06-24 09:15:00'); INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '午间冥想放松'), '午间放松推荐', '午间冥想放松课程,通过呼吸和正念冥想,深度放松身心,缓解工作压力。', '适合上班族,午间放松充电,提升下午工作效率', 8, true, 'admin', '2026-06-12 09:00:00', '2026-06-12 09:00:00'); +((SELECT id FROM group_course WHERE course_name = '午间冥想放松'), '午间放松推荐', '午间冥想放松课程,通过呼吸和正念冥想,深度放松身心,缓解工作压力。', '适合上班族,午间放松充电,提升下午工作效率', 8, true, 'admin', '2026-06-24 09:00:00', '2026-06-24 09:00:00'); INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '极速燃脂单车'), '减脂首选课程', '想要快速减脂?极速燃脂单车是你的最佳选择!专业教练带领,科学训练计划。', '减脂效果最佳,课程强度适中,适合想要快速瘦身的学员', 16, true, 'coach_zhang', '2026-06-16 14:00:00', '2026-06-16 14:00:00'); +((SELECT id FROM group_course WHERE course_name = '极速燃脂单车'), '减脂首选课程', '想要快速减脂?极速燃脂单车是你的最佳选择!专业教练带领,科学训练计划。', '减脂效果最佳,课程强度适中,适合想要快速瘦身的学员', 16, true, 'coach_zhang', '2026-06-24 14:00:00', '2026-06-24 14:00:00'); INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '清晨流瑜伽'), '晨练优选', '清晨流瑜伽,唤醒身体能量,开启活力一天!适合晨练爱好者。', '晨练最佳选择,提升身体活力,改善精神状态', 14, true, 'coach_wang', '2026-06-16 15:00:00', '2026-06-16 15:00:00'); +((SELECT id FROM group_course WHERE course_name = '清晨流瑜伽'), '晨练优选', '清晨流瑜伽,唤醒身体能量,开启活力一天!适合晨练爱好者。', '晨练最佳选择,提升身体活力,改善精神状态', 14, true, 'coach_wang', '2026-06-24 15:00:00', '2026-06-24 15:00:00'); INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '哈他瑜伽'), '身心平衡推荐', '哈他瑜伽课程,通过体式练习和呼吸控制,达到身心平衡,提升整体健康水平。', '改善身体柔韧性,增强核心力量,提升身体协调性', 11, true, 'coach_li', '2026-06-16 16:00:00', '2026-06-16 16:00:00'); +((SELECT id FROM group_course WHERE course_name = '哈他瑜伽'), '身心平衡推荐', '哈他瑜伽课程,通过体式练习和呼吸控制,达到身心平衡,提升整体健康水平。', '改善身体柔韧性,增强核心力量,提升身体协调性', 11, true, 'coach_li', '2026-06-24 16:00:00', '2026-06-24 16:00:00'); INSERT INTO group_course_recommend (course_id, recommend_title, recommend_content, recommend_reason, priority, is_active, create_by, created_at, updated_at) VALUES -((SELECT id FROM group_course WHERE course_name = '午间冥想放松'), '职场减压课程', '午间冥想放松,专为职场人士设计,快速缓解工作压力,提升工作状态。', '职场减压首选,课程时间短,效果显著', 9, false, 'admin', '2026-06-12 10:00:00', '2026-06-12 10:00:00'); +((SELECT id FROM group_course WHERE course_name = '午间冥想放松'), '职场减压课程', '午间冥想放松,专为职场人士设计,快速缓解工作压力,提升工作状态。', '职场减压首选,课程时间短,效果显著', 9, false, 'admin', '2026-06-24 10:00:00', '2026-06-24 10:00:00'); -- ============================================================ -- Section K: 统计说明 -- ============================================================ --- 今日(2026-06-16)统计预期: +-- 今日(2026-06-24)统计预期: -- 新增会员: 3 (1005, 1006, 1007) -- 签到会员: 12 -- 预约总数: 12 (4001-4012),取消: 2,出席: 8,缺席: 2 @@ -310,33 +310,33 @@ INSERT INTO group_course_recommend (course_id, recommend_title, recommend_conten -- Section L: 测试场景汇总 -- ============================================================ -- 1. V7 团课预约场景: --- - 极速燃脂单车: 明天,0人,可预约 --- - 清晨流瑜伽: 6月20日,5/15人,可预约 --- - 燃脂搏击: 6月18日,满员,不可预约 --- - 哈他瑜伽: 今天17:45,距开始<30min,不可预约 --- - 周末冥想修复: 6月28日,已取消(status=1) --- - 蜜桃臀塑造: 6月10日,已结束(status=2) --- - 午间冥想放松: 6月12日,已结束(status=2) +-- - 极速燃脂单车: 明天(6/25),0人,可预约 +-- - 清晨流瑜伽: 6月28日,5/15人,可预约 +-- - 燃脂搏击: 6月26日,满员,不可预约 +-- - 哈他瑜伽: 6/24 17:45,距开始<30min,不可预约 +-- - 周末冥想修复: 7月6日,已取消(status=1) +-- - 蜜桃臀塑造: 6月18日,已结束(status=2) +-- - 午间冥想放松: 6月20日,已结束(status=2) -- -- 2. V10 会员卡预约资格校验: -- - 用户A: 无会员卡 → "无可用会员卡" -- - 用户B: 时长卡过期 → "会员卡已过期" -- - 会员C: 时长卡有效 → 可正常预约 -- - 会员D: 次数为0 → "剩余次数不足" --- - 会员E: 次数充足 → 可正常预约 --- - 会员F: 储值卡30元,课程需20元 → 可正常预约 --- - 会员G: 储值卡200元,课程需20元 → 可正常预约 +-- - 会员E: 次数充足 → 不可用次数卡预约团课(仅支持储值卡) +-- - 会员F: 储值卡30元,课程需50元 → 余额不足 +-- - 会员G: 储值卡200元,课程需50元 → 可正常预约 -- -- 3. V11 取消预约: --- - 张三(时长卡)、李四(次数卡)、王五(储值卡) 预约了晚间瑜伽_取消测试 +-- - 张三(时长卡)、李四(储值卡)、王五(储值卡) 预约了晚间瑜伽_取消测试 -- - 取消后应恢复对应卡状态,释放课程名额 -- -- 4. V12 时间冲突检测: --- - 团课A: 6/18 13:00-15:00, 团课B: 6/18 14:00-16:00 → 时间重叠 --- - 团课C: 6/18 10:00-12:00 → 与A/B不冲突 +-- - 团课A: 6/26 13:00-15:00, 团课B: 6/26 14:00-16:00 → 时间重叠 +-- - 团课C: 6/26 10:00-12:00 → 与A/B不冲突 -- -- 5. V14 数据统计: --- - 3天签到/预约数据,覆盖今日/昨日/前日 +-- - 3天签到/预约数据,覆盖今天/昨天/前天 -- -- 6. V18 团课推荐: -- - 10条推荐记录,覆盖不同优先级和启用状态 diff --git a/gym-manage-api/manage-db/src/main/resources/db/migration/V23__Add_Coach_Test_Data.sql b/gym-manage-api/manage-db/src/main/resources/db/migration/V23__Add_Coach_Test_Data.sql index fa0167c..48bd01a 100644 --- a/gym-manage-api/manage-db/src/main/resources/db/migration/V23__Add_Coach_Test_Data.sql +++ b/gym-manage-api/manage-db/src/main/resources/db/migration/V23__Add_Coach_Test_Data.sql @@ -58,32 +58,32 @@ AND NOT EXISTS ( -- ============================================================ -- 6. 为教练分配今天的测试团课 -- ============================================================ -INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, point_card_amount, create_by, created_at, updated_at) +INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, stored_value_amount, create_by, created_at, updated_at) VALUES ('核心力量训练', 20, (SELECT id FROM group_course_type WHERE type_name = '核心训练' LIMIT 1), - CURRENT_DATE + TIME '08:00', CURRENT_DATE + TIME '09:00', 15, 3, '0', '健身房B区', '针对核心肌群的专项训练,适合所有水平学员', 1, 'system', NOW(), NOW()), + CURRENT_DATE + TIME '08:00', CURRENT_DATE + TIME '09:00', 15, 3, '0', '健身房B区', '针对核心肌群的专项训练,适合所有水平学员', 50.00, 'system', NOW(), NOW()), ('瑜伽入门', 20, (SELECT id FROM group_course_type WHERE type_name = '瑜伽入门' LIMIT 1), - CURRENT_DATE + TIME '10:00', CURRENT_DATE + TIME '11:00', 12, 5, '0', '瑜伽教室', '基础的瑜伽体式教学,新课上线欢迎参加', 1, 'system', NOW(), NOW()), + CURRENT_DATE + TIME '10:00', CURRENT_DATE + TIME '11:00', 12, 5, '0', '瑜伽教室', '基础的瑜伽体式教学,新课上线欢迎参加', 50.00, 'system', NOW(), NOW()), ('动感单车', 20, (SELECT id FROM group_course_type WHERE type_name = '动感单车' LIMIT 1), - CURRENT_DATE + TIME '14:00', CURRENT_DATE + TIME '15:00', 20, 8, '0', '单车房', '高强度燃脂骑行,动感音乐带你飞', 2, 'system', NOW(), NOW()), + CURRENT_DATE + TIME '14:00', CURRENT_DATE + TIME '15:00', 20, 8, '0', '单车房', '高强度燃脂骑行,动感音乐带你飞', 50.00, 'system', NOW(), NOW()), ('晚间普拉提', 20, (SELECT id FROM group_course_type WHERE type_name = '普拉提' LIMIT 1), - CURRENT_DATE + TIME '18:00', CURRENT_DATE + TIME '19:00', 10, 2, '0', '普拉提教室', '注重核心力量和身体控制,放松一天疲劳', 1, 'system', NOW(), NOW()); + CURRENT_DATE + TIME '18:00', CURRENT_DATE + TIME '19:00', 10, 2, '0', '普拉提教室', '注重核心力量和身体控制,放松一天疲劳', 50.00, 'system', NOW(), NOW()); -- ============================================================ -- 7. 为教练创建一个未来的团课(方便测试时间表) -- ============================================================ -INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, point_card_amount, create_by, created_at, updated_at) +INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, stored_value_amount, create_by, created_at, updated_at) VALUES ('HIIT燃脂训练', 20, (SELECT id FROM group_course_type WHERE type_name = 'HIIT训练' LIMIT 1), CURRENT_DATE + INTERVAL '1 day' + TIME '08:00', CURRENT_DATE + INTERVAL '1 day' + TIME '09:00', - 15, 0, '0', '综合训练区', '高强度间歇训练,挑战心肺极限', 2, 'system', NOW(), NOW()), + 15, 0, '0', '综合训练区', '高强度间歇训练,挑战心肺极限', 50.00, 'system', NOW(), NOW()), ('周末瑜伽', 20, (SELECT id FROM group_course_type WHERE type_name = '瑜伽进阶' LIMIT 1), CURRENT_DATE + INTERVAL '3 days' + TIME '09:00', CURRENT_DATE + INTERVAL '3 days' + TIME '10:30', - 12, 0, '0', '瑜伽教室', '针对有基础的进阶瑜伽课程', 1, 'system', NOW(), NOW()); + 12, 0, '0', '瑜伽教室', '针对有基础的进阶瑜伽课程', 50.00, 'system', NOW(), NOW()); -- ============================================================ -- 8. 重置序列值 diff --git a/gym-manage-api/manage-db/src/main/resources/db/migration/V24__Add_Second_Coach_Test_Data.sql b/gym-manage-api/manage-db/src/main/resources/db/migration/V24__Add_Second_Coach_Test_Data.sql index 9398aef..3aee92c 100644 --- a/gym-manage-api/manage-db/src/main/resources/db/migration/V24__Add_Second_Coach_Test_Data.sql +++ b/gym-manage-api/manage-db/src/main/resources/db/migration/V24__Add_Second_Coach_Test_Data.sql @@ -25,23 +25,23 @@ ON CONFLICT (user_id, role_id) DO NOTHING; -- ============================================================ -- 3. 为李教练分配测试团课(未来一周的课程) -- ============================================================ -INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, point_card_amount, create_by, created_at, updated_at) +INSERT INTO group_course (course_name, coach_id, course_type, start_time, end_time, max_members, current_members, status, location, description, stored_value_amount, create_by, created_at, updated_at) VALUES ('入门瑜伽', 21, (SELECT id FROM group_course_type WHERE type_name = '瑜伽入门' LIMIT 1), CURRENT_DATE + INTERVAL '2 days' + TIME '09:00', CURRENT_DATE + INTERVAL '2 days' + TIME '10:00', - 15, 0, '0', '瑜伽教室', '适合零基础学员的入门瑜伽课程', 1, 'system', NOW(), NOW()), + 15, 0, '0', '瑜伽教室', '适合零基础学员的入门瑜伽课程', 50.00, 'system', NOW(), NOW()), ('燃脂搏击', 21, (SELECT id FROM group_course_type WHERE type_name = '动感单车' LIMIT 1), CURRENT_DATE + INTERVAL '2 days' + TIME '15:00', CURRENT_DATE + INTERVAL '2 days' + TIME '16:00', - 20, 0, '0', '综合训练区', '高强度搏击操,燃烧卡路里', 2, 'system', NOW(), NOW()), + 20, 0, '0', '综合训练区', '高强度搏击操,燃烧卡路里', 50.00, 'system', NOW(), NOW()), ('肩颈理疗', 21, (SELECT id FROM group_course_type WHERE type_name = '普拉提' LIMIT 1), CURRENT_DATE + INTERVAL '4 days' + TIME '10:00', CURRENT_DATE + INTERVAL '4 days' + TIME '11:00', - 12, 0, '0', '普拉提教室', '针对久坐人群的肩颈放松课程', 1, 'system', NOW(), NOW()), + 12, 0, '0', '普拉提教室', '针对久坐人群的肩颈放松课程', 50.00, 'system', NOW(), NOW()), ('晨间有氧', 21, (SELECT id FROM group_course_type WHERE type_name = 'HIIT训练' LIMIT 1), CURRENT_DATE + INTERVAL '5 days' + TIME '07:00', CURRENT_DATE + INTERVAL '5 days' + TIME '08:00', - 20, 0, '0', '有氧区', '清晨燃脂有氧训练,开启活力一天', 2, 'system', NOW(), NOW()); + 20, 0, '0', '有氧区', '清晨燃脂有氧训练,开启活力一天', 50.00, 'system', NOW(), NOW()); -- ============================================================ -- 4. 重置序列值 diff --git a/gym-manage-api/manage-db/src/main/resources/db/migration/V6__Create_GroupCourse_table.sql b/gym-manage-api/manage-db/src/main/resources/db/migration/V6__Create_GroupCourse_table.sql index 714cb41..685d19e 100644 --- a/gym-manage-api/manage-db/src/main/resources/db/migration/V6__Create_GroupCourse_table.sql +++ b/gym-manage-api/manage-db/src/main/resources/db/migration/V6__Create_GroupCourse_table.sql @@ -18,7 +18,6 @@ CREATE TABLE IF NOT EXISTS group_course ( location VARCHAR(255), cover_image VARCHAR(500), description TEXT, - point_card_amount INTEGER DEFAULT 1, stored_value_amount DECIMAL(10,2) DEFAULT 0, create_by VARCHAR(50), update_by VARCHAR(50), @@ -58,7 +57,6 @@ COMMENT ON COLUMN group_course.actual_end_time IS '实际结课时间(教练 COMMENT ON COLUMN group_course.location IS '上课地点'; COMMENT ON COLUMN group_course.cover_image IS '封面图URL'; COMMENT ON COLUMN group_course.description IS '课程描述'; -COMMENT ON COLUMN group_course.point_card_amount IS '点卡额度(消耗次数)'; COMMENT ON COLUMN group_course.stored_value_amount IS '储值卡额度(消耗金额)'; COMMENT ON COLUMN group_course.create_by IS '创建人'; COMMENT ON COLUMN group_course.update_by IS '更新人';