upload-exam-paper.blade.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <x-filament-panels::page>
  2. <div class="space-y-6">
  3. {{-- 模式选择 --}}
  4. <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
  5. <div class="flex gap-4">
  6. <button
  7. wire:click="$set('mode', 'select_paper')"
  8. class="px-4 py-2 rounded-md font-medium transition-colors {{ $mode === 'select_paper' ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200' }}"
  9. >
  10. <svg class="w-5 h-5 inline-block mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  11. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.707.293V19a2 2 0 012-2H5a2 2 0 01-2 2v-14z"></path>
  12. </svg>
  13. 选择已有试卷评分
  14. </button>
  15. <button
  16. wire:click="$set('mode', 'upload')"
  17. class="px-4 py-2 rounded-md font-medium transition-colors {{ $mode === 'upload' ? 'bg-blue-600 text-white' : 'bg-gray-100 text-gray-700 hover:bg-gray-200' }}"
  18. >
  19. <svg class="w-5 h-5 inline-block mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  20. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003 3v-1m-4-8l-4-4m0 0L8 8m4-4v12"></path>
  21. </svg>
  22. 上传试卷照片
  23. </button>
  24. </div>
  25. </div>
  26. {{-- 上传模式 --}}
  27. @if($mode === 'upload')
  28. {{-- 选择老师和学生 --}}
  29. <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-6">
  30. <h2 class="text-lg font-semibold mb-4 flex items-center">
  31. <svg class="w-5 h-5 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  32. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
  33. </svg>
  34. 选择老师和学生
  35. </h2>
  36. <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
  37. {{-- 选择老师 --}}
  38. <div class="form-control w-full">
  39. <label class="block text-sm font-medium text-gray-700 mb-2">
  40. 选择老师 <span class="text-red-500">*</span>
  41. @if($isTeacher)
  42. <span class="text-green-600 text-xs ml-2">(当前登录)</span>
  43. @endif
  44. </label>
  45. <select
  46. wire:model.live="teacherId"
  47. @if($isTeacher) disabled @endif
  48. class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 @if($isTeacher) bg-gray-100 @endif"
  49. >
  50. <option value="">请选择老师...</option>
  51. @foreach($this->teachers as $teacher)
  52. <option value="{{ $teacher->teacher_id }}">
  53. {{ trim($teacher->name ?? $teacher->teacher_id) . ($teacher->subject ? " ({$teacher->subject})" : '') }}
  54. </option>
  55. @endforeach
  56. </select>
  57. </div>
  58. {{-- 选择学生 --}}
  59. <div class="form-control w-full">
  60. <label class="block text-sm font-medium text-gray-700 mb-2">选择学生 <span class="text-red-500">*</span></label>
  61. <select
  62. wire:model.live="studentId"
  63. wire:loading.attr="disabled"
  64. @if(empty($teacherId)) disabled @endif
  65. class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 @if(empty($teacherId)) bg-gray-100 @endif"
  66. >
  67. <option value="">
  68. @if(empty($teacherId))
  69. 请先选择老师
  70. @else
  71. 请选择学生...
  72. @endif
  73. </option>
  74. @foreach($this->students as $student)
  75. <option value="{{ $student->student_id }}">
  76. {{ trim($student->name ?? $student->student_id) . " ({$student->grade} - {$student->class_name})" }}
  77. </option>
  78. @endforeach
  79. </select>
  80. </div>
  81. </div>
  82. </div>
  83. {{-- 图片上传和OCR识别组件 --}}
  84. @if(!empty($teacherId) && !empty($studentId))
  85. @livewire(\App\Livewire\UploadExam\UploadForm::class, ['teacherId' => $teacherId, 'studentId' => $studentId])
  86. @livewire(\App\Livewire\UploadExam\OCRResults::class)
  87. @endif
  88. @endif
  89. {{-- 选择试卷评分模式 --}}
  90. @if($mode === 'select_paper')
  91. <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
  92. <h2 class="text-xl font-semibold mb-6 flex items-center">
  93. <svg class="w-6 h-6 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  94. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.707.293V19a2 2 0 012-2H5a2 2 0 01-2 2v-14z"></path>
  95. </svg>
  96. 选择已有试卷评分
  97. </h2>
  98. {{-- 选择老师和学生 --}}
  99. <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
  100. {{-- 选择老师 --}}
  101. <div class="form-control w-full">
  102. <label class="block text-sm font-medium text-gray-700 mb-2">
  103. 选择老师 <span class="text-red-500">*</span>
  104. @if($isTeacher)
  105. <span class="text-green-600 text-xs ml-2">(当前登录)</span>
  106. @endif
  107. </label>
  108. <select
  109. wire:model.live="teacherId"
  110. @if($isTeacher) disabled @endif
  111. class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 @if($isTeacher) bg-gray-100 @endif"
  112. >
  113. <option value="">请选择老师...</option>
  114. @foreach($this->teachers as $teacher)
  115. <option value="{{ $teacher->teacher_id }}">
  116. {{ trim($teacher->name ?? $teacher->teacher_id) . ($teacher->subject ? " ({$teacher->subject})" : '') }}
  117. </option>
  118. @endforeach
  119. </select>
  120. </div>
  121. {{-- 选择学生 --}}
  122. <div class="form-control w-full">
  123. <label class="block text-sm font-medium text-gray-700 mb-2">选择学生 <span class="text-red-500">*</span></label>
  124. <select
  125. wire:model.live="studentId"
  126. wire:loading.attr="disabled"
  127. @if(empty($teacherId)) disabled @endif
  128. class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
  129. >
  130. <option value="">
  131. @if(empty($teacherId))
  132. 请先选择老师
  133. @else
  134. 请选择学生...
  135. @endif
  136. </option>
  137. @foreach($this->students as $student)
  138. <option value="{{ $student->student_id }}">
  139. {{ trim($student->name ?? $student->student_id) . " ({$student->grade} - {$student->class_name})" }}
  140. </option>
  141. @endforeach
  142. </select>
  143. </div>
  144. </div>
  145. {{-- 选择试卷 --}}
  146. @if(!empty($studentId))
  147. <div class="form-control w-full mt-6">
  148. <label class="block text-sm font-medium text-gray-700 mb-2">选择试卷 <span class="text-red-500">*</span></label>
  149. <select
  150. wire:model.live="selectedPaperId"
  151. class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500"
  152. >
  153. <option value="">请选择试卷...</option>
  154. @foreach($this->studentPapers as $paper)
  155. <option value="{{ $paper['paper_id'] }}">
  156. {{ $paper['paper_name'] }} ({{ $paper['total_questions'] }}题 / {{ $paper['total_score'] }}分) - {{ $paper['created_at'] }}
  157. </option>
  158. @endforeach
  159. </select>
  160. </div>
  161. @endif
  162. {{-- 评分面板组件 --}}
  163. @if(!empty($selectedPaperId))
  164. @livewire(\App\Livewire\UploadExam\GradingPanel::class, [
  165. 'teacherId' => $teacherId,
  166. 'studentId' => $studentId,
  167. 'selectedPaperId' => $selectedPaperId,
  168. 'questions' => $this->selectedPaperQuestions
  169. ])
  170. @endif
  171. </div>
  172. @endif
  173. {{-- 最近上传记录 --}}
  174. <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
  175. <h2 class="text-lg font-semibold mb-4 flex items-center">
  176. <svg class="w-5 h-5 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  177. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6 2a9 9 0 11-18 0 9 9 0 011-18 0z"></path>
  178. </svg>
  179. 最近试卷记录
  180. </h2>
  181. @if(count($this->recentRecords) > 0)
  182. <div class="overflow-x-auto">
  183. <table class="min-w-full divide-y divide-gray-200">
  184. <thead class="bg-gray-50">
  185. <tr>
  186. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">试卷名称</th>
  187. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">学生</th>
  188. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">题目数</th>
  189. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th>
  190. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">创建时间</th>
  191. </tr>
  192. </thead>
  193. <tbody class="bg-white divide-y divide-gray-200">
  194. @foreach($this->recentRecords as $record)
  195. <tr class="hover:bg-gray-50">
  196. <td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-blue-600">
  197. @php
  198. $url = '';
  199. if (in_array($record['type'], ['graded_paper', 'generated'])) {
  200. $url = '/admin/exam-analysis?paperId=' . ($record['paper_id'] ?? '') . '&studentId=' . $record['student_id'];
  201. } elseif ($record['type'] === 'ocr_upload') {
  202. $url = '/admin/exam-analysis?recordId=' . ($record['record_id'] ?? '') . '&studentId=' . $record['student_id'];
  203. }
  204. @endphp
  205. @if($url)
  206. <a href="{{ $url }}" class="hover:underline">{{ $record['paper_name'] }}</a>
  207. @else
  208. {{ $record['paper_name'] }}
  209. @endif
  210. </td>
  211. <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
  212. {{ $record['student_name'] }}
  213. </td>
  214. <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
  215. {{ $record['total_questions'] }}
  216. </td>
  217. <td class="px-6 py-4 whitespace-nowrap">
  218. <span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full
  219. @if($record['is_completed'])
  220. bg-green-100 text-green-800
  221. @elseif($record['status'] === 'processing')
  222. bg-yellow-100 text-yellow-800
  223. @else
  224. bg-gray-100 text-gray-800
  225. @endif">
  226. {{ $record['status_text'] ?? $record['status'] }}
  227. </span>
  228. </td>
  229. <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
  230. {{ $record['created_at'] }}
  231. </td>
  232. </tr>
  233. @endforeach
  234. </tbody>
  235. </table>
  236. </div>
  237. @else
  238. <div class="text-center py-8 text-gray-500">
  239. <svg class="w-12 h-12 mx-auto mb-3 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  240. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6m-3-9v9h6m0 6v6m-6-6h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.707.293V19a2 2 0 012-2H5a2 2 0 01-2 2v-14z"></path>
  241. </svg>
  242. <p>暂无上传记录</p>
  243. </div>
  244. @endif
  245. </div>
  246. </x-filament-panels::page>