...
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Services\ApiService;
|
||||
use Exception;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
@@ -62,6 +63,7 @@ class StatementController extends Controller
|
||||
$typesResponse = $this->api->get('/employee/types');
|
||||
$teachersResponse = $this->api->get('/employee/teachers');
|
||||
|
||||
// Если employee API успешно ответил
|
||||
if ($statementResponse->successful() &&
|
||||
$groupsResponse->successful() &&
|
||||
$disciplinesResponse->successful() &&
|
||||
@@ -78,7 +80,29 @@ class StatementController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
abort($statementResponse->status());
|
||||
$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()) {
|
||||
|
||||
return view('statements.form', [
|
||||
'statement' => $statementResponse2->json(),
|
||||
'groups' => $groupsResponse2->json(),
|
||||
'disciplines' => $disciplinesResponse2->json(),
|
||||
'types' => $typesResponse2->json(),
|
||||
'teachers' => $teachersResponse2->json(),
|
||||
'isEdit' => true
|
||||
]);
|
||||
}
|
||||
|
||||
abort($statementResponse->status() ?? $statementResponse2->status() ?? 500);
|
||||
}
|
||||
|
||||
public function update(Request $request, $id)
|
||||
@@ -118,4 +142,82 @@ class StatementController extends Controller
|
||||
'disciplines' => $disciplines,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Генерация PDF ведомости
|
||||
*/
|
||||
public function generatePdf(int $statementId, Request $request)
|
||||
{
|
||||
try {
|
||||
$withGrades = $request->input('with_grades', true);
|
||||
$response = $this->api->get("/teacher/statements/{$statementId}/pdf", [
|
||||
'with_grades' => $withGrades
|
||||
]);
|
||||
|
||||
if ($response->successful()) {
|
||||
$content = $response->body();
|
||||
$contentType = $response->header('Content-Type');
|
||||
$contentDisposition = $response->header('Content-Disposition');
|
||||
|
||||
return response($content)
|
||||
->header('Content-Type', $contentType)
|
||||
->header('Content-Disposition', $contentDisposition);
|
||||
}
|
||||
|
||||
return back()->withErrors($response->json()['error'] ?? 'Ошибка при генерации PDF');
|
||||
} catch (\Exception $e) {
|
||||
return back()->withErrors('Ошибка при генерации PDF: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Финализация ведомости
|
||||
*/
|
||||
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)
|
||||
{
|
||||
try {
|
||||
$disciplinesResponse = $this->api->get('/teacher/disciplines/my');
|
||||
$disciplines = $disciplinesResponse->json()['data'] ?? [];
|
||||
|
||||
$apiParams = [
|
||||
'academic_year' => $request->input('academic_year'),
|
||||
'discipline_id' => $request->input('discipline_id')
|
||||
];
|
||||
|
||||
$statementsResponse = $this->api->get('/teacher/statements', $apiParams);
|
||||
|
||||
if (!$statementsResponse->successful()) {
|
||||
throw new \Exception('Failed to load statements');
|
||||
}
|
||||
|
||||
$groups = $this->api->get('/employee/groups')->json();
|
||||
|
||||
return view('teacher.statements.index', [
|
||||
'statements' => $statementsResponse->json(),
|
||||
'disciplines' => $disciplines,
|
||||
'filters' => $request->only(['academic_year', 'discipline_id']),
|
||||
'groups' => $groups
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('Ошибка в myStatements: ' . $e->getMessage());
|
||||
|
||||
return back()->with('error', $e->getMessage())->withInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Employee Login</title>
|
||||
<title>Вход</title>
|
||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||
<style>
|
||||
body {
|
||||
@@ -52,7 +52,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="login-container">
|
||||
<h1 class="text-2xl font-bold mb-6">Employee Portal</h1>
|
||||
<h1 class="text-2xl font-bold mb-6">Вход</h1>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="mb-4 p-2 bg-red-100 text-red-700 rounded">
|
||||
@@ -63,7 +63,7 @@
|
||||
<form method="POST" action="{{ route('login') }}">
|
||||
@csrf
|
||||
<div class="form-group">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<label for="email" class="form-label">Вход</label>
|
||||
<input id="email" type="email" class="form-input" name="email" value="{{ old('email') }}" required autofocus>
|
||||
@error('email')
|
||||
<span class="error-message">{{ $message }}</span>
|
||||
@@ -71,7 +71,7 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="password" class="form-label">Password</label>
|
||||
<label for="password" class="form-label">Пароль</label>
|
||||
<input id="password" type="password" class="form-input" name="password" required>
|
||||
@error('password')
|
||||
<span class="error-message">{{ $message }}</span>
|
||||
|
||||
@@ -52,9 +52,9 @@
|
||||
</head>
|
||||
<body>
|
||||
<div class="verify-container">
|
||||
<h1 class="text-2xl font-bold mb-6">Two-Factor Authentication</h1>
|
||||
<h1 class="text-2xl font-bold mb-6">Двухфакторная аутентификация</h1>
|
||||
|
||||
<p class="mb-4">We've sent a 6-digit verification code to your email. Please enter it below.</p>
|
||||
<p class="mb-4">Мы отправили 6-значный проверочный код на ваш электронный адрес. Пожалуйста, введите его ниже.</p>
|
||||
|
||||
@if ($errors->any())
|
||||
<div class="mb-4 p-2 bg-red-100 text-red-700 rounded">
|
||||
@@ -65,7 +65,7 @@
|
||||
<form method="POST" action="{{ route('verify-2fa') }}">
|
||||
@csrf
|
||||
<div class="form-group">
|
||||
<label for="code" class="form-label">Verification Code</label>
|
||||
<label for="code" class="form-label">Код подтверждения</label>
|
||||
<input id="code" type="text" class="form-input" name="code" required autofocus maxlength="6" pattern="\d{6}">
|
||||
@error('code')
|
||||
<span class="error-message">{{ $message }}</span>
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<button type="submit" class="btn">
|
||||
Verify
|
||||
Подтвердить
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,43 +1,152 @@
|
||||
@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')
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<h1 class="text-2xl font-bold">Результаты поиска ведомостей</h1>
|
||||
<a href="{{ route('teacher.statements.search') }}" class="text-blue-600 hover:text-blue-800">
|
||||
Новый поиск
|
||||
</a>
|
||||
<div class="flex justify-between items-center mb-8">
|
||||
<h1 class="text-2xl font-bold">Список ведомостей</h1>
|
||||
<div class="flex flex-wrap gap-2 justify-end">
|
||||
<a href="{{ url('/dashboard') }}" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded">
|
||||
Перейти в панель
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Фильтры -->
|
||||
<div class="bg-white rounded-lg shadow p-6 mb-6">
|
||||
<form method="GET" action="{{ route('teacher.statements.index') }}">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
<div>
|
||||
<label for="academic_year" class="block text-sm font-medium text-gray-700">Учебный год</label>
|
||||
<select id="academic_year" name="academic_year" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
|
||||
<option value="">Все годы</option>
|
||||
@php
|
||||
$currentYear = date('Y');
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$year = $currentYear - $i;
|
||||
$yearRange = $year . '-' . ($year + 1);
|
||||
@endphp
|
||||
<option value="{{ $yearRange }}" {{ request('academic_year') == $yearRange ? 'selected' : '' }}>
|
||||
{{ $yearRange }}
|
||||
</option>
|
||||
@php } @endphp
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="discipline_id" class="block text-sm font-medium text-gray-700">Дисциплина</label>
|
||||
<select id="discipline_id" name="discipline_id" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
|
||||
<option value="">Все дисциплины</option>
|
||||
@foreach($disciplines as $discipline)
|
||||
<option value="{{ $discipline['id'] }}" {{ request('discipline_id') == $discipline['id'] ? 'selected' : '' }}>
|
||||
{{ $discipline['name'] }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="group_id" class="block text-sm font-medium text-gray-700">Группа</label>
|
||||
<select id="group_id" name="group_id" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm">
|
||||
<option value="">Все группы</option>
|
||||
@foreach($groups as $group)
|
||||
<option value="{{ $group }}" {{ request('group_id') == $group ? 'selected' : '' }}>
|
||||
{{ $group }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex items-end">
|
||||
<button type="submit" class="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 w-full">
|
||||
Применить фильтры
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<!-- Таблица ведомостей -->
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<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">Группа</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">Семестр</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">Действия</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
@foreach($statements as $statement)
|
||||
@if(count($statements) > 0)
|
||||
<div class="table-responsive">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ $statement['discipline']['name'] }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ $statement['group']['name'] }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ $statement['academic_year'] }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ $statement['semester'] }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">{{ $statement['type_certification']['name'] }}</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<a href="{{ route('teacher.statements.show', $statement['id']) }}" class="text-blue-600 hover:text-blue-900">Просмотр</a>
|
||||
</td>
|
||||
<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">Группа</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">Семестр</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">Статус</th>
|
||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"></th>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</thead>
|
||||
<tbody class="bg-white divide-y divide-gray-200">
|
||||
@foreach($statements as $statement)
|
||||
<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 font-medium text-gray-900">
|
||||
{{ $statement['discipline']['name'] }}
|
||||
</div>
|
||||
</td>
|
||||
<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['group']['name'] }}
|
||||
</div>
|
||||
</td>
|
||||
<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['academic_year'] }}</div>
|
||||
</td>
|
||||
<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['semester'] }}</div>
|
||||
</td>
|
||||
<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['type_certification']['name'] }}</div>
|
||||
</td>
|
||||
<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">
|
||||
@if($statement['is_finalized'])
|
||||
<span class="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs">
|
||||
Проведена
|
||||
</span>
|
||||
@else
|
||||
<span class="px-2 py-1 bg-yellow-100 text-yellow-800 rounded-full text-xs">
|
||||
Сохранена
|
||||
</span>
|
||||
@endif
|
||||
</div>
|
||||
</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>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@else
|
||||
<div class="p-6 text-center text-gray-500">
|
||||
Ведомости не найдены. Попробуйте изменить параметры поиска.
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@@ -10,17 +10,12 @@
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('teacher.statements.index') }}">
|
||||
@csrf
|
||||
@if(isset($student))
|
||||
@method('PATCH')
|
||||
@endif
|
||||
|
||||
<form method="GET" action="{{ route('teacher.statements.index') }}">
|
||||
<div class="row mb-3">
|
||||
<label for="surname" 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>
|
||||
<option>Выберите учебный год</option>
|
||||
@php
|
||||
$currentYear = date('Y');
|
||||
$nextYear = $currentYear + 1;
|
||||
@@ -73,9 +68,9 @@
|
||||
<div class="row mb-0">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Найти ведомость
|
||||
Найти ведомости
|
||||
</button>
|
||||
<a href="{{ route('students.index') }}" class="btn btn-secondary">Отмена</a>
|
||||
<a href="{{ route('teacher.statements.index') }}" class="btn btn-secondary">Отмена</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -42,6 +42,9 @@ Route::middleware(['jwt.auth'])->group(function () {
|
||||
Route::resource('statements', StatementController::class)->except(['show']);
|
||||
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/pdf', [StatementController::class, 'generatePdf'])->name('teacher.statements.generatePdf');
|
||||
Route::get('/statements/sendFinalizationCode', [StatementController::class, 'finalize'])->name('teacher.statements.sendFinalizationCode');
|
||||
/* Route::get('/statements/{id}/sendFinalizationCode', [StatementController::class, 'myStatements'])->name('teacher.statements.sendFinalizationCode');*/
|
||||
|
||||
// Statistics
|
||||
Route::get('/statistics', [StatisticController::class, 'index'])->name('statistics.index');
|
||||
|
||||
Reference in New Issue
Block a user