MistakeTrendsChart.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. <?php
  2. namespace App\Livewire\MistakeBook;
  3. use App\Models\MistakeRecord;
  4. use Filament\Widgets\ChartWidget;
  5. class MistakeTrendsChart extends ChartWidget
  6. {
  7. public ?string $studentId;
  8. protected static ?int $sort = 1;
  9. protected int | string | array $columnSpan = 'full';
  10. public function mount(?string $studentId = null): void
  11. {
  12. $this->studentId = $studentId;
  13. }
  14. protected function getData(): array
  15. {
  16. if (!$this->studentId) {
  17. return [
  18. 'datasets' => [],
  19. 'labels' => [],
  20. ];
  21. }
  22. // 获取最近30天的错题趋势数据
  23. $trends = $this->calculateTrends($this->studentId);
  24. return [
  25. 'datasets' => [
  26. [
  27. 'label' => '新增错题',
  28. 'data' => $trends['daily'],
  29. 'backgroundColor' => 'rgba(239, 68, 68, 0.5)',
  30. 'borderColor' => 'rgb(239, 68, 68)',
  31. 'borderWidth' => 2,
  32. 'fill' => true,
  33. ],
  34. [
  35. 'label' => '复习完成',
  36. 'data' => $trends['reviewed'],
  37. 'backgroundColor' => 'rgba(34, 197, 94, 0.5)',
  38. 'borderColor' => 'rgb(34, 197, 94)',
  39. 'borderWidth' => 2,
  40. 'fill' => true,
  41. ],
  42. ],
  43. 'labels' => $trends['labels'],
  44. ];
  45. }
  46. protected function getType(): string
  47. {
  48. return 'line';
  49. }
  50. protected function getOptions(): array
  51. {
  52. return [
  53. 'responsive' => true,
  54. 'maintainAspectRatio' => false,
  55. 'plugins' => [
  56. 'legend' => [
  57. 'display' => true,
  58. 'position' => 'top',
  59. ],
  60. ],
  61. 'scales' => [
  62. 'y' => [
  63. 'beginAtZero' => true,
  64. 'ticks' => [
  65. 'stepSize' => 1,
  66. ],
  67. ],
  68. ],
  69. ];
  70. }
  71. private function calculateTrends(string $studentId): array
  72. {
  73. $days = collect(range(29, 0))->map(function ($day) use ($studentId) {
  74. $date = now()->subDays($day)->startOfDay();
  75. $endDate = (clone $date)->endOfDay();
  76. $created = MistakeRecord::forStudent($studentId)
  77. ->whereBetween('created_at', [$date, $endDate])
  78. ->count();
  79. $reviewed = MistakeRecord::forStudent($studentId)
  80. ->whereBetween('reviewed_at', [$date, $endDate])
  81. ->count();
  82. return [
  83. 'date' => $date->format('m-d'),
  84. 'created' => $created,
  85. 'reviewed' => $reviewed,
  86. ];
  87. });
  88. return [
  89. 'labels' => $days->pluck('date')->toArray(),
  90. 'daily' => $days->pluck('created')->toArray(),
  91. 'reviewed' => $days->pluck('reviewed')->toArray(),
  92. ];
  93. }
  94. }