mirror of
https://github.com/Dvorinka/PPve.git
synced 2026-06-04 12:32:59 +00:00
c
This commit is contained in:
+159
-53
@@ -1252,6 +1252,57 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Reservations Management Section -->
|
||||||
|
<div class="card" style="margin: 2rem auto; max-width: 1200px;">
|
||||||
|
<h3>Správa rezervací vozidel</h3>
|
||||||
|
|
||||||
|
<!-- Filters -->
|
||||||
|
<div class="mb-6 bg-gray-50 p-4 rounded-lg">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
||||||
|
<div>
|
||||||
|
<label for="vehicleFilter" class="block text-sm font-medium text-gray-700 mb-1">Filtrovat dle vozidla:</label>
|
||||||
|
<select id="vehicleFilter" class="form-control w-full">
|
||||||
|
<option value="">Všechna vozidla</option>
|
||||||
|
<!-- Vehicle options will be populated by JavaScript -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="dateFilter" class="block text-sm font-medium text-gray-700 mb-1">Filtrovat dle data:</label>
|
||||||
|
<input type="date" id="dateFilter" class="form-control w-full">
|
||||||
|
</div>
|
||||||
|
<div class="flex items-end">
|
||||||
|
<button id="exportButton" class="btn btn-primary w-full">
|
||||||
|
<i class="fas fa-file-export mr-2"></i>Exportovat do Excelu
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Reservations Table -->
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table id="reservationsTable" class="min-w-full divide-y divide-gray-200">
|
||||||
|
<thead class="bg-gray-50">
|
||||||
|
<tr>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Řidič</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Vozidlo</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Od</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Do</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Účel</th>
|
||||||
|
<th scope="col" class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Akce</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="bg-white divide-y divide-gray-200">
|
||||||
|
<!-- Rows will be populated by JavaScript -->
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="px-6 py-4 text-center text-gray-500">
|
||||||
|
Načítám data o rezervacích...
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Icon Picker Modal -->
|
<!-- Icon Picker Modal -->
|
||||||
<div id="iconPickerModal" class="fixed inset-0 z-50 hidden">
|
<div id="iconPickerModal" class="fixed inset-0 z-50 hidden">
|
||||||
<div id="iconPickerContainer" class="bg-white rounded-xl shadow-2xl overflow-hidden flex flex-col">
|
<div id="iconPickerContainer" class="bg-white rounded-xl shadow-2xl overflow-hidden flex flex-col">
|
||||||
@@ -4314,38 +4365,34 @@ function displayReservations(reservations) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody.innerHTML = reservations.map(res => {
|
// Format date and time as DD.MM.YYYY HH:MM
|
||||||
const startDate = new Date(res.start);
|
const formatDateTime = (dateString) => {
|
||||||
const endDate = new Date(res.end);
|
const date = new Date(dateString);
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const hours = String(date.getHours()).padStart(2, '0');
|
||||||
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||||
|
return `${day}.${month}.${year} ${hours}:${minutes}`;
|
||||||
|
};
|
||||||
|
|
||||||
// Format date as DD.MM.YYYY
|
tbody.innerHTML = reservations.map(res => `
|
||||||
const formatDate = (date) => {
|
<tr class="hover:bg-gray-50">
|
||||||
const day = String(date.getDate()).padStart(2, '0');
|
<td class="px-6 py-4">${res.driverName || '-'}</td>
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
<td class="px-6 py-4">${res.vehicle || '-'}</td>
|
||||||
const year = date.getFullYear();
|
<td class="px-6 py-4 whitespace-nowrap">${formatDateTime(res.start)}</td>
|
||||||
return `${day}.${month}.${year}`;
|
<td class="px-6 py-4 whitespace-nowrap">${formatDateTime(res.end)}</td>
|
||||||
};
|
<td class="px-6 py-4">${res.purpose || '-'}</td>
|
||||||
|
<td class="px-6 py-4 whitespace-nowrap">
|
||||||
// Format time as HH:MM
|
<button onclick="editReservation('${res.id}')" class="text-blue-600 hover:text-blue-900 mr-3">
|
||||||
const formatTime = (date) => {
|
<i class="fas fa-edit"></i> Upravit
|
||||||
const hours = String(date.getHours()).padStart(2, '0');
|
</button>
|
||||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
<button onclick="deleteReservation('${res.id}')" class="text-red-600 hover:text-red-900">
|
||||||
return `${hours}:${minutes}`;
|
<i class="fas fa-trash"></i> Smazat
|
||||||
};
|
</button>
|
||||||
|
</td>
|
||||||
return `
|
</tr>
|
||||||
<tr class="hover:bg-gray-50">
|
`).join('');
|
||||||
<td class="px-6 py-4">${res.driverName || '-'}</td>
|
|
||||||
<td class="px-6 py-4">${res.vehicle || '-'}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${formatDate(startDate)}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${formatTime(startDate)}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${formatDate(endDate)}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${formatTime(endDate)}</td>
|
|
||||||
<td class="px-6 py-4">${res.purpose || '-'}</td>
|
|
||||||
<td class="px-6 py-4 whitespace-nowrap">${calculateDuration(res)}</td>
|
|
||||||
</tr>
|
|
||||||
`;
|
|
||||||
}).join('');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to filter reservations
|
// Function to filter reservations
|
||||||
@@ -4379,39 +4426,98 @@ function exportReservations() {
|
|||||||
const vehicleFilter = document.getElementById('vehicleFilter').value;
|
const vehicleFilter = document.getElementById('vehicleFilter').value;
|
||||||
const dateFilter = document.getElementById('dateFilter').value;
|
const dateFilter = document.getElementById('dateFilter').value;
|
||||||
|
|
||||||
let dataToExport = window.allReservations;
|
let dataToExport = [...window.allReservations];
|
||||||
|
|
||||||
|
// Apply filters if set
|
||||||
if (vehicleFilter) {
|
if (vehicleFilter) {
|
||||||
dataToExport = dataToExport.filter(res => res.vehicle === vehicleFilter);
|
dataToExport = dataToExport.filter(res => res.vehicle === vehicleFilter);
|
||||||
}
|
}
|
||||||
if (dateFilter) {
|
if (dateFilter) {
|
||||||
dataToExport = dataToExport.filter(res => res.startDate === dateFilter);
|
dataToExport = dataToExport.filter(res => {
|
||||||
|
const resDate = new Date(res.start).toISOString().split('T')[0];
|
||||||
|
return resDate === dateFilter;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create CSV content
|
// Sort by start date
|
||||||
const headers = ['Řidič', 'Vozidlo', 'Datum od', 'Čas od', 'Datum do', 'Čas do', 'Účel', 'Doba trvání'];
|
dataToExport.sort((a, b) => new Date(a.start) - new Date(b.start));
|
||||||
const csvContent = [
|
|
||||||
headers.join(','),
|
// Format date as DD.MM.YYYY
|
||||||
...dataToExport.map(res => [
|
const formatDate = (dateString) => {
|
||||||
`"${res.driverName}"`,
|
const date = new Date(dateString);
|
||||||
`"${res.vehicle}"`,
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
res.startDate,
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
res.startTime,
|
const year = date.getFullYear();
|
||||||
res.endDate,
|
return `${day}.${month}.${year}`;
|
||||||
res.endTime,
|
};
|
||||||
`"${res.purpose || ''}"`,
|
|
||||||
`"${calculateDuration(res)}"`
|
// Format time as HH:MM
|
||||||
].join(','))
|
const formatTime = (dateString) => {
|
||||||
].join('\n');
|
const date = new Date(dateString);
|
||||||
|
const hours = String(date.getHours()).padStart(2, '0');
|
||||||
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||||
|
return `${hours}:${minutes}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Format date and time for Excel (YYYY-MM-DD HH:MM)
|
||||||
|
const excelDateTime = (dateString) => {
|
||||||
|
const date = new Date(dateString);
|
||||||
|
const year = date.getFullYear();
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
const hours = String(date.getHours()).padStart(2, '0');
|
||||||
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create CSV content with semicolon as delimiter for better Excel compatibility
|
||||||
|
const headers = [
|
||||||
|
'Řidič',
|
||||||
|
'Vozidlo',
|
||||||
|
'Začátek rezervace',
|
||||||
|
'Konec rezervace',
|
||||||
|
'Doba trvání',
|
||||||
|
'Účel cesty'
|
||||||
|
];
|
||||||
|
|
||||||
|
const csvContent = [
|
||||||
|
headers.join(';'),
|
||||||
|
...dataToExport.map(res => {
|
||||||
|
const start = new Date(res.start);
|
||||||
|
const end = new Date(res.end);
|
||||||
|
|
||||||
|
return [
|
||||||
|
`"${res.driverName || 'Neznámý řidič'}"`,
|
||||||
|
`"${res.vehicle || 'Neznámé vozidlo'}"`,
|
||||||
|
`"${excelDateTime(start)}"`,
|
||||||
|
`"${excelDateTime(end)}"`,
|
||||||
|
`"${calculateDuration(res)}"`,
|
||||||
|
`"${res.purpose || 'Nespecifikováno'}"`
|
||||||
|
].join(';');
|
||||||
|
})
|
||||||
|
].join('\r\n');
|
||||||
|
|
||||||
|
// Create and trigger download with proper encoding for Excel
|
||||||
|
const blob = new Blob([
|
||||||
|
'\ufeff', // UTF-8 BOM for Excel
|
||||||
|
csvContent
|
||||||
|
], {
|
||||||
|
type: 'text/csv;charset=utf-8;'
|
||||||
|
});
|
||||||
|
|
||||||
// Create and trigger download
|
|
||||||
const blob = new Blob(['\ufeff' + csvContent], { type: 'text/csv;charset=utf-8;' });
|
|
||||||
const link = document.createElement('a');
|
const link = document.createElement('a');
|
||||||
const date = new Date().toISOString().split('T')[0];
|
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||||
link.href = URL.createObjectURL(blob);
|
link.href = URL.createObjectURL(blob);
|
||||||
link.download = `rezervace_${date}.csv`;
|
link.download = `rezervace_${timestamp}.csv`;
|
||||||
|
link.style.display = 'none';
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
document.body.removeChild(link);
|
|
||||||
|
// Clean up
|
||||||
|
setTimeout(() => {
|
||||||
|
document.body.removeChild(link);
|
||||||
|
URL.revokeObjectURL(link.href);
|
||||||
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to format date and time
|
// Helper function to format date and time
|
||||||
|
|||||||
Reference in New Issue
Block a user