270 lines
11 KiB
PHP
270 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Support\MedicalReport;
|
|
|
|
use App\Models\Department;
|
|
use App\Models\HospitalUnit;
|
|
use App\Models\MedicalReport;
|
|
use App\Models\MedicalReportFormTemplate;
|
|
|
|
class FormTemplateBuilderPage
|
|
{
|
|
public function __construct(
|
|
private readonly TemplateWorkbook $templateWorkbook,
|
|
private readonly StructuredTemplateRegistry $structuredTemplateRegistry,
|
|
private readonly ReportInputTypeBlueprintFactory $reportInputTypeBlueprintFactory,
|
|
) {}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function pageData(MedicalReport $medicalReport, ?string $selectedDepartmentKey = null): array
|
|
{
|
|
$departments = $this->templateWorkbook->departments();
|
|
$selectedDepartmentKey ??= $departments[0]['key'] ?? null;
|
|
$selectedDepartment = $selectedDepartmentKey === null
|
|
? null
|
|
: collect($departments)->firstWhere('key', $selectedDepartmentKey);
|
|
$selectedHospitalUnitId = $selectedDepartment['id'] ?? null;
|
|
$databaseTemplateKeys = MedicalReportFormTemplate::query()
|
|
->with('hospitalUnit:id,slug')
|
|
->get()
|
|
->map(fn (MedicalReportFormTemplate $template): ?string => $template->hospitalUnit?->slug ?: $template->department_key)
|
|
->filter()
|
|
->values()
|
|
->all();
|
|
$databaseTemplate = $selectedDepartmentKey === null
|
|
? null
|
|
: MedicalReportFormTemplate::query()
|
|
->where(function ($query) use ($selectedHospitalUnitId, $selectedDepartmentKey): void {
|
|
if ($selectedHospitalUnitId !== null) {
|
|
$query->where('hospital_unit_id', $selectedHospitalUnitId)
|
|
->orWhere('department_key', $selectedDepartmentKey);
|
|
|
|
return;
|
|
}
|
|
|
|
$query->where('department_key', $selectedDepartmentKey);
|
|
})
|
|
->first();
|
|
$effectiveTemplate = $selectedDepartmentKey === null
|
|
? null
|
|
: $this->structuredTemplateRegistry->templateForDepartment($selectedDepartmentKey);
|
|
$blueprintTemplate = $selectedDepartment === null
|
|
? null
|
|
: $this->reportInputTypeBlueprintFactory->templateForDepartment($selectedDepartment);
|
|
$builderStarterTemplate = $selectedDepartment === null
|
|
? null
|
|
: ($databaseTemplate !== null
|
|
? $effectiveTemplate
|
|
: ($blueprintTemplate ?? $effectiveTemplate));
|
|
$starterSource = $databaseTemplate !== null
|
|
? 'database'
|
|
: ($blueprintTemplate !== null ? 'blueprint' : 'source');
|
|
|
|
return [
|
|
'report' => [
|
|
'id' => $medicalReport->id,
|
|
'name' => $medicalReport->name,
|
|
'year' => $medicalReport->year,
|
|
'updated_at' => $medicalReport->updated_at?->toIso8601String(),
|
|
],
|
|
'selectedDepartment' => $selectedDepartmentKey,
|
|
'departments' => array_map(function (array $department) use ($databaseTemplateKeys): array {
|
|
return [
|
|
...$department,
|
|
'has_builder_template' => in_array($department['key'], $databaseTemplateKeys, true),
|
|
];
|
|
}, $departments),
|
|
'builder' => $selectedDepartment === null ? null : [
|
|
'department' => [
|
|
'key' => $selectedDepartment['key'],
|
|
'name' => $selectedDepartment['name'],
|
|
'profile_name' => $selectedDepartment['profile_name'] ?? null,
|
|
'report_input_type' => $selectedDepartment['report_input_type'] ?? null,
|
|
'report_input_type_label' => $selectedDepartment['report_input_type_label'] ?? null,
|
|
'sources' => $selectedDepartment['sources'] ?? [],
|
|
],
|
|
'template' => $this->builderTemplate(
|
|
$selectedDepartment['key'],
|
|
$selectedDepartment['name'],
|
|
$builderStarterTemplate,
|
|
$effectiveTemplate['department_options'] ?? null,
|
|
),
|
|
'uses_database_template' => $databaseTemplate !== null,
|
|
'starter_source' => $starterSource,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed>|null $effectiveTemplate
|
|
* @param array<int, array{id: int, name: string}>|null $fallbackDepartmentOptions
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function builderTemplate(
|
|
string $departmentKey,
|
|
string $departmentName,
|
|
?array $effectiveTemplate,
|
|
?array $fallbackDepartmentOptions = null,
|
|
): array {
|
|
$sections = collect($effectiveTemplate['sections'] ?? [])
|
|
->map(function (array $section): array {
|
|
return [
|
|
'key' => (string) $section['key'],
|
|
'title' => (string) $section['title'],
|
|
'economist_label' => (string) ($section['economist_label'] ?? ''),
|
|
'fields' => array_values($section['fields'] ?? []),
|
|
'export_metrics' => $this->exportMetrics(
|
|
$section['export_metrics'] ?? [],
|
|
$section['fields'] ?? [],
|
|
),
|
|
'default_entries' => array_values($section['default_entries'] ?? [$section['empty_entry'] ?? []]),
|
|
];
|
|
})
|
|
->values()
|
|
->all();
|
|
|
|
if ($sections === [] && $effectiveTemplate !== null) {
|
|
$sections = [[
|
|
'key' => 'main',
|
|
'title' => 'Основной блок',
|
|
'economist_label' => $departmentName.' / Основной блок',
|
|
'fields' => array_values($effectiveTemplate['fields'] ?? []),
|
|
'export_metrics' => $this->exportMetrics(
|
|
$effectiveTemplate['export_metrics'] ?? [],
|
|
$effectiveTemplate['fields'] ?? [],
|
|
),
|
|
'default_entries' => array_values($effectiveTemplate['default_entries'] ?? [$effectiveTemplate['empty_entry'] ?? []]),
|
|
]];
|
|
}
|
|
|
|
if ($sections === []) {
|
|
$sections = [[
|
|
'key' => 'main',
|
|
'title' => 'Основной блок',
|
|
'economist_label' => $departmentName.' / Основной блок',
|
|
'fields' => [
|
|
['key' => 'name', 'label' => 'Показатель', 'type' => 'text'],
|
|
['key' => 'value', 'label' => 'Значение', 'type' => 'number'],
|
|
],
|
|
'export_metrics' => [
|
|
[
|
|
'key' => 'value_total',
|
|
'label' => 'Значение',
|
|
'source_field' => 'value',
|
|
'aggregation' => 'sum',
|
|
],
|
|
],
|
|
'default_entries' => [
|
|
['name' => '', 'value' => '0'],
|
|
],
|
|
]];
|
|
}
|
|
|
|
return [
|
|
'department' => $departmentKey,
|
|
'name' => (string) ($effectiveTemplate['title'] ?? $departmentName),
|
|
'description' => (string) ($effectiveTemplate['description'] ?? ''),
|
|
'department_options' => $effectiveTemplate['department_options']
|
|
?? $fallbackDepartmentOptions
|
|
?? $this->departmentOptions(),
|
|
'analysis_columns' => $this->analysisColumns(),
|
|
'analysis_units' => $this->analysisUnits(),
|
|
'schema' => [
|
|
'title' => (string) ($effectiveTemplate['title'] ?? $departmentName),
|
|
'description' => (string) ($effectiveTemplate['description'] ?? ''),
|
|
'sections' => $sections,
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return list<array{id: int, name: string}>
|
|
*/
|
|
private function departmentOptions(): array
|
|
{
|
|
return Department::query()
|
|
->where('is_active', true)
|
|
->orderBy('name')
|
|
->get(['id', 'name'])
|
|
->map(fn (Department $department): array => [
|
|
'id' => $department->id,
|
|
'name' => $department->name,
|
|
])
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* @param list<array<string, mixed>> $configuredMetrics
|
|
* @param list<array<string, mixed>> $fields
|
|
* @return list<array{key: string, label: string, source_field: string, aggregation: string}>
|
|
*/
|
|
private function exportMetrics(array $configuredMetrics, array $fields): array
|
|
{
|
|
if ($configuredMetrics !== []) {
|
|
return collect($configuredMetrics)
|
|
->map(fn (array $metric): array => [
|
|
'key' => (string) ($metric['key'] ?? ''),
|
|
'label' => (string) ($metric['label'] ?? ''),
|
|
'source_field' => (string) ($metric['source_field'] ?? ''),
|
|
'aggregation' => (string) ($metric['aggregation'] ?? 'sum'),
|
|
'analysis_column' => ($metric['analysis_column'] ?? null) !== null ? (string) $metric['analysis_column'] : null,
|
|
'row_mode' => ($metric['row_mode'] ?? null) !== null ? (string) $metric['row_mode'] : null,
|
|
'target_unit_slug' => ($metric['target_unit_slug'] ?? null) !== null ? (string) $metric['target_unit_slug'] : null,
|
|
])
|
|
->all();
|
|
}
|
|
|
|
$hasDepartmentSelect = collect($fields)
|
|
->contains(fn (array $field): bool => ($field['type'] ?? null) === 'department-select');
|
|
|
|
return collect($fields)
|
|
->filter(fn (array $field): bool => ($field['type'] ?? 'text') === 'number')
|
|
->map(fn (array $field): array => [
|
|
'key' => (string) $field['key'].'_total',
|
|
'label' => (string) $field['label'],
|
|
'source_field' => (string) $field['key'],
|
|
'aggregation' => 'sum',
|
|
'analysis_column' => null,
|
|
'row_mode' => $hasDepartmentSelect ? 'entry_department' : 'fixed_unit',
|
|
'target_unit_slug' => null,
|
|
])
|
|
->values()
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* @return list<array{key: string, label: string, coordinate: string}>
|
|
*/
|
|
private function analysisColumns(): array
|
|
{
|
|
return collect(config('medical-report.economist_analysis_columns', []))
|
|
->filter(fn (mixed $column): bool => is_array($column))
|
|
->map(fn (array $column): array => [
|
|
'key' => (string) ($column['key'] ?? ''),
|
|
'label' => (string) ($column['label'] ?? ''),
|
|
'coordinate' => (string) ($column['coordinate'] ?? ''),
|
|
])
|
|
->filter(fn (array $column): bool => $column['key'] !== '' && $column['label'] !== '')
|
|
->values()
|
|
->all();
|
|
}
|
|
|
|
/**
|
|
* @return list<array{slug: string, name: string}>
|
|
*/
|
|
private function analysisUnits(): array
|
|
{
|
|
return HospitalUnit::query()
|
|
->where('is_active', true)
|
|
->orderBy('name')
|
|
->get(['slug', 'name'])
|
|
->map(fn (HospitalUnit $hospitalUnit): array => [
|
|
'slug' => $hospitalUnit->slug,
|
|
'name' => $hospitalUnit->name,
|
|
])
|
|
->all();
|
|
}
|
|
}
|