exam-detail.blade.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <x-filament-panels::page>
  2. <div class="space-y-6">
  3. <!-- 页面顶部:返回按钮和标题 -->
  4. <div class="flex items-center justify-between">
  5. <div class="flex items-center gap-4">
  6. <a href="{{ url('/admin/exam-history') }}"
  7. class="btn btn-ghost btn-sm">
  8. <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  9. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
  10. </svg>
  11. 返回列表
  12. </a>
  13. <div>
  14. <h2 class="text-2xl font-bold text-gray-900">试卷详情</h2>
  15. <p class="mt-1 text-sm text-gray-500">
  16. 查看和编辑试卷信息,管理试卷中的题目
  17. </p>
  18. </div>
  19. </div>
  20. </div>
  21. @if(empty($paperDetail))
  22. <div class="alert alert-error">
  23. <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  24. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
  25. </svg>
  26. <span>试卷不存在或已被删除</span>
  27. </div>
  28. @else
  29. <!-- 试卷基本信息卡片 -->
  30. <div class="card bg-base-100 shadow-xl">
  31. <div class="card-body">
  32. <div class="flex items-start justify-between">
  33. <div class="flex-1">
  34. <div class="flex items-center gap-3 mb-4">
  35. <h3 class="card-title text-xl">{{ $paperDetail['paper_name'] ?? '未命名试卷' }}</h3>
  36. <span class="badge badge-{{ $this->getStatusColor($paperDetail['status']) }}">
  37. {{ $this->getStatusLabel($paperDetail['status']) }}
  38. </span>
  39. <span class="badge badge-{{ $this->getDifficultyColor($paperDetail['difficulty_category']) }}">
  40. {{ $paperDetail['difficulty_category'] }}
  41. </span>
  42. </div>
  43. <div class="stats stats-horizontal shadow bg-base-200">
  44. <div class="stat">
  45. <div class="stat-title">题目数量</div>
  46. <div class="stat-value text-primary">{{ $paperDetail['question_count'] }}</div>
  47. <div class="stat-desc">题</div>
  48. </div>
  49. <div class="stat">
  50. <div class="stat-title">总分</div>
  51. <div class="stat-value text-secondary">{{ $paperDetail['total_score'] }}</div>
  52. <div class="stat-desc">分</div>
  53. </div>
  54. <div class="stat">
  55. <div class="stat-title">创建时间</div>
  56. <div class="stat-value text-lg" style="font-size: 1rem;">
  57. {{ \Carbon\Carbon::parse($paperDetail['created_at'])->format('Y-m-d') }}
  58. </div>
  59. <div class="stat-desc">
  60. {{ \Carbon\Carbon::parse($paperDetail['created_at'])->format('H:i') }}
  61. </div>
  62. </div>
  63. </div>
  64. </div>
  65. <div class="flex gap-2">
  66. <button
  67. wire:click="startEditExam"
  68. class="btn btn-outline btn-sm">
  69. <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  70. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"></path>
  71. </svg>
  72. 编辑试卷
  73. </button>
  74. <button
  75. wire:click="exportPdf"
  76. class="btn btn-outline btn-sm"
  77. title="注意:PDF导出功能依赖外部题库API,可能不稳定">
  78. <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  79. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
  80. </svg>
  81. 导出PDF
  82. </button>
  83. <button
  84. wire:click="duplicateExam"
  85. class="btn btn-outline btn-sm">
  86. <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  87. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
  88. </svg>
  89. 复制配置
  90. </button>
  91. <button
  92. wire:click="$toggle('showAddQuestionModal')"
  93. class="btn btn-primary btn-sm">
  94. <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  95. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
  96. </svg>
  97. 添加题目
  98. </button>
  99. </div>
  100. </div>
  101. </div>
  102. </div>
  103. <!-- 题目列表 -->
  104. <div class="card bg-base-100 shadow-xl">
  105. <div class="card-body">
  106. <div class="flex items-center justify-between mb-4">
  107. <h3 class="card-title">试卷题目</h3>
  108. <span class="badge badge-lg">{{ count($paperDetail['questions']) }} 题</span>
  109. </div>
  110. @forelse($paperDetail['questions'] as $question)
  111. <div class="border rounded-lg p-4 mb-4 hover:bg-gray-50">
  112. <div class="flex items-start justify-between gap-4">
  113. <div class="flex-1">
  114. <!-- 题目头部信息 -->
  115. <div class="flex items-center gap-2 mb-3">
  116. <span class="badge badge-primary badge-lg">
  117. 第 {{ $question['question_number'] }} 题
  118. </span>
  119. <span class="badge badge-sm">
  120. {{ $question['question_type'] }}
  121. </span>
  122. <span class="badge badge-outline badge-sm">
  123. {{ $question['knowledge_point'] }}
  124. </span>
  125. <span class="badge badge-{{ $question['difficulty'] <= 0.4 ? 'success' : ($question['difficulty'] <= 0.7 ? 'warning' : 'error') }} badge-sm">
  126. {{ $question['difficulty_label'] }}
  127. </span>
  128. <span class="badge badge-secondary badge-sm">
  129. {{ $question['score'] }} 分
  130. </span>
  131. <span class="badge badge-ghost badge-sm">
  132. {{ $question['estimated_time'] }} 秒
  133. </span>
  134. </div>
  135. <!-- 题目题干 -->
  136. <div class="bg-base-200 p-4 rounded-lg mb-3">
  137. <div class="text-sm text-gray-500 mb-2">题干:</div>
  138. <div class="prose prose-sm max-w-none">
  139. {!! nl2br(e($question['stem'])) !!}
  140. </div>
  141. </div>
  142. <!-- 答案和解析 -->
  143. <div class="grid grid-cols-1 md:grid-cols-2 gap-3">
  144. @if($question['answer'])
  145. <div class="bg-success/10 p-3 rounded-lg">
  146. <div class="text-sm font-semibold text-success mb-1">答案:</div>
  147. <div class="text-sm">{!! nl2br(e($question['answer'])) !!}</div>
  148. </div>
  149. @endif
  150. @if($question['solution'])
  151. <div class="bg-info/10 p-3 rounded-lg">
  152. <div class="text-sm font-semibold text-info mb-1">解析:</div>
  153. <div class="text-sm">{!! nl2br(e($question['solution'])) !!}</div>
  154. </div>
  155. @endif
  156. </div>
  157. <!-- 题目代码 -->
  158. @if($question['question_code'])
  159. <div class="text-xs text-gray-400 mt-2">
  160. 题目编号:{{ $question['question_code'] }}
  161. </div>
  162. @endif
  163. </div>
  164. <!-- 操作按钮 -->
  165. <div class="flex flex-col gap-2">
  166. <button
  167. wire:click="deleteQuestion({{ $question['id'] }})"
  168. wire:confirm="确定要删除这道题目吗?"
  169. class="btn btn-error btn-outline btn-sm">
  170. <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  171. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"></path>
  172. </svg>
  173. 删除
  174. </button>
  175. </div>
  176. </div>
  177. </div>
  178. @empty
  179. <div class="text-center py-12 text-gray-400">
  180. <svg class="w-16 h-16 mx-auto mb-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  181. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
  182. </svg>
  183. <p>试卷中暂无题目</p>
  184. <button
  185. wire:click="$toggle('showAddQuestionModal')"
  186. class="btn btn-primary btn-sm mt-4">
  187. 立即添加题目
  188. </button>
  189. </div>
  190. @endforelse
  191. </div>
  192. </div>
  193. @endif
  194. </div>
  195. <!-- 编辑试卷模态框 -->
  196. @if($editingExamId)
  197. <div class="modal modal-open">
  198. <div class="modal-box">
  199. <h3 class="font-bold text-lg mb-4">编辑试卷</h3>
  200. <div class="space-y-4">
  201. <div class="form-control">
  202. <label class="label">
  203. <span class="label-text">试卷名称</span>
  204. </label>
  205. <input type="text" wire:model="editForm.paper_name"
  206. class="input input-bordered input-primary"
  207. placeholder="请输入试卷名称" />
  208. @error('editForm.paper_name')
  209. <label class="label">
  210. <span class="label-text-alt text-error">{{ $message }}</span>
  211. </label>
  212. @enderror
  213. </div>
  214. <div class="form-control">
  215. <label class="label">
  216. <span class="label-text">难度分类</span>
  217. </label>
  218. <select wire:model="editForm.difficulty_category"
  219. class="select select-bordered select-primary">
  220. <option value="">-- 请选择难度 --</option>
  221. <option value="基础">基础</option>
  222. <option value="进阶">进阶</option>
  223. <option value="竞赛">竞赛</option>
  224. </select>
  225. @error('editForm.difficulty_category')
  226. <label class="label">
  227. <span class="label-text-alt text-error">{{ $message }}</span>
  228. </label>
  229. @enderror
  230. </div>
  231. <div class="form-control">
  232. <label class="label">
  233. <span class="label-text">状态</span>
  234. </label>
  235. <select wire:model="editForm.status"
  236. class="select select-bordered select-primary">
  237. <option value="">-- 请选择状态 --</option>
  238. <option value="draft">草稿</option>
  239. <option value="completed">已完成</option>
  240. <option value="graded">已评分</option>
  241. </select>
  242. @error('editForm.status')
  243. <label class="label">
  244. <span class="label-text-alt text-error">{{ $message }}</span>
  245. </label>
  246. @enderror
  247. </div>
  248. </div>
  249. <div class="modal-action">
  250. <button wire:click="cancelEdit" class="btn btn-ghost">取消</button>
  251. <button wire:click="saveExamEdit" class="btn btn-primary">保存</button>
  252. </div>
  253. </div>
  254. </div>
  255. @endif
  256. <!-- 添加题目模态框 -->
  257. @if($showAddQuestionModal)
  258. <div class="modal modal-open">
  259. <div class="modal-box max-w-4xl">
  260. <h3 class="font-bold text-lg mb-4">添加题目</h3>
  261. <div class="space-y-4">
  262. <div class="alert alert-info">
  263. <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  264. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
  265. </svg>
  266. <span>
  267. <strong>提示:</strong>添加题目功能需要连接外部题库API,当前版本暂未开放此功能。
  268. 您可以删除现有题目,或通过其他方式管理试卷题目。
  269. </span>
  270. </div>
  271. </div>
  272. <div class="modal-action">
  273. <button wire:click="$toggle('showAddQuestionModal')" class="btn btn-ghost">关闭</button>
  274. </div>
  275. </div>
  276. </div>
  277. @endif
  278. </x-filament-panels::page>