# 学习记录功能完善 - 问题分析与解决方案 ## 📊 现状分析 ### 1. 现有功能 - ✅ **成长记录功能**(已完成) - 位置:`/user-package/pages/growth/list.vue` - 功能:陪伴员填写的每日/周/月反馈 - 数据来源:`growth_record` 表 - 接口:`/api/growth-record/*` - ⚠️ **学习记录功能**(数据来源不明确) - 位置:`/user-package/pages/user/learning-record.vue` - 功能:学习记录列表和详情 - 数据来源:**未明确** - 接口:`/api/record/*`(**接口不存在**) ### 2. 核心问题 #### 问题1:功能重复 - **成长记录** 和 **学习记录** 本质上是同一个功能 - 两个页面展示相同的数据(陪伴员填写的服务记录) - 造成用户困惑和维护成本增加 #### 问题2:API不存在 ```javascript // learning-record.vue 调用的API recordApi.getRecordList() // ❌ /api/record/list 不存在 recordApi.getRecordDetail() // ❌ /api/record/detail/:id 不存在 recordApi.getStats() // ❌ /api/record/stats 不存在 ``` #### 问题3:数据关联不清晰 - 学习记录应该来自成长记录 - 但代码中没有明确的关联关系 - 导致数据显示不一致 ## 🎯 解决方案 ### 方案A:统一为成长记录(推荐)✅ **核心思路**:将"学习记录"功能合并到"成长记录",统一入口和数据源 #### 优点 - ✅ 功能统一,用户体验更好 - ✅ 减少维护成本 - ✅ 数据来源明确 - ✅ 已有完整的后端支持 #### 实施步骤 **1. 更新用户中心入口** ```vue 📚 成长记录 > ``` **2. 删除冗余页面** - 删除 `learning-record.vue` - 删除 `learning-record-detail.vue` - 删除 `recordApi` 相关代码 **3. 完善成长记录功能** - 添加统计数据展示 - 优化列表和详情页面 - 确保包含所有必要信息 --- ### 方案B:保留两个功能,明确区分 **核心思路**:明确区分两个功能的用途 #### 功能定位 - **成长记录**:陪伴员填写的专业反馈(每日/周/月) - **学习记录**:家长视角的服务记录汇总 #### 实施步骤 **1. 创建学习记录后端接口** ```java @RestController @RequestMapping("/api/record") public class LearningRecordController { // 获取学习记录列表(基于成长记录) @GetMapping("/list") public Result> getList( @RequestParam Long studentId, @RequestParam(required = false) String period, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size ) { // 从 growth_record 表查询数据 // 转换为学习记录格式 } // 获取学习统计 @GetMapping("/stats") public Result getStats(@RequestParam Long studentId) { // 统计总学习时长、次数、平均评分等 } } ``` **2. 数据转换逻辑** ```java // 将成长记录转换为学习记录 LearningRecordVO vo = new LearningRecordVO(); vo.setId(growthRecord.getId()); vo.setServiceDate(growthRecord.getRecordDate()); vo.setContent(growthRecord.getContent()); vo.setTeacherName(teacher.getName()); vo.setStudentName(student.getName()); // 从签到记录获取服务时长 CheckInRecord checkIn = getCheckInByOrderId(growthRecord.getOrderId()); vo.setDuration(calculateDuration(checkIn)); // 从评价获取评分 Review review = getReviewByOrderId(growthRecord.getOrderId()); vo.setRating(review != null ? review.getRating() : null); ``` ## 📋 推荐方案详细实施 ### 采用方案A:统一为成长记录 #### 第一步:更新前端路由和入口 **1. 修改用户中心入口** 文件位置:`peidu/uniapp/src/pages/user/index.vue` ```vue 📚 学习记录 > 📚 成长记录 > ``` **2. 更新pages.json配置** 删除学习记录相关页面配置: ```json { "path": "pages/user/learning-record", "style": { "navigationBarTitleText": "学习记录" } }, { "path": "pages/user/learning-record-detail", "style": { "navigationBarTitleText": "记录详情" } } ``` #### 第二步:完善成长记录功能 **1. 添加统计数据展示** 修改 `peidu/uniapp/src/user-package/pages/growth/list.vue`: ```vue ``` **2. 完善详情页面信息** 修改 `peidu/uniapp/src/user-package/pages/growth/detail.vue`,确保包含: - ✅ 服务时间、时长 - ✅ 学习内容 - ✅ 陪伴员评价 - ✅ 照片记录 - ✅ 学生表现 - ✅ 视频记录(如果有) #### 第三步:创建后端统计接口 **文件位置**:`peidu/backend/src/main/java/com/peidu/controller/GrowthRecordController.java` ```java /** * 获取家长端统计数据 */ @ApiOperation("获取家长端统计数据") @GetMapping("/parent/stats") public Result> getParentStats( @RequestParam Long studentId, HttpServletRequest request) { try { log.info("获取家长端统计数据: studentId={}", studentId); // 查询该学生的所有成长记录 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("student_id", studentId) .eq("record_type", "daily") .orderByDesc("record_date"); List records = growthRecordService.list(wrapper); // 统计数据 int totalMinutes = 0; int totalSessions = records.size(); double totalRating = 0; int ratingCount = 0; for (GrowthRecord record : records) { // 计算服务时长 if (record.getOrderId() != null) { Order order = orderService.getById(record.getOrderId()); if (order != null) { // 从签到记录获取实际服务时长 QueryWrapper checkInWrapper = new QueryWrapper<>(); checkInWrapper.eq("order_id", record.getOrderId()) .orderByAsc("check_time"); List checkInRecords = checkInRecordMapper.selectList(checkInWrapper); LocalDateTime checkInTime = null; LocalDateTime checkOutTime = null; for (CheckInRecord checkRecord : checkInRecords) { if ("checkin".equals(checkRecord.getCheckType()) && checkInTime == null) { checkInTime = checkRecord.getCheckTime(); } else if ("checkout".equals(checkRecord.getCheckType())) { checkOutTime = checkRecord.getCheckTime(); } } if (checkInTime != null && checkOutTime != null) { Duration duration = Duration.between(checkInTime, checkOutTime); totalMinutes += (int) duration.toMinutes(); } // 获取评分 QueryWrapper reviewWrapper = new QueryWrapper<>(); reviewWrapper.eq("order_id", record.getOrderId()); Review review = reviewMapper.selectOne(reviewWrapper); if (review != null && review.getRating() != null) { totalRating += review.getRating(); ratingCount++; } } } } // 构建返回数据 Map stats = new HashMap<>(); stats.put("totalHours", String.format("%.1f", totalMinutes / 60.0)); stats.put("totalSessions", totalSessions); stats.put("avgScore", ratingCount > 0 ? String.format("%.1f", totalRating / ratingCount) : "0"); log.info("统计结果: {}", stats); return Result.success(stats); } catch (Exception e) { log.error("获取统计数据失败", e); return Result.error(e.getMessage()); } } /** * 获取家长端成长记录列表 */ @ApiOperation("获取家长端成长记录列表") @GetMapping("/parent/list") public Result> getParentList( @RequestParam Long studentId, @RequestParam(required = false) String recordType, @RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer size) { try { log.info("获取家长端成长记录列表: studentId={}, recordType={}, page={}, size={}", studentId, recordType, page, size); Page pageParam = new Page<>(page, size); QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("student_id", studentId); if (recordType != null && !"all".equals(recordType)) { wrapper.eq("record_type", recordType); } wrapper.orderByDesc("record_date"); Page recordPage = growthRecordService.page(pageParam, wrapper); // 转换为VO Page voPage = new Page<>(); voPage.setCurrent(recordPage.getCurrent()); voPage.setSize(recordPage.getSize()); voPage.setTotal(recordPage.getTotal()); List voList = new ArrayList<>(); for (GrowthRecord record : recordPage.getRecords()) { GrowthRecordVO vo = convertToVO(record); voList.add(vo); } voPage.setRecords(voList); log.info("查询成功,共{}条记录", voPage.getTotal()); return Result.success(voPage); } catch (Exception e) { log.error("获取家长端成长记录列表失败", e); return Result.error(e.getMessage()); } } /** * 转换为VO对象 */ private GrowthRecordVO convertToVO(GrowthRecord record) { GrowthRecordVO vo = new GrowthRecordVO(); vo.setId(record.getId()); vo.setRecordDate(record.getRecordDate()); vo.setRecordType(record.getRecordType()); vo.setContent(record.getContent()); vo.setImageList(record.getImageList()); vo.setVideoList(record.getVideoList()); // 设置类型名称 String typeName = "每日反馈"; if ("weekly".equals(record.getRecordType())) { typeName = "周反馈"; } else if ("monthly".equals(record.getRecordType())) { typeName = "月反馈"; } vo.setRecordTypeName(typeName); // 获取学生信息 if (record.getStudentId() != null) { Student student = studentMapper.selectById(record.getStudentId()); if (student != null) { vo.setStudentName(student.getName()); } } // 获取教师信息 if (record.getTeacherId() != null) { Teacher teacher = teacherMapper.selectById(record.getTeacherId()); if (teacher != null) { vo.setTeacherName(teacher.getName()); } } // 获取服务时长 if (record.getOrderId() != null) { QueryWrapper checkInWrapper = new QueryWrapper<>(); checkInWrapper.eq("order_id", record.getOrderId()) .orderByAsc("check_time"); List checkInRecords = checkInRecordMapper.selectList(checkInWrapper); LocalDateTime checkInTime = null; LocalDateTime checkOutTime = null; for (CheckInRecord checkRecord : checkInRecords) { if ("checkin".equals(checkRecord.getCheckType()) && checkInTime == null) { checkInTime = checkRecord.getCheckTime(); } else if ("checkout".equals(checkRecord.getCheckType())) { checkOutTime = checkRecord.getCheckTime(); } } if (checkInTime != null && checkOutTime != null) { Duration duration = Duration.between(checkInTime, checkOutTime); int minutes = (int) duration.toMinutes(); int hours = minutes / 60; int mins = minutes % 60; vo.setDurationText(hours > 0 ? String.format("%d小时%d分钟", hours, mins) : String.format("%d分钟", mins)); } } return vo; } ``` **需要添加的依赖注入**: ```java @Autowired private StudentMapper studentMapper; @Autowired private TeacherMapper teacherMapper; @Autowired private ReviewMapper reviewMapper; ``` #### 第四步:更新VO类 **文件位置**:`peidu/backend/src/main/java/com/peidu/vo/GrowthRecordVO.java` ```java /** * 成长记录VO */ @Data public class GrowthRecordVO { private Long id; private Long orderId; private Long studentId; private String studentName; // 新增 private Long teacherId; private String teacherName; // 新增 private LocalDate recordDate; private String recordType; private String recordTypeName; // 新增:类型名称 private String content; private String imageList; private String videoList; private String durationText; // 新增:服务时长文本 private LocalDateTime createTime; private LocalDateTime updateTime; } ``` #### 第五步:清理冗余代码 **1. 删除文件** ```bash # 删除学习记录页面 peidu/uniapp/src/user-package/pages/user/learning-record.vue peidu/uniapp/src/user-package/pages/user/learning-record-detail.vue # 如果存在旧版本,也一并删除 peidu/uniapp/user-package/pages/user/learning-record.vue ``` **2. 清理API定义** 修改 `peidu/uniapp/src/api/index.js`,删除recordApi: ```javascript // 删除这部分代码 export const recordApi = { getRecordList(params) { return request.get('/api/record/list', { params }) }, getRecordDetail(id) { return request.get(`/api/record/detail/${id}`) }, getStats() { return request.get('/api/record/stats') } } ``` ## 📝 数据关联说明 ### 成长记录包含的完整信息 ``` 成长记录 (growth_record) ├── 基础信息 │ ├── 服务日期 (record_date) │ ├── 记录类型 (record_type: daily/weekly/monthly) │ └── 创建时间 (create_time) │ ├── 关联信息 │ ├── 订单ID (order_id) → 关联订单表 │ ├── 学生ID (student_id) → 关联学生表 │ └── 教师ID (teacher_id) → 关联教师表 │ ├── 内容信息 │ ├── 学习内容 (content) │ ├── 照片列表 (image_list) │ ├── 视频列表 (video_list) │ └── 周/月总结 (summary) │ └── 扩展信息(通过关联获取) ├── 服务时长 → 从 check_in_record 表计算 ├── 学生姓名 → 从 student 表获取 ├── 教师姓名 → 从 teacher 表获取 └── 评价评分 → 从 review 表获取 ``` ### 数据流转图 ``` 陪伴员填写成长记录 ↓ 保存到 growth_record 表 ↓ 家长端查看成长记录 ↓ 展示完整信息: - 基础信息(日期、内容、照片) - 服务时长(从签到记录计算) - 评价评分(从评价表获取) - 学生/教师信息(从关联表获取) ``` ## ✅ 实施检查清单 ### 前端修改 - [ ] 修改用户中心入口(user/index.vue) - [ ] 完善成长记录列表页(growth/list.vue) - [ ] 添加统计卡片 - [ ] 调用统计接口 - [ ] 确认详情页信息完整(growth/detail.vue) - [ ] 删除学习记录页面文件 - [ ] 清理recordApi定义 - [ ] 更新pages.json配置 ### 后端修改 - [ ] 添加家长端统计接口 - [ ] 添加家长端列表接口 - [ ] 完善GrowthRecordVO类 - [ ] 添加必要的Mapper注入 - [ ] 测试接口返回数据 ### 测试验证 - [ ] 用户中心入口跳转正确 - [ ] 统计数据显示正确 - [ ] 列表数据加载正常 - [ ] 详情页信息完整 - [ ] 服务时长计算准确 - [ ] 评分显示正确 ## 🎉 预期效果 完成后,家长端将拥有统一的"成长记录"功能: 1. **统计概览** - 累计学习时长 - 服务次数 - 平均评分 2. **记录列表** - 每日反馈 - 周反馈 - 月反馈 3. **详细信息** - 服务时间、时长 - 学习内容 - 陪伴员评价 - 照片/视频记录 - 学生表现 4. **数据来源清晰** - 所有数据来自 `growth_record` 表 - 通过关联表获取完整信息 - 数据一致性有保障