exam-history.blade.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <x-filament-panels::page>
  2. @push('styles')
  3. <style>
  4. .exam-card {
  5. transition: all 0.3s ease;
  6. }
  7. .exam-card:hover {
  8. transform: translateY(-2px);
  9. box-shadow: 0 8px 20px rgba(0,0,0,0.12);
  10. }
  11. .status-badge {
  12. display: inline-block;
  13. padding: 4px 12px;
  14. border-radius: 12px;
  15. font-size: 12px;
  16. font-weight: 500;
  17. }
  18. </style>
  19. @endpush
  20. <div class="space-y-6">
  21. <!-- 页面标题 -->
  22. <div class="flex justify-between items-center">
  23. <div>
  24. <h2 class="text-2xl font-bold text-gray-900">卷子历史记录</h2>
  25. <p class="mt-1 text-sm text-gray-500">
  26. 查看所有历史生成的试卷,支持导出、复制和删除操作
  27. </p>
  28. </div>
  29. </div>
  30. <!-- 筛选器 -->
  31. <x-filament::card>
  32. <div class="grid grid-cols-1 md:grid-cols-4 gap-4">
  33. <input
  34. wire:model.live="search"
  35. placeholder="搜索试卷名称..."
  36. icon="heroicon-m-magnifying-glass"
  37. />
  38. <select
  39. wire:model.live="statusFilter"
  40. placeholder="筛选状态"
  41. >
  42. <option value="">-- 全部状态 --</option>
  43. <option value="draft">草稿</option>
  44. <option value="completed">已完成</option>
  45. <option value="graded">已评分</option>
  46. /select>
  47. <select
  48. wire:model.live="difficultyFilter"
  49. placeholder="筛选难度"
  50. >
  51. <option value="">-- 全部难度 --</option>
  52. <option value="基础">基础</option>
  53. <option value="进阶">进阶</option>
  54. <option value="竞赛">竞赛</option>
  55. /select>
  56. button
  57. color="gray"
  58. wire:click="reset"
  59. >
  60. <x-heroicon-m-arrow-path class="w-5 h-5 mr-2" />
  61. 重置
  62. /button>
  63. </div>
  64. </x-filament::card>
  65. <!-- 试卷列表 -->
  66. <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
  67. <!-- 左侧:试卷列表 -->
  68. <div class="lg:col-span-2 space-y-4">
  69. @if(count($this->exams()['data']) > 0)
  70. @foreach($this->exams()['data'] as $exam)
  71. <x-filament::card class="exam-card cursor-pointer" wire:click="viewExamDetail('{{ $exam['paper_id'] }}')">
  72. <div class="flex items-start justify-between">
  73. <div class="flex-1">
  74. <div class="flex items-center gap-3 mb-2">
  75. <h3 class="text-lg font-semibold text-gray-900">{{ $exam['paper_name'] }}</h3>
  76. <span class="status-badge" style="background: {{ getStatusColor($exam['status']) }}20; color: {{ getStatusColor($exam['status']) }};">
  77. {{ getStatusLabel($exam['status']) }}
  78. </span>
  79. </div>
  80. <div class="grid grid-cols-3 gap-4 text-sm text-gray-600">
  81. <div>
  82. <span class="text-gray-500">题目数量:</span>
  83. <span class="font-medium">{{ $exam['question_count'] }} 题</span>
  84. </div>
  85. <div>
  86. <span class="text-gray-500">总分:</span>
  87. <span class="font-medium">{{ $exam['total_score'] }} 分</span>
  88. </div>
  89. <div>
  90. <span class="text-gray-500">难度:</span>
  91. <span class="px-2 py-0.5 rounded text-white text-xs" style="background: {{ getDifficultyColor($exam['difficulty_category']) }};">
  92. {{ $exam['difficulty_category'] }}
  93. </span>
  94. </div>
  95. </div>
  96. <div class="mt-3 text-xs text-gray-500">
  97. <span>创建时间:{{ \Carbon\Carbon::parse($exam['created_at'])->format('Y-m-d H:i') }}</span>
  98. </div>
  99. </div>
  100. <div class="flex flex-col gap-2 ml-4">
  101. button
  102. color="primary"
  103. size="sm"
  104. wire:click.stop="exportPdf('{{ $exam['paper_id'] }}')"
  105. >
  106. <x-heroicon-m-arrow-down-tray class="w-4 h-4 mr-1" />
  107. 导出
  108. /button>
  109. button
  110. color="gray"
  111. size="sm"
  112. wire:click.stop="duplicateExam({{ json_encode($exam) }})"
  113. >
  114. <x-heroicon-m-document-duplicate class="w-4 h-4 mr-1" />
  115. 复制
  116. /button>
  117. </div>
  118. </div>
  119. </x-filament::card>
  120. @endforeach
  121. <!-- 分页 -->
  122. <div class="mt-6">
  123. {{ $this->meta()['total'] }} 条记录,共 {{ $this->meta()['total_pages'] }} 页
  124. <div class="mt-4 flex justify-center">
  125. <div class="flex gap-2">
  126. @if($currentPage > 1)
  127. button
  128. color="gray"
  129. size="sm"
  130. wire:click="$set('currentPage', {{ $currentPage - 1 }})"
  131. >
  132. 上一页
  133. /button>
  134. @endif
  135. <span class="px-4 py-2 text-sm text-gray-600">
  136. 第 {{ $currentPage }} 页
  137. </span>
  138. @if($currentPage < $this->meta()['total_pages'])
  139. button
  140. color="gray"
  141. size="sm"
  142. wire:click="$set('currentPage', {{ $currentPage + 1 }})"
  143. >
  144. 下一页
  145. /button>
  146. @endif
  147. </div>
  148. </div>
  149. </div>
  150. @else
  151. <x-filament::card class="text-center py-12">
  152. <x-heroicon-o-document-duplicate class="w-16 h-16 text-gray-400 mx-auto mb-4" />
  153. <div class="text-lg font-medium text-gray-900 mb-2">暂无试卷记录</div>
  154. <div class="text-sm text-gray-500 mb-4">
  155. 请前往"智能出卷"页面生成您的第一份试卷
  156. </div>
  157. button
  158. color="primary"
  159. wire:click="$dispatch('navigateToIntelligentExam')"
  160. >
  161. <x-heroicon-m-sparkles class="w-5 h-5 mr-2" />
  162. 去出卷
  163. /button>
  164. </x-filament::card>
  165. @endif
  166. </div>
  167. <!-- 右侧:试卷详情 -->
  168. <div class="lg:col-span-1">
  169. @if($selectedExamId && !empty($selectedExamDetail))
  170. <x-filament::card sticky>
  171. <x-slot name="header">
  172. <div class="flex items-center justify-between">
  173. <h3 class="text-lg font-semibold text-gray-900">试卷详情</h3>
  174. button
  175. color="gray"
  176. size="sm"
  177. wire:click="$set('selectedExamId', null)"
  178. >
  179. <x-heroicon-o-x-mark class="w-4 h-4" />
  180. /button>
  181. </div>
  182. </x-slot>
  183. <div class="space-y-4">
  184. <div>
  185. <div class="text-sm text-gray-500">试卷名称</div>
  186. <div class="font-medium text-gray-900">{{ $selectedExamDetail['paper']['paper_name'] ?? '' }}</div>
  187. </div>
  188. <div class="grid grid-cols-2 gap-4">
  189. <div>
  190. <div class="text-sm text-gray-500">题目数量</div>
  191. <div class="font-medium text-gray-900">{{ $selectedExamDetail['paper']['question_count'] ?? 0 }} 题</div>
  192. </div>
  193. <div>
  194. <div class="text-sm text-gray-500">总分</div>
  195. <div class="font-medium text-gray-900">{{ $selectedExamDetail['paper']['total_score'] ?? 0 }} 分</div>
  196. </div>
  197. </div>
  198. <div>
  199. <div class="text-sm text-gray-500">难度分类</div>
  200. <div class="mt-1">
  201. <span class="px-2 py-0.5 rounded text-white text-xs" style="background: {{ getDifficultyColor($selectedExamDetail['paper']['difficulty_category'] ?? '') }};">
  202. {{ $selectedExamDetail['paper']['difficulty_category'] ?? '' }}
  203. </span>
  204. </div>
  205. </div>
  206. <div>
  207. <div class="text-sm text-gray-500">创建时间</div>
  208. <div class="font-medium text-gray-900">
  209. {{ \Carbon\Carbon::parse($selectedExamDetail['paper']['created_at'])->format('Y-m-d H:i') }}
  210. </div>
  211. </div>
  212. <div>
  213. <div class="text-sm text-gray-500 mb-2">题目列表</div>
  214. <div class="space-y-2 max-h-64 overflow-y-auto">
  215. @foreach($selectedExamDetail['questions'] ?? [] as $idx => $question)
  216. <div class="p-2 bg-gray-50 rounded text-sm">
  217. <div class="font-medium text-gray-900">{{ $idx + 1 }}. {{ Str::limit($question['stem'] ?? '', 50) }}</div>
  218. <div class="text-xs text-gray-600 mt-1">
  219. {{ $question['knowledge_point'] ?? '' }} |
  220. 难度: {{ $question['difficulty'] ?? 0 }}
  221. </div>
  222. </div>
  223. @endforeach
  224. </div>
  225. </div>
  226. <div class="pt-4 border-t space-y-2">
  227. button
  228. color="primary"
  229. class="w-full"
  230. wire:click="exportPdf('{{ $selectedExamId }}')"
  231. >
  232. <x-heroicon-m-arrow-down-tray class="w-4 h-4 mr-2" />
  233. 导出PDF
  234. /button>
  235. button
  236. color="gray"
  237. class="w-full"
  238. wire:click="duplicateExam({{ json_encode($selectedExamDetail['paper']) }})"
  239. >
  240. <x-heroicon-m-document-duplicate class="w-4 h-4 mr-2" />
  241. 复制试卷配置
  242. /button>
  243. button
  244. color="danger"
  245. class="w-full"
  246. wire:click="deleteExam('{{ $selectedExamId }}')"
  247. >
  248. <x-heroicon-m-trash class="w-4 h-4 mr-2" />
  249. 删除试卷
  250. /button>
  251. </div>
  252. </div>
  253. </x-filament::card>
  254. @else
  255. <x-filament::card class="text-center py-12">
  256. <x-heroicon-o-information-circle class="w-12 h-12 text-gray-400 mx-auto mb-3" />
  257. <div class="text-sm text-gray-600">
  258. 点击左侧试卷查看详情
  259. </div>
  260. </x-filament::card>
  261. @endif
  262. </div>
  263. </div>
  264. </div>
  265. </x-filament-pages::page>