Files
plates-server/docs/training-plans-optimization-summary.md
richarjiang bea71af5d3 优化训练计划项目管理功能
- 更新训练项目文档,增加与动作库的智能关联和简化接口操作的说明
- 移除批量操作接口,专注于单项操作,提升用户体验
- 增强数据模型,确保训练项目与动作库的关联性,提升数据一致性和查询性能
- 更新服务逻辑,支持动作存在性验证,确保数据的准确性和完整性
2025-08-15 11:37:11 +08:00

5.5 KiB
Raw Blame History

训练计划项目管理系统优化总结

优化背景

原始设计存在以下问题:

  1. 训练项目与系统动作库缺乏关联
  2. 接口复杂,包含过多批量操作
  3. 数据结构冗余,缺乏标准化

核心优化

1. 数据库模型优化

之前的设计

// 独立的项目标识,与动作库无关联
interface ScheduleExercise {
  key: string;           // 自定义项目key
  name: string;          // 自定义名称
  category?: string;     // 自定义分类
  // ...
}

优化后的设计

// 智能关联动作库的设计
interface ScheduleExercise {
  exerciseKey?: string;  // 关联动作库(外键)
  name: string;          // 可自定义的名称
  // ...
  exercise?: {           // 关联的动作信息
    key: string;
    name: string;
    description: string;
    categoryKey: string;
    categoryName: string;
  };
}

数据库关系

  • ScheduleExercise.exerciseKeyExercise.key (外键关联)
  • 支持左连接查询,获取完整动作信息
  • exercise类型项目必须关联动作库rest/note类型可选

2. 接口设计简化

去除的批量操作接口

  • POST /exercises/batch - 批量创建
  • PUT /exercises/batch - 批量更新
  • DELETE /exercises - 批量删除

保留的核心接口

  • POST /exercises - 单个创建
  • GET /exercises - 列表查询
  • GET /exercises/:id - 详情查询
  • PUT /exercises/:id - 单个更新
  • DELETE /exercises/:id - 单个删除
  • PUT /exercises/order - 排序调整
  • PUT /exercises/:id/complete - 完成状态
  • GET /exercises/stats/completion - 统计信息

3. 业务逻辑优化

智能验证机制

// 动作存在性验证
private async validateExercise(exerciseKey: string) {
  const exercise = await this.exerciseModel.findByPk(exerciseKey);
  if (!exercise) {
    throw new NotFoundException(`动作 "${exerciseKey}" 不存在`);
  }
  return exercise;
}

// 创建时的验证逻辑
if (dto.itemType === 'exercise' && dto.exerciseKey) {
  await this.validateExercise(dto.exerciseKey);
}

关联数据获取

// 查询时自动包含动作信息
const exercises = await this.scheduleExerciseModel.findAll({
  include: [{ model: Exercise, required: false }],
  order: [['sortOrder', 'ASC']],
});

// 格式化返回数据
return exercises.map(exercise => ({
  ...exercise.toJSON(),
  exercise: exercise.exercise ? {
    key: exercise.exercise.key,
    name: exercise.exercise.name,
    description: exercise.exercise.description,
    categoryKey: exercise.exercise.categoryKey,
    categoryName: exercise.exercise.categoryName,
  } : undefined
}));

技术收益

1. 数据一致性提升

  • 动作信息标准化,避免重复维护
  • 外键约束确保数据完整性
  • 动作库统一管理,便于更新

2. 接口复杂度降低

  • 去除批量操作,专注单项操作
  • 接口数量从11个减少到8个
  • 参数验证逻辑简化

3. 查询性能优化

  • 左连接一次性获取完整信息
  • 减少前端多次API调用
  • 数据库索引优化

4. 扩展性增强

  • 新增动作自动可用于训练计划
  • 动作分类变更自动同步
  • 支持动作版本管理

业务价值

1. 用户体验改善

  • 专业性提升: 基于标准动作库,确保训练的专业性
  • 操作简化: 单项操作更直观,降低学习成本
  • 信息完整: 自动获取动作描述、分类等详细信息

2. 内容管理优化

  • 集中管理: 动作库统一维护,避免内容重复
  • 质量控制: 标准化的动作描述和分类
  • 版本控制: 支持动作信息的统一更新

3. 开发效率提升

  • 接口简化: 减少API数量降低维护成本
  • 类型安全: 强类型验证,减少运行时错误
  • 测试简化: 单项操作更容易编写测试用例

前端适配建议

1. 动作选择组件

// 获取可用动作列表
const exercises = await api.get('/exercises/config');

// 创建训练项目时选择动作
const createExercise = {
  exerciseKey: selectedExercise.key,  // 从动作库选择
  name: customName || selectedExercise.name,  // 可自定义名称
  sets: 3,
  reps: 15,
  itemType: 'exercise'
};

2. 数据显示组件

// 显示训练项目时同时展示动作详情
const ExerciseItem = ({ item }) => (
  <div>
    <h3>{item.name}</h3>
    {item.exercise && (
      <div>
        <p>分类: {item.exercise.categoryName}</p>
        <p>说明: {item.exercise.description}</p>
      </div>
    )}
    <p>组数: {item.sets} | 次数: {item.reps}</p>
  </div>
);

3. 操作流程优化

// 简化的操作流程
const addExercise = async (exerciseKey, customParams) => {
  const exercise = await api.post(`/training-plans/${planId}/exercises`, {
    exerciseKey,
    ...customParams
  });
  
  // 无需额外查询,响应已包含完整信息
  updateExerciseList(exercise);
};

总结

这次优化重点解决了数据关联和接口复杂度两大核心问题:

  1. 智能关联: 通过外键关联确保训练项目与动作库的数据一致性
  2. 接口简化: 去除批量操作,专注于单项操作的用户体验
  3. 性能优化: 通过关联查询减少API调用次数
  4. 扩展性: 为未来的功能扩展提供了良好的架构基础

这个优化后的设计既保持了功能的完整性,又显著提升了系统的可维护性和用户体验。