first commit

This commit is contained in:
brusnitsyn
2026-01-04 23:15:06 +09:00
commit 0ec04cfb4b
104 changed files with 19072 additions and 0 deletions

View File

@@ -0,0 +1,153 @@
<?php
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Models\MetrikaForm;
use App\Models\MetrikaGroup;
use App\Models\MetrikaItem;
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 = 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);
}
}