140 lines
5.0 KiB
PHP
140 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Web;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Department;
|
|
use App\Models\User;
|
|
use App\Services\DateRangeService;
|
|
use App\Services\Reports\Contracts\ReportDefinition;
|
|
use App\Services\Reports\Export\ReportExcelExport;
|
|
use App\Services\Reports\Export\ReportPdfExport;
|
|
use App\Services\Reports\ReportRegistry;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Inertia\Inertia;
|
|
use Maatwebsite\Excel\Facades\Excel;
|
|
|
|
class ReportsController extends Controller
|
|
{
|
|
public function __construct(
|
|
protected ReportRegistry $reportRegistry,
|
|
protected DateRangeService $dateRangeService,
|
|
) {}
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$user = Auth::user();
|
|
$available = $this->reportRegistry->availableFor($user);
|
|
|
|
abort_if(empty($available), 403);
|
|
|
|
$department = $this->resolveDepartment($request, $user);
|
|
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
|
|
|
// Без явного типа в запросе показываем только список отчётов — без предпросмотра.
|
|
$type = $request->query('type');
|
|
$definition = $type ? $this->reportRegistry->find($type, $user) : null;
|
|
$payload = $definition?->build($department, $dateRange);
|
|
|
|
return Inertia::render('Reports/Index', [
|
|
'reportTypes' => array_map(fn (ReportDefinition $d) => [
|
|
'code' => $d->code(),
|
|
'label' => $d->label(),
|
|
'audience' => $this->audienceLabel($d->requiredPermissions()),
|
|
], $available),
|
|
'departments' => collect($user->availableDepartments())->map(fn (Department $d) => [
|
|
'id' => $d->department_id,
|
|
'name' => $d->name_full ?? $d->name_short,
|
|
])->values()->all(),
|
|
'selectedType' => $definition?->code(),
|
|
'selectedDepartmentId' => $department->department_id,
|
|
'isHeadOrAdmin' => $user->isSeniorStaff(),
|
|
'date' => [
|
|
$dateRange->start()->getTimestampMs(),
|
|
$dateRange->end()->getTimestampMs(),
|
|
],
|
|
'payload' => $payload ? [
|
|
'title' => $payload->title,
|
|
'meta' => $payload->meta,
|
|
'sections' => array_map(fn ($section) => [
|
|
'title' => $section->title,
|
|
'columns' => $section->columns,
|
|
'rows' => $section->rows,
|
|
], $payload->sections),
|
|
] : null,
|
|
]);
|
|
}
|
|
|
|
public function exportExcel(Request $request)
|
|
{
|
|
[$definition, $department, $dateRange] = $this->resolveExportContext($request);
|
|
|
|
$payload = $definition->build($department, $dateRange);
|
|
|
|
return Excel::download(new ReportExcelExport($payload), $this->fileName($definition, 'xlsx'));
|
|
}
|
|
|
|
public function exportPdf(Request $request)
|
|
{
|
|
[$definition, $department, $dateRange] = $this->resolveExportContext($request);
|
|
|
|
$payload = $definition->build($department, $dateRange);
|
|
|
|
return ReportPdfExport::render($payload)->download($this->fileName($definition, 'pdf'));
|
|
}
|
|
|
|
/**
|
|
* @return array{0: ReportDefinition, 1: Department, 2: \App\Services\DateRange}
|
|
*/
|
|
private function resolveExportContext(Request $request): array
|
|
{
|
|
$user = Auth::user();
|
|
$type = $request->query('type');
|
|
$definition = $type ? $this->reportRegistry->find($type, $user) : null;
|
|
|
|
abort_if($definition === null, 403);
|
|
|
|
$department = $this->resolveDepartment($request, $user);
|
|
$dateRange = $this->dateRangeService->getDateRangeFromRequest($request, $user);
|
|
|
|
return [$definition, $department, $dateRange];
|
|
}
|
|
|
|
private function resolveDepartment(Request $request, User $user): Department
|
|
{
|
|
$departmentId = $request->query('departmentId');
|
|
$available = collect($user->availableDepartments());
|
|
|
|
if ($departmentId && $available->contains(fn (Department $d) => (int) $d->department_id === (int) $departmentId)) {
|
|
return $available->first(fn (Department $d) => (int) $d->department_id === (int) $departmentId);
|
|
}
|
|
|
|
return $user->department ?? $available->first();
|
|
}
|
|
|
|
/**
|
|
* @param array<int,string> $permissions
|
|
*/
|
|
private function audienceLabel(array $permissions): string
|
|
{
|
|
if (empty($permissions)) {
|
|
return 'Доступен всем';
|
|
}
|
|
|
|
$labels = [
|
|
'report.view' => 'Дежурный врач',
|
|
'nurse.report.view' => 'Старшая медсестра',
|
|
];
|
|
|
|
return implode(' · ', array_map(fn ($p) => $labels[$p] ?? $p, $permissions));
|
|
}
|
|
|
|
private function fileName(ReportDefinition $definition, string $extension): string
|
|
{
|
|
$slug = str_replace([' ', ':', '/', '\\'], '_', $definition->label());
|
|
|
|
return sprintf('%s_%s.%s', $slug, now('Asia/Yakutsk')->format('Ymd_His'), $extension);
|
|
}
|
|
}
|