GenerateActivityReportCommand.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <?php
  2. namespace App\Module\Activity\Commands;
  3. use App\Module\Activity\Enums\ACTIVITY_STATUS;
  4. use App\Module\Activity\Enums\PARTICIPATION_STATUS;
  5. use App\Module\Activity\Enums\REWARD_STATUS;
  6. use App\Module\Activity\Models\ActivityConfig;
  7. use App\Module\Activity\Models\ActivityParticipation;
  8. use App\Module\Activity\Models\UserActivityData;
  9. use Carbon\Carbon;
  10. use Illuminate\Console\Command;
  11. use Illuminate\Support\Facades\DB;
  12. use Illuminate\Support\Facades\File;
  13. /**
  14. * 生成活动报告命令
  15. */
  16. class GenerateActivityReportCommand extends Command
  17. {
  18. /**
  19. * 命令名称
  20. *
  21. * @var string
  22. */
  23. protected $signature = 'activity:report {activity_id? : 活动ID,不指定则生成所有活动的报告} {--output=storage/activity_reports : 报告输出目录}';
  24. /**
  25. * 命令描述
  26. *
  27. * @var string
  28. */
  29. protected $description = '生成活动参与和完成情况报告';
  30. /**
  31. * 执行命令
  32. *
  33. * @return int
  34. */
  35. public function handle()
  36. {
  37. $activityId = $this->argument('activity_id');
  38. $outputDir = $this->option('output');
  39. // 创建输出目录
  40. if (!File::exists($outputDir)) {
  41. File::makeDirectory($outputDir, 0755, true);
  42. }
  43. // 获取活动列表
  44. if ($activityId) {
  45. $activities = ActivityConfig::where('id', $activityId)->get();
  46. if ($activities->isEmpty()) {
  47. $this->error("活动 ID {$activityId} 不存在");
  48. return 1;
  49. }
  50. } else {
  51. $activities = ActivityConfig::all();
  52. if ($activities->isEmpty()) {
  53. $this->info("没有找到任何活动");
  54. return 0;
  55. }
  56. }
  57. $this->info("开始生成 " . count($activities) . " 个活动的报告...");
  58. $timestamp = Carbon::now()->format('YmdHis');
  59. $summaryData = [];
  60. foreach ($activities as $activity) {
  61. $this->info("正在处理活动: [{$activity->id}] {$activity->name}");
  62. // 收集活动数据
  63. $participantCount = ActivityParticipation::where('activity_id', $activity->id)
  64. ->distinct('user_id')
  65. ->count('user_id');
  66. $completedCount = ActivityParticipation::where('activity_id', $activity->id)
  67. ->where('completion_status', PARTICIPATION_STATUS::COMPLETED)
  68. ->count();
  69. $inProgressCount = ActivityParticipation::where('activity_id', $activity->id)
  70. ->where('completion_status', PARTICIPATION_STATUS::IN_PROGRESS)
  71. ->count();
  72. $failedCount = ActivityParticipation::where('activity_id', $activity->id)
  73. ->where('completion_status', PARTICIPATION_STATUS::FAILED)
  74. ->count();
  75. $rewardClaimedCount = ActivityParticipation::where('activity_id', $activity->id)
  76. ->where('reward_status', REWARD_STATUS::CLAIMED)
  77. ->count();
  78. $rewardNotClaimedCount = ActivityParticipation::where('activity_id', $activity->id)
  79. ->where('reward_status', REWARD_STATUS::NOT_CLAIMED)
  80. ->count();
  81. $rewardExpiredCount = ActivityParticipation::where('activity_id', $activity->id)
  82. ->where('reward_status', REWARD_STATUS::EXPIRED)
  83. ->count();
  84. // 计算平均进度
  85. $averageProgress = UserActivityData::where('activity_id', $activity->id)
  86. ->avg('progress') ?: 0;
  87. // 计算完成率
  88. $completionRate = $participantCount > 0 ? round(($completedCount / $participantCount) * 100, 2) : 0;
  89. // 计算奖励领取率
  90. $rewardClaimRate = $completedCount > 0 ? round(($rewardClaimedCount / $completedCount) * 100, 2) : 0;
  91. // 收集每日参与数据
  92. $dailyParticipations = DB::table('activity_participation')
  93. ->select(DB::raw('DATE(participate_time) as date'), DB::raw('COUNT(*) as count'))
  94. ->where('activity_id', $activity->id)
  95. ->groupBy('date')
  96. ->orderBy('date')
  97. ->get();
  98. // 收集每日完成数据
  99. $dailyCompletions = DB::table('activity_participation')
  100. ->select(DB::raw('DATE(completion_time) as date'), DB::raw('COUNT(*) as count'))
  101. ->where('activity_id', $activity->id)
  102. ->where('completion_status', PARTICIPATION_STATUS::COMPLETED)
  103. ->groupBy('date')
  104. ->orderBy('date')
  105. ->get();
  106. // 生成报告内容
  107. $reportContent = "# 活动报告: [{$activity->id}] {$activity->name}\n\n";
  108. $reportContent .= "生成时间: " . Carbon::now()->toDateTimeString() . "\n\n";
  109. $reportContent .= "## 活动基本信息\n\n";
  110. $reportContent .= "- 活动ID: {$activity->id}\n";
  111. $reportContent .= "- 活动名称: {$activity->name}\n";
  112. $reportContent .= "- 活动类型: " . \App\Module\Activity\Enums\ACTIVITY_TYPE::getName($activity->type) . "\n";
  113. $reportContent .= "- 开始时间: {$activity->start_time}\n";
  114. $reportContent .= "- 结束时间: {$activity->end_time}\n";
  115. $reportContent .= "- 当前状态: " . ACTIVITY_STATUS::getName($activity->status) . "\n";
  116. $reportContent .= "\n## 参与情况统计\n\n";
  117. $reportContent .= "- 总参与人数: {$participantCount}\n";
  118. $reportContent .= "- 已完成人数: {$completedCount}\n";
  119. $reportContent .= "- 进行中人数: {$inProgressCount}\n";
  120. $reportContent .= "- 已失败人数: {$failedCount}\n";
  121. $reportContent .= "- 完成率: {$completionRate}%\n";
  122. $reportContent .= "- 平均进度: " . round($averageProgress, 2) . "\n";
  123. $reportContent .= "\n## 奖励领取情况\n\n";
  124. $reportContent .= "- 已领取奖励人数: {$rewardClaimedCount}\n";
  125. $reportContent .= "- 未领取奖励人数: {$rewardNotClaimedCount}\n";
  126. $reportContent .= "- 已过期奖励人数: {$rewardExpiredCount}\n";
  127. $reportContent .= "- 奖励领取率: {$rewardClaimRate}%\n";
  128. $reportContent .= "\n## 每日参与人数\n\n";
  129. $reportContent .= "| 日期 | 参与人数 |\n";
  130. $reportContent .= "|------|--------|\n";
  131. foreach ($dailyParticipations as $data) {
  132. $reportContent .= "| {$data->date} | {$data->count} |\n";
  133. }
  134. $reportContent .= "\n## 每日完成人数\n\n";
  135. $reportContent .= "| 日期 | 完成人数 |\n";
  136. $reportContent .= "|------|--------|\n";
  137. foreach ($dailyCompletions as $data) {
  138. $reportContent .= "| {$data->date} | {$data->count} |\n";
  139. }
  140. // 保存报告文件
  141. $filename = "activity_{$activity->id}_report_{$timestamp}.md";
  142. $filePath = "{$outputDir}/{$filename}";
  143. File::put($filePath, $reportContent);
  144. $this->info("活动报告已保存到: {$filePath}");
  145. // 收集汇总数据
  146. $summaryData[] = [
  147. 'id' => $activity->id,
  148. 'name' => $activity->name,
  149. 'status' => ACTIVITY_STATUS::getName($activity->status),
  150. 'participants' => $participantCount,
  151. 'completed' => $completedCount,
  152. 'completion_rate' => $completionRate . '%',
  153. 'rewards_claimed' => $rewardClaimedCount,
  154. 'claim_rate' => $rewardClaimRate . '%'
  155. ];
  156. }
  157. // 生成汇总报告
  158. if (count($activities) > 1) {
  159. $summaryContent = "# 活动汇总报告\n\n";
  160. $summaryContent .= "生成时间: " . Carbon::now()->toDateTimeString() . "\n\n";
  161. $summaryContent .= "## 活动列表\n\n";
  162. $summaryContent .= "| ID | 活动名称 | 状态 | 参与人数 | 完成人数 | 完成率 | 领取奖励人数 | 领取率 |\n";
  163. $summaryContent .= "|----|---------|----|--------|--------|-------|------------|-------|\n";
  164. foreach ($summaryData as $data) {
  165. $summaryContent .= "| {$data['id']} | {$data['name']} | {$data['status']} | {$data['participants']} | {$data['completed']} | {$data['completion_rate']} | {$data['rewards_claimed']} | {$data['claim_rate']} |\n";
  166. }
  167. // 保存汇总报告
  168. $summaryFilename = "activity_summary_report_{$timestamp}.md";
  169. $summaryFilePath = "{$outputDir}/{$summaryFilename}";
  170. File::put($summaryFilePath, $summaryContent);
  171. $this->info("汇总报告已保存到: {$summaryFilePath}");
  172. }
  173. $this->info("活动报告生成完成");
  174. return 0;
  175. }
  176. }