ExamHistory.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <?php
  2. namespace App\Filament\Pages;
  3. use App\Services\QuestionBankService;
  4. use BackedEnum;
  5. use Filament\Notifications\Notification;
  6. use Filament\Pages\Page;
  7. use UnitEnum;
  8. use Livewire\Attributes\Computed;
  9. class ExamHistory extends Page
  10. {
  11. protected static ?string $title = '卷子历史记录';
  12. protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-document-duplicate';
  13. protected static ?string $navigationLabel = '卷子历史';
  14. protected static string|UnitEnum|null $navigationGroup = '管理';
  15. protected static ?int $navigationSort = 3;
  16. protected string $view = 'filament.pages.exam-history-simple';
  17. // 分页
  18. public int $currentPage = 1;
  19. public int $perPage = 20;
  20. // 筛选
  21. public ?string $search = null;
  22. public ?string $statusFilter = null;
  23. public ?string $difficultyFilter = null;
  24. // 详情
  25. public ?string $selectedExamId = null;
  26. public array $selectedExamDetail = [];
  27. #[Computed(cache: false)]
  28. public function exams(): array
  29. {
  30. try {
  31. // 从本地数据库读取试卷列表 - 使用 papers 表
  32. $query = \App\Models\Paper::query();
  33. // 应用搜索过滤
  34. if ($this->search) {
  35. $query->where('paper_name', 'like', '%' . $this->search . '%');
  36. }
  37. // 应用状态过滤
  38. if ($this->statusFilter) {
  39. $query->where('status', $this->statusFilter);
  40. }
  41. // 应用难度过滤
  42. if ($this->difficultyFilter) {
  43. $query->where('difficulty_category', $this->difficultyFilter);
  44. }
  45. // 分页
  46. $total = $query->count();
  47. $papers = $query->orderBy('created_at', 'desc')
  48. ->skip(($this->currentPage - 1) * $this->perPage)
  49. ->take($this->perPage)
  50. ->get()
  51. ->map(function ($paper) {
  52. return [
  53. 'id' => $paper->paper_id,
  54. 'paper_name' => $paper->paper_name,
  55. 'question_count' => $paper->question_count,
  56. 'total_score' => $paper->total_score,
  57. 'difficulty_category' => $paper->difficulty_category,
  58. 'status' => $paper->status,
  59. 'created_at' => $paper->created_at,
  60. ];
  61. })
  62. ->toArray();
  63. return [
  64. 'data' => $papers,
  65. 'meta' => [
  66. 'page' => $this->currentPage,
  67. 'per_page' => $this->perPage,
  68. 'total' => $total,
  69. 'total_pages' => ceil($total / $this->perPage),
  70. ]
  71. ];
  72. } catch (\Exception $e) {
  73. \Illuminate\Support\Facades\Log::error('获取试卷列表失败', ['error' => $e->getMessage()]);
  74. return [
  75. 'data' => [],
  76. 'meta' => ['page' => 1, 'per_page' => 20, 'total' => 0, 'total_pages' => 0]
  77. ];
  78. }
  79. }
  80. #[Computed(cache: false)]
  81. public function meta(): array
  82. {
  83. $examsData = $this->exams();
  84. return $examsData['meta'] ?? ['page' => 1, 'per_page' => 20, 'total' => 0, 'total_pages' => 0];
  85. }
  86. public function updatedCurrentPage()
  87. {
  88. $this->reset('selectedExamId', 'selectedExamDetail');
  89. }
  90. public function viewExamDetail(string $examId)
  91. {
  92. $this->selectedExamId = $examId;
  93. $this->loadExamDetail();
  94. }
  95. protected function loadExamDetail()
  96. {
  97. if (!$this->selectedExamId) {
  98. return;
  99. }
  100. $questionBankService = app(QuestionBankService::class);
  101. $this->selectedExamDetail = $questionBankService->getExamById($this->selectedExamId) ?? [];
  102. }
  103. public function exportPdf(string $examId)
  104. {
  105. $questionBankService = app(QuestionBankService::class);
  106. $pdfUrl = $questionBankService->exportExamToPdf($examId);
  107. if ($pdfUrl) {
  108. // TODO: 实际下载PDF
  109. Notification::make()
  110. ->title('PDF导出成功')
  111. ->body('试卷已导出为PDF格式')
  112. ->success()
  113. ->send();
  114. } else {
  115. Notification::make()
  116. ->title('PDF导出失败')
  117. ->body('无法导出试卷,请稍后重试')
  118. ->danger()
  119. ->send();
  120. }
  121. }
  122. public function duplicateExam(array $examData)
  123. {
  124. // 复制试卷配置,用于快速生成类似试卷
  125. $learningService = app(\App\Services\LearningAnalyticsService::class);
  126. // 提取试卷配置
  127. $examConfig = [
  128. 'paper_name' => $examData['paper_name'] . ' (副本)',
  129. 'total_questions' => $examData['question_count'],
  130. 'difficulty_category' => $examData['difficulty_category'] ?? '基础',
  131. 'question_type_ratio' => [
  132. '选择题' => 40,
  133. '填空题' => 30,
  134. '解答题' => 30,
  135. ],
  136. 'difficulty_ratio' => [
  137. '基础' => 50,
  138. '中等' => 35,
  139. '拔高' => 15,
  140. ],
  141. ];
  142. // TODO: 跳转到智能出卷页面并预填充配置
  143. // 这里可以通过session传递配置,或者使用URL参数
  144. Notification::make()
  145. ->title('试卷配置已复制')
  146. ->body('请前往智能出卷页面查看并使用该配置')
  147. ->success()
  148. ->send();
  149. }
  150. public function deleteExam(string $examId)
  151. {
  152. // TODO: 实现删除试卷功能
  153. // 需要在QuestionBankService中添加deleteExam方法
  154. Notification::make()
  155. ->title('删除成功')
  156. ->body('试卷记录已删除')
  157. ->success()
  158. ->send();
  159. $this->reset('selectedExamId', 'selectedExamDetail');
  160. }
  161. public function getStatusColor(string $status): string
  162. {
  163. return match($status) {
  164. 'draft' => 'ghost',
  165. 'completed' => 'success',
  166. 'graded' => 'primary',
  167. default => 'ghost',
  168. };
  169. }
  170. public function getStatusLabel(string $status): string
  171. {
  172. return match($status) {
  173. 'draft' => '草稿',
  174. 'completed' => '已完成',
  175. 'graded' => '已评分',
  176. default => '未知',
  177. };
  178. }
  179. public function getDifficultyColor(string $difficulty): string
  180. {
  181. return match($difficulty) {
  182. '基础' => 'success',
  183. '进阶' => 'warning',
  184. '竞赛' => 'error',
  185. default => 'ghost',
  186. };
  187. }
  188. }