export to xlsx added, map preview fixed

This commit is contained in:
s416422 2019-12-14 22:03:41 +01:00
parent fa2f05b01f
commit 2ed41c54df
20 changed files with 276 additions and 68 deletions

View File

@ -0,0 +1,27 @@
<?php
namespace App\Exports;
use App\Attendance;
use Maatwebsite\Excel\Concerns\FromView;
use Illuminate\Contracts\View\View;
class AttendanceExportView implements FromView
{
/**
* @return \Illuminate\Support\Collection
*/
private $classes_id;
public function __construct($classes_id)
{
$this->classes_id = $classes_id;
}
public function view(): View
{
$attendances = Attendance::where('classes_id', $this->classes_id)->get();
return view('user.attendances_table_preview', ['attendances' => $attendances]);
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Exports;
use App\Subject;
use App\Classes;
use Maatwebsite\Excel\Concerns\FromView;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\WithTitle;
class AttendanceGroupedExportSingleView implements FromView, WithTitle
{
/**
* @return \Illuminate\Support\Collection
*/
private $attendances;
private $groupBy;
private $groupedValue;
public function __construct($attendances, $groupBy, $groupedValue)
{
$this->attendances = $attendances;
$this->groupBy = $groupBy;
$this->groupedValue = $groupedValue;
}
public function view(): View
{
return view('user.attendances_table', ['attendances_list' => $this->attendances, 'export' => 1]);
}
public function title(): string
{
if($this->groupBy == 'classes_id') {
$subject = Subject::find(Classes::find($this->groupedValue)->subject_id)->name;
$date = Classes::find($this->groupedValue)->date;
$this->groupedValue = "{$subject} {$date}";
}
return str_replace(":", "-", "{$this->groupedValue}");
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace App\Exports;
use App\Attendance;
use App\Subject;
use App\Classes;
use Illuminate\Support\Facades\Auth;
use Illuminate\Contracts\View\View;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithMultipleSheets;
class AttendanceGroupedExportView implements WithMultipleSheets
{
/**
* @return \Illuminate\Support\Collection
*/
use Exportable;
private $groupBy;
public function __construct($groupBy)
{
$this->groupBy = $groupBy;
}
public function sheets(): array
{
$user_id = Auth::id();
$subjects = Subject::where('user_id', $user_id)->get();
$subjects_ids = $subjects->pluck('id')->toArray();
$classes = Classes::whereIn('subject_id', $subjects_ids)->orderBy('created_at','DESC')->get();
$classes_ids = $classes->pluck('id')->toArray();
$attendances = Attendance::whereIn('classes_id', $classes_ids)->get();
$attendances_grouped = $attendances->groupBy($this->groupBy);
foreach ($attendances_grouped as $attendances_group_name => $attendances_list) {
$sheets[] = new AttendanceGroupedExportSingleView($attendances_list, $this->groupBy, $attendances_group_name);
}
return $sheets;
}
}

View File

@ -5,6 +5,9 @@ namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller; use App\Http\Controllers\Controller;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Auth;
use App\Exports\AttendanceExportView;
use App\Exports\AttendanceGroupedExportView;
use Maatwebsite\Excel\Facades\Excel;
use App\Subject; use App\Subject;
use App\Classes; use App\Classes;
@ -52,4 +55,21 @@ class UserAttendancesController extends Controller
Attendance::find($attendance_id); Attendance::find($attendance_id);
return redirect(route('user_attendances')); return redirect(route('user_attendances'));
} }
public function export($classes_id)
{
$classes_date = Classes::find($classes_id)->date;
return Excel::download(new AttendanceExportView($classes_id), "classes-attendance-{$classes_date}.xlsx");
}
public function export_grouped($groupBy)
{
$today_date = date('Y-m-d');
$groupByLabel = str_replace("_", "-", $groupBy);
if($groupBy == 'classes_id') {
$groupByLabel = 'classes_name';
}
return Excel::download(new AttendanceGroupedExportView($groupBy), "all-attendance-grouped-by-{$groupByLabel}-{$today_date}.xlsx");
}
} }

View File

