PointDashboardController.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <?php
  2. namespace App\Module\Point\AdminControllers;
  3. use App\Module\Point\Repositorys\PointRepository;
  4. use App\Module\Point\Repositorys\PointLogRepository;
  5. use App\Module\Point\Repositorys\PointAdminRepository;
  6. use App\Module\Point\Repositorys\PointCirculationRepository;
  7. use App\Module\Point\Repositorys\PointTransferRepository;
  8. use App\Module\Point\Repositorys\PointOrderRepository;
  9. use Dcat\Admin\Layout\Content;
  10. use Dcat\Admin\Widgets\Card;
  11. use Dcat\Admin\Widgets\InfoBox;
  12. use Spatie\RouteAttributes\Attributes\Get;
  13. use UCore\DcatAdmin\AdminController;
  14. /**
  15. * 种植点数统计仪表板控制器
  16. *
  17. * 路由: /admin/point/dashboard
  18. * 菜单: 积分管理 -> 统计仪表板
  19. * 功能: 展示种植点数系统的统计数据和分析图表
  20. */
  21. class PointDashboardController extends AdminController
  22. {
  23. /**
  24. * 页面标题
  25. */
  26. protected $title = '种植点数统计仪表板';
  27. /**
  28. * 仪表板页面
  29. */
  30. #[Get('point/dashboard', name: 'admin.point.dashboard.index')]
  31. public function index(Content $content)
  32. {
  33. return $content
  34. ->title($this->title)
  35. ->description('积分系统数据统计')
  36. ->body($this->overview())
  37. ->body($this->pointTypeStats())
  38. ->body($this->recentActivity());
  39. }
  40. /**
  41. * 概览统计
  42. */
  43. protected function overview()
  44. {
  45. $pointRepo = new PointRepository();
  46. $logRepo = new PointLogRepository();
  47. $adminRepo = new PointAdminRepository();
  48. $circulationRepo = new PointCirculationRepository();
  49. $transferRepo = new PointTransferRepository();
  50. $orderRepo = new PointOrderRepository();
  51. // 基础统计
  52. $totalAccounts = $pointRepo->model()->count();
  53. $totalLogs = $logRepo->model()->count();
  54. $totalAdminOps = $adminRepo->model()->count();
  55. $totalCirculations = $circulationRepo->model()->count();
  56. $totalTransfers = $transferRepo->model()->count();
  57. $totalOrders = $orderRepo->model()->count();
  58. // 今日统计
  59. $todayStart = strtotime('today');
  60. $todayLogs = $logRepo->model()->where('create_time', '>=', $todayStart)->count();
  61. $todayAdminOps = $adminRepo->model()->where('create_time', '>=', $todayStart)->count();
  62. return new Card('系统概览', [
  63. new InfoBox('积分账户总数', 'users', 'aqua', route('admin.point.index'), $totalAccounts),
  64. new InfoBox('积分日志总数', 'file-text-o', 'green', route('admin.point-log.index'), $totalLogs),
  65. new InfoBox('管理员操作', 'cog', 'yellow', route('admin.point-admin.index'), $totalAdminOps),
  66. new InfoBox('今日日志', 'calendar', 'red', route('admin.point-log.index'), $todayLogs),
  67. ]);
  68. }
  69. /**
  70. * 积分类型统计
  71. */
  72. protected function pointTypeStats()
  73. {
  74. $pointRepo = new PointRepository();
  75. $stats = $pointRepo->getPointTypeStats();
  76. $pointTypes = [
  77. 1 => '经验积分',
  78. 2 => '成就积分',
  79. 3 => '活动积分',
  80. 4 => '签到积分',
  81. 5 => '推荐积分',
  82. ];
  83. $html = '<div class="row">';
  84. foreach ($stats as $stat) {
  85. $pointId = $stat['point_id'];
  86. $typeName = $pointTypes[$pointId] ?? "积分{$pointId}";
  87. $userCount = $stat['user_count'];
  88. $totalBalance = number_format($stat['total_balance']);
  89. $avgBalance = number_format($stat['avg_balance'], 2);
  90. $html .= "
  91. <div class='col-md-4'>
  92. <div class='info-box'>
  93. <span class='info-box-icon bg-blue'><i class='fa fa-star'></i></span>
  94. <div class='info-box-content'>
  95. <span class='info-box-text'>{$typeName}</span>
  96. <span class='info-box-number'>{$userCount} 用户</span>
  97. <div class='progress'>
  98. <div class='progress-bar' style='width: 70%'></div>
  99. </div>
  100. <span class='progress-description'>
  101. 总积分: {$totalBalance} | 平均: {$avgBalance}
  102. </span>
  103. </div>
  104. </div>
  105. </div>
  106. ";
  107. }
  108. $html .= '</div>';
  109. return new Card('积分类型统计', $html);
  110. }
  111. /**
  112. * 最近活动
  113. */
  114. protected function recentActivity()
  115. {
  116. $logRepo = new PointLogRepository();
  117. $recentLogs = $logRepo->model()
  118. ->orderBy('create_time', 'desc')
  119. ->limit(10)
  120. ->get();
  121. $pointTypes = [
  122. 1 => '经验积分',
  123. 2 => '成就积分',
  124. 3 => '活动积分',
  125. 4 => '签到积分',
  126. 5 => '推荐积分',
  127. ];
  128. $html = '<div class="table-responsive"><table class="table table-striped">';
  129. $html .= '<thead><tr><th>时间</th><th>用户</th><th>积分类型</th><th>变更</th><th>备注</th></tr></thead>';
  130. $html .= '<tbody>';
  131. foreach ($recentLogs as $log) {
  132. $time = date('m-d H:i', $log->create_time);
  133. $pointType = $pointTypes[$log->point_id] ?? "积分{$log->point_id}";
  134. $amount = $log->amount > 0 ? "+{$log->amount}" : $log->amount;
  135. $amountClass = $log->amount > 0 ? 'text-success' : 'text-danger';
  136. $remark = mb_substr($log->remark, 0, 20) . (mb_strlen($log->remark) > 20 ? '...' : '');
  137. $html .= "
  138. <tr>
  139. <td>{$time}</td>
  140. <td>用户{$log->user_id}</td>
  141. <td>{$pointType}</td>
  142. <td class='{$amountClass}'>{$amount}</td>
  143. <td>{$remark}</td>
  144. </tr>
  145. ";
  146. }
  147. $html .= '</tbody></table></div>';
  148. return new Card('最近活动', $html);
  149. }
  150. }