StudentController.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <?php
  2. namespace App\Http\Controllers\Api;
  3. use App\Http\Controllers\Controller;
  4. use App\Services\MathRecSysService;
  5. use Illuminate\Http\Request;
  6. use Illuminate\Http\JsonResponse;
  7. class StudentController extends Controller
  8. {
  9. protected MathRecSysService $mathRecSys;
  10. public function __construct(MathRecSysService $mathRecSys)
  11. {
  12. $this->mathRecSys = $mathRecSys;
  13. }
  14. /**
  15. * 获取学生完整信息(集成MathRecSys数据)
  16. *
  17. * @param string $studentId 学生ID
  18. * @return JsonResponse
  19. */
  20. public function show(string $studentId): JsonResponse
  21. {
  22. try {
  23. // 获取Laravel本地数据
  24. $localStudent = $this->getLocalStudent($studentId);
  25. // 获取MathRecSys能力画像
  26. $mathRecSysProfile = $this->mathRecSys->getStudentProfile($studentId);
  27. // 获取薄弱知识点
  28. $weakPoints = $this->mathRecSys->getWeakPoints($studentId);
  29. // 合并数据
  30. $studentData = [
  31. 'basic_info' => $localStudent,
  32. 'ability_profile' => $mathRecSysProfile['data'] ?? [],
  33. 'mastery_levels' => $this->formatMasteryLevels($mathRecSysProfile),
  34. 'weak_points' => $weakPoints['data'] ?? [],
  35. 'learning_progress' => $mathRecSysProfile['progress'] ?? [],
  36. 'recommendations' => $this->getStudentRecommendations($studentId),
  37. 'last_updated' => now()->toISOString()
  38. ];
  39. return response()->json([
  40. 'success' => true,
  41. 'data' => $studentData
  42. ]);
  43. } catch (\Exception $e) {
  44. \Log::error('获取学生信息失败', [
  45. 'student_id' => $studentId,
  46. 'error' => $e->getMessage()
  47. ]);
  48. return response()->json([
  49. 'success' => false,
  50. 'message' => '获取学生信息失败: ' . $e->getMessage()
  51. ], 500);
  52. }
  53. }
  54. /**
  55. * 获取班级整体分析
  56. *
  57. * @param string $classId 班级ID
  58. * @return JsonResponse
  59. */
  60. public function classAnalysis(string $classId): JsonResponse
  61. {
  62. try {
  63. $analysis = $this->mathRecSys->getClassAnalysis($classId);
  64. return response()->json([
  65. 'success' => true,
  66. 'data' => $analysis['data'] ?? []
  67. ]);
  68. } catch (\Exception $e) {
  69. \Log::error('获取班级分析失败', [
  70. 'class_id' => $classId,
  71. 'error' => $e->getMessage()
  72. ]);
  73. return response()->json([
  74. 'success' => false,
  75. 'message' => '获取班级分析失败'
  76. ], 500);
  77. }
  78. }
  79. /**
  80. * 获取学生个性化推荐
  81. *
  82. * @param string $studentId 学生ID
  83. * @param Request $request
  84. * @return JsonResponse
  85. */
  86. public function getRecommendations(string $studentId, Request $request): JsonResponse
  87. {
  88. try {
  89. $options = $request->only(['count', 'difficulty', 'focus_kp']);
  90. $recommendations = $this->mathRecSys->getRecommendations($studentId, $options);
  91. return response()->json([
  92. 'success' => true,
  93. 'data' => $recommendations['data'] ?? []
  94. ]);
  95. } catch (\Exception $e) {
  96. \Log::error('获取推荐失败', [
  97. 'student_id' => $studentId,
  98. 'error' => $e->getMessage()
  99. ]);
  100. return response()->json([
  101. 'success' => false,
  102. 'message' => '获取推荐失败'
  103. ], 500);
  104. }
  105. }
  106. /**
  107. * 智能分析题目
  108. *
  109. * @param Request $request
  110. * @param string $studentId 学生ID
  111. * @return JsonResponse
  112. */
  113. public function analyzeQuestion(Request $request, string $studentId): JsonResponse
  114. {
  115. $request->validate([
  116. 'question' => 'required|string',
  117. 'student_answer' => 'required|string',
  118. 'correct_answer' => 'required|string',
  119. 'focus_kp' => 'nullable|string',
  120. 'question_type' => 'nullable|string',
  121. 'difficulty' => 'nullable|numeric|min:0|max:1',
  122. ]);
  123. try {
  124. $analysisData = [
  125. 'student_id' => $studentId,
  126. 'question' => $request->question,
  127. 'student_answer' => $request->student_answer,
  128. 'correct_answer' => $request->correct_answer,
  129. 'focus_kp' => $request->focus_kp,
  130. 'question_type' => $request->question_type ?? '计算题',
  131. 'difficulty' => $request->difficulty ?? 0.5,
  132. ];
  133. $analysis = $this->mathRecSys->smartAnalyze($analysisData);
  134. return response()->json([
  135. 'success' => true,
  136. 'data' => $analysis['data'] ?? []
  137. ]);
  138. } catch (\Exception $e) {
  139. \Log::error('题目分析失败', [
  140. 'student_id' => $studentId,
  141. 'error' => $e->getMessage()
  142. ]);
  143. return response()->json([
  144. 'success' => false,
  145. 'message' => '题目分析失败'
  146. ], 500);
  147. }
  148. }
  149. /**
  150. * 获取学习轨迹
  151. *
  152. * @param string $studentId 学生ID
  153. * @param Request $request
  154. * @return JsonResponse
  155. */
  156. public function getTrajectory(string $studentId, Request $request): JsonResponse
  157. {
  158. try {
  159. $startDate = $request->input('start_date');
  160. $endDate = $request->input('end_date');
  161. $trajectory = $this->mathRecSys->getLearningTrajectory($studentId, $startDate, $endDate);
  162. return response()->json([
  163. 'success' => true,
  164. 'data' => $trajectory['data'] ?? []
  165. ]);
  166. } catch (\Exception $e) {
  167. \Log::error('获取学习轨迹失败', [
  168. 'student_id' => $studentId,
  169. 'error' => $e->getMessage()
  170. ]);
  171. return response()->json([
  172. 'success' => false,
  173. 'message' => '获取学习轨迹失败'
  174. ], 500);
  175. }
  176. }
  177. /**
  178. * 获取学习建议
  179. *
  180. * @param string $studentId 学生ID
  181. * @return JsonResponse
  182. */
  183. public function getSuggestions(string $studentId): JsonResponse
  184. {
  185. try {
  186. $suggestions = $this->mathRecSys->getLearningSuggestions($studentId);
  187. return response()->json([
  188. 'success' => true,
  189. 'data' => $suggestions['data'] ?? []
  190. ]);
  191. } catch (\Exception $e) {
  192. \Log::error('获取学习建议失败', [
  193. 'student_id' => $studentId,
  194. 'error' => $e->getMessage()
  195. ]);
  196. return response()->json([
  197. 'success' => false,
  198. 'message' => '获取学习建议失败'
  199. ], 500);
  200. }
  201. }
  202. /**
  203. * 更新学生掌握度
  204. *
  205. * @param Request $request
  206. * @param string $studentId 学生ID
  207. * @return JsonResponse
  208. */
  209. public function updateMastery(Request $request, string $studentId): JsonResponse
  210. {
  211. $request->validate([
  212. 'mastery_data' => 'required|array',
  213. 'mastery_data.*.kp' => 'required|string',
  214. 'mastery_data.*.level' => 'required|numeric|min:0|max:1',
  215. ]);
  216. try {
  217. // 使用本地的MasteryCalculator
  218. $masteryCalculator = app(\App\Services\MasteryCalculator::class);
  219. $kpCodes = array_map(function($item) {
  220. return $item['kp'];
  221. }, $request->mastery_data);
  222. // 批量更新掌握度
  223. $results = $masteryCalculator->batchUpdateMastery($studentId, $kpCodes);
  224. return response()->json([
  225. 'success' => true,
  226. 'data' => [
  227. 'student_id' => $studentId,
  228. 'updated_count' => count($results),
  229. 'results' => $results,
  230. ]
  231. ]);
  232. } catch (\Exception $e) {
  233. \Log::error('更新掌握度失败', [
  234. 'student_id' => $studentId,
  235. 'error' => $e->getMessage()
  236. ]);
  237. return response()->json([
  238. 'success' => false,
  239. 'message' => '更新掌握度失败: ' . $e->getMessage()
  240. ], 500);
  241. }
  242. }
  243. /**
  244. * 检查MathRecSys服务状态
  245. *
  246. * @return JsonResponse
  247. */
  248. public function checkServiceHealth(): JsonResponse
  249. {
  250. $isHealthy = $this->mathRecSys->isHealthy();
  251. return response()->json([
  252. 'success' => true,
  253. 'healthy' => $isHealthy,
  254. 'timestamp' => now()->toISOString()
  255. ]);
  256. }
  257. /**
  258. * 从本地数据库获取学生基本信息
  259. *
  260. * @param string $studentId
  261. * @return array
  262. */
  263. private function getLocalStudent(string $studentId): array
  264. {
  265. // 这里应该从Laravel数据库查询学生信息
  266. // 示例返回数据,实际应该查询数据库
  267. return [
  268. 'id' => $studentId,
  269. 'name' => '学生_' . substr($studentId, -3),
  270. 'class' => '五年级一班',
  271. 'grade' => '五年级',
  272. 'created_at' => now()->subMonths(6)->toISOString(),
  273. ];
  274. }
  275. /**
  276. * 格式化掌握度数据
  277. *
  278. * @param array $profile
  279. * @return array
  280. */
  281. private function formatMasteryLevels(array $profile): array
  282. {
  283. $masteryData = $profile['data']['mastery'] ?? $profile['mastery'] ?? [];
  284. return array_map(function ($item) {
  285. return [
  286. 'kp' => $item['kp'] ?? $item['kp_id'] ?? '',
  287. 'level' => floatval($item['level'] ?? $item['mastery_level'] ?? 0),
  288. 'practice_count' => $item['practice_count'] ?? 0,
  289. 'success_rate' => floatval($item['success_rate'] ?? 0),
  290. 'last_practice' => $item['last_practice'] ?? null
  291. ];
  292. }, $masteryData);
  293. }
  294. /**
  295. * 获取推荐(内部方法)
  296. *
  297. * @param string $studentId
  298. * @return array
  299. */
  300. private function getStudentRecommendations(string $studentId): array
  301. {
  302. try {
  303. $recommendations = $this->mathRecSys->getRecommendations($studentId, ['count' => 5]);
  304. return $recommendations['data'] ?? [];
  305. } catch (\Exception $e) {
  306. \Log::warning('获取推荐失败', ['error' => $e->getMessage()]);
  307. return [];
  308. }
  309. }
  310. }