2105 lines
50 KiB
Svelte
2105 lines
50 KiB
Svelte
<script>
|
||
import { onMount, onDestroy, tick } from 'svelte';
|
||
import { goto } from '$app/navigation';
|
||
import { io } from 'socket.io-client';
|
||
import VehiclesContent from '$lib/components/VehiclesContent.svelte';
|
||
import UnitsContent from '$lib/components/UnitsContent.svelte';
|
||
import PersonnelContent from '$lib/components/PersonnelContent.svelte';
|
||
import GoodsManagersContent from '$lib/components/GoodsManagersContent.svelte';
|
||
import GoodsManagerContent from '$lib/components/GoodsManagerContent.svelte';
|
||
import DevriçarkContent from '$lib/components/DevriçarkContent.svelte';
|
||
import MonthlyFuelReportContent from '$lib/components/MonthlyFuelReportContent.svelte';
|
||
|
||
let user = null;
|
||
let loading = true;
|
||
let currentTime = '';
|
||
let showMobileMenu = false;
|
||
let showFuelForm = false;
|
||
let showGoodsManager = false;
|
||
let showVehicles = false;
|
||
let showUnits = false;
|
||
let showPersonnel = false;
|
||
let showGoodsManagers = false;
|
||
let showDevriçark = false;
|
||
let showMonthlyReport = false;
|
||
let socket = null;
|
||
|
||
// Admin state reset function
|
||
function resetAdminStates() {
|
||
showVehicles = false;
|
||
showUnits = false;
|
||
showPersonnel = false;
|
||
showGoodsManagers = false;
|
||
showFuelForm = false;
|
||
showGoodsManager = false;
|
||
showDevriçark = false;
|
||
showMonthlyReport = false;
|
||
}
|
||
|
||
|
||
// Fuel Manager için veriler
|
||
let fuelSummary = { benzin: 0, motorin: 0 };
|
||
let pendingSlips = [];
|
||
let approvedRejectedSlips = [];
|
||
let fuelLoading = true;
|
||
let vehicles = [];
|
||
let units = [];
|
||
let personnel = [];
|
||
let goodsManagers = [];
|
||
let formError = '';
|
||
let formSuccess = '';
|
||
let isSubmitting = false;
|
||
|
||
let formData = {
|
||
date: new Date().toISOString().split('T')[0],
|
||
force_command: '1. Komutanlık',
|
||
unit_id: '',
|
||
vehicle_id: '',
|
||
fuel_type: 'benzin',
|
||
liters: '',
|
||
km: '',
|
||
personnel_id: '',
|
||
goods_manager_id: '',
|
||
notes: ''
|
||
};
|
||
|
||
$: displayPendingSlips = pendingSlips;
|
||
$: displayHistorySlips = approvedRejectedSlips;
|
||
|
||
onMount(async () => {
|
||
// localStorage'dan kullanıcı bilgisini al
|
||
const userData = localStorage.getItem('user');
|
||
if (!userData) {
|
||
goto('/');
|
||
return;
|
||
}
|
||
|
||
user = JSON.parse(userData);
|
||
loading = false;
|
||
|
||
// Zamanı güncelle
|
||
updateTime();
|
||
setInterval(updateTime, 1000);
|
||
|
||
// Eğer fuel_manager ise yakıt verilerini yükle ve socket bağlantısı kur
|
||
if (user.role === 'fuel_manager') {
|
||
await loadFuelData();
|
||
|
||
// Socket.IO bağlantısı
|
||
socket = io('http://localhost:3000');
|
||
|
||
// Fiş durumu güncellendiğinde listeyi yenile
|
||
socket.on('fuel-slip-updated', (data) => {
|
||
console.log('Dashboard - fuel-slip-updated received:', data);
|
||
if (data.fuel_manager_id === user.id) {
|
||
loadFuelData();
|
||
formSuccess = `Fiş durumu güncellendi: ${data.status === 'approved' ? 'Onaylandı' : 'Reddedildi'}`;
|
||
setTimeout(() => formSuccess = '', 3000);
|
||
}
|
||
});
|
||
|
||
socket.on('connect', () => {
|
||
console.log('Dashboard - Socket.IO connected for fuel_manager:', socket.id);
|
||
});
|
||
}
|
||
|
||
// Eğer goods_manager ise socket bağlantısı kur (GoodsManagerContent component'i kendi socket'ini kullanacak)
|
||
if (user.role === 'goods_manager') {
|
||
console.log('Dashboard - goods_manager logged in, user:', user);
|
||
}
|
||
});
|
||
|
||
// Cleanup
|
||
onDestroy(() => {
|
||
if (socket) {
|
||
socket.disconnect();
|
||
}
|
||
});
|
||
|
||
async function loadFuelData() {
|
||
fuelLoading = true;
|
||
try {
|
||
const slipsResponse = await fetch('/api/fuel-slips');
|
||
if (slipsResponse.ok) {
|
||
const data = await slipsResponse.json();
|
||
const allSlips = data.fuelSlips || [];
|
||
|
||
// Sadece bu yakıt sorumlusunun onaylı fişlerini topla
|
||
const myApprovedSlips = allSlips.filter(slip => slip.status === 'approved' && slip.fuel_manager_id === user.id);
|
||
fuelSummary = myApprovedSlips.reduce(
|
||
(summary, slip) => {
|
||
if (slip.fuel_type === 'benzin') {
|
||
summary.benzin += slip.liters || 0;
|
||
} else if (slip.fuel_type === 'motorin') {
|
||
summary.motorin += slip.liters || 0;
|
||
}
|
||
return summary;
|
||
},
|
||
{ benzin: 0, motorin: 0 }
|
||
);
|
||
|
||
// Sadece bu yakıt sorumlusunun fişlerini göster
|
||
const mySlips = allSlips.filter(slip => slip.fuel_manager_id === user.id);
|
||
pendingSlips = mySlips.filter(slip => slip.status === 'pending');
|
||
approvedRejectedSlips = mySlips.filter(slip => slip.status !== 'pending');
|
||
}
|
||
|
||
// Form için gerekli veriler
|
||
const [vehiclesRes, unitsRes, personnelRes, goodsManagersRes] = await Promise.all([
|
||
fetch('/api/vehicles'),
|
||
fetch('/api/units'),
|
||
fetch('/api/fuel-personnel'),
|
||
fetch('/api/goods-managers')
|
||
]);
|
||
|
||
if (vehiclesRes.ok) {
|
||
const vehiclesData = await vehiclesRes.json();
|
||
vehicles = vehiclesData.vehicles || [];
|
||
}
|
||
|
||
if (unitsRes.ok) {
|
||
const unitsData = await unitsRes.json();
|
||
units = unitsData.units || [];
|
||
}
|
||
|
||
if (personnelRes.ok) {
|
||
const personnelData = await personnelRes.json();
|
||
personnel = personnelData.fuelPersonnel?.filter(p => p.is_active) || [];
|
||
}
|
||
|
||
if (goodsManagersRes.ok) {
|
||
const goodsData = await goodsManagersRes.json();
|
||
goodsManagers = goodsData.goodsManagers?.filter(gm => gm.is_active) || [];
|
||
if (!formData.goods_manager_id && goodsManagers.length) {
|
||
formData.goods_manager_id = goodsManagers[0].id;
|
||
}
|
||
}
|
||
} catch (err) {
|
||
console.error('Yakıt verileri yüklenemedi:', err);
|
||
formError = 'Veriler yüklenirken bir hata oluştu.';
|
||
} finally {
|
||
fuelLoading = false;
|
||
}
|
||
}
|
||
|
||
function resetForm() {
|
||
formData = {
|
||
date: new Date().toISOString().split('T')[0],
|
||
force_command: '1. Komutanlık',
|
||
unit_id: '',
|
||
vehicle_id: '',
|
||
fuel_type: 'benzin',
|
||
liters: '',
|
||
km: '',
|
||
personnel_id: '',
|
||
goods_manager_id: goodsManagers[0]?.id || '',
|
||
notes: ''
|
||
};
|
||
}
|
||
|
||
async function handleCreateSlip() {
|
||
if (!user) return;
|
||
|
||
formError = '';
|
||
formSuccess = '';
|
||
|
||
const requiredFields = ['date', 'force_command', 'unit_id', 'vehicle_id', 'fuel_type', 'liters', 'km', 'personnel_id', 'goods_manager_id'];
|
||
for (const field of requiredFields) {
|
||
if (!formData[field]) {
|
||
formError = 'Lütfen tüm zorunlu alanları doldurun.';
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (Number(formData.liters) <= 0 || Number(formData.km) < 0) {
|
||
formError = 'Litre ve KM değerleri geçerli olmalıdır.';
|
||
return;
|
||
}
|
||
|
||
isSubmitting = true;
|
||
|
||
try {
|
||
const response = await fetch('/api/fuel-slips', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
...formData,
|
||
fuel_manager_id: user.id
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (!response.ok) {
|
||
formError = data?.message || 'Yakıt fişi oluşturulamadı.';
|
||
return;
|
||
}
|
||
|
||
formSuccess = 'Yakıt fişi başarıyla oluşturuldu.';
|
||
resetForm();
|
||
await loadFuelData();
|
||
showFuelForm = false;
|
||
} catch (err) {
|
||
console.error('Yakıt fişi oluşturulamadı:', err);
|
||
formError = 'Sunucuya ulaşılamadı.';
|
||
} finally {
|
||
isSubmitting = false;
|
||
}
|
||
}
|
||
|
||
function updateTime() {
|
||
const now = new Date();
|
||
const options = {
|
||
year: 'numeric',
|
||
month: 'long',
|
||
day: 'numeric',
|
||
hour: '2-digit',
|
||
minute: '2-digit',
|
||
second: '2-digit'
|
||
};
|
||
currentTime = now.toLocaleDateString('tr-TR', options);
|
||
}
|
||
|
||
function handleLogout() {
|
||
localStorage.removeItem('user');
|
||
goto('/');
|
||
}
|
||
|
||
function getRoleDisplayName(role) {
|
||
switch (role) {
|
||
case 'admin':
|
||
return '<i class="fas fa-user-shield"></i> Sistem Yöneticisi';
|
||
case 'fuel_manager':
|
||
return '<i class="fas fa-gas-pump"></i> Yakıt Sorumlusu';
|
||
case 'goods_manager':
|
||
return '<i class="fas fa-clipboard-check"></i> Mal Sorumlusu';
|
||
default:
|
||
return 'Bilinmeyen Rol';
|
||
}
|
||
}
|
||
|
||
function getRoleBadgeClass(role) {
|
||
switch (role) {
|
||
case 'admin':
|
||
return 'role-admin';
|
||
case 'fuel_manager':
|
||
return 'role-fuel';
|
||
case 'goods_manager':
|
||
return 'role-goods';
|
||
default:
|
||
return '';
|
||
}
|
||
}
|
||
|
||
function getStatusClass(status) {
|
||
switch (status) {
|
||
case 'pending':
|
||
return 'status-pending';
|
||
case 'approved':
|
||
return 'status-approved';
|
||
case 'rejected':
|
||
return 'status-rejected';
|
||
default:
|
||
return '';
|
||
}
|
||
}
|
||
|
||
function getStatusLabel(status) {
|
||
switch (status) {
|
||
case 'pending':
|
||
return '<i class="fas fa-clock"></i> Beklemede';
|
||
case 'approved':
|
||
return '<i class="fas fa-check-circle"></i> Onaylı';
|
||
case 'rejected':
|
||
return '<i class="fas fa-times-circle"></i> Reddedildi';
|
||
default:
|
||
return 'Bilinmiyor';
|
||
}
|
||
}
|
||
|
||
function formatDate(value) {
|
||
const date = value ? new Date(value) : null;
|
||
return date ? date.toLocaleDateString('tr-TR') : '-';
|
||
}
|
||
|
||
function formatKm(value) {
|
||
return typeof value === 'number'
|
||
? value.toLocaleString('tr-TR')
|
||
: value
|
||
? Number(value).toLocaleString('tr-TR')
|
||
: '-';
|
||
}
|
||
|
||
function formatLiters(value) {
|
||
return value ? `${Number(value).toFixed(0)}L` : '-';
|
||
}
|
||
|
||
function getFuelTypeLabel(type) {
|
||
return type === 'benzin' ? '⛽ Benzin' : '🛢️ Motorin';
|
||
}
|
||
|
||
function navigateTo(page) {
|
||
|
||
if (page === 'fuel-slips' && user?.role === 'fuel_manager') {
|
||
showFuelForm = true;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
|
||
if (page === '' && user?.role === 'fuel_manager') {
|
||
showFuelForm = false;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
|
||
if (page === '' && user?.role === 'goods_manager') {
|
||
showGoodsManager = false;
|
||
showDevriçark = false;
|
||
showMonthlyReport = false;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
|
||
if (page === 'goods-manager' && user?.role === 'goods_manager') {
|
||
console.log('🎯 Navigating to goods-manager, user:', user);
|
||
showGoodsManager = true;
|
||
showDevriçark = false;
|
||
showMonthlyReport = false;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
|
||
if (page === 'devriçark' && user?.role === 'goods_manager') {
|
||
console.log('🎯 Navigating to devriçark, user:', user);
|
||
showGoodsManager = false;
|
||
showDevriçark = true;
|
||
showMonthlyReport = false;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
|
||
if (page === 'aylik-yakit-dokumu' && user?.role === 'goods_manager') {
|
||
console.log('🎯 Navigating to aylik-yakit-dokumu, user:', user);
|
||
showGoodsManager = false;
|
||
showDevriçark = false;
|
||
showMonthlyReport = true;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
|
||
if (page === 'distribution-document' && user?.role === 'fuel_manager') {
|
||
// Dağıtım belgesi sayfasına yönlendir (gelecekte oluşturulacak)
|
||
showMobileMenu = false;
|
||
alert('Dağıtım Belgesi özelliği yakında eklenecek.');
|
||
return;
|
||
}
|
||
|
||
showMobileMenu = false;
|
||
|
||
if (page === 'goods-manager') {
|
||
if (user?.role === 'goods_manager') {
|
||
console.log('🎯 Setting showGoodsManager to true');
|
||
showGoodsManager = true;
|
||
showFuelForm = false;
|
||
showMobileMenu = false;
|
||
return;
|
||
} else {
|
||
goto('/goods-manager');
|
||
return;
|
||
}
|
||
}
|
||
|
||
// Admin page navigation for SPA
|
||
if (user?.role === 'admin') {
|
||
// Hide all content first
|
||
showFuelForm = false;
|
||
showGoodsManager = false;
|
||
|
||
// 🎯 Ana Sayfa Case'i - Admin SPA içinde ana sayfaya dönüş
|
||
if (page === '') {
|
||
resetAdminStates(); // Tüm admin state'lerini false yap
|
||
showMobileMenu = false;
|
||
tick(); // Svelte reactivity'yi zorla
|
||
return; // goto çağrısı yapma, SPA içinde kal
|
||
}
|
||
|
||
if (page === 'vehicles') {
|
||
resetAdminStates();
|
||
showVehicles = true;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
|
||
if (page === 'units') {
|
||
resetAdminStates();
|
||
showUnits = true;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
|
||
if (page === 'personnel') {
|
||
resetAdminStates();
|
||
showPersonnel = true;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
|
||
if (page === 'goods-managers') {
|
||
resetAdminStates();
|
||
showGoodsManagers = true;
|
||
showMobileMenu = false;
|
||
return;
|
||
}
|
||
}
|
||
|
||
goto(`/dashboard/${page}`);
|
||
}
|
||
</script>
|
||
|
||
<div class="welcome-container">
|
||
<div class="container">
|
||
{#if loading}
|
||
<div class="text-center">
|
||
<div class="inline-block animate-spin rounded-full h-8 w-8 border-b-2 border-blue-600"></div>
|
||
<p class="mt-4">Yükleniyor...</p>
|
||
</div>
|
||
{:else if user}
|
||
<div class="dashboard-layout">
|
||
<!-- Sol Navigasyon Menüsü -->
|
||
<nav class="sidebar {showMobileMenu ? 'mobile-open' : ''}">
|
||
<div class="sidebar-header">
|
||
<h3 class="sidebar-title">
|
||
{#if user.role === 'admin'}
|
||
Yönetim Paneli
|
||
{:else if user.role === 'fuel_manager'}
|
||
Yakıt İşlemleri
|
||
{:else if user.role === 'goods_manager'}
|
||
Onay Paneli
|
||
{/if}
|
||
</h3>
|
||
<button class="mobile-close-btn" on:click={() => showMobileMenu = false}>×</button>
|
||
</div>
|
||
<ul class="nav-menu">
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('')} class:active={user.role === 'admin' ? !showVehicles && !showUnits && !showPersonnel && !showGoodsManagers : (user.role === 'goods_manager' ? !showGoodsManager && !showDevriçark && !showMonthlyReport : (user.role !== 'fuel_manager' ? !showFuelForm : true))}>
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||
</svg>
|
||
Ana Sayfa
|
||
</button>
|
||
</li>
|
||
|
||
{#if user.role === 'admin'}
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('vehicles')} class:active={showVehicles}>
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M19 9l-7 7-7-7"/>
|
||
<rect x="11" y="5" width="2" height="14"/>
|
||
<path d="M5 5v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V5"/>
|
||
</svg>
|
||
Araç Yönetimi
|
||
</button>
|
||
</li>
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('units')} class:active={showUnits}>
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M3 21h18"/>
|
||
<path d="M5 21V7l8-4v18"/>
|
||
<path d="M19 21V11l-6-4"/>
|
||
</svg>
|
||
Birlik Yönetimi
|
||
</button>
|
||
</li>
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('personnel')} class:active={showPersonnel}>
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
|
||
<circle cx="9" cy="7" r="4"/>
|
||
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
|
||
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
||
</svg>
|
||
Yakıt Personeli
|
||
</button>
|
||
</li>
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('goods-managers')} class:active={showGoodsManagers}>
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/>
|
||
<circle cx="9" cy="7" r="4"/>
|
||
<path d="M23 21v-2a4 4 0 0 0-3-3.87"/>
|
||
<path d="M16 3.13a4 4 0 0 1 0 7.75"/>
|
||
</svg>
|
||
Personel İşlemleri
|
||
</button>
|
||
</li>
|
||
{:else if user.role === 'fuel_manager'}
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('fuel-slips')} class:active={showFuelForm}>
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||
<polyline points="14 2 14 8 20 8"/>
|
||
<line x1="16" y1="13" x2="8" y2="13"/>
|
||
<line x1="16" y1="17" x2="8" y2="17"/>
|
||
<polyline points="10 9 9 9 8 9"/>
|
||
</svg>
|
||
Yakıt Fişi Oluştur
|
||
</button>
|
||
</li>
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('distribution-document')}>
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||
<polyline points="14 2 14 8 20 8"/>
|
||
<line x1="12" y1="18" x2="12" y2="12"/>
|
||
<line x1="9" y1="15" x2="15" y2="15"/>
|
||
</svg>
|
||
Dağıtım Belgesi Oluştur
|
||
</button>
|
||
</li>
|
||
{:else if user.role === 'goods_manager'}
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('goods-manager')} class:active={showGoodsManager}>
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
|
||
<polyline points="22 4 12 14.01 9 11.01"/>
|
||
</svg>
|
||
Atanan Fişler
|
||
</button>
|
||
</li>
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('aylik-yakit-dokumu')} class:active={showMonthlyReport}>
|
||
<i class="fa-solid fa-list-ol"></i>
|
||
Aylık Yakıt Dökümü
|
||
</button>
|
||
</li>
|
||
<li class="nav-item">
|
||
<button class="nav-btn" on:click={() => navigateTo('devriçark')} class:active={showDevriçark}>
|
||
<i class="fa-regular fa-file-lines"></i>
|
||
Devriçark İşlemleri
|
||
</button>
|
||
</li>
|
||
{/if}
|
||
</ul>
|
||
</nav>
|
||
|
||
<!-- Ana İçerik Alanı -->
|
||
<div class="main-content">
|
||
<div class="welcome-card card">
|
||
<!-- Üst kısım: Kullanıcı bilgileri -->
|
||
<div class="user-header">
|
||
<div class="user-avatar">
|
||
<div class="avatar-circle">
|
||
{#if user.role === 'admin'}
|
||
<i class="fa-solid fa-user-tie"></i>
|
||
{:else if user.role === 'fuel_manager'}
|
||
<i class="fa-solid fa-gas-pump"></i>
|
||
{:else if user.role === 'goods_manager'}
|
||
<i class="fa-solid fa-truck"></i>
|
||
{/if}
|
||
</div>
|
||
</div>
|
||
<div class="user-info">
|
||
<h2 class="user-name">{user.full_name}</h2>
|
||
<div class="role-badge {getRoleBadgeClass(user.role)}">
|
||
{@html getRoleDisplayName(user.role)}
|
||
</div>
|
||
</div>
|
||
<div class="header-actions">
|
||
<button class="btn mobile-menu-btn" on:click={() => showMobileMenu = !showMobileMenu}>
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<line x1="3" y1="12" x2="21" y2="12"/>
|
||
<line x1="3" y1="6" x2="21" y2="6"/>
|
||
<line x1="3" y1="18" x2="21" y2="18"/>
|
||
</svg>
|
||
</button>
|
||
<button class="btn btn-inactive" on:click={handleLogout}>
|
||
Çıkış Yap
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Ayırıcı -->
|
||
<div class="divider"></div>
|
||
|
||
<!-- Sadece admin ve goods_manager için bilgilendirme -->
|
||
{#if user.role === 'admin' && !showVehicles && !showUnits && !showPersonnel && !showGoodsManagers}
|
||
<!-- Karşılama mesajı -->
|
||
<div class="welcome-content">
|
||
<div class="welcome-icon">
|
||
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M3 12h18m-9-9v18"/>
|
||
</svg>
|
||
</div>
|
||
<h1 class="welcome-title">Hoş Geldiniz! 👋</h1>
|
||
<p class="welcome-message">
|
||
{#if user.role === 'admin'}
|
||
Sisteme hoş geldiniz! Araç, birlik ve personel yönetimi yapabilirsiniz.
|
||
{:else if user.role === 'goods_manager'}
|
||
Hoş geldiniz! Size atanan yakıt fişlerini onaylayabilirsiniz.
|
||
{/if}
|
||
</p>
|
||
|
||
<div class="current-time">
|
||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="inline mr-2">
|
||
<circle cx="12" cy="12" r="10"/>
|
||
<polyline points="12 6 12 12 16 14"/>
|
||
</svg>
|
||
{currentTime}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- İstatistikler Kartları -->
|
||
<div class="stats-grid">
|
||
<div class="stat-card card">
|
||
<div class="stat-icon fuel-icon">
|
||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M3 3h18v18H3z"/>
|
||
<path d="M7 7h10v10H7z"/>
|
||
<path d="M11 3v18"/>
|
||
<path d="M3 11h18"/>
|
||
</svg>
|
||
</div>
|
||
<div class="stat-info">
|
||
<h3 class="stat-title">Yakıt İşlemleri</h3>
|
||
<p class="stat-value">Sistem Hazır</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stat-card card">
|
||
<div class="stat-icon goods-icon">
|
||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/>
|
||
</svg>
|
||
</div>
|
||
<div class="stat-info">
|
||
<h3 class="stat-title">Mal Takibi</h3>
|
||
<p class="stat-value">Aktif</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="stat-card card">
|
||
<div class="stat-icon system-icon">
|
||
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<rect x="2" y="3" width="20" height="14" rx="2" ry="2"/>
|
||
<line x1="8" y1="21" x2="16" y2="21"/>
|
||
<line x1="12" y1="17" x2="12" y2="21"/>
|
||
</svg>
|
||
</div>
|
||
<div class="stat-info">
|
||
<h3 class="stat-title">Sistem Durumu</h3>
|
||
<p class="stat-value">✅ Çalışıyor</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Bilgilendirme -->
|
||
<div class="info-section">
|
||
<div class="info-card card">
|
||
<h3 class="info-title">📋 Bilgilendirme</h3>
|
||
<div class="info-content">
|
||
{#if user.role === 'admin'}
|
||
<ul class="info-list">
|
||
<li>Araç, birlik ve personel yönetimi yapabilirsiniz</li>
|
||
<li>Personel işlemlerini yönetebilirsiniz</li>
|
||
<li>Tüm kullanıcıları yönetebilirsiniz</li>
|
||
<li>Sistem ayarlarını yapılandırabilirsiniz</li>
|
||
<li>Raporları görüntüleyebilirsiniz</li>
|
||
</ul>
|
||
{:else if user.role === 'goods_manager'}
|
||
<ul class="info-list">
|
||
<li>Araçların aldığı yakıtları takip edebilirsiniz</li>
|
||
<li>Onay/red işlemleri yapabilirsiniz</li>
|
||
<li>Ay sonu devriçark cetveli hazırlayabilirsiniz</li>
|
||
</ul>
|
||
{/if}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{:else if user.role === 'goods_manager' && showGoodsManager}
|
||
<!-- Goods Manager Content -->
|
||
<GoodsManagerContent {user} />
|
||
{:else if user.role === 'goods_manager' && showMonthlyReport}
|
||
<!-- Monthly Fuel Report Content -->
|
||
<MonthlyFuelReportContent {user} />
|
||
{:else if user.role === 'goods_manager' && showDevriçark}
|
||
<!-- Devriçark Content -->
|
||
<DevriçarkContent {user} />
|
||
{:else if user.role === 'admin'}
|
||
<!-- Admin Dynamic Content -->
|
||
|
||
{#if showVehicles}
|
||
<VehiclesContent {user} />
|
||
{:else if showUnits}
|
||
<UnitsContent {user} />
|
||
{:else if showPersonnel}
|
||
<PersonnelContent {user} />
|
||
{:else if showGoodsManagers}
|
||
<GoodsManagersContent {user} />
|
||
{:else}
|
||
<!-- Admin Welcome Message (Default) -->
|
||
<div class="welcome-card card">
|
||
<div class="card-header">
|
||
<div class="card-icon">🚗</div>
|
||
<h3>Araç Yönetimi</h3>
|
||
</div>
|
||
<div class="card-content">
|
||
<p>Yukarıdaki menüden Araç Yönetimi'ni seçerek araçları yönetebilirsiniz.</p>
|
||
<p style="margin-top: 1rem; color: var(--primary-color); font-weight: 600;">✅ Admin SPA yüklendi!</p>
|
||
</div>
|
||
</div>
|
||
{/if}
|
||
{:else}
|
||
<!-- Fuel Manager ana görünümü -->
|
||
{#if formSuccess}
|
||
<div class="form-alert success-alert">
|
||
{formSuccess}
|
||
</div>
|
||
{/if}
|
||
|
||
{#if formError && showFuelForm}
|
||
<div class="form-alert error-alert">
|
||
{formError}
|
||
</div>
|
||
{/if}
|
||
|
||
|
||
{#if !showFuelForm}
|
||
<section class="fuel-summary-section">
|
||
<div class="fuel-summary-grid">
|
||
<div class="fuel-summary-card benzin">
|
||
<div class="summary-icon-wrapper">
|
||
<div class="summary-icon">⛽</div>
|
||
</div>
|
||
<div class="summary-info">
|
||
<h3 class="summary-title">Benzin</h3>
|
||
<p class="summary-amount">
|
||
{fuelLoading ? '...' : fuelSummary.benzin.toFixed(1)}
|
||
<span class="summary-unit">LT</span>
|
||
</p>
|
||
<span class="summary-label">Toplam Yakıt</span>
|
||
</div>
|
||
</div>
|
||
<div class="fuel-summary-card motorin">
|
||
<div class="summary-icon-wrapper">
|
||
<div class="summary-icon">🛢️</div>
|
||
</div>
|
||
<div class="summary-info">
|
||
<h3 class="summary-title">Motorin</h3>
|
||
<p class="summary-amount">
|
||
{fuelLoading ? '...' : fuelSummary.motorin.toFixed(1)}
|
||
<span class="summary-unit">LT</span>
|
||
</p>
|
||
<span class="summary-label">Toplam Yakıt</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section class="tables-section">
|
||
<div class="table-container">
|
||
<div class="fuel-table-header">
|
||
<h3 class="fuel-table-title">Onay Bekleyen Fişler</h3>
|
||
<span class="count-badge">{pendingSlips.length}</span>
|
||
</div>
|
||
{#if fuelLoading}
|
||
<div class="table-loader">Yükleniyor...</div>
|
||
{:else if pendingSlips.length === 0}
|
||
<div class="empty-table">
|
||
<div class="empty-table-icon">📄</div>
|
||
<p>Onay bekleyen fiş bulunmamaktadır.</p>
|
||
</div>
|
||
{:else}
|
||
<div class="table-wrapper">
|
||
<table class="fuel-table">
|
||
<thead>
|
||
<tr>
|
||
<th>S.No</th>
|
||
<th>Araç Plaka</th>
|
||
<th>Personel</th>
|
||
<th>Mal Sorumlusu</th>
|
||
<th>KM</th>
|
||
<th>Tarih</th>
|
||
<th>Yakıt Cinsi</th>
|
||
<th>Miktar</th>
|
||
<th>Durum</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{#each pendingSlips as slip, index}
|
||
<tr>
|
||
<td>{index + 1}</td>
|
||
<td>{slip.vehicle_info?.plate || '-'}</td>
|
||
<td>{slip.personnel_info?.full_name || '-'}</td>
|
||
<td>{slip.goods_manager_info?.full_name || '-'}</td>
|
||
<td>{formatKm(slip.km)}</td>
|
||
<td>{formatDate(slip.date)}</td>
|
||
<td>{getFuelTypeLabel(slip.fuel_type)}</td>
|
||
<td>{formatLiters(slip.liters)}</td>
|
||
<td>
|
||
<span
|
||
class={`status-badge ${getStatusClass(slip.status)}`}
|
||
title={slip.status === 'rejected' && slip.approval_notes ? `Red Nedeni: ${slip.approval_notes}` : ''}
|
||
>
|
||
{@html getStatusLabel(slip.status)}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
{/each}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{/if}
|
||
</div>
|
||
|
||
<div class="table-container">
|
||
<div class="fuel-table-header">
|
||
<h3 class="fuel-table-title">İşlem Geçmişi</h3>
|
||
<span class="count-badge">{approvedRejectedSlips.length}</span>
|
||
</div>
|
||
{#if fuelLoading}
|
||
<div class="table-loader">Yükleniyor...</div>
|
||
{:else if approvedRejectedSlips.length === 0}
|
||
<div class="empty-table">
|
||
<div class="empty-table-icon">🗂️</div>
|
||
<p>İşlenmiş fiş bulunmamaktadır.</p>
|
||
</div>
|
||
{:else}
|
||
<div class="table-wrapper">
|
||
<table class="fuel-table">
|
||
<thead>
|
||
<tr>
|
||
<th>S.No</th>
|
||
<th>Araç Plaka</th>
|
||
<th>Personel</th>
|
||
<th>Mal Sorumlusu</th>
|
||
<th>KM</th>
|
||
<th>Tarih</th>
|
||
<th>Yakıt Cinsi</th>
|
||
<th>Miktar</th>
|
||
<th>Durum</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{#each approvedRejectedSlips as slip, index}
|
||
<tr>
|
||
<td>{index + 1}</td>
|
||
<td>{slip.vehicle_info?.plate || '-'}</td>
|
||
<td>{slip.personnel_info?.full_name || '-'}</td>
|
||
<td>{slip.goods_manager_info?.full_name || '-'}</td>
|
||
<td>{formatKm(slip.km)}</td>
|
||
<td>{formatDate(slip.date)}</td>
|
||
<td>{getFuelTypeLabel(slip.fuel_type)}</td>
|
||
<td>{formatLiters(slip.liters)}</td>
|
||
<td>
|
||
<span
|
||
class={`status-badge ${getStatusClass(slip.status)}`}
|
||
title={slip.status === 'rejected' && slip.approval_notes ? `Red Nedeni: ${slip.approval_notes}` : ''}
|
||
>
|
||
{@html getStatusLabel(slip.status)}
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
{/each}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
{/if}
|
||
</div>
|
||
</section>
|
||
{/if}
|
||
|
||
{#if showFuelForm}
|
||
<section class="fuel-form-section">
|
||
<div class="fuel-form-header">
|
||
<h3 class="fuel-form-title">
|
||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display: inline-block; vertical-align: middle; margin-right: 0.5rem;">
|
||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||
<polyline points="14 2 14 8 20 8"/>
|
||
<line x1="16" y1="13" x2="8" y2="13"/>
|
||
<line x1="16" y1="17" x2="8" y2="17"/>
|
||
<polyline points="10 9 9 9 8 9"/>
|
||
</svg>
|
||
Yeni Yakıt Fişi Oluştur
|
||
</h3>
|
||
</div>
|
||
|
||
{#if formError}
|
||
<div class="form-alert error-alert">
|
||
{formError}
|
||
</div>
|
||
{/if}
|
||
|
||
<form class="fuel-form" on:submit|preventDefault={handleCreateSlip}>
|
||
<div class="form-grid">
|
||
<div class="form-group">
|
||
<label for="force_command">Kuvvet Komutanlığı</label>
|
||
<input
|
||
id="force_command"
|
||
class="form-input"
|
||
type="text"
|
||
placeholder="1. Komutanlık"
|
||
bind:value={formData.force_command}
|
||
required
|
||
/>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="date">Tarih</label>
|
||
<input
|
||
id="date"
|
||
class="form-input"
|
||
type="date"
|
||
bind:value={formData.date}
|
||
required
|
||
/>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="unit_id">Birlik</label>
|
||
<select
|
||
id="unit_id"
|
||
class="form-select"
|
||
bind:value={formData.unit_id}
|
||
required
|
||
>
|
||
<option value="">Birlik Seçin</option>
|
||
{#each units as unit}
|
||
<option value={unit.id}>{unit.name}</option>
|
||
{/each}
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="vehicle_id">Araç</label>
|
||
<select
|
||
id="vehicle_id"
|
||
class="form-select"
|
||
bind:value={formData.vehicle_id}
|
||
required
|
||
>
|
||
<option value="">Araç Seçin</option>
|
||
{#each vehicles as vehicle}
|
||
<option value={vehicle.id}>{vehicle.brand} {vehicle.model} ({vehicle.plate})</option>
|
||
{/each}
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="fuel_type">Yakıt Türü</label>
|
||
<select
|
||
id="fuel_type"
|
||
class="form-select"
|
||
bind:value={formData.fuel_type}
|
||
required
|
||
>
|
||
<option value="benzin">Benzin</option>
|
||
<option value="motorin">Motorin</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="liters">Litre</label>
|
||
<input
|
||
id="liters"
|
||
class="form-input"
|
||
type="number"
|
||
min="0.1"
|
||
step="0.1"
|
||
placeholder="45"
|
||
bind:value={formData.liters}
|
||
required
|
||
/>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="km">Kilometre</label>
|
||
<input
|
||
id="km"
|
||
class="form-input"
|
||
type="number"
|
||
min="0"
|
||
placeholder="125.420"
|
||
bind:value={formData.km}
|
||
required
|
||
/>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="personnel_id">Teslim Eden</label>
|
||
<select
|
||
id="personnel_id"
|
||
class="form-select"
|
||
bind:value={formData.personnel_id}
|
||
required
|
||
>
|
||
<option value="">Personel Seçin</option>
|
||
{#each personnel as person}
|
||
<option value={person.id}>{person.rank} {person.full_name}</option>
|
||
{/each}
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="goods_manager_id">Teslim Alan</label>
|
||
<select
|
||
id="goods_manager_id"
|
||
class="form-select"
|
||
bind:value={formData.goods_manager_id}
|
||
required
|
||
>
|
||
<option value="">Mal Sorumlusu Seçin</option>
|
||
{#each goodsManagers as manager}
|
||
<option value={manager.id}>{manager.rank} {manager.full_name}</option>
|
||
{/each}
|
||
</select>
|
||
</div>
|
||
<div class="form-group full-width">
|
||
<label for="notes">Notlar</label>
|
||
<textarea
|
||
id="notes"
|
||
class="form-textarea"
|
||
rows="2"
|
||
placeholder="Haftalık yakıt ikmali..."
|
||
bind:value={formData.notes}
|
||
></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button
|
||
type="button"
|
||
class="btn btn-secondary"
|
||
on:click={() => { showFuelForm = false; formError = ''; }}
|
||
>
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<line x1="18" y1="6" x2="6" y2="18"/>
|
||
<line x1="6" y1="6" x2="18" y2="18"/>
|
||
</svg>
|
||
Vazgeç
|
||
</button>
|
||
<button type="submit" class="btn btn-primary" disabled={isSubmitting}>
|
||
{#if isSubmitting}
|
||
<span class="btn-spinner"></span>
|
||
Kaydediliyor...
|
||
{:else}
|
||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||
<path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/>
|
||
<polyline points="17 21 17 13 7 13 7 21"/>
|
||
<polyline points="7 3 7 8 15 8"/>
|
||
</svg>
|
||
Fiş Oluştur
|
||
{/if}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</section>
|
||
{/if}
|
||
{/if}
|
||
</div>
|
||
</div> <!-- main-content kapanış -->
|
||
</div> <!-- dashboard-layout kapanış -->
|
||
{:else}
|
||
<div class="text-center">
|
||
<p>Oturum bulunamadı. Yönlendiriliyorsunuz...</p>
|
||
</div>
|
||
{/if}
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
.welcome-container {
|
||
min-height: 100vh;
|
||
background: #F2F3F7;
|
||
padding: 2rem;
|
||
}
|
||
|
||
:global(.welcome-container .container) {
|
||
max-width: 1560px;
|
||
}
|
||
|
||
.welcome-card {
|
||
max-width: 1400px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.user-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.user-avatar {
|
||
margin-right: 1.5rem;
|
||
}
|
||
|
||
.avatar-circle {
|
||
width: 80px;
|
||
height: 80px;
|
||
border-radius: 50%;
|
||
background: var(--primary-color);
|
||
color: white;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 2.5rem;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.avatar-circle i {
|
||
font-size: 2.5rem;
|
||
}
|
||
|
||
.user-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.user-name {
|
||
font-size: 1.8rem;
|
||
font-weight: 700;
|
||
color: var(--text-color);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.divider {
|
||
height: 1px;
|
||
background: var(--card-border-color);
|
||
margin: 2rem 0;
|
||
}
|
||
|
||
.welcome-content {
|
||
text-align: center;
|
||
padding: 2rem 0;
|
||
}
|
||
|
||
.welcome-icon {
|
||
color: var(--primary-color);
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.welcome-title {
|
||
font-size: 2.5rem;
|
||
font-weight: 700;
|
||
color: var(--text-color);
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.welcome-message {
|
||
font-size: 1.2rem;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 1.5rem;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.current-time {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: var(--text-secondary);
|
||
font-size: 1rem;
|
||
margin-top: 1rem;
|
||
}
|
||
|
||
.stats-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||
gap: 1.5rem;
|
||
margin: 3rem 0;
|
||
}
|
||
|
||
.stat-card {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 1.5rem;
|
||
border: 1px solid var(--card-border-color);
|
||
border-radius: 12px;
|
||
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
||
}
|
||
|
||
.stat-card:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.stat-icon {
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-right: 1rem;
|
||
}
|
||
|
||
.fuel-icon {
|
||
background: rgba(37, 99, 235, 0.1);
|
||
color: #2563EB;
|
||
}
|
||
|
||
.goods-icon {
|
||
background: rgba(5, 150, 105, 0.1);
|
||
color: #059669;
|
||
}
|
||
|
||
.system-icon {
|
||
background: rgba(220, 38, 38, 0.1);
|
||
color: #DC2626;
|
||
}
|
||
|
||
.stat-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.stat-title {
|
||
font-size: 1rem;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.stat-value {
|
||
font-size: 1.4rem;
|
||
font-weight: 700;
|
||
color: var(--text-color);
|
||
}
|
||
|
||
.info-section {
|
||
margin-top: 2rem;
|
||
}
|
||
|
||
.info-title {
|
||
font-size: 1.3rem;
|
||
font-weight: 600;
|
||
color: var(--text-color);
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.info-list {
|
||
list-style: none;
|
||
padding: 0;
|
||
}
|
||
|
||
.info-list li {
|
||
padding: 0.75rem 0;
|
||
border-bottom: 1px solid var(--card-border-color);
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.info-list li:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.info-list li::before {
|
||
content: "✓";
|
||
color: var(--primary-color);
|
||
font-weight: bold;
|
||
margin-right: 0.75rem;
|
||
}
|
||
|
||
/* Responsive tasarım */
|
||
@media (max-width: 768px) {
|
||
.user-header {
|
||
flex-direction: column;
|
||
text-align: center;
|
||
}
|
||
|
||
.user-avatar {
|
||
margin-right: 0;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.avatar-circle {
|
||
width: 60px;
|
||
height: 60px;
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.welcome-title {
|
||
font-size: 2rem;
|
||
}
|
||
|
||
.stats-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.current-time {
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
}
|
||
}
|
||
|
||
/* Dashboard Layout */
|
||
.dashboard-layout {
|
||
display: flex;
|
||
gap: 2rem;
|
||
min-height: calc(100vh - 4rem);
|
||
width: 90%;
|
||
max-width: 90%;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.sidebar {
|
||
width: 280px;
|
||
background: white;
|
||
border: 1px solid var(--card-border-color);
|
||
border-radius: 12px;
|
||
padding: 1.5rem;
|
||
height: fit-content;
|
||
position: sticky;
|
||
top: 2rem;
|
||
}
|
||
|
||
.sidebar-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 2rem;
|
||
padding-bottom: 1rem;
|
||
border-bottom: 1px solid var(--card-border-color);
|
||
}
|
||
|
||
.sidebar-title {
|
||
font-size: 1.2rem;
|
||
font-weight: 600;
|
||
color: var(--text-color);
|
||
margin: 0;
|
||
}
|
||
|
||
.mobile-close-btn {
|
||
display: none;
|
||
background: none;
|
||
border: none;
|
||
font-size: 1.5rem;
|
||
color: var(--text-secondary);
|
||
cursor: pointer;
|
||
padding: 0.25rem;
|
||
}
|
||
|
||
.nav-menu {
|
||
list-style: none;
|
||
padding: 0;
|
||
margin: 0;
|
||
}
|
||
|
||
.nav-item {
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.nav-btn {
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
padding: 0.75rem 1rem;
|
||
background: none;
|
||
border: none;
|
||
border-radius: 8px;
|
||
color: var(--text-secondary);
|
||
font-size: 0.95rem;
|
||
cursor: pointer;
|
||
transition: all 0.3s ease;
|
||
text-align: left;
|
||
}
|
||
|
||
.nav-btn:hover {
|
||
background: var(--primary-color);
|
||
color: white;
|
||
transform: translateX(4px);
|
||
}
|
||
|
||
.nav-btn.active {
|
||
background: var(--primary-color);
|
||
color: white;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.main-content {
|
||
flex: 30;
|
||
}
|
||
|
||
.header-actions {
|
||
display: flex;
|
||
gap: 1rem;
|
||
align-items: center;
|
||
}
|
||
|
||
.mobile-menu-btn {
|
||
display: none;
|
||
background: none;
|
||
border: 1px solid var(--card-border-color);
|
||
border-radius: 8px;
|
||
padding: 0.5rem;
|
||
cursor: pointer;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
/* Responsive Tasarım */
|
||
@media (max-width: 1024px) {
|
||
.dashboard-layout {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.sidebar {
|
||
width: 100%;
|
||
position: static;
|
||
display: none;
|
||
}
|
||
|
||
.sidebar.mobile-open {
|
||
display: block;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 1000;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
padding: 0;
|
||
}
|
||
|
||
.sidebar.mobile-open > * {
|
||
background: white;
|
||
border-radius: 12px;
|
||
margin: 2rem;
|
||
max-height: 80vh;
|
||
overflow-y: auto;
|
||
}
|
||
|
||
.mobile-close-btn {
|
||
display: block;
|
||
}
|
||
|
||
.mobile-menu-btn {
|
||
display: block;
|
||
}
|
||
|
||
.header-actions {
|
||
flex-wrap: wrap;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.user-header {
|
||
flex-direction: column;
|
||
text-align: center;
|
||
gap: 1rem;
|
||
}
|
||
|
||
.user-avatar {
|
||
margin-right: 0;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.avatar-circle {
|
||
width: 60px;
|
||
height: 60px;
|
||
font-size: 1.5rem;
|
||
}
|
||
|
||
.avatar-circle i {
|
||
font-size: 1.75rem;
|
||
}
|
||
|
||
.welcome-title {
|
||
font-size: 2rem;
|
||
}
|
||
|
||
.stats-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.current-time {
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.sidebar.mobile-open > * {
|
||
margin: 1rem;
|
||
}
|
||
}
|
||
|
||
/* Animasyonlar */
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.welcome-card {
|
||
animation: fadeIn 0.6s ease-out;
|
||
}
|
||
|
||
.stat-card {
|
||
animation: fadeIn 0.8s ease-out;
|
||
}
|
||
|
||
.stat-card:nth-child(2) {
|
||
animation-delay: 0.1s;
|
||
}
|
||
|
||
.stat-card:nth-child(3) {
|
||
animation-delay: 0.2s;
|
||
}
|
||
|
||
.nav-item {
|
||
animation: fadeIn 0.5s ease-out;
|
||
}
|
||
|
||
.nav-item:nth-child(1) { animation-delay: 0.1s; }
|
||
.nav-item:nth-child(2) { animation-delay: 0.2s; }
|
||
.nav-item:nth-child(3) { animation-delay: 0.3s; }
|
||
.nav-item:nth-child(4) { animation-delay: 0.4s; }
|
||
|
||
/* Fuel Form Styles */
|
||
.fuel-form-section {
|
||
animation: slideDown 0.3s ease-out;
|
||
}
|
||
|
||
@keyframes slideDown {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(-20px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.fuel-form-header {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 2rem;
|
||
padding-bottom: 1.5rem;
|
||
border-bottom: 2px solid #E5E7EB;
|
||
}
|
||
|
||
.fuel-form-title {
|
||
font-size: 1.75rem;
|
||
font-weight: 700;
|
||
color: var(--text-color);
|
||
margin: 0;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.fuel-form {
|
||
animation: fadeIn 0.4s ease-out 0.1s both;
|
||
}
|
||
|
||
.form-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||
gap: 1.5rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.form-group.full-width {
|
||
grid-column: 1 / -1;
|
||
}
|
||
|
||
.form-group label {
|
||
display: block;
|
||
margin-bottom: 0.5rem;
|
||
font-weight: 600;
|
||
color: var(--text-color);
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.form-select, .form-textarea {
|
||
width: 100%;
|
||
padding: 0.875rem 1rem;
|
||
border: 2px solid #E5E7EB;
|
||
border-radius: 8px;
|
||
font-size: 0.95rem;
|
||
transition: all 0.2s ease;
|
||
background: white;
|
||
font-family: inherit;
|
||
}
|
||
|
||
.form-select:focus, .form-textarea:focus, .form-input:focus {
|
||
outline: none;
|
||
border-color: var(--primary-color);
|
||
box-shadow: 0 0 0 3px rgba(108, 165, 227, 0.1);
|
||
}
|
||
|
||
.form-textarea {
|
||
resize: vertical;
|
||
min-height: 80px;
|
||
}
|
||
|
||
.form-actions {
|
||
display: flex;
|
||
gap: 1rem;
|
||
justify-content: flex-end;
|
||
padding-top: 2rem;
|
||
border-top: 2px solid #F3F4F6;
|
||
}
|
||
|
||
.btn-spinner {
|
||
width: 16px;
|
||
height: 16px;
|
||
border: 2px solid rgba(255, 255, 255, 0.3);
|
||
border-top-color: white;
|
||
border-radius: 50%;
|
||
display: inline-block;
|
||
animation: spin 0.8s linear infinite;
|
||
}
|
||
|
||
@keyframes spin {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
|
||
.form-alert {
|
||
padding: 1rem 1.25rem;
|
||
border-radius: 8px;
|
||
margin-bottom: 1.5rem;
|
||
font-size: 0.9rem;
|
||
font-weight: 500;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.75rem;
|
||
animation: slideDown 0.3s ease-out;
|
||
}
|
||
|
||
.success-alert {
|
||
background: #D1FAE5;
|
||
color: #065F46;
|
||
border: 1px solid #6EE7B7;
|
||
}
|
||
|
||
.error-alert {
|
||
background: #FEE2E2;
|
||
color: #991B1B;
|
||
border: 1px solid #FCA5A5;
|
||
}
|
||
|
||
.success-alert::before {
|
||
content: '✓';
|
||
font-size: 1.25rem;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.error-alert::before {
|
||
content: '⚠';
|
||
font-size: 1.25rem;
|
||
}
|
||
|
||
/* Redirect Section Styles */
|
||
.redirect-section {
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
min-height: 400px;
|
||
padding: 2rem 0;
|
||
}
|
||
|
||
.redirect-card {
|
||
text-align: center;
|
||
max-width: 500px;
|
||
padding: 3rem;
|
||
}
|
||
|
||
.redirect-icon {
|
||
color: var(--primary-color);
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.redirect-title {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
color: var(--text-color);
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.redirect-message {
|
||
font-size: 1.1rem;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 2rem;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.btn-large {
|
||
padding: 1rem 2rem;
|
||
font-size: 1.1rem;
|
||
font-weight: 600;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.btn-large svg {
|
||
width: 24px;
|
||
height: 24px;
|
||
}
|
||
|
||
/* Fuel Manager Summary Styles */
|
||
.fuel-summary-section {
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.fuel-summary-grid {
|
||
display: flex;
|
||
gap: 1.5rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.fuel-summary-card {
|
||
padding: 1.5rem 2rem;
|
||
border-radius: 16px;
|
||
border: 1px solid transparent;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 1.5rem;
|
||
flex: 1;
|
||
min-width: 240px;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.fuel-summary-card.benzin {
|
||
background: #FFEDD5;
|
||
border-color: #FED7AA;
|
||
}
|
||
|
||
.fuel-summary-card.motorin {
|
||
background: #DBEAFE;
|
||
border-color: #BFDBFE;
|
||
}
|
||
|
||
.fuel-summary-card:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
|
||
}
|
||
|
||
.fuel-summary-card.benzin:hover {
|
||
background: #FED7AA;
|
||
border-color: #FDBA74;
|
||
}
|
||
|
||
.fuel-summary-card.motorin:hover {
|
||
background: #BFDBFE;
|
||
border-color: #93C5FD;
|
||
}
|
||
|
||
.summary-icon-wrapper {
|
||
width: 64px;
|
||
height: 64px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.fuel-summary-card.benzin .summary-icon-wrapper {
|
||
background: #FDE047;
|
||
}
|
||
|
||
.fuel-summary-card.motorin .summary-icon-wrapper {
|
||
background: #93C5FD;
|
||
}
|
||
|
||
.summary-icon {
|
||
font-size: 2rem;
|
||
}
|
||
|
||
.summary-info {
|
||
flex: 1;
|
||
min-width: 0;
|
||
}
|
||
|
||
.summary-title {
|
||
font-size: 0.875rem;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
margin-bottom: 0.5rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
.summary-amount {
|
||
font-size: 2rem;
|
||
font-weight: 700;
|
||
color: var(--text-color);
|
||
margin-bottom: 0.25rem;
|
||
line-height: 1;
|
||
}
|
||
|
||
.summary-unit {
|
||
font-size: 1rem;
|
||
color: var(--text-secondary);
|
||
margin-left: 0.25rem;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.summary-label {
|
||
font-size: 0.75rem;
|
||
color: var(--text-secondary);
|
||
display: block;
|
||
}
|
||
|
||
/* Tables Section Styles */
|
||
.tables-section {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 2rem;
|
||
}
|
||
|
||
.table-container {
|
||
background: white;
|
||
border-radius: 12px;
|
||
border: 1px solid var(--card-border-color);
|
||
overflow: hidden;
|
||
}
|
||
|
||
.fuel-table-header {
|
||
padding: 1.5rem;
|
||
border-bottom: 1px solid var(--card-border-color);
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
}
|
||
|
||
.fuel-table-title {
|
||
font-size: 1.2rem;
|
||
font-weight: 600;
|
||
color: var(--text-color);
|
||
margin: 0;
|
||
}
|
||
|
||
.count-badge {
|
||
background: var(--primary-color);
|
||
color: white;
|
||
padding: 0.25rem 0.75rem;
|
||
border-radius: 12px;
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.table-wrapper {
|
||
overflow-x: auto;
|
||
border-radius: 12px;
|
||
border: 1px solid #E5E7EB;
|
||
}
|
||
|
||
.fuel-table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
background: white;
|
||
}
|
||
|
||
.fuel-table th {
|
||
background: #F9FAFB;
|
||
padding: 1rem 1.25rem;
|
||
text-align: left;
|
||
font-weight: 600;
|
||
color: var(--text-color);
|
||
border-bottom: 2px solid #E5E7EB;
|
||
white-space: nowrap;
|
||
font-size: 0.875rem;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.5px;
|
||
}
|
||
|
||
.fuel-table th:first-child {
|
||
padding-left: 1.5rem;
|
||
border-top-left-radius: 12px;
|
||
}
|
||
|
||
.fuel-table th:last-child {
|
||
border-top-right-radius: 12px;
|
||
}
|
||
|
||
.fuel-table td {
|
||
padding: 1rem 1.25rem;
|
||
border-bottom: 1px solid #F3F4F6;
|
||
color: var(--text-color);
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.fuel-table td:first-child {
|
||
padding-left: 1.5rem;
|
||
font-weight: 600;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.fuel-table tbody tr {
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.fuel-table tbody tr:hover {
|
||
background: #F9FAFB;
|
||
transform: scale(1.001);
|
||
}
|
||
|
||
.fuel-table tbody tr:last-child td {
|
||
border-bottom: none;
|
||
}
|
||
|
||
|
||
.status-badge {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.375rem;
|
||
padding: 0.375rem 0.875rem;
|
||
border-radius: 20px;
|
||
font-size: 0.8rem;
|
||
font-weight: 600;
|
||
white-space: nowrap;
|
||
text-transform: capitalize;
|
||
}
|
||
|
||
.status-pending {
|
||
background: #FEF3C7;
|
||
color: #92400E;
|
||
border: 1px solid #FCD34D;
|
||
}
|
||
|
||
.status-approved {
|
||
background: #D1FAE5;
|
||
color: #065F46;
|
||
border: 1px solid #6EE7B7;
|
||
}
|
||
|
||
.status-rejected {
|
||
background: #FEE2E2;
|
||
color: #991B1B;
|
||
border: 1px solid #FCA5A5;
|
||
}
|
||
|
||
.empty-table {
|
||
padding: 3rem;
|
||
text-align: center;
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
.empty-table-icon {
|
||
font-size: 2rem;
|
||
margin-bottom: 1rem;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
/* Fuel Manager Responsive Design */
|
||
@media (max-width: 1024px) {
|
||
.fuel-summary-grid {
|
||
width: 100%;
|
||
}
|
||
|
||
.fuel-table {
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.fuel-table th,
|
||
.fuel-table td {
|
||
padding: 0.75rem;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.fuel-summary-grid {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.fuel-summary-card {
|
||
min-width: auto;
|
||
}
|
||
|
||
.fuel-table {
|
||
font-size: 0.8rem;
|
||
}
|
||
|
||
.fuel-table th,
|
||
.fuel-table td {
|
||
padding: 0.5rem 0.75rem;
|
||
}
|
||
|
||
.fuel-table th:first-child,
|
||
.fuel-table td:first-child {
|
||
padding-left: 0.75rem;
|
||
}
|
||
|
||
.status-badge {
|
||
font-size: 0.7rem;
|
||
padding: 0.25rem 0.625rem;
|
||
}
|
||
|
||
.summary-icon-wrapper {
|
||
width: 56px;
|
||
height: 56px;
|
||
}
|
||
|
||
.summary-icon {
|
||
font-size: 1.75rem;
|
||
}
|
||
|
||
.summary-amount {
|
||
font-size: 1.5rem;
|
||
}
|
||
}
|
||
|
||
/* Goods Manager Content Styles */
|
||
.goods-manager-content {
|
||
padding: 0;
|
||
max-width: none;
|
||
margin: 0;
|
||
}
|
||
|
||
.content-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 2rem;
|
||
gap: 1rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.content-title {
|
||
font-size: 1.8rem;
|
||
font-weight: 700;
|
||
color: var(--text-color);
|
||
margin: 0;
|
||
}
|
||
|
||
.goods-manager-content .stats-badge {
|
||
background: var(--primary-color);
|
||
color: white;
|
||
padding: 0.5rem 1rem;
|
||
border-radius: 20px;
|
||
font-size: 0.9rem;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.goods-manager-content .count {
|
||
background: rgba(255, 255, 255, 0.2);
|
||
padding: 0.25rem 0.5rem;
|
||
border-radius: 10px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.goods-manager-content .empty-state {
|
||
text-align: center;
|
||
padding: 3rem;
|
||
background: white;
|
||
border-radius: 12px;
|
||
border: 1px solid var(--card-border-color);
|
||
}
|
||
|
||
.goods-manager-content .empty-icon {
|
||
color: var(--text-secondary);
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.goods-manager-content .empty-state h3 {
|
||
font-size: 1.5rem;
|
||
font-weight: 600;
|
||
color: var(--text-color);
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.goods-manager-content .empty-state p {
|
||
color: var(--text-secondary);
|
||
margin: 0;
|
||
}
|
||
</style>
|