Почти работает генерация ведомости

This commit is contained in:
2025-05-31 22:20:31 +04:00
parent 18b4d060a2
commit 5bfff5eb38
5 changed files with 434 additions and 314 deletions

View File

@@ -3,7 +3,6 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Services\ApiService; use App\Services\ApiService;
use Exception;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
@@ -35,7 +34,7 @@ class StatementController extends Controller
$types = $this->api->get('/employee/types')->json(); $types = $this->api->get('/employee/types')->json();
$teachers = $this->api->get('/employee/teachers')->json(); $teachers = $this->api->get('/employee/teachers')->json();
return view('statements.form', [ return view('statements.create', [
'groups' => $groups, 'groups' => $groups,
'disciplines' => $disciplines, 'disciplines' => $disciplines,
'types' => $types, 'types' => $types,
@@ -57,29 +56,30 @@ class StatementController extends Controller
public function edit($id) public function edit($id)
{ {
$estimations = $this->api->get("/employee/estimations");
$statementResponse = $this->api->get("/employee/statements/{$id}"); $statementResponse = $this->api->get("/employee/statements/{$id}");
$groupsResponse = $this->api->get('/employee/groups'); $groupsResponse = $this->api->get('/employee/groups');
$disciplinesResponse = $this->api->get('/employee/disciplines'); $disciplinesResponse = $this->api->get('/employee/disciplines');
$typesResponse = $this->api->get('/employee/types'); $typesResponse = $this->api->get('/employee/types');
$teachersResponse = $this->api->get('/employee/teachers'); $teachersResponse = $this->api->get('/employee/teachers');
// Если employee API успешно ответил
if ($statementResponse->successful() && if ($statementResponse->successful() &&
$groupsResponse->successful() && $groupsResponse->successful() &&
$disciplinesResponse->successful() && $disciplinesResponse->successful() &&
$typesResponse->successful() && $typesResponse->successful() &&
$teachersResponse->successful()) { $teachersResponse->successful() &&
$estimations->successful()) {
return view('statements.form', [ return view('statements.form', [
'statement' => $statementResponse->json(), 'statement' => $statementResponse->json(),
'groups' => $groupsResponse->json(), 'groups' => $groupsResponse->json(),
'disciplines' => $disciplinesResponse->json(), 'disciplines' => $disciplinesResponse->json(),
'types' => $typesResponse->json(), 'types' => $typesResponse->json(),
'teachers' => $teachersResponse->json(), 'teachers' => $teachersResponse->json(),
'isEdit' => true 'isEdit' => true,
'estimations' => $estimations->json()
]); ]);
} }
$estimations2 = $this->api->get("/teacher/estimations");
$statementResponse2 = $this->api->get("/teacher/statements/{$id}"); $statementResponse2 = $this->api->get("/teacher/statements/{$id}");
$groupsResponse2 = $this->api->get('/teacher/groups'); $groupsResponse2 = $this->api->get('/teacher/groups');
$disciplinesResponse2 = $this->api->get('/teacher/disciplines'); $disciplinesResponse2 = $this->api->get('/teacher/disciplines');
@@ -90,7 +90,8 @@ class StatementController extends Controller
$groupsResponse2->successful() && $groupsResponse2->successful() &&
$disciplinesResponse2->successful() && $disciplinesResponse2->successful() &&
$typesResponse2->successful() && $typesResponse2->successful() &&
$teachersResponse2->successful()) { $teachersResponse2->successful() &&
$estimations2->successful()) {
return view('statements.form', [ return view('statements.form', [
'statement' => $statementResponse2->json(), 'statement' => $statementResponse2->json(),
@@ -98,7 +99,8 @@ class StatementController extends Controller
'disciplines' => $disciplinesResponse2->json(), 'disciplines' => $disciplinesResponse2->json(),
'types' => $typesResponse2->json(), 'types' => $typesResponse2->json(),
'teachers' => $teachersResponse2->json(), 'teachers' => $teachersResponse2->json(),
'isEdit' => true 'isEdit' => true,
'estimations' => $estimations2->json()
]); ]);
} }
@@ -110,6 +112,8 @@ class StatementController extends Controller
$data = $request->all(); $data = $request->all();
$data['is_finalized'] = $data['is_finalized'] ?? false; $data['is_finalized'] = $data['is_finalized'] ?? false;
Log::info('Updating statement data:', $data);
$response = $this->api->patch("/employee/statements/{$id}", $data); $response = $this->api->patch("/employee/statements/{$id}", $data);
if ($response->successful()) { if ($response->successful()) {
@@ -117,6 +121,11 @@ class StatementController extends Controller
->with('success', 'Ведомость успешно обновлена'); ->with('success', 'Ведомость успешно обновлена');
} }
Log::error('Failed to update statement:', [
'status' => $response->status(),
'response' => $response->json()
]);
return back()->withErrors($response->json()['errors'] ?? []); return back()->withErrors($response->json()['errors'] ?? []);
} }
@@ -196,27 +205,27 @@ class StatementController extends Controller
$apiParams = [ $apiParams = [
'academic_year' => $request->input('academic_year'), 'academic_year' => $request->input('academic_year'),
'discipline_id' => $request->input('discipline_id') 'discipline_id' => $request->input('discipline_id'),
'group_id' => $request->input('group_id')
]; ];
$statementsResponse = $this->api->get('/teacher/statements', $apiParams); $statementsResponse = $this->api->get('/teacher/statements', $apiParams);
if (!$statementsResponse->successful()) { if (!$statementsResponse->successful()) {
throw new \Exception('Failed to load statements'); throw new \Exception('Не удалось загрузить ведомости');
} }
$groups = $this->api->get('/employee/groups')->json(); $groupsResponse = $this->api->get('/teacher/groups');
$groups = $groupsResponse->json()['data'] ?? $groupsResponse->json();
return view('teacher.statements.index', [ return view('teacher.statements.index', [
'statements' => $statementsResponse->json(), 'statements' => $statementsResponse->json()['data'] ?? $statementsResponse->json(),
'disciplines' => $disciplines, 'disciplines' => $disciplines,
'filters' => $request->only(['academic_year', 'discipline_id']), 'filters' => $request->only(['academic_year', 'discipline_id', 'group_id']),
'groups' => $groups 'groups' => $groups
]); ]);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('Ошибка в myStatements: ' . $e->getMessage()); Log::error('Ошибка в myStatements: ' . $e->getMessage());
return back()->with('error', $e->getMessage())->withInput(); return back()->with('error', $e->getMessage())->withInput();
} }
} }

