mistakeBookService = $mistakeBookService; } /** * 获取错题列表 * * @param Request $request * @return JsonResponse */ public function listMistakes(Request $request): JsonResponse { try { $params = $request->only([ 'student_id', 'start_time', 'end_time', 'kp_ids', 'skill_ids', 'error_types', 'time_range', 'page', 'per_page', 'sort_by' ]); // 设置默认值 $params['page'] = (int) ($params['page'] ?? 1); $params['per_page'] = (int) ($params['per_page'] ?? 20); $params['sort_by'] = $params['sort_by'] ?? 'created_at_desc'; // 调用服务层获取错题列表 $result = $this->mistakeBookService->listMistakes($params); Log::info('获取错题列表成功', [ 'student_id' => $params['student_id'] ?? 'N/A', 'page' => $params['page'], 'per_page' => $params['per_page'], 'total' => $result['meta']['total'] ?? 0 ]); return response()->json([ 'success' => true, 'data' => $result['data'] ?? [], 'meta' => $result['meta'] ?? [], 'statistics' => $result['statistics'] ?? null ]); } catch (\Exception $e) { Log::error('获取错题列表失败', [ 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString(), 'params' => $request->all() ]); return response()->json([ 'success' => false, 'message' => '获取错题列表失败: ' . $e->getMessage(), 'data' => [], 'meta' => [ 'total' => 0, 'page' => (int) ($request->get('page', 1)), 'per_page' => (int) ($request->get('per_page', 20)) ] ], 500); } } /** * 获取单条错题详情 * * @param string $mistakeId * @param Request $request * @return JsonResponse */ public function getMistakeDetail(string $mistakeId, Request $request): JsonResponse { try { $studentId = $request->get('student_id'); $mistake = $this->mistakeBookService->getMistakeDetail($mistakeId, $studentId); if (empty($mistake)) { return response()->json([ 'success' => false, 'message' => '错题记录不存在' ], 404); } Log::info('获取错题详情成功', [ 'mistake_id' => $mistakeId, 'student_id' => $studentId ?? 'N/A' ]); return response()->json([ 'success' => true, 'data' => $mistake ]); } catch (\Exception $e) { Log::error('获取错题详情失败', [ 'mistake_id' => $mistakeId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => '获取错题详情失败: ' . $e->getMessage() ], 500); } } /** * 获取错题统计概要 * * @param Request $request * @return JsonResponse */ public function getSummary(Request $request): JsonResponse { try { $studentId = $request->get('student_id'); if (!$studentId) { return response()->json([ 'success' => false, 'message' => '缺少必要参数:student_id' ], 400); } $startTime = $request->get('start_time'); $endTime = $request->get('end_time'); // 构建查询参数 $params = ['student_id' => $studentId]; if ($startTime) { $params['start_time'] = $startTime; } if ($endTime) { $params['end_time'] = $endTime; } // 获取错题列表(用于计算统计信息) $mistakesResult = $this->mistakeBookService->listMistakes($params); // 获取概要统计 $summary = $this->mistakeBookService->summarize($studentId); Log::info('获取错题概要统计成功', [ 'student_id' => $studentId, 'total_mistakes' => $summary['total'] ?? 0 ]); return response()->json([ 'success' => true, 'data' => [ 'total' => $summary['total'] ?? 0, 'this_week' => $summary['this_week'] ?? 0, 'pending_review' => $summary['pending_review'] ?? 0, 'mastery_rate' => $summary['mastery_rate'] ?? 0.0, 'statistics' => $mistakesResult['statistics'] ?? null ] ]); } catch (\Exception $e) { Log::error('获取错题概要统计失败', [ 'student_id' => $request->get('student_id'), 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => '获取错题概要统计失败: ' . $e->getMessage() ], 500); } } /** * 获取错误模式分析 * * @param Request $request * @return JsonResponse */ public function getMistakePatterns(Request $request): JsonResponse { try { $studentId = $request->get('student_id'); if (!$studentId) { return response()->json([ 'success' => false, 'message' => '缺少必要参数:student_id' ], 400); } $patterns = $this->mistakeBookService->getMistakePatterns($studentId); Log::info('获取错误模式分析成功', [ 'student_id' => $studentId, 'top_kps_count' => count($patterns['top_kps'] ?? []) ]); return response()->json([ 'success' => true, 'data' => $patterns ]); } catch (\Exception $e) { Log::error('获取错误模式分析失败', [ 'student_id' => $request->get('student_id'), 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => '获取错误模式分析失败: ' . $e->getMessage() ], 500); } } /** * 收藏/取消收藏错题 * * @param string $mistakeId * @param Request $request * @return JsonResponse */ public function toggleFavorite(string $mistakeId, Request $request): JsonResponse { try { $data = $request->only(['favorite']); $favorite = $data['favorite'] ?? true; $result = $this->mistakeBookService->toggleFavorite($mistakeId, $favorite); Log::info(($favorite ? '收藏' : '取消收藏') . '错题', [ 'mistake_id' => $mistakeId, 'favorite' => $favorite, 'result' => $result ]); return response()->json([ 'success' => $result, 'message' => $result ? '操作成功' : '操作失败', 'data' => [ 'mistake_id' => $mistakeId, 'favorite' => $favorite ] ]); } catch (\Exception $e) { Log::error('收藏错题失败', [ 'mistake_id' => $mistakeId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => '收藏错题失败: ' . $e->getMessage() ], 500); } } /** * 标记错题已复习 * * @param string $mistakeId * @return JsonResponse */ public function markReviewed(string $mistakeId): JsonResponse { try { $result = $this->mistakeBookService->markReviewed($mistakeId); Log::info('标记错题已复习', [ 'mistake_id' => $mistakeId, 'result' => $result ]); return response()->json([ 'success' => $result, 'message' => $result ? '操作成功' : '操作失败', 'data' => [ 'mistake_id' => $mistakeId, 'reviewed' => $result, 'reviewed_at' => $result ? now()->toISOString() : null ] ]); } catch (\Exception $e) { Log::error('标记错题已复习失败', [ 'mistake_id' => $mistakeId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => '标记错题已复习失败: ' . $e->getMessage() ], 500); } } /** * 加入重练清单 * * @param string $mistakeId * @return JsonResponse */ public function addToRetryList(string $mistakeId): JsonResponse { try { $result = $this->mistakeBookService->addToRetryList($mistakeId); Log::info('加入重练清单', [ 'mistake_id' => $mistakeId, 'result' => $result ]); return response()->json([ 'success' => $result, 'message' => $result ? '操作成功' : '操作失败', 'data' => [ 'mistake_id' => $mistakeId, 'added' => $result ] ]); } catch (\Exception $e) { Log::error('加入重练清单失败', [ 'mistake_id' => $mistakeId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => '加入重练清单失败: ' . $e->getMessage() ], 500); } } /** * 获取题目正确率 * * @param string $questionId * @return JsonResponse */ public function getQuestionAccuracy(string $questionId): JsonResponse { try { $accuracy = $this->mistakeBookService->getQuestionAccuracy($questionId); Log::info('获取题目正确率成功', [ 'question_id' => $questionId, 'accuracy' => $accuracy ]); return response()->json([ 'success' => true, 'data' => [ 'question_id' => $questionId, 'accuracy' => $accuracy, 'correct_attempts' => null // LearningAnalytics不返回具体次数 ] ]); } catch (\Exception $e) { Log::error('获取题目正确率失败', [ 'question_id' => $questionId, 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => '获取题目正确率失败: ' . $e->getMessage() ], 500); } } /** * 推荐练习题 * * @param Request $request * @return JsonResponse */ public function recommendPractice(Request $request): JsonResponse { try { $studentId = $request->get('student_id'); $kpIds = $request->get('kp_ids', []); $skillIds = $request->get('skill_ids', []); if (!$studentId) { return response()->json([ 'success' => false, 'message' => '缺少必要参数:student_id' ], 400); } $recommendations = $this->mistakeBookService->recommendPractice( $studentId, $kpIds, $skillIds ); Log::info('获取推荐练习题成功', [ 'student_id' => $studentId, 'kp_ids' => $kpIds, 'recommendations_count' => count($recommendations['data'] ?? []) ]); return response()->json([ 'success' => true, 'data' => $recommendations['data'] ?? [] ]); } catch (\Exception $e) { Log::error('获取推荐练习题失败', [ 'student_id' => $request->get('student_id'), 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => '获取推荐练习题失败: ' . $e->getMessage() ], 500); } } /** * 获取错题本快照数据(用于仪表板) * * @param Request $request * @return JsonResponse */ public function getSnapshot(Request $request): JsonResponse { try { $studentId = $request->get('student_id'); $limit = (int) ($request->get('limit', 5)); if (!$studentId) { return response()->json([ 'success' => false, 'message' => '缺少必要参数:student_id' ], 400); } $snapshot = $this->mistakeBookService->getPanelSnapshot($studentId, $limit); Log::info('获取错题本快照数据成功', [ 'student_id' => $studentId, 'limit' => $limit, 'recent_count' => count($snapshot['recent'] ?? []) ]); return response()->json([ 'success' => true, 'data' => $snapshot ]); } catch (\Exception $e) { Log::error('获取错题本快照数据失败', [ 'student_id' => $request->get('student_id'), 'error' => $e->getMessage(), 'trace' => $e->getTraceAsString() ]); return response()->json([ 'success' => false, 'message' => '获取错题本快照数据失败: ' . $e->getMessage() ], 500); } } /** * 修改错题复习状态 */ public function updateReviewStatus(Request $request, string $mistakeId): JsonResponse { try { $validated = $request->validate([ 'action' => 'required|in:increment,reset', 'force_review' => 'boolean', ]); $action = $validated['action']; $forceReview = $validated['force_review'] ?? false; $result = $this->mistakeBookService->updateReviewStatus($mistakeId, $action, $forceReview); if ($result['success'] ?? false) { return response()->json([ 'success' => true, 'data' => $result, 'message' => $result['message'] ?? '复习状态更新成功', ]); } return response()->json([ 'success' => false, 'message' => $result['error'] ?? '更新复习状态失败', ], 400); } catch (\Throwable $e) { Log::error('Update review status error', [ 'mistake_id' => $mistakeId, 'error' => $e->getMessage(), ]); return response()->json([ 'success' => false, 'message' => '更新复习状态失败', 'error' => $e->getMessage(), ], 500); } } /** * 获取错题复习状态 */ public function getReviewStatus(string $mistakeId): JsonResponse { try { $result = $this->mistakeBookService->getReviewStatus($mistakeId); if ($result['success'] ?? false) { return response()->json([ 'success' => true, 'data' => $result, ]); } return response()->json([ 'success' => false, 'message' => $result['error'] ?? '获取复习状态失败', ], 400); } catch (\Throwable $e) { Log::error('Get review status error', [ 'mistake_id' => $mistakeId, 'error' => $e->getMessage(), ]); return response()->json([ 'success' => false, 'message' => '获取复习状态失败', 'error' => $e->getMessage(), ], 500); } } /** * 增加复习次数 */ public function incrementReview(Request $request, string $mistakeId): JsonResponse { try { $validated = $request->validate([ 'force_review' => 'boolean', ]); $forceReview = $validated['force_review'] ?? false; $result = $this->mistakeBookService->incrementReviewCount($mistakeId, $forceReview); if ($result['success'] ?? false) { return response()->json([ 'success' => true, 'data' => $result, 'message' => $result['message'] ?? '复习次数增加成功', ]); } return response()->json([ 'success' => false, 'message' => $result['error'] ?? '增加复习次数失败', ], 400); } catch (\Throwable $e) { Log::error('Increment review count error', [ 'mistake_id' => $mistakeId, 'error' => $e->getMessage(), ]); return response()->json([ 'success' => false, 'message' => '增加复习次数失败', 'error' => $e->getMessage(), ], 500); } } /** * 重置为强制复习状态 */ public function resetReview(string $mistakeId): JsonResponse { try { $result = $this->mistakeBookService->resetReviewStatus($mistakeId); if ($result['success'] ?? false) { return response()->json([ 'success' => true, 'data' => $result, 'message' => $result['message'] ?? '复习状态重置成功', ]); } return response()->json([ 'success' => false, 'message' => $result['error'] ?? '重置复习状态失败', ], 400); } catch (\Throwable $e) { Log::error('Reset review status error', [ 'mistake_id' => $mistakeId, 'error' => $e->getMessage(), ]); return response()->json([ 'success' => false, 'message' => '重置复习状态失败', 'error' => $e->getMessage(), ], 500); } } }