intelligent-exam-generation-simple.blade.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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 10px 25px rgba(0,0,0,0.1);
  10. }
  11. </style>
  12. @endpush
  13. <div class="space-y-6">
  14. <!-- 页面标题 -->
  15. <div class="flex justify-between items-center">
  16. <div>
  17. <h2 class="text-2xl font-bold text-gray-900">智能出卷系统</h2>
  18. <p class="mt-1 text-sm text-gray-500">
  19. 基于知识点掌握度,智能生成个性化试卷
  20. </p>
  21. </div>
  22. <div class="flex gap-3">
  23. <button
  24. wire:click="resetForm"
  25. type="button"
  26. class="filament-button filament-button-size-sm filament-button-color-gray filament-button-icon-start inline-flex items-center justify-center px-4 py-2 text-sm font-medium transition-colors border border-transparent rounded-lg focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
  27. >
  28. 重置
  29. </button>
  30. </div>
  31. </div>
  32. <!-- 基本信息卡片 -->
  33. <div class="bg-white p-6 rounded-lg border shadow-sm">
  34. <h3 class="text-lg font-semibold text-gray-900 mb-4">基本信息</h3>
  35. <div class="space-y-4">
  36. <div class="grid grid-cols-3 gap-4">
  37. <div>
  38. <label class="block text-sm font-medium text-gray-700 mb-2">难度分类</label>
  39. <select wire:model="difficultyCategory" class="form-select w-full px-3 py-2 border rounded-lg">
  40. <option value="基础">基础</option>
  41. <option value="进阶">进阶</option>
  42. <option value="竞赛">竞赛</option>
  43. </select>
  44. </div>
  45. <div>
  46. <label class="block text-sm font-medium text-gray-700 mb-2">题目数量 <span class="text-red-500">*</span></label>
  47. <input
  48. type="number"
  49. wire:model="totalQuestions"
  50. class="form-input w-full px-3 py-2 border rounded-lg"
  51. min="6"
  52. max="100"
  53. required
  54. />
  55. </div>
  56. <div>
  57. <label class="block text-sm font-medium text-gray-700 mb-2">总分</label>
  58. <input
  59. type="number"
  60. wire:model="totalScore"
  61. class="form-input w-full px-3 py-2 border rounded-lg"
  62. min="0"
  63. max="200"
  64. />
  65. </div>
  66. </div>
  67. <div>
  68. <label class="block text-sm font-medium text-gray-700 mb-2">试卷名称 <span class="text-gray-400 font-normal">(选填,未填则自动生成)</span></label>
  69. <input
  70. type="text"
  71. wire:model="paperName"
  72. class="form-input w-full px-3 py-2 border rounded-lg"
  73. placeholder="例如:因式分解专项练习(基础版)"
  74. />
  75. </div>
  76. </div>
  77. </div>
  78. <!-- 教师和学生选择 -->
  79. <div class="bg-white p-6 rounded-lg border shadow-sm">
  80. <h3 class="text-lg font-semibold text-gray-900 mb-4">针对性出卷</h3>
  81. <div class="space-y-4">
  82. <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
  83. <div>
  84. <label class="block text-sm font-medium text-gray-700 mb-2">选择教师</label>
  85. <select
  86. wire:model.live="selectedTeacherId"
  87. class="form-select w-full px-3 py-2 border rounded-lg"
  88. required
  89. >
  90. <option value="">-- 请选择教师 --</option>
  91. @foreach($this->teachers() as $teacher)
  92. <option value="{{ $teacher->teacher_id }}">
  93. {{ $teacher->name }} ({{ $teacher->subject ?? '未知' }})
  94. </option>
  95. @endforeach
  96. </select>
  97. </div>
  98. <div>
  99. <label class="block text-sm font-medium text-gray-700 mb-2">选择学生</label>
  100. <select
  101. wire:model.live="selectedStudentId"
  102. class="form-select w-full px-3 py-2 border rounded-lg"
  103. @if(!$selectedTeacherId) disabled @endif
  104. required
  105. >
  106. <option value="">-- 请先选择教师 --</option>
  107. @foreach($this->students() as $student)
  108. <option value="{{ $student->student_id }}">
  109. {{ $student->name ?? $student->student_id }} - {{ $student->grade }}{{ $student->class_name }}
  110. </option>
  111. @endforeach
  112. </select>
  113. </div>
  114. </div>
  115. @if($selectedTeacherId && $selectedStudentId)
  116. <div class="p-4 bg-blue-50 rounded-lg">
  117. <div class="flex items-start gap-3">
  118. <svg class="w-5 h-5 text-blue-600 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  119. <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>
  120. </svg>
  121. <div>
  122. <div class="font-medium text-blue-900">针对性出卷已启用</div>
  123. <div class="text-sm text-blue-700 mt-1">
  124. 将根据所选学生的薄弱知识点进行智能推荐,建议自动勾选相关知识点
  125. </div>
  126. <label class="flex items-center gap-2 mt-3">
  127. <input
  128. type="checkbox"
  129. wire:model="filterByStudentWeakness"
  130. class="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
  131. />
  132. <span class="text-sm text-blue-700">根据学生薄弱点自动选择知识点</span>
  133. </label>
  134. </div>
  135. </div>
  136. </div>
  137. @endif
  138. </div>
  139. </div>
  140. <!-- 知识点选择 -->
  141. <div class="bg-white p-6 rounded-lg border shadow-sm">
  142. <div class="flex items-center justify-between mb-4">
  143. <h3 class="text-lg font-semibold text-gray-900">知识点选择</h3>
  144. <div class="text-sm text-gray-500">
  145. 已选择: {{ count($selectedKpCodes) }} 个
  146. </div>
  147. </div>
  148. <div class="grid grid-cols-1 md:grid-cols-2 gap-3 max-h-64 overflow-y-auto">
  149. @foreach($this->knowledgePoints as $kp)
  150. <label class="flex items-start gap-3 p-3 border rounded-lg hover:bg-gray-50 cursor-pointer">
  151. <input
  152. type="checkbox"
  153. wire:model="selectedKpCodes"
  154. value="{{ $kp['kp_code'] }}"
  155. class="mt-1"
  156. />
  157. <div class="flex-1">
  158. <div class="font-medium text-gray-900">{{ $kp['cn_name'] ?? $kp['kp_code'] }}</div>
  159. @if(!empty($kp['description']))
  160. <div class="text-sm text-gray-500 mt-1">{{ Str::limit($kp['description'], 80) }}</div>
  161. @endif
  162. <div class="flex items-center gap-2 mt-2">
  163. <span class="text-xs px-2 py-0.5 bg-blue-100 text-blue-700 rounded">
  164. {{ $kp['kp_code'] }}
  165. </span>
  166. </div>
  167. </div>
  168. </label>
  169. @endforeach
  170. </div>
  171. </div>
  172. <!-- 生成按钮 -->
  173. <div class="bg-white p-6 rounded-lg border shadow-sm">
  174. <button
  175. wire:click="generateExam"
  176. type="button"
  177. class="filament-button filament-button-size-lg filament-button-color-primary filament-button-icon-start inline-flex items-center justify-center w-full px-6 py-3 text-base font-medium transition-colors border border-transparent rounded-lg focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
  178. wire:loading.attr="disabled"
  179. >
  180. @if($isGenerating)
  181. <svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
  182. <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
  183. <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
  184. </svg>
  185. 生成中...
  186. @else
  187. <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  188. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
  189. </svg>
  190. 智能生成试卷
  191. @endif
  192. </button>
  193. @if($generatedPaperId)
  194. <div class="mt-4 p-4 bg-green-50 rounded-lg">
  195. <div class="flex items-center gap-2 text-green-800">
  196. <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  197. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>
  198. </svg>
  199. <div class="font-medium">生成成功</div>
  200. </div>
  201. <div class="mt-2 text-sm text-green-700">
  202. 已生成试卷ID: <span class="font-mono">{{ $generatedPaperId }}</span>
  203. </div>
  204. <div class="mt-4 flex gap-2">
  205. <button
  206. onclick="document.getElementById('pdfPreview').scrollIntoView({behavior: 'smooth'})"
  207. type="button"
  208. class="filament-button filament-button-size-md filament-button-color-secondary">
  209. 查看预览
  210. </button>
  211. <button wire:click="exportToPdf" type="button" class="filament-button filament-button-size-md filament-button-color-primary">
  212. 新窗口打开
  213. </button>
  214. </div>
  215. </div>
  216. <!-- PDF 预览区域 -->
  217. <div id="pdfPreview" class="mt-6 bg-white rounded-lg border shadow-sm">
  218. <div class="p-4 border-b bg-gray-50 flex justify-between items-center">
  219. <h3 class="text-lg font-semibold">试卷预览</h3>
  220. <button
  221. onclick="document.getElementById('pdfFrame').contentWindow.print()"
  222. class="filament-button filament-button-size-sm filament-button-color-primary">
  223. 打印试卷
  224. </button>
  225. </div>
  226. <div class="p-4">
  227. <iframe
  228. id="pdfFrame"
  229. src="{{ route('filament.admin.auth.intelligent-exam.pdf', ['paper_id' => $generatedPaperId]) }}"
  230. class="w-full border-0"
  231. style="height: 1200px;"
  232. title="试卷预览">
  233. </iframe>
  234. </div>
  235. </div>
  236. @endif
  237. </div>
  238. </div>
  239. </x-filament-panels::page>