GradingPanel.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <?php
  2. namespace App\Livewire\UploadExam;
  3. use Livewire\Component;
  4. use App\Services\ExamPaperService;
  5. use Filament\Notifications\Notification;
  6. use Livewire\Attributes\On;
  7. class GradingPanel extends Component
  8. {
  9. public ?string $teacherId = null;
  10. public ?string $studentId = null;
  11. public ?string $selectedPaperId = null;
  12. public array $questions = [];
  13. public array $gradingData = [];
  14. public array $questionGrades = []; // 添加这个属性
  15. public ?string $paperName = null;
  16. public ?string $paperClass = null;
  17. public ?string $paperStudent = null;
  18. public ?string $paperDate = null;
  19. public bool $showGrading = false; // 添加这个属性
  20. protected $listeners = [
  21. 'loadPaper' => 'loadPaper',
  22. 'submitManualGrading' => 'handleSubmitFromParent',
  23. ];
  24. // 接收从父组件传递的参数
  25. public function mount(
  26. ?string $teacherId = null,
  27. ?string $studentId = null,
  28. ?string $selectedPaperId = null,
  29. array $questions = []
  30. ): void {
  31. $this->teacherId = $teacherId;
  32. $this->studentId = $studentId;
  33. $this->selectedPaperId = $selectedPaperId;
  34. $this->questions = $questions;
  35. // 如果传入了题目,初始化评分数据
  36. if (!empty($questions)) {
  37. $this->initializeGradingData();
  38. }
  39. }
  40. #[On('loadPaper')]
  41. public function loadPaper(string $paperId, string $teacherId, string $studentId): void
  42. {
  43. $this->selectedPaperId = $paperId;
  44. $this->teacherId = $teacherId;
  45. $this->studentId = $studentId;
  46. }
  47. public function updatedSelectedPaperId($value): void
  48. {
  49. if (!empty($value)) {
  50. // 清空评分数据
  51. $this->gradingData = [];
  52. $this->loadPaperForGrading($value);
  53. } else {
  54. $this->questions = [];
  55. $this->gradingData = [];
  56. $this->showGrading = false;
  57. }
  58. }
  59. public function setChoiceAnswer(int $index, bool $isCorrect)
  60. {
  61. if (!isset($this->gradingData[$index])) {
  62. $this->gradingData[$index] = [];
  63. }
  64. $this->gradingData[$index]['is_correct'] = $isCorrect;
  65. // 选择题自动计算分数
  66. if ($isCorrect && isset($this->questions[$index]['score'])) {
  67. $this->gradingData[$index]['score'] = $this->questions[$index]['score'];
  68. } else {
  69. $this->gradingData[$index]['score'] = 0;
  70. }
  71. }
  72. public function resetGrading()
  73. {
  74. $this->gradingData = array_fill(0, count($this->questions), ['score' => null, 'is_correct' => null]);
  75. Notification::make()
  76. ->title('已重置评分')
  77. ->success()
  78. ->send();
  79. }
  80. public function submitGrading()
  81. {
  82. try {
  83. // 数据验证和处理
  84. $this->convertGradingDataToQuestionGrades();
  85. \Log::info('GradingPanel: 转换后的评分数据', [
  86. 'questionGrades' => $this->questionGrades
  87. ]);
  88. if (empty($this->questionGrades)) {
  89. Notification::make()
  90. ->title('请至少为一道题目评分')
  91. ->danger()
  92. ->send();
  93. return;
  94. }
  95. // dispatch 事件让父页面处理提交
  96. $this->dispatch('submitManualGrading',
  97. questionGrades: $this->questionGrades,
  98. gradingData: $this->gradingData,
  99. questions: $this->questions
  100. );
  101. } catch (\Exception $e) {
  102. \Log::error('GradingPanel: 提交失败', [
  103. 'error' => $e->getMessage(),
  104. 'trace' => $e->getTraceAsString()
  105. ]);
  106. Notification::make()
  107. ->title('提交失败')
  108. ->body($e->getMessage())
  109. ->danger()
  110. ->send();
  111. }
  112. }
  113. private function convertGradingDataToQuestionGrades()
  114. {
  115. $this->questionGrades = [];
  116. foreach ($this->questions as $index => $question) {
  117. $grading = $this->gradingData[$index] ?? null;
  118. // 检查 grading 数据是否存在且有评分信息
  119. if ($grading && (
  120. (isset($grading['is_correct']) && $grading['is_correct'] !== null) ||
  121. (isset($grading['score']) && $grading['score'] !== null)
  122. )) {
  123. $questionId = $question['id'];
  124. // 处理评分数据...
  125. $this->questionGrades[$questionId] = [
  126. 'is_correct' => $grading['is_correct'] ?? null,
  127. 'score' => $grading['score'] ?? null,
  128. 'student_answer' => '',
  129. ];
  130. }
  131. }
  132. }
  133. public function render()
  134. {
  135. return view('livewire.upload-exam.grading-panel');
  136. }
  137. public function loadPaperForGrading($paperId): void
  138. {
  139. try {
  140. $paper = \App\Models\Paper::where('paper_id', $paperId)->first();
  141. if (!$paper) {
  142. Notification::make()
  143. ->title('试卷不存在')
  144. ->danger()
  145. ->send();
  146. return;
  147. }
  148. // 设置试卷信息
  149. $this->paperName = $paper->paper_name;
  150. $this->paperClass = $paper->difficulty_category ?? '未设置';
  151. $this->paperStudent = $paper->student_id;
  152. $this->paperDate = $paper->created_at->format('Y-m-d H:i');
  153. // 使用 Service 加载题目
  154. $questions = app(ExamPaperService::class)->getPaperQuestions($paperId);
  155. // 转换 Service 返回的题目格式以适配 GradingPanel 的视图
  156. // Service 返回的格式:
  157. // [
  158. // 'id' => $q->id,
  159. // 'question_number' => $q->question_number,
  160. // 'question_bank_id' => $q->question_bank_id,
  161. // 'question_type' => $q->question_type,
  162. // 'content' => $detail['stem'] ?? '题目内容缺失',
  163. // 'answer' => $detail['answer'] ?? '',
  164. // 'score' => $q->score ?? 5,
  165. // 'kp_code' => $q->knowledge_point,
  166. // ]
  167. $this->questions = collect($questions)->map(function($q) {
  168. // 如果是特殊信息行(如 no_questions, missing_data),直接返回
  169. if (isset($q['is_empty']) || isset($q['is_missing_data']) || isset($q['is_error'])) {
  170. return $q;
  171. }
  172. return [
  173. 'id' => $q['id'],
  174. 'question_number' => $q['question_number'],
  175. 'question_type' => $q['question_type'],
  176. 'question_text' => $q['content'], // 视图可能使用 question_text
  177. 'content' => $q['content'],
  178. 'options' => [], // 暂时留空,如果需要选项显示需要从 Service 获取更多详情
  179. 'answer' => $q['answer'],
  180. 'correct_answer' => $q['answer'],
  181. 'student_answer' => '',
  182. 'score' => $q['score'],
  183. 'max_score' => $q['score'],
  184. 'question_bank_id' => $q['question_bank_id'],
  185. 'is_empty' => false
  186. ];
  187. })->toArray();
  188. $this->initializeGradingData();
  189. $this->showGrading = true;
  190. } catch (\Exception $e) {
  191. \Log::error('加载试卷题目失败', [
  192. 'paper_id' => $paperId,
  193. 'error' => $e->getMessage()
  194. ]);
  195. Notification::make()
  196. ->title('加载失败')
  197. ->body($e->getMessage())
  198. ->danger()
  199. ->send();
  200. }
  201. }
  202. private function initializeGradingData()
  203. {
  204. $this->gradingData = array_fill(0, count($this->questions), ['score' => null, 'is_correct' => null, 'comment' => '']);
  205. }
  206. }