Files
onboard/app/Services/Analytics/DataSets/ShiftsDataSet.php

123 lines
4.8 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Services\Analytics\DataSets;
use App\Domain\Reports\ValueObjects\MetrikaConfig;
use App\Models\Department;
use App\Models\MisLpuDoctor;
use App\Services\Analytics\AbstractDataSet;
use App\Services\Analytics\AnalyticsQuery;
use App\Services\Analytics\Dimension;
use App\Services\Analytics\FilterDef;
use App\Services\Analytics\Measure;
use Illuminate\Database\Query\Builder;
use Illuminate\Support\Facades\DB;
class ShiftsDataSet extends AbstractDataSet
{
private const STATUS_OPTIONS = [1 => 'Черновик', 2 => 'Сдан'];
public function key(): string
{
return 'shifts';
}
public function label(): string
{
return 'Смены / дежурства';
}
public function description(): string
{
return 'Показатели сданных дежурных смен отделения';
}
public function category(): string
{
return 'Дежурства';
}
protected function dateField(): string
{
return 'rd.period_start';
}
protected function baseQuery(AnalyticsQuery $query): Builder
{
return DB::table('report_duties as rd')
->leftJoin('duty_report_metric_results as m', 'm.rf_report_id', '=', 'rd.id')
->where('rd.rf_department_id', $query->department->department_id)
->where('rd.status_id', 2)
->where('rd.period_start', '>=', $query->dateRange->startSql())
->where('rd.period_end', '<=', $query->dateRange->endSql());
}
public function dimensions(): array
{
return [
new Dimension('shift_date', 'Дата смены', 'date', 'CAST(rd.period_start AS date)'),
new Dimension(
'doctor',
'Врач',
'string',
'rd.rf_lpudoctor_id',
labels: fn (array $ids) => MisLpuDoctor::whereIn('LPUDoctorID', $ids)->get()
->mapWithKeys(fn ($d) => [$d->LPUDoctorID => trim("{$d->FAM_V} {$d->IM_V} {$d->OT_V}") ?: "Врач #{$d->LPUDoctorID}"])
->all(),
),
new Dimension(
'department',
'Отделение',
'string',
'rd.rf_department_id',
labels: fn (array $ids) => Department::whereIn('department_id', $ids)->get()
->mapWithKeys(fn ($d) => [$d->department_id => $d->name_full ?? $d->name_short])
->all(),
),
new Dimension(
'status',
'Статус',
'string',
'rd.status_id',
labels: fn () => self::STATUS_OPTIONS,
),
];
}
public function measures(): array
{
return [
new Measure('shifts_count', 'Количество смен', 'count', 'COUNT(DISTINCT rd.id)'),
new Measure('beds', 'Коек', 'count', $this->sum(MetrikaConfig::BEDS)),
new Measure('recipient_plan', 'Поступило плановых', 'count', $this->sum(MetrikaConfig::PLAN)),
new Measure('recipient_emergency', 'Поступило экстренных', 'count', $this->sum(MetrikaConfig::EMERGENCY)),
new Measure('discharged', 'Выписано', 'count', $this->sum(MetrikaConfig::DISCHARGED)),
new Measure('transferred', 'Переведено', 'count', $this->sum(MetrikaConfig::TRANSFERRED)),
new Measure('deceased', 'Умерло', 'count', $this->sum(MetrikaConfig::DECEASED)),
new Measure('surgery_plan', 'Операции плановые', 'count', $this->sum(MetrikaConfig::PLAN_SURGERY)),
new Measure('surgery_emergency', 'Операции экстренные', 'count', $this->sum(MetrikaConfig::EMERGENCY_SURGERY)),
new Measure('occupancy_percent', 'Занятость, %', 'percent', $this->avg(MetrikaConfig::DEPARTMENT_LOADED)),
new Measure('avg_bed_days', 'Ср. койко-день', null, $this->avg(MetrikaConfig::AVERAGE_BED_DAYS)),
new Measure('lethality_percent', 'Летальность, %', 'percent', $this->avg(MetrikaConfig::LETHALITY)),
new Measure('staff_count', 'Мед. персонал', 'count', $this->avg(MetrikaConfig::STAFF_COUNT)),
];
}
public function filters(): array
{
return [
new FilterDef('doctor', 'Врач', 'rd.rf_lpudoctor_id', 'select', null, 'doctors'),
];
}
private function sum(int $metricId): string
{
return "SUM(CASE WHEN m.rf_metrika_item_id = {$metricId} THEN NULLIF(m.value, '')::numeric ELSE 0 END)";
}
private function avg(int $metricId): string
{
return "AVG(CASE WHEN m.rf_metrika_item_id = {$metricId} THEN NULLIF(m.value, '')::numeric END)";
}
}