149 lines
5.1 KiB
PHP
149 lines
5.1 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Controllers\Web\Admin;
|
||
|
||
use App\Http\Controllers\Controller;
|
||
use App\Models\ReportTemplate;
|
||
use App\Services\Reports\ReportSourceRegistry;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Auth;
|
||
use Inertia\Inertia;
|
||
|
||
class ReportTemplateController extends Controller
|
||
{
|
||
private const PERMISSION_OPTIONS = ['report.view', 'nurse.report.view'];
|
||
|
||
public function __construct(protected ReportSourceRegistry $sources) {}
|
||
|
||
public function index()
|
||
{
|
||
$this->authorizeAccess();
|
||
|
||
$templates = ReportTemplate::with('creator')->latest()->get()->map(fn (ReportTemplate $t) => [
|
||
'id' => $t->id,
|
||
'name' => $t->name,
|
||
'sourceLabels' => collect($t->sections ?? [])
|
||
->map(fn (array $s) => $this->sources->all()[$s['source']]?->label ?? $s['source'])
|
||
->unique()
|
||
->values()
|
||
->all(),
|
||
'sectionsCount' => count($t->sections ?? []),
|
||
'requiredPermissions' => $t->required_permissions ?? [],
|
||
'creator' => $t->creator?->name,
|
||
]);
|
||
|
||
return Inertia::render('Admin/ReportTemplates/Index', ['templates' => $templates]);
|
||
}
|
||
|
||
public function create()
|
||
{
|
||
$this->authorizeAccess();
|
||
|
||
return Inertia::render('Admin/ReportTemplates/Form', [
|
||
'template' => null,
|
||
'sources' => $this->sourcesPayload(),
|
||
]);
|
||
}
|
||
|
||
public function store(Request $request)
|
||
{
|
||
$this->authorizeAccess();
|
||
|
||
ReportTemplate::create([
|
||
...$this->validateTemplate($request),
|
||
'created_by' => Auth::id(),
|
||
]);
|
||
|
||
return redirect('/admin/report-templates')->with('success', 'Шаблон создан');
|
||
}
|
||
|
||
public function edit(ReportTemplate $template)
|
||
{
|
||
$this->authorizeAccess();
|
||
|
||
return Inertia::render('Admin/ReportTemplates/Form', [
|
||
'template' => [
|
||
'id' => $template->id,
|
||
'name' => $template->name,
|
||
'sections' => $template->sections,
|
||
'requiredPermissions' => $template->required_permissions ?? [],
|
||
],
|
||
'sources' => $this->sourcesPayload(),
|
||
]);
|
||
}
|
||
|
||
public function update(ReportTemplate $template, Request $request)
|
||
{
|
||
$this->authorizeAccess();
|
||
|
||
$template->update($this->validateTemplate($request));
|
||
|
||
return redirect('/admin/report-templates')->with('success', 'Шаблон сохранён');
|
||
}
|
||
|
||
public function destroy(ReportTemplate $template)
|
||
{
|
||
$this->authorizeAccess();
|
||
|
||
$template->delete();
|
||
|
||
return redirect('/admin/report-templates')->with('success', 'Шаблон удалён');
|
||
}
|
||
|
||
private function validateTemplate(Request $request): array
|
||
{
|
||
$sourceKeys = array_keys($this->sources->all());
|
||
|
||
$validated = $request->validate([
|
||
'name' => 'required|string|max:255',
|
||
'sections' => 'required|array|min:1',
|
||
'sections.*.source' => ['required', 'string', 'in:'.implode(',', $sourceKeys)],
|
||
'sections.*.title' => 'nullable|string|max:255',
|
||
'sections.*.columns' => 'required|array|min:1',
|
||
'sections.*.columns.*' => 'string',
|
||
'sections.*.filters' => 'nullable|array',
|
||
'sections.*.filters.*.field' => 'required_with:sections.*.filters|string',
|
||
'sections.*.filters.*.value' => 'nullable',
|
||
'required_permissions' => 'nullable|array',
|
||
'required_permissions.*' => 'in:'.implode(',', self::PERMISSION_OPTIONS),
|
||
]);
|
||
|
||
// Допускаем только колонки/поля фильтров, реально существующие у источника секции —
|
||
// защита от рассинхрона формы и произвольных значений в БД.
|
||
$validated['sections'] = array_map(function (array $section) {
|
||
$source = $this->sources->get($section['source']);
|
||
|
||
return [
|
||
'source' => $section['source'],
|
||
'title' => $section['title'] ?? $source->label,
|
||
'columns' => array_values(array_intersect($section['columns'], array_keys($source->columns))),
|
||
'filters' => array_values(array_filter(
|
||
$section['filters'] ?? [],
|
||
fn (array $filter) => array_key_exists($filter['field'], $source->filterableFields)
|
||
)),
|
||
];
|
||
}, $validated['sections']);
|
||
|
||
$validated['required_permissions'] = array_values($validated['required_permissions'] ?? []);
|
||
|
||
return $validated;
|
||
}
|
||
|
||
private function sourcesPayload(): array
|
||
{
|
||
return collect($this->sources->all())->map(fn ($source) => [
|
||
'key' => $source->key,
|
||
'label' => $source->label,
|
||
'columns' => $source->columns,
|
||
'filterableFields' => $source->filterableFields,
|
||
])->values()->all();
|
||
}
|
||
|
||
private function authorizeAccess(): void
|
||
{
|
||
$user = Auth::user();
|
||
|
||
abort_unless($user->isAdmin() || $user->isChiefDoctor() || $user->isDeputyChief(), 403);
|
||
}
|
||
}
|