216 lines
7.7 KiB
PHP
216 lines
7.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Web;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Department;
|
|
use App\Models\MetrikaForm;
|
|
use App\Models\MetrikaGroup;
|
|
use App\Models\MetrikaItem;
|
|
use App\Models\MetrikaResult;
|
|
use App\Models\Report;
|
|
use Illuminate\Database\Eloquent\Builder;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Inertia\Inertia;
|
|
|
|
class StatisticController extends Controller
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
$user = $request->user();
|
|
|
|
$userDepartment = $user->department;
|
|
|
|
$data = [];
|
|
|
|
$departments = Department::select('department_id', 'name_short')->get();
|
|
|
|
foreach ($departments as $department) {
|
|
$allCount = MetrikaResult::whereHas('report', function ($query) use ($userDepartment, $department) {
|
|
$query->where('rf_department_id', $department->department_id);
|
|
})->where('rf_metrika_item_id', 3)
|
|
->sum(DB::raw('value::integer'));
|
|
|
|
$leaveCount = MetrikaResult::whereHas('report', function ($query) use ($userDepartment, $department) {
|
|
$query->where('rf_department_id', $department->department_id);
|
|
})->where('rf_metrika_item_id', 7)
|
|
->sum(DB::raw('value::integer'));
|
|
|
|
$consistCount = optional(MetrikaResult::where('rf_metrika_item_id', 8)
|
|
->whereHas('report', function (Builder $query) use ($department) {
|
|
$query->where('rf_department_id', $department->department_id);
|
|
})->join('reports', 'metrika_results.rf_report_id', '=', 'reports.report_id')
|
|
->select('metrika_results.value')
|
|
->orderBy('reports.sent_at', 'desc')
|
|
)->value('value') ?? 0;
|
|
|
|
$beds = (int)optional($department->metrikaDefault()
|
|
->where('rf_metrika_item_id', 1)
|
|
->first())->value ?? 0;
|
|
|
|
$occupiedBeds = (int)optional(Report::where('rf_department_id', $department->department_id)
|
|
->join('metrika_results', 'reports.report_id', '=', 'metrika_results.rf_report_id')
|
|
->where('metrika_results.rf_metrika_item_id', 8)
|
|
->orderBy('reports.sent_at', 'desc')
|
|
->first())->value ?? 0;
|
|
|
|
$percentLoadedBeds = $beds > 0 ? $occupiedBeds * 100 / $beds : 0;
|
|
|
|
$data[] = [
|
|
'department' => $department->name_short,
|
|
'beds' => $beds,
|
|
'all' => $allCount,
|
|
'plan' => '0',
|
|
'emergency' => '0',
|
|
'leave' => $leaveCount,
|
|
'consist' => $consistCount,
|
|
'percentLoadedBeds' => $percentLoadedBeds,
|
|
];
|
|
}
|
|
|
|
return Inertia::render('Statistic/Index', [
|
|
'data' => $data
|
|
]);
|
|
}
|
|
|
|
public function indexOld(Request $request)
|
|
{
|
|
$user = Auth::user();
|
|
|
|
$validator = Validator::make($request->all(), [
|
|
'sent_at' => 'required|string'
|
|
]);
|
|
|
|
$groupId = (int)$request->query('groupId');
|
|
|
|
if ($validator->fails()) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'errors' => $validator->errors()
|
|
], 422);
|
|
}
|
|
|
|
$timestamps = explode(',', $request->sent_at);
|
|
$startAt = intval($timestamps[0] / 1000);
|
|
$endAt = intval($timestamps[1] / 1000);
|
|
|
|
// Проверяем период (максимум 1 год)
|
|
$daysDiff = ($endAt - $startAt) / (60 * 60 * 24);
|
|
if ($daysDiff > 365) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Период не может превышать 1 год'
|
|
], 400);
|
|
}
|
|
|
|
$dateStart = date('Y-m-d', $startAt);
|
|
$dateEnd = date('Y-m-d', $endAt);
|
|
|
|
$group = MetrikaGroup::findOrFail($groupId);
|
|
|
|
// Оптимизированный агрегированный запрос
|
|
$aggregatedData = DB::table('metrika_results as mr')
|
|
->join('metrika_result_values as mv', 'mr.metrika_result_id', '=', 'mv.rf_metrika_result_id')
|
|
->join('reports as r', 'mr.rf_report_id', '=', 'r.report_id')
|
|
->where('mr.rf_metrika_group_id', $groupId)
|
|
->whereBetween('r.sent_at', [$dateStart, $dateEnd])
|
|
->when(!$user->isAdmin() && !$user->isHeadOfDepartment(), function ($query) use ($user) {
|
|
return $query->where('r.rf_user_id', $user->id);
|
|
})
|
|
->select([
|
|
'mv.rf_metrika_item_id',
|
|
DB::raw('SUM(CAST(mv.value AS DECIMAL(10,2))) as total_sum'),
|
|
DB::raw('COUNT(DISTINCT r.report_id) as reports_count'),
|
|
DB::raw('AVG(CAST(mv.value AS DECIMAL(10,2))) as avg_value')
|
|
])
|
|
->groupBy('mv.rf_metrika_item_id')
|
|
->get()
|
|
->keyBy('rf_metrika_item_id');
|
|
|
|
if ($aggregatedData->isEmpty()) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Данные за указанный период не найдены'
|
|
], 404);
|
|
}
|
|
|
|
// Получаем названия метрик одним запросом
|
|
$itemIds = $aggregatedData->pluck('rf_metrika_item_id')->toArray();
|
|
$items = MetrikaItem::whereIn('metrika_item_id', $itemIds)
|
|
->pluck('name', 'metrika_item_id');
|
|
|
|
// Формируем ответ
|
|
$formValues = [];
|
|
foreach ($aggregatedData as $itemId => $data) {
|
|
$formValues["metrika_item_{$itemId}"] = [
|
|
'sum' => (float) $data->total_sum,
|
|
'average' => (float) $data->avg_value,
|
|
'reports_count' => $data->reports_count,
|
|
'item_name' => $items[$itemId] ?? 'Неизвестный показатель'
|
|
];
|
|
}
|
|
|
|
// Получаем структуру формы
|
|
$formData = MetrikaForm::getFormData($groupId);
|
|
|
|
return Inertia::render('Statistic/Index', [
|
|
'is_view_only' => true,
|
|
'period' => [
|
|
'start' => $dateStart,
|
|
'end' => $dateEnd,
|
|
'days' => $daysDiff + 1
|
|
],
|
|
'group' => [
|
|
'id' => $group->metrika_group_id,
|
|
'name' => $group->name,
|
|
'description' => $group->description,
|
|
],
|
|
'metrics' => [
|
|
'total_items' => count($formValues),
|
|
'total_reports' => $aggregatedData->first()->reports_count ?? 0,
|
|
'values' => $formValues,
|
|
'aggregation' => 'sum_and_average'
|
|
],
|
|
'form' => [
|
|
'fields' => $formData,
|
|
'sections' => $this->groupFieldsBySection($formData)
|
|
]
|
|
]);
|
|
}
|
|
|
|
private function groupFieldsBySection($fields)
|
|
{
|
|
$sections = [];
|
|
|
|
foreach ($fields as $field) {
|
|
$section = $field['section'] ?? 'general';
|
|
|
|
if (!isset($sections[$section])) {
|
|
$sections[$section] = [
|
|
'name' => $this->getSectionName($section),
|
|
'fields' => []
|
|
];
|
|
}
|
|
|
|
$sections[$section]['fields'][] = $field;
|
|
}
|
|
|
|
return array_values($sections);
|
|
}
|
|
|
|
private function getSectionName($section)
|
|
{
|
|
$names = [
|
|
'general' => 'Основные показатели',
|
|
'admissions' => 'Поступления',
|
|
'discharges' => 'Выписки',
|
|
'additional' => 'Дополнительная информация'
|
|
];
|
|
|
|
return $names[$section] ?? ucfirst($section);
|
|
}
|
|
}
|