Проведение

This commit is contained in:
2025-06-02 15:24:14 +04:00
parent 92ebaee310
commit 99bf27d3b0
4 changed files with 236 additions and 96 deletions

View File

@@ -56,55 +56,35 @@ class StatementController extends Controller
public function edit($id)
{
$estimations = $this->api->get("/employee/estimations");
$statementResponse = $this->api->get("/employee/statements/{$id}");
$groupsResponse = $this->api->get('/employee/groups');
$disciplinesResponse = $this->api->get('/employee/disciplines');
$typesResponse = $this->api->get('/employee/types');
$teachersResponse = $this->api->get('/employee/teachers');
if ($statementResponse->successful() &&
$groupsResponse->successful() &&
$disciplinesResponse->successful() &&
$typesResponse->successful() &&
$teachersResponse->successful() &&
$estimations->successful()) {
return view('statements.form', [
'statement' => $statementResponse->json(),
'groups' => $groupsResponse->json(),
'disciplines' => $disciplinesResponse->json(),
'types' => $typesResponse->json(),
'teachers' => $teachersResponse->json(),
'isEdit' => true,
'estimations' => $estimations->json()
]);
foreach (['/employee', '/teacher'] as $prefix) {
$statementResponse = $this->api->get("{$prefix}/statements/{$id}");
$groupsResponse = $this->api->get("{$prefix}/groups");
$disciplinesResponse = $this->api->get("{$prefix}/disciplines");
$typesResponse = $this->api->get("{$prefix}/types");
$teachersResponse = $this->api->get("{$prefix}/teachers");
$estimationsResponse = $this->api->get("{$prefix}/estimations");
if (
$statementResponse->successful() &&
$groupsResponse->successful() &&
$disciplinesResponse->successful() &&
$typesResponse->successful() &&
$teachersResponse->successful() &&
$estimationsResponse->successful()
) {
return view('statements.form', [
'statement' => $statementResponse->json(),
'groups' => $groupsResponse->json(),
'disciplines' => $disciplinesResponse->json(),
'types' => $typesResponse->json(),
'teachers' => $teachersResponse->json(),
'isEdit' => true,
'estimations' => $estimationsResponse->json()
]);
}
}
$estimations2 = $this->api->get("/teacher/estimations");
$statementResponse2 = $this->api->get("/teacher/statements/{$id}");
$groupsResponse2 = $this->api->get('/teacher/groups');
$disciplinesResponse2 = $this->api->get('/teacher/disciplines');
$typesResponse2 = $this->api->get('/teacher/types');
$teachersResponse2 = $this->api->get('/teacher/teachers');
if ($statementResponse2->successful() &&
$groupsResponse2->successful() &&
$disciplinesResponse2->successful() &&
$typesResponse2->successful() &&
$teachersResponse2->successful() &&
$estimations2->successful()) {
return view('statements.form', [
'statement' => $statementResponse2->json(),
'groups' => $groupsResponse2->json(),
'disciplines' => $disciplinesResponse2->json(),
'types' => $typesResponse2->json(),
'teachers' => $teachersResponse2->json(),
'isEdit' => true,
'estimations' => $estimations2->json()
]);
}
abort($statementResponse->status() ?? $statementResponse2->status() ?? 500);
abort(500, 'Не удалось загрузить данные для редактирования ведомости');
}
public function update(Request $request, $id)
@@ -126,7 +106,33 @@ class StatementController extends Controller
'response' => $response->json()
]);
return back()->withErrors($response->json()['errors'] ?? []);
$teacherResponse = $this->api->patch("/teacher/statements/{$id}", $data);
if ($teacherResponse->successful()) {
return redirect()->route('statements.index')
->with('success', 'Ведомость успешно обновлена');
}
Log::error('Both employee and teacher API update failed:', [
'employee_status' => $response->status(),
'employee_response' => $response->json(),
'teacher_status' => $teacherResponse->status(),
'teacher_response' => $teacherResponse->json()
]);
$errorMessage = 'Ошибка при обновлении ведомости: ';
if ($teacherResponse->status() === 403 || $response->status() === 403) {
$errorMessage = 'Доступ запрещен. У вас недостаточно прав для изменения этой ведомости.';
} elseif ($teacherResponse->status() === 404 || $response->status() === 404) {
$errorMessage = 'Ведомость не найдена.';
} else {
$errorMessage .= $teacherResponse->json()['message'] ??
$response->json()['message'] ??
'Неизвестная ошибка';
}
return back()->with('error', $errorMessage);
}
public function destroy($id)
@@ -159,17 +165,18 @@ class StatementController extends Controller
{
try {
$withGrades = $request->input('with_grades', true);
$response = $this->api->get("/employee/statements/{$statementId}/pdf", [
'with_grades' => $withGrades
]);
if ($response->successful()) {
$content = $response->body();
$contentType = $response->header('Content-Type');
$contentDisposition = $response->header('Content-Disposition');
$endpoints = ["/employee/statements/{$statementId}/pdf", "/teacher/statements/{$statementId}/pdf"];
return response($content)
->header('Content-Type', $contentType)
->header('Content-Disposition', $contentDisposition);
foreach ($endpoints as $endpoint) {
$response = $this->api->get($endpoint, [
'with_grades' => $withGrades
]);
if ($response->successful()) {
return response($response->body())
->header('Content-Type', $response->header('Content-Type'))
->header('Content-Disposition', $response->header('Content-Disposition'));
}
}
return back()->withErrors($response->json()['error'] ?? 'Ошибка при генерации PDF');
@@ -178,23 +185,6 @@ class StatementController extends Controller
}
}
/**
* Финализация ведомости
*/
public function finalize(int $statementId)
{
try {
$response = $this->api->post("/teacher/statements/{$statementId}/finalize");
if ($response->successful()) {
return redirect()->back()->with('success', 'Ведомость успешно финализирована');
}
return back()->withErrors($response->json()['error'] ?? 'Ошибка при финализации ведомости');
} catch (\Exception $e) {
return back()->withErrors('Ошибка при финализации ведомости: ' . $e->getMessage());
}
}
public function myStatements(Request $request)
{

View File

@@ -105,6 +105,8 @@ return [
),
],
'api_base_url' => env('API_BASE_URL', 'http://127.0.0.1:8000/api'),
/*
|--------------------------------------------------------------------------
| Maintenance Mode Driver

View File

@@ -25,8 +25,15 @@
.hidden {
display: none;
}
.code-input {
transition: all 0.3s ease;
}
.code-input::placeholder {
color: rgba(0, 0, 0, 0.3);
}
</style>
@endsection
@section('content')
<div class="container mx-auto px-4 py-8">
<div class="bg-white rounded-lg shadow p-6 mb-6">
@@ -73,28 +80,65 @@
</div>
<div></div>
</div>
<form method="POST" action="{{route('statements.update', ['statement' => $statement['id']])}}">
<form method="POST" action="{{route('statements.update', ['statement' => $statement['id']])}}" id="statementForm">
@csrf
@method('PATCH')
<!-- Кнопки действий -->
<div class="flex space-x-4 mb-8">
<button type="submit"
onclick="saveAndRefresh(event)"
class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
Сохранить
</button>
<button class="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600">
Провести
</button>
<div class="flex space-x-4 mb-8" id="actionButtons">
@if(($statement['status']['id'] ?? 0) != 3)
<button type="submit"
onclick="saveAndRefresh(event)"
class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
id="saveButton">
Сохранить
</button>
<button type="button"
onclick="initiateFinalization()"
class="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
id="finalizeButton">
Провести
</button>
@endif
<a href="{{ route('teacher.statements.generatePdf', ['statementId' => $statement['id'], 'with_grades' => false]) }}"
target="_blank"
class="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600">
Скачать ведомость без оценок
</a>
@if(($statement['status']['id'] ?? 0) == 3)
<a href="{{ route('teacher.statements.generatePdf', ['statementId' => $statement['id'], 'with_grades' => true]) }}"
target="_blank"
class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
Скачать ведомость с оценками
</a>
@endif
<a href="/statements" class="px-4 py-2 bg-gray-300 text-gray-700 rounded hover:bg-gray-400">
Назад
</a>
</div>
<!-- Блок для ввода кода подтверждения (изначально скрыт) -->
<div id="codeVerificationBlock" class="hidden flex space-x-4 mb-8">
<input type="text"
id="verificationCode"
name="verification_code"
placeholder="Код подтверждения"
class="code-input px-4 py-2 border rounded focus:outline-none focus:ring-2 focus:ring-green-500">
<button type="button"
onclick="confirmFinalization()"
class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700">
Подтвердить код
</button>
<button type="button"
onclick="cancelFinalization()"
class="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600">
Отмена
</button>
</div>
<!-- Таблица студентов -->
@@ -117,14 +161,28 @@
{{ $student['full_name'] ?? '' }}
</td>
<td class="px-6 py-4 whitespace-nowrap">
<select name="grades[{{ $student['student_profile_id'] }}]" class="border-gray-300 rounded">
<option value="" disabled {{ empty($student['estimation_name']) ? 'selected' : '' }}>Укажите оценку</option>
@foreach($estimations as $estimation)
<option value="{{ $estimation['id'] }}" {{ $student['estimation_name'] == $estimation['name'] ? 'selected' : '' }}>
{{ $estimation['name'] }}
</option>
@endforeach
</select>
@if(($statement['status']['id'] ?? 0) != 3)
<select name="grades[{{ $student['student_profile_id'] }}]" class="border-gray-300 rounded">
<option value="" disabled {{ empty($student['estimation_name']) ? 'selected' : '' }}>Укажите оценку</option>
@foreach($estimations as $estimation)
@if($statement['type_certification']['id'] == 1)
@if(in_array($estimation['id'], [1, 2, 3]))
<option value="{{ $estimation['id'] }}" {{ $student['estimation_name'] == $estimation['name'] ? 'selected' : '' }}>
{{ $estimation['name'] }}
</option>
@endif
@else
@if(in_array($estimation['id'], [1, 4, 5, 6, 7]))
<option value="{{ $estimation['id'] }}" {{ $student['estimation_name'] == $estimation['name'] ? 'selected' : '' }}>
{{ $estimation['name'] }}
</option>
@endif
@endif
@endforeach
</select>
@else
{{ $student['estimation_name'] ?? 'Не указано' }}
@endif
</td>
</tr>
@endforeach
@@ -136,12 +194,18 @@
</div>
<div id="notification" class="notification hidden"></div>
<script>
function showNotification(message) {
function showNotification(message, isError = false) {
const notification = document.getElementById('notification');
notification.textContent = message;
notification.classList.remove('hidden');
notification.classList.add('show');
if (isError) {
notification.style.backgroundColor = '#e53e3e'; // red
} else {
notification.style.backgroundColor = '#48bb78'; // green
}
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
@@ -176,8 +240,93 @@
})
.catch(error => {
console.error('Ошибка:', error);
showNotification(error.message);
showNotification(error.message, true);
});
}
function initiateFinalization() {
const allEstimationsFilled = {{ $statement['all_estimations_filled'] ? 'true' : 'false' }};
if (!allEstimationsFilled) {
showNotification('Нельзя провести ведомость: не все оценки выставлены.', true);
return;
}
window.apiToken = "{{ session('api_token') }}";
window.apiBaseUrl = "{{ config('app.api_base_url') }}";
window.userRole = "{{ session('user_role') }}";
const rolePath = window.userRole == 2 ? 'teacher' : 'employee';
fetch(`${window.apiBaseUrl}/${rolePath}/statements/{{ $statement['id'] }}/send-code`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${window.apiToken}`,
'X-CSRF-TOKEN': '{{ csrf_token() }}',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.error) {
throw new Error(data.error);
}
document.getElementById('actionButtons').classList.add('hidden');
document.getElementById('codeVerificationBlock').classList.remove('hidden');
document.getElementById('verificationCode').focus();
showNotification(data.message || 'Код подтверждения отправлен на вашу почту');
})
.catch(error => {
console.error('Ошибка:', error);
showNotification(error.message, true);
});
}
function confirmFinalization() {
window.apiToken = "{{ session('api_token') }}";
window.apiBaseUrl = "{{ config('app.api_base_url') }}";
window.userRole = "{{ session('user_role') }}";
const code = document.getElementById('verificationCode').value.trim();
if (!code) {
showNotification('Введите код подтверждения', true);
return;
}
const rolePath = window.userRole == 2 ? 'teacher' : 'employee';
fetch(`${window.apiBaseUrl}/${rolePath}/statements/{{ $statement['id'] }}/verify`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${window.apiToken}`,
'X-CSRF-TOKEN': '{{ csrf_token() }}',
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ code: code })
})
.then(response => response.json())
.then(data => {
if (data.error) {
throw new Error(data.error);
}
showNotification(data.message || 'Ведомость успешно проведена');
setTimeout(() => {
window.location.reload();
}, 1000);
})
.catch(error => {
console.error('Ошибка:', error);
showNotification(error.message, true);
});
}
function cancelFinalization() {
document.getElementById('actionButtons').classList.remove('hidden');
document.getElementById('codeVerificationBlock').classList.add('hidden');
document.getElementById('verificationCode').value = '';
}
</script>
@endsection

View File

@@ -41,7 +41,6 @@ Route::middleware(['jwt.auth'])->group(function () {
Route::get('/statements/search', [StatementController::class, 'search'])->name('teacher.statements.search');
Route::get('/my/statements', [StatementController::class, 'myStatements'])->name('teacher.statements.index');
Route::get('/statements/{statementId}/pdf', [StatementController::class, 'generatePdf'])->name('teacher.statements.generatePdf');
Route::get('/statements/sendFinalizationCode', [StatementController::class, 'finalize'])->name('teacher.statements.sendFinalizationCode');
// Statistics
Route::get('/statistics', [StatisticController::class, 'index'])->name('statistics.index');