This commit is contained in:
2025-11-07 00:53:00 +03:00
parent c9abe6cc55
commit 673d53f126
9 changed files with 1308 additions and 12 deletions

View File

@@ -65,6 +65,54 @@ let units = [
let nextUnitId = 4;
// Vehicles veritabanı
let vehicles = [
{
id: 1,
brand: 'Mercedes-Benz',
model: 'Actros 1851',
year: 2020,
plate: '34 ABC 123',
fuel_type: 'Dizel',
fuel_capacity: 500,
current_fuel: 300,
status: 'Aktif',
driver_id: 3,
driver_name: 'Ali Veli',
created_at: new Date().toISOString()
},
{
id: 2,
brand: 'Volvo',
model: 'FH16 750',
year: 2021,
plate: '34 XYZ 789',
fuel_type: 'Dizel',
fuel_capacity: 600,
current_fuel: 450,
status: 'Aktif',
driver_id: 4,
driver_name: 'İbrahim Kara',
created_at: new Date().toISOString()
},
{
id: 3,
brand: 'Scania',
model: 'R730',
year: 2019,
plate: '34 DEF 456',
fuel_type: 'Dizel',
fuel_capacity: 550,
current_fuel: 200,
status: 'Bakımda',
driver_id: null,
driver_name: null,
created_at: new Date().toISOString()
}
];
let nextVehicleId = 4;
const app = express();
const server = createServer(app);
const io = new Server(server, {
@@ -77,7 +125,7 @@ const io = new Server(server, {
// Export io for use in other modules
export { io };
const PORT = process.env.PORT || 3002;
const PORT = process.env.PORT || 3001;
// ES Module equivalent of __dirname
const __filename = fileURLToPath(import.meta.url);
@@ -90,7 +138,7 @@ const dbPath = join(dbDir, 'yakit_takip.db');
// Middleware
app.use(express.json());
app.use(express.static('build'));
// Note: static file serving removed - SvelteKit handles frontend in development
// Session middleware
app.use(session({
@@ -602,6 +650,540 @@ app.delete('/api/goods-managers', async (req, res) => {
}
});
// Fuel Personnel API endpoint'leri
// GET - Tüm yakıt personelini listele
app.get('/api/fuel-personnel', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
const fuelPersonnel = [
{
id: 1,
full_name: 'Ahmet Demir',
rank: 'Üsteğmen',
registration_number: '111222',
tc_kimlik: '11111111111',
phone: '05321112233',
is_active: true,
created_at: new Date().toISOString()
},
{
id: 2,
full_name: 'Mustafa Çelik',
rank: 'Astsubay',
registration_number: '333444',
tc_kimlik: '22222222222',
phone: '05334455566',
is_active: true,
created_at: new Date().toISOString()
}
];
res.json({ fuelPersonnel });
});
// Fuel Slips API endpoint'leri
// GET - Yakıt fişlerini listele
app.get('/api/fuel-slips', (req, res) => {
const searchParams = req.query;
const status = searchParams.status;
const manager_id = searchParams.manager_id;
const fuel_manager_id = searchParams.fuel_manager_id;
// Veritabanı sorgusu
let query = 'SELECT * FROM fuel_slips WHERE 1=1';
const params = [];
// Status filtreleme
if (status) {
query += ' AND status = ?';
params.push(status);
}
// Mal sorumlusu filtreleme
if (manager_id) {
query += ' AND goods_manager_id = ?';
params.push(manager_id);
}
// Yakıt sorumlusu filtreleme
if (fuel_manager_id) {
query += ' AND fuel_manager_id = ?';
params.push(fuel_manager_id);
}
// Tarihe göre ters sırala
query += ' ORDER BY created_at DESC';
db.all(query, params, (err, rows) => {
if (err) {
console.error('GET fuel slips error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
// JSON string olarak saklanan alanları parse et
const fuelSlips = rows.map(row => ({
...row,
vehicle_info: row.vehicle_info ? JSON.parse(row.vehicle_info) : null,
personnel_info: row.personnel_info ? JSON.parse(row.personnel_info) : null,
goods_manager_info: row.goods_manager_info ? JSON.parse(row.goods_manager_info) : null,
fuel_manager_info: row.fuel_manager_info ? JSON.parse(row.fuel_manager_info) : null
}));
res.json({ fuelSlips });
});
});
// POST - Yeni yakıt fişi oluştur
app.post('/api/fuel-slips', async (req, res) => {
try {
const slipData = req.body;
console.log('📝 Creating new fuel slip with data:', slipData);
// Validasyon
const requiredFields = [
'date', 'force_command', 'unit_id', 'vehicle_id',
'fuel_type', 'liters', 'km', 'personnel_id',
'goods_manager_id', 'fuel_manager_id'
];
for (const field of requiredFields) {
if (!slipData[field]) {
return res.status(400).json({ message: `${field} alanı zorunludur.` });
}
}
// Litre ve KM validasyonu
if (slipData.liters <= 0 || slipData.km < 0) {
return res.status(400).json({ message: 'Litre ve KM değerleri geçersiz.' });
}
// Araç, personel ve mal sorumlusu bilgilerini getir
const [vehicle, unit, person, goodsManager] = await Promise.all([
vehicles.find(v => v.id === parseInt(slipData.vehicle_id)),
units.find(u => u.id === parseInt(slipData.unit_id)),
Promise.resolve({ // Temporary fuel personnel lookup
id: 1,
full_name: 'Ahmet Demir',
rank: 'Üsteğmen'
}),
Promise.resolve({ // Temporary goods manager lookup
id: slipData.goods_manager_id,
full_name: 'Mal Sorumlusu',
rank: 'Yüzbaşı'
})
]);
const vehicleInfo = vehicle ? {
brand: vehicle.brand,
model: vehicle.model,
plate: vehicle.plate,
year: vehicle.year
} : {
brand: 'Bilinmeyen',
model: 'Araç',
plate: 'Bilinmiyor',
year: 0
};
const personnelInfo = person ? {
full_name: person.full_name,
rank: person.rank
} : {
full_name: 'Bilinmeyen Personel',
rank: ''
};
const goodsManagerInfo = goodsManager ? {
full_name: goodsManager.full_name,
rank: goodsManager.rank
} : {
full_name: 'Bilinmeyen Mal Sorumlusu',
rank: ''
};
const fuelManagerInfo = { full_name: 'Yakıt Sorumlusu', rank: 'Yüzbaşı' };
const query = `
INSERT INTO fuel_slips (
date, force_command, unit_id, unit_name, vehicle_id, vehicle_info,
fuel_type, liters, km, personnel_id, personnel_info, goods_manager_id,
goods_manager_info, fuel_manager_id, fuel_manager_info, status, notes
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`;
const params = [
slipData.date,
slipData.force_command,
slipData.unit_id,
unit?.name || `Birim ${slipData.unit_id}`,
slipData.vehicle_id,
JSON.stringify(vehicleInfo),
slipData.fuel_type,
parseFloat(slipData.liters),
parseInt(slipData.km),
slipData.personnel_id,
JSON.stringify(personnelInfo),
slipData.goods_manager_id,
JSON.stringify(goodsManagerInfo),
slipData.fuel_manager_id,
JSON.stringify(fuelManagerInfo),
'pending',
slipData.notes || ''
];
db.run(query, params, function(err) {
if (err) {
console.error('Create fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
const newSlip = {
id: this.lastID,
date: slipData.date,
force_command: slipData.force_command,
unit_id: slipData.unit_id,
unit_name: unit?.name || `Birim ${slipData.unit_id}`,
vehicle_id: slipData.vehicle_id,
vehicle_info: vehicleInfo,
fuel_type: slipData.fuel_type,
liters: parseFloat(slipData.liters),
km: parseInt(slipData.km),
personnel_id: slipData.personnel_id,
personnel_info: personnelInfo,
goods_manager_id: slipData.goods_manager_id,
goods_manager_info: goodsManagerInfo,
fuel_manager_id: slipData.fuel_manager_id,
fuel_manager_info: fuelManagerInfo,
status: 'pending',
notes: slipData.notes || '',
created_at: new Date().toISOString()
};
console.log('✅ Fuel slip created:', newSlip);
// Socket.IO ile mal sorumlusuna bildirim gönder
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);
io.emit('fuel-slip-assigned', socketData);
res.json({
message: 'Yakıt fişi başarıyla oluşturuldu.',
fuelSlip: newSlip
});
});
} catch (error) {
console.error('Create fuel slip error:', error);
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// PUT - Fiş durumunu güncelle (onay/reddet)
app.put('/api/fuel-slips', async (req, res) => {
try {
const { id, status, approval_notes } = req.body;
if (!id || !status) {
return res.status(400).json({ message: 'ID ve durum zorunludur.' });
}
if (!['approved', 'rejected'].includes(status)) {
return res.status(400).json({ message: 'Geçersiz durum.' });
}
const query = `
UPDATE fuel_slips
SET status = ?, approval_date = ?, approval_notes = ?
WHERE id = ?
`;
const params = [
status,
new Date().toISOString(),
approval_notes || '',
parseInt(id)
];
db.run(query, params, function(err) {
if (err) {
console.error('Update fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
if (this.changes === 0) {
return res.status(404).json({ message: 'Fiş bulunamadı.' });
}
// Güncellenmiş fişi getir
db.get('SELECT * FROM fuel_slips WHERE id = ?', [id], (err, row) => {
if (err) {
console.error('Get updated fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
const updatedSlip = {
...row,
vehicle_info: row.vehicle_info ? JSON.parse(row.vehicle_info) : null,
personnel_info: row.personnel_info ? JSON.parse(row.personnel_info) : null,
goods_manager_info: row.goods_manager_info ? JSON.parse(row.goods_manager_info) : null,
fuel_manager_info: row.fuel_manager_info ? JSON.parse(row.fuel_manager_info) : null
};
console.log('✅ Fuel slip updated:', updatedSlip);
// Socket.IO ile yakıt sorumlusuna bildirim gönder
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);
io.emit('fuel-slip-updated', socketData);
res.json({
message: `Fiş başarıyla ${status === 'approved' ? 'onaylandı' : 'reddedildi'}.`,
fuelSlip: updatedSlip
});
});
});
} catch (error) {
console.error('Update fuel slip error:', error);
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// DELETE - Fiş sil
app.delete('/api/fuel-slips', async (req, res) => {
try {
const { id } = req.body;
if (!id) {
return res.status(400).json({ message: 'Fiş ID zorunludur.' });
}
// Önce fişin durumunu kontrol et
db.get('SELECT status FROM fuel_slips WHERE id = ?', [id], (err, row) => {
if (err) {
console.error('Check fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
if (!row) {
return res.status(404).json({ message: 'Fiş bulunamadı.' });
}
// Sadece pending olan fişler silinebilir
if (row.status !== 'pending') {
return res.status(400).json({ message: 'Sadece bekleyen fişler silinebilir.' });
}
// Fiş sil
db.run('DELETE FROM fuel_slips WHERE id = ?', [id], function(err) {
if (err) {
console.error('Delete fuel slip error:', err);
return res.status(500).json({ message: 'Veritabanı hatası.' });
}
if (this.changes === 0) {
return res.status(404).json({ message: 'Fiş bulunamadı.' });
}
res.json({
message: 'Fiş başarıyla silindi.',
fuelSlipId: parseInt(id)
});
});
});
} catch (error) {
console.error('Delete fuel slip error:', error);
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Vehicles API endpoint'leri
// GET - Tüm araçları listele
app.get('/api/vehicles', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
res.json({ vehicles });
});
// POST - Yeni araç ekle
app.post('/api/vehicles', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const {
brand,
model,
year,
plate,
fuel_type,
fuel_capacity,
current_fuel,
status = 'Aktif',
driver_id,
driver_name
} = req.body;
// Validasyon
if (!brand || !model || !year || !plate || !fuel_type || !fuel_capacity) {
return res.status(400).json({ message: 'Tüm zorunlu alanları doldurun.' });
}
if (year < 1990 || year > new Date().getFullYear() + 1) {
return res.status(400).json({ message: 'Geçerli bir yıl girin.' });
}
if (current_fuel < 0 || current_fuel > fuel_capacity) {
return res.status(400).json({ message: 'Mevcut yakıt değeri geçersiz.' });
}
// Plaka tekrar kontrolü
const existingVehicle = vehicles.find(v =>
v.plate.toLowerCase() === plate.toLowerCase()
);
if (existingVehicle) {
return res.status(400).json({ message: 'Bu plaka zaten kayıtlı.' });
}
// Yeni araç oluştur
const newVehicle = {
id: nextVehicleId++,
brand: brand.trim(),
model: model.trim(),
year: parseInt(year),
plate: plate.trim().toUpperCase(),
fuel_type: fuel_type.trim(),
fuel_capacity: parseInt(fuel_capacity),
current_fuel: parseInt(current_fuel) || 0,
status: status.trim(),
driver_id: driver_id ? parseInt(driver_id) : null,
driver_name: driver_name ? driver_name.trim() : null,
created_at: new Date().toISOString()
};
vehicles.push(newVehicle);
res.json({
message: 'Araç başarıyla eklendi.',
vehicle: newVehicle
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// PUT - Araç güncelle
app.put('/api/vehicles', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const {
id,
brand,
model,
year,
plate,
fuel_type,
fuel_capacity,
current_fuel,
status,
driver_id,
driver_name
} = req.body;
// Validasyon
if (!id || !brand || !model || !year || !plate || !fuel_type || !fuel_capacity) {
return res.status(400).json({ message: 'Tüm zorunlu alanları doldurun.' });
}
if (year < 1990 || year > new Date().getFullYear() + 1) {
return res.status(400).json({ message: 'Geçerli bir yıl girin.' });
}
if (current_fuel < 0 || current_fuel > fuel_capacity) {
return res.status(400).json({ message: 'Mevcut yakıt değeri geçersiz.' });
}
// Araç bul
const vehicleIndex = vehicles.findIndex(v => v.id === parseInt(id));
if (vehicleIndex === -1) {
return res.status(404).json({ message: 'Araç bulunamadı.' });
}
// Plaka tekrar kontrolü (diğer araçlar için)
const existingVehicle = vehicles.find(v =>
v.id !== parseInt(id) && v.plate.toLowerCase() === plate.toLowerCase()
);
if (existingVehicle) {
return res.status(400).json({ message: 'Bu plaka başka bir araçta kullanılıyor.' });
}
// Araç güncelle
vehicles[vehicleIndex] = {
...vehicles[vehicleIndex],
brand: brand.trim(),
model: model.trim(),
year: parseInt(year),
plate: plate.trim().toUpperCase(),
fuel_type: fuel_type.trim(),
fuel_capacity: parseInt(fuel_capacity),
current_fuel: parseInt(current_fuel) || 0,
status: status.trim(),
driver_id: driver_id ? parseInt(driver_id) : null,
driver_name: driver_name ? driver_name.trim() : null
};
res.json({
message: 'Araç başarıyla güncellendi.',
vehicle: vehicles[vehicleIndex]
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// DELETE - Araç sil
app.delete('/api/vehicles', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const { id } = req.body;
if (!id) {
return res.status(400).json({ message: 'Araç ID zorunludur.' });
}
// Araç bul
const vehicleIndex = vehicles.findIndex(v => v.id === parseInt(id));
if (vehicleIndex === -1) {
return res.status(404).json({ message: 'Araç bulunamadı.' });
}
// Araç sil
const deletedVehicle = vehicles.splice(vehicleIndex, 1)[0];
res.json({
message: 'Araç başarıyla silindi.',
vehicle: deletedVehicle
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Socket.IO bağlantıları
io.on('connection', (socket) => {
console.log('✅ Bir kullanıcı bağlandı:', socket.id);
@@ -622,10 +1204,8 @@ io.on('connection', (socket) => {
});
});
// SvelteKit için tüm route'ları handle et
app.use('*', (req, res) => {
res.sendFile('build/index.html', { root: '.' });
});
// API server only - frontend handled by SvelteKit dev server in development
// In production, the build will be served differently
// Sunucuyu başlat
async function startServer() {