View File

@@ -0,0 +1,276 @@
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">
{{ isset($statement) ? 'Редактирование ведомости' : 'Создание новой ведомости' }}
</div>
<div class="card-body">
<form method="POST" action="{{ isset($statement) ? route('statements.update', $statement['id']) : route('statements.store') }}">
@csrf
@if(isset($statement))
@method('PATCH')
@endif
<div class="row mb-3">
<label for="discipline_id" class="col-md-4 col-form-label text-md-end">Дисциплина*</label>
<div class="col-md-6">
<select id="discipline_id" class="form-control @error('discipline_id') is-invalid @enderror" name="discipline_id" required>
<option value="" disabled {{ old('discipline_id', $statement['discipline']['id'] ?? '') == '' ? 'selected' : '' }}>Выберите дисциплину</option>
@isset($disciplines)
@foreach($disciplines as $discipline)
<option value="{{ $discipline['id'] }}" {{ (old('discipline_id', $statement['discipline']['id'] ?? '') == $discipline['id'] ? 'selected' : '') }}>
{{ $discipline['name'] }}
</option>
@endforeach
@else
<option value="" disabled>Нет доступных дисциплин</option>
@endisset
</select>
@error('discipline_id')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="group_id" class="col-md-4 col-form-label text-md-end">Группа*</label>
<div class="col-md-6">
<select id="group_id" class="form-control @error('group_id') is-invalid @enderror" name="group_id" required>
<option value="" disabled {{ old('group_id', $statement['group']['id'] ?? '') == '' ? 'selected' : '' }}>Выберите группу</option>
@isset($groups)
@foreach($groups as $group)
<option value="{{ $group['id'] }}" {{ (old('group_id', $statement['group']['id'] ?? '') == $group['id'] ? 'selected' : '') }}>
{{ $group['name'] }}
</option>
@endforeach
@else
<option value="" disabled>Нет доступных групп</option>
@endisset
</select>
@error('group_id')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="teacher_id" class="col-md-4 col-form-label text-md-end">Преподаватель*</label>
<div class="col-md-6">
<select id="teacher_id" name="teacher_id" required class="form-control @error('teacher_id') is-invalid @enderror">
<option value="" disabled {{ empty($statement['teacher']['teacher_id'] ?? null) ? 'selected' : '' }}>
Выберите преподавателя
</option>
@isset($teachers['data'])
@foreach($teachers['data'] as $teacher)
<option value="{{ $teacher['teacher_id'] }}"
{{ ($statement['teacher']['teacher_id'] ?? null) == $teacher['teacher_id'] ? 'selected' : '' }}>
{{ $teacher['surname'] }} {{ $teacher['name'] }} {{ $teacher['patronymic'] }}
</option>
@endforeach
@else
<option value="" disabled>Нет доступных преподавателей</option>
@endisset
</select>
@error('teacher_id')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="type_certification_id" class="col-md-4 col-form-label text-md-end">Тип аттестации*</label>
<div class="col-md-6">
<select id="type_certification_id" class="form-control @error('type_certification_id') is-invalid @enderror" name="type_certification_id" required>
<option value="" disabled {{ old('type_certification_id', $statement['type_certification']['id'] ?? '') == '' ? 'selected' : '' }}>Выберите тип</option>
@isset($types)
@foreach($types as $type)
<option value="{{ $type['id'] }}" {{ (old('type_certification_id', $statement['type_certification']['id'] ?? '') == $type['id'] ? 'selected' : '') }}>
{{ $type['name'] }}
</option>
@endforeach
@else
<option value="" disabled>Нет доступных типов</option>
@endisset
</select>
@error('type_certification_id')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="semester" class="col-md-4 col-form-label text-md-end">Семестр*</label>
<div class="col-md-6">
<select id="semester" class="form-control @error('semester') is-invalid @enderror" name="semester" required>
<option value="" disabled {{ empty(old('semester', $statement['semester'] ?? '')) ? 'selected' : '' }}>Выберите семестр</option>
@php
$semesters = [
1 => 'Первый семестр',
2 => 'Второй семестр',
3 => 'Третий семестр',
4 => 'Четвертый семестр',
5 => 'Пятый семестр',
6 => 'Шестой семестр',
7 => 'Седьмой семестр',
8 => 'Восьмой семестр',
9 => 'Девятый семестр',
10 => 'Десятый семестр',
11 => 'Одиннадцатый семестр',
12 => 'Двенадцатый семестр'
];
$selected = old('semester', $statement['semester'] ?? '');
@endphp
@foreach($semesters as $number => $name)
<option value="{{ $name }}" {{ $selected == $name ? 'selected' : '' }}>
{{ $name }}
</option>
@endforeach
</select>
@error('semester')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="academic_year" class="col-md-4 col-form-label text-md-end">Учебный год*</label>
<div class="col-md-6">
<select id="academic_year" class="form-control @error('academic_year') is-invalid @enderror" name="academic_year" required>
<option value="" disabled {{ empty(old('academic_year', $statement['academic_year'] ?? '')) ? 'selected' : '' }}>Выберите учебный год</option>
@php
$currentYear = date('Y');
$nextYear = $currentYear + 1;
$selectedYear = old('academic_year', $statement['academic_year'] ?? '');
@endphp
@for($i = 0; $i < 10; $i++)
@php
$year = $currentYear - $i;
$next = $year + 1;
$yearRange = "{$year}-{$next}";
@endphp
<option value="{{ $yearRange }}" {{ $selectedYear == $yearRange ? 'selected' : '' }}>
{{ $yearRange }}
@if($i == 0) @endif
</option>
@endfor
</select>
@error('academic_year')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="hours" class="col-md-4 col-form-label text-md-end">Часы*</label>
<div class="col-md-6">
<input id="hours" type="text" class="form-control @error('hours') is-invalid @enderror" name="hours" value="{{ old('hours', $statement['hours'] ?? '') }}" required>
@error('hours')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="exam_date" class="col-md-4 col-form-label text-md-end">Дата занятия*</label>
<div class="col-md-6">
<input id="exam_date" type="date" class="form-control @error('exam_date') is-invalid @enderror" name="exam_date"
value="{{ old('exam_date', $statement['exam_date'] ?? '') }}"
min="" max="" required>
@error('exam_date')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
<small class="text-muted" id="date-range-info"></small>
</div>
</div>
<div class="row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ isset($statement) ? 'Обновить' : 'Создать' }}
</button>
<a href="{{ route('statements.index') }}" class="btn btn-secondary">Отмена</a>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const academicYearSelect = document.getElementById('academic_year');
const examDateInput = document.getElementById('exam_date');
const dateRangeInfo = document.getElementById('date-range-info');
const form = document.getElementById('statementForm');
academicYearSelect.addEventListener('change', updateDateRange);
if (academicYearSelect.value) {
updateDateRange();
}
form.addEventListener('submit', function(event) {
if (!validateExamDate()) {
event.preventDefault();
alert('Дата занятия должна быть в пределах выбранного учебного года (с 1 сентября по 30 июня)');
}
});
function updateDateRange() {
const yearRange = academicYearSelect.value;
if (!yearRange) return;
const [startYear, endYear] = yearRange.split('-').map(Number);
const minDate = `${startYear}-09-01`;
const maxDate = `${endYear}-06-30`;
examDateInput.min = minDate;
examDateInput.max = maxDate;
dateRangeInfo.textContent = `Допустимый диапазон: 01.09.${startYear} - 30.06.${endYear}`;
if (examDateInput.value) {
validateExamDate();
}
}
function validateExamDate() {
const examDate = new Date(examDateInput.value);
const minDate = new Date(examDateInput.min);
const maxDate = new Date(examDateInput.max);
if (examDate < minDate || examDate > maxDate) {
examDateInput.classList.add('is-invalid');
return false;
} else {
examDateInput.classList.remove('is-invalid');
return true;
}
}
});
</script>
@endsection

