|
|
package com.gym.service;
|
|
|
|
|
|
import com.gym.model.TrainingPlan;
|
|
|
import com.gym.model.User;
|
|
|
import com.gym.repository.TrainingPlanRepository;
|
|
|
import com.gym.repository.UserRepository;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import java.time.LocalDate;
|
|
|
import java.time.LocalDateTime;
|
|
|
import java.time.temporal.ChronoUnit;
|
|
|
import java.util.List;
|
|
|
import java.util.Optional;
|
|
|
|
|
|
// 需要导入的包
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@Service
|
|
|
public class TrainingPlanService {
|
|
|
|
|
|
@Autowired
|
|
|
private TrainingPlanRepository trainingPlanRepository;
|
|
|
|
|
|
@Autowired
|
|
|
private UserRepository userRepository;
|
|
|
|
|
|
// 创建训练计划
|
|
|
public TrainingPlan createPlan(TrainingPlan plan, Long memberId, Long coachId) {
|
|
|
// 验证会员是否存在
|
|
|
User member = userRepository.findById(memberId)
|
|
|
.orElseThrow(() -> new RuntimeException("会员不存在"));
|
|
|
|
|
|
// 验证教练是否存在
|
|
|
User coach = userRepository.findById(coachId)
|
|
|
.orElseThrow(() -> new RuntimeException("教练不存在"));
|
|
|
|
|
|
// 验证角色
|
|
|
if (!"MEMBER".equals(member.getRole())) {
|
|
|
throw new RuntimeException("该用户不是会员");
|
|
|
}
|
|
|
if (!"COACH".equals(coach.getRole())) {
|
|
|
throw new RuntimeException("该用户不是教练");
|
|
|
}
|
|
|
|
|
|
plan.setMember(member);
|
|
|
plan.setCoach(coach);
|
|
|
plan.setCompletedDays(0);
|
|
|
plan.setProgress(0.0);
|
|
|
plan.setStatus("ACTIVE");
|
|
|
plan.setCreateTime(LocalDateTime.now());
|
|
|
plan.setUpdateTime(LocalDateTime.now());
|
|
|
|
|
|
// 如果提供了开始和结束日期,计算周期
|
|
|
if (plan.getStartDate() != null && plan.getEndDate() != null) {
|
|
|
long days = ChronoUnit.DAYS.between(plan.getStartDate(), plan.getEndDate());
|
|
|
plan.setDurationWeeks((int) (days / 7));
|
|
|
}
|
|
|
|
|
|
return trainingPlanRepository.save(plan);
|
|
|
}
|
|
|
|
|
|
// 获取所有训练计划
|
|
|
public List<TrainingPlan> getAllPlans() {
|
|
|
return trainingPlanRepository.findAll();
|
|
|
}
|
|
|
|
|
|
// 根据ID获取训练计划
|
|
|
public Optional<TrainingPlan> getPlanById(Long id) {
|
|
|
return trainingPlanRepository.findById(id);
|
|
|
}
|
|
|
|
|
|
// 获取会员的训练计划
|
|
|
public List<TrainingPlan> getMemberPlans(Long memberId) {
|
|
|
return trainingPlanRepository.findByMemberId(memberId);
|
|
|
}
|
|
|
|
|
|
// 获取教练制定的训练计划
|
|
|
public List<TrainingPlan> getCoachPlans(Long coachId) {
|
|
|
return trainingPlanRepository.findByCoachId(coachId);
|
|
|
}
|
|
|
|
|
|
// 获取活跃的训练计划
|
|
|
public List<TrainingPlan> getActivePlansByMember(Long memberId) {
|
|
|
return trainingPlanRepository.findActivePlansByMember(memberId);
|
|
|
}
|
|
|
|
|
|
// 更新训练计划
|
|
|
public TrainingPlan updatePlan(Long id, TrainingPlan updatedPlan) {
|
|
|
return trainingPlanRepository.findById(id)
|
|
|
.map(plan -> {
|
|
|
if (updatedPlan.getGoal() != null) {
|
|
|
plan.setGoal(updatedPlan.getGoal());
|
|
|
}
|
|
|
if (updatedPlan.getDailyPlan() != null) {
|
|
|
plan.setDailyPlan(updatedPlan.getDailyPlan());
|
|
|
}
|
|
|
if (updatedPlan.getDietAdvice() != null) {
|
|
|
plan.setDietAdvice(updatedPlan.getDietAdvice());
|
|
|
}
|
|
|
if (updatedPlan.getTrainingContent() != null) {
|
|
|
plan.setTrainingContent(updatedPlan.getTrainingContent());
|
|
|
}
|
|
|
if (updatedPlan.getRestDays() != null) {
|
|
|
plan.setRestDays(updatedPlan.getRestDays());
|
|
|
}
|
|
|
if (updatedPlan.getDifficultyLevel() != null) {
|
|
|
plan.setDifficultyLevel(updatedPlan.getDifficultyLevel());
|
|
|
}
|
|
|
if (updatedPlan.getWarmupSuggestions() != null) {
|
|
|
plan.setWarmupSuggestions(updatedPlan.getWarmupSuggestions());
|
|
|
}
|
|
|
if (updatedPlan.getCooldownSuggestions() != null) {
|
|
|
plan.setCooldownSuggestions(updatedPlan.getCooldownSuggestions());
|
|
|
}
|
|
|
if (updatedPlan.getPrecautions() != null) {
|
|
|
plan.setPrecautions(updatedPlan.getPrecautions());
|
|
|
}
|
|
|
|
|
|
plan.setUpdateTime(LocalDateTime.now());
|
|
|
return trainingPlanRepository.save(plan);
|
|
|
})
|
|
|
.orElseThrow(() -> new RuntimeException("训练计划不存在"));
|
|
|
}
|
|
|
|
|
|
// 更新训练进度
|
|
|
public TrainingPlan updateProgress(Long id, Integer completedDays) {
|
|
|
return trainingPlanRepository.findById(id)
|
|
|
.map(plan -> {
|
|
|
plan.setCompletedDays(completedDays);
|
|
|
|
|
|
// 计算进度
|
|
|
if (plan.getDurationWeeks() != null && plan.getDurationWeeks() > 0) {
|
|
|
int totalDays = plan.getDurationWeeks() * 7;
|
|
|
double progress = (double) completedDays / totalDays * 100;
|
|
|
plan.setProgress(Math.min(progress, 100.0));
|
|
|
|
|
|
// 如果进度达到100%,标记为完成
|
|
|
if (progress >= 100) {
|
|
|
plan.setStatus("COMPLETED");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
plan.setUpdateTime(LocalDateTime.now());
|
|
|
return trainingPlanRepository.save(plan);
|
|
|
})
|
|
|
.orElseThrow(() -> new RuntimeException("训练计划不存在"));
|
|
|
}
|
|
|
|
|
|
// 标记为完成
|
|
|
public TrainingPlan markAsCompleted(Long id) {
|
|
|
return trainingPlanRepository.findById(id)
|
|
|
.map(plan -> {
|
|
|
plan.setStatus("COMPLETED");
|
|
|
plan.setProgress(100.0);
|
|
|
plan.setUpdateTime(LocalDateTime.now());
|
|
|
return trainingPlanRepository.save(plan);
|
|
|
})
|
|
|
.orElseThrow(() -> new RuntimeException("训练计划不存在"));
|
|
|
}
|
|
|
|
|
|
// 暂停训练计划
|
|
|
public TrainingPlan pausePlan(Long id) {
|
|
|
return trainingPlanRepository.findById(id)
|
|
|
.map(plan -> {
|
|
|
plan.setStatus("PAUSED");
|
|
|
plan.setUpdateTime(LocalDateTime.now());
|
|
|
return trainingPlanRepository.save(plan);
|
|
|
})
|
|
|
.orElseThrow(() -> new RuntimeException("训练计划不存在"));
|
|
|
}
|
|
|
|
|
|
// 恢复训练计划
|
|
|
public TrainingPlan resumePlan(Long id) {
|
|
|
return trainingPlanRepository.findById(id)
|
|
|
.map(plan -> {
|
|
|
plan.setStatus("ACTIVE");
|
|
|
plan.setUpdateTime(LocalDateTime.now());
|
|
|
return trainingPlanRepository.save(plan);
|
|
|
})
|
|
|
.orElseThrow(() -> new RuntimeException("训练计划不存在"));
|
|
|
}
|
|
|
|
|
|
// AI训练推荐(基于简单规则)
|
|
|
public String recommendTraining(User member) {
|
|
|
String goal = member.getFitnessGoal();
|
|
|
Double weight = member.getWeight();
|
|
|
Double height = member.getHeight();
|
|
|
Integer age = member.getAge();
|
|
|
|
|
|
if (goal == null) {
|
|
|
goal = "保持健康";
|
|
|
}
|
|
|
|
|
|
StringBuilder recommendation = new StringBuilder();
|
|
|
recommendation.append("💪 基于您的信息,推荐训练计划:\n\n");
|
|
|
|
|
|
// 计算BMI
|
|
|
if (height != null && weight != null && height > 0) {
|
|
|
double bmi = weight / ((height / 100) * (height / 100));
|
|
|
recommendation.append("📊 您的BMI: ").append(String.format("%.1f", bmi)).append("\n");
|
|
|
|
|
|
if (bmi < 18.5) {
|
|
|
recommendation.append("⚠️ 体重偏轻,建议增加肌肉训练\n");
|
|
|
} else if (bmi > 24) {
|
|
|
recommendation.append("⚠️ 体重偏重,建议增加有氧运动\n");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 基于目标推荐
|
|
|
switch (goal.toLowerCase()) {
|
|
|
case "减脂":
|
|
|
recommendation.append("🎯 目标:减脂\n");
|
|
|
recommendation.append("🏃 训练建议:\n");
|
|
|
recommendation.append(" • 每周4-5次有氧运动(跑步、游泳、动感单车)\n");
|
|
|
recommendation.append(" • 每次45-60分钟\n");
|
|
|
recommendation.append(" • 心率保持在120-150次/分钟\n");
|
|
|
recommendation.append(" • 配合力量训练,每周2-3次\n");
|
|
|
recommendation.append("🍎 饮食建议:\n");
|
|
|
recommendation.append(" • 控制碳水化合物摄入\n");
|
|
|
recommendation.append(" • 增加蛋白质摄入\n");
|
|
|
recommendation.append(" • 多喝水,少喝含糖饮料\n");
|
|
|
break;
|
|
|
|
|
|
case "增肌":
|
|
|
recommendation.append("🎯 目标:增肌\n");
|
|
|
recommendation.append("🏋️ 训练建议:\n");
|
|
|
recommendation.append(" • 每周4-5次力量训练\n");
|
|
|
recommendation.append(" • 重点训练:卧推、深蹲、硬拉、引体向上\n");
|
|
|
recommendation.append(" • 每组8-12次,每个动作3-4组\n");
|
|
|
recommendation.append(" • 组间休息60-90秒\n");
|
|
|
recommendation.append("🍗 饮食建议:\n");
|
|
|
recommendation.append(" • 增加蛋白质摄入(体重×1.5-2克/天)\n");
|
|
|
recommendation.append(" • 适量碳水化合物提供能量\n");
|
|
|
recommendation.append(" • 训练后30分钟内补充蛋白质\n");
|
|
|
break;
|
|
|
|
|
|
case "塑形":
|
|
|
recommendation.append("🎯 目标:塑形\n");
|
|
|
recommendation.append("🤸 训练建议:\n");
|
|
|
recommendation.append(" • 每周3-4次全身训练\n");
|
|
|
recommendation.append(" • 结合力量和有氧训练\n");
|
|
|
recommendation.append(" • 重点:核心训练、臀部训练\n");
|
|
|
recommendation.append(" • 每组12-15次,中等重量\n");
|
|
|
recommendation.append("🥗 饮食建议:\n");
|
|
|
recommendation.append(" • 均衡饮食,控制总热量\n");
|
|
|
recommendation.append(" • 多吃蔬菜水果\n");
|
|
|
recommendation.append(" • 减少加工食品\n");
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
recommendation.append("🎯 目标:保持健康\n");
|
|
|
recommendation.append("🏃 训练建议:\n");
|
|
|
recommendation.append(" • 每周3-4次运动\n");
|
|
|
recommendation.append(" • 每次30-45分钟\n");
|
|
|
recommendation.append(" • 结合有氧和力量训练\n");
|
|
|
recommendation.append(" • 保持中等强度\n");
|
|
|
recommendation.append("🥦 饮食建议:\n");
|
|
|
recommendation.append(" • 均衡营养,多样化饮食\n");
|
|
|
recommendation.append(" • 控制盐、糖、油摄入\n");
|
|
|
recommendation.append(" • 每天喝足水\n");
|
|
|
}
|
|
|
|
|
|
return recommendation.toString();
|
|
|
}
|
|
|
|
|
|
// 获取统计数据
|
|
|
public Map<String, Object> getStats(Long memberId) {
|
|
|
Map<String, Object> stats = new HashMap<>();
|
|
|
|
|
|
List<TrainingPlan> allPlans = trainingPlanRepository.findByMemberId(memberId);
|
|
|
List<TrainingPlan> activePlans = trainingPlanRepository.findActivePlansByMember(memberId);
|
|
|
Long completedCount = trainingPlanRepository.countCompletedPlansByMember(memberId);
|
|
|
|
|
|
stats.put("totalPlans", allPlans.size());
|
|
|
stats.put("activePlans", activePlans.size());
|
|
|
stats.put("completedPlans", completedCount);
|
|
|
|
|
|
// 计算平均进度
|
|
|
double avgProgress = allPlans.stream()
|
|
|
.mapToDouble(TrainingPlan::getProgress)
|
|
|
.average()
|
|
|
.orElse(0.0);
|
|
|
stats.put("averageProgress", String.format("%.1f%%", avgProgress));
|
|
|
|
|
|
// 按目标分类统计
|
|
|
Map<String, Long> goalStats = allPlans.stream()
|
|
|
.collect(Collectors.groupingBy(TrainingPlan::getGoal, Collectors.counting()));
|
|
|
stats.put("goalDistribution", goalStats);
|
|
|
|
|
|
return stats;
|
|
|
}
|
|
|
|
|
|
|
|
|
} |