mirror of
https://github.com/Dvorinka/PPve.git
synced 2026-06-04 04:22:58 +00:00
c
This commit is contained in:
+134
-140
@@ -1208,30 +1208,32 @@
|
|||||||
|
|
||||||
<!-- Add this new card before the existing cards -->
|
<!-- Add this new card before the existing cards -->
|
||||||
<div class="card" style="margin: 2rem auto; max-width: 1000px;">
|
<div class="card" style="margin: 2rem auto; max-width: 1000px;">
|
||||||
<h3 class="text-xl font-bold mb-4">Správa rezervací vozidel</h3>
|
<h3>Správa rezervací vozidel</h3>
|
||||||
|
|
||||||
<!-- Filters -->
|
<div class="flex justify-between items-center mb-6">
|
||||||
<div class="flex flex-wrap gap-4 mb-4">
|
<div class="space-x-2">
|
||||||
<select id="vehicleFilter" onchange="filterReservations()" class="rounded border p-2">
|
<button class="btn btn-primary" onclick="location.href='/rezervace-aut'">
|
||||||
<option value="">Všechna vozidla</option>
|
<i class="fas fa-calendar-plus mr-2"></i>Nová rezervace
|
||||||
<option value="VW Caddy - 4Z1 8241">VW Caddy - 4Z1 8241</option>
|
</button>
|
||||||
<option value="VW Golf - 5Z5 8694">VW Golf - 5Z5 8694</option>
|
<button class="btn btn-secondary" onclick="exportReservations()">
|
||||||
<option value="Škoda Fabia - 1Z3 5789">Škoda Fabia - 1Z3 5789</option>
|
<i class="fas fa-file-export mr-2"></i>Export
|
||||||
<option value="BMW 218d - 6Z5 4739">BMW 218d - 6Z5 4739</option>
|
|
||||||
<option value="BMW 218d - 6Z5 4740">BMW 218d - 6Z5 4740</option>
|
|
||||||
<option value="Škoda Superb - 2BY 2398">Škoda Superb - 2BY 2398</option>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<input type="date" id="dateFilter" onchange="filterReservations()" class="rounded border p-2">
|
|
||||||
|
|
||||||
<button onclick="exportReservations()" class="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700">
|
|
||||||
<i class="fas fa-file-excel mr-2"></i>Exportovat do Excel
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<select id="vehicleFilter" class="form-control" onchange="filterReservations()">
|
||||||
|
<option value="">Všechna vozidla</option>
|
||||||
|
<option value="VW Caddy">VW Caddy</option>
|
||||||
|
<option value="VW Golf">VW Golf</option>
|
||||||
|
<option value="Škoda Fabia">Škoda Fabia</option>
|
||||||
|
<option value="BMW 218d">BMW 218d</option>
|
||||||
|
<option value="Škoda Superb">Škoda Superb</option>
|
||||||
|
</select>
|
||||||
|
<input type="date" id="dateFilter" class="form-control" onchange="filterReservations()">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Reservations Table -->
|
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
<table id="reservationsTable" class="min-w-full bg-white">
|
<table class="min-w-full divide-y divide-gray-200">
|
||||||
<thead class="bg-gray-50">
|
<thead class="bg-gray-50">
|
||||||
<tr>
|
<tr>
|
||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Řidič</th>
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Řidič</th>
|
||||||
@@ -1239,11 +1241,11 @@
|
|||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Od</th>
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Od</th>
|
||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Do</th>
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Do</th>
|
||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Účel</th>
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Účel</th>
|
||||||
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Doba trvání</th>
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Akce</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody id="reservationsTable" class="bg-white divide-y divide-gray-200">
|
||||||
<!-- Reservations will be loaded here -->
|
<!-- Reservations will be populated here -->
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@@ -4267,16 +4269,33 @@ function preventDefaults(e) {
|
|||||||
// Function to load and display reservations
|
// Function to load and display reservations
|
||||||
async function loadReservations() {
|
async function loadReservations() {
|
||||||
const tbody = document.querySelector('#reservationsTable tbody');
|
const tbody = document.querySelector('#reservationsTable tbody');
|
||||||
if (!tbody) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/reservations');
|
const response = await fetch('/api/reservations');
|
||||||
if (!response.ok) throw new Error('Failed to load reservations');
|
if (!response.ok) throw new Error('Failed to load reservations');
|
||||||
|
|
||||||
const reservations = await response.json();
|
const reservations = await response.json();
|
||||||
window.allReservations = reservations;
|
window.allReservations = reservations; // Store for filtering
|
||||||
|
|
||||||
if (!reservations || reservations.length === 0) {
|
displayReservations(reservations);
|
||||||
|
updateVehicleFilter(reservations);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading reservations:', error);
|
||||||
|
tbody.innerHTML = `
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="px-6 py-4 text-center text-red-500">
|
||||||
|
Chyba při načítání rezervací: ${error.message}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to display reservations
|
||||||
|
function displayReservations(reservations) {
|
||||||
|
const tbody = document.querySelector('#reservationsTable tbody');
|
||||||
|
if (!tbody) return;
|
||||||
|
|
||||||
|
if (!reservations.length) {
|
||||||
tbody.innerHTML = `
|
tbody.innerHTML = `
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="px-6 py-4 text-center text-gray-500">
|
<td colspan="6" class="px-6 py-4 text-center text-gray-500">
|
||||||
@@ -4287,44 +4306,95 @@ async function loadReservations() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody.innerHTML = reservations.map(res => {
|
tbody.innerHTML = reservations.map(res => `
|
||||||
const start = new Date(`${res.startDate}T${res.startTime}`);
|
|
||||||
const end = new Date(`${res.endDate}T${res.endTime}`);
|
|
||||||
const duration = calculateDuration(start, end);
|
|
||||||
|
|
||||||
return `
|
|
||||||
<tr class="hover:bg-gray-50">
|
<tr class="hover:bg-gray-50">
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${res.driverName}</td>
|
<td class="px-6 py-4">${res.driverName}</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${res.vehicle}</td>
|
<td class="px-6 py-4">${res.vehicle}</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${formatDateTime(res.startDate, res.startTime)}</td>
|
<td class="px-6 py-4">${formatDateTime(res.startDate, res.startTime)}</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${formatDateTime(res.endDate, res.endTime)}</td>
|
<td class="px-6 py-4">${formatDateTime(res.endDate, res.endTime)}</td>
|
||||||
<td class="px-6 py-4">${res.purpose || '-'}</td>
|
<td class="px-6 py-4">${res.purpose || '-'}</td>
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${duration}</td>
|
<td class="px-6 py-4">${calculateDuration(res)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
`;
|
`).join('');
|
||||||
}).join('');
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error loading reservations:', error);
|
|
||||||
tbody.innerHTML = `
|
|
||||||
<tr>
|
|
||||||
<td colspan="6" class="px-6 py-4 text-center text-red-500">
|
|
||||||
Chyba při načítání rezervací
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to filter reservations
|
||||||
|
function filterReservations() {
|
||||||
|
if (!window.allReservations) return;
|
||||||
|
|
||||||
|
const vehicleFilter = document.getElementById('vehicleFilter').value;
|
||||||
|
const dateFilter = document.getElementById('dateFilter').value;
|
||||||
|
|
||||||
|
let filtered = window.allReservations;
|
||||||
|
|
||||||
|
if (vehicleFilter) {
|
||||||
|
filtered = filtered.filter(res => res.vehicle === vehicleFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dateFilter) {
|
||||||
|
filtered = filtered.filter(res => res.startDate === dateFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayReservations(filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to export reservations to Excel
|
||||||
|
function exportReservations() {
|
||||||
|
if (!window.allReservations || !window.allReservations.length) {
|
||||||
|
showNotification('Žádné rezervace k exportu', 'warning');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get filtered reservations
|
||||||
|
const vehicleFilter = document.getElementById('vehicleFilter').value;
|
||||||
|
const dateFilter = document.getElementById('dateFilter').value;
|
||||||
|
|
||||||
|
let dataToExport = window.allReservations;
|
||||||
|
if (vehicleFilter) {
|
||||||
|
dataToExport = dataToExport.filter(res => res.vehicle === vehicleFilter);
|
||||||
|
}
|
||||||
|
if (dateFilter) {
|
||||||
|
dataToExport = dataToExport.filter(res => res.startDate === dateFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create CSV content
|
||||||
|
const headers = ['Řidič', 'Vozidlo', 'Datum od', 'Čas od', 'Datum do', 'Čas do', 'Účel', 'Doba trvání'];
|
||||||
|
const csvContent = [
|
||||||
|
headers.join(','),
|
||||||
|
...dataToExport.map(res => [
|
||||||
|
`"${res.driverName}"`,
|
||||||
|
`"${res.vehicle}"`,
|
||||||
|
res.startDate,
|
||||||
|
res.startTime,
|
||||||
|
res.endDate,
|
||||||
|
res.endTime,
|
||||||
|
`"${res.purpose || ''}"`,
|
||||||
|
`"${calculateDuration(res)}"`
|
||||||
|
].join(','))
|
||||||
|
].join('\n');
|
||||||
|
|
||||||
|
// Create and trigger download
|
||||||
|
const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' });
|
||||||
|
const link = document.createElement('a');
|
||||||
|
const date = new Date().toISOString().split('T')[0];
|
||||||
|
link.href = URL.createObjectURL(blob);
|
||||||
|
link.download = `rezervace_${date}.csv`;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to format date and time
|
// Helper function to format date and time
|
||||||
function formatDateTime(date, time) {
|
function formatDateTime(date, time) {
|
||||||
const [year, month, day] = date.split('-');
|
return `${date} ${time}`;
|
||||||
return `${day}.${month}.${year} ${time}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to calculate duration
|
// Helper function to calculate duration
|
||||||
function calculateDuration(start, end) {
|
function calculateDuration(reservation) {
|
||||||
|
const start = new Date(`${reservation.startDate}T${reservation.startTime}`);
|
||||||
|
const end = new Date(`${reservation.endDate}T${reservation.endTime}`);
|
||||||
const diff = end - start;
|
const diff = end - start;
|
||||||
|
|
||||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
|
||||||
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
|
||||||
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
|
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
|
||||||
@@ -4337,99 +4407,23 @@ function calculateDuration(start, end) {
|
|||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to export to Excel
|
// Function to update vehicle filter options
|
||||||
function exportReservations() {
|
function updateVehicleFilter(reservations) {
|
||||||
if (!window.allReservations || window.allReservations.length === 0) {
|
const vehicleFilter = document.getElementById('vehicleFilter');
|
||||||
showNotification('Žádné rezervace k exportu', 'warning');
|
if (!vehicleFilter) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const reservations = filterReservations(true);
|
const vehicles = [...new Set(reservations.map(r => r.vehicle))];
|
||||||
const headers = ['Řidič', 'Vozidlo', 'Datum od', 'Čas od', 'Datum do', 'Čas do', 'Účel', 'Doba trvání'];
|
vehicleFilter.innerHTML = `
|
||||||
|
<option value="">Všechna vozidla</option>
|
||||||
let csvContent = '\ufeff' + headers.join(',') + '\n';
|
${vehicles.map(v => `<option value="${v}">${v}</option>`).join('')}
|
||||||
|
|
||||||
csvContent += reservations.map(res => {
|
|
||||||
const start = new Date(`${res.startDate}T${res.startTime}`);
|
|
||||||
const end = new Date(`${res.endDate}T${res.endTime}`);
|
|
||||||
const duration = calculateDuration(start, end);
|
|
||||||
|
|
||||||
return [
|
|
||||||
`"${res.driverName}"`,
|
|
||||||
`"${res.vehicle}"`,
|
|
||||||
res.startDate,
|
|
||||||
res.startTime,
|
|
||||||
res.endDate,
|
|
||||||
res.endTime,
|
|
||||||
`"${res.purpose || ''}"`,
|
|
||||||
`"${duration}"`
|
|
||||||
].join(',');
|
|
||||||
}).join('\n');
|
|
||||||
|
|
||||||
const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
||||||
const link = document.createElement('a');
|
|
||||||
link.href = URL.createObjectURL(blob);
|
|
||||||
link.download = `rezervace_${new Date().toISOString().split('T')[0]}.csv`;
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
document.body.removeChild(link);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to filter reservations
|
|
||||||
function filterReservations(returnData = false) {
|
|
||||||
if (!window.allReservations) return returnData ? [] : null;
|
|
||||||
|
|
||||||
const vehicleFilter = document.getElementById('vehicleFilter').value;
|
|
||||||
const dateFilter = document.getElementById('dateFilter').value;
|
|
||||||
|
|
||||||
let filtered = window.allReservations;
|
|
||||||
|
|
||||||
if (vehicleFilter) {
|
|
||||||
filtered = filtered.filter(res => res.vehicle === vehicleFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dateFilter) {
|
|
||||||
filtered = filtered.filter(res => res.startDate === dateFilter || res.endDate === dateFilter);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (returnData) return filtered;
|
|
||||||
|
|
||||||
const tbody = document.querySelector('#reservationsTable tbody');
|
|
||||||
if (tbody) {
|
|
||||||
if (filtered.length === 0) {
|
|
||||||
tbody.innerHTML = `
|
|
||||||
<tr>
|
|
||||||
<td colspan="6" class="px-6 py-4 text-center text-gray-500">
|
|
||||||
Žádné rezervace odpovídající filtru
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
`;
|
`;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tbody.innerHTML = filtered.map(res => {
|
|
||||||
const start = new Date(`${res.startDate}T${res.startTime}`);
|
|
||||||
const end = new Date(`${res.endDate}T${res.endTime}`);
|
|
||||||
const duration = calculateDuration(start, end);
|
|
||||||
|
|
||||||
return `
|
|
||||||
<tr class="hover:bg-gray-50">
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${res.driverName}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${res.vehicle}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${formatDateTime(res.startDate, res.startTime)}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${formatDateTime(res.endDate, res.endTime)}</td>
|
|
||||||
<td class="px-6 py-4">${res.purpose || '-'}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${duration}</td>
|
|
||||||
</tr>
|
|
||||||
`;
|
|
||||||
}).join('');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load reservations when page loads
|
// Load reservations when page loads
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// ...existing code...
|
||||||
loadReservations();
|
loadReservations();
|
||||||
// Set today's date as default for date filter
|
|
||||||
const today = new Date().toISOString().split('T')[0];
|
|
||||||
document.getElementById('dateFilter').value = today;
|
|
||||||
});
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
+1
-13
@@ -431,19 +431,7 @@
|
|||||||
|
|
||||||
<!-- Apps Grid -->
|
<!-- Apps Grid -->
|
||||||
<div id="appsGrid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
<div id="appsGrid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
|
||||||
<!-- Add Rezervace aut card before other hardcoded apps -->
|
<!-- Hardcoded apps -->
|
||||||
<div class="card bg-white rounded-xl shadow p-6 border-t-4 border-indigo-600" data-name="rezervace aut vozidel kalendar" data-id="hardcoded-rezervace">
|
|
||||||
<div class="rounded-full w-14 h-14 flex items-center justify-center bg-indigo-100 text-indigo-600 mb-4">
|
|
||||||
<i class="fas fa-calendar-alt text-2xl"></i>
|
|
||||||
</div>
|
|
||||||
<h2 class="text-xl font-bold text-gray-800 mb-2">Rezervace vozidel</h2>
|
|
||||||
<p class="text-gray-600 mb-4">Kalendář pro rezervaci služebních vozidel a plánování jízd</p>
|
|
||||||
<a href="/rezervace-aut" class="block text-center bg-indigo-600 hover:bg-indigo-700 text-white font-medium py-2 px-4 rounded-lg transition-colors">
|
|
||||||
Otevřít aplikaci
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Other hardcoded apps -->
|
|
||||||
<div class="card bg-white rounded-xl shadow p-6 border-t-4 border-blue-600" data-name="zápis cest aut project" data-id="hardcoded-car">
|
<div class="card bg-white rounded-xl shadow p-6 border-t-4 border-blue-600" data-name="zápis cest aut project" data-id="hardcoded-car">
|
||||||
<div class="rounded-full w-14 h-14 flex items-center justify-center bg-blue-100 text-blue-600 mb-4">
|
<div class="rounded-full w-14 h-14 flex items-center justify-center bg-blue-100 text-blue-600 mb-4">
|
||||||
<i class="fas fa-car-side text-2xl"></i>
|
<i class="fas fa-car-side text-2xl"></i>
|
||||||
|
|||||||
Reference in New Issue
Block a user