View File

@@ -1,277 +1,110 @@
@extends('layouts.app') @extends('layouts.app')
@section('links')
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
<link href="/resources/css/app.css" rel="stylesheet">
@endsection
@section('content') @section('content')
<div class="container"> <div class="container mx-auto px-4 py-8">
<div class="row justify-content-center"> <div class="bg-white rounded-lg shadow p-6 mb-6">
<div class="col-md-8"> <!-- Шапка ведомости -->
<div class="card"> <div class="grid grid-cols-3 gap-4 mb-6">
<div class="card-header"> <div>
{{ isset($statement) ? 'Редактирование ведомости' : 'Создание новой ведомости' }} <span class="font-semibold">Номер ведомости:</span> {{ $statement['id'] ?? 'Не указано' }}
</div> </div>
<div>
<span class="font-semibold">Дата:</span> {{ \Carbon\Carbon::parse($statement['exam_date'])->format('d.m.Y') ?? 'Не указано' }}
</div>
<div>
<span class="font-semibold">Учебный год:</span> {{ $statement['academic_year'] ?? 'Не указано' }}
</div>
</div>
<div class="card-body"> <div class="grid grid-cols-3 gap-4 mb-6">
<form method="POST" action="{{ isset($statement) ? route('statements.update', $statement['id']) : route('statements.store') }}"> <div>
@csrf <span class="font-semibold">Дисциплина:</span> {{ $statement['discipline']['name'] ?? 'Не указано' }}
@if(isset($statement)) </div>
@method('PATCH') <div>
@endif <span class="font-semibold">Преподаватель:</span>
{{ $statement['teacher']['surname'] ?? '' }}
{{ $statement['teacher']['name'] ?? '' }}
{{ $statement['teacher']['patronymic'] ?? '' }}
</div>
<div>
<span class="font-semibold">Вид контроля:</span> {{ $statement['type_certification']['name'] ?? 'Не указано' }}
</div>
</div>
<div class="row mb-3"> <div class="grid grid-cols-3 gap-4 mb-8">
<label for="discipline_id" class="col-md-4 col-form-label text-md-end">Дисциплина*</label> <div>
<div class="col-md-6"> <span class="font-semibold">Статус:</span>
<select id="discipline_id" class="form-control @error('discipline_id') is-invalid @enderror" name="discipline_id" required> @if(($statement['status']['id'] ?? 0) == 3)
<option value="" disabled {{ old('discipline_id', $statement['discipline']['id'] ?? '') == '' ? 'selected' : '' }}>Выберите дисциплину</option> <span class="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs">
@isset($disciplines) Проведена
@foreach($disciplines as $discipline) </span>
<option value="{{ $discipline['id'] }}" {{ (old('discipline_id', $statement['discipline']['id'] ?? '') == $discipline['id'] ? 'selected' : '') }}> @else
{{ $discipline['name'] }} <span class="px-2 py-1 bg-yellow-100 text-yellow-800 rounded-full text-xs">
</option> Не проведена
@endforeach </span>
@else @endif
<option value="" disabled>Нет доступных дисциплин</option> </div>
@endisset <div></div>
</select> </div>
@error('discipline_id') <form method="POST" action="{{route('statements.update', ['statement' => $statement['id']])}}">
<span class="invalid-feedback" role="alert"> @csrf
<strong>{{ $message }}</strong> @method('PATCH')
</span> <!-- Кнопки действий -->
@enderror <div class="flex space-x-4 mb-8">
</div> <button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
</div> Сохранить
</button>
<button class="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600">
Провести
</button>
<a href="{{ route('teacher.statements.generatePdf', ['statementId' => $statement['id'], 'with_grades' => false]) }}"
class="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600">
Скачать ведомость без оценок
</a>
<a href="{{ url()->previous() }}" class="px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400">
Назад
</a>
<div class="row mb-3"> </div>
<label for="group_id" class="col-md-4 col-form-label text-md-end">Группа*</label>
<div class="col-md-6">
<select id="group_id" class="form-control @error('group_id') is-invalid @enderror" name="group_id" required>
<option value="" disabled {{ old('group_id', $statement['group']['id'] ?? '') == '' ? 'selected' : '' }}>Выберите группу</option>
@isset($groups)
@foreach($groups as $group)
<option value="{{ $group['id'] }}" {{ (old('group_id', $statement['group']['id'] ?? '') == $group['id'] ? 'selected' : '') }}>
{{ $group['name'] }}
</option>
@endforeach
@else
<option value="" disabled>Нет доступных групп</option>
@endisset
</select>
@error('group_id')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3"> <!-- Таблица студентов -->
<label for="teacher_id" class="col-md-4 col-form-label text-md-end">Преподаватель*</label> <div class="overflow-x-auto">
<div class="col-md-6"> <table class="min-w-full divide-y divide-gray-200">
<select id="teacher_id" name="teacher_id" required class="form-control @error('teacher_id') is-invalid @enderror"> <thead class="bg-gray-50">
<option value="" disabled {{ empty($statement['teacher']['teacher_id'] ?? null) ? 'selected' : '' }}> <tr>
Выберите преподавателя <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Номер зачетной книжки</th>
</option> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Группа</th>
@isset($teachers['data']) <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Ф.И.О.</th>
@foreach($teachers['data'] as $teacher) <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Отметка</th>
<option value="{{ $teacher['teacher_id'] }}" </tr>
{{ ($statement['teacher']['teacher_id'] ?? null) == $teacher['teacher_id'] ? 'selected' : '' }}> </thead>
{{ $teacher['surname'] }} {{ $teacher['name'] }} {{ $teacher['patronymic'] }} <tbody class="bg-white divide-y divide-gray-200">
</option> @foreach($statement['students'] ?? [] as $student)
@endforeach <tr>
@else <td class="px-6 py-4 whitespace-nowrap">{{ $student['matriculation_number'] ?? 'Не указано' }}</td>
<option value="" disabled>Нет доступных преподавателей</option> <td class="px-6 py-4 whitespace-nowrap">{{ $statement['group']['name'] ?? 'Не указано' }}</td>
@endisset <td class="px-6 py-4 whitespace-nowrap">
</select> {{ $student['full_name'] ?? '' }}
@error('teacher_id') </td>
<span class="invalid-feedback" role="alert"> <td class="px-6 py-4 whitespace-nowrap">
<strong>{{ $message }}</strong> <select name="grades[{{ $student['student_profile_id'] }}]" class="border-gray-300 rounded">
</span> <option value="" disabled {{ empty($student['estimation_name']) ? 'selected' : '' }}>Укажите оценку</option>
@enderror @foreach($estimations as $estimation)
</div> <option value="{{ $estimation['id'] }}" {{ $student['estimation_name'] == $estimation['name'] ? 'selected' : '' }}>
</div> {{ $estimation['name'] }}
<div class="row mb-3">
<label for="type_certification_id" class="col-md-4 col-form-label text-md-end">Тип аттестации*</label>
<div class="col-md-6">
<select id="type_certification_id" class="form-control @error('type_certification_id') is-invalid @enderror" name="type_certification_id" required>
<option value="" disabled {{ old('type_certification_id', $statement['type_certification']['id'] ?? '') == '' ? 'selected' : '' }}>Выберите тип</option>
@isset($types)
@foreach($types as $type)
<option value="{{ $type['id'] }}" {{ (old('type_certification_id', $statement['type_certification']['id'] ?? '') == $type['id'] ? 'selected' : '') }}>
{{ $type['name'] }}
</option>
@endforeach
@else
<option value="" disabled>Нет доступных типов</option>
@endisset
</select>
@error('type_certification_id')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="semester" class="col-md-4 col-form-label text-md-end">Семестр*</label>
<div class="col-md-6">
<select id="semester" class="form-control @error('semester') is-invalid @enderror" name="semester" required>
<option value="" disabled {{ empty(old('semester', $statement['semester'] ?? '')) ? 'selected' : '' }}>Выберите семестр</option>
@php
$semesters = [
1 => 'Первый семестр',
2 => 'Второй семестр',
3 => 'Третий семестр',
4 => 'Четвертый семестр',
5 => 'Пятый семестр',
6 => 'Шестой семестр',
7 => 'Седьмой семестр',
8 => 'Восьмой семестр',
9 => 'Девятый семестр',
10 => 'Десятый семестр',
11 => 'Одиннадцатый семестр',
12 => 'Двенадцатый семестр'
];
$selected = old('semester', $statement['semester'] ?? '');
@endphp
@foreach($semesters as $number => $name)
<option value="{{ $name }}" {{ $selected == $name ? 'selected' : '' }}>
{{ $name }}
</option> </option>
@endforeach @endforeach
</select> </select>
@error('semester') </td>
<span class="invalid-feedback" role="alert"> </tr>
<strong>{{ $message }}</strong> @endforeach
</span> </tbody>
@enderror </table>
</div>
</div>
<div class="row mb-3">
<label for="academic_year" class="col-md-4 col-form-label text-md-end">Учебный год*</label>
<div class="col-md-6">
<select id="academic_year" class="form-control @error('academic_year') is-invalid @enderror" name="academic_year" required>
<option value="" disabled {{ empty(old('academic_year', $statement['academic_year'] ?? '')) ? 'selected' : '' }}>Выберите учебный год</option>
@php
$currentYear = date('Y');
$nextYear = $currentYear + 1;
$selectedYear = old('academic_year', $statement['academic_year'] ?? '');
@endphp
@for($i = 0; $i < 10; $i++)
@php
$year = $currentYear - $i;
$next = $year + 1;
$yearRange = "{$year}-{$next}";
@endphp
<option value="{{ $yearRange }}" {{ $selectedYear == $yearRange ? 'selected' : '' }}>
{{ $yearRange }}
@if($i == 0) @endif
</option>
@endfor
</select>
@error('academic_year')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="hours" class="col-md-4 col-form-label text-md-end">Часы*</label>
<div class="col-md-6">
<input id="hours" type="text" class="form-control @error('hours') is-invalid @enderror" name="hours" value="{{ old('hours', $statement['hours'] ?? '') }}" required>
@error('hours')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="row mb-3">
<label for="exam_date" class="col-md-4 col-form-label text-md-end">Дата занятия*</label>
<div class="col-md-6">
<input id="exam_date" type="date" class="form-control @error('exam_date') is-invalid @enderror" name="exam_date"
value="{{ old('exam_date', $statement['exam_date'] ?? '') }}"
min="" max="" required>
@error('exam_date')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
<small class="text-muted" id="date-range-info"></small>
</div>
</div>
<div class="row mb-0">
<div class="col-md-6 offset-md-4">
<button type="submit" class="btn btn-primary">
{{ isset($statement) ? 'Обновить' : 'Создать' }}
</button>
<a href="{{ route('statements.index') }}" class="btn btn-secondary">Отмена</a>
</div>
</div>
</form>
</div>
</div> </div>
</div> </form>
</div> </div>
</div> </div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const academicYearSelect = document.getElementById('academic_year');
const examDateInput = document.getElementById('exam_date');
const dateRangeInfo = document.getElementById('date-range-info');
const form = document.getElementById('statementForm');
academicYearSelect.addEventListener('change', updateDateRange);
if (academicYearSelect.value) {
updateDateRange();
}
// Валидация перед отправкой формы
form.addEventListener('submit', function(event) {
if (!validateExamDate()) {
event.preventDefault();
alert('Дата занятия должна быть в пределах выбранного учебного года (с 1 сентября по 30 июня)');
}
});
function updateDateRange() {
const yearRange = academicYearSelect.value;
if (!yearRange) return;
const [startYear, endYear] = yearRange.split('-').map(Number);
const minDate = `${startYear}-09-01`;
const maxDate = `${endYear}-06-30`;
examDateInput.min = minDate;
examDateInput.max = maxDate;
dateRangeInfo.textContent = `Допустимый диапазон: 01.09.${startYear} - 30.06.${endYear}`;
if (examDateInput.value) {
validateExamDate();
}
}
function validateExamDate() {
const examDate = new Date(examDateInput.value);
const minDate = new Date(examDateInput.min);
const maxDate = new Date(examDateInput.max);
if (examDate < minDate || examDate > maxDate) {
examDateInput.classList.add('is-invalid');
return false;
} else {
examDateInput.classList.remove('is-invalid');
return true;
}
}
});
</script>
@endsection @endsection

