*/ class MakeStatisticalResourceCommand extends Command { /** * The name of command. * * @var string */ protected $signature = 'make:statistical-resource {date?}'; /** * The description of command. * * @var string */ protected $description = '制造数据'; /** * The type of class being generated. * * @var string */ protected $type = 'permission'; const TotalNums = 50; const PageNums = 50; /** * Execute the command. * * @return void * @see fire() */ public function handle() { $day = $this->argument('date'); $now = Carbon::now()->toDateString(); if (!$day) { $day = Carbon::yesterday()->toDateString(); } else { $now = Carbon::parse($day)->toDateString(); $day = Carbon::parse($day)->subDay()->toDateString(); } $this->line($day); $isOpenGroup = (bool)Setting::byCodeGetSetting('h5_paihangbang_is_group_user'); if ($isOpenGroup) { $this->openGroup($day, $now); return; } $this->noOpenGroup($day, $now); $this->line('ok'); } /** * 开分组 * @param $day * @param $now * @return void */ public function openGroup($day, $now) { $userGroupMaps = User::GroupMaps; //1.当天的排行榜 $startTimeTxt = Carbon::parse($day)->startOfDay()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfDay()->format('Y年m月d日 H:i'); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; foreach ($userGroupMaps as $map) { $group_id = $map['id']; $model = Ranking::query()->where('group_id', $group_id); $rankings = $model->clone()->where('day_type', DayTypeEnum::day)->where('day', $day)->with(['user'])->orderByDesc('xuefen')->limit(self::TotalNums)->get()->toArray(); $this->makeRangingImg($rankings, $timeTxt, $day, DayTypeEnum::day, $group_id); $xueba = $model->clone()->where('day_type', DayTypeEnum::day)->where('day', $day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $day, DayTypeEnum::day, $group_id); //2.周排行榜 $firstDay = Carbon::parse($now)->startOfWeek(); if (Carbon::parse($now)->isSameDay($firstDay)) { $startTimeTxt = Carbon::parse($day)->startOfWeek()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfWeek()->format('Y年m月d日 H:i'); $start_day = Carbon::parse($day)->startOfWeek()->toDateString(); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; $this->line("周:" . $group_id); $rankings = $model->clone()->where('day_type', DayTypeEnum::week)->where('day', $start_day)->with('user')->limit(self::TotalNums)->orderByDesc('xuefen')->get(); $this->makeRangingImg($rankings, $timeTxt, $start_day, DayTypeEnum::week, $group_id); $xueba = $model->clone()->where('day_type', DayTypeEnum::week)->where('day', $start_day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $start_day, DayTypeEnum::week, $group_id); } //3.月排行榜 $firstDay = Carbon::parse($now)->startOfMonth(); if (Carbon::parse($now)->isSameDay($firstDay)) { $startTimeTxt = Carbon::parse($day)->startOfMonth()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfMonth()->format('Y年m月d日 H:i'); $start_day = Carbon::parse($day)->startOfMonth()->toDateString(); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; $rankings = $model->clone()->where('day_type', DayTypeEnum::month)->where('day', $start_day)->with('user')->limit(self::TotalNums)->orderByDesc('xuefen')->get(); $this->makeRangingImg($rankings, $timeTxt, $start_day, DayTypeEnum::month, $group_id); $xueba = $model->clone()->where('day_type', DayTypeEnum::month)->where('day', $start_day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $start_day, DayTypeEnum::month, $group_id); } //4.季排行榜 $firstDay = Carbon::parse($now)->startOfQuarter(); if (Carbon::parse($now)->isSameDay($firstDay)) { $startTimeTxt = Carbon::parse($day)->startOfQuarter()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfQuarter()->format('Y年m月d日 H:i'); $this->line("季:{$startTimeTxt}--{$endTimeTxt}"); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; $start_day = Carbon::parse($day)->startOfQuarter()->toDateString(); $rankings = $model->clone()->where('day_type', DayTypeEnum::quarter)->where('day', $start_day)->with('user')->limit(self::TotalNums)->orderByDesc('xuefen')->get(); $this->makeRangingImg($rankings, $timeTxt, $start_day, DayTypeEnum::quarter, $group_id); $xueba = $model->clone()->where('day_type', DayTypeEnum::quarter)->where('day', $start_day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $start_day, DayTypeEnum::quarter, $group_id); } //5.年排行榜 $firstDay = Carbon::parse($now)->startOfYear(); if (Carbon::parse($now)->isSameDay($firstDay)) { $startTimeTxt = Carbon::parse($day)->startOfYear()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfYear()->format('Y年m月d日 H:i'); $start_day = Carbon::parse($day)->startOfYear()->toDateString(); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; $rankings = $model->clone()->where('day_type', DayTypeEnum::year)->where('day', $start_day)->with('user')->limit(self::TotalNums)->orderByDesc('xuefen')->get(); $this->makeRangingImg($rankings, $timeTxt, $start_day, DayTypeEnum::year, $group_id); $xueba = $model->clone()->where('day_type', DayTypeEnum::year)->where('day', $start_day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $start_day, DayTypeEnum::year, $group_id); } } } /** * 没有开分组 * @param $day * @param $now * @return void */ public function noOpenGroup($day, $now) { //1.当天的排行榜 $startTimeTxt = Carbon::parse($day)->startOfDay()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfDay()->format('Y年m月d日 H:i'); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; $rankings = Ranking::query()->where('day_type', DayTypeEnum::day)->where('day', $day)->with(['user'])->orderByDesc('xuefen')->limit(30)->get()->toArray(); $this->makeRangingImg($rankings, $timeTxt, $day, DayTypeEnum::day); $xueba = Ranking::query()->where('day_type', DayTypeEnum::day)->where('day', $day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $day, DayTypeEnum::day); //2.周排行榜 $firstDay = Carbon::parse($now)->startOfWeek(); if (Carbon::parse($now)->isSameDay($firstDay)) { $startTimeTxt = Carbon::parse($day)->startOfWeek()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfWeek()->format('Y年m月d日 H:i'); $start_day = Carbon::parse($day)->startOfWeek()->toDateString(); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; $rankings = Ranking::query()->where('day_type', DayTypeEnum::week)->where('day', $start_day)->with('user')->limit(self::TotalNums)->orderByDesc('xuefen')->get(); $this->makeRangingImg($rankings, $timeTxt, $start_day, DayTypeEnum::week); $xueba = Ranking::query()->where('day_type', DayTypeEnum::week)->where('day', $start_day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $start_day, DayTypeEnum::week); } //3.月排行榜 $firstDay = Carbon::parse($now)->startOfMonth(); if (Carbon::parse($now)->isSameDay($firstDay)) { $startTimeTxt = Carbon::parse($day)->startOfMonth()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfMonth()->format('Y年m月d日 H:i'); $start_day = Carbon::parse($day)->startOfMonth()->toDateString(); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; $rankings = Ranking::query()->where('day_type', DayTypeEnum::month)->where('day', $start_day)->with('user')->limit(self::TotalNums)->orderByDesc('xuefen')->get(); $this->makeRangingImg($rankings, $timeTxt, $start_day, DayTypeEnum::month); $xueba = Ranking::query()->where('day_type', DayTypeEnum::month)->where('day', $start_day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $start_day, DayTypeEnum::month); } //4.季排行榜 $firstDay = Carbon::parse($now)->startOfQuarter(); if (Carbon::parse($now)->isSameDay($firstDay)) { $startTimeTxt = Carbon::parse($day)->startOfQuarter()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfQuarter()->format('Y年m月d日 H:i'); $this->line("季:{$startTimeTxt}--{$endTimeTxt}"); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; $start_day = Carbon::parse($day)->startOfQuarter()->toDateString(); $rankings = Ranking::query()->where('day_type', DayTypeEnum::quarter)->where('day', $start_day)->with('user')->limit(self::TotalNums)->orderByDesc('xuefen')->get(); $this->makeRangingImg($rankings, $timeTxt, $start_day, DayTypeEnum::quarter); $xueba = Ranking::query()->where('day_type', DayTypeEnum::quarter)->where('day', $start_day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $start_day, DayTypeEnum::quarter); } //5.年排行榜 $firstDay = Carbon::parse($now)->startOfYear(); if (Carbon::parse($now)->isSameDay($firstDay)) { $startTimeTxt = Carbon::parse($day)->startOfYear()->format('Y年m月d日 H:i'); $endTimeTxt = Carbon::parse($day)->endOfYear()->format('Y年m月d日 H:i'); $start_day = Carbon::parse($day)->startOfYear()->toDateString(); $this->line($timeTxt . '==>' . $start_day . '===' . $start_day); $timeTxt = "{$startTimeTxt}-{$endTimeTxt}"; $rankings = Ranking::query()->where('day_type', DayTypeEnum::year)->where('day', $start_day)->with('user')->limit(self::TotalNums)->orderByDesc('xuefen')->get(); $this->makeRangingImg($rankings, $timeTxt, $start_day, DayTypeEnum::year); $xueba = Ranking::query()->where('day_type', DayTypeEnum::year)->where('day', $start_day)->with(['user'])->where('is_xueba', ModelStatusEnum::OK)->first(); $this->makeXueBaImg($xueba, $timeTxt, $start_day, DayTypeEnum::year); } } /** * 生成学霸 * @param $rankings * @param $timeTxt * @param $day * @param $day_type * @param $type * @return void */ public function makeXueBaImg($ranking, $timeTxt, $day, $day_type, $group_id = 0) { $type = StatisticalResourceTypeEnum::xueba; $bgPath = Setting::byCodeGetSetting('h5_base_img_xueba_beijingtu') ?? base_path('Data/xueba_bg.jpg'); $logo = base_path('Data/xueba_logo.jpg'); try { $image = Image::make($bgPath); if (!$ranking) return; $user = $ranking['user']; $name = $this->filterEmoji($user['nickname']); $avatar = Image::make($user['headimg'])->resize(830, 830); $avatar = $this->imgCircle($avatar, 830); $avatar_x = 120; $avatar_y = 570; $image->insert($avatar, 'top-left', $avatar_x, $avatar_y); $image->insert($logo); $length = mb_strlen($name); if ($length >= 6) { $name = mb_substr($name, 0, 6); $h = 835 - 40; $y = 80; } elseif ($length == 5) { $h = 835 - 20; $y = 80; } elseif ($length == 4) { $h = 835; $y = 80; } elseif ($length == 3) { $h = 835 + 40; $y = 120; } elseif ($length == 2) { $h = 835 + 80; $y = 160; } else { $h = 835 + 160; $y = 0; } for ($i = 0; $i < $length; $i++) { $this->addText($image, mb_substr($name, $i, 1), 951, $h + $i * $y, 83, 'fff'); } $timeTxt = Carbon::parse($day)->format("m月d日"); $this->addText($image, $timeTxt, 250, 440, 150, 'FFF', base_path("Data/ziti/zi.otf")); $dir = "xuebaImg/" . $day_type . '/' . $day; $filename = Str::random() . '.png'; Storage::disk('public')->put("{$dir}/{$filename}.txt", 1); $path = Storage::disk('public')->path("{$dir}/{$filename}"); $image->save($path); Storage::disk('public')->delete("{$dir}/{$filename}.txt"); StatisticalResource::query()->updateOrCreate([ 'day_type' => $day_type, 'day' => $day, 'type' => $type, 'group_id' => $group_id, ], [ 'page' => 1, 'status' => ModelStatusEnum::OK, 'path' => "{$dir}/{$filename}", 'user_ids' => [$user['id']] ]); } catch (\Exception $exception) { log_record('排行榜生成异常', compact('ranking', 'bgPath', 'timeTxt', 'day_type', 'day')); Log::error($exception); } } /** * 生成排行榜 * @param $rankings * @param $timeTxt * @param $day * @param $day_type * @param $type * @return void */ public function makeRangingImg($rankings, $timeTxt, $day, $day_type, $group_id = 0) { $type = StatisticalResourceTypeEnum::paihangbang; if ($group_id) { $bgPath = Setting::byCodeGetSetting('h5_base_img_ranking_group_' . $group_id); } else { $bgPath = Setting::byCodeGetSetting('h5_base_img_ranking'); } $bgPath = $bgPath ?? base_path('Data/paihangbang_bg.jpg'); log_record('学霸', ['bg' => $bgPath, 'day' => $day, 'day_type' => $day_type, 'group_id' => $group_id]); $start_x = 90; $x_py = 490; $start_y = 750; $y_py = 0; $pageNums = 15; $rowY = 77; $count = count($rankings); if (!$count) return; $tPage = ceil($count / self::PageNums); try { for ($page = 0; $page < $tPage; $page++) { $image = Image::make($bgPath); $headimgBg = Image::make(base_path('Data/headimg_bg.png')); $user_ids = []; foreach ($rankings as $k => $ranking) { $user = $ranking['user']; $user_ids[] = $user['id']; $num = $k + 1 + ($page * 30); $name = "{$num}." . self::filterEmoji($user['nickname']); $avatar = Image::make($user['headimg']); $avatar = self::imgCircle($avatar, 60); $score = $ranking['xuefen']; if ($k >= ($pageNums * 2)) continue; $h = $k; if ($k >= $pageNums) { $start_x += $x_py; $h -= $pageNums; } $avatar_x = $start_x; $name_x = $start_x + 83; $score_x = $start_x + 367; $name_y = $start_y + $h * $rowY; $score_y = $start_y + $h * $rowY; $avatar_y = $start_y - 40 + $h * $rowY; // $avatar_x = 72; // $name_x = 155; // $score_x = 439; // // $jt = -300; // $avatar_y = 1000 + ($k) * 80 + $jt; // $name_y = 1040 + ($k) * 80 + $jt; // $score_y = 1040 + ($k) * 80 + $jt; // // if ($k >= 15) { // // $avatar_y = 1000 + ($k - 15) * 80 + $jt; // $name_y = 1040 + ($k - 15) * 80 + $jt; // $score_y = 1040 + ($k - 15) * 80 + $jt; // // $avatar_x = 578; // $name_x = 660; // $score_x = 947; // } $image->insert($avatar, 'top-left', $avatar_x, $avatar_y); $image->insert($headimgBg, 'top-left', $avatar_x, $avatar_y); $this->addText($image, $name, $name_x, $name_y, 30, '000'); $this->addText($image, $score, $score_x, $score_y, 30, '000'); } self::addText($image, $timeTxt, 101, 2320, 41, 'F8ECD2'); $dir = "rankImg/" . $day_type . '/' . $day; $filename = Str::random() . '.png'; Storage::disk('public')->put("{$dir}/{$filename}.txt", 1); $path = Storage::disk('public')->path("{$dir}/{$filename}"); $image->save($path); Storage::disk('public')->delete("{$dir}/{$filename}.txt"); StatisticalResource::query()->updateOrCreate([ 'day_type' => $day_type, 'day' => $day, 'type' => $type, 'page' => ($page + 1), 'group_id' => $group_id ], [ 'user_ids' => $user_ids, 'status' => ModelStatusEnum::OK, 'path' => "{$dir}/{$filename}" ]); } } catch (\Exception $exception) { log_record('排行榜生成异常', compact('rankings', 'bgPath', 'timeTxt', 'day_type', 'day')); Log::error($exception); } } public static function addText(&$bgImage, $text, $x, $y, $size, $color, $ziti = '') { if (!$ziti) $ziti = base_path('Data/ziti/ht.otf'); // $y += ($size / 2); $bgImage->text($text, $x, $y, function ($font) use ($size, $color, $ziti) { $font->file($ziti); $font->size($size); $font->color($color); $font->angle(0); }); // return $bgImage; } /** * 处理头像 * @param $path * @return \Intervention\Image\Image */ private static function imgCircle($img2, $size = 60) { $img2 = $img2->resize($size, $size); $r = $img2->width() / 2; $img3 = Image::canvas($size, $size); for ($x = 0; $x < $img2->width(); $x++) { for ($y = 0; $y < $img2->height(); $y++) { if (((($x - $r) * ($x - $r) + ($y - $r) * ($y - $r)) < ($r * $r))) { $c = $img2->pickColor($x, $y, 'array'); $img3->pixel($c, $x, $y); } } } return $img3; } /** * 过滤符号 * @param $str * @return mixed */ private static function filterEmoji($str, $maxLen = 5) { $str = json_encode($str); $str = json_decode(preg_replace("#(\\\ud[0-9a-f]{3})#i", "", $str)); if (mb_strlen($str) > $maxLen) { $str = mb_substr($str, 0, $maxLen); } return $str; } private static function getImgPath($dir_fix, $day_type, $day) { $dir = "{$dir_fix}/" . $day_type . '/' . $day; $filename = Str::random() . '.png'; Storage::disk('public')->put("{$dir}/{$filename}.txt", 1); $path = Storage::disk('public')->path("{$dir}/{$filename}"); return [ 'path' => $path, 'xd_path' => "{$dir}/{$filename}", 'ls_file' => "{$dir}/{$filename}.txt" ]; } }