Работа со студентами готова
This commit is contained in:
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
class AuthController extends Controller
|
class AuthController extends Controller
|
||||||
{
|
{
|
||||||
@@ -63,9 +65,13 @@ class AuthController extends Controller
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
if ($response->successful()) {
|
if ($response->successful()) {
|
||||||
$token = $response->json()['token'];
|
$data = $response->json();
|
||||||
session(['api_token' => $token]);
|
Session::put([
|
||||||
session()->forget('user_id');
|
'api_token' => $data['token'],
|
||||||
|
'user_id' => $data['user']['id'] ?? null,
|
||||||
|
'user_name' => $data['user']['name'] ?? null,
|
||||||
|
'user_role' => $data['user']['roles_id'] ?? null,
|
||||||
|
]);
|
||||||
return redirect()->intended('/dashboard');
|
return redirect()->intended('/dashboard');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,12 +80,15 @@ class AuthController extends Controller
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
public function logout(Request $request)
|
public function logout(Request $request)
|
||||||
{
|
{
|
||||||
Http::withToken(session('api_token'))
|
$response = Http::withToken(Session::get('api_token'))
|
||||||
->post("{$this->apiBaseUrl}/employee/logout");
|
->post("{$this->apiBaseUrl}/employee/logout");
|
||||||
|
|
||||||
$request->session()->invalidate();
|
$request->session()->invalidate();
|
||||||
return redirect('/');
|
return redirect('/login');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,37 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
use App\Services\ApiService;
|
||||||
|
use Illuminate\Contracts\View\Factory;
|
||||||
|
use Illuminate\Contracts\View\View;
|
||||||
|
use Illuminate\Foundation\Application;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
|
|
||||||
class DashboardController extends Controller
|
class DashboardController extends Controller
|
||||||
{
|
{
|
||||||
public function index()
|
protected ApiService $api;
|
||||||
|
|
||||||
|
public function __construct(ApiService $api)
|
||||||
{
|
{
|
||||||
return view('dashboard');
|
$this->api = $api;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ApiService $api
|
||||||
|
* @return Factory|View|Application|\Illuminate\View\View|object
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function index(ApiService $api)
|
||||||
|
{
|
||||||
|
$response = $api->withAuth()->get('/employee/me');
|
||||||
|
$user = $response->json();
|
||||||
|
|
||||||
|
$statsResponse = $api->withAuth()->get('/employee/statistics');
|
||||||
|
$stats = $statsResponse->json();
|
||||||
|
|
||||||
|
return view('dashboard', [
|
||||||
|
'user' => $user,
|
||||||
|
'stats' => $stats
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
University.Web/app/Http/Controllers/StatisticController.php
Normal file
10
University.Web/app/Http/Controllers/StatisticController.php
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
|
class StatisticController extends Controller
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
@@ -2,9 +2,93 @@
|
|||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use App\Services\ApiService;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class StudentController extends Controller
|
class StudentController extends Controller
|
||||||
{
|
{
|
||||||
//
|
protected ApiService $api;
|
||||||
|
|
||||||
|
public function __construct(ApiService $api)
|
||||||
|
{
|
||||||
|
$this->api = $api;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$responseStudents = $this->api->get('/employee/students');
|
||||||
|
$responseGroups = $this->api->get('/employee/groups');
|
||||||
|
|
||||||
|
if ($responseStudents->successful() && $responseGroups->successful()) {
|
||||||
|
$students = $responseStudents->json();
|
||||||
|
$groups = $responseGroups->json();
|
||||||
|
$groupsList = collect($groups)->pluck('name', 'id')->toArray();
|
||||||
|
return view('students.index', compact('students', 'groupsList'));
|
||||||
|
}
|
||||||
|
|
||||||
|
abort($responseStudents->status());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create()
|
||||||
|
{
|
||||||
|
$groups = $this->api->get('/employee/groups')->json();
|
||||||
|
return view('students.form', ['groups' => $groups]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function store(Request $request)
|
||||||
|
{
|
||||||
|
$response = $this->api->post('/employee/students', $request->all());
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
return redirect()->route('students.index')
|
||||||
|
->with('success', 'Студент успешно создан');
|
||||||
|
}
|
||||||
|
|
||||||
|
return back()->withErrors($response->json()['errors'] ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit($id)
|
||||||
|
{
|
||||||
|
$response = $this->api->get("/employee/students/{$id}");
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
$student = $response->json();
|
||||||
|
$groups = $this->api->get('/employee/groups')->json();
|
||||||
|
return view('students.form', [
|
||||||
|
'student' => $student,
|
||||||
|
'groups' => $groups,
|
||||||
|
'isEdit' => true
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
abort($response->status());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$response = $this->api->patch("/employee/students/{$id}", $request->all());
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
return redirect()->route('students.index')
|
||||||
|
->with('success', 'Данные студента обновлены');
|
||||||
|
}
|
||||||
|
|
||||||
|
return back()->withErrors($response->json()['errors'] ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
$response = $this->api->delete("/employee/students/{$id}");
|
||||||
|
|
||||||
|
if ($response->successful()) {
|
||||||
|
return redirect()->route('students.index')
|
||||||
|
->with('success', 'Студент удален');
|
||||||
|
}
|
||||||
|
|
||||||
|
return back()->withErrors($response->json()['error'] ?? 'Ошибка при удалении');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
University.Web/app/Http/Middleware/CheckJWTToken.php
Normal file
31
University.Web/app/Http/Middleware/CheckJWTToken.php
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
|
class CheckJWTToken
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function handle($request, Closure $next)
|
||||||
|
{
|
||||||
|
if (!Session::has('api_token')) {
|
||||||
|
return redirect()->route('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = Http::withToken(Session::get('api_token'))
|
||||||
|
->get(env('API_BASE_URL') . '/employee/me');
|
||||||
|
|
||||||
|
if ($response->failed()) {
|
||||||
|
Session::forget('api_token');
|
||||||
|
return redirect()->route('login');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
66
University.Web/app/Services/ApiService.php
Normal file
66
University.Web/app/Services/ApiService.php
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use GuzzleHttp\Promise\PromiseInterface;
|
||||||
|
use Illuminate\Http\Client\ConnectionException;
|
||||||
|
use Illuminate\Http\Client\PendingRequest;
|
||||||
|
use Illuminate\Http\Client\Response;
|
||||||
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
|
class ApiService
|
||||||
|
{
|
||||||
|
protected string $baseUrl;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->baseUrl = env('API_BASE_URL', 'http://127.0.0.1:8000/api');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function withAuth(): PendingRequest
|
||||||
|
{
|
||||||
|
return Http::withToken(Session::get('api_token'))
|
||||||
|
->baseUrl($this->baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function get(string $url, array $params = []): PromiseInterface|Response
|
||||||
|
{
|
||||||
|
return $this->withAuth()->get($url, $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function post(string $url, array $data = []): PromiseInterface|Response
|
||||||
|
{
|
||||||
|
return $this->withAuth()->post($url, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function patch(string $url, array $data = []): PromiseInterface|Response
|
||||||
|
{
|
||||||
|
return $this->withAuth()->patch($url, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function put(string $url, array $data = []): PromiseInterface|Response
|
||||||
|
{
|
||||||
|
return $this->withAuth()->put($url, $data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ConnectionException
|
||||||
|
*/
|
||||||
|
public function delete(string $url, array $params = []): PromiseInterface|Response
|
||||||
|
{
|
||||||
|
return $this->withAuth()->delete($url, $params);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
use App\Http\Middleware\CheckJWTToken;
|
||||||
use Illuminate\Foundation\Application;
|
use Illuminate\Foundation\Application;
|
||||||
use Illuminate\Foundation\Configuration\Exceptions;
|
use Illuminate\Foundation\Configuration\Exceptions;
|
||||||
use Illuminate\Foundation\Configuration\Middleware;
|
use Illuminate\Foundation\Configuration\Middleware;
|
||||||
@@ -11,7 +12,9 @@ return Application::configure(basePath: dirname(__DIR__))
|
|||||||
health: '/up',
|
health: '/up',
|
||||||
)
|
)
|
||||||
->withMiddleware(function (Middleware $middleware) {
|
->withMiddleware(function (Middleware $middleware) {
|
||||||
//
|
$middleware->alias([
|
||||||
|
'jwt.auth' => CheckJWTToken::class,
|
||||||
|
]);
|
||||||
})
|
})
|
||||||
->withExceptions(function (Exceptions $exceptions) {
|
->withExceptions(function (Exceptions $exceptions) {
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -6,112 +6,283 @@
|
|||||||
<title>Панель управления</title>
|
<title>Панель управления</title>
|
||||||
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
@vite(['resources/css/app.css', 'resources/js/app.js'])
|
||||||
<style>
|
<style>
|
||||||
|
:root {
|
||||||
|
--primary-color: #3b82f6;
|
||||||
|
--secondary-color: #64748b;
|
||||||
|
--success-color: #10b981;
|
||||||
|
--warning-color: #f59e0b;
|
||||||
|
--danger-color: #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
background-color: #f8fafc;
|
||||||
|
}
|
||||||
|
|
||||||
.dashboard-container {
|
.dashboard-container {
|
||||||
max-width: 1200px;
|
max-width: 1400px;
|
||||||
margin: 2rem auto;
|
margin: 2rem auto;
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dashboard-header {
|
.dashboard-header {
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2.5rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.stats-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||||
|
gap: 1.5rem;
|
||||||
|
margin-bottom: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background: white;
|
||||||
|
border-radius: 0.75rem;
|
||||||
|
padding: 1.5rem;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||||
|
transition: transform 0.2s;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 4px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.students::before {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.groups::before {
|
||||||
|
background-color: var(--success-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.directions::before {
|
||||||
|
background-color: var(--warning-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.discipline::before {
|
||||||
|
background-color: var(--danger-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.statements::before {
|
||||||
|
background-color: var(--color-amber-700);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-title {
|
||||||
|
color: var(--secondary-color);
|
||||||
|
font-size: 0.875rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.05em;
|
||||||
|
}
|
||||||
|
|
||||||
.cards-grid {
|
.cards-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||||
gap: 1.5rem;
|
gap: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.75rem;
|
||||||
padding: 1.5rem;
|
padding: 1.75rem;
|
||||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05);
|
||||||
transition: transform 0.2s;
|
transition: all 0.3s ease;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card:hover {
|
.card:hover {
|
||||||
transform: translateY(-5px);
|
transform: translateY(-5px);
|
||||||
box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||||
|
border-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-icon {
|
.card-icon {
|
||||||
width: 64px;
|
width: 64px;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
margin: 0 auto 1rem;
|
margin: 0 auto 1.25rem;
|
||||||
color: #3b82f6;
|
color: var(--primary-color);
|
||||||
|
transition: transform 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card:hover .card-icon {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
|
||||||
.card-title {
|
.card-title {
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
color: #1e293b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-description {
|
.card-description {
|
||||||
color: #64748b;
|
color: var(--secondary-color);
|
||||||
|
font-size: 0.9375rem;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn {
|
||||||
|
display: block;
|
||||||
|
margin: 3rem auto 0;
|
||||||
|
padding: 0.75rem 1.5rem;
|
||||||
|
background-color: var(--danger-color);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logout-btn:hover {
|
||||||
|
background-color: #dc2626;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: 700;
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
color: #1e293b;
|
||||||
|
position: relative;
|
||||||
|
padding-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 4px;
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-50">
|
<body class="bg-gray-50">
|
||||||
<div class="dashboard-container">
|
<div class="dashboard-container">
|
||||||
<div class="dashboard-header">
|
<div class="dashboard-header">
|
||||||
<h1 class="text-3xl font-bold text-gray-800">Панель управления сотрудника</h1>
|
<h1 class="text-4xl font-bold text-gray-800 mb-2">Панель управления</h1>
|
||||||
<p class="text-gray-600">Выберите раздел для работы</p>
|
<p class="text-lg text-gray-600">Добро пожаловать, {{ $user['name'] }}!</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="cards-grid">
|
<div>
|
||||||
<!-- Студенты -->
|
<h2 class="section-title">Статистика</h2>
|
||||||
<a href="{{ route('students.index') }}" class="card">
|
<div class="stats-grid">
|
||||||
<div class="card-icon">
|
<div class="stat-card students">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
<div class="stat-value">{{ number_format($stats['students_count'] ?? 0, 0, ',', ' ') }}</div>
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
<div class="stat-title">Студентов</div>
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title">Студенты</h3>
|
|
||||||
<p class="card-description">Управление списком студентов</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Группы -->
|
<div class="stat-card groups">
|
||||||
<a href="{{ route('groups.index') }}" class="card">
|
<div class="stat-value">{{ number_format($stats['groups_count'] ?? 0, 0, ',', ' ') }}</div>
|
||||||
<div class="card-icon">
|
<div class="stat-title">Учебных группы</div>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title">Группы</h3>
|
|
||||||
<p class="card-description">Управление учебными группами</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Направления -->
|
<div class="stat-card directions">
|
||||||
<a href="{{ route('directions.index') }}" class="card">
|
<div class="stat-value">{{ number_format($stats['directions_count'] ?? 0, 0, ',', ' ') }}</div>
|
||||||
<div class="card-icon">
|
<div class="stat-title">Направлений</div>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title">Направления</h3>
|
|
||||||
<p class="card-description">Управление направлениями подготовки</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Дисциплины -->
|
<div class="stat-card discipline">
|
||||||
<a href="{{ route('disciplines.index') }}" class="card">
|
<div class="stat-value">{{ number_format($stats['disciplines_count'] ?? 0, 0, ',', ' ') }}</div>
|
||||||
<div class="card-icon">
|
<div class="stat-title">Дисциплин</div>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 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>
|
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title">Дисциплины</h3>
|
|
||||||
<p class="card-description">Управление учебными дисциплинами</p>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Ведомости -->
|
<div class="stat-card statements">
|
||||||
<a href="{{ route('statements.index') }}" class="card">
|
<div class="stat-value">{{ number_format($stats['statements_count'] ?? 0, 0, ',', ' ') }}</div>
|
||||||
<div class="card-icon">
|
<div class="stat-title">Ведомостей</div>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
||||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
<h3 class="card-title">Ведомости</h3>
|
</div>
|
||||||
<p class="card-description">Работа с ведомостями успеваемости</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<h2 class="section-title">Быстрый доступ</h2>
|
||||||
|
<div class="cards-grid">
|
||||||
|
<a href="{{ route('students.index') }}" class="card">
|
||||||
|
<div class="card-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197M13 7a4 4 0 11-8 0 4 4 0 018 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title">Студенты</h3>
|
||||||
|
<p class="card-description">Управление списком студентов</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('groups.index') }}" class="card">
|
||||||
|
<div class="card-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title">Группы</h3>
|
||||||
|
<p class="card-description">Управление учебными группами</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('directions.index') }}" class="card">
|
||||||
|
<div class="card-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title">Направления</h3>
|
||||||
|
<p class="card-description">Управление направлениями подготовки</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('disciplines.index') }}" class="card">
|
||||||
|
<div class="card-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 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>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title">Дисциплины</h3>
|
||||||
|
<p class="card-description">Управление учебными дисциплинами</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('statements.index') }}" class="card">
|
||||||
|
<div class="card-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title">Ведомости</h3>
|
||||||
|
<p class="card-description">Работа с ведомостями</p>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<a href="{{ route('statistics.index') }}" class="card">
|
||||||
|
<div class="card-icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<h3 class="card-title">Аналитика</h3>
|
||||||
|
<p class="card-description">Подробная статистика и аналитические отчеты</p>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form action="{{ route('logout') }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
<button type="submit" class="logout-btn">
|
||||||
|
Выйти из системы
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
39
University.Web/resources/views/layouts/app.blade.php
Normal file
39
University.Web/resources/views/layouts/app.blade.php
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<!-- CSRF Token -->
|
||||||
|
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||||
|
|
||||||
|
<title>@yield('title')</title>
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
|
<link rel="dns-prefetch" href="//fonts.bunny.net">
|
||||||
|
<link href="https://fonts.bunny.net/css?family=Nunito" rel="stylesheet">
|
||||||
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
@yield('links')
|
||||||
|
<!-- Scripts -->
|
||||||
|
@vite([ 'resources/js/app.js'])
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand" href="{{ url('/dashboard') }}">
|
||||||
|
Университет
|
||||||
|
</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<main class="py-4">
|
||||||
|
@yield('content')
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
187
University.Web/resources/views/students/form.blade.php
Normal file
187
University.Web/resources/views/students/form.blade.php
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
@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($student) ? 'Редактирование студента' : 'Добавление нового студента' }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="POST" action="{{ isset($student) ? route('students.update', $student['id']) : route('students.store') }}">
|
||||||
|
@csrf
|
||||||
|
@if(isset($student))
|
||||||
|
@method('PATCH')
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="surname" class="col-md-4 col-form-label text-md-end">Фамилия*</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="surname" type="text" class="form-control @error('surname') is-invalid @enderror" name="surname" value="{{ old('surname', $student['surname'] ?? '') }}" required autocomplete="surname" autofocus>
|
||||||
|
@error('surname')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="name" class="col-md-4 col-form-label text-md-end">Имя*</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name', $student['name'] ?? '') }}" required autocomplete="name">
|
||||||
|
@error('name')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="patronymic" class="col-md-4 col-form-label text-md-end">Отчество</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="patronymic" type="text" class="form-control @error('patronymic') is-invalid @enderror" name="patronymic" value="{{ old('patronymic', $student['patronymic'] ?? '') }}" autocomplete="patronymic">
|
||||||
|
@error('patronymic')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="email" class="col-md-4 col-form-label text-md-end">Email*</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email', $student['email'] ?? '') }}" required autocomplete="email">
|
||||||
|
@error('email')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="telephone" class="col-md-4 col-form-label text-md-end">Телефон*</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="telephone"
|
||||||
|
type="text"
|
||||||
|
class="form-control @error('telephone') is-invalid @enderror"
|
||||||
|
name="telephone"
|
||||||
|
value="{{ old('telephone', $student['telephone'] ?? '') }}"
|
||||||
|
required
|
||||||
|
pattern="^[0-9\+\-\(\)\s]+$"
|
||||||
|
inputmode="tel"
|
||||||
|
title="Введите только цифры, пробелы, +, -, ( )">
|
||||||
|
@error('telephone')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="password" class="col-md-4 col-form-label text-md-end">{{ isset($student) ? 'Новый пароль' : 'Пароль*' }}</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" {{ isset($student) ? '' : 'required' }} autocomplete="new-password">
|
||||||
|
@error('password')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="gender" class="col-md-4 col-form-label text-md-end">Пол*</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<select id="gender" class="form-control @error('gender') is-invalid @enderror" name="gender" required>
|
||||||
|
<option value="" disabled {{ old('gender', $student['gender'] ?? '') == '' ? 'selected' : '' }} hidden>Выберите пол</option>
|
||||||
|
<option value="М" {{ (old('gender', $student['gender'] ?? '') == 'М' ? 'selected' : '') }}>Мужской</option>
|
||||||
|
<option value="Ж" {{ (old('gender', $student['gender'] ?? '') == 'Ж' ? 'selected' : '') }}>Женский</option>
|
||||||
|
</select>
|
||||||
|
@error('gender')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="birth_date" class="col-md-4 col-form-label text-md-end">Дата рождения*</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="birth_date" type="date" class="form-control @error('birth_date') is-invalid @enderror" name="birth_date" value="{{ old('birth_date', $student['birth_date'] ?? '') }}" required>
|
||||||
|
@error('birth_date')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="citizenship" class="col-md-4 col-form-label text-md-end">Гражданство*</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="citizenship" type="text" class="form-control @error('citizenship') is-invalid @enderror" name="citizenship" value="{{ old('citizenship', $student['citizenship'] ?? '') }}" required>
|
||||||
|
@error('citizenship')
|
||||||
|
<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">
|
||||||
|
<option value="" disabled {{ empty($student['student_profile']['group_id']) ? 'selected' : '' }} hidden>Не выбрана</option>
|
||||||
|
@foreach($groups as $group)
|
||||||
|
<option value="{{ $group['id'] }}"
|
||||||
|
{{ (isset($student['student_profile']['group_id']) && $student['student_profile']['group_id'] == $group['id']) ? 'selected' : '' }}>
|
||||||
|
{{ $group['name'] }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
@error('group_id')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="row mb-3">
|
||||||
|
<label for="matriculation_number" class="col-md-4 col-form-label text-md-end">Номер зачетной книжки</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input id="matriculation_number" type="text" class="form-control @error('matriculation_number') is-invalid @enderror" name="matriculation_number" value="{{ $student['student_profile']['matriculation_number'] ?? old('matriculation_number') }}">
|
||||||
|
@error('matriculation_number')
|
||||||
|
<span class="invalid-feedback" role="alert">
|
||||||
|
<strong>{{ $message }}</strong>
|
||||||
|
</span>
|
||||||
|
@enderror
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-0">
|
||||||
|
<div class="col-md-6 offset-md-4">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
{{ isset($student) ? 'Обновить' : 'Создать' }}
|
||||||
|
</button>
|
||||||
|
<a href="{{ route('students.index') }}" class="btn btn-secondary">Отмена</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
87
University.Web/resources/views/students/index.blade.php
Normal file
87
University.Web/resources/views/students/index.blade.php
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
@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-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>
|
||||||
|
<a href="{{ route('students.create') }}" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded">
|
||||||
|
Добавить студента
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<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">Email</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>
|
||||||
|
</thead>
|
||||||
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
|
@foreach($students as $student)
|
||||||
|
<tr class="hover:bg-gray-50">
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('students.edit', $student['id']) }}'">
|
||||||
|
<div class="text-sm font-medium text-gray-900">
|
||||||
|
{{ $student['surname'] }} {{ $student['name'] }} {{ $student['patronymic'] ?? '' }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('students.edit', $student['id']) }}'">
|
||||||
|
<div class="text-sm text-gray-500">
|
||||||
|
{{ $groupsList[$student['student_profile']['group_id']] ?? 'Не указана' }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('students.edit', $student['id']) }}'">
|
||||||
|
<div class="text-sm text-gray-500">{{ $student['email'] }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('students.edit', $student['id']) }}'">
|
||||||
|
<div class="text-sm text-gray-500">{{ $student['telephone'] }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('students.edit', $student['id']) }}'">
|
||||||
|
<div class="text-sm text-gray-500">{{ $student['gender'] }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('students.edit', $student['id']) }}'">
|
||||||
|
<div class="text-sm text-gray-500">{{ \Carbon\Carbon::parse($student['birth_date'])->format('d.m.Y') }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('students.edit', $student['id']) }}'">
|
||||||
|
<div class="text-sm text-gray-500">{{ $student['citizenship'] }}</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap cursor-pointer" onclick="window.location='{{ route('students.edit', $student['id']) }}'">
|
||||||
|
<div class="text-sm text-gray-500">
|
||||||
|
{{ $student['student_profile']['matriculation_number'] ?? 'Не указан' }}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium flex justify-center items-center">
|
||||||
|
|
||||||
|
<form action="{{ route('students.destroy', $student['id']) }}" method="POST" class="inline">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="text-red-500 hover:text-red-700" onclick="return confirm('Вы уверены?')">
|
||||||
|
<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="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
@@ -6,6 +6,7 @@ use App\Http\Controllers\DirectionController;
|
|||||||
use App\Http\Controllers\DisciplineController;
|
use App\Http\Controllers\DisciplineController;
|
||||||
use App\Http\Controllers\GroupController;
|
use App\Http\Controllers\GroupController;
|
||||||
use App\Http\Controllers\StatementController;
|
use App\Http\Controllers\StatementController;
|
||||||
|
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;
|
||||||
|
|
||||||
@@ -21,12 +22,12 @@ Route::controller(AuthController::class)->group(function () {
|
|||||||
Route::post('/logout', 'logout')->name('logout');
|
Route::post('/logout', 'logout')->name('logout');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::middleware(['auth'])->group(function () {
|
Route::middleware(['jwt.auth'])->group(function () {
|
||||||
// Dashboard
|
// Dashboard
|
||||||
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
|
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
|
||||||
|
|
||||||
// Students
|
// Students
|
||||||
Route::get('/students', [StudentController::class, 'index'])->name('students.index');
|
Route::resource('students', StudentController::class)->except(['show']);
|
||||||
|
|
||||||
// Groups
|
// Groups
|
||||||
Route::get('/groups', [GroupController::class, 'index'])->name('groups.index');
|
Route::get('/groups', [GroupController::class, 'index'])->name('groups.index');
|
||||||
@@ -39,4 +40,7 @@ Route::middleware(['auth'])->group(function () {
|
|||||||
|
|
||||||
// Statements
|
// Statements
|
||||||
Route::get('/statements', [StatementController::class, 'index'])->name('statements.index');
|
Route::get('/statements', [StatementController::class, 'index'])->name('statements.index');
|
||||||
|
|
||||||
|
// Statistics
|
||||||
|
Route::get('/statistics', [StatisticController::class, 'index'])->name('statistics.index');
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user