select([DB::raw('SUM(sales) as sales'), DB::raw('SUM(expenditure) as expenditure')]) ->first(); return [ 'sales' => trim_zeros($aggregate->sales ?? 0), 'expenditure' => trim_zeros($aggregate->expenditure ?? 0), ]; } /** * 总账数据趋势(日) */ public function dailyLedgerTrend(Carbon $start, Carbon $end, array $input = []): array { $input = array_merge($input, [ 'date_range' => $start->toDateString().','.$end->toDateString(), ]); $aggregates = Ledger::select(['date', DB::raw('SUM(`sales`) as `sales`'), DB::raw('SUM(`expenditure`) as `expenditure`')]) ->filter($input, LedgerFilter::class) ->groupBy('date') ->get() ->keyBy('date'); $trend = collect(); while ($start->lte($end)) { $date = $start->toDateString(); $aggregate = $aggregates->get($date); $trend->push([ 'date' => $date, 'sales' => trim_zeros($aggregate->sales ?? 0), 'expenditure' => trim_zeros($aggregate->expenditure ?? 0), ]); $start->addDay(); } return $trend->all(); } /** * 总账数据趋势(月) */ public function monthlyLedgerTrend(Carbon $start, Carbon $end, array $input = []): array { $input = array_merge($input, [ 'date_range' => $start->toDateString().','.$end->toDateString(), ]); $aggregates = Ledger::select([DB::raw("DATE_FORMAT(`date`, '%Y-%m') as `month`"), DB::raw('SUM(`sales`) as `sales`'), DB::raw('SUM(`expenditure`) as `expenditure`')]) ->filter($input, LedgerFilter::class) ->groupBy('month') ->get() ->keyBy('month'); $diffMonths = 0; if ($start->lte($end)) { $datetime = $start->copy(); while (true) { $diffMonths += 1; if ($datetime->isSameMonth($end)) { break; } $datetime->addMonth(); } } $trend = collect(); for ($i=0; $i < $diffMonths; $i++) { $month = $start->format('Y-m'); $aggregate = $aggregates->get($month); $trend->push([ 'month' => $month, 'sales' => trim_zeros($aggregate->sales ?? 0), 'expenditure' => trim_zeros($aggregate->expenditure ?? 0), ]); $start->addMonth(); } return $trend->all(); } /** * 销售统计 */ public function sales(Carbon $start, Carbon $end, array $input = []): array { $input = array_merge($input, [ 'date_range' => $start->toDateString().','.$end->toDateString(), ]); /** @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) ->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')) ->groupBy(['date', 'ledger_item_type_id']) ->get() ->groupBy('date'); $data = collect(); while ($end->gte($start)) { $date = $end->format('Y-m-d'); $ledgerStatistic = $ledgerStatistics->get($date); /** @var \Illuminate\Support\Collection */ $lotteryTypeStatistics = $ledgerItemStatistics->get($date, collect())->keyBy('ledger_item_type_id'); $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), ]; }), ]); $end->subDay(); } return $data->all(); } /** * 门店排名 */ public function storeRanking(array $input = [], int $top = 0): array { $storeLedgers = Ledger::select(['store_id', DB::raw('SUM(sales) as sales'), DB::raw('SUM(expenditure) as expenditure')]) ->filter(Arr::except($input, ['region']), LedgerFilter::class) ->groupBy('store_id'); $stores = Store::filter($input, StoreFilter::class) ->selectRaw('stores.*,IFNULL(store_ledgers.sales, 0) as sales,IFNULL(store_ledgers.expenditure, 0) as expenditure') ->leftJoinSub($storeLedgers, 'store_ledgers', fn ($join) => $join->on('stores.id', '=', 'store_ledgers.store_id')) ->when($input['sort'] ?? '', function ($query, $sort) { foreach (explode(',', $sort) as $sort) { $column = ltrim($sort, '-'); $direction = str_starts_with($sort, '-') ? 'desc' : 'asc'; $query->orderBy($column, $direction); } }, fn ($query) => $query->orderBy('sales', 'desc')) ->when($top > 0, fn ($query) => $query->limit($top)) ->get(); return $stores->map(function (Store $store, $key) { return [ 'ranking' => $key + 1, 'store' => [ 'id' => $store->id, 'title' => $store->title, ], 'sales' => trim_zeros($store->sales ?: 0), 'expenditure' => trim_zeros($store->expenditure ?: 0), ]; })->all(); } }