'balance', 'label' => '余额', 'fields' => FundForecast::BALANCE_FIELDS], ['key' => 'income', 'label' => '收入', 'fields' => FundForecast::INCOME_FIELDS], ['key' => 'expense', 'label' => '支出', 'fields' => FundForecast::EXPENSE_FIELDS], ['key' => 'summary', 'label' => '汇总', 'fields' => FundForecast::SUMMARY_FIELDS], ]; public function data(Request $request): array { $filters = $this->filters($request); if (! Schema::hasColumns('business_fund_forecast', ['company_name', 'balance_bank', 'gap_surplus'])) { return $this->pendingData($request, $filters); } $base = FundForecast::query(); $this->applyFilters($base, $filters); $scopeCounts = [ 'all' => (clone $base)->count(), 'gap' => $this->applyScope(clone $base, 'gap')->count(), 'unreported' => $this->applyScope(clone $base, 'unreported')->count(), 'pending_review' => $this->applyScope(clone $base, 'pending_review')->count(), ]; $query = $this->applyScope(clone $base, $filters['view']); $summaryQuery = clone $query; $rows = $query ->orderByDesc('budget_month') ->orderBy('company_name') ->orderByDesc('id') ->paginate(50) ->withQueryString(); $labels = FundForecast::columnLabels(); $groups = array_map(function (array $group) use ($labels): array { $group['columns'] = array_map( fn (string $field): array => ['field' => $field, 'label' => $labels[$field]], $group['fields'], ); return $group; }, self::GROUPS); return [ 'ready' => true, 'filters' => $filters, 'months' => FundForecast::query()->whereNotNull('budget_month')->where('budget_month', '<>', '') ->distinct()->orderByDesc('budget_month')->pluck('budget_month')->all(), 'regions' => FundForecast::query()->whereNotNull('region')->where('region', '<>', '') ->distinct()->orderBy('region')->pluck('region')->all(), 'rows' => $rows, 'groups' => $groups, 'scopeCounts' => $scopeCounts, 'summary' => [ 'company_count' => (clone $summaryQuery)->whereNotNull('company_name')->where('company_name', '<>', '') ->distinct()->count('company_name'), 'balance_total' => $this->sumColumns(clone $summaryQuery, FundForecast::BALANCE_FIELDS), 'income_total' => (float) (clone $summaryQuery)->sum('forecast_month_income'), 'gap_surplus' => (float) (clone $summaryQuery)->sum('gap_surplus'), ], ]; } private function pendingData(Request $request, array $filters): array { $labels = FundForecast::columnLabels(); $groups = array_map(function (array $group) use ($labels): array { $group['columns'] = array_map( fn (string $field): array => ['field' => $field, 'label' => $labels[$field]], $group['fields'], ); return $group; }, self::GROUPS); return [ 'ready' => false, 'filters' => $filters, 'months' => [], 'regions' => [], 'rows' => new LengthAwarePaginator([], 0, 50, max((int) $request->query('page', 1), 1), [ 'path' => $request->url(), 'query' => $request->query(), ]), 'groups' => $groups, 'scopeCounts' => ['all' => 0, 'gap' => 0, 'unreported' => 0, 'pending_review' => 0], 'summary' => ['company_count' => 0, 'balance_total' => 0.0, 'income_total' => 0.0, 'gap_surplus' => 0.0], ]; } private function filters(Request $request): array { $month = trim((string) $request->query('budget_month', '')); $month = preg_match('/^\d{4}-(0[1-9]|1[0-2])$/', $month) === 1 ? $month : ''; $status = trim((string) $request->query('report_status', '')); $status = in_array($status, ['待填报', '待审核', '已审核'], true) ? $status : ''; $view = trim((string) $request->query('view', 'all')); $view = in_array($view, ['all', 'gap', 'unreported', 'pending_review'], true) ? $view : 'all'; return [ 'budget_month' => $month, 'region' => mb_substr(trim((string) $request->query('region', '')), 0, 64), 'report_status' => $status, 'company_name' => mb_substr(trim((string) $request->query('company_name', '')), 0, 191), 'view' => $view, ]; } private function applyFilters(Builder $query, array $filters): void { if ($filters['budget_month'] !== '') { $query->where('budget_month', $filters['budget_month']); } if ($filters['region'] !== '') { $query->where('region', $filters['region']); } if ($filters['report_status'] !== '') { $query->where('report_status', $filters['report_status']); } if ($filters['company_name'] !== '') { $query->where('company_name', 'like', '%' . addcslashes($filters['company_name'], '%_\\') . '%'); } } private function applyScope(Builder $query, string $scope): Builder { return match ($scope) { 'gap' => $query->where(function (Builder $nested): void { $nested->where('has_gap', true)->orWhere('gap_surplus', '<', 0); }), 'unreported' => $query->where(function (Builder $nested): void { $nested->whereNull('report_status')->orWhere('report_status', '待填报'); }), 'pending_review' => $query->where('report_status', '待审核'), default => $query, }; } private function sumColumns(Builder $query, array $columns): float { return array_reduce( $columns, fn (float $sum, string $column): float => $sum + (float) (clone $query)->sum($column), 0.0, ); } }