View File

@@ -52,8 +52,12 @@
<select id="group_id" name="group_id" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm"> <select id="group_id" name="group_id" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
<option value="">Все группы</option> <option value="">Все группы</option>
@foreach($groups as $group) @foreach($groups as $group)
<option value="{{ $group }}" {{ request('group_id') == $group ? 'selected' : '' }}> @php
{{ $group }} $groupId = is_array($group) ? ($group['id'] ?? $group) : $group;
$groupName = is_array($group) ? ($group['name'] ?? $group) : $group;
@endphp
<option value="{{ $groupId }}" {{ request('group_id') == $groupId ? 'selected' : '' }}>
{{ $groupName }}
</option> </option>
@endforeach @endforeach
</select> </select>
@@ -64,6 +68,11 @@
Применить фильтры Применить фильтры
</button> </button>
</div> </div>
<div class="flex items-end">
<button type="button" class="px-4 py-2 bg-red-500 text-white rounded-md hover:bg-red-600 w-full" id="clearParams">
Стереть фильтры
</button>
</div>
</div> </div>
</form> </form>
</div> </div>
@@ -72,21 +81,24 @@
<div class="bg-white rounded-lg shadow overflow-hidden"> <div class="bg-white rounded-lg shadow overflow-hidden">
@if(count($statements) > 0) @if(count($statements) > 0)
<div class="table-responsive"> <div class="table-responsive">
<table class="min-w-full divide-y divide-gray-200"> <table class="min-w-full divide-y divide-gray-200 text-center">
<thead class="bg-gray-50"> <thead class="bg-gray-50">
<tr> <tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Дисциплина</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider text-center">Номер ведомости</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Группа</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider text-center">Дисциплина</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Учебный год</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider text-center">Группа</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Семестр</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider text-center">Учебный год</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Тип аттестации</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider text-center">Семестр</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Статус</th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider text-center">Тип аттестации</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"></th> <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider text-center">Статус</th>
</tr> </tr>
</thead> </thead>
<tbody class="bg-white divide-y divide-gray-200"> <tbody class="bg-white divide-y divide-gray-200">
@foreach($statements as $statement) @foreach($statements as $statement)
<tr class="hover:bg-gray-50"> <tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('statements.edit', $statement['id']) }}'">
<div class="text-sm text-gray-500">{{ $statement['id'] }}</div>
</td>
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('statements.edit', $statement['id']) }}'"> <td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('statements.edit', $statement['id']) }}'">
<div class="text-sm font-medium text-gray-900"> <div class="text-sm font-medium text-gray-900">
{{ $statement['discipline']['name'] }} {{ $statement['discipline']['name'] }}
@@ -108,7 +120,7 @@
</td> </td>
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('statements.edit', $statement['id']) }}'"> <td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('statements.edit', $statement['id']) }}'">
<div class="text-sm text-gray-500"> <div class="text-sm text-gray-500">
@if($statement['is_finalized']) @if($statement['status']['id'] == 3)
<span class="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs"> <span class="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs">
Проведена Проведена
</span> </span>
@@ -119,24 +131,6 @@
@endif @endif
</div> </div>
</td> </td>
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium flex justify-end items-center space-x-2">
<a href="{{ route('teacher.statements.generatePdf', ['statementId' => $statement['id'], 'with_grades' => true]) }}"
class="text-blue-500 hover:text-blue-700" title="Скачать с оценками">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
</a>
@if(!$statement['is_finalized'])
<form action="{{ route('teacher.statements.sendFinalizationCode', $statement['id']) }}" method="POST" class="inline">
@csrf
<button type="submit" class="text-green-500 hover:text-green-700" title="Завершить ведомость">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7" />
</svg>
</button>
</form>
@endif
</td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
@@ -149,4 +143,15 @@
@endif @endif
</div> </div>
</div> </div>
<script>
document.getElementById('clearParams').onclick = function(event) {
event.preventDefault();
const url = new URL(window.location.href);
url.searchParams.delete('academic_year');
url.searchParams.delete('discipline_id');
url.searchParams.delete('group_id');
window.location.href = url.toString();
};
</script>
@endsection @endsection

