@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 --}}
Контакты @if (in_array($role, ['admin'], true)) @endif
Телефон студента
{{ $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 }}

Геймификация
Имя героя
Опыт (XP)
Монеты

Геймификация пока не настроена для этого студента.

@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']))
@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) @endforeach
СПоПричинаДействие
{{ $freeze->date_from }} {{ $freeze->date_to }} {!! nl2br(e($freeze->reason)) !!}
@csrf
@else

Нет замороженных дней.

@endif
Добавить заморозку
@csrf
@endif {{-- Status history --}} @if (in_array($role, ['admin', 'adviser'], true))
История статусов
@if ($statusHistory)
@foreach ($statusHistory as $change) @endforeach
Дата и времяБылоСталоПричинаКто изменил
{{ 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 ?? '—' }}
@else

Изменений статуса ещё не было.

@endif
@endif Вернуться на панель @endif {{-- end $studentInfo check --}}
{{-- MODALS --}} @if (in_array($role, ['admin'], true)) @endif @if (in_array($role, ['admin'], true)) @endif @if (in_array($role, ['admin'], true)) @endif @if (in_array($role, ['admin'], true)) @endif @if (in_array($role, ['admin'], true)) @endif @endsection @push('scripts') @endpush