diff --git a/app/Admin/Controllers/Finance/SalesStatisticController.php b/app/Admin/Controllers/Finance/SalesStatisticController.php new file mode 100644 index 0000000..a66fc42 --- /dev/null +++ b/app/Admin/Controllers/Finance/SalesStatisticController.php @@ -0,0 +1,89 @@ +actionOfGetData()) { + return $this->response()->success([ + 'items' => $this->getLotteryTypeStatistics(request()), + ]); + } + + return $this->response()->success( + $this->baseList( + $this->baseCRUD() + ->headerToolbar([ + amis('filter-toggler')->align('right'), + ]) + ->footerToolbar([]) + ->bulkActions([]) + ->filter($this->baseFilter()->body([ + amis()->GroupControl()->mode('horizontal')->body([ + amis()->DateRangeControl('date_range', '日期') + ->valueFormat('YYYY-MM-DD') + ->columnRatio(6), + amis()->InputCityControl('region', '区域') + ->inputClassName('w-40') + ->allowDistrict(false) + ->extractValue(false), + amis()->SelectControl('store_id', __('finance.ledger.store')) + ->source(admin_url('api/stores?region=${region}')) + ->labelField('title') + ->valueField('id') + ->clearable(), + ]), + ])) + ->columns([ + amis()->TableColumn('name', '彩种'), + amis()->TableColumn('sales', '销量'), + amis()->TableColumn('expenditure', '兑奖'), + ]) + ->affixRow([ + ['type' => 'text', 'text' => '合计'], + ['type' => 'tpl', 'text' => '${items|pick:sales|sum}'], + ['type' => 'tpl', 'text' => '${items|pick:expenditure|sum}'], + ]) + ) + ); + } + + protected function getLotteryTypeStatistics(Request $request): array + { + /** @var \Illuminate\Database\Eloquent\Collection */ + $lotteryTypes = Keyword::where('parent_key', 'lottery_type')->get(); + + /** @var \Illuminate\Database\Eloquent\Collection */ + $statistics = LedgerItem::select([ + 'ledger_item_type_id', + DB::raw('SUM(sales) as sales'), + DB::raw('SUM(expenditure) as expenditure'), + ]) + ->filter($request->input(), LedgerItemFilter::class) + ->whereIn('ledger_item_type_id', $lotteryTypes->pluck('value')) + ->groupBy('ledger_item_type_id') + ->get() + ->keyBy('ledger_item_type_id'); + + return $lotteryTypes->map(function ($lotteryType) use ($statistics) { + $statistic = $statistics->get($lotteryType->value); + return [ + 'name' => $lotteryType->name, + 'sales' => trim_zeros($statistic->sales ?? '0.00'), + 'expenditure' => trim_zeros($statistic->expenditure ?? '0.00'), + ]; + })->all(); + } +} diff --git a/app/Admin/Filters/LedgerItemFilter.php b/app/Admin/Filters/LedgerItemFilter.php new file mode 100644 index 0000000..a8d2b9e --- /dev/null +++ b/app/Admin/Filters/LedgerItemFilter.php @@ -0,0 +1,37 @@ +whereBetween('date', explode(',', $dateRange)); + } + + public function region($region) + { + if ($this->input('store_id') !== null || ! is_array($region)) { + return; + } + + $provinceCode = Arr::get($region, 'provinceCode'); + $cityCode = Arr::get($region, 'cityCode'); + if (empty($provinceCode) && empty($cityCode)) { + return; + } + + $this->related('store', function($query) use ($provinceCode, $cityCode) { + $query->when($provinceCode, fn ($query) => $query->where('region->provinceCode', $provinceCode)) + ->when($cityCode, fn ($query) => $query->where('region->cityCode', $cityCode)); + }); + } + + public function store($id) + { + $this->where('store_id', $id); + } +} diff --git a/app/Admin/Filters/StoreFilter.php b/app/Admin/Filters/StoreFilter.php index 8e2e943..989b67a 100644 --- a/app/Admin/Filters/StoreFilter.php +++ b/app/Admin/Filters/StoreFilter.php @@ -3,6 +3,7 @@ namespace App\Admin\Filters; use EloquentFilter\ModelFilter; +use Illuminate\Support\Arr; class StoreFilter extends ModelFilter { @@ -30,4 +31,19 @@ class StoreFilter extends ModelFilter { $this->where('business_status', $key); } + + public function region($region) + { + if (! is_array($region)) { + return; + } + + if ($provinceCode = Arr::get($region, 'provinceCode')) { + $this->where('region->provinceCode', $provinceCode); + } + + if ($cityCode = Arr::get($region, 'cityCode')) { + $this->where('region->cityCode', $cityCode); + } + } } diff --git a/app/Admin/routes.php b/app/Admin/routes.php index 816eb40..c59dd6b 100644 --- a/app/Admin/routes.php +++ b/app/Admin/routes.php @@ -2,6 +2,7 @@ use App\Admin\Controllers\BaseKeywordController; use App\Admin\Controllers\Finance\LedgerController; +use App\Admin\Controllers\Finance\SalesStatisticController; use App\Admin\Controllers\Hr\EmployeeController; use App\Admin\Controllers\Hr\RestController; use App\Admin\Controllers\Hr\SignController; @@ -85,6 +86,8 @@ Route::group([ // 上报数据 $router->resource('ledgers', LedgerController::class); $router->post('ledgers/{ledger}/approval', [LedgerController::class, 'approval'])->name('ledgers.approval'); + // 销售统计 + $router->get('sales-statistics', [SalesStatisticController::class, 'index'])->name('sales_statistics.index'); }); /* diff --git a/app/Models/LedgerItem.php b/app/Models/LedgerItem.php index 4e44503..7cc1f1f 100644 --- a/app/Models/LedgerItem.php +++ b/app/Models/LedgerItem.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Traits\HasDateTimeFormatter; use EloquentFilter\Filterable; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -36,4 +37,9 @@ class LedgerItem extends Model { return $this->belongsTo(Keyword::class, 'ledger_item_type_id', 'key'); } + + public function store(): BelongsTo + { + return $this->belongsTo(Store::class); + } } diff --git a/bootstrap/helpers.php b/bootstrap/helpers.php new file mode 100644 index 0000000..7bdf723 --- /dev/null +++ b/bootstrap/helpers.php @@ -0,0 +1,25 @@ + ['list', 'update', 'view'], 'children' => [], ], + 'sales_statistics' => [ + 'name' => '销售统计', + 'icon' => 'ri:bar-chart-2-line', + 'uri' => '/finance/sales-statistics', + 'resource' => false, + 'children' => [ + 'index' => '销售统计', + ], + ], ], ],