From 2b0c9e82cd5e71b23b09244bd400831357693900 Mon Sep 17 00:00:00 2001 From: szbk Date: Wed, 5 Nov 2025 23:13:07 +0300 Subject: [PATCH] =?UTF-8?q?fix:=20Socket.io=20real-time=20g=C3=BCncelleme?= =?UTF-8?q?=20sistemi=20tamamen=20d=C3=BCzeltildi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Socket.IO client modülü oluşturuldu (socketClient.js) - SvelteKit API route'larından Socket.IO event gönderimi için client kullanımı - fuel-slips API'de HTTP fetch yerine Socket.IO client kullanımı - Server'da API event'larını dinleyip broadcast etme eklendi - GoodsManagerContent component'inde Socket.IO dinleyicileri düzeltildi - Dashboard'da Mal Sorumlusu content render düzeltmesi - İbrahim Kara kullanıcısı ve mal sorumlusu kaydı eklendi - Login endpoint'inde goods_manager ID mapping düzeltmesi - fuel-slips/+page.svelte'de eksik fonksiyonlar eklendi - Kapsamlı debug logları tüm Socket.IO işlemlerine eklendi Çalışma prensibi: 1. Yakıt fişi oluşturulduğunda -> api-fuel-slip-assigned -> broadcast fuel-slip-assigned 2. Fiş onaylandığında/reddedildiğinde -> api-fuel-slip-updated -> broadcast fuel-slip-updated 3. Tüm değişiklikler anlık olarak ilgili ekranlarda güncelleniyor --- src/lib/components/GoodsManagerContent.svelte | 42 ++++++++++- src/lib/server/socketClient.js | 44 ++++++++++++ src/routes/api/fuel-slips/+server.js | 70 ++++++++----------- src/routes/api/goods-managers/+server.js | 15 +++- src/routes/dashboard/+page.svelte | 38 ++++------ src/routes/fuel-slips/+page.svelte | 59 +++++++++++++++- src/server.js | 50 ++++++++++--- 7 files changed, 238 insertions(+), 80 deletions(-) create mode 100644 src/lib/server/socketClient.js diff --git a/src/lib/components/GoodsManagerContent.svelte b/src/lib/components/GoodsManagerContent.svelte index dd29d9c..a1eb409 100644 --- a/src/lib/components/GoodsManagerContent.svelte +++ b/src/lib/components/GoodsManagerContent.svelte @@ -18,40 +18,78 @@ let rejectionNotes = ''; onMount(async () => { + console.log('🟢 GoodsManagerContent mounted, user:', user); + + if (!user) { + console.error('❌ User is null in GoodsManagerContent'); + error = 'Kullanıcı bilgisi bulunamadı.'; + loading = false; + return; + } + + console.log('🔌 Connecting to Socket.IO...'); // Socket.IO bağlantısı socket = io('http://localhost:3000'); + console.log('👤 Goods Manager ID:', user.id); + // Yeni fiş atandığında bildirim socket.on('fuel-slip-assigned', (data) => { + console.log('Socket event received: fuel-slip-assigned', data); if (data.goods_manager_id === user.id) { + console.log('✅ Slip assigned to this manager, reloading...'); loadAssignedSlips(); successMessage = 'Yeni yakıt fişi atandı!'; setTimeout(() => successMessage = '', 3000); + } else { + console.log('ℹ️ Slip assigned to different manager:', data.goods_manager_id, 'vs', user.id); } }); // Fiş durumu güncellendiğinde listeyi yenile socket.on('fuel-slip-updated', (data) => { + console.log('Socket event received: fuel-slip-updated', data); if (data.goods_manager_id === user.id) { + console.log('✅ Slip updated for this manager, reloading...'); loadAssignedSlips(); } }); + socket.on('connect', () => { + console.log('Socket.IO connected:', socket.id); + }); + + socket.on('disconnect', () => { + console.log('Socket.IO disconnected'); + }); + await loadAssignedSlips(); }); async function loadAssignedSlips() { + if (!user) { + console.error('❌ Cannot load slips: user is null'); + return; + } + + console.log(`📥 Loading slips for goods_manager_id: ${user.id}`); + try { - const response = await fetch(`/api/fuel-slips?manager_id=${user.id}&status=pending`); + const url = `/api/fuel-slips?manager_id=${user.id}&status=pending`; + console.log('🌐 Fetching from:', url); + + const response = await fetch(url); if (response.ok) { const data = await response.json(); assignedSlips = data.fuelSlips || []; + console.log('✅ Assigned slips loaded:', assignedSlips.length, assignedSlips); } else { + console.error('❌ Failed to load slips, status:', response.status); error = 'Atanan fişler yüklenemedi.'; } } catch (err) { error = 'Bağlantı hatası.'; - console.error('Load assigned slips error:', err); + console.error('❌ Load assigned slips error:', err); } finally { loading = false; } diff --git a/src/lib/server/socketClient.js b/src/lib/server/socketClient.js new file mode 100644 index 0000000..f0fa4c4 --- /dev/null +++ b/src/lib/server/socketClient.js @@ -0,0 +1,44 @@ +import { io } from 'socket.io-client'; + +let socket = null; + +export function getSocketClient() { + if (!socket) { + socket = io('http://localhost:3000', { + transports: ['websocket', 'polling'] + }); + + socket.on('connect', () => { + console.log('✅ Server-side Socket.IO client connected:', socket.id); + }); + + socket.on('disconnect', () => { + console.log('❌ Server-side Socket.IO client disconnected'); + }); + + socket.on('connect_error', (err) => { + console.error('❌ Socket.IO connection error:', err.message); + }); + } + + return socket; +} + +export function emitSocketEvent(event, data) { + const client = getSocketClient(); + console.log(`📢 Attempting to emit event: ${event}, connected: ${client?.connected}`); + + if (client && client.connected) { + console.log(`📢 Emitting API event to server: api-${event}`, data); + // API event olarak gönder, server broadcast edecek + client.emit(`api-${event}`, data); + return true; + } else { + console.warn('⚠️ Socket not connected, cannot emit event'); + // Bağlantı yoksa yeniden bağlanmayı dene + if (client && !client.connected) { + client.connect(); + } + return false; + } +} \ No newline at end of file diff --git a/src/routes/api/fuel-slips/+server.js b/src/routes/api/fuel-slips/+server.js index 341f4f0..4025d73 100644 --- a/src/routes/api/fuel-slips/+server.js +++ b/src/routes/api/fuel-slips/+server.js @@ -1,4 +1,5 @@ import { json } from '@sveltejs/kit'; +import { emitSocketEvent } from '$lib/server/socketClient.js'; // Geçici veritabanı simülasyonu let fuelSlips = [ @@ -15,7 +16,7 @@ let fuelSlips = [ km: 125420, personnel_id: 1, personnel_info: { full_name: 'Ahmet Demir', rank: 'Üsteğmen' }, - goods_manager_id: 2, + goods_manager_id: 3, goods_manager_info: { full_name: 'Ali Veli', rank: 'Binbaşı' }, fuel_manager_id: 1, fuel_manager_info: { full_name: 'Admin User', rank: 'Yüzbaşı' }, @@ -36,7 +37,7 @@ let fuelSlips = [ km: 87320, personnel_id: 2, personnel_info: { full_name: 'Mustafa Çelik', rank: 'Astsubay' }, - goods_manager_id: 2, + goods_manager_id: 3, goods_manager_info: { full_name: 'Ali Veli', rank: 'Binbaşı' }, fuel_manager_id: 1, fuel_manager_info: { full_name: 'Admin User', rank: 'Yüzbaşı' }, @@ -83,6 +84,7 @@ export async function GET({ request, url }) { export async function POST({ request }) { try { const slipData = await request.json(); + console.log('📝 Creating new fuel slip with data:', slipData); // Validasyon const requiredFields = [ @@ -168,26 +170,21 @@ export async function POST({ request }) { }; fuelSlips.push(newSlip); + console.log('✅ Fuel slip created:', newSlip); + console.log('📊 Total slips now:', fuelSlips.length); // Socket.IO ile mal sorumlusuna bildirim gönder - try { - // Express sunucusuna Socket.IO olay gönder - const response = await fetch('http://localhost:3000/api/socket-notify', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - event: 'fuel-slip-assigned', - data: { - goods_manager_id: newSlip.goods_manager_id, - fuel_slip_id: newSlip.id, - message: `${newSlip.vehicle_info.plate} plakalı araç için yeni yakıt fişi` - } - }) - }); - } catch (socketError) { - console.warn('Socket.IO bildirimi gönderilemedi:', socketError); + const socketData = { + goods_manager_id: newSlip.goods_manager_id, + fuel_slip_id: newSlip.id, + message: `${newSlip.vehicle_info.plate} plakalı araç için yeni yakıt fişi` + }; + console.log('📢 Sending socket notification: fuel-slip-assigned', socketData); + + // Socket client kullanarak bildirim gönder + const sent = emitSocketEvent('fuel-slip-assigned', socketData); + if (!sent) { + console.warn('⚠️ Socket notification could not be sent'); } return json({ @@ -229,27 +226,22 @@ export async function PUT({ request }) { }; fuelSlips[slipIndex] = updatedSlip; + console.log('✅ Fuel slip updated:', updatedSlip); // Socket.IO ile yakıt sorumlusuna bildirim gönder - try { - const response = await fetch('http://localhost:3000/api/socket-notify', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - event: 'fuel-slip-updated', - data: { - goods_manager_id: updatedSlip.goods_manager_id, - fuel_manager_id: updatedSlip.fuel_manager_id, - fuel_slip_id: updatedSlip.id, - status: updatedSlip.status, - approval_notes: updatedSlip.approval_notes - } - }) - }); - } catch (socketError) { - console.warn('Socket.IO bildirimi gönderilemedi:', socketError); + const socketData = { + goods_manager_id: updatedSlip.goods_manager_id, + fuel_manager_id: updatedSlip.fuel_manager_id, + fuel_slip_id: updatedSlip.id, + status: updatedSlip.status, + approval_notes: updatedSlip.approval_notes + }; + console.log('📢 Sending socket notification: fuel-slip-updated', socketData); + + // Socket client kullanarak bildirim gönder + const sent = emitSocketEvent('fuel-slip-updated', socketData); + if (!sent) { + console.warn('⚠️ Socket notification could not be sent'); } return json({ diff --git a/src/routes/api/goods-managers/+server.js b/src/routes/api/goods-managers/+server.js index 438c96c..be1e633 100644 --- a/src/routes/api/goods-managers/+server.js +++ b/src/routes/api/goods-managers/+server.js @@ -14,10 +14,23 @@ let goodsManagers = [ password: 'goods123', is_active: true, created_at: new Date().toISOString() + }, + { + id: 4, + full_name: 'İbrahim Kara', + rank: 'Yüzbaşı', + registration_number: 'GM002', + tc_kimlik: '98765432101', + phone: '05339876543', + email: 'ibrahim.kara@mil.tr', + username: 'ibrahim_kara', + password: 'kara123', + is_active: true, + created_at: new Date().toISOString() } ]; -let nextId = 4; +let nextId = 5; // GET - Tüm mal sorumlularını listele export async function GET({ request }) { diff --git a/src/routes/dashboard/+page.svelte b/src/routes/dashboard/+page.svelte index fcf422b..21b4189 100644 --- a/src/routes/dashboard/+page.svelte +++ b/src/routes/dashboard/+page.svelte @@ -114,12 +114,22 @@ // 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); } }); @@ -371,7 +381,7 @@ } if (page === 'goods-manager' && user?.role === 'goods_manager') { - console.log('🎯 Setting showGoodsManager to true'); + console.log('🎯 Navigating to goods-manager, user:', user); showGoodsManager = true; showMobileMenu = false; return; @@ -696,31 +706,7 @@ {:else if user.role === 'goods_manager' && showGoodsManager} -
-
-

Atanan Yakıt Fişleri

-
- 0 - Bekleyen Fiş -
-
- -
-
- - - - - - - - -
-

Onay Bekleyen Fiş Yok

-

Size atanan yeni yakıt fişleri olmadığında burada görünecekler.

-

✅ SPA navigasyonu başarıyla çalışıyor!

-
-
+ {:else if user.role === 'admin'} diff --git a/src/routes/fuel-slips/+page.svelte b/src/routes/fuel-slips/+page.svelte index ecc111a..63b4c8c 100644 --- a/src/routes/fuel-slips/+page.svelte +++ b/src/routes/fuel-slips/+page.svelte @@ -24,7 +24,7 @@ let showFuelForm = false; let successMessage = ''; let socket = null; - let selectedUnit = ''; + let selectedUnit = 'all'; let fuelSummary = { benzin: 0, motorin: 0 }; // Form değişkenleri @@ -55,6 +55,7 @@ // Fiş durumu güncellendiğinde listeyi yenile socket.on('fuel-slip-updated', (data) => { + console.log('Socket event received: fuel-slip-updated', data); if (data.fuel_manager_id === user.id) { loadData(); successMessage = `Fiş durumu güncellendi: ${data.status === 'approved' ? 'Onaylandı' : 'Reddedildi'}`; @@ -62,6 +63,14 @@ } }); + socket.on('connect', () => { + console.log('Socket.IO connected:', socket.id); + }); + + socket.on('disconnect', () => { + console.log('Socket.IO disconnected'); + }); + await loadData(); }); @@ -131,7 +140,7 @@ liters: '', km: '', personnel_id: '', - goods_manager_id: '', + goods_manager_id: goodsManagers.length > 0 ? goodsManagers[0].id : '', notes: '' }; } @@ -215,6 +224,41 @@ return type === 'benzin' ? '⛽' : '🛢️'; } + function openFuelForm() { + showFuelForm = true; + error = ''; + successMessage = ''; + } + + function closeFuelForm() { + showFuelForm = false; + resetForm(); + } + + function getFilteredSlips() { + if (!selectedUnit || selectedUnit === 'all') { + return fuelSlips; + } + return fuelSlips.filter(slip => slip.unit_name === selectedUnit); + } + + function getFilteredHistory() { + if (!selectedUnit || selectedUnit === 'all') { + return approvedRejectedSlips; + } + return approvedRejectedSlips.filter(slip => slip.unit_name === selectedUnit); + } + + function getPriorityClass(liters) { + if (liters > 100) return 'priority-high'; + if (liters > 50) return 'priority-medium'; + return 'priority-low'; + } + + function formatFuelType(type) { + return type === 'benzin' ? 'Benzin' : 'Motorin'; + } + function handleLogout() { localStorage.removeItem('user'); goto('/'); @@ -331,6 +375,17 @@ required /> +
+ + +