View File

@@ -10,9 +10,7 @@ use App\Http\Controllers\StatisticController;
use App\Http\Controllers\StudentController; use App\Http\Controllers\StudentController;
use Illuminate\Support\Facades\Route; use Illuminate\Support\Facades\Route;
Route::get('/', function () { Route::redirect('/', '/login');
return view('welcome');
});
Route::controller(AuthController::class)->group(function () { Route::controller(AuthController::class)->group(function () {
Route::get('/login', 'showLoginForm')->name('login'); Route::get('/login', 'showLoginForm')->name('login');
@@ -42,9 +40,8 @@ Route::middleware(['jwt.auth'])->group(function () {
Route::resource('statements', StatementController::class)->except(['show']); Route::resource('statements', StatementController::class)->except(['show']);
Route::get('/statements/search', [StatementController::class, 'search'])->name('teacher.statements.search'); Route::get('/statements/search', [StatementController::class, 'search'])->name('teacher.statements.search');
Route::get('/my/statements', [StatementController::class, 'myStatements'])->name('teacher.statements.index'); Route::get('/my/statements', [StatementController::class, 'myStatements'])->name('teacher.statements.index');
Route::get('/statements/pdf', [StatementController::class, 'generatePdf'])->name('teacher.statements.generatePdf'); Route::get('/statements/{statementId}/pdf', [StatementController::class, 'generatePdf'])->name('teacher.statements.generatePdf');
Route::get('/statements/sendFinalizationCode', [StatementController::class, 'finalize'])->name('teacher.statements.sendFinalizationCode'); Route::get('/statements/sendFinalizationCode', [StatementController::class, 'finalize'])->name('teacher.statements.sendFinalizationCode');
/* Route::get('/statements/{id}/sendFinalizationCode', [StatementController::class, 'myStatements'])->name('teacher.statements.sendFinalizationCode');*/
// Statistics // Statistics
Route::get('/statistics', [StatisticController::class, 'index'])->name('statistics.index'); Route::get('/statistics', [StatisticController::class, 'index'])->name('statistics.index');