student-dashboard.blade.php 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. <div class="min-h-screen bg-gray-50 p-8">
  2. {{-- 页面标题区域 --}}
  3. <div class="mb-8">
  4. <div class="bg-white rounded-xl shadow-sm p-6 border border-gray-200">
  5. <div class="flex items-center justify-between mb-6">
  6. <div>
  7. <h1 class="text-3xl font-bold text-gray-900 flex items-center">
  8. <svg class="w-8 h-8 mr-3 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  9. <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>
  10. </svg>
  11. 学生仪表板
  12. </h1>
  13. <p class="mt-2 text-sm text-gray-600 ml-11">
  14. 全面展示学生的学习分析数据,包括掌握度、技能熟练度、提分预测和学习路径
  15. </p>
  16. </div>
  17. </div>
  18. {{-- 选择器区域 --}}
  19. <div class="bg-gray-50 rounded-lg p-4 border border-gray-200">
  20. <livewire:teacher-student-selector
  21. wire:model.selectedTeacherId="teacherId"
  22. wire:model.selectedStudentId="studentId"
  23. :required="true"
  24. teacher-label="选择老师"
  25. student-label="选择学生"
  26. teacher-helper-text="选择要查看的老师"
  27. student-helper-text="选择要查看的学生"
  28. />
  29. <div class="mt-4 pb-0.5 flex space-x-2">
  30. <button
  31. wire:click="loadDashboardData"
  32. wire:loading.attr="disabled"
  33. class="inline-flex items-center px-6 py-2.5 border border-transparent text-sm font-medium rounded-lg shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 transition-colors duration-200"
  34. >
  35. <svg wire:loading class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
  36. <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
  37. <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>
  38. </svg>
  39. 刷新数据
  40. </button>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. {{-- 错误提示 --}}
  46. @if ($errorMessage)
  47. <div class="mb-8">
  48. <div class="bg-red-50 border border-red-200 rounded-xl p-4">
  49. <div class="flex items-start">
  50. <div class="flex-shrink-0">
  51. <svg class="h-5 w-5 text-red-400" viewBox="0 0 20 20" fill="currentColor">
  52. <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" />
  53. </svg>
  54. </div>
  55. <div class="ml-3">
  56. <h3 class="text-sm font-medium text-red-800">加载错误</h3>
  57. <div class="mt-2 text-sm text-red-700">
  58. <p>{{ $errorMessage }}</p>
  59. </div>
  60. </div>
  61. </div>
  62. </div>
  63. </div>
  64. @endif
  65. {{-- 加载状态 --}}
  66. @if ($isLoading)
  67. <div class="mb-8">
  68. <div class="bg-white rounded-xl shadow-sm p-12 border border-gray-200">
  69. <div class="flex flex-col items-center justify-center">
  70. <svg class="animate-spin h-12 w-12 text-indigo-600" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
  71. <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
  72. <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>
  73. </svg>
  74. <p class="mt-4 text-sm text-gray-600">正在加载数据,请稍候...</p>
  75. </div>
  76. </div>
  77. </div>
  78. @else
  79. {{-- 加载完成后显示内容 --}}
  80. {{-- 快速概览卡片 --}}
  81. {{-- 快速概览卡片 --}}
  82. <div class="mb-8">
  83. <div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-4">
  84. {{-- 掌握度概览 --}}
  85. @if (isset($dashboardData['mastery']['overview']))
  86. <div class="bg-white overflow-hidden shadow-sm rounded-xl border border-gray-200 hover:shadow-md transition-shadow duration-200">
  87. <div class="p-6">
  88. <div class="flex items-center justify-between">
  89. <div class="flex items-center">
  90. <div class="flex-shrink-0">
  91. <div class="w-12 h-12 bg-gradient-to-br from-indigo-500 to-indigo-600 rounded-xl flex items-center justify-center shadow-lg">
  92. <svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  93. <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>
  94. </svg>
  95. </div>
  96. </div>
  97. <div class="ml-4">
  98. <p class="text-sm font-medium text-gray-600">平均掌握度</p>
  99. <p class="text-2xl font-bold text-gray-900 mt-1">
  100. {{ number_format($dashboardData['mastery']['overview']['average_mastery_level'] * 100, 1) }}%
  101. </p>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. <div class="bg-gray-50 px-6 py-4 border-t border-gray-100">
  107. <div class="flex justify-between text-xs">
  108. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
  109. 已掌握: {{ $dashboardData['mastery']['overview']['mastered_knowledge_points'] }}
  110. </span>
  111. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
  112. 薄弱: {{ $dashboardData['mastery']['overview']['weak_knowledge_points'] }}
  113. </span>
  114. </div>
  115. </div>
  116. </div>
  117. @endif
  118. {{-- 技能熟练度概览 --}}
  119. @if (isset($dashboardData['skill']['summary']))
  120. <div class="bg-white overflow-hidden shadow-sm rounded-xl border border-gray-200 hover:shadow-md transition-shadow duration-200">
  121. <div class="p-6">
  122. <div class="flex items-center justify-between">
  123. <div class="flex items-center">
  124. <div class="flex-shrink-0">
  125. <div class="w-12 h-12 bg-gradient-to-br from-green-500 to-green-600 rounded-xl flex items-center justify-center shadow-lg">
  126. <svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  127. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
  128. </svg>
  129. </div>
  130. </div>
  131. <div class="ml-4">
  132. <p class="text-sm font-medium text-gray-600">技能熟练度</p>
  133. <p class="text-2xl font-bold text-gray-900 mt-1">
  134. {{ number_format($dashboardData['skill']['summary']['average_proficiency_level'] * 100, 1) }}%
  135. </p>
  136. </div>
  137. </div>
  138. </div>
  139. </div>
  140. <div class="bg-gray-50 px-6 py-4 border-t border-gray-100">
  141. <div class="flex justify-between text-xs">
  142. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
  143. 技能: {{ $dashboardData['skill']['summary']['total_skills'] }}
  144. </span>
  145. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800">
  146. 练习: {{ $dashboardData['skill']['summary']['total_questions_attempted'] }}
  147. </span>
  148. </div>
  149. </div>
  150. </div>
  151. @endif
  152. {{-- 提分潜力 --}}
  153. @if (isset($dashboardData['prediction']['quick']))
  154. <div class="bg-white overflow-hidden shadow-sm rounded-xl border border-gray-200 hover:shadow-md transition-shadow duration-200">
  155. <div class="p-6">
  156. <div class="flex items-center justify-between">
  157. <div class="flex items-center">
  158. <div class="flex-shrink-0">
  159. <div class="w-12 h-12 bg-gradient-to-br from-yellow-500 to-orange-500 rounded-xl flex items-center justify-center shadow-lg">
  160. <svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  161. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
  162. </svg>
  163. </div>
  164. </div>
  165. <div class="ml-4">
  166. <p class="text-sm font-medium text-gray-600">预期提分</p>
  167. <p class="text-2xl font-bold text-gray-900 mt-1">
  168. +{{ $dashboardData['prediction']['quick']['quick_prediction']['improvement_potential'] ?? 0 }}
  169. <span class="text-lg text-gray-500">分</span>
  170. </p>
  171. </div>
  172. </div>
  173. </div>
  174. </div>
  175. <div class="bg-gray-50 px-6 py-4 border-t border-gray-100">
  176. <div class="flex justify-between text-xs">
  177. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-orange-100 text-orange-800">
  178. 学习: {{ $dashboardData['prediction']['quick']['quick_prediction']['estimated_study_hours'] ?? 0 }}小时
  179. </span>
  180. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800">
  181. 置信度: {{ number_format(($dashboardData['prediction']['quick']['quick_prediction']['confidence_level'] ?? 0) * 100, 0) }}%
  182. </span>
  183. </div>
  184. </div>
  185. </div>
  186. @endif
  187. {{-- 学习路径 --}}
  188. @if (isset($dashboardData['learning_path']['analytics']))
  189. <div class="bg-white overflow-hidden shadow-sm rounded-xl border border-gray-200 hover:shadow-md transition-shadow duration-200">
  190. <div class="p-6">
  191. <div class="flex items-center justify-between">
  192. <div class="flex items-center">
  193. <div class="flex-shrink-0">
  194. <div class="w-12 h-12 bg-gradient-to-br from-purple-500 to-purple-600 rounded-xl flex items-center justify-center shadow-lg">
  195. <svg class="w-6 h-6 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  196. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7"></path>
  197. </svg>
  198. </div>
  199. </div>
  200. <div class="ml-4">
  201. <p class="text-sm font-medium text-gray-600">活跃路径</p>
  202. <p class="text-2xl font-bold text-gray-900 mt-1">
  203. {{ $dashboardData['learning_path']['analytics']['active_paths'] ?? 0 }}
  204. </p>
  205. </div>
  206. </div>
  207. </div>
  208. </div>
  209. <div class="bg-gray-50 px-6 py-4 border-t border-gray-100">
  210. <div class="flex justify-between text-xs">
  211. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
  212. 已完成: {{ $dashboardData['learning_path']['analytics']['completed_paths'] ?? 0 }}
  213. </span>
  214. <span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800">
  215. 效率: {{ number_format(($dashboardData['learning_path']['analytics']['average_efficiency_score'] ?? 0) * 100, 0) }}%
  216. </span>
  217. </div>
  218. </div>
  219. </div>
  220. @endif
  221. </div>
  222. </div>
  223. {{-- 主要内容区域 --}}
  224. <div class="mb-8">
  225. <div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
  226. {{-- 掌握度分析 --}}
  227. <div class="bg-white shadow-sm rounded-xl border border-gray-200">
  228. <div class="px-6 py-5 border-b border-gray-100 flex items-center justify-between">
  229. <h3 class="text-lg font-semibold text-gray-900 flex items-center">
  230. <svg class="w-5 h-5 mr-2 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  231. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
  232. </svg>
  233. 知识点掌握度
  234. </h3>
  235. <button
  236. wire:click="batchUpdateSkills"
  237. class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs font-medium rounded-lg text-indigo-700 bg-indigo-100 hover:bg-indigo-200 transition-colors duration-150"
  238. >
  239. <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  240. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
  241. </svg>
  242. 刷新
  243. </button>
  244. </div>
  245. <div class="p-6">
  246. @if (isset($dashboardData['mastery']['overview']['total_knowledge_points']))
  247. <div class="space-y-4">
  248. <div class="flex items-center justify-between text-sm">
  249. <span class="text-gray-600">总知识点数</span>
  250. <span class="font-medium text-gray-900">{{ $dashboardData['mastery']['overview']['total_knowledge_points'] }}</span>
  251. </div>
  252. <div class="w-full bg-gray-200 rounded-full h-2">
  253. <div class="bg-indigo-600 h-2 rounded-full" style="width: {{ $dashboardData['mastery']['overview']['average_mastery_level'] * 100 }}%"></div>
  254. </div>
  255. <div class="grid grid-cols-3 gap-4 mt-4">
  256. <div class="text-center">
  257. <div class="text-2xl font-semibold text-green-600">{{ $dashboardData['mastery']['overview']['mastered_knowledge_points'] }}</div>
  258. <div class="text-xs text-gray-500">已掌握 (≥85%)</div>
  259. </div>
  260. <div class="text-center">
  261. <div class="text-2xl font-semibold text-blue-600">{{ $dashboardData['mastery']['overview']['good_knowledge_points'] }}</div>
  262. <div class="text-xs text-gray-500">良好 (70-85%)</div>
  263. </div>
  264. <div class="text-center">
  265. <div class="text-2xl font-semibold text-red-600">{{ $dashboardData['mastery']['overview']['weak_knowledge_points'] }}</div>
  266. <div class="text-xs text-gray-500">薄弱 (<50%)</div>
  267. </div>
  268. </div>
  269. @if (!empty($dashboardData['mastery']['overview']['weak_knowledge_points_list']))
  270. <div class="mt-6">
  271. <h4 class="text-sm font-medium text-gray-900 mb-3">薄弱知识点</h4>
  272. <div class="space-y-2">
  273. @foreach (array_slice($dashboardData['mastery']['overview']['weak_knowledge_points_list'], 0, 5) as $weak)
  274. <div class="flex items-center justify-between p-3 bg-red-50 rounded-lg">
  275. <div class="flex items-center">
  276. <div class="w-2 h-2 bg-red-500 rounded-full mr-3"></div>
  277. <span class="text-sm font-medium text-gray-900">{{ $weak['kp_code'] ?? $weak['knowledge_point_code'] ?? 'N/A' }}</span>
  278. </div>
  279. <div class="flex items-center space-x-3">
  280. <span class="text-sm text-gray-600">{{ number_format(($weak['mastery_level'] ?? $weak['mastery'] ?? 0) * 100, 1) }}%</span>
  281. <button
  282. wire:click="recalculateMastery('{{ $weak['kp_code'] ?? $weak['knowledge_point_code'] ?? '' }}')"
  283. class="text-xs text-indigo-600 hover:text-indigo-800"
  284. >
  285. 重新计算
  286. </button>
  287. </div>
  288. </div>
  289. @endforeach
  290. </div>
  291. </div>
  292. @endif
  293. </div>
  294. @else
  295. <div class="text-center py-8 text-gray-500">
  296. 暂无掌握度数据
  297. </div>
  298. @endif
  299. </div>
  300. </div>
  301. {{-- 技能熟练度 --}}
  302. <div class="bg-white shadow-sm rounded-xl border border-gray-200">
  303. <div class="px-6 py-5 border-b border-gray-100 flex items-center justify-between">
  304. <h3 class="text-lg font-semibold text-gray-900 flex items-center">
  305. <svg class="w-5 h-5 mr-2 text-green-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  306. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
  307. </svg>
  308. 技能熟练度
  309. </h3>
  310. <button
  311. wire:click="batchUpdateSkills"
  312. class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs font-medium rounded-lg text-green-700 bg-green-100 hover:bg-green-200 transition-colors duration-150"
  313. >
  314. <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  315. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
  316. </svg>
  317. 批量更新
  318. </button>
  319. </div>
  320. <div class="p-6">
  321. @php
  322. $skillData = $dashboardData['skill']['proficiency']['data'] ?? [];
  323. if (!is_array($skillData)) {
  324. $skillData = [];
  325. }
  326. @endphp
  327. @if (!empty($skillData))
  328. <div class="space-y-4">
  329. @foreach (array_slice($skillData, 0, 5) as $skill)
  330. <div class="flex items-center justify-between">
  331. <div class="flex items-center flex-1">
  332. <div class="w-2 h-2 bg-green-500 rounded-full mr-3"></div>
  333. <div class="flex-1">
  334. <div class="text-sm font-medium text-gray-900">{{ $skill['skill_name'] ?? 'N/A' }}</div>
  335. <div class="w-full bg-gray-200 rounded-full h-1.5 mt-1">
  336. <div class="bg-green-500 h-1.5 rounded-full" style="width: {{ (($skill['proficiency_level'] ?? 0) * 100) }}%"></div>
  337. </div>
  338. </div>
  339. </div>
  340. <div class="ml-4 text-right">
  341. <div class="text-sm font-semibold text-gray-900">{{ number_format(($skill['proficiency_level'] ?? 0) * 100, 1) }}%</div>
  342. <div class="text-xs text-gray-500">{{ $skill['total_questions_attempted'] ?? 0 }}题</div>
  343. </div>
  344. </div>
  345. @endforeach
  346. </div>
  347. @else
  348. <div class="text-center py-8 text-gray-500">
  349. 暂无技能数据
  350. </div>
  351. @endif
  352. </div>
  353. </div>
  354. </div>
  355. {{-- 技能熟练度雷达图 - 已隐藏(功能已实现但暂时隐藏以简化界面) --}}
  356. {{-- <div class="mb-8">
  357. <div class="bg-white shadow-sm rounded-xl border border-gray-200">
  358. <div class="px-6 py-5 border-b border-gray-100">
  359. <h3 class="text-lg font-semibold text-gray-900 flex items-center">
  360. <svg class="w-5 h-5 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  361. <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>
  362. </svg>
  363. 技能熟练度雷达图
  364. </h3>
  365. </div>
  366. <div class="p-6">
  367. <livewire:skill-proficiency-radar :student-id="$studentId" />
  368. </div>
  369. </div>
  370. </div> --}}
  371. {{-- 提分预测和学习路径 - 已实现 --}}
  372. <div class="mb-8">
  373. <div class="grid grid-cols-1 gap-6 lg:grid-cols-2">
  374. {{-- 提分预测 --}}
  375. <div class="bg-white shadow-sm rounded-xl border border-gray-200">
  376. <div class="px-6 py-5 border-b border-gray-100 flex items-center justify-between">
  377. <h3 class="text-lg font-semibold text-gray-900 flex items-center">
  378. <svg class="w-5 h-5 mr-2 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  379. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
  380. </svg>
  381. 提分预测
  382. </h3>
  383. <button
  384. wire:click="generateQuickPrediction"
  385. class="inline-flex items-center px-3 py-1.5 border border-transparent text-xs font-medium rounded-lg text-yellow-700 bg-yellow-100 hover:bg-yellow-200 transition-colors duration-150"
  386. >
  387. <svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  388. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
  389. </svg>
  390. 快速预测
  391. </button>
  392. </div>
  393. <div class="p-6">
  394. {{-- 快速预测结果 --}}
  395. @if (isset($dashboardData['prediction']['quick']) && !empty($dashboardData['prediction']['quick']['quick_prediction']))
  396. @php
  397. $quickPrediction = $dashboardData['prediction']['quick']['quick_prediction'];
  398. @endphp
  399. {{-- 主要预测信息卡片 --}}
  400. <div class="bg-gradient-to-r from-blue-50 to-indigo-50 rounded-lg p-6 mb-6 border border-blue-200">
  401. <div class="flex items-center justify-between mb-4">
  402. <div>
  403. <h4 class="text-lg font-semibold text-gray-900">智能提分预测</h4>
  404. <p class="text-sm text-gray-600 mt-1">基于当前学习数据的AI分析</p>
  405. </div>
  406. <div class="text-right">
  407. <div class="text-2xl font-bold text-green-600">
  408. +{{ number_format($quickPrediction['improvement_potential'] ?? 0, 1) }}分
  409. </div>
  410. <div class="text-sm text-gray-500">预期提分</div>
  411. </div>
  412. </div>
  413. <div class="grid grid-cols-3 gap-4 mb-4">
  414. <div class="text-center">
  415. <div class="text-lg font-semibold text-gray-900">
  416. {{ $quickPrediction['current_score'] ?? 0 }}分
  417. </div>
  418. <div class="text-xs text-gray-500">当前分数</div>
  419. </div>
  420. <div class="text-center">
  421. <div class="text-lg font-semibold text-blue-600">
  422. {{ $quickPrediction['predicted_score'] ?? 0 }}分
  423. </div>
  424. <div class="text-xs text-gray-500">预测分数</div>
  425. </div>
  426. <div class="text-center">
  427. <div class="text-lg font-semibold text-purple-600">
  428. {{ $quickPrediction['estimated_study_hours'] ?? 0 }}h
  429. </div>
  430. <div class="text-xs text-gray-500">建议学习时间</div>
  431. </div>
  432. </div>
  433. <div class="flex items-center justify-between">
  434. <div class="flex items-center space-x-2">
  435. <span class="text-sm text-gray-600">置信度:</span>
  436. <div class="flex items-center">
  437. <div class="w-20 bg-gray-200 rounded-full h-2 mr-2">
  438. <div class="bg-blue-600 h-2 rounded-full" style="width: {{ ($quickPrediction['confidence_level'] ?? 0) * 100 }}%"></div>
  439. </div>
  440. <span class="text-sm font-medium text-gray-900">{{ number_format(($quickPrediction['confidence_level'] ?? 0) * 100, 0) }}%</span>
  441. </div>
  442. </div>
  443. <div class="text-xs text-gray-500">
  444. {{ $quickPrediction['weak_knowledge_points_count'] ?? 0 }}个薄弱知识点
  445. </div>
  446. </div>
  447. </div>
  448. {{-- 优先学习主题 --}}
  449. @if (!empty($quickPrediction['priority_topics']))
  450. <div class="mb-6">
  451. <h5 class="text-sm font-medium text-gray-900 mb-3 flex items-center">
  452. <svg class="w-4 h-4 mr-2 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  453. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
  454. </svg>
  455. 优先学习主题 (前5个)
  456. </h5>
  457. <div class="space-y-2">
  458. @foreach (array_slice($quickPrediction['priority_topics'], 0, 5) as $topic)
  459. <div class="flex items-center justify-between p-3 bg-yellow-50 rounded-lg border border-yellow-200">
  460. <div class="flex items-center space-x-3">
  461. <div class="w-8 h-8 bg-yellow-100 rounded-full flex items-center justify-center">
  462. <span class="text-xs font-medium text-yellow-800">{{ substr($topic['kp_code'] ?? '', -2) }}</span>
  463. </div>
  464. <div>
  465. <div class="text-sm font-medium text-gray-900">{{ $topic['kp_code'] ?? 'N/A' }}</div>
  466. <div class="text-xs text-gray-500">掌握度: {{ number_format(($topic['mastery_level'] ?? 0) * 100, 1) }}%</div>
  467. </div>
  468. </div>
  469. <div class="text-right">
  470. <div class="text-sm font-medium text-gray-900">优先级</div>
  471. <div class="text-xs text-gray-500">{{ number_format($topic['priority_score'] ?? 0, 2) }}</div>
  472. </div>
  473. </div>
  474. @endforeach
  475. </div>
  476. </div>
  477. @endif
  478. {{-- 学习建议 --}}
  479. @if (!empty($quickPrediction['recommended_actions']))
  480. <div>
  481. <h5 class="text-sm font-medium text-gray-900 mb-3 flex items-center">
  482. <svg class="w-4 h-4 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  483. <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>
  484. </svg>
  485. 个性化学习建议
  486. </h5>
  487. <div class="space-y-3">
  488. @foreach (array_slice($quickPrediction['recommended_actions'], 0, 3) as $recommendation)
  489. <div class="p-3 bg-blue-50 rounded-lg border border-blue-200">
  490. <div class="flex items-center justify-between mb-2">
  491. <span class="text-sm font-medium text-gray-900">{{ $recommendation['kp_code'] ?? 'N/A' }}</span>
  492. <span class="text-xs text-gray-500">
  493. {{ number_format(($recommendation['current_mastery'] ?? 0) * 100, 0) }}% → {{ number_format(($recommendation['target_mastery'] ?? 0) * 100, 0) }}%
  494. </span>
  495. </div>
  496. <div class="flex flex-wrap gap-1">
  497. @foreach (($recommendation['actions'] ?? []) as $action)
  498. <span class="inline-flex items-center px-2 py-1 rounded-full text-xs bg-blue-100 text-blue-800">
  499. {{ $action }}
  500. </span>
  501. @endforeach
  502. </div>
  503. </div>
  504. @endforeach
  505. </div>
  506. </div>
  507. @endif
  508. {{-- 历史预测记录 --}}
  509. @elseif (!empty($dashboardData['prediction']['list']['predictions']))
  510. @php
  511. $historicalPredictions = $dashboardData['prediction']['list']['predictions'];
  512. @endphp
  513. <div class="space-y-4">
  514. <h5 class="text-sm font-medium text-gray-900 mb-3">历史预测记录</h5>
  515. @foreach (array_slice($historicalPredictions, 0, 3) as $prediction)
  516. <div class="p-4 border border-gray-200 rounded-lg">
  517. <div class="flex items-center justify-between mb-2">
  518. <div class="text-sm font-medium text-gray-900">{{ $prediction['target_entity'] ?? 'N/A' }}</div>
  519. <span class="text-xs text-gray-500">{{ $prediction['prediction_date'] ?? date('m-d') }}</span>
  520. </div>
  521. <div class="flex items-center justify-between">
  522. <div class="text-sm text-gray-600">
  523. 当前: {{ $prediction['current_score'] ?? 0 }}分 →
  524. <span class="font-semibold text-gray-900">{{ $prediction['predicted_score'] ?? 0 }}分</span>
  525. </div>
  526. <div class="text-sm font-semibold text-green-600">
  527. +{{ number_format(($prediction['predicted_score'] ?? 0) - ($prediction['current_score'] ?? 0), 1) }}分
  528. </div>
  529. </div>
  530. </div>
  531. @endforeach
  532. </div>
  533. @else
  534. <div class="text-center py-8 text-gray-500">
  535. <div class="mb-4">
  536. <svg class="w-12 h-12 mx-auto text-gray-300" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  537. <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>
  538. </svg>
  539. </div>
  540. <p class="text-sm font-medium text-gray-900 mb-1">暂无预测数据</p>
  541. <p class="text-xs text-gray-500 mb-4">点击"快速预测"按钮生成AI预测分析</p>
  542. <button
  543. wire:click="generateQuickPrediction"
  544. class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-lg text-white bg-blue-600 hover:bg-blue-700 transition-colors duration-200"
  545. >
  546. <svg class="w-4 h-4 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  547. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
  548. </svg>
  549. 生成快速预测
  550. </button>
  551. </div>
  552. @endif
  553. </div>
  554. </div>
  555. </div>
  556. {{-- 掌握度热力图 - 已隐藏(功能已实现但暂时隐藏以简化界面) --}}
  557. {{-- <div class="mb-8">
  558. <div class="bg-white shadow-sm rounded-xl border border-gray-200">
  559. <div class="px-6 py-5 border-b border-gray-100">
  560. <h3 class="text-lg font-semibold text-gray-900 flex items-center">
  561. <svg class="w-5 h-5 mr-2 text-red-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  562. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 5a1 1 0 011-1h14a1 1 0 011 1v2a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM4 13a1 1 0 011-1h6a1 1 0 011 1v6a1 1 0 01-1 1H5a1 1 0 01-1-1v-6zM16 13a1 1 0 011-1h2a1 1 0 011 1v6a1 1 0 01-1 1h-2a1 1 0 01-1-1v-6z"></path>
  563. </svg>
  564. 知识点掌握度热力图
  565. </h3>
  566. </div>
  567. <div class="p-6">
  568. <livewire:mastery-heatmap :student-id="$studentId" />
  569. </div>
  570. </div>
  571. </div> --}}
  572. {{-- 知识点依赖关系图 - 已隐藏(功能已实现但暂时隐藏以简化界面) --}}
  573. {{-- <div class="mb-8">
  574. <div class="bg-white shadow-sm rounded-xl border border-gray-200">
  575. <div class="px-6 py-5 border-b border-gray-100">
  576. <h3 class="text-lg font-semibold text-gray-900 flex items-center">
  577. <svg class="w-5 h-5 mr-2 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  578. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
  579. </svg>
  580. 知识点依赖关系图
  581. </h3>
  582. </div>
  583. <div class="p-6">
  584. <livewire:knowledge-dependency-graph :student-id="$studentId" />
  585. </div>
  586. </div>
  587. </div> --}}
  588. {{-- 推荐学习路径 - 已隐藏(功能已实现但暂时隐藏以简化界面) --}}
  589. {{-- @if (isset($dashboardData['learning_path']['recommendations']['recommendations']))
  590. <div class="mb-8">
  591. <div class="bg-white shadow-sm rounded-xl border border-gray-200">
  592. <div class="px-6 py-5 border-b border-gray-100">
  593. <h3 class="text-lg font-semibold text-gray-900 flex items-center">
  594. <svg class="w-5 h-5 mr-2 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  595. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"></path>
  596. </svg>
  597. 推荐学习路径
  598. </h3>
  599. </div>
  600. <div class="p-6">
  601. <div class="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
  602. @foreach ($dashboardData['learning_path']['recommendations']['recommendations'] as $recommendation)
  603. <div class="p-4 border border-gray-200 rounded-lg hover:border-indigo-300 transition-colors">
  604. <div class="flex items-center mb-3">
  605. <div class="w-8 h-8 bg-indigo-100 rounded-full flex items-center justify-center mr-3">
  606. <svg class="w-4 h-4 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
  607. <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
  608. </svg>
  609. </div>
  610. <div class="flex-1">
  611. <div class="text-sm font-medium text-gray-900">{{ $recommendation['target_kp_name'] }}</div>
  612. <div class="text-xs text-gray-500">{{ $recommendation['target_kp_code'] }}</div>
  613. </div>
  614. </div>
  615. <div class="mb-3">
  616. <div class="flex items-center justify-between text-xs text-gray-600 mb-1">
  617. <span>当前掌握度</span>
  618. <span class="font-medium">{{ number_format($recommendation['current_mastery'] * 100, 1) }}%</span>
  619. </div>
  620. <div class="w-full bg-gray-200 rounded-full h-1.5">
  621. <div class="bg-indigo-500 h-1.5 rounded-full" style="width: {{ $recommendation['current_mastery'] * 100 }}%"></div>
  622. </div>
  623. </div>
  624. <p class="text-xs text-gray-600 mb-3">{{ $recommendation['reason'] }}</p>
  625. <button class="w-full text-xs bg-indigo-600 text-white py-2 px-3 rounded-md hover:bg-indigo-700 transition-colors">
  626. 生成学习路径
  627. </button>
  628. </div>
  629. @endforeach
  630. </div>
  631. </div>
  632. </div>
  633. @endif --}}
  634. </div>
  635. </div>
  636. @endif
  637. {{-- 通知脚本 --}}
  638. <script>
  639. document.addEventListener('notify', (event) => {
  640. const message = event.detail.message;
  641. const type = event.detail.type || 'info';
  642. alert(message);
  643. });
  644. </script>