defaultFilterInput($request), LedgerFilter::class ); // 昨天 $yesterday = Carbon::yesterday(); //-------------------------------------------------------------------------- // 本月总账录入 //-------------------------------------------------------------------------- $currentMonthLedger = (clone $query) ->select([DB::raw('SUM(sales) as sales'), DB::raw('SUM(expenditure) as expenditure')]) ->whereBetween('date', [$yesterday->copy()->startOfMonth()->format('Y-m-d'), $yesterday->format('Y-m-d')]) ->first(); //-------------------------------------------------------------------------- // 昨日总账录入 //-------------------------------------------------------------------------- $yesterdayLedger = (clone $query)->where('date', $yesterday->format('Y-m-d'))->first(); //-------------------------------------------------------------------------- // 近 30 天趋势数据 //-------------------------------------------------------------------------- $start = $yesterday->copy()->subDays(29); $end = $yesterday->copy(); /** @var \Illuminate\Database\Eloquent\Collection */ $ledgers30days = (clone $query) ->whereBetween('date', [$start, $end]) ->get(['date', 'sales', 'expenditure']) ->keyBy('date'); return [ // 本月总账录入 'current_month_ledger' => [ // 截止日期 'deadline' => $yesterday->format('Y-m-d'), 'sales' => trim_zeros($currentMonthLedger->sales ?? 0), 'expenditure' => trim_zeros($currentMonthLedger->expenditure ?? 0), ], // 昨日累计金额 'yesterday_ledger' => [ 'date' => $yesterday->format('Y-m-d'), 'sales' => trim_zeros($yesterdayLedger->sales ?? 0), 'expenditure' => trim_zeros($yesterdayLedger->expenditure ?? 0), ], // 近30天趋势数据 'trend_data_of_30days' => $this->prepareTrendData($start->copy(), $end->copy(), $ledgers30days), ]; } /** * 门店统计 */ public function stores(Request $request, StatisticService $statisticService) { $request->validate( rules: [ 'start_at' => ['bail', 'required', 'date_format:Y-m-d'], 'end_at' => ['bail', 'required', 'date_format:Y-m-d'], ], attributes: [ 'start_at' => '开始日期', 'end_at' => '结束日期', ], ); $input = array_merge( $this->defaultFilterInput($request), $request->only(['start_at', 'end_at']), ); $sorts = [['sales', 'desc'], ['id', 'asc']]; return $statisticService->stores($input, $sorts); } /** * 销售统计 */ public function sales(Request $request): array { $request->validate( rules: [ 'start_at' => ['bail', 'required', 'date_format:Y-m-d'], 'end_at' => ['bail', 'required', 'date_format:Y-m-d'], ], attributes: [ 'start_at' => '开始日期', 'end_at' => '结束日期', ], ); // 开始日期 $startAt = Carbon::parse($request->input('start_at')); // 结束日期 $endAt = Carbon::parse($request->input('end_at')); $input = $this->defaultFilterInput($request); /** @var \Illuminate\Database\Eloquent\Collection */ $lotteryTypes = Keyword::where('parent_key', 'lottery_type')->get(); /** @var \Illuminate\Support\Collection */ $ledgerStatistics = Ledger::select([ 'date', DB::raw('SUM(new_customers) as new_customers'), DB::raw('SUM(sales) as sales'), DB::raw('SUM(expenditure) as expenditure') ]) ->filter($input, LedgerFilter::class) ->whereBetween('date', [$startAt->format('Y-m-d'), $endAt->format('Y-m-d')]) ->groupBy(['date']) ->get() ->keyBy('date'); /** @var \Illuminate\Support\Collection */ $ledgerItemStatistics = LedgerItem::select([ 'date', 'ledger_item_type_id', DB::raw('SUM(sales) as sales'), DB::raw('SUM(expenditure) as expenditure'), ]) ->filter($input, LedgerItemFilter::class) ->whereIn('ledger_item_type_id', $lotteryTypes->pluck('key')) ->whereBetween('date', [$startAt->format('Y-m-d'), $endAt->format('Y-m-d')]) ->groupBy(['date', 'ledger_item_type_id']) ->get() ->groupBy('date'); $data = collect(); $date = $endAt->copy(); while ($date->gte($startAt)) { $_date = $date->format('Y-m-d'); $ledgerStatistic = $ledgerStatistics->get($_date); /** @var \Illuminate\Support\Collection */ $lotteryTypeStatistics = $ledgerItemStatistics->get($_date, collect())->keyBy('ledger_item_type_id'); $lotteryTypes->map(function ($lotteryType) use ($lotteryTypeStatistics) { $lotteryTypeStatistic = $lotteryTypeStatistics->get($lotteryType->key); return [ 'name' => $lotteryType->name, 'sales' => trim_zeros($lotteryTypeStatistic->sales ?? 0), 'expenditure' => trim_zeros($lotteryTypeStatistic->expenditure ?? 0), ]; }); $data->push([ 'date' => $_date, 'ledger' => [ 'new_customers' => $ledgerStatistic->new_customers ?? 0, 'sales' => trim_zeros($ledgerStatistic->sales ?? 0), 'expenditure' => trim_zeros($ledgerStatistic->expenditure ?? 0), ], 'lottery_types' => $lotteryTypes->map(function ($lotteryType) use ($lotteryTypeStatistics) { $lotteryTypeStatistic = $lotteryTypeStatistics->get($lotteryType->key); return [ 'name' => $lotteryType->name, 'sales' => trim_zeros($lotteryTypeStatistic->sales ?? 0), 'expenditure' => trim_zeros($lotteryTypeStatistic->expenditure ?? 0), ]; }), ]); $date->subDay(); } return $data->all(); } /** * 准备趋势数据 */ protected function prepareTrendData(Carbon $start, Carbon $end, Collection $ledgers): array { $data = collect(); do { $ledger = $ledgers->get( $date = $start->format('Y-m-d') ); $data->push([ 'date' => $date, 'sales' => trim_zeros($ledger->sales ?? 0), 'expenditure' => trim_zeros($ledger->expenditure ?? 0), ]); $start->addDay(); } while ($start->lte($end)); return $data->all(); } /** * 处理区域和门店过滤条件 */ protected function defaultFilterInput(Request $request): array { $input = []; if ($request->filled('store_id')) { $input['store_id'] = $request->input('store_id'); } else { $region = []; if ($request->filled('province_code')) { $region['provinceCode'] = $request->input('province_code'); } if ($request->filled('city_code')) { $region['cityCode'] = $request->input('city_code'); } $input['region'] = $region; } return $input; } }