@ -109,12 +109,13 @@ class UserClassesController extends Controller
if(!$classes_id == 0) { if(!$classes_id == 0) {
$classes = Classes::find($classes_id); $classes = Classes::find($classes_id);
$attendances = Attendance::where('classes_id', $classes->id)->get(); $attendances = Attendance::where('classes_id', $classes->id)->get();
$seat_numbers = $attendances->pluck('seat_number')->toArray();
$subject = Subject::find($classes->subject_id); $subject = Subject::find($classes->subject_id);
$room_arrangement = Room::find($subject->room_id)->arrangement; $room_arrangement = Room::find($subject->room_id)->arrangement;
if(!$room_arrangement) { if(!$room_arrangement) {
$room_arrangement = Room::where('name', 'Inna sala')->first()->arrangement; $room_arrangement = Room::where('name', 'Inna sala')->first()->arrangement;
} }
} }
return view('user.user_preview_classes', ['classes_id' => $classes_id, 'room_arrangement' => $room_arrangement, 'attendances' => $attendances]); return view('user.user_preview_classes', ['classes_id' => $classes_id, 'room_arrangement' => $room_arrangement, 'attendances' => $attendances, 'seat_numbers' => $seat_numbers]);
} }
} }

View File

@ -12,7 +12,8 @@
"fideloper/proxy": "^4.0", "fideloper/proxy": "^4.0",
"laravel/framework": "^6.2", "laravel/framework": "^6.2",
"laravel/tinker": "^1.0", "laravel/tinker": "^1.0",
"laravel/ui": "^1.1" "laravel/ui": "^1.1",
"maatwebsite/excel": "^3.1"
}, },
"require-dev": { "require-dev": {
"facade/ignition": "^1.4", "facade/ignition": "^1.4",

View File

@ -165,7 +165,7 @@ return [
/* /*
* Package Service Providers... * Package Service Providers...
*/ */
Maatwebsite\Excel\ExcelServiceProvider::class,
/* /*
* Application Service Providers... * Application Service Providers...
*/ */

View File

@ -11193,3 +11193,6 @@ a.text-dark:focus {
.nav-link:hover { .nav-link:hover {
transform: scale(1.1); transform: scale(1.1);
} }
.btn-export {
background-color: #649a24;
}

View File

@ -84,7 +84,7 @@ button:active {
background-color: #3654ff; background-color: #3654ff;
} }
a.checkout-button { a.checkout-button {
color: black; color: #fff;
text-decoration: none; text-decoration: none;
} }
.add-mn-btn { .add-mn-btn {

View File

@ -113,6 +113,7 @@ body {
display: inline-block; display: inline-block;
text-align: center; text-align: center;
box-shadow:0px 4px 0px #1e3572; box-shadow:0px 4px 0px #1e3572;
color: #fff;
} }
.checkout-button:hover { .checkout-button:hover {
@ -127,7 +128,7 @@ body {
background-color: #3654ff; background-color: #3654ff;
} }
a.checkout-button { a.checkout-button {
color: black; color: #fff;
text-decoration: none; text-decoration: none;
} }
.map-buttons { .map-buttons {

View File

@ -1,7 +1,6 @@
.add-mn-btn, .end-button { .add-mn-btn, .end-button {
display: none; display: none;
} }
.preview-page-content { .preview-page-content {
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -38,3 +37,28 @@
.preview-name { .preview-name {
color: rgba(0,0,0,0.7); color: rgba(0,0,0,0.7);
} }
.front-indicator-preview {
display: flex;
align-items: center;
justify-content: center;
}
.preview-box {
display: flex;
align-items: center;
}
.checkout-button-preview {
justify-content: flex-start;
width: 40%;
padding-left: 35px;
}
.seat-p-ppreview {
justify-content: center;
width: 60%;
padding: 0 auto;
}
div.seatCharts-seat.available {
background-color: rgba(111,120,129, 0.7);
}
div.seatCharts-seat.taken {
background-color: #649a24;
}

View File

@ -48,7 +48,7 @@ a {
} }
.booking-details h2 { .booking-details h2 {
margin: 25px 0 20px 0; margin: 25px 0 20px 0;
font-size: 35px; font-size: 22px;
color: #333333; color: #333333;
letter-spacing: 0.15em; letter-spacing: 0.15em;
font-weight: bold; font-weight: bold;
@ -135,7 +135,7 @@ span.seatCharts-legendDescription {
border-color: #2176bd; border-color: #2176bd;
} }
a.checkout-button { a.checkout-button {
color: black; color: #fff;
text-decoration: none; text-decoration: none;
} }

View File

@ -5,7 +5,7 @@ function assignPlaces() {
const name = $(this).attr('id').split('++')[1]; const name = $(this).attr('id').split('++')[1];
const surname = $(this).attr('id').split('++')[2]; const surname = $(this).attr('id').split('++')[2];
const map_seat = $('#seat-map').find(`#${seat_number}`); const map_seat = $('#seat-map').find(`#${seat_number}`);
map_seat.html(`<b>${seat_number}</b><br><span class="preview-name">${name} ${surname}</span>`) map_seat.html(`<b>${seat_number}</b> <br><span class="preview-name">${name} ${surname}</span>`)
map_seat.on('mouseover', () => { map_seat.on('mouseover', () => {
map_seat.css('backgroundColor', 'lightgrey'); map_seat.css('backgroundColor', 'lightgrey');
$(this).css('backgroundColor', 'lightgrey'); $(this).css('backgroundColor', 'lightgrey');
@ -23,6 +23,24 @@ function assignPlaces() {
}) })
} }
function checkForUnavailablePlaces() {
const unavailablePlaces = Array();
$('.unavailable_place').each(function(){
unavailablePlaces.push($(this).val());
});
const allPlaces = $('.seatCharts-seat.seatCharts-cell.available');
if(unavailablePlaces){
allPlaces.each(function(){
if(unavailablePlaces.includes($(this).text().split(" ")[0]) && !$(this).parent().hasClass('seatCharts-legendItem')) {
$(this).addClass('taken');
console.log($(this));
}
});
}
}
$(document).ready(function(){ $(document).ready(function(){
assignPlaces(); assignPlaces();
checkForUnavailablePlaces();
}); });

View File

@ -16,20 +16,21 @@
@endif @endif
@section('user_content') @section('user_content')
<h4> Garść przydatnych informacji </h4> <h4> Garść przydatnych informacji </h4>
<p> W zakładce <b>Moje przedmioty</b> znajdują się przedmioty, których jesteś prowadzącym. <p> W zakładce <a href="{{ route('user_subjects') }}"> <b>Moje przedmioty</b> </a> znajdują się przedmioty, których jesteś prowadzącym.
<br>Możesz tam także dodać nowy przedmiot. <br>Przedmioty możesz grupować i usuwać. Możesz także dodać nowy przedmiot.
</p> </p>
<p></p> <p></p>
<p> Sprawdzanie obecności możesz rozpocząć w zakładce <b>Sprawdź obecność</b>. <p> Sprawdzanie obecności możesz rozpocząć w zakładce <a href="{{ route('user_classes') }}"><b>Sprawdź obecność</b></a>.
<br> Po rozpoczęciu zapisów zostanie wygenerowany i wyświetlony na ekranie kod weryfikacyjny. <br> Po rozpoczęciu zapisów zostanie wygenerowany i wyświetlony na ekranie kod weryfikacyjny.
Należy go wprowadzić do programu obsługującego odczyt danych z legitymacji studenckich. Należy go wprowadzić do programu obsługującego odczyt danych z legitymacji studenckich.
Kod jest ważny 1,5 godziny od momentu utworzenia zajęć. Kod jest ważny 1,5 godziny od momentu utworzenia zajęć.
Dopóki kod jest aktywny, zapisy można przerywać i ponownie kontynuować, gdy zajdzie taka potrzeba. Dopóki kod jest aktywny, zapisy można przerywać i ponownie kontynuować, gdy zajdzie taka potrzeba.
<br> W tej zakładce znajdziesz także listę wszystkich minionych zajęć. <br> W tej zakładce znajdziesz także listę wszystkich minionych zajęć.
<br> W każdym momencie możesz zobaczyć podgląd sali i listę obecności dla konkretnych zajęć. <br> W każdym momencie możesz zobaczyć podgląd sali i listę obecności dla konkretnych zajęć. Taką listę możesz wyeksportować do formatu xlsx.
</p> </p>
<p> <p>
Dane dotyczące obecności znajdziesz także w zakładce <b>Obecności</b>. Dane dotyczące obecności znajdziesz także w zakładce <a href="{{ route('user_attendances') }}"><b>Obecności</b></a>.
<br> Rekordy dotyczące wszystkich obecności możesz grupować i wyeksportować. Przy eksporcie każda tabela-grupa trafi do pliku xlsx jako osobny arkusz.
</p> </p>
@endsection @endsection
@yield('user_content') @yield('user_content')

View File

@ -10,8 +10,8 @@
<title>@CHECK | @yield('title')</title> <title>@CHECK | @yield('title')</title>
<!-- Scripts --> <!-- Scripts -->
<script src="{{ secure_asset('js/app.js') }}" defer></script> <script src="{{ asset('js/app.js') }}" defer></script>
<script src="{{ secure_asset('js/custom.js') }}" defer></script> <script src="{{ asset('js/custom.js') }}" defer></script>
<!-- Fonts --> <!-- Fonts -->
@ -19,8 +19,8 @@
<link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Nunito" rel="stylesheet">
<!-- Styles --> <!-- Styles -->
<link href="{{ secure_asset('css/app.css') }}" rel="stylesheet"> <link href="{{ asset('css/app.css') }}" rel="stylesheet">
<link rel="shortcut icon" href="{{ secure_asset('img/favicon.png') }}"> <link rel="shortcut icon" href="{{ asset('img/favicon.png') }}">
@yield('main_meta') @yield('main_meta')
</head> </head>

View File

@ -0,0 +1,31 @@
<table class="table table-striped subjects-table">
<tr class="thead-dark">
@if(!$export == 1)
<th> Nazwa zajęć </th>
@endif
<th> Nr indeksu </th>
<th> Imię </th>
<th> Nazwisko </th>
<th> Nr miejsca </th>
@if(!$export == 1)
<th></th>
@endif
</tr>
@foreach ($attendances_list as $attendance)
<tr>
@if(!$export == 1)
<td> {{ App\Subject::find(App\Classes::find($attendance->classes_id)->subject_id)->name }},
{{ App\Classes::find($attendance->classes_id)-> date }} {{ App\Subject::find(App\Classes::find($attendance->classes_id)->subject_id)->time }}, sala {{ App\Room::find(App\Subject::find(App\Classes::find($attendance->classes_id)->subject_id)->room_id)->name }} </td>
@endif
<td> {{ $attendance->student_id_number }} </td>
<td> {{ $attendance->student_name}}</td>
<td> {{ $attendance->student_surname}}</td>
<td> {{ $attendance->seat_number }} </td>
@if(!$export == 1)
<td>
<a href="{{ route('user_delete_attendance', [$attendance->id]) }}" name="delete-attendance-btn" class="btn btn-danger"> Usuń </a>
</td>
@endif
</tr>
@endforeach
</table>

View File

@ -0,0 +1,17 @@
<table class="table subjects-table">
<tr class="thead-light">
<th> Nr indeksu </th>
<th> Imię </th>
<th> Nazwisko </th>
<th> Nr miejsca </th>
</tr>
@foreach ($attendances as $attendance)
<tr class="attendance-id" id="{{ $attendance->seat_number }}++{{ $attendance->student_name}}++{{ $attendance->student_surname}}">
<td> {{ $attendance->student_id_number }} </td>
<td> {{ $attendance->student_name}}</td>
<td> {{ $attendance->student_surname}}</td>
<td> {{ $attendance->seat_number }} </td>
</tr>
@endforeach
</table>

View File

@ -108,8 +108,11 @@
<a href="{{ route('user_attendances', ['classes_id']) }}" class="btn btn-primary"> po nazwie zajęć </a> <a href="{{ route('user_attendances', ['classes_id']) }}" class="btn btn-primary"> po nazwie zajęć </a>
<a href="{{ route('user_attendances', ['student_id_number']) }}" class="btn btn-primary"> po numerze indeksu </a> <a href="{{ route('user_attendances', ['student_id_number']) }}" class="btn btn-primary"> po numerze indeksu </a>
<a href="{{ route('user_attendances', ['seat_number']) }}" class="btn btn-primary"> po numerze miejsca </a> <a href="{{ route('user_attendances', ['seat_number']) }}" class="btn btn-primary"> po numerze miejsca </a>
<a href="{{ route('user_export_grouped', [$grouped_by]) }}" class="btn btn-success btn-export"> Wyeksportuj do xlsx </a>
</div> </div>
<div class="card-body"> <div class="card-body">
@foreach ($attendances_grouped as $attendances_group_name => $attendances_list) @foreach ($attendances_grouped as $attendances_group_name => $attendances_list)
@if($attendances_group_name) @if($attendances_group_name)
@if($grouped_by == 'classes_id') @if($grouped_by == 'classes_id')
@ -122,31 +125,7 @@
@else @else
<h5 class="card-title"> Inne ({{ $attendances_list->count() }})</h5> <h5 class="card-title"> Inne ({{ $attendances_list->count() }})</h5>
@endif @endif
@include('user.attendances_table', ['attendances_list' => $attendances_list, 'export' => 0])
<table class="table table-striped subjects-table">
<tr class="thead-dark">
<th> Nazwa zajęć </th>
<th> Nr indeksu </th>
<th> Imię </th>
<th> Nazwisko </th>
<th> Nr miejsca </th>
<th></th>
<th></th>
</tr>
@foreach ($attendances_list as $attendance)
<tr>
<td> {{ App\Subject::find(App\Classes::find($attendance->classes_id)->subject_id)->name }},
{{ App\Classes::find($attendance->classes_id)-> date }} {{ App\Subject::find(App\Classes::find($attendance->classes_id)->subject_id)->time }}, sala {{ App\Room::find(App\Subject::find(App\Classes::find($attendance->classes_id)->subject_id)->room_id)->name }} </td>
<td> {{ $attendance->student_id_number }} </td>
<td> {{ $attendance->student_name}}</td>
<td> {{ $attendance->student_surname}}</td>
<td> {{ $attendance->seat_number }} </td>
<td>
<a href="{{ route('user_delete_attendance', [$attendance->id]) }}" name="delete-attendance-btn" class="btn btn-danger"> Usuń </a>
</td>
</tr>
@endforeach
</table>
@endforeach @endforeach
</div> </div>
@else @else

View File

@ -11,7 +11,11 @@
@endsection @endsection
@section('map_content') @section('map_content')
<div class="front-indicator"> <div class="front-indicator front-indicator-preview">
<div class="preview-box checkout-button-preview">
<a href="{{ route('user_classes') }}" class="checkout-button"> Zakończ podgląd </a>
</div>
<div class="preview-box seat-p-ppreview">
<p class="seat-p"> <p class="seat-p">
{{ App\Subject::find(App\Classes::find($classes_id)->subject_id)->name }}, {{ App\Subject::find(App\Classes::find($classes_id)->subject_id)->name }},
{{ App\Subject::find(App\Classes::find($classes_id)->subject_id)->weekday }} {{ App\Subject::find(App\Classes::find($classes_id)->subject_id)->weekday }}
@ -19,33 +23,24 @@
<b>sala {{ App\Room::find(App\Subject::find(App\Classes::find($classes_id)->subject_id)->room_id)->name }}</b> <b>sala {{ App\Room::find(App\Subject::find(App\Classes::find($classes_id)->subject_id)->room_id)->name }}</b>
</p> </p>
</div> </div>
</div>
<div class="preview-page-content"> <div class="preview-page-content">
<div class="preview-attendance-table"> <div class="preview-attendance-table">
<div class="card-header custom-header"> <div class="card-header custom-header">
<h4> Lista obecności </h4> <h4> Lista obecności </h4>
<a href="{{ route('user_export', [$classes_id]) }}"class="btn btn-success btn-export"> Wyeksportuj do xlsx </a>
</div> </div>
<table class="table subjects-table">
<tr class="thead-light">
<th> Nr indeksu </th>
<th> Imię </th>
<th> Nazwisko </th>
<th> Nr miejsca </th>
</tr>
@foreach ($attendances as $attendance)
<tr class="attendance-id" id="{{ $attendance->seat_number }}++{{ $attendance->student_name}}++{{ $attendance->student_surname}}">
<td> {{ $attendance->student_id_number }} </td>
<td> {{ $attendance->student_name}}</td>
<td> {{ $attendance->student_surname}}</td>
<td> {{ $attendance->seat_number }} </td>
</tr>
@endforeach
</table>
@include('user.attendances_table_preview', $attendances)
</div> </div>
<div class="seat-chart-wrapper"> <div class="seat-chart-wrapper">
<div id="seat-map"></div> <div id="seat-map"></div>
<input type="hidden" class="room_arrangement" name="room_arrangement" id="room_arrangement" value="{{ $room_arrangement }}"> <input type="hidden" class="room_arrangement" name="room_arrangement" id="room_arrangement" value="{{ $room_arrangement }}">
</div> </div>
@foreach($seat_numbers as $seat_number)
<input type="hidden" class="unavailable_place" value="{{ $seat_number }}">
@endforeach
</div> </div>
@endsection @endsection

View File

@ -77,6 +77,8 @@ Route::group(array('prefix' => 'user', 'namespace' => 'User'), function() { //TO
Route::get('/attendance/{attendance_id}/{groupBy?}', 'UserAttendancesController@edit_attendance')->name('user_edit_attendance'); Route::get('/attendance/{attendance_id}/{groupBy?}', 'UserAttendancesController@edit_attendance')->name('user_edit_attendance');
}); });
Route::get('/export/attendances/{classes_id}', 'UserAttendancesController@export')->name('user_export');
Route::get('/export/attendances/grouped/{groupBy}', 'UserAttendancesController@export_grouped')->name('user_export_grouped');
}); });