student-analytics.blade.php 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. <div class="space-y-6">
  2. {{-- Header --}}
  3. <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
  4. <div class="flex items-center justify-between">
  5. <div>
  6. <h2 class="text-2xl font-bold text-gray-900">{{ $student->name ?? '学生' }}</h2>
  7. <p class="text-sm text-gray-500 mt-1">
  8. 学号: {{ $studentId }} |
  9. 邮箱: {{ $student->email ?? 'N/A' }}
  10. </p>
  11. </div>
  12. <div class="flex items-center space-x-4">
  13. <div class="text-right">
  14. <p class="text-sm text-gray-500">知识点数量</p>
  15. <p class="text-2xl font-bold text-indigo-600">{{ $totalKnowledgePoints }}</p>
  16. </div>
  17. </div>
  18. </div>
  19. </div>
  20. {{-- Loading State --}}
  21. @if($loading)
  22. <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-12 text-center">
  23. <div class="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600 mx-auto"></div>
  24. <p class="mt-4 text-gray-500">加载学习数据中...</p>
  25. </div>
  26. {{-- Error State --}}
  27. @elseif($error)
  28. <div class="bg-red-50 border border-red-200 rounded-lg p-6">
  29. <div class="flex">
  30. <svg class="h-5 w-5 text-red-400" fill="currentColor" viewBox="0 0 20 20">
  31. <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z" clip-rule="evenodd"></path>
  32. </svg>
  33. <div class="ml-3">
  34. <h3 class="text-sm font-medium text-red-800">加载失败</h3>
  35. <p class="mt-2 text-sm text-red-700">{{ $error }}</p>
  36. </div>
  37. </div>
  38. </div>
  39. {{-- Data --}}
  40. @else
  41. {{-- Mastery Overview --}}
  42. <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
  43. <h3 class="text-lg font-semibold text-gray-900 mb-4">掌握度概览</h3>
  44. @if(empty($masteryPoints))
  45. <div class="text-center py-12 text-gray-500">
  46. <svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  47. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path>
  48. </svg>
  49. <p class="mt-2">暂无掌握度数据</p>
  50. </div>
  51. @else
  52. <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  53. @foreach($masteryPoints as $point)
  54. @php
  55. $mastery = $point['mastery_level'] * 100;
  56. if ($mastery >= 80) {
  57. $colorClass = 'green';
  58. $badgeClass = 'bg-green-100 text-green-800';
  59. $barClass = 'bg-green-600';
  60. } elseif ($mastery >= 60) {
  61. $colorClass = 'yellow';
  62. $badgeClass = 'bg-yellow-100 text-yellow-800';
  63. $barClass = 'bg-yellow-600';
  64. } else {
  65. $colorClass = 'red';
  66. $badgeClass = 'bg-red-100 text-red-800';
  67. $barClass = 'bg-red-600';
  68. }
  69. @endphp
  70. <div class="border border-gray-200 rounded-lg p-4">
  71. <div class="flex items-center justify-between mb-2">
  72. <h4 class="font-medium text-gray-900">{{ $point['kp_code'] }}</h4>
  73. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium {{ $badgeClass }}">
  74. {{ number_format($mastery, 1) }}%
  75. </span>
  76. </div>
  77. <p class="text-sm text-gray-600 mb-2">{{ $point['kp_name'] ?? 'N/A' }}</p>
  78. <div class="w-full bg-gray-200 rounded-full h-2">
  79. <div class="{{ $barClass }} h-2 rounded-full"
  80. style="width: {{ $mastery }}%"></div>
  81. </div>
  82. <div class="mt-2 flex justify-between text-xs text-gray-500">
  83. <span>答题: {{ $point['total_attempts'] ?? 0 }} 次</span>
  84. <span>正确: {{ $point['correct_attempts'] ?? 0 }} 次</span>
  85. </div>
  86. </div>
  87. @endforeach
  88. </div>
  89. @endif
  90. </div>
  91. {{-- Exercise History --}}
  92. @if(!empty($analysis['exercises']))
  93. <div class="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
  94. <h3 class="text-lg font-semibold text-gray-900 mb-4">最近练习</h3>
  95. <div class="overflow-x-auto">
  96. <table class="min-w-full divide-y divide-gray-200">
  97. <thead class="bg-gray-50">
  98. <tr>
  99. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">时间</th>
  100. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">题目</th>
  101. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">结果</th>
  102. <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">用时</th>
  103. </tr>
  104. </thead>
  105. <tbody class="bg-white divide-y divide-gray-200">
  106. @foreach(array_slice($analysis['exercises'], 0, 10) as $exercise)
  107. <tr>
  108. <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
  109. {{ \Carbon\Carbon::parse($exercise->created_at)->format('m-d H:i') }}
  110. </td>
  111. <td class="px-6 py-4 text-sm text-gray-900">{{ $exercise->question_id }}</td>
  112. <td class="px-6 py-4 whitespace-nowrap">
  113. @if($exercise->is_correct)
  114. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
  115. 正确
  116. </span>
  117. @else
  118. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
  119. 错误
  120. </span>
  121. @endif
  122. </td>
  123. <td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
  124. {{ $exercise->time_spent_seconds ?? 0 }}秒
  125. </td>
  126. </tr>
  127. @endforeach
  128. </tbody>
  129. </table>
  130. </div>
  131. </div>
  132. @endif
  133. @endif
  134. </div>