prod #14
43
app/Console/Commands/AddAdmin.php
Normal file
43
app/Console/Commands/AddAdmin.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class AddAdmin extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'app:add-admin';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Create new admin';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$admin = Admin::create();
|
||||||
|
|
||||||
|
$user = User::create([
|
||||||
|
'email' => 'admin' . $admin->id . '@mail',
|
||||||
|
'password' => 'password',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$admin->user()->save($user);
|
||||||
|
|
||||||
|
$this->info('Admin created successfully!');
|
||||||
|
$this->info('email = ' . $user->email);
|
||||||
|
$this->info('password = password');
|
||||||
|
}
|
||||||
|
}
|
43
app/Console/Commands/AddScores.php
Normal file
43
app/Console/Commands/AddScores.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use App\Models\Grade;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
|
||||||
|
class AddScores extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'app:add-scores {grade}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Add 4 and 5 scores for students';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$grade = Grade::firstWhere('id', $this->argument('grade'));
|
||||||
|
|
||||||
|
$grade->students->random(7)->each(function ($student) {
|
||||||
|
$student
|
||||||
|
->lessons()
|
||||||
|
->syncWithPivotValues($student->lessons()->pluck('id'), ['score' => 4]);
|
||||||
|
});
|
||||||
|
|
||||||
|
$grade->students->random(5)->each(function ($student) {
|
||||||
|
$student
|
||||||
|
->lessons()
|
||||||
|
->syncWithPivotValues($student->lessons()->pluck('id'), ['score' => 5]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -5,11 +5,20 @@ namespace App\Enums;
|
|||||||
enum ScoreEnum: string
|
enum ScoreEnum: string
|
||||||
{
|
{
|
||||||
case WithoutScore = 'Без оценки';
|
case WithoutScore = 'Без оценки';
|
||||||
case One = '1';
|
|
||||||
case Two = '2';
|
case Two = '2';
|
||||||
case Three = '3';
|
case Three = '3';
|
||||||
case Four = '4';
|
case Four = '4';
|
||||||
case Five = '5';
|
case Five = '5';
|
||||||
case Absent = 'Н';
|
case Absent = 'Н';
|
||||||
case Sick = 'Б';
|
case Sick = 'Б';
|
||||||
|
|
||||||
|
public static function getNumScores(): array
|
||||||
|
{
|
||||||
|
return [self::Two, self::Three, self::Four, self::Five];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDebtScores(): array
|
||||||
|
{
|
||||||
|
return [self::Absent, self::Sick];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,4 +8,16 @@ enum TypeLesson: string
|
|||||||
case Classwork = "Работа в классе";
|
case Classwork = "Работа в классе";
|
||||||
case TestClass = "Самостоятельная работа";
|
case TestClass = "Самостоятельная работа";
|
||||||
case ExamClass = "Контрольная работа";
|
case ExamClass = "Контрольная работа";
|
||||||
|
|
||||||
|
public static function getShortType($type)
|
||||||
|
{
|
||||||
|
|
||||||
|
return match ($type) {
|
||||||
|
self::Homework->value => "д/р",
|
||||||
|
self::Classwork->value => "кл/р",
|
||||||
|
self::TestClass->value => "с/р",
|
||||||
|
self::ExamClass->value => "к/р",
|
||||||
|
default => "-",
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
73
app/Export/JournalExport.php
Normal file
73
app/Export/JournalExport.php
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Export;
|
||||||
|
|
||||||
|
use App\Enums\ScoreEnum;
|
||||||
|
use Maatwebsite\Excel\Concerns\FromCollection;
|
||||||
|
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||||
|
use Maatwebsite\Excel\Concerns\WithStyles;
|
||||||
|
use Maatwebsite\Excel\Concerns\WithTitle;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Style\Alignment;
|
||||||
|
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||||
|
|
||||||
|
class JournalExport implements FromCollection, ShouldAutoSize, WithTitle, WithStyles
|
||||||
|
{
|
||||||
|
protected $lessons;
|
||||||
|
protected $students;
|
||||||
|
|
||||||
|
public function __construct($lessons, $students)
|
||||||
|
{
|
||||||
|
$this->lessons = $lessons;
|
||||||
|
$this->students = $students;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return \Illuminate\Support\Collection
|
||||||
|
*/
|
||||||
|
public function collection()
|
||||||
|
{
|
||||||
|
$result = collect();
|
||||||
|
|
||||||
|
$headRow = collect();
|
||||||
|
$headRow->push('');
|
||||||
|
|
||||||
|
$this->lessons->each(function ($lesson) use ($headRow) {
|
||||||
|
$headRow->push($lesson->date);
|
||||||
|
});
|
||||||
|
$result->push($headRow);
|
||||||
|
|
||||||
|
$headRow = collect();
|
||||||
|
$headRow->push('ФИО');
|
||||||
|
|
||||||
|
$this->lessons->each(function ($lesson) use ($headRow) {
|
||||||
|
$headRow->push($lesson->shortType);
|
||||||
|
});
|
||||||
|
|
||||||
|
$result->push($headRow);
|
||||||
|
|
||||||
|
$this->students->each(function ($student) use ($result){
|
||||||
|
$row = collect();
|
||||||
|
$row->push($student->fio);
|
||||||
|
|
||||||
|
$this->lessons->each(function ($lesson) use ($row, $student) {
|
||||||
|
$row->push($student->lessons->find($lesson->id)->pivot->score ?? ScoreEnum::WithoutScore);
|
||||||
|
});
|
||||||
|
|
||||||
|
$result->push($row);
|
||||||
|
});
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function title(): string
|
||||||
|
{
|
||||||
|
return 'Журнал';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function styles(Worksheet $sheet)
|
||||||
|
{
|
||||||
|
$sheet->getStyle($sheet->calculateWorksheetDimension())
|
||||||
|
->getAlignment()
|
||||||
|
->setHorizontal(Alignment::HORIZONTAL_CENTER);
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,8 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Http\Requests\GradePostRequest;
|
use App\Http\Requests\GradePostRequest;
|
||||||
use App\Models\Grade;
|
use App\Models\Grade;
|
||||||
use App\Services\ServiceInterface;
|
use App\Services\FileService;
|
||||||
|
use App\Services\GradeService;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
@ -13,10 +14,14 @@ class GradeController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*/
|
*/
|
||||||
public function index(): View
|
public function index(GradeService $service): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('viewAny', Grade::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('grades.index', [
|
return view('grades.index', [
|
||||||
'grades' => Grade::filter()->paginate(5)->withQueryString(),
|
'grades' => $service->getGrades(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,6 +30,10 @@ class GradeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create(): View
|
public function create(): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', Grade::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('grades.create');
|
return view('grades.create');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +42,10 @@ class GradeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(GradePostRequest $request): RedirectResponse
|
public function store(GradePostRequest $request): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', Grade::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->route('grades.show', Grade::create($request->validated()));
|
return redirect()->route('grades.show', Grade::create($request->validated()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +54,10 @@ class GradeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show(Grade $grade): View
|
public function show(Grade $grade): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('view', $grade)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('grades.show', [
|
return view('grades.show', [
|
||||||
'grade' => $grade,
|
'grade' => $grade,
|
||||||
'subjects' => $grade->subjects,
|
'subjects' => $grade->subjects,
|
||||||
@ -52,6 +69,10 @@ class GradeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit(Grade $grade): View
|
public function edit(Grade $grade): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('update', $grade)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('grades.edit', [
|
return view('grades.edit', [
|
||||||
'grade' => $grade,
|
'grade' => $grade,
|
||||||
]);
|
]);
|
||||||
@ -62,7 +83,13 @@ class GradeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(GradePostRequest $request, Grade $grade): RedirectResponse
|
public function update(GradePostRequest $request, Grade $grade): RedirectResponse
|
||||||
{
|
{
|
||||||
return redirect()->route('grades.show', $grade->update($request->validated()));
|
if(request()->user()->cannot('update', $grade)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
$grade->update($request->validated());
|
||||||
|
|
||||||
|
return redirect()->route('grades.show', $grade);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,8 +97,17 @@ class GradeController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy(Grade $grade): RedirectResponse
|
public function destroy(Grade $grade): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('delete', $grade)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
$grade->delete();
|
$grade->delete();
|
||||||
|
|
||||||
return redirect()->route('grades.index');
|
return redirect()->route('grades.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function listStudents(Grade $grade, FileService $fileService)
|
||||||
|
{
|
||||||
|
return $fileService->exportStudents($grade);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ namespace App\Http\Controllers;
|
|||||||
use App\Http\Requests\GradeSubjectPostRequest;
|
use App\Http\Requests\GradeSubjectPostRequest;
|
||||||
use App\Models\Grade;
|
use App\Models\Grade;
|
||||||
use App\Models\Subject;
|
use App\Models\Subject;
|
||||||
use App\Services\ServiceInterface;
|
use App\Services\FileService;
|
||||||
|
use App\Services\JournalService;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
@ -26,27 +27,25 @@ class GradeSubjectController extends Controller
|
|||||||
return redirect()->route('grades.show', $grade);
|
return redirect()->route('grades.show', $grade);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function edit(Grade $grade, Subject $subject): View
|
|
||||||
{
|
|
||||||
return view('grade-subject.edit', [
|
|
||||||
'grade' => $grade,
|
|
||||||
'updateSubject' => $subject,
|
|
||||||
'subjects' => Subject::all(),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update(GradeSubjectPostRequest $request, Grade $grade, Subject $subject): RedirectResponse
|
|
||||||
{
|
|
||||||
$grade->subjects()->detach($subject);
|
|
||||||
$grade->subjects()->attach($request->subject_id);
|
|
||||||
|
|
||||||
return redirect()->route('grades.show', $grade);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function destroy(Grade $grade, Subject $subject): RedirectResponse
|
public function destroy(Grade $grade, Subject $subject): RedirectResponse
|
||||||
{
|
{
|
||||||
$grade->subjects()->detach($subject);
|
$grade->subjects()->detach($subject);
|
||||||
|
|
||||||
return redirect()->route('grades.show', $grade);
|
return redirect()->route('grades.show', $grade);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function journal(Grade $grade, Subject $subject, JournalService $service): View
|
||||||
|
{
|
||||||
|
return view('grade-subject.journal', [
|
||||||
|
'lessons' => $grade->lessons()->where('subject_id', $subject->id)->with('students')->get(),
|
||||||
|
'students' => $grade->students()->orderBy('last_name')->get(),
|
||||||
|
'grade' => $grade,
|
||||||
|
'subject' => $subject,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportToExcel(Grade $grade, Subject $subject, FileService $service)
|
||||||
|
{
|
||||||
|
return $service->exportJournal($grade, $subject);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use App\Http\Requests\GradeTeacherPostRequest;
|
|||||||
use App\Models\Grade;
|
use App\Models\Grade;
|
||||||
use App\Models\Subject;
|
use App\Models\Subject;
|
||||||
use App\Models\Teacher;
|
use App\Models\Teacher;
|
||||||
use App\Services\ServiceInterface;
|
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ use App\Enums\TypeLesson;
|
|||||||
use App\Http\Requests\LessonPostRequest;
|
use App\Http\Requests\LessonPostRequest;
|
||||||
use App\Models\Grade;
|
use App\Models\Grade;
|
||||||
use App\Models\Lesson;
|
use App\Models\Lesson;
|
||||||
use App\Services\ServiceInterface;
|
use App\Services\LessonService;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
@ -23,10 +23,14 @@ class LessonController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*/
|
*/
|
||||||
public function index(Grade $grade): View
|
public function index(Grade $grade, LessonService $service): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('viewAny', $grade)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('grade-lesson.index', [
|
return view('grade-lesson.index', [
|
||||||
'lessons' => $grade->lessons()->filter()->get(),
|
'lessons' => $service->getLessons($grade),
|
||||||
'grade' => $grade,
|
'grade' => $grade,
|
||||||
'subjects' => $grade->subjects,
|
'subjects' => $grade->subjects,
|
||||||
]);
|
]);
|
||||||
@ -37,6 +41,10 @@ class LessonController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create(Grade $grade): View
|
public function create(Grade $grade): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', Lesson::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('grade-lesson.create', [
|
return view('grade-lesson.create', [
|
||||||
'types' => TypeLesson::cases(),
|
'types' => TypeLesson::cases(),
|
||||||
'grade' => $grade,
|
'grade' => $grade,
|
||||||
@ -48,6 +56,10 @@ class LessonController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(LessonPostRequest $request, Grade $grade): RedirectResponse
|
public function store(LessonPostRequest $request, Grade $grade): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', [Lesson::class, $grade])) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
$lesson = Lesson::create($request->validated());
|
$lesson = Lesson::create($request->validated());
|
||||||
$lesson
|
$lesson
|
||||||
->students()
|
->students()
|
||||||
@ -66,6 +78,10 @@ class LessonController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show(Grade $grade, Lesson $lesson): View
|
public function show(Grade $grade, Lesson $lesson): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('view', $lesson)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('grade-lesson.show', [
|
return view('grade-lesson.show', [
|
||||||
'lesson' => $lesson,
|
'lesson' => $lesson,
|
||||||
'grade' => $grade,
|
'grade' => $grade,
|
||||||
@ -77,6 +93,10 @@ class LessonController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit(Grade $grade, Lesson $lesson): View
|
public function edit(Grade $grade, Lesson $lesson): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('update', $lesson)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('grade-lesson.edit', [
|
return view('grade-lesson.edit', [
|
||||||
'lesson' => $lesson,
|
'lesson' => $lesson,
|
||||||
'grade' => $grade,
|
'grade' => $grade,
|
||||||
@ -89,12 +109,13 @@ class LessonController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(LessonPostRequest $request, Grade $grade, Lesson $lesson): RedirectResponse
|
public function update(LessonPostRequest $request, Grade $grade, Lesson $lesson): RedirectResponse
|
||||||
{
|
{
|
||||||
return redirect()->route(
|
if(request()->user()->cannot('update', $lesson)) {
|
||||||
'grades.lessons.show',[
|
abort(403);
|
||||||
$grade,
|
}
|
||||||
$lesson->update($request->validated()),
|
|
||||||
]
|
$lesson->update($request->validated());
|
||||||
);
|
|
||||||
|
return redirect()->route('grades.lessons.show',[$grade, $lesson,]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,6 +123,10 @@ class LessonController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy(Grade $grade, Lesson $lesson): RedirectResponse
|
public function destroy(Grade $grade, Lesson $lesson): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('update', $lesson)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
$lesson->delete();
|
$lesson->delete();
|
||||||
|
|
||||||
return redirect()->route('grades.lessons.index', $grade);
|
return redirect()->route('grades.lessons.index', $grade);
|
||||||
|
@ -5,7 +5,6 @@ namespace App\Http\Controllers;
|
|||||||
use App\Enums\ScoreEnum;
|
use App\Enums\ScoreEnum;
|
||||||
use App\Models\Lesson;
|
use App\Models\Lesson;
|
||||||
use App\Services\ScoreService;
|
use App\Services\ScoreService;
|
||||||
use App\Services\ServiceInterface;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
|
||||||
class ScoreController extends Controller
|
class ScoreController extends Controller
|
||||||
@ -19,7 +18,7 @@ class ScoreController extends Controller
|
|||||||
public function show(Lesson $lesson)
|
public function show(Lesson $lesson)
|
||||||
{
|
{
|
||||||
return view('scores.show', [
|
return view('scores.show', [
|
||||||
'students' => $lesson->students,
|
'students' => $lesson->students()->orderBy('last_name')->get(),
|
||||||
'lesson' => $lesson,
|
'lesson' => $lesson,
|
||||||
'scores' => ScoreEnum::cases(),
|
'scores' => ScoreEnum::cases(),
|
||||||
]);
|
]);
|
||||||
|
@ -5,7 +5,8 @@ namespace App\Http\Controllers;
|
|||||||
use App\Http\Requests\StudentPostRequest;
|
use App\Http\Requests\StudentPostRequest;
|
||||||
use App\Models\Grade;
|
use App\Models\Grade;
|
||||||
use App\Models\Student;
|
use App\Models\Student;
|
||||||
use App\Services\ServiceInterface;
|
use App\Models\Subject;
|
||||||
|
use App\Services\FileService;
|
||||||
use App\Services\StudentService;
|
use App\Services\StudentService;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
@ -22,6 +23,10 @@ class StudentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function index(): View
|
public function index(): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('viewAny', Student::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('students.index', [
|
return view('students.index', [
|
||||||
'students' => Student::filter()->paginate(5)->withQueryString(),
|
'students' => Student::filter()->paginate(5)->withQueryString(),
|
||||||
]);
|
]);
|
||||||
@ -32,6 +37,10 @@ class StudentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create(): View
|
public function create(): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', Student::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('students.create', [
|
return view('students.create', [
|
||||||
'grades' => Grade::all(),
|
'grades' => Grade::all(),
|
||||||
]);
|
]);
|
||||||
@ -42,6 +51,10 @@ class StudentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(StudentPostRequest $request): RedirectResponse
|
public function store(StudentPostRequest $request): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', Student::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->route(
|
return redirect()->route(
|
||||||
'students.show',
|
'students.show',
|
||||||
$this->service->create($request->validated())
|
$this->service->create($request->validated())
|
||||||
@ -53,6 +66,10 @@ class StudentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show(Student $student): View
|
public function show(Student $student): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('view', $student)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('students.show', [
|
return view('students.show', [
|
||||||
'student' => $student,
|
'student' => $student,
|
||||||
'grades' => Grade::all(),
|
'grades' => Grade::all(),
|
||||||
@ -64,6 +81,10 @@ class StudentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit(Student $student): View
|
public function edit(Student $student): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('update', $student)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('students.edit', [
|
return view('students.edit', [
|
||||||
'student' => $student,
|
'student' => $student,
|
||||||
'grades' => Grade::all(),
|
'grades' => Grade::all(),
|
||||||
@ -75,6 +96,10 @@ class StudentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(StudentPostRequest $request, Student $student): RedirectResponse
|
public function update(StudentPostRequest $request, Student $student): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('update', $student)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->route(
|
return redirect()->route(
|
||||||
'students.show',
|
'students.show',
|
||||||
$this->service->update($student, $request->validated())
|
$this->service->update($student, $request->validated())
|
||||||
@ -86,9 +111,33 @@ class StudentController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy(Student $student): RedirectResponse
|
public function destroy(Student $student): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('delete', $student)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
$student->user()->delete();
|
$student->user()->delete();
|
||||||
$student->delete();
|
$student->delete();
|
||||||
|
|
||||||
return redirect()->route('students.index');
|
return redirect()->route('students.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function scores(StudentService $service, Subject $subject): View
|
||||||
|
{
|
||||||
|
return view('students.scores', [
|
||||||
|
'lessons' => $service->getScores($subject),
|
||||||
|
'avgScore' => $service->getAvgScore($subject),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function debts(StudentService $service): View
|
||||||
|
{
|
||||||
|
return view('students.debts', [
|
||||||
|
'lessons' => $service->getDebts(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportAvgScores(StudentService $service)
|
||||||
|
{
|
||||||
|
return $service->exportAvgScores();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Http\Requests\SubjectPostRequest;
|
use App\Http\Requests\SubjectPostRequest;
|
||||||
use App\Models\Subject;
|
use App\Models\Subject;
|
||||||
use App\Services\ServiceInterface;
|
|
||||||
|
use App\Services\SubjectService;
|
||||||
|
use App\Services\FileService;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
@ -13,10 +15,10 @@ class SubjectController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*/
|
*/
|
||||||
public function index(): View
|
public function index(SubjectService $service): View
|
||||||
{
|
{
|
||||||
return view('subjects.index', [
|
return view('subjects.index', [
|
||||||
'subjects' => Subject::filter()->paginate(5)->withQueryString(),
|
'subjects' => $service->getSubjects(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,6 +27,10 @@ class SubjectController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create(): View
|
public function create(): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', Subject::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('subjects.create');
|
return view('subjects.create');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,6 +39,10 @@ class SubjectController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(SubjectPostRequest $request): RedirectResponse
|
public function store(SubjectPostRequest $request): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', Subject::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->route(
|
return redirect()->route(
|
||||||
'subjects.show',
|
'subjects.show',
|
||||||
Subject::create($request->validated()),
|
Subject::create($request->validated()),
|
||||||
@ -54,6 +64,10 @@ class SubjectController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit(Subject $subject): View
|
public function edit(Subject $subject): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('update', $subject)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('subjects.edit', [
|
return view('subjects.edit', [
|
||||||
'subject' => $subject,
|
'subject' => $subject,
|
||||||
]);
|
]);
|
||||||
@ -64,10 +78,13 @@ class SubjectController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(SubjectPostRequest $request, Subject $subject): RedirectResponse
|
public function update(SubjectPostRequest $request, Subject $subject): RedirectResponse
|
||||||
{
|
{
|
||||||
return redirect()->route(
|
if(request()->user()->cannot('update', $subject)) {
|
||||||
'subjects.show',
|
abort(403);
|
||||||
$subject->update($request->validated())
|
}
|
||||||
);
|
|
||||||
|
$subject->update($request->validated());
|
||||||
|
|
||||||
|
return redirect()->route('subjects.show', $subject);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,8 +92,17 @@ class SubjectController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy(Subject $subject): RedirectResponse
|
public function destroy(Subject $subject): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('delete', $subject)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
$subject->delete();
|
$subject->delete();
|
||||||
|
|
||||||
return redirect()->route('subjects.index');
|
return redirect()->route('subjects.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function exportToPDF(FileService $fileService)
|
||||||
|
{
|
||||||
|
return $fileService->exportSubjects();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,19 @@ namespace App\Http\Controllers;
|
|||||||
use App\Http\Requests\SubjectTeacherPostRequest;
|
use App\Http\Requests\SubjectTeacherPostRequest;
|
||||||
use App\Models\Subject;
|
use App\Models\Subject;
|
||||||
use App\Models\Teacher;
|
use App\Models\Teacher;
|
||||||
use App\Services\ServiceInterface;
|
use App\Services\TeacherService;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
|
|
||||||
class SubjectTeacherController extends Controller
|
class SubjectTeacherController extends Controller
|
||||||
{
|
{
|
||||||
|
public function index(Teacher $teacher, TeacherService $service)
|
||||||
|
{
|
||||||
|
return view('subject-teacher.index', [
|
||||||
|
'subjects' => $service->getSubjects($teacher),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function create(Teacher $teacher): View
|
public function create(Teacher $teacher): View
|
||||||
{
|
{
|
||||||
return view('subject-teacher.create', [
|
return view('subject-teacher.create', [
|
||||||
|
@ -4,7 +4,6 @@ namespace App\Http\Controllers;
|
|||||||
|
|
||||||
use App\Http\Requests\TeacherPostRequest;
|
use App\Http\Requests\TeacherPostRequest;
|
||||||
use App\Models\Teacher;
|
use App\Models\Teacher;
|
||||||
use App\Services\ServiceInterface;
|
|
||||||
use App\Services\TeacherService;
|
use App\Services\TeacherService;
|
||||||
use Illuminate\Http\RedirectResponse;
|
use Illuminate\Http\RedirectResponse;
|
||||||
use Illuminate\View\View;
|
use Illuminate\View\View;
|
||||||
@ -19,10 +18,14 @@ class TeacherController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Display a listing of the resource.
|
* Display a listing of the resource.
|
||||||
*/
|
*/
|
||||||
public function index(): View
|
public function index(TeacherService $service): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('viewAny', Teacher::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('teachers.index', [
|
return view('teachers.index', [
|
||||||
'teachers' => Teacher::filter()->paginate(5)->withQueryString(),
|
'teachers' => $service->getTeachers(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,6 +34,10 @@ class TeacherController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function create(): View
|
public function create(): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', Teacher::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('teachers.create');
|
return view('teachers.create');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +46,10 @@ class TeacherController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function store(TeacherPostRequest $request): RedirectResponse
|
public function store(TeacherPostRequest $request): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('create', Teacher::class)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->route(
|
return redirect()->route(
|
||||||
'teachers.show',
|
'teachers.show',
|
||||||
$this->service->create($request->validated())
|
$this->service->create($request->validated())
|
||||||
@ -50,6 +61,10 @@ class TeacherController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function show(Teacher $teacher): View
|
public function show(Teacher $teacher): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('view', $teacher)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('teachers.show', [
|
return view('teachers.show', [
|
||||||
'teacher' => $teacher,
|
'teacher' => $teacher,
|
||||||
'subjects' => $teacher->subjects,
|
'subjects' => $teacher->subjects,
|
||||||
@ -61,6 +76,10 @@ class TeacherController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function edit(Teacher $teacher): View
|
public function edit(Teacher $teacher): View
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('update', $teacher)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return view('teachers.edit', [
|
return view('teachers.edit', [
|
||||||
'teacher' => $teacher,
|
'teacher' => $teacher,
|
||||||
]);
|
]);
|
||||||
@ -71,6 +90,10 @@ class TeacherController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function update(TeacherPostRequest $request, Teacher $teacher): RedirectResponse
|
public function update(TeacherPostRequest $request, Teacher $teacher): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('update', $teacher)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->route(
|
return redirect()->route(
|
||||||
'teachers.show',
|
'teachers.show',
|
||||||
$this->service->update($teacher, $request->validated())
|
$this->service->update($teacher, $request->validated())
|
||||||
@ -82,6 +105,10 @@ class TeacherController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function destroy(Teacher $teacher): RedirectResponse
|
public function destroy(Teacher $teacher): RedirectResponse
|
||||||
{
|
{
|
||||||
|
if(request()->user()->cannot('update', $teacher)) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
$teacher->user()->delete();
|
$teacher->user()->delete();
|
||||||
$teacher->delete();
|
$teacher->delete();
|
||||||
|
|
||||||
|
26
app/Http/Middleware/AdminAction.php
Normal file
26
app/Http/Middleware/AdminAction.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class AdminAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if (Auth::user()->userable_type != Admin::class) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
26
app/Http/Middleware/StudentAction.php
Normal file
26
app/Http/Middleware/StudentAction.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Models\Student;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class StudentAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if (Auth::user()->userable_type != Student::class) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
26
app/Http/Middleware/TeacherAction.php
Normal file
26
app/Http/Middleware/TeacherAction.php
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Middleware;
|
||||||
|
|
||||||
|
use App\Models\Teacher;
|
||||||
|
use Closure;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class TeacherAction
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle an incoming request.
|
||||||
|
*
|
||||||
|
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
|
||||||
|
*/
|
||||||
|
public function handle(Request $request, Closure $next): Response
|
||||||
|
{
|
||||||
|
if (Auth::user()->userable_type != Teacher::class) {
|
||||||
|
abort(403);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $next($request);
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class StudentPostRequest extends FormRequest
|
class StudentPostRequest extends FormRequest
|
||||||
{
|
{
|
||||||
@ -27,7 +29,7 @@ class StudentPostRequest extends FormRequest
|
|||||||
'middle_name' => 'required|max:255',
|
'middle_name' => 'required|max:255',
|
||||||
'birthday' => 'required|date',
|
'birthday' => 'required|date',
|
||||||
'grade_id' => 'required|exists:grades,id',
|
'grade_id' => 'required|exists:grades,id',
|
||||||
'email' => 'required|max:255|lowercase|unique:users,email',
|
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', Rule::unique(User::class)->ignore($this->route('student')?->user->id), 'regex:/^(([^<>()\[\]\\.,;:\s@”]+(\.[^<>()\[\]\\.,;:\s@”]+)*)|(“.+”))@((\[[0–9]{1,3}\.[0–9]{1,3}\.[0–9]{1,3}\.[0–9]{1,3}])|(([a-zA-Z\-0–9]+\.)+[a-zA-Z]{2,}))$/'],
|
||||||
'password' => 'required|max:255',
|
'password' => 'required|max:255',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
namespace App\Http\Requests;
|
namespace App\Http\Requests;
|
||||||
|
|
||||||
|
use App\Models\User;
|
||||||
use Illuminate\Foundation\Http\FormRequest;
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
use Illuminate\Validation\Rule;
|
||||||
|
|
||||||
class TeacherPostRequest extends FormRequest
|
class TeacherPostRequest extends FormRequest
|
||||||
{
|
{
|
||||||
@ -26,7 +28,7 @@ class TeacherPostRequest extends FormRequest
|
|||||||
'last_name' => 'required|max:255',
|
'last_name' => 'required|max:255',
|
||||||
'middle_name' => 'required|max:255',
|
'middle_name' => 'required|max:255',
|
||||||
'birthday' => 'required|date',
|
'birthday' => 'required|date',
|
||||||
'email' => 'required|max:255|lowercase|unique:users,email',
|
'email' => ['required', 'string', 'lowercase', 'email', 'max:255', Rule::unique(User::class)->ignore($this->route('teacher')?->user->id), 'regex:/^(([^<>()\[\]\\.,;:\s@”]+(\.[^<>()\[\]\\.,;:\s@”]+)*)|(“.+”))@((\[[0–9]{1,3}\.[0–9]{1,3}\.[0–9]{1,3}\.[0–9]{1,3}])|(([a-zA-Z\-0–9]+\.)+[a-zA-Z]{2,}))$/'],
|
||||||
'password' => 'required|max:255',
|
'password' => 'required|max:255',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
52
app/Mail/UserCreated.php
Normal file
52
app/Mail/UserCreated.php
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Mail;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
|
use Illuminate\Mail\Mailable;
|
||||||
|
use Illuminate\Mail\Mailables\Content;
|
||||||
|
use Illuminate\Mail\Mailables\Envelope;
|
||||||
|
use Illuminate\Queue\SerializesModels;
|
||||||
|
|
||||||
|
class UserCreated extends Mailable
|
||||||
|
{
|
||||||
|
use Queueable, SerializesModels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new message instance.
|
||||||
|
*/
|
||||||
|
public function __construct(public string $password)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message envelope.
|
||||||
|
*/
|
||||||
|
public function envelope(): Envelope
|
||||||
|
{
|
||||||
|
return new Envelope(
|
||||||
|
subject: 'Создана учетная запись',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the message content definition.
|
||||||
|
*/
|
||||||
|
public function content(): Content
|
||||||
|
{
|
||||||
|
return new Content(
|
||||||
|
view: 'mails.user_created',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the attachments for the message.
|
||||||
|
*
|
||||||
|
* @return array<int, \Illuminate\Mail\Mailables\Attachment>
|
||||||
|
*/
|
||||||
|
public function attachments(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\TypeLesson;
|
||||||
use Illuminate\Contracts\Database\Eloquent\Builder;
|
use Illuminate\Contracts\Database\Eloquent\Builder;
|
||||||
|
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Support\Carbon;
|
||||||
|
|
||||||
class Lesson extends Model
|
class Lesson extends Model
|
||||||
{
|
{
|
||||||
@ -51,4 +53,18 @@ class Lesson extends Model
|
|||||||
$query->where('subject_id', $subject_id);
|
$query->where('subject_id', $subject_id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function shortType(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => TypeLesson::getShortType($this->type),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function date(): Attribute
|
||||||
|
{
|
||||||
|
return Attribute::make(
|
||||||
|
get: fn () => Carbon::parse($this->lesson_date)->format('d-m-Y')
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ class Student extends Model
|
|||||||
|
|
||||||
public function lessons(): BelongsToMany
|
public function lessons(): BelongsToMany
|
||||||
{
|
{
|
||||||
return $this->belongsToMany(Lesson::class);
|
return $this->belongsToMany(Lesson::class)->withPivot('score');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scopeFilter(Builder $query): void
|
public function scopeFilter(Builder $query): void
|
||||||
|
@ -3,11 +3,15 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
// use Illuminate\Contracts\Auth\MustVerifyEmail;
|
||||||
|
|
||||||
|
use App\Observers\UserObserver;
|
||||||
|
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
|
|
||||||
|
#[ObservedBy(UserObserver::class)]
|
||||||
class User extends Authenticatable
|
class User extends Authenticatable
|
||||||
{
|
{
|
||||||
use HasFactory, Notifiable;
|
use HasFactory, Notifiable;
|
||||||
|
18
app/Observers/UserObserver.php
Normal file
18
app/Observers/UserObserver.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Observers;
|
||||||
|
|
||||||
|
use App\Mail\UserCreated;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
|
||||||
|
class UserObserver
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Handle the User "created" event.
|
||||||
|
*/
|
||||||
|
public function created(User $user): void
|
||||||
|
{
|
||||||
|
Mail::to($user)->send(new UserCreated(request()->all()['password']));
|
||||||
|
}
|
||||||
|
}
|
62
app/Policies/GradePolicy.php
Normal file
62
app/Policies/GradePolicy.php
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Models\Grade;
|
||||||
|
use App\Models\Student;
|
||||||
|
use App\Models\Teacher;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class GradePolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view any models.
|
||||||
|
*/
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type != Student::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*/
|
||||||
|
public function view(User $user, Grade $grade): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type != Student::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can create models.
|
||||||
|
*/
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can update the model.
|
||||||
|
*/
|
||||||
|
public function update(User $user, Grade $grade): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, Grade $grade): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function journal(User $user)
|
||||||
|
{
|
||||||
|
return $user->userable_type == Teacher::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function list(User $user)
|
||||||
|
{
|
||||||
|
return $user->userable_type == Teacher::class;
|
||||||
|
}
|
||||||
|
}
|
53
app/Policies/LessonPolicy.php
Normal file
53
app/Policies/LessonPolicy.php
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Models\Grade;
|
||||||
|
use App\Models\Lesson;
|
||||||
|
use App\Models\Student;
|
||||||
|
use App\Models\Teacher;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class LessonPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view any models.
|
||||||
|
*/
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Teacher::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*/
|
||||||
|
public function view(User $user, Lesson $lesson): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Teacher::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can create models.
|
||||||
|
*/
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Teacher::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can update the model.
|
||||||
|
*/
|
||||||
|
public function update(User $user, Lesson $lesson): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Teacher::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, Lesson $lesson): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Teacher::class;
|
||||||
|
}
|
||||||
|
}
|
60
app/Policies/StudentPolicy.php
Normal file
60
app/Policies/StudentPolicy.php
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Models\Student;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class StudentPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view any models.
|
||||||
|
*/
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type != Student::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*/
|
||||||
|
public function view(User $user, Student $student): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can create models.
|
||||||
|
*/
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can update the model.
|
||||||
|
*/
|
||||||
|
public function update(User $user, Student $student): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, Student $student): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function debts(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Student::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function avgScores(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Student::class;
|
||||||
|
}
|
||||||
|
}
|
50
app/Policies/SubjectPolicy.php
Normal file
50
app/Policies/SubjectPolicy.php
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Models\Student;
|
||||||
|
use App\Models\Subject;
|
||||||
|
use App\Models\Teacher;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class SubjectPolicy
|
||||||
|
{
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type != Teacher::class;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Determine whether the user can create models.
|
||||||
|
*/
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can update the model.
|
||||||
|
*/
|
||||||
|
public function update(User $user, Subject $subject): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, Subject $subject): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scores(User $user, Subject $subject): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Student::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function pdf(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Student::class;
|
||||||
|
}
|
||||||
|
}
|
56
app/Policies/TeacherPolicy.php
Normal file
56
app/Policies/TeacherPolicy.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Admin;
|
||||||
|
use App\Models\Student;
|
||||||
|
use App\Models\Teacher;
|
||||||
|
use App\Models\User;
|
||||||
|
|
||||||
|
class TeacherPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view any models.
|
||||||
|
*/
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type != Teacher::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*/
|
||||||
|
public function view(User $user, Teacher $teacher): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can create models.
|
||||||
|
*/
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can update the model.
|
||||||
|
*/
|
||||||
|
public function update(User $user, Teacher $teacher): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, Teacher $teacher): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Admin::class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function teacherSubjects(User $user, Teacher $teacher): bool
|
||||||
|
{
|
||||||
|
return $user->userable_type == Student::class;
|
||||||
|
}
|
||||||
|
}
|
58
app/Services/FileService.php
Normal file
58
app/Services/FileService.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Export\JournalExport;
|
||||||
|
use App\Models\Grade;
|
||||||
|
use App\Models\Subject;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
use Maatwebsite\Excel\Facades\Excel;
|
||||||
|
|
||||||
|
class FileService
|
||||||
|
{
|
||||||
|
public function exportSubjects()
|
||||||
|
{
|
||||||
|
$listSubjects = collect();
|
||||||
|
$student = Auth::user()->userable;
|
||||||
|
$subjects = $student->grade->subjects;
|
||||||
|
$teachers = $student->grade->teachers;
|
||||||
|
|
||||||
|
$teachers->each(function ($teacher) use ($subjects, $listSubjects) {
|
||||||
|
$teacher->subjects->each(function ($subject) use ($subjects, $listSubjects, $teacher) {
|
||||||
|
if ($subjects->contains($subject)) {
|
||||||
|
$listSubjects->push(['subject' => $subject->name, 'teacher' => $teacher->fio]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return Pdf::loadView('subjects.pdf', ['subjects' => $listSubjects])->download('Предметы.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportStudents(Grade $grade)
|
||||||
|
{
|
||||||
|
$excellentStudents = $this->getMinScore($grade, 5);
|
||||||
|
$goodStudents = $this->getMinScore($grade, 4);
|
||||||
|
|
||||||
|
return Pdf::loadView('grades.list-students', [
|
||||||
|
'excellentStudents' => $excellentStudents,
|
||||||
|
'goodStudents' => $goodStudents,
|
||||||
|
])->download('Студенты.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getMinScore(Grade $grade, $minScore)
|
||||||
|
{
|
||||||
|
return $grade->students->filter(function ($student) use ($minScore) {
|
||||||
|
return $student->lessons->min('pivot.score') == $minScore;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportJournal(Grade $grade, Subject $subject)
|
||||||
|
{
|
||||||
|
$lessons = $grade->lessons()->where('subject_id', $subject->id)->with('students')->get();
|
||||||
|
$students = $grade->students()->orderBy('last_name')->get();
|
||||||
|
$fileName = $subject->name . '(' . $grade->name . ').xlsx';
|
||||||
|
|
||||||
|
return Excel::download(new JournalExport($lessons, $students), $fileName);
|
||||||
|
}
|
||||||
|
}
|
23
app/Services/GradeService.php
Normal file
23
app/Services/GradeService.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Grade;
|
||||||
|
use App\Models\Teacher;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class GradeService
|
||||||
|
{
|
||||||
|
public function getGrades()
|
||||||
|
{
|
||||||
|
if (Auth::user()->userable_type == Teacher::class) {
|
||||||
|
return Grade::join('grade_teacher', 'grade_teacher.grade_id', '=', 'grades.id')
|
||||||
|
->where('grade_teacher.teacher_id', Auth::user()->userable_id)
|
||||||
|
->filter()
|
||||||
|
->paginate(5)
|
||||||
|
->withQueryString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Grade::filter()->paginate(5)->withQueryString();
|
||||||
|
}
|
||||||
|
}
|
19
app/Services/JournalService.php
Normal file
19
app/Services/JournalService.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Grade;
|
||||||
|
use App\Models\Subject;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class JournalService
|
||||||
|
{
|
||||||
|
public function getLessons(Grade $grade, Subject $subject)
|
||||||
|
{
|
||||||
|
return DB::table('lessons')
|
||||||
|
->where('grade_id', $grade->id)
|
||||||
|
->where('subject_id', $subject->id)
|
||||||
|
->orderBy('lesson_date')
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
}
|
23
app/Services/LessonService.php
Normal file
23
app/Services/LessonService.php
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Grade;
|
||||||
|
use App\Models\Teacher;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class LessonService
|
||||||
|
{
|
||||||
|
public function getLessons(Grade $grade)
|
||||||
|
{
|
||||||
|
if (Auth::user()->userable_type == Teacher::class) {
|
||||||
|
return $grade
|
||||||
|
->lessons()
|
||||||
|
->where('teacher_id', Auth::user()->userable_id)
|
||||||
|
->filter()
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $grade->lessons()->filter()->get();
|
||||||
|
}
|
||||||
|
}
|
@ -3,7 +3,6 @@
|
|||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
use App\Models\Lesson;
|
use App\Models\Lesson;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
|
||||||
|
|
||||||
class ScoreService
|
class ScoreService
|
||||||
{
|
{
|
||||||
|
@ -4,8 +4,12 @@ namespace App\Services;
|
|||||||
|
|
||||||
use App\Enums\ScoreEnum;
|
use App\Enums\ScoreEnum;
|
||||||
use App\Models\Student;
|
use App\Models\Student;
|
||||||
|
use App\Models\Subject;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
|
use Barryvdh\DomPDF\Facade\Pdf;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class StudentService
|
class StudentService
|
||||||
{
|
{
|
||||||
@ -53,4 +57,44 @@ class StudentService
|
|||||||
$model->user()->delete();
|
$model->user()->delete();
|
||||||
$model->delete();
|
$model->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getScores(Subject $subject): Collection
|
||||||
|
{
|
||||||
|
$student = Auth::user()->userable;
|
||||||
|
|
||||||
|
return $student->lessons()->where('subject_id', $subject->id)->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAvgScore(Subject $subject)
|
||||||
|
{
|
||||||
|
$student = Auth::user()->userable;
|
||||||
|
$scores = $student
|
||||||
|
->lessons()
|
||||||
|
->where('subject_id', $subject->id)
|
||||||
|
->whereIn('score', ScoreEnum::getNumScores())
|
||||||
|
->pluck('score');
|
||||||
|
|
||||||
|
return round($scores->avg(), 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDebts(): Collection
|
||||||
|
{
|
||||||
|
$student = Auth::user()->userable;
|
||||||
|
|
||||||
|
return $student->lessons()->whereIn('score', ScoreEnum::getDebtScores())->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function exportAvgScores()
|
||||||
|
{
|
||||||
|
$subjects = Auth::user()->userable->grade->subjects;
|
||||||
|
$avgScores = collect();
|
||||||
|
|
||||||
|
$subjects->each(function ($subject) use ($avgScores) {
|
||||||
|
$avgScores->put($subject->name, $this->getAvgScore($subject));
|
||||||
|
});
|
||||||
|
|
||||||
|
return Pdf::loadView('students.avg-scores', [
|
||||||
|
'avgScores' => $avgScores,
|
||||||
|
])->download('Успеваемость.pdf');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
22
app/Services/SubjectService.php
Normal file
22
app/Services/SubjectService.php
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Student;
|
||||||
|
use App\Models\Subject;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
|
class SubjectService
|
||||||
|
{
|
||||||
|
public function getSubjects()
|
||||||
|
{
|
||||||
|
if(Auth::user()->userable_type == Student::class) {
|
||||||
|
return Subject::whereIn('id', Auth::user()->userable->grade->subjects->pluck('id'))
|
||||||
|
->filter()
|
||||||
|
->paginate(5)
|
||||||
|
->withQueryString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Subject::filter()->paginate(5)->withQueryString();
|
||||||
|
}
|
||||||
|
}
|
@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
namespace App\Services;
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Student;
|
||||||
|
use App\Models\Subject;
|
||||||
use App\Models\Teacher;
|
use App\Models\Teacher;
|
||||||
use App\Models\User;
|
use App\Models\User;
|
||||||
use Illuminate\Pagination\LengthAwarePaginator;
|
use Illuminate\Pagination\LengthAwarePaginator;
|
||||||
|
use Illuminate\Support\Facades\Auth;
|
||||||
|
|
||||||
class TeacherService
|
class TeacherService
|
||||||
{
|
{
|
||||||
@ -47,4 +50,30 @@ class TeacherService
|
|||||||
$teacher->user()->delete();
|
$teacher->user()->delete();
|
||||||
$teacher->delete();
|
$teacher->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getTeachers()
|
||||||
|
{
|
||||||
|
if (Auth::user()->userable_type == Student::class) {
|
||||||
|
return Teacher::join('grade_teacher', 'teachers.id', '=', 'grade_teacher.teacher_id')
|
||||||
|
->where('grade_id', Auth::user()->userable->grade_id)
|
||||||
|
->filter()
|
||||||
|
->paginate(5)
|
||||||
|
->withQueryString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Teacher::filter()->paginate(5)->withQueryString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSubjects(Teacher $teacher)
|
||||||
|
{
|
||||||
|
if (Auth::user()->userable_type == Student::class) {
|
||||||
|
return Subject::join('subject_teacher', 'subject_teacher.subject_id', '=', 'subjects.id')
|
||||||
|
->join('grade_subject', 'grade_subject.subject_id', '=', 'subjects.id')
|
||||||
|
->where('grade_subject.grade_id', Auth::user()->userable->grade_id)
|
||||||
|
->where('subject_teacher.teacher_id', $teacher->id)
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $teacher->subjects;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,12 @@
|
|||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.2",
|
"php": "^8.2",
|
||||||
|
"barryvdh/laravel-dompdf": "^2.2",
|
||||||
"laravel/framework": "^11.0",
|
"laravel/framework": "^11.0",
|
||||||
"laravel/telescope": "^5.0",
|
"laravel/telescope": "^5.0",
|
||||||
"laravel/tinker": "^2.9",
|
"laravel/tinker": "^2.9",
|
||||||
"laravel/ui": "^4.5"
|
"laravel/ui": "^4.5",
|
||||||
|
"maatwebsite/excel": "^3.1"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.23",
|
"fakerphp/faker": "^1.23",
|
||||||
|
960
composer.lock
generated
960
composer.lock
generated
File diff suppressed because it is too large
Load Diff
284
config/dompdf.php
Normal file
284
config/dompdf.php
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return array(
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Settings
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Set some default values. It is possible to add all defines that can be set
|
||||||
|
| in dompdf_config.inc.php. You can also override the entire config file.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'show_warnings' => false, // Throw an Exception on warnings from dompdf
|
||||||
|
|
||||||
|
'public_path' => null, // Override the public path if needed
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dejavu Sans font is missing glyphs for converted entities, turn it off if you need to show € and £.
|
||||||
|
*/
|
||||||
|
'convert_entities' => true,
|
||||||
|
|
||||||
|
'options' => array(
|
||||||
|
/**
|
||||||
|
* The location of the DOMPDF font directory
|
||||||
|
*
|
||||||
|
* The location of the directory where DOMPDF will store fonts and font metrics
|
||||||
|
* Note: This directory must exist and be writable by the webserver process.
|
||||||
|
* *Please note the trailing slash.*
|
||||||
|
*
|
||||||
|
* Notes regarding fonts:
|
||||||
|
* Additional .afm font metrics can be added by executing load_font.php from command line.
|
||||||
|
*
|
||||||
|
* Only the original "Base 14 fonts" are present on all pdf viewers. Additional fonts must
|
||||||
|
* be embedded in the pdf file or the PDF may not display correctly. This can significantly
|
||||||
|
* increase file size unless font subsetting is enabled. Before embedding a font please
|
||||||
|
* review your rights under the font license.
|
||||||
|
*
|
||||||
|
* Any font specification in the source HTML is translated to the closest font available
|
||||||
|
* in the font directory.
|
||||||
|
*
|
||||||
|
* The pdf standard "Base 14 fonts" are:
|
||||||
|
* Courier, Courier-Bold, Courier-BoldOblique, Courier-Oblique,
|
||||||
|
* Helvetica, Helvetica-Bold, Helvetica-BoldOblique, Helvetica-Oblique,
|
||||||
|
* Times-Roman, Times-Bold, Times-BoldItalic, Times-Italic,
|
||||||
|
* Symbol, ZapfDingbats.
|
||||||
|
*/
|
||||||
|
"font_dir" => storage_path('fonts'), // advised by dompdf (https://github.com/dompdf/dompdf/pull/782)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of the DOMPDF font cache directory
|
||||||
|
*
|
||||||
|
* This directory contains the cached font metrics for the fonts used by DOMPDF.
|
||||||
|
* This directory can be the same as DOMPDF_FONT_DIR
|
||||||
|
*
|
||||||
|
* Note: This directory must exist and be writable by the webserver process.
|
||||||
|
*/
|
||||||
|
"font_cache" => storage_path('fonts'),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of a temporary directory.
|
||||||
|
*
|
||||||
|
* The directory specified must be writeable by the webserver process.
|
||||||
|
* The temporary directory is required to download remote images and when
|
||||||
|
* using the PDFLib back end.
|
||||||
|
*/
|
||||||
|
"temp_dir" => sys_get_temp_dir(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ==== IMPORTANT ====
|
||||||
|
*
|
||||||
|
* dompdf's "chroot": Prevents dompdf from accessing system files or other
|
||||||
|
* files on the webserver. All local files opened by dompdf must be in a
|
||||||
|
* subdirectory of this directory. DO NOT set it to '/' since this could
|
||||||
|
* allow an attacker to use dompdf to read any files on the server. This
|
||||||
|
* should be an absolute path.
|
||||||
|
* This is only checked on command line call by dompdf.php, but not by
|
||||||
|
* direct class use like:
|
||||||
|
* $dompdf = new DOMPDF(); $dompdf->load_html($htmldata); $dompdf->render(); $pdfdata = $dompdf->output();
|
||||||
|
*/
|
||||||
|
"chroot" => realpath(base_path()),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Protocol whitelist
|
||||||
|
*
|
||||||
|
* Protocols and PHP wrappers allowed in URIs, and the validation rules
|
||||||
|
* that determine if a resouce may be loaded. Full support is not guaranteed
|
||||||
|
* for the protocols/wrappers specified
|
||||||
|
* by this array.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
'allowed_protocols' => [
|
||||||
|
"file://" => ["rules" => []],
|
||||||
|
"http://" => ["rules" => []],
|
||||||
|
"https://" => ["rules" => []]
|
||||||
|
],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
'log_output_file' => null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to enable font subsetting or not.
|
||||||
|
*/
|
||||||
|
"enable_font_subsetting" => false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The PDF rendering backend to use
|
||||||
|
*
|
||||||
|
* Valid settings are 'PDFLib', 'CPDF' (the bundled R&OS PDF class), 'GD' and
|
||||||
|
* 'auto'. 'auto' will look for PDFLib and use it if found, or if not it will
|
||||||
|
* fall back on CPDF. 'GD' renders PDFs to graphic files. {@link
|
||||||
|
* Canvas_Factory} ultimately determines which rendering class to instantiate
|
||||||
|
* based on this setting.
|
||||||
|
*
|
||||||
|
* Both PDFLib & CPDF rendering backends provide sufficient rendering
|
||||||
|
* capabilities for dompdf, however additional features (e.g. object,
|
||||||
|
* image and font support, etc.) differ between backends. Please see
|
||||||
|
* {@link PDFLib_Adapter} for more information on the PDFLib backend
|
||||||
|
* and {@link CPDF_Adapter} and lib/class.pdf.php for more information
|
||||||
|
* on CPDF. Also see the documentation for each backend at the links
|
||||||
|
* below.
|
||||||
|
*
|
||||||
|
* The GD rendering backend is a little different than PDFLib and
|
||||||
|
* CPDF. Several features of CPDF and PDFLib are not supported or do
|
||||||
|
* not make any sense when creating image files. For example,
|
||||||
|
* multiple pages are not supported, nor are PDF 'objects'. Have a
|
||||||
|
* look at {@link GD_Adapter} for more information. GD support is
|
||||||
|
* experimental, so use it at your own risk.
|
||||||
|
*
|
||||||
|
* @link http://www.pdflib.com
|
||||||
|
* @link http://www.ros.co.nz/pdf
|
||||||
|
* @link http://www.php.net/image
|
||||||
|
*/
|
||||||
|
"pdf_backend" => "CPDF",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDFlib license key
|
||||||
|
*
|
||||||
|
* If you are using a licensed, commercial version of PDFlib, specify
|
||||||
|
* your license key here. If you are using PDFlib-Lite or are evaluating
|
||||||
|
* the commercial version of PDFlib, comment out this setting.
|
||||||
|
*
|
||||||
|
* @link http://www.pdflib.com
|
||||||
|
*
|
||||||
|
* If pdflib present in web server and auto or selected explicitely above,
|
||||||
|
* a real license code must exist!
|
||||||
|
*/
|
||||||
|
//"DOMPDF_PDFLIB_LICENSE" => "your license key here",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* html target media view which should be rendered into pdf.
|
||||||
|
* List of types and parsing rules for future extensions:
|
||||||
|
* http://www.w3.org/TR/REC-html40/types.html
|
||||||
|
* screen, tty, tv, projection, handheld, print, braille, aural, all
|
||||||
|
* Note: aural is deprecated in CSS 2.1 because it is replaced by speech in CSS 3.
|
||||||
|
* Note, even though the generated pdf file is intended for print output,
|
||||||
|
* the desired content might be different (e.g. screen or projection view of html file).
|
||||||
|
* Therefore allow specification of content here.
|
||||||
|
*/
|
||||||
|
"default_media_type" => "screen",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default paper size.
|
||||||
|
*
|
||||||
|
* North America standard is "letter"; other countries generally "a4"
|
||||||
|
*
|
||||||
|
* @see CPDF_Adapter::PAPER_SIZES for valid sizes ('letter', 'legal', 'A4', etc.)
|
||||||
|
*/
|
||||||
|
"default_paper_size" => "a4",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default paper orientation.
|
||||||
|
*
|
||||||
|
* The orientation of the page (portrait or landscape).
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
'default_paper_orientation' => "portrait",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default font family
|
||||||
|
*
|
||||||
|
* Used if no suitable fonts can be found. This must exist in the font folder.
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
"default_font" => "serif",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Image DPI setting
|
||||||
|
*
|
||||||
|
* This setting determines the default DPI setting for images and fonts. The
|
||||||
|
* DPI may be overridden for inline images by explictly setting the
|
||||||
|
* image's width & height style attributes (i.e. if the image's native
|
||||||
|
* width is 600 pixels and you specify the image's width as 72 points,
|
||||||
|
* the image will have a DPI of 600 in the rendered PDF. The DPI of
|
||||||
|
* background images can not be overridden and is controlled entirely
|
||||||
|
* via this parameter.
|
||||||
|
*
|
||||||
|
* For the purposes of DOMPDF, pixels per inch (PPI) = dots per inch (DPI).
|
||||||
|
* If a size in html is given as px (or without unit as image size),
|
||||||
|
* this tells the corresponding size in pt.
|
||||||
|
* This adjusts the relative sizes to be similar to the rendering of the
|
||||||
|
* html page in a reference browser.
|
||||||
|
*
|
||||||
|
* In pdf, always 1 pt = 1/72 inch
|
||||||
|
*
|
||||||
|
* Rendering resolution of various browsers in px per inch:
|
||||||
|
* Windows Firefox and Internet Explorer:
|
||||||
|
* SystemControl->Display properties->FontResolution: Default:96, largefonts:120, custom:?
|
||||||
|
* Linux Firefox:
|
||||||
|
* about:config *resolution: Default:96
|
||||||
|
* (xorg screen dimension in mm and Desktop font dpi settings are ignored)
|
||||||
|
*
|
||||||
|
* Take care about extra font/image zoom factor of browser.
|
||||||
|
*
|
||||||
|
* In images, <img> size in pixel attribute, img css style, are overriding
|
||||||
|
* the real image dimension in px for rendering.
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
"dpi" => 96,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable inline PHP
|
||||||
|
*
|
||||||
|
* If this setting is set to true then DOMPDF will automatically evaluate
|
||||||
|
* inline PHP contained within <script type="text/php"> ... </script> tags.
|
||||||
|
*
|
||||||
|
* Enabling this for documents you do not trust (e.g. arbitrary remote html
|
||||||
|
* pages) is a security risk. Set this option to false if you wish to process
|
||||||
|
* untrusted documents.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
"enable_php" => false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable inline Javascript
|
||||||
|
*
|
||||||
|
* If this setting is set to true then DOMPDF will automatically insert
|
||||||
|
* JavaScript code contained within <script type="text/javascript"> ... </script> tags.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
"enable_javascript" => true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable remote file access
|
||||||
|
*
|
||||||
|
* If this setting is set to true, DOMPDF will access remote sites for
|
||||||
|
* images and CSS files as required.
|
||||||
|
* This is required for part of test case www/test/image_variants.html through www/examples.php
|
||||||
|
*
|
||||||
|
* Attention!
|
||||||
|
* This can be a security risk, in particular in combination with DOMPDF_ENABLE_PHP and
|
||||||
|
* allowing remote access to dompdf.php or on allowing remote html code to be passed to
|
||||||
|
* $dompdf = new DOMPDF(, $dompdf->load_html(...,
|
||||||
|
* This allows anonymous users to download legally doubtful internet content which on
|
||||||
|
* tracing back appears to being downloaded by your server, or allows malicious php code
|
||||||
|
* in remote html pages to be executed by your server with your account privileges.
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
"enable_remote" => true,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ratio applied to the fonts height to be more like browsers' line height
|
||||||
|
*/
|
||||||
|
"font_height_ratio" => 1.1,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use the HTML5 Lib parser
|
||||||
|
*
|
||||||
|
* @deprecated This feature is now always on in dompdf 2.x
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
"enable_html5_parser" => true,
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
);
|
379
config/excel.php
Normal file
379
config/excel.php
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Maatwebsite\Excel\Excel;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'exports' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Chunk size
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When using FromQuery, the query is automatically chunked.
|
||||||
|
| Here you can specify how big the chunk should be.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'chunk_size' => 1000,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Pre-calculate formulas during export
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
'pre_calculate_formulas' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Enable strict null comparison
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When enabling strict null comparison empty cells ('') will
|
||||||
|
| be added to the sheet.
|
||||||
|
*/
|
||||||
|
'strict_null_comparison' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CSV Settings
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure e.g. delimiter, enclosure and line ending for CSV exports.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'csv' => [
|
||||||
|
'delimiter' => ',',
|
||||||
|
'enclosure' => '"',
|
||||||
|
'line_ending' => PHP_EOL,
|
||||||
|
'use_bom' => false,
|
||||||
|
'include_separator_line' => false,
|
||||||
|
'excel_compatibility' => false,
|
||||||
|
'output_encoding' => '',
|
||||||
|
'test_auto_detect' => true,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Worksheet properties
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure e.g. default title, creator, subject,...
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'properties' => [
|
||||||
|
'creator' => '',
|
||||||
|
'lastModifiedBy' => '',
|
||||||
|
'title' => '',
|
||||||
|
'description' => '',
|
||||||
|
'subject' => '',
|
||||||
|
'keywords' => '',
|
||||||
|
'category' => '',
|
||||||
|
'manager' => '',
|
||||||
|
'company' => '',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'imports' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Read Only
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with imports, you might only be interested in the
|
||||||
|
| data that the sheet exists. By default we ignore all styles,
|
||||||
|
| however if you want to do some logic based on style data
|
||||||
|
| you can enable it by setting read_only to false.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'read_only' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Ignore Empty
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with imports, you might be interested in ignoring
|
||||||
|
| rows that have null values or empty strings. By default rows
|
||||||
|
| containing empty strings or empty values are not ignored but can be
|
||||||
|
| ignored by enabling the setting ignore_empty to true.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'ignore_empty' => false,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Heading Row Formatter
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure the heading row formatter.
|
||||||
|
| Available options: none|slug|custom
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'heading_row' => [
|
||||||
|
'formatter' => 'slug',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| CSV Settings
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure e.g. delimiter, enclosure and line ending for CSV imports.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'csv' => [
|
||||||
|
'delimiter' => null,
|
||||||
|
'enclosure' => '"',
|
||||||
|
'escape_character' => '\\',
|
||||||
|
'contiguous' => false,
|
||||||
|
'input_encoding' => 'UTF-8',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Worksheet properties
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure e.g. default title, creator, subject,...
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'properties' => [
|
||||||
|
'creator' => '',
|
||||||
|
'lastModifiedBy' => '',
|
||||||
|
'title' => '',
|
||||||
|
'description' => '',
|
||||||
|
'subject' => '',
|
||||||
|
'keywords' => '',
|
||||||
|
'category' => '',
|
||||||
|
'manager' => '',
|
||||||
|
'company' => '',
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cell Middleware
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure middleware that is executed on getting a cell value
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'cells' => [
|
||||||
|
'middleware' => [
|
||||||
|
//\Maatwebsite\Excel\Middleware\TrimCellValue::class,
|
||||||
|
//\Maatwebsite\Excel\Middleware\ConvertEmptyCellValuesToNull::class,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Extension detector
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure here which writer/reader type should be used when the package
|
||||||
|
| needs to guess the correct type based on the extension alone.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'extension_detector' => [
|
||||||
|
'xlsx' => Excel::XLSX,
|
||||||
|
'xlsm' => Excel::XLSX,
|
||||||
|
'xltx' => Excel::XLSX,
|
||||||
|
'xltm' => Excel::XLSX,
|
||||||
|
'xls' => Excel::XLS,
|
||||||
|
'xlt' => Excel::XLS,
|
||||||
|
'ods' => Excel::ODS,
|
||||||
|
'ots' => Excel::ODS,
|
||||||
|
'slk' => Excel::SLK,
|
||||||
|
'xml' => Excel::XML,
|
||||||
|
'gnumeric' => Excel::GNUMERIC,
|
||||||
|
'htm' => Excel::HTML,
|
||||||
|
'html' => Excel::HTML,
|
||||||
|
'csv' => Excel::CSV,
|
||||||
|
'tsv' => Excel::TSV,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| PDF Extension
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Configure here which Pdf driver should be used by default.
|
||||||
|
| Available options: Excel::MPDF | Excel::TCPDF | Excel::DOMPDF
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'pdf' => Excel::DOMPDF,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Value Binder
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| PhpSpreadsheet offers a way to hook into the process of a value being
|
||||||
|
| written to a cell. In there some assumptions are made on how the
|
||||||
|
| value should be formatted. If you want to change those defaults,
|
||||||
|
| you can implement your own default value binder.
|
||||||
|
|
|
||||||
|
| Possible value binders:
|
||||||
|
|
|
||||||
|
| [x] Maatwebsite\Excel\DefaultValueBinder::class
|
||||||
|
| [x] PhpOffice\PhpSpreadsheet\Cell\StringValueBinder::class
|
||||||
|
| [x] PhpOffice\PhpSpreadsheet\Cell\AdvancedValueBinder::class
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'value_binder' => [
|
||||||
|
'default' => Maatwebsite\Excel\DefaultValueBinder::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
'cache' => [
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Default cell caching driver
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| By default PhpSpreadsheet keeps all cell values in memory, however when
|
||||||
|
| dealing with large files, this might result into memory issues. If you
|
||||||
|
| want to mitigate that, you can configure a cell caching driver here.
|
||||||
|
| When using the illuminate driver, it will store each value in the
|
||||||
|
| cache store. This can slow down the process, because it needs to
|
||||||
|
| store each value. You can use the "batch" store if you want to
|
||||||
|
| only persist to the store when the memory limit is reached.
|
||||||
|
|
|
||||||
|
| Drivers: memory|illuminate|batch
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'driver' => 'memory',
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Batch memory caching
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with the "batch" caching driver, it will only
|
||||||
|
| persist to the store when the memory limit is reached.
|
||||||
|
| Here you can tweak the memory limit to your liking.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'batch' => [
|
||||||
|
'memory_limit' => 60000,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Illuminate cache
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When using the "illuminate" caching driver, it will automatically use
|
||||||
|
| your default cache store. However if you prefer to have the cell
|
||||||
|
| cache on a separate store, you can configure the store name here.
|
||||||
|
| You can use any store defined in your cache config. When leaving
|
||||||
|
| at "null" it will use the default store.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'illuminate' => [
|
||||||
|
'store' => null,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Cache Time-to-live (TTL)
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The TTL of items written to cache. If you want to keep the items cached
|
||||||
|
| indefinitely, set this to null. Otherwise, set a number of seconds,
|
||||||
|
| a \DateInterval, or a callable.
|
||||||
|
|
|
||||||
|
| Allowable types: callable|\DateInterval|int|null
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'default_ttl' => 10800,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Transaction Handler
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| By default the import is wrapped in a transaction. This is useful
|
||||||
|
| for when an import may fail and you want to retry it. With the
|
||||||
|
| transactions, the previous import gets rolled-back.
|
||||||
|
|
|
||||||
|
| You can disable the transaction handler by setting this to null.
|
||||||
|
| Or you can choose a custom made transaction handler here.
|
||||||
|
|
|
||||||
|
| Supported handlers: null|db
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'transactions' => [
|
||||||
|
'handler' => 'db',
|
||||||
|
'db' => [
|
||||||
|
'connection' => null,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
|
||||||
|
'temporary_files' => [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Local Temporary Path
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When exporting and importing files, we use a temporary file, before
|
||||||
|
| storing reading or downloading. Here you can customize that path.
|
||||||
|
| permissions is an array with the permission flags for the directory (dir)
|
||||||
|
| and the create file (file).
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'local_path' => storage_path('framework/cache/laravel-excel'),
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Local Temporary Path Permissions
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Permissions is an array with the permission flags for the directory (dir)
|
||||||
|
| and the create file (file).
|
||||||
|
| If omitted the default permissions of the filesystem will be used.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'local_permissions' => [
|
||||||
|
// 'dir' => 0755,
|
||||||
|
// 'file' => 0644,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Remote Temporary Disk
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with a multi server setup with queues in which you
|
||||||
|
| cannot rely on having a shared local temporary path, you might
|
||||||
|
| want to store the temporary file on a shared disk. During the
|
||||||
|
| queue executing, we'll retrieve the temporary file from that
|
||||||
|
| location instead. When left to null, it will always use
|
||||||
|
| the local path. This setting only has effect when using
|
||||||
|
| in conjunction with queued imports and exports.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'remote_disk' => null,
|
||||||
|
'remote_prefix' => null,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Force Resync
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| When dealing with a multi server setup as above, it's possible
|
||||||
|
| for the clean up that occurs after entire queue has been run to only
|
||||||
|
| cleanup the server that the last AfterImportJob runs on. The rest of the server
|
||||||
|
| would still have the local temporary file stored on it. In this case your
|
||||||
|
| local storage limits can be exceeded and future imports won't be processed.
|
||||||
|
| To mitigate this you can set this config value to be true, so that after every
|
||||||
|
| queued chunk is processed the local temporary file is deleted on the server that
|
||||||
|
| processed it.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'force_resync_remote' => null,
|
||||||
|
],
|
||||||
|
];
|
51
config/tinker.php
Normal file
51
config/tinker.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Console Commands
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option allows you to add additional Artisan commands that should
|
||||||
|
| be available within the Tinker environment. Once the command is in
|
||||||
|
| this array you may execute the command in Tinker using its name.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'commands' => [
|
||||||
|
App\Console\Commands\AddAdmin::class,
|
||||||
|
App\Console\Commands\AddScores::class,
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Auto Aliased Classes
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Tinker will not automatically alias classes in your vendor namespaces
|
||||||
|
| but you may explicitly allow a subset of classes to get aliased by
|
||||||
|
| adding the names of each of those classes to the following list.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'alias' => [
|
||||||
|
//
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Classes That Should Not Be Aliased
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Typically, Tinker automatically aliases classes as you require them in
|
||||||
|
| Tinker. However, you may wish to never alias certain classes, which
|
||||||
|
| you may accomplish by listing the classes in the following array.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
'dont_alias' => [
|
||||||
|
'App\Nova',
|
||||||
|
],
|
||||||
|
|
||||||
|
];
|
@ -18,9 +18,39 @@ class DatabaseSeeder extends Seeder
|
|||||||
*/
|
*/
|
||||||
public function run(): void
|
public function run(): void
|
||||||
{
|
{
|
||||||
|
$namesSubjects = [
|
||||||
|
'Русский язык',
|
||||||
|
'Математика',
|
||||||
|
'Английский язык',
|
||||||
|
'Биология',
|
||||||
|
'Химия',
|
||||||
|
'Литература',
|
||||||
|
'География',
|
||||||
|
'История',
|
||||||
|
'Обществознание',
|
||||||
|
'Информатика',
|
||||||
|
];
|
||||||
|
$subjects = collect();
|
||||||
|
|
||||||
|
foreach ($namesSubjects as $name) {
|
||||||
|
$subjects->push(Subject::factory()->create([
|
||||||
|
'name' => $name,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$letterGrades = ['A', 'Б', 'В',];
|
||||||
|
$numberGrades = 11;
|
||||||
|
$grades = collect();
|
||||||
|
|
||||||
|
while($numberGrades > 0) {
|
||||||
|
foreach ($letterGrades as $letter) {
|
||||||
|
$grades->push(Grade::factory()->create([
|
||||||
|
'name' => $numberGrades . $letter,
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
$numberGrades--;
|
||||||
|
}
|
||||||
$teachers = Teacher::factory(15)->create();
|
$teachers = Teacher::factory(15)->create();
|
||||||
$grades = Grade::factory(10)->create();
|
|
||||||
$subjects = Subject::factory(10)->create();
|
|
||||||
$scores = ScoreEnum::cases();
|
$scores = ScoreEnum::cases();
|
||||||
|
|
||||||
$teachers->each(function ($teacher) {
|
$teachers->each(function ($teacher) {
|
||||||
@ -28,33 +58,45 @@ class DatabaseSeeder extends Seeder
|
|||||||
$teacher->user()->save($user);
|
$teacher->user()->save($user);
|
||||||
});
|
});
|
||||||
|
|
||||||
$grades->each(function ($grade) use ($subjects, $teachers, $scores){
|
$teacher = Teacher::factory()->create();
|
||||||
$grade->subjects()->sync($subjects);
|
$teacher->user()->save(User::factory()->create(['email' => 'teacher@mail']));
|
||||||
$grade->teachers()->sync($teachers);
|
$teacher->grades()->attach($grades->pluck('id'));
|
||||||
|
|
||||||
$students = Student::factory(10)->create([
|
$student = Student::factory()->create(['grade_id' => $grades->first()->id]);
|
||||||
|
$student->user()->save(User::factory()->create(['email' => 'student@mail']));
|
||||||
|
|
||||||
|
$grade = $student->grade;
|
||||||
|
|
||||||
|
$lessons = collect();
|
||||||
|
$subjects->each(function ($item) use ($lessons, $teacher, $student, $grade) {
|
||||||
|
$teacher->subjects()->attach($item);
|
||||||
|
$grade->subjects()->attach($item);
|
||||||
|
|
||||||
|
$lessons->push(Lesson::factory(5)->create([
|
||||||
|
'description' => 'Выполнение задания №3 на 87 стр. учебника',
|
||||||
|
'grade_id' => $student->grade_id,
|
||||||
|
'subject_id' => $item->id,
|
||||||
|
'teacher_id' => $teacher->id,
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
$grades->each(function ($grade) use ($subjects, $teachers, $scores){
|
||||||
|
Student::factory(30)->create([
|
||||||
'grade_id' => $grade->id,
|
'grade_id' => $grade->id,
|
||||||
])->each(function ($student) use ($scores) {
|
])->each(function ($student) use ($scores) {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$student->user()->save($user);
|
$student->user()->save($user);
|
||||||
});
|
});
|
||||||
|
|
||||||
$lessons = Lesson::factory(30)->create([
|
|
||||||
'grade_id' => $grade->id,
|
|
||||||
'subject_id' => $grade->subjects->random()->id,
|
|
||||||
'teacher_id' => $grade->teachers->random()->id,
|
|
||||||
]);
|
|
||||||
|
|
||||||
$students->each(function ($student) use ($lessons, $scores) {
|
|
||||||
$lessons->each(function ($lesson) use ($student, $scores) {
|
|
||||||
$student->lessons()
|
|
||||||
->syncWithoutDetaching([$lesson->id => ['score' => $scores[array_rand($scores)]]]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$subjects->each(function ($subject) use ($teachers) {
|
$grade->students->each(function ($student) use ($grade, $scores) {
|
||||||
$subject->teachers()->sync($teachers->random(2));
|
$grade->lessons->each(function ($lesson) use ($student, $scores) {
|
||||||
|
$student->lessons()
|
||||||
|
->syncWithoutDetaching([
|
||||||
|
$lesson->id => ['score' => $scores[array_rand($scores)]]
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "course_work",
|
"name": "CourseWork",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<select id="type" name="type" class="form-select" required>
|
<select id="type" name="type" class="form-select" required>
|
||||||
<option value="">Выберите тип деятельности</option>
|
<option value="">Выберите тип деятельности</option>
|
||||||
@foreach($types as $type)
|
@foreach($types as $type)
|
||||||
<option value="{{ $type }}" {{ isset($lesson) && $lesson->type == $type ? 'selected' : old('type') }}>
|
<option value="{{ $type }}" {{ isset($lesson) && $lesson->type == $type->value ? 'selected' : old('type') }}>
|
||||||
{{ $type }}
|
{{ $type }}
|
||||||
</option>
|
</option>
|
||||||
@endforeach
|
@endforeach
|
||||||
@ -36,7 +36,7 @@
|
|||||||
<textarea class="form-control" id="description" name="description" rows="5" >{{ isset($lesson) ? $lesson->description : old('description') }}</textarea>
|
<textarea class="form-control" id="description" name="description" rows="5" >{{ isset($lesson) ? $lesson->description : old('description') }}</textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="lesson_date" class="form-label">Дата рождения:</label>
|
<label for="lesson_date" class="form-label">Дата занятия:</label>
|
||||||
<input type="date" id="lesson_date" name="lesson_date" class="form-control" value="{{ isset($lesson) ? $lesson->lesson_date : old('lesson_date') }}" required>
|
<input type="date" id="lesson_date" name="lesson_date" class="form-control" value="{{ isset($lesson) ? $lesson->lesson_date : old('lesson_date') }}" required>
|
||||||
</div>
|
</div>
|
||||||
<input type="hidden" name="grade_id" value="{{ $grade->id }}">
|
<input type="hidden" name="grade_id" value="{{ $grade->id }}">
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
`@extends('layouts.application')
|
@extends('layouts.application')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="container col-md-5">
|
<div class="container col-md-5">
|
||||||
@ -53,5 +53,3 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
`
|
|
||||||
|
@ -19,10 +19,12 @@
|
|||||||
<h5><strong>Описание: </strong>{{ $lesson->description }}</h5>
|
<h5><strong>Описание: </strong>{{ $lesson->description }}</h5>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
@can('update', $lesson)
|
||||||
<a href="{{ route('lessons.scores.show', $lesson) }}" class="btn btn-success">Оценки</a>
|
<div class="card-footer">
|
||||||
<a href="{{ route('grades.lessons.edit', [$grade, $lesson]) }}" class="btn btn-primary">Редактировать</a>
|
<a href="{{ route('lessons.scores.show', $lesson) }}" class="btn btn-success">Оценки</a>
|
||||||
</div>
|
<a href="{{ route('grades.lessons.edit', [$grade, $lesson]) }}" class="btn btn-primary">Редактировать</a>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
48
resources/views/grade-subject/journal.blade.php
Normal file
48
resources/views/grade-subject/journal.blade.php
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
@extends('layouts.application')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container col-md-8">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
@if (count($students))
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
{{__('Журнал')}}
|
||||||
|
<a href="{{ route('export-excel', [$grade, $subject]) }}" class="btn btn-info">Excel</a>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col"></th>
|
||||||
|
@foreach ($lessons as $lesson)
|
||||||
|
<th style="text-align: center; vertical-align: middle;" scope="col">{{ $lesson->date }}</th>
|
||||||
|
@endforeach
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th style="text-align: center; vertical-align: middle;" scope="col">ФИО</th>
|
||||||
|
@foreach ($lessons as $lesson)
|
||||||
|
<th style="text-align: center; vertical-align: middle;" scope="col">{{ $lesson->shortType }}</th>
|
||||||
|
@endforeach
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach ($students as $student)
|
||||||
|
<tr>
|
||||||
|
<td style="text-align: center; vertical-align: middle;"> {{ $student->fio }}</td>
|
||||||
|
@foreach ($lessons as $lesson)
|
||||||
|
<td style="text-align: center; vertical-align: middle;">
|
||||||
|
{{ $student->lessons->find($lesson->id)->pivot->score ?? "-" }}
|
||||||
|
</td>
|
||||||
|
@endforeach
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
@ -36,24 +36,37 @@
|
|||||||
class="btn btn-block col-8">{{ $grade->name }}</a>
|
class="btn btn-block col-8">{{ $grade->name }}</a>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
@can('viewAny', \App\Models\Lesson::class)
|
||||||
<div>
|
<td>
|
||||||
<a href="{{ route('grades.lessons.index', $grade) }}" class="btn btn-primary">Занятия</a>
|
<div>
|
||||||
</div>
|
<a href="{{ route('grades.lessons.index', $grade) }}" class="btn btn-primary">Занятия</a>
|
||||||
</td>
|
</div>
|
||||||
<td>
|
</td>
|
||||||
<div>
|
@endcan
|
||||||
<a href="{{ route('grades.edit', $grade) }}" class="btn btn-warning">Редактировать</a>
|
@can('list', \App\Models\Grade::class)
|
||||||
</div>
|
<td>
|
||||||
</td>
|
<div>
|
||||||
<td>
|
<a href="{{ route('list-students', $grade) }}" class="btn btn-info">Списки учеников</a>
|
||||||
<form action="{{ route('grades.destroy', $grade) }}" method="POST"
|
</div>
|
||||||
style="display: inline-block;">
|
</td>
|
||||||
@csrf
|
@endcan
|
||||||
@method('DELETE')
|
@can('update', $grade)
|
||||||
<button type="submit" class="btn btn-danger">Удалить</button>
|
<td>
|
||||||
</form>
|
<div>
|
||||||
</td>
|
<a href="{{ route('grades.edit', $grade) }}" class="btn btn-warning">Редактировать</a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
@endcan
|
||||||
|
@can('delete', $grade)
|
||||||
|
<td>
|
||||||
|
<form action="{{ route('grades.destroy', $grade) }}" method="POST"
|
||||||
|
style="display: inline-block;">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-danger">Удалить</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
@endcan
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -62,9 +75,11 @@
|
|||||||
<p>Классы отсутствуют</p>
|
<p>Классы отсутствуют</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
@can('create', \App\Models\Grade::class)
|
||||||
<a href="{{ route('grades.create') }}" class="btn btn-success">Добавить</a>
|
<div class="card-footer">
|
||||||
</div>
|
<a href="{{ route('grades.create') }}" class="btn btn-success">Добавить</a>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
<div class="card-footer">{{ $grades->links() }}</div>
|
<div class="card-footer">{{ $grades->links() }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
56
resources/views/grades/list-students.blade.php
Normal file
56
resources/views/grades/list-students.blade.php
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
|
<style>
|
||||||
|
* { font-family: DejaVu Sans !important; }
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>Списки студентов</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h3>Список отличников</h3>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ФИО</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($excellentStudents as $student)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $student->fio }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<h3>Список хорошистов</h3>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ФИО</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($goodStudents as $student)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $student->fio }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -10,9 +10,11 @@
|
|||||||
<h5><strong>Название: </strong>{{ $grade->name }}</h5>
|
<h5><strong>Название: </strong>{{ $grade->name }}</h5>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
@can('update', $grade)
|
||||||
<a href="{{ route('grades.edit', $grade) }}" class="btn btn-primary">Редактировать</a>
|
<div class="card-footer">
|
||||||
</div>
|
<a href="{{ route('grades.edit', $grade) }}" class="btn btn-primary">Редактировать</a>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
<div class="card mt-4">
|
<div class="card mt-4">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@ -33,18 +35,22 @@
|
|||||||
{{ $subject->name }}
|
{{ $subject->name }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
@can('journal', \App\Models\Grade::class)
|
||||||
<div>
|
<td>
|
||||||
<a href="{{ route('grades.subjects.edit', [$grade, $subject]) }}" class="btn btn-warning">Редактировать</a>
|
<div>
|
||||||
</div>
|
<a href="{{ route('grades.subjects.journal', [$grade, $subject]) }}" class="btn btn-primary">Журнал</a>
|
||||||
</td>
|
</div>
|
||||||
<td>
|
</td>
|
||||||
<form action="{{ route('grades.subjects.destroy', [$grade, $subject]) }}" method="POST" style="display: inline-block;">
|
@endcan
|
||||||
@csrf
|
@can('delete', $grade)
|
||||||
@method('DELETE')
|
<td>
|
||||||
<button type="submit" class="btn btn-danger">Удалить</button>
|
<form action="{{ route('grades.subjects.destroy', [$grade, $subject]) }}" method="POST" style="display: inline-block;">
|
||||||
</form>
|
@csrf
|
||||||
</td>
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-danger">Удалить</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
@endcan
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -53,9 +59,11 @@
|
|||||||
<p>У класса отсутствуют предметы</p>
|
<p>У класса отсутствуют предметы</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
@can('create', \App\Models\Grade::class)
|
||||||
<a href="{{ route('grades.subjects.create', $grade) }}" class="btn btn-success">Добавить</a>
|
<div class="card-footer">
|
||||||
</div>
|
<a href="{{ route('grades.subjects.create', $grade) }}" class="btn btn-success">Добавить</a>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,35 +5,49 @@
|
|||||||
<div class="flex">
|
<div class="flex">
|
||||||
<!-- Logo -->
|
<!-- Logo -->
|
||||||
<div class="shrink-0 flex items-center">
|
<div class="shrink-0 flex items-center">
|
||||||
<a href="{{ route('grades.index') }}">
|
<x-application-logo class="block h-9 w-auto fill-current text-gray-800" />
|
||||||
<x-application-logo class="block h-9 w-auto fill-current text-gray-800" />
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Navigation Links -->
|
<!-- Navigation Links -->
|
||||||
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
@can('viewAny', \App\Models\Grade::class)
|
||||||
<x-nav-link :href="route('grades.index')" :active="request()->routeIs('dashboard')">
|
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
||||||
{{ __('Классы') }}
|
<x-nav-link :href="route('grades.index')" :active="request()->routeIs('grades.index')">
|
||||||
</x-nav-link>
|
{{ __('Классы') }}
|
||||||
</div>
|
</x-nav-link>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
|
|
||||||
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
@can('viewAny', \App\Models\Subject::class)
|
||||||
<x-nav-link :href="route('subjects.index')" :active="request()->routeIs('dashboard')">
|
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
||||||
{{ __('Предметы') }}
|
<x-nav-link :href="route('subjects.index')" :active="request()->routeIs('subjects.index')">
|
||||||
</x-nav-link>
|
{{ __('Предметы') }}
|
||||||
</div>
|
</x-nav-link>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
|
|
||||||
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
@can('viewAny', \App\Models\Student::class)
|
||||||
<x-nav-link :href="route('students.index')" :active="request()->routeIs('dashboard')">
|
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
||||||
{{ __('Студенты') }}
|
<x-nav-link :href="route('students.index')" :active="request()->routeIs('students.index')">
|
||||||
</x-nav-link>
|
{{ __('Ученики') }}
|
||||||
</div>
|
</x-nav-link>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
|
|
||||||
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
@can('viewAny', \App\Models\Teacher::class)
|
||||||
<x-nav-link :href="route('teachers.index')" :active="request()->routeIs('dashboard')">
|
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
||||||
{{ __('Учителя') }}
|
<x-nav-link :href="route('teachers.index')" :active="request()->routeIs('teachers.index')">
|
||||||
</x-nav-link>
|
{{ __('Учителя') }}
|
||||||
</div>
|
</x-nav-link>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
@can('debts', \App\Models\Student::class)
|
||||||
|
<div class="hidden space-x-8 sm:-my-px sm:ms-10 sm:flex">
|
||||||
|
<x-nav-link :href="route('student-debts')" :active="request()->routeIs('student-debts')">
|
||||||
|
{{ __('Задолженности') }}
|
||||||
|
</x-nav-link>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Settings Dropdown -->
|
<!-- Settings Dropdown -->
|
||||||
@ -41,7 +55,7 @@
|
|||||||
<x-dropdown align="right" width="48">
|
<x-dropdown align="right" width="48">
|
||||||
<x-slot name="trigger">
|
<x-slot name="trigger">
|
||||||
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
|
<button class="inline-flex items-center px-3 py-2 border border-transparent text-sm leading-4 font-medium rounded-md text-gray-500 bg-white hover:text-gray-700 focus:outline-none transition ease-in-out duration-150">
|
||||||
<div>{{ Auth::user()->name }}</div>
|
<div>{{ Auth::user()->userable->fio }}</div>
|
||||||
|
|
||||||
<div class="ms-1">
|
<div class="ms-1">
|
||||||
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20">
|
||||||
@ -85,9 +99,35 @@
|
|||||||
<!-- Responsive Navigation Menu -->
|
<!-- Responsive Navigation Menu -->
|
||||||
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
|
<div :class="{'block': open, 'hidden': ! open}" class="hidden sm:hidden">
|
||||||
<div class="pt-2 pb-3 space-y-1">
|
<div class="pt-2 pb-3 space-y-1">
|
||||||
<x-responsive-nav-link :href="route('dashboard')" :active="request()->routeIs('dashboard')">
|
@can('viewAny', \App\Models\Grade::class)
|
||||||
{{ __('Dashboard') }}
|
<x-responsive-nav-link :href="route('grades.index')" :active="request()->routeIs('grades.index')">
|
||||||
</x-responsive-nav-link>
|
{{ __('Классы') }}
|
||||||
|
</x-responsive-nav-link>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
@can('viewAny', \App\Models\Subject::class)
|
||||||
|
<x-responsive-nav-link :href="route('subjects.index')" :active="request()->routeIs('subjects.index')">
|
||||||
|
{{ __('Предметы') }}
|
||||||
|
</x-responsive-nav-link>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
@can('viewAny', \App\Models\Student::class)
|
||||||
|
<x-responsive-nav-link :href="route('students.index')" :active="request()->routeIs('students.index')">
|
||||||
|
{{ __('Ученики') }}
|
||||||
|
</x-responsive-nav-link>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
@can('viewAny', \App\Models\Teacher::class)
|
||||||
|
<x-responsive-nav-link :href="route('teachers.index')" :active="request()->routeIs('teachers.index')">
|
||||||
|
{{ __('Учителя') }}
|
||||||
|
</x-responsive-nav-link>
|
||||||
|
@endcan
|
||||||
|
|
||||||
|
@can('debts', \App\Models\Student::class)
|
||||||
|
<x-responsive-nav-link :href="route('student-debts')" :active="request()->routeIs('student-debts')">
|
||||||
|
{{ __('Задолженности') }}
|
||||||
|
</x-responsive-nav-link>
|
||||||
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Responsive Settings Options -->
|
<!-- Responsive Settings Options -->
|
||||||
|
3
resources/views/mails/user_created.blade.php
Normal file
3
resources/views/mails/user_created.blade.php
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<div>
|
||||||
|
Ваш пароль для входа на {{ url('/') }}: {{ $password }}
|
||||||
|
</div>
|
43
resources/views/students/avg-scores.blade.php
Normal file
43
resources/views/students/avg-scores.blade.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
|
<style>
|
||||||
|
* { font-family: DejaVu Sans !important; }
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>Успеваемость ученика</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Информация об успеваемости</h1>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Предмет</th>
|
||||||
|
<th>Средняя оценка</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($avgScores as $key => $item)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $key }}</td>
|
||||||
|
<td>{{ $item }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
28
resources/views/students/debts.blade.php
Normal file
28
resources/views/students/debts.blade.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
@extends('layouts.application')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container col-md-6">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
@if(count($lessons))
|
||||||
|
@foreach($lessons as $lesson)
|
||||||
|
<a href="{{ route('grades.lessons.show', [$lesson->grade_id, $lesson]) }}" class="text-decoration-none">
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header"><strong>{{ $lesson->subject->name }} - {{ $lesson->pivot->score }}</strong></div>
|
||||||
|
<div class="card-header">{{ $lesson->type }}</div>
|
||||||
|
<div class="card-body">
|
||||||
|
{{ $lesson->name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
@endforeach
|
||||||
|
@else
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header"><strong>Задолженности</strong></div>
|
||||||
|
<div class="card-body">
|
||||||
|
Задолженности отсутствуют
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
@ -24,6 +24,7 @@
|
|||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<th>ФИО</th>
|
<th>ФИО</th>
|
||||||
|
<th>Класс</th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -31,21 +32,34 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="table-text">
|
<td class="table-text">
|
||||||
<div>
|
<div>
|
||||||
<a href="{{ route('students.show', $student) }}" class="btn btn-block col-8">{{ $student->fio }}</a>
|
@can('view', $student)
|
||||||
|
<a href="{{ route('students.show', $student) }}" class="btn btn-block col-8">{{ $student->fio }}</a>
|
||||||
|
@else
|
||||||
|
{{ $student->fio }}
|
||||||
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td class="table-text">
|
||||||
<div>
|
<div>
|
||||||
<a href="{{ route('students.edit', $student) }}" class="btn btn-warning">Редактировать</a>
|
{{ $student->grade->name }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
@can('update', $student)
|
||||||
<form action="{{ route('students.destroy', $student) }}" method="POST" style="display: inline-block;">
|
<td>
|
||||||
@csrf
|
<div>
|
||||||
@method('DELETE')
|
<a href="{{ route('students.edit', $student) }}" class="btn btn-warning">Редактировать</a>
|
||||||
<button type="submit" class="btn btn-danger">Удалить</button>
|
</div>
|
||||||
</form>
|
</td>
|
||||||
</td>
|
@endcan
|
||||||
|
@can('delete', $student)
|
||||||
|
<td>
|
||||||
|
<form action="{{ route('students.destroy', $student) }}" method="POST" style="display: inline-block;">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-danger">Удалить</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
@endcan
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -54,9 +68,11 @@
|
|||||||
<p>Ученики остутствуют</p>
|
<p>Ученики остутствуют</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
@can('create', \App\Models\Student::class)
|
||||||
<a href="{{ route('students.create') }}" class="btn btn-success">Добавить</a>
|
<div class="card-footer">
|
||||||
</div>
|
<a href="{{ route('students.create') }}" class="btn btn-success">Добавить</a>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
<div class="card-footer">{{ $students->links() }}</div>
|
<div class="card-footer">{{ $students->links() }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
24
resources/views/students/scores.blade.php
Normal file
24
resources/views/students/scores.blade.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
@extends('layouts.application')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container col-md-6">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header"><strong>Средняя оценка - {{ $avgScore }}</strong></div>
|
||||||
|
</div>
|
||||||
|
@if(count($lessons))
|
||||||
|
@foreach($lessons as $lesson)
|
||||||
|
<a href="{{ route('grades.lessons.show', [$lesson->grade_id, $lesson]) }}" class="text-decoration-none">
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header"><strong>{{ $lesson->subject->name }} - {{ $lesson->pivot->score }}</strong></div>
|
||||||
|
<div class="card-header">{{ $lesson->type }}</div>
|
||||||
|
<div class="card-body">
|
||||||
|
{{ $lesson->name }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
@endforeach
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
19
resources/views/subject-teacher/index.blade.php
Normal file
19
resources/views/subject-teacher/index.blade.php
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
@extends('layouts.application')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container col-md-6">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="card mt-4">
|
||||||
|
<div class="card-header">{{__('Предметы')}}</div>
|
||||||
|
<div class="card-body">
|
||||||
|
@if(count($subjects))
|
||||||
|
<ul class="list-group list-group-flush text-center">
|
||||||
|
@foreach ($subjects as $subject)
|
||||||
|
<li class="list-group-item">{{ $subject->name }}</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
@ -18,7 +18,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card mt-4">
|
<div class="card mt-4">
|
||||||
<div class="card-header">{{__('Предметы')}}</div>
|
<div class="card-header d-flex justify-content-between align-items-center">
|
||||||
|
{{__('Предметы')}}
|
||||||
|
@can('avgScores', \App\Models\Student::class)
|
||||||
|
<a href="{{ route('export-avg-scores') }}" class="btn btn-primary">Успеваемость</a>
|
||||||
|
@endcan
|
||||||
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@if (count($subjects))
|
@if (count($subjects))
|
||||||
<table class="table table-striped">
|
<table class="table table-striped">
|
||||||
@ -31,21 +36,32 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="table-text">
|
<td class="table-text">
|
||||||
<div>
|
<div>
|
||||||
<a href="{{ route('subjects.show', $subject) }}" class="btn btn-block col-8">{{ $subject->name }}</a>
|
{{ $subject->name }}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
@can('scores', $subject)
|
||||||
<div>
|
<td>
|
||||||
<a href="{{ route('subjects.edit', $subject) }}" class="btn btn-warning">Редактировать</a>
|
<div>
|
||||||
</div>
|
<a href="{{ route('student-scores', $subject) }}" class="btn btn-success">Оценки</a>
|
||||||
</td>
|
</div>
|
||||||
<td>
|
</td>
|
||||||
<form action="{{ route('subjects.destroy', $subject) }}" method="POST" style="display: inline-block;">
|
@endcan
|
||||||
@csrf
|
@can('update', $subject)
|
||||||
@method('DELETE')
|
<td>
|
||||||
<button type="submit" class="btn btn-danger">Удалить</button>
|
<div>
|
||||||
</form>
|
<a href="{{ route('subjects.edit', $subject) }}" class="btn btn-warning">Редактировать</a>
|
||||||
</td>
|
</div>
|
||||||
|
</td>
|
||||||
|
@endcan
|
||||||
|
@can('delete', $subject)
|
||||||
|
<td>
|
||||||
|
<form action="{{ route('subjects.destroy', $subject) }}" method="POST" style="display: inline-block;">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-danger">Удалить</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
@endcan
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -55,7 +71,12 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
<div class="card-footer">
|
||||||
<a href="{{ route('subjects.create') }}" class="btn btn-success">Добавить</a>
|
@can('create', \App\Models\Subject::class)
|
||||||
|
<a href="{{ route('subjects.create') }}" class="btn btn-success">Добавить</a>
|
||||||
|
@endcan
|
||||||
|
@can('pdf', \App\Models\Subject::class)
|
||||||
|
<a href="{{ route('export-pdf') }}" class="btn btn-info">PDF</a>
|
||||||
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">{{ $subjects->links() }}</div>
|
<div class="card-footer">{{ $subjects->links() }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
43
resources/views/subjects/pdf.blade.php
Normal file
43
resources/views/subjects/pdf.blade.php
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
|
<style>
|
||||||
|
* { font-family: DejaVu Sans !important; }
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid black;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: 8px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<title>Информация о предметах</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Информация о предметах</h1>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Предмет</th>
|
||||||
|
<th>ФИО учителя</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($subjects as $subject)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $subject['subject'] }}</td>
|
||||||
|
<td>{{ $subject['teacher'] }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -31,21 +31,36 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td class="table-text">
|
<td class="table-text">
|
||||||
<div>
|
<div>
|
||||||
<a href="{{ route('teachers.show', $teacher) }}" class="btn btn-block col-8">{{ $teacher->last_name }} {{ $teacher->name }} {{ $teacher->middle_name }}</a>
|
@can('view', $teacher)
|
||||||
|
<a href="{{ route('teachers.show', $teacher) }}" class="btn btn-block">{{ $teacher->fio }}</a>
|
||||||
|
@else
|
||||||
|
{{ $teacher->fio }}
|
||||||
|
@endcan
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
@can('teacherSubjects', $teacher)
|
||||||
<div>
|
<td>
|
||||||
<a href="{{ route('teachers.edit', $teacher) }}" class="btn btn-warning">Редактировать</a>
|
<div>
|
||||||
</div>
|
<a href="{{ route('teachers.subjects.index', $teacher) }}" class="btn btn-warning">Предметы</a>
|
||||||
</td>
|
</div>
|
||||||
<td>
|
</td>
|
||||||
<form action="{{ route('teachers.destroy', $teacher) }}" method="POST" style="display: inline-block;">
|
@endcan
|
||||||
@csrf
|
@can('update', $teacher)
|
||||||
@method('DELETE')
|
<td>
|
||||||
<button type="submit" class="btn btn-danger">Удалить</button>
|
<div>
|
||||||
</form>
|
<a href="{{ route('teachers.edit', $teacher) }}" class="btn btn-warning">Редактировать</a>
|
||||||
</td>
|
</div>
|
||||||
|
</td>
|
||||||
|
@endcan
|
||||||
|
@can('delete', $teacher)
|
||||||
|
<td>
|
||||||
|
<form action="{{ route('teachers.destroy', $teacher) }}" method="POST" style="display: inline-block;">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-danger">Удалить</button>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
@endcan
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@endforeach
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -54,9 +69,11 @@
|
|||||||
<p>Учителя отсутствуют</p>
|
<p>Учителя отсутствуют</p>
|
||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer">
|
@can('create', \App\Models\Teacher::class)
|
||||||
<a href="{{ route('teachers.create') }}" class="btn btn-success">Добавить</a>
|
<div class="card-footer">
|
||||||
</div>
|
<a href="{{ route('teachers.create') }}" class="btn btn-success">Добавить</a>
|
||||||
|
</div>
|
||||||
|
@endcan
|
||||||
<div class="card-footer">{{ $teachers->links() }}</div>
|
<div class="card-footer">{{ $teachers->links() }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use App\Http\Controllers\ProfileController;
|
use App\Http\Controllers\ProfileController;
|
||||||
|
use App\Http\Middleware\AdminAction;
|
||||||
|
use App\Http\Middleware\StudentAction;
|
||||||
|
use App\Http\Middleware\TeacherAction;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
use App\Http\Controllers\GradeController;
|
use App\Http\Controllers\GradeController;
|
||||||
use App\Http\Controllers\GradeSubjectController;
|
use App\Http\Controllers\GradeSubjectController;
|
||||||
@ -33,12 +36,27 @@ Route::middleware('auth')->group(function () {
|
|||||||
'grades.lessons' => LessonController::class,
|
'grades.lessons' => LessonController::class,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Route::resource('teachers.subjects', SubjectTeacherController::class)->except('index');
|
Route::middleware([AdminAction::class])->group(function () {
|
||||||
Route::resource('teachers.subjects.grades', GradeTeacherController::class)->except('index', 'show');
|
Route::resource('teachers.subjects', SubjectTeacherController::class)->except('index');
|
||||||
Route::resource('grades.subjects', GradeSubjectController::class)->except('index', 'show');
|
Route::resource('teachers.subjects.grades', GradeTeacherController::class)->except('index', 'show');
|
||||||
Route::get('lessons/{lesson}/scores', [ScoreController::class, 'show'])->name('lessons.scores.show');
|
Route::resource('grades.subjects', GradeSubjectController::class)->except('index', 'show');
|
||||||
Route::put('lessons/{lesson}/scores', [ScoreController::class, 'update'])->name('lessons.scores.update');
|
});
|
||||||
|
|
||||||
|
Route::middleware([TeacherAction::class])->group(function () {
|
||||||
|
Route::get('lessons/{lesson}/scores', [ScoreController::class, 'show'])->name('lessons.scores.show');
|
||||||
|
Route::put('lessons/{lesson}/scores', [ScoreController::class, 'update'])->name('lessons.scores.update');
|
||||||
|
Route::get('grades/{grade}/subjects/{subject}/journal', [GradeSubjectController::class, 'journal'])->name('grades.subjects.journal');
|
||||||
|
Route::get('grades/{grade}/list-students', [GradeController::class, 'listStudents'])->name('list-students');
|
||||||
|
Route::get('grades/{grade}/subjects/{subject}/journal/export-excel', [GradeSubjectController::class, 'exportToExcel'])->name('export-excel');
|
||||||
|
});
|
||||||
|
|
||||||
|
Route::middleware([StudentAction::class])->group(function () {
|
||||||
|
Route::get('export-pdf', [SubjectController::class, 'exportToPDF'])->name('export-pdf');
|
||||||
|
Route::get('subjects/{subject}/student-scores', [StudentController::class, 'scores'])->name('student-scores');
|
||||||
|
Route::get('student-debts', [StudentController::class, 'debts'])->name('student-debts');
|
||||||
|
Route::get('teachers/{teacher}/subjects', [SubjectTeacherController::class, 'index'])->name('teachers.subjects.index');
|
||||||
|
Route::get('export-avg-scores', [StudentController::class, 'exportAvgScores'])->name('export-avg-scores');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
require __DIR__.'/auth.php';
|
require __DIR__.'/auth.php';
|
||||||
|
Loading…
Reference in New Issue
Block a user