@extends('layouts.app')
@section('title', 'Информация о студенте')
{{--
Ports app/Views/student/show.php (legacy, 1716 lines) + the render()
payload from App\Controllers\StudentController::show()
(app/Controllers/StudentController.php:756-959) — see the Phase 8 plan.
Every write form on this page is Laravel-native (@csrf) as of Phase 14 —
payments/charges (PaymentController, Phases 9-10/12), frozen days
(Phase 11), student edit/responsibles (Phase 13), and status
change/tariff assignment (Phase 14) each moved once their last legacy
caller was confirmed gone. The lessonStatusModal's fetch() still has no
CSRF field at all, matching legacy LessonController::updateStudentStatus(),
which never called verifyCsrf() either — its endpoint moved to
LessonAttendanceController::updateStudentStatus() in Phase 27 (the JS
here is unchanged, still posts the same JSON to the same URL).
Role gating below mirrors the legacy view's per-section
in_array($role, [...]) checks exactly — the page itself has no
page-level role restriction (only SessionAuth::check()), which is a
pre-existing gap flagged (not fixed) in the Phase 8 plan.
--}}
@push('styles')
@endpush
@php
$attColorClass = $attendancePct < 50 ? 'red' : ($attendancePct < 80 ? 'warning' : 'green');
$latenessColorClass = $latenessCount > 0 ? 'red' : '';
$absencesColorClass = $absences > 0 ? 'red' : '';
@endphp
@section('content')
@if (!$studentInfo)
Информация о студенте не найдена.
@else
{{-- SECTION 1 — Main info --}}
{{ mb_strtoupper(mb_substr($studentInfo->last_name, 0, 1).mb_substr($studentInfo->first_name, 0, 1)) }}
{{ trim($studentInfo->last_name.' '.$studentInfo->first_name.' '.($studentInfo->middle_name ?? '')) }}
@if (!empty($studentInfo->status_name))
{{ $studentInfo->status_name }}
@endif
Фамилия
{{ $studentInfo->last_name ?: '—' }}
Имя
{{ $studentInfo->first_name ?: '—' }}
Класс
{{ $studentInfo->class_name ?? '—' }}
Язык обучения
{{ $studentInfo->language_name ?? '—' }}
Формат обучения
{{ $studentInfo->learning_type_name ?? '—' }}
Статус
{{ $studentInfo->status_name ?? '—' }}
Скидка за лояльность
{{ $studentInfo->discount_percent > 0 ? $studentInfo->discount_percent.'%' : 'Без скидки' }}
{{-- SECTION 2 — Contacts --}}
Телефон студента
{{ $studentInfo->phone ?? '—' }}
ИИН
{{ $studentInfo->iin ?? '—' }}
Номер договора
{{ $studentInfo->agreement_number ?? '—' }}
Цель
{!! nl2br(e($studentInfo->goal ?? '—')) !!}
Фамилия родителя
{{ $studentInfo->agent_last_name ?? '—' }}
Имя родителя
{{ $studentInfo->agent_first_name ?? '—' }}
Телефон родителя
{{ $studentInfo->agent_phone_number ?? '—' }}
@if (in_array($role, ['admin'], true))
Куратор
{{ trim($responsibles->curator_fullname ?? '—') }}
Менеджер
{{ trim($responsibles->manager_fullname ?? '—') }}
@endif
{{-- SECTION 3 — Indicators --}}
Дата добавления
{{ $studentInfo->created_at ? date('d.m.Y', strtotime($studentInfo->created_at)) : '—' }}
Последний урок
{{ $lastLessonDate ? date('d.m.Y', strtotime($lastLessonDate)) : '—' }}
Часов в Axioma
{{ $hoursInAxioma }}
Посещаемость
{{ $attendancePct }}%
Опозданий
{{ $latenessCount }}
Пропусков
{{ $absences }}
Средний балл КР/ДЗ
{{ $avgKrDz ?? '—' }}
Средний балл тестов
{{ $avgTestScore ?? '—' }}
{{-- SECTION 4 — Finance & Gamification (admin only) --}}
@if (in_array($role, ['admin'], true))
@php
$totalPaid = (float) ($balance->total_paid ?? 0);
$totalCharged = (float) ($balance->total_charged ?? 0);
$net = $totalPaid - $totalCharged;
if ($net >= 0) {
$payStatusLabel = 'Оплачено';
$payStatusClass = 'success';
} elseif ($net > -5000) {
$payStatusLabel = 'Частично';
$payStatusClass = 'warning';
} else {
$payStatusLabel = 'Долг';
$payStatusClass = 'danger';
}
@endphp
Финансы
Оплачено (всё время)
{{ number_format($totalPaid, 0, ',', ' ') }} ₸
Долг за год
{{ number_format(abs($annualDebt), 0, ',', ' ') }} ₸
Статус оплаты
{{ $payStatusLabel }}
Все платежи
Групповой тариф
@if (!empty($studentInfo->general_tariff_name))
{{ preg_replace('/^\[manual\]\s*/', '', $studentInfo->general_tariff_name) }}
·
{{ number_format((float) $studentInfo->general_tariff_price, 0, ',', ' ') }} ₸
/ {{ (int) $studentInfo->general_tariff_lessons_count }} уроков
@if ((int) $studentInfo->general_tariff_lessons_count > 0)
({{ number_format((float) $studentInfo->general_tariff_price / (int) $studentInfo->general_tariff_lessons_count, 0, ',', ' ') }} ₸/ур.)
@endif
@else
Не назначен
@endif
@if ($role === 'admin')
✎
@endif
Индивидуальный тариф
@if (!empty($studentInfo->individual_tariff_name))
{{ preg_replace('/^\[manual\]\s*/', '', $studentInfo->individual_tariff_name) }}
·
{{ number_format((float) $studentInfo->individual_tariff_price, 0, ',', ' ') }} ₸
/ {{ (int) $studentInfo->individual_tariff_lessons_count }} уроков
@if ((int) $studentInfo->individual_tariff_lessons_count > 0)
({{ number_format((float) $studentInfo->individual_tariff_price / (int) $studentInfo->individual_tariff_lessons_count, 0, ',', ' ') }} ₸/ур.)
@endif
@else
Не назначен
@endif
@if ($role === 'admin')
✎
@endif
Жалобы и похвалы
Похвалы
{{ $praiseCount }}
Жалобы
{{ $complaintCount }}
Все записи
Геймификация
Геймификация пока не настроена для этого студента.
@endif
{{-- GROUPS --}}
Группы студента
@if (in_array($role, ['admin'], true))
Добавить в группу
@endif
@if (!empty($groupInfo['active']) || !empty($groupInfo['inactive']))
@foreach ($groupInfo['active'] as $group)
@include('students._group_card', ['group' => $group])
@endforeach
@if (!empty($groupInfo['inactive']))
Бывшие группы ({{ count($groupInfo['inactive']) }}) ▾
@foreach ($groupInfo['inactive'] as $group)
@include('students._group_card', ['group' => $group])
@endforeach
@endif
@else
Студент не состоит ни в одной группе.
@endif
{{-- Weekly test results --}}
@if (in_array($role, ['admin', 'adviser'], true))
Результаты еженедельных тестов
@if (!empty($weeklyResults))
@foreach ($weeklyResults as $res)
@php
$scoreText = $res->score !== null ? "{$res->score}/{$res->max_score}" : '—';
$passed = $res->score !== null && $res->score >= ($res->max_score / 2);
$bgColor = $passed ? '#28a745' : '#dc3545';
$tooltip = 'Дата: '.date('d.m.Y', strtotime($res->lesson_date ?? '')).
"\nУчитель: ".($res->teacher_name ?? '—').
"\nРезультат: ".$scoreText;
@endphp
{{ $scoreText }}
@endforeach
@else
Нет результатов тестов.
@endif
@endif
{{-- Frozen days --}}
@if (in_array($role, ['admin', 'adviser'], true))
Замороженные дни
@if ($frozenDays)
С По Причина Действие
@foreach ($frozenDays as $freeze)
{{ $freeze->date_from }}
{{ $freeze->date_to }}
{!! nl2br(e($freeze->reason)) !!}
@endforeach
@else
Нет замороженных дней.
@endif
Добавить заморозку
@endif
{{-- Status history --}}
@if (in_array($role, ['admin', 'adviser'], true))
История статусов
@if ($statusHistory)
Дата и время Было Стало Причина Кто изменил
@foreach ($statusHistory as $change)
{{ date('d.m.Y H:i', strtotime($change->created_at)) }}
@if ($change->old_status_name)
{{ $change->old_status_name }}
@else
—
@endif
@if ($change->new_status_name)
{{ $change->new_status_name }}
@else
—
@endif
{{ $change->reason_name ?? '—' }}
{{ $change->changed_by_name ?? '—' }}
@endforeach
@else
Изменений статуса ещё не было.
@endif
@endif
Вернуться на панель
@endif {{-- end $studentInfo check --}}
{{-- MODALS --}}