161 lines
6.3 KiB
PHP
161 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace App\Business;
|
|
|
|
use App\Models\Business\FundForecast;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Support\Facades\Schema;
|
|
|
|
class FundForecastPage
|
|
{
|
|
public const GROUPS = [
|
|
['key' => '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,
|
|
);
|
|
}
|
|
}
|