MistakeBookController.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906
  1. <?php
  2. namespace App\Http\Controllers\Api;
  3. use App\Http\Controllers\Controller;
  4. use App\Services\MistakeBookService;
  5. use Illuminate\Http\Request;
  6. use Illuminate\Http\JsonResponse;
  7. use Illuminate\Support\Facades\Log;
  8. class MistakeBookController extends Controller
  9. {
  10. protected MistakeBookService $mistakeBookService;
  11. public function __construct(MistakeBookService $mistakeBookService)
  12. {
  13. $this->mistakeBookService = $mistakeBookService;
  14. }
  15. /**
  16. * 获取错题列表
  17. *
  18. * @param Request $request
  19. * @return JsonResponse
  20. */
  21. public function listMistakes(Request $request): JsonResponse
  22. {
  23. try {
  24. $params = $request->only([
  25. 'student_id',
  26. 'start_time',
  27. 'end_time',
  28. 'kp_ids',
  29. 'skill_ids',
  30. 'error_types',
  31. 'time_range',
  32. 'page',
  33. 'per_page',
  34. 'sort_by'
  35. ]);
  36. // 设置默认值
  37. $params['page'] = (int) ($params['page'] ?? 1);
  38. $params['per_page'] = (int) ($params['per_page'] ?? 20);
  39. $params['sort_by'] = $params['sort_by'] ?? 'created_at_desc';
  40. // 调用服务层获取错题列表
  41. $result = $this->mistakeBookService->listMistakes($params);
  42. Log::info('获取错题列表成功', [
  43. 'student_id' => $params['student_id'] ?? 'N/A',
  44. 'page' => $params['page'],
  45. 'per_page' => $params['per_page'],
  46. 'total' => $result['meta']['total'] ?? 0
  47. ]);
  48. return response()->json([
  49. 'success' => true,
  50. 'data' => $result['data'] ?? [],
  51. 'meta' => $result['meta'] ?? [],
  52. 'statistics' => $result['statistics'] ?? null
  53. ]);
  54. } catch (\Exception $e) {
  55. Log::error('获取错题列表失败', [
  56. 'error' => $e->getMessage(),
  57. 'trace' => $e->getTraceAsString(),
  58. 'params' => $request->all()
  59. ]);
  60. return response()->json([
  61. 'success' => false,
  62. 'message' => '获取错题列表失败: ' . $e->getMessage(),
  63. 'data' => [],
  64. 'meta' => [
  65. 'total' => 0,
  66. 'page' => (int) ($request->get('page', 1)),
  67. 'per_page' => (int) ($request->get('per_page', 20))
  68. ]
  69. ], 500);
  70. }
  71. }
  72. /**
  73. * 新增错题
  74. */
  75. public function addMistake(Request $request): JsonResponse
  76. {
  77. $payload = $request->only([
  78. 'student_id',
  79. 'question_id',
  80. 'my_answer',
  81. 'correct_answer',
  82. 'source',
  83. 'happened_at',
  84. 'idempotency_key',
  85. ]);
  86. if (empty($payload['student_id']) || empty($payload['question_id'])) {
  87. return response()->json([
  88. 'success' => false,
  89. 'message' => '缺少必要参数:student_id, question_id',
  90. ], 400);
  91. }
  92. try {
  93. $result = $this->mistakeBookService->createMistake($payload);
  94. return response()->json([
  95. 'success' => true,
  96. 'data' => $result,
  97. 'duplicate' => $result['duplicate'] ?? false,
  98. ]);
  99. } catch (\Exception $e) {
  100. Log::error('新增错题失败', [
  101. 'error' => $e->getMessage(),
  102. 'payload' => $payload,
  103. ]);
  104. return response()->json([
  105. 'success' => false,
  106. 'message' => '新增错题失败: ' . $e->getMessage(),
  107. ], 500);
  108. }
  109. }
  110. /**
  111. * 获取单条错题详情
  112. *
  113. * @param string $mistakeId
  114. * @param Request $request
  115. * @return JsonResponse
  116. */
  117. public function getMistakeDetail(string $mistakeId, Request $request): JsonResponse
  118. {
  119. try {
  120. $studentId = $request->get('student_id');
  121. $mistake = $this->mistakeBookService->getMistakeDetail($mistakeId, $studentId);
  122. if (empty($mistake)) {
  123. return response()->json([
  124. 'success' => false,
  125. 'message' => '错题记录不存在'
  126. ], 404);
  127. }
  128. Log::info('获取错题详情成功', [
  129. 'mistake_id' => $mistakeId,
  130. 'student_id' => $studentId ?? 'N/A'
  131. ]);
  132. return response()->json([
  133. 'success' => true,
  134. 'data' => $mistake
  135. ]);
  136. } catch (\Exception $e) {
  137. Log::error('获取错题详情失败', [
  138. 'mistake_id' => $mistakeId,
  139. 'error' => $e->getMessage(),
  140. 'trace' => $e->getTraceAsString()
  141. ]);
  142. return response()->json([
  143. 'success' => false,
  144. 'message' => '获取错题详情失败: ' . $e->getMessage()
  145. ], 500);
  146. }
  147. }
  148. /**
  149. * 获取错题统计概要
  150. *
  151. * @param Request $request
  152. * @return JsonResponse
  153. */
  154. public function getSummary(Request $request): JsonResponse
  155. {
  156. try {
  157. $studentId = $request->get('student_id');
  158. if (!$studentId) {
  159. return response()->json([
  160. 'success' => false,
  161. 'message' => '缺少必要参数:student_id'
  162. ], 400);
  163. }
  164. $startTime = $request->get('start_time');
  165. $endTime = $request->get('end_time');
  166. // 构建查询参数
  167. $params = ['student_id' => $studentId];
  168. if ($startTime) {
  169. $params['start_time'] = $startTime;
  170. }
  171. if ($endTime) {
  172. $params['end_time'] = $endTime;
  173. }
  174. // 获取错题列表(用于计算统计信息)
  175. $mistakesResult = $this->mistakeBookService->listMistakes($params);
  176. // 获取概要统计
  177. $summary = $this->mistakeBookService->summarize($studentId);
  178. Log::info('获取错题概要统计成功', [
  179. 'student_id' => $studentId,
  180. 'total_mistakes' => $summary['total'] ?? 0
  181. ]);
  182. return response()->json([
  183. 'success' => true,
  184. 'data' => [
  185. 'total' => $summary['total'] ?? 0,
  186. 'this_week' => $summary['this_week'] ?? 0,
  187. 'pending_review' => $summary['pending_review'] ?? 0,
  188. 'mastery_rate' => $summary['mastery_rate'] ?? 0.0,
  189. 'statistics' => $mistakesResult['statistics'] ?? null
  190. ]
  191. ]);
  192. } catch (\Exception $e) {
  193. Log::error('获取错题概要统计失败', [
  194. 'student_id' => $request->get('student_id'),
  195. 'error' => $e->getMessage(),
  196. 'trace' => $e->getTraceAsString()
  197. ]);
  198. return response()->json([
  199. 'success' => false,
  200. 'message' => '获取错题概要统计失败: ' . $e->getMessage()
  201. ], 500);
  202. }
  203. }
  204. /**
  205. * 获取错误模式分析
  206. *
  207. * @param Request $request
  208. * @return JsonResponse
  209. */
  210. public function getMistakePatterns(Request $request): JsonResponse
  211. {
  212. try {
  213. $studentId = $request->get('student_id');
  214. if (!$studentId) {
  215. return response()->json([
  216. 'success' => false,
  217. 'message' => '缺少必要参数:student_id'
  218. ], 400);
  219. }
  220. $patterns = $this->mistakeBookService->getMistakePatterns($studentId);
  221. Log::info('获取错误模式分析成功', [
  222. 'student_id' => $studentId,
  223. 'top_kps_count' => count($patterns['top_kps'] ?? [])
  224. ]);
  225. return response()->json([
  226. 'success' => true,
  227. 'data' => $patterns
  228. ]);
  229. } catch (\Exception $e) {
  230. Log::error('获取错误模式分析失败', [
  231. 'student_id' => $request->get('student_id'),
  232. 'error' => $e->getMessage(),
  233. 'trace' => $e->getTraceAsString()
  234. ]);
  235. return response()->json([
  236. 'success' => false,
  237. 'message' => '获取错误模式分析失败: ' . $e->getMessage()
  238. ], 500);
  239. }
  240. }
  241. /**
  242. * 收藏/取消收藏错题
  243. *
  244. * @param string $mistakeId
  245. * @param Request $request
  246. * @return JsonResponse
  247. */
  248. public function toggleFavorite(string $mistakeId, Request $request): JsonResponse
  249. {
  250. try {
  251. $data = $request->only(['favorite']);
  252. $favorite = $data['favorite'] ?? true;
  253. $result = $this->mistakeBookService->toggleFavorite($mistakeId, $favorite);
  254. Log::info(($favorite ? '收藏' : '取消收藏') . '错题', [
  255. 'mistake_id' => $mistakeId,
  256. 'favorite' => $favorite,
  257. 'result' => $result
  258. ]);
  259. return response()->json([
  260. 'success' => $result,
  261. 'message' => $result ? '操作成功' : '操作失败',
  262. 'data' => [
  263. 'mistake_id' => $mistakeId,
  264. 'favorite' => $favorite
  265. ]
  266. ]);
  267. } catch (\Exception $e) {
  268. Log::error('收藏错题失败', [
  269. 'mistake_id' => $mistakeId,
  270. 'error' => $e->getMessage(),
  271. 'trace' => $e->getTraceAsString()
  272. ]);
  273. return response()->json([
  274. 'success' => false,
  275. 'message' => '收藏错题失败: ' . $e->getMessage()
  276. ], 500);
  277. }
  278. }
  279. /**
  280. * 标记错题已复习
  281. *
  282. * @param string $mistakeId
  283. * @return JsonResponse
  284. */
  285. public function markReviewed(string $mistakeId): JsonResponse
  286. {
  287. try {
  288. $result = $this->mistakeBookService->markReviewed($mistakeId);
  289. Log::info('标记错题已复习', [
  290. 'mistake_id' => $mistakeId,
  291. 'result' => $result
  292. ]);
  293. return response()->json([
  294. 'success' => $result,
  295. 'message' => $result ? '操作成功' : '操作失败',
  296. 'data' => [
  297. 'mistake_id' => $mistakeId,
  298. 'reviewed' => $result,
  299. 'reviewed_at' => $result ? now()->toISOString() : null
  300. ]
  301. ]);
  302. } catch (\Exception $e) {
  303. Log::error('标记错题已复习失败', [
  304. 'mistake_id' => $mistakeId,
  305. 'error' => $e->getMessage(),
  306. 'trace' => $e->getTraceAsString()
  307. ]);
  308. return response()->json([
  309. 'success' => false,
  310. 'message' => '标记错题已复习失败: ' . $e->getMessage()
  311. ], 500);
  312. }
  313. }
  314. /**
  315. * 加入重练清单
  316. *
  317. * @param string $mistakeId
  318. * @return JsonResponse
  319. */
  320. public function addToRetryList(string $mistakeId): JsonResponse
  321. {
  322. try {
  323. $result = $this->mistakeBookService->addToRetryList($mistakeId);
  324. Log::info('加入重练清单', [
  325. 'mistake_id' => $mistakeId,
  326. 'result' => $result
  327. ]);
  328. return response()->json([
  329. 'success' => $result,
  330. 'message' => $result ? '操作成功' : '操作失败',
  331. 'data' => [
  332. 'mistake_id' => $mistakeId,
  333. 'added' => $result
  334. ]
  335. ]);
  336. } catch (\Exception $e) {
  337. Log::error('加入重练清单失败', [
  338. 'mistake_id' => $mistakeId,
  339. 'error' => $e->getMessage(),
  340. 'trace' => $e->getTraceAsString()
  341. ]);
  342. return response()->json([
  343. 'success' => false,
  344. 'message' => '加入重练清单失败: ' . $e->getMessage()
  345. ], 500);
  346. }
  347. }
  348. /**
  349. * 获取题目正确率
  350. *
  351. * @param string $questionId
  352. * @return JsonResponse
  353. */
  354. public function getQuestionAccuracy(string $questionId): JsonResponse
  355. {
  356. try {
  357. $accuracy = $this->mistakeBookService->getQuestionAccuracy($questionId);
  358. Log::info('获取题目正确率成功', [
  359. 'question_id' => $questionId,
  360. 'accuracy' => $accuracy
  361. ]);
  362. return response()->json([
  363. 'success' => true,
  364. 'data' => [
  365. 'question_id' => $questionId,
  366. 'accuracy' => $accuracy,
  367. 'correct_attempts' => null // LearningAnalytics不返回具体次数
  368. ]
  369. ]);
  370. } catch (\Exception $e) {
  371. Log::error('获取题目正确率失败', [
  372. 'question_id' => $questionId,
  373. 'error' => $e->getMessage(),
  374. 'trace' => $e->getTraceAsString()
  375. ]);
  376. return response()->json([
  377. 'success' => false,
  378. 'message' => '获取题目正确率失败: ' . $e->getMessage()
  379. ], 500);
  380. }
  381. }
  382. /**
  383. * 推荐练习题
  384. *
  385. * @param Request $request
  386. * @return JsonResponse
  387. */
  388. public function recommendPractice(Request $request): JsonResponse
  389. {
  390. try {
  391. $studentId = $request->get('student_id');
  392. $kpIds = $request->get('kp_ids', []);
  393. $skillIds = $request->get('skill_ids', []);
  394. if (!$studentId) {
  395. return response()->json([
  396. 'success' => false,
  397. 'message' => '缺少必要参数:student_id'
  398. ], 400);
  399. }
  400. $recommendations = $this->mistakeBookService->recommendPractice(
  401. $studentId,
  402. $kpIds,
  403. $skillIds
  404. );
  405. Log::info('获取推荐练习题成功', [
  406. 'student_id' => $studentId,
  407. 'kp_ids' => $kpIds,
  408. 'recommendations_count' => count($recommendations['data'] ?? [])
  409. ]);
  410. return response()->json([
  411. 'success' => true,
  412. 'data' => $recommendations['data'] ?? []
  413. ]);
  414. } catch (\Exception $e) {
  415. Log::error('获取推荐练习题失败', [
  416. 'student_id' => $request->get('student_id'),
  417. 'error' => $e->getMessage(),
  418. 'trace' => $e->getTraceAsString()
  419. ]);
  420. return response()->json([
  421. 'success' => false,
  422. 'message' => '获取推荐练习题失败: ' . $e->getMessage()
  423. ], 500);
  424. }
  425. }
  426. /**
  427. * 获取错题本快照数据(用于仪表板)
  428. *
  429. * @param Request $request
  430. * @return JsonResponse
  431. */
  432. public function getSnapshot(Request $request): JsonResponse
  433. {
  434. try {
  435. $studentId = $request->get('student_id');
  436. $limit = (int) ($request->get('limit', 5));
  437. if (!$studentId) {
  438. return response()->json([
  439. 'success' => false,
  440. 'message' => '缺少必要参数:student_id'
  441. ], 400);
  442. }
  443. $snapshot = $this->mistakeBookService->getPanelSnapshot($studentId, $limit);
  444. Log::info('获取错题本快照数据成功', [
  445. 'student_id' => $studentId,
  446. 'limit' => $limit,
  447. 'recent_count' => count($snapshot['recent'] ?? [])
  448. ]);
  449. return response()->json([
  450. 'success' => true,
  451. 'data' => $snapshot
  452. ]);
  453. } catch (\Exception $e) {
  454. Log::error('获取错题本快照数据失败', [
  455. 'student_id' => $request->get('student_id'),
  456. 'error' => $e->getMessage(),
  457. 'trace' => $e->getTraceAsString()
  458. ]);
  459. return response()->json([
  460. 'success' => false,
  461. 'message' => '获取错题本快照数据失败: ' . $e->getMessage()
  462. ], 500);
  463. }
  464. }
  465. /**
  466. * 修改错题复习状态
  467. */
  468. public function updateReviewStatus(Request $request, string $mistakeId): JsonResponse
  469. {
  470. try {
  471. $validated = $request->validate([
  472. 'action' => 'required|in:increment,reset,mastered',
  473. 'force_review' => 'boolean',
  474. ]);
  475. $action = $validated['action'];
  476. $forceReview = $validated['force_review'] ?? false;
  477. $result = $this->mistakeBookService->updateReviewStatus($mistakeId, $action, $forceReview);
  478. if ($result['success'] ?? false) {
  479. return response()->json([
  480. 'success' => true,
  481. 'data' => $result,
  482. 'message' => $result['message'] ?? '复习状态更新成功',
  483. ]);
  484. }
  485. return response()->json([
  486. 'success' => false,
  487. 'message' => $result['error'] ?? '更新复习状态失败',
  488. ], 400);
  489. } catch (\Throwable $e) {
  490. Log::error('Update review status error', [
  491. 'mistake_id' => $mistakeId,
  492. 'error' => $e->getMessage(),
  493. ]);
  494. return response()->json([
  495. 'success' => false,
  496. 'message' => '更新复习状态失败',
  497. 'error' => $e->getMessage(),
  498. ], 500);
  499. }
  500. }
  501. /**
  502. * 获取错题复习状态
  503. */
  504. public function getReviewStatus(string $mistakeId): JsonResponse
  505. {
  506. try {
  507. $result = $this->mistakeBookService->getReviewStatus($mistakeId);
  508. if ($result['success'] ?? false) {
  509. return response()->json([
  510. 'success' => true,
  511. 'data' => $result,
  512. ]);
  513. }
  514. return response()->json([
  515. 'success' => false,
  516. 'message' => $result['error'] ?? '获取复习状态失败',
  517. ], 400);
  518. } catch (\Throwable $e) {
  519. Log::error('Get review status error', [
  520. 'mistake_id' => $mistakeId,
  521. 'error' => $e->getMessage(),
  522. ]);
  523. return response()->json([
  524. 'success' => false,
  525. 'message' => '获取复习状态失败',
  526. 'error' => $e->getMessage(),
  527. ], 500);
  528. }
  529. }
  530. /**
  531. * 增加复习次数
  532. */
  533. public function incrementReview(Request $request, string $mistakeId): JsonResponse
  534. {
  535. try {
  536. $validated = $request->validate([
  537. 'force_review' => 'boolean',
  538. ]);
  539. $forceReview = $validated['force_review'] ?? false;
  540. $result = $this->mistakeBookService->incrementReviewCount($mistakeId, $forceReview);
  541. if ($result['success'] ?? false) {
  542. return response()->json([
  543. 'success' => true,
  544. 'data' => $result,
  545. 'message' => $result['message'] ?? '复习次数增加成功',
  546. ]);
  547. }
  548. return response()->json([
  549. 'success' => false,
  550. 'message' => $result['error'] ?? '增加复习次数失败',
  551. ], 400);
  552. } catch (\Throwable $e) {
  553. Log::error('Increment review count error', [
  554. 'mistake_id' => $mistakeId,
  555. 'error' => $e->getMessage(),
  556. ]);
  557. return response()->json([
  558. 'success' => false,
  559. 'message' => '增加复习次数失败',
  560. 'error' => $e->getMessage(),
  561. ], 500);
  562. }
  563. }
  564. /**
  565. * 重置为强制复习状态
  566. */
  567. public function resetReview(string $mistakeId): JsonResponse
  568. {
  569. try {
  570. $result = $this->mistakeBookService->resetReviewStatus($mistakeId);
  571. if ($result['success'] ?? false) {
  572. return response()->json([
  573. 'success' => true,
  574. 'data' => $result,
  575. 'message' => $result['message'] ?? '复习状态重置成功',
  576. ]);
  577. }
  578. return response()->json([
  579. 'success' => false,
  580. 'message' => $result['error'] ?? '重置复习状态失败',
  581. ], 400);
  582. } catch (\Throwable $e) {
  583. Log::error('Reset review status error', [
  584. 'mistake_id' => $mistakeId,
  585. 'error' => $e->getMessage(),
  586. ]);
  587. return response()->json([
  588. 'success' => false,
  589. 'message' => '重置复习状态失败',
  590. 'error' => $e->getMessage(),
  591. ], 500);
  592. }
  593. }
  594. /**
  595. * 批量操作错题
  596. */
  597. public function batchOperation(Request $request): JsonResponse
  598. {
  599. try {
  600. $validated = $request->validate([
  601. 'mistake_ids' => 'required|array|min:1',
  602. 'mistake_ids.*' => 'string',
  603. 'operation' => 'required|string|in:favorite,reviewed,mastered,retry_list,remove_retry_list,set_error_type,set_importance',
  604. 'params' => 'array',
  605. ]);
  606. $mistakeIds = $validated['mistake_ids'];
  607. $operation = $validated['operation'];
  608. $params = $validated['params'] ?? [];
  609. $result = $this->mistakeBookService->batchOperation($mistakeIds, $operation, $params);
  610. if ($result['success'] ?? false) {
  611. return response()->json([
  612. 'success' => true,
  613. 'data' => $result,
  614. 'message' => "批量操作成功,成功处理 {$result['success_count']} 条记录",
  615. ]);
  616. }
  617. return response()->json([
  618. 'success' => false,
  619. 'message' => $result['error'] ?? '批量操作失败',
  620. ], 400);
  621. } catch (\Throwable $e) {
  622. Log::error('Batch operation error', [
  623. 'error' => $e->getMessage(),
  624. 'request' => $request->all(),
  625. ]);
  626. return response()->json([
  627. 'success' => false,
  628. 'message' => '批量操作失败',
  629. 'error' => $e->getMessage(),
  630. ], 500);
  631. }
  632. }
  633. /**
  634. * 批量标记为已复习
  635. */
  636. public function batchMarkReviewed(Request $request): JsonResponse
  637. {
  638. $validated = $request->validate([
  639. 'mistake_ids' => 'required|array|min:1',
  640. 'mistake_ids.*' => 'string',
  641. ]);
  642. $result = $this->mistakeBookService->batchOperation(
  643. $validated['mistake_ids'],
  644. 'reviewed'
  645. );
  646. return response()->json([
  647. 'success' => $result['success'] ?? false,
  648. 'data' => $result,
  649. 'message' => $result['success'] ?? false
  650. ? "已标记 {$result['success_count']} 道题为已复习"
  651. : ($result['error'] ?? '操作失败'),
  652. ]);
  653. }
  654. /**
  655. * 批量标记为已掌握
  656. */
  657. public function batchMarkMastered(Request $request): JsonResponse
  658. {
  659. $validated = $request->validate([
  660. 'mistake_ids' => 'required|array|min:1',
  661. 'mistake_ids.*' => 'string',
  662. ]);
  663. $result = $this->mistakeBookService->batchOperation(
  664. $validated['mistake_ids'],
  665. 'mastered'
  666. );
  667. return response()->json([
  668. 'success' => $result['success'] ?? false,
  669. 'data' => $result,
  670. 'message' => $result['success'] ?? false
  671. ? "已标记 {$result['success_count']} 道题为已掌握"
  672. : ($result['error'] ?? '操作失败'),
  673. ]);
  674. }
  675. /**
  676. * 批量加入重练清单
  677. */
  678. public function batchAddToRetryList(Request $request): JsonResponse
  679. {
  680. $validated = $request->validate([
  681. 'mistake_ids' => 'required|array|min:1',
  682. 'mistake_ids.*' => 'string',
  683. ]);
  684. $result = $this->mistakeBookService->batchOperation(
  685. $validated['mistake_ids'],
  686. 'retry_list'
  687. );
  688. return response()->json([
  689. 'success' => $result['success'] ?? false,
  690. 'data' => $result,
  691. 'message' => $result['success'] ?? false
  692. ? "已加入 {$result['success_count']} 道题到重练清单"
  693. : ($result['error'] ?? '操作失败'),
  694. ]);
  695. }
  696. /**
  697. * 批量从重练清单移除
  698. */
  699. public function batchRemoveFromRetryList(Request $request): JsonResponse
  700. {
  701. $validated = $request->validate([
  702. 'mistake_ids' => 'required|array|min:1',
  703. 'mistake_ids.*' => 'string',
  704. ]);
  705. $result = $this->mistakeBookService->batchOperation(
  706. $validated['mistake_ids'],
  707. 'remove_retry_list'
  708. );
  709. return response()->json([
  710. 'success' => $result['success'] ?? false,
  711. 'data' => $result,
  712. 'message' => $result['success'] ?? false
  713. ? "已从重练清单移除 {$result['success_count']} 道题"
  714. : ($result['error'] ?? '操作失败'),
  715. ]);
  716. }
  717. /**
  718. * 批量设置错误类型
  719. */
  720. public function batchSetErrorType(Request $request): JsonResponse
  721. {
  722. $validated = $request->validate([
  723. 'mistake_ids' => 'required|array|min:1',
  724. 'mistake_ids.*' => 'string',
  725. 'error_type' => 'required|string|in:concept,calculation,careless,logic,other',
  726. ]);
  727. $result = $this->mistakeBookService->batchOperation(
  728. $validated['mistake_ids'],
  729. 'set_error_type',
  730. ['error_type' => $validated['error_type']]
  731. );
  732. return response()->json([
  733. 'success' => $result['success'] ?? false,
  734. 'data' => $result,
  735. 'message' => $result['success'] ?? false
  736. ? "已为 {$result['success_count']} 道题设置错误类型"
  737. : ($result['error'] ?? '操作失败'),
  738. ]);
  739. }
  740. /**
  741. * 批量设置重要程度
  742. */
  743. public function batchSetImportance(Request $request): JsonResponse
  744. {
  745. $validated = $request->validate([
  746. 'mistake_ids' => 'required|array|min:1',
  747. 'mistake_ids.*' => 'string',
  748. 'importance' => 'required|integer|min:1|max:10',
  749. ]);
  750. $result = $this->mistakeBookService->batchOperation(
  751. $validated['mistake_ids'],
  752. 'set_importance',
  753. ['importance' => $validated['importance']]
  754. );
  755. return response()->json([
  756. 'success' => $result['success'] ?? false,
  757. 'data' => $result,
  758. 'message' => $result['success'] ?? false
  759. ? "已为 {$result['success_count']} 道题设置重要程度"
  760. : ($result['error'] ?? '操作失败'),
  761. ]);
  762. }
  763. /**
  764. * 批量切换收藏状态
  765. */
  766. public function batchToggleFavorite(Request $request): JsonResponse
  767. {
  768. $validated = $request->validate([
  769. 'mistake_ids' => 'required|array|min:1',
  770. 'mistake_ids.*' => 'string',
  771. ]);
  772. $result = $this->mistakeBookService->batchOperation(
  773. $validated['mistake_ids'],
  774. 'favorite'
  775. );
  776. return response()->json([
  777. 'success' => $result['success'] ?? false,
  778. 'data' => $result,
  779. 'message' => $result['success'] ?? false
  780. ? "已为 {$result['success_count']} 道题切换收藏状态"
  781. : ($result['error'] ?? '操作失败'),
  782. ]);
  783. }
  784. }