Переписал контроллер для KPI
This commit is contained in:
@@ -266,10 +266,22 @@ class StatisticsService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$grandTotals = $this->calculateGrandTotals($totalsByType);
|
||||||
|
$bedsTotal = (int) collect($beds)->sum('value');
|
||||||
|
// Посуточные ряды для фон-спарклайнов KPI-карточек
|
||||||
|
$grandTotals['sparklines'] = $this->calculateDailySparklines(
|
||||||
|
$allDeptIds,
|
||||||
|
$startDate,
|
||||||
|
$endDate,
|
||||||
|
$bedsTotal
|
||||||
|
);
|
||||||
|
// KPI за предыдущий аналогичный период (для бейджей тренда)
|
||||||
|
$grandTotals['previous'] = $this->calculatePreviousKpis($allDeptIds, $startDate, $endDate, $bedsTotal);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'data' => $this->buildFinalData($groupedData, $totalsByType),
|
'data' => $this->buildFinalData($groupedData, $totalsByType),
|
||||||
'totalsByType' => $totalsByType,
|
'totalsByType' => $totalsByType,
|
||||||
'grandTotals' => $this->calculateGrandTotals($totalsByType),
|
'grandTotals' => $grandTotals,
|
||||||
'recipientPlanOfYear' => [
|
'recipientPlanOfYear' => [
|
||||||
'plan' => $grandRecipientPlan, // Сумма планов по периоду
|
'plan' => $grandRecipientPlan, // Сумма планов по периоду
|
||||||
'progress' => $grandProgressPlan, // Сумма фактов по периоду
|
'progress' => $grandProgressPlan, // Сумма фактов по периоду
|
||||||
@@ -277,6 +289,123 @@ class StatisticsService
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Посуточные ряды по каждому KPI за период — для фоновых спарклайнов.
|
||||||
|
* Источник — суточные дежурные отчёты (report_duties + duty_report_metric_results).
|
||||||
|
*/
|
||||||
|
private function calculateDailySparklines(array $deptIds, string $startDate, string $endDate, int $bedsTotal): array
|
||||||
|
{
|
||||||
|
if (empty($deptIds)) {
|
||||||
|
return ['days' => [], 'consist' => [], 'admissions' => [], 'outcome' => [], 'operations' => [], 'deceased' => [], 'load' => []];
|
||||||
|
}
|
||||||
|
|
||||||
|
$rows = DB::table('report_duties as r')
|
||||||
|
->join('duty_report_metric_results as mr', 'r.id', '=', 'mr.rf_report_id')
|
||||||
|
->whereIn('r.rf_department_id', $deptIds)
|
||||||
|
->where('r.period_end', '>=', $startDate)
|
||||||
|
->where('r.period_end', '<=', $endDate)
|
||||||
|
->whereIn('mr.rf_metrika_item_id', [4, 7, 8, 9, 10, 11, 12])
|
||||||
|
->select(
|
||||||
|
DB::raw('DATE(r.period_end) as day'),
|
||||||
|
'mr.rf_metrika_item_id as metric',
|
||||||
|
DB::raw('SUM(CAST(mr.value AS DECIMAL)) as total')
|
||||||
|
)
|
||||||
|
->groupBy(DB::raw('DATE(r.period_end)'), 'mr.rf_metrika_item_id')
|
||||||
|
->orderBy('day')
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// day => [metric_id => total]
|
||||||
|
$byDay = [];
|
||||||
|
foreach ($rows as $row) {
|
||||||
|
$byDay[(string) $row->day][(int) $row->metric] = (float) $row->total;
|
||||||
|
}
|
||||||
|
ksort($byDay);
|
||||||
|
|
||||||
|
$days = array_keys($byDay);
|
||||||
|
$consist = $admissions = $outcome = $operations = $deceased = $load = [];
|
||||||
|
foreach ($byDay as $m) {
|
||||||
|
$c = (int) ($m[8] ?? 0);
|
||||||
|
$consist[] = $c;
|
||||||
|
$admissions[] = (int) (($m[4] ?? 0) + ($m[12] ?? 0));
|
||||||
|
$outcome[] = (int) ($m[7] ?? 0);
|
||||||
|
$operations[] = (int) (($m[11] ?? 0) + ($m[10] ?? 0));
|
||||||
|
$deceased[] = (int) ($m[9] ?? 0);
|
||||||
|
$load[] = $bedsTotal > 0 ? (int) round($c / $bedsTotal * 100) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return compact('days', 'consist', 'admissions', 'outcome', 'operations', 'deceased', 'load');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* KPI за предыдущий аналогичный период: столько же, вплотную перед выбранным.
|
||||||
|
* Сдвигаем оба конца назад на (длина периода + 1 день) — так предыдущий идёт встык,
|
||||||
|
* без нахлёста (для одних суток сравнение с предыдущими сутками).
|
||||||
|
*/
|
||||||
|
private function calculatePreviousKpis(array $deptIds, string $startDate, string $endDate, int $bedsTotal): array
|
||||||
|
{
|
||||||
|
$start = Carbon::parse($startDate);
|
||||||
|
$end = Carbon::parse($endDate);
|
||||||
|
|
||||||
|
$shiftSeconds = $start->diffInSeconds($end) + 86400;
|
||||||
|
|
||||||
|
$prevStart = $start->copy()->subSeconds($shiftSeconds);
|
||||||
|
$prevEnd = $end->copy()->subSeconds($shiftSeconds);
|
||||||
|
|
||||||
|
return $this->kpiTotalsForRange(
|
||||||
|
$deptIds,
|
||||||
|
$prevStart->format('Y-m-d H:i:s'),
|
||||||
|
$prevEnd->format('Y-m-d H:i:s'),
|
||||||
|
$bedsTotal
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Сводные KPI за произвольный диапазон (суммы метрик + состав на конец периода).
|
||||||
|
*/
|
||||||
|
private function kpiTotalsForRange(array $deptIds, string $start, string $end, int $bedsTotal): array
|
||||||
|
{
|
||||||
|
$empty = ['consist' => 0, 'admissions' => 0, 'outcome' => 0, 'operations' => 0, 'deceased' => 0, 'load' => 0];
|
||||||
|
if (empty($deptIds)) {
|
||||||
|
return $empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Суммы метрик за период
|
||||||
|
$sums = DB::table('report_duties as r')
|
||||||
|
->join('duty_report_metric_results as mr', 'r.id', '=', 'mr.rf_report_id')
|
||||||
|
->whereIn('r.rf_department_id', $deptIds)
|
||||||
|
->where('r.period_start', '>=', $start)
|
||||||
|
->where('r.period_end', '<=', $end)
|
||||||
|
->whereIn('mr.rf_metrika_item_id', [4, 7, 9, 10, 11, 12])
|
||||||
|
->select('mr.rf_metrika_item_id as metric', DB::raw('SUM(CAST(mr.value AS DECIMAL)) as total'))
|
||||||
|
->groupBy('mr.rf_metrika_item_id')
|
||||||
|
->get()
|
||||||
|
->keyBy(fn ($r) => (int) $r->metric);
|
||||||
|
|
||||||
|
$g = fn ($id) => (int) ($sums[$id]->total ?? 0);
|
||||||
|
|
||||||
|
// Состав на конец периода: последний отчёт по каждому отделению ≤ end, суммируем
|
||||||
|
$consistRows = DB::table('report_duties as r')
|
||||||
|
->join('duty_report_metric_results as mr', 'r.id', '=', 'mr.rf_report_id')
|
||||||
|
->whereIn('r.rf_department_id', $deptIds)
|
||||||
|
->where('mr.rf_metrika_item_id', 8)
|
||||||
|
->where('r.period_end', '<=', $end)
|
||||||
|
->select('r.rf_department_id', 'mr.value')
|
||||||
|
->orderBy('r.rf_department_id')
|
||||||
|
->orderBy('r.period_end', 'desc')
|
||||||
|
->distinct('r.rf_department_id')
|
||||||
|
->get();
|
||||||
|
$consist = (int) $consistRows->sum(fn ($x) => (float) $x->value);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'consist' => $consist,
|
||||||
|
'admissions' => $g(4) + $g(12),
|
||||||
|
'outcome' => $g(7),
|
||||||
|
'operations' => $g(11) + $g(10),
|
||||||
|
'deceased' => $g(9),
|
||||||
|
'load' => $bedsTotal > 0 ? (int) round($consist / $bedsTotal * 100) : 0,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Инициализация итогов по типу
|
* Инициализация итогов по типу
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user