fixed
This commit is contained in:
1
.serena/.gitignore
vendored
Normal file
1
.serena/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/cache
|
||||
84
.serena/project.yml
Normal file
84
.serena/project.yml
Normal file
@@ -0,0 +1,84 @@
|
||||
# list of languages for which language servers are started; choose from:
|
||||
# al bash clojure cpp csharp csharp_omnisharp
|
||||
# dart elixir elm erlang fortran go
|
||||
# haskell java julia kotlin lua markdown
|
||||
# nix perl php python python_jedi r
|
||||
# rego ruby ruby_solargraph rust scala swift
|
||||
# terraform typescript typescript_vts zig
|
||||
# Note:
|
||||
# - For C, use cpp
|
||||
# - For JavaScript, use typescript
|
||||
# Special requirements:
|
||||
# - csharp: Requires the presence of a .sln file in the project folder.
|
||||
# When using multiple languages, the first language server that supports a given file will be used for that file.
|
||||
# The first language is the default language and the respective language server will be used as a fallback.
|
||||
# Note that when using the JetBrains backend, language servers are not used and this list is correspondingly ignored.
|
||||
languages:
|
||||
- typescript
|
||||
|
||||
# the encoding used by text files in the project
|
||||
# For a list of possible encodings, see https://docs.python.org/3.11/library/codecs.html#standard-encodings
|
||||
encoding: "utf-8"
|
||||
|
||||
# whether to use the project's gitignore file to ignore files
|
||||
# Added on 2025-04-07
|
||||
ignore_all_files_in_gitignore: true
|
||||
|
||||
# list of additional paths to ignore
|
||||
# same syntax as gitignore, so you can use * and **
|
||||
# Was previously called `ignored_dirs`, please update your config if you are using that.
|
||||
# Added (renamed) on 2025-04-07
|
||||
ignored_paths: []
|
||||
|
||||
# whether the project is in read-only mode
|
||||
# If set to true, all editing tools will be disabled and attempts to use them will result in an error
|
||||
# Added on 2025-04-18
|
||||
read_only: false
|
||||
|
||||
# list of tool names to exclude. We recommend not excluding any tools, see the readme for more details.
|
||||
# Below is the complete list of tools for convenience.
|
||||
# To make sure you have the latest list of tools, and to view their descriptions,
|
||||
# execute `uv run scripts/print_tool_overview.py`.
|
||||
#
|
||||
# * `activate_project`: Activates a project by name.
|
||||
# * `check_onboarding_performed`: Checks whether project onboarding was already performed.
|
||||
# * `create_text_file`: Creates/overwrites a file in the project directory.
|
||||
# * `delete_lines`: Deletes a range of lines within a file.
|
||||
# * `delete_memory`: Deletes a memory from Serena's project-specific memory store.
|
||||
# * `execute_shell_command`: Executes a shell command.
|
||||
# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced.
|
||||
# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type).
|
||||
# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type).
|
||||
# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes.
|
||||
# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file.
|
||||
# * `initial_instructions`: Gets the initial instructions for the current project.
|
||||
# Should only be used in settings where the system prompt cannot be set,
|
||||
# e.g. in clients you have no control over, like Claude Desktop.
|
||||
# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol.
|
||||
# * `insert_at_line`: Inserts content at a given line in a file.
|
||||
# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol.
|
||||
# * `list_dir`: Lists files and directories in the given directory (optionally with recursion).
|
||||
# * `list_memories`: Lists memories in Serena's project-specific memory store.
|
||||
# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building).
|
||||
# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context).
|
||||
# * `read_file`: Reads a file within the project directory.
|
||||
# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store.
|
||||
# * `remove_project`: Removes a project from the Serena configuration.
|
||||
# * `replace_lines`: Replaces a range of lines within a file with new content.
|
||||
# * `replace_symbol_body`: Replaces the full definition of a symbol.
|
||||
# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen.
|
||||
# * `search_for_pattern`: Performs a search for a pattern in the project.
|
||||
# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase.
|
||||
# * `switch_modes`: Activates modes by providing a list of their names
|
||||
# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information.
|
||||
# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task.
|
||||
# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed.
|
||||
# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store.
|
||||
excluded_tools: []
|
||||
|
||||
# initial prompt for the project. It will always be given to the LLM upon activating the project
|
||||
# (contrary to the memories, which are loaded on demand).
|
||||
initial_prompt: ""
|
||||
|
||||
project_name: "ytp-glm"
|
||||
included_optional_tools: []
|
||||
@@ -5,7 +5,7 @@
|
||||
KNOWLEDGE_BASE.md'deki iş akışlarına göre implement edilen tam fonksiyonel yakıt takip sistemi.
|
||||
|
||||
### 🚀 **Sunucu Durumu**
|
||||
- **Frontend**: `http://localhost:5174/` (SvelteKit)
|
||||
- **Frontend**: `http://localhost:5173/` (SvelteKit)
|
||||
- **Backend**: `http://localhost:3000` (Express/Socket.IO)
|
||||
- **Status**: ✅ Çalışıyor
|
||||
|
||||
@@ -23,7 +23,7 @@ KNOWLEDGE_BASE.md'deki iş akışlarına göre implement edilen tam fonksiyonel
|
||||
|
||||
#### 1.1 Giriş Testi
|
||||
```bash
|
||||
✓ Adım 1: http://localhost:5174/ adresine git
|
||||
✓ Adım 1: http://localhost:5173/ adresine git
|
||||
✓ Adım 2: "admin" / "admin123" ile giriş yap
|
||||
✓ Beklenen: /dashboard sayfasına yönlendirme
|
||||
✓ Kontrol: Sol menüde "Yönetim Paneli" başlığı
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
"client": "vite dev",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview",
|
||||
"start": "node src/server.js",
|
||||
"start": "node src/production-server.js",
|
||||
"prod": "npm run build && npm run start",
|
||||
"setup": "node -e \"import('./src/server.js').then(() => console.log('Database setup completed')).catch(console.error);\"",
|
||||
"init-db": "node -e \"import('./src/server.js').catch(console.error)\""
|
||||
},
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
console.log('🔌 Connecting to Socket.IO...');
|
||||
// Socket.IO bağlantısı
|
||||
socket = io('http://localhost:3000');
|
||||
socket = io('http://localhost:3001');
|
||||
|
||||
console.log('👤 Goods Manager ID:', user.id);
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ let socket = null;
|
||||
|
||||
export function getSocketClient() {
|
||||
if (!socket) {
|
||||
socket = io('http://localhost:3000', {
|
||||
socket = io('http://localhost:3001', {
|
||||
transports: ['websocket', 'polling']
|
||||
});
|
||||
|
||||
|
||||
630
src/production-server.js
Normal file
630
src/production-server.js
Normal file
@@ -0,0 +1,630 @@
|
||||
import express from 'express';
|
||||
import session from 'express-session';
|
||||
import { createServer } from 'http';
|
||||
import { Server } from 'socket.io';
|
||||
import sqlite3 from 'sqlite3';
|
||||
import bcrypt from 'bcrypt';
|
||||
import { promises as fs } from 'fs';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import {
|
||||
getGoodsManagers,
|
||||
addGoodsManager,
|
||||
updateGoodsManager,
|
||||
deleteGoodsManager
|
||||
} from './lib/data/goodsManagers.js';
|
||||
|
||||
// Import the handler from the built SvelteKit app
|
||||
import { handler } from '../build/handler.js';
|
||||
|
||||
// Units veritabanı
|
||||
let units = [
|
||||
{
|
||||
id: 1,
|
||||
name: '1. Motorlu Piyade Tugayı',
|
||||
address: 'Mecidiyeköy, Şişli/İstanbul',
|
||||
stk: 'STK-12345',
|
||||
btk: 'BTK-67890',
|
||||
commander: {
|
||||
full_name: 'Mehmet Yılmaz',
|
||||
rank: 'Yüzbaşı',
|
||||
registration_number: '123456',
|
||||
tc_kimlik: '12345678901',
|
||||
phone: '05321234567'
|
||||
},
|
||||
created_at: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '2. Zırhlı Tabur',
|
||||
address: 'Havran, Balıkesir',
|
||||
stk: 'STK-54321',
|
||||
btk: 'BTK-09876',
|
||||
commander: {
|
||||
full_name: 'Ali Kaya',
|
||||
rank: 'Binbaşı',
|
||||
registration_number: '654321',
|
||||
tc_kimlik: '98765432109',
|
||||
phone: '05337654321'
|
||||
},
|
||||
created_at: new Date().toISOString()
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '3. Komutanlık',
|
||||
address: 'Çankaya, Ankara',
|
||||
stk: 'STK-11111',
|
||||
btk: 'BTK-22222',
|
||||
commander: {
|
||||
full_name: 'Hasan Demir',
|
||||
rank: 'Üsteğmen',
|
||||
registration_number: '111111',
|
||||
tc_kimlik: '11111111111',
|
||||
phone: '05321111111'
|
||||
},
|
||||
created_at: new Date().toISOString()
|
||||
}
|
||||
];
|
||||
|
||||
let nextUnitId = 4;
|
||||
|
||||
const app = express();
|
||||
const server = createServer(app);
|
||||
const io = new Server(server, {
|
||||
cors: {
|
||||
origin: process.env.NODE_ENV === 'production' ? false : ["http://localhost:5173"],
|
||||
methods: ["GET", "POST"]
|
||||
}
|
||||
});
|
||||
|
||||
// Export io for use in other modules
|
||||
export { io };
|
||||
|
||||
const PORT = process.env.PORT || 3001;
|
||||
|
||||
// ES Module equivalent of __dirname
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
// Database path setup - ensure /db directory exists and use it
|
||||
const projectRoot = dirname(__dirname); // Go up from src/ to project root
|
||||
const dbDir = join(projectRoot, 'db');
|
||||
const dbPath = join(dbDir, 'yakit_takip.db');
|
||||
|
||||
// Middleware
|
||||
app.use(express.json());
|
||||
|
||||
// Session middleware
|
||||
app.use(session({
|
||||
secret: 'yakit-takip-modulu-secret-key-2023',
|
||||
resave: false,
|
||||
saveUninitialized: false,
|
||||
cookie: {
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
maxAge: 24 * 60 * 60 * 1000 // 24 saat
|
||||
}
|
||||
}));
|
||||
|
||||
// Ensure /db directory exists
|
||||
async function ensureDbDirectory() {
|
||||
try {
|
||||
await fs.mkdir(dbDir, { recursive: true });
|
||||
console.log(`📁 Database directory ensured: ${dbDir}`);
|
||||
} catch (error) {
|
||||
console.error('❌ Error creating database directory:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Veritabanı değişkeni (başlangıçta null)
|
||||
let db;
|
||||
|
||||
// Veritabanı bağlantısını oluştur
|
||||
async function createDatabaseConnection() {
|
||||
return new Promise((resolve, reject) => {
|
||||
db = new sqlite3.Database(dbPath, (err) => {
|
||||
if (err) {
|
||||
console.error('❌ Database connection error:', err);
|
||||
reject(err);
|
||||
} else {
|
||||
console.log('✅ Database connection established');
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Veritabanı tablolarını oluştur
|
||||
async function initializeDatabase() {
|
||||
return new Promise((resolve, reject) => {
|
||||
db.serialize(() => {
|
||||
// Kullanıcılar tablosu
|
||||
db.run(`CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
password TEXT NOT NULL,
|
||||
role TEXT NOT NULL,
|
||||
full_name TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
is_active BOOLEAN DEFAULT 1
|
||||
)`, (err) => {
|
||||
if (err) reject(err);
|
||||
});
|
||||
|
||||
// Örnek kullanıcıları ekle
|
||||
const users = [
|
||||
{ username: 'admin', password: 'admin123', role: 'admin', full_name: 'Sistem Yöneticisi' },
|
||||
{ username: 'fuel', password: 'fuel123', role: 'fuel_manager', full_name: 'Yakıt Sorumlusu' },
|
||||
{ username: 'goods', password: 'goods123', role: 'goods_manager', full_name: 'Mal Sorumlusu' },
|
||||
{ username: 'ibrahim_kara', password: 'kara123', role: 'goods_manager', full_name: 'İbrahim Kara' }
|
||||
];
|
||||
|
||||
// Yakıt fişleri tablosu
|
||||
db.run(`CREATE TABLE IF NOT EXISTS fuel_slips (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date TEXT NOT NULL,
|
||||
force_command TEXT NOT NULL,
|
||||
unit_id INTEGER,
|
||||
unit_name TEXT,
|
||||
vehicle_id INTEGER,
|
||||
vehicle_info TEXT,
|
||||
fuel_type TEXT NOT NULL,
|
||||
liters REAL NOT NULL,
|
||||
km INTEGER,
|
||||
personnel_id INTEGER,
|
||||
personnel_info TEXT,
|
||||
goods_manager_id INTEGER,
|
||||
goods_manager_info TEXT,
|
||||
fuel_manager_id INTEGER,
|
||||
fuel_manager_info TEXT,
|
||||
status TEXT DEFAULT 'pending',
|
||||
notes TEXT,
|
||||
approval_date TEXT,
|
||||
approval_notes TEXT,
|
||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)`, (err) => {
|
||||
if (err) reject(err);
|
||||
});
|
||||
|
||||
// Her kullanıcıyı kontrol et ve yoksa ekle
|
||||
users.forEach(async (user) => {
|
||||
const hashedPassword = await bcrypt.hash(user.password, 10);
|
||||
|
||||
db.get('SELECT id FROM users WHERE username = ?', [user.username], (err, row) => {
|
||||
if (!row) {
|
||||
db.run('INSERT INTO users (username, password, role, full_name) VALUES (?, ?, ?, ?)',
|
||||
[user.username, hashedPassword, user.role, user.full_name]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// API Routes
|
||||
|
||||
// Login endpoint
|
||||
app.post('/api/login', async (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!username || !password) {
|
||||
return res.status(400).json({ message: 'Kullanıcı adı ve şifre gerekli.' });
|
||||
}
|
||||
|
||||
try {
|
||||
db.get('SELECT * FROM users WHERE username = ? AND is_active = 1', [username], async (err, user) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ message: 'Veritabanı hatası.' });
|
||||
}
|
||||
|
||||
if (!user) {
|
||||
return res.status(401).json({ message: 'Kullanıcı bulunamadı.' });
|
||||
}
|
||||
|
||||
const passwordMatch = await bcrypt.compare(password, user.password);
|
||||
if (!passwordMatch) {
|
||||
return res.status(401).json({ message: 'Şifre hatalı.' });
|
||||
}
|
||||
|
||||
// Session oluştur
|
||||
let sessionUser = {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
full_name: user.full_name
|
||||
};
|
||||
|
||||
// Eğer goods_manager ise, goods_managers API'den gerçek ID'yi al
|
||||
if (user.role === 'goods_manager') {
|
||||
try {
|
||||
const goodsManagersRes = await fetch('http://localhost:3000/api/goods-managers');
|
||||
if (goodsManagersRes.ok) {
|
||||
const goodsData = await goodsManagersRes.json();
|
||||
const goodsManager = goodsData.goodsManagers?.find(gm => gm.username === user.username);
|
||||
if (goodsManager) {
|
||||
sessionUser.id = goodsManager.id; // goods_manager ID'sini kullan
|
||||
console.log(`✅ Goods manager logged in: ${user.full_name} (ID: ${goodsManager.id})`);
|
||||
}
|
||||
}
|
||||
} catch (fetchError) {
|
||||
console.warn('⚠️ Could not fetch goods manager ID:', fetchError);
|
||||
}
|
||||
}
|
||||
|
||||
req.session.user = sessionUser;
|
||||
|
||||
res.json({
|
||||
message: 'Giriş başarılı.',
|
||||
user: sessionUser
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: 'Sunucu hatası.' });
|
||||
}
|
||||
});
|
||||
|
||||
// Logout endpoint
|
||||
app.post('/api/logout', (req, res) => {
|
||||
req.session.destroy((err) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ message: 'Çıkış yapılamadı.' });
|
||||
}
|
||||
res.json({ message: 'Çıkış başarılı.' });
|
||||
});
|
||||
});
|
||||
|
||||
// Mevcut kullanıcı bilgisi
|
||||
app.get('/api/user', (req, res) => {
|
||||
if (!req.session.user) {
|
||||
return res.status(401).json({ message: 'Oturum bulunamadı.' });
|
||||
}
|
||||
|
||||
res.json({ user: req.session.user });
|
||||
});
|
||||
|
||||
// Socket.IO bildirim endpoint'i
|
||||
app.post('/api/socket-notify', (req, res) => {
|
||||
const { event, data } = req.body;
|
||||
|
||||
if (!event || !data) {
|
||||
return res.status(400).json({ message: 'Event ve data zorunludur.' });
|
||||
}
|
||||
|
||||
// Socket.IO ile olay yayınla
|
||||
console.log(`📢 Socket.IO event emitted: ${event}`, data);
|
||||
io.emit(event, data);
|
||||
|
||||
res.json({ message: 'Bildirim gönderildi.' });
|
||||
});
|
||||
|
||||
// Tüm kullanıcıları getir (sadece admin)
|
||||
app.get('/api/users', (req, res) => {
|
||||
if (!req.session.user || req.session.user.role !== 'admin') {
|
||||
return res.status(403).json({ message: 'Yetkisiz erişim.' });
|
||||
}
|
||||
|
||||
db.all('SELECT id, username, role, full_name, created_at, is_active FROM users', (err, users) => {
|
||||
if (err) {
|
||||
return res.status(500).json({ message: 'Veritabanı hatası.' });
|
||||
}
|
||||
res.json({ users });
|
||||
});
|
||||
});
|
||||
|
||||
// Units API endpoint'leri
|
||||
app.get('/api/units', (req, res) => {
|
||||
res.json({ units });
|
||||
});
|
||||
|
||||
app.post('/api/units', (req, res) => {
|
||||
try {
|
||||
const {
|
||||
name,
|
||||
address,
|
||||
stk,
|
||||
btk,
|
||||
commander
|
||||
} = req.body;
|
||||
|
||||
// Validasyon
|
||||
if (!name || !address || !stk || !btk || !commander) {
|
||||
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
|
||||
}
|
||||
|
||||
// Komutan validasyonu
|
||||
const { full_name, rank, registration_number, tc_kimlik, phone } = commander;
|
||||
if (!full_name || !rank || !registration_number || !tc_kimlik || !phone) {
|
||||
return res.status(400).json({ message: 'Birlik sorumlusunun tüm bilgileri zorunludur.' });
|
||||
}
|
||||
|
||||
// TC Kimlik numarası validasyonu
|
||||
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
|
||||
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
|
||||
}
|
||||
|
||||
// Yeni birlik oluştur
|
||||
const newUnit = {
|
||||
id: nextUnitId++,
|
||||
name: name.trim(),
|
||||
address: address.trim(),
|
||||
stk: stk.trim().toUpperCase(),
|
||||
btk: btk.trim().toUpperCase(),
|
||||
commander: {
|
||||
full_name: full_name.trim(),
|
||||
rank: rank.trim(),
|
||||
registration_number: registration_number.trim(),
|
||||
tc_kimlik: tc_kimlik.trim(),
|
||||
phone: phone.trim()
|
||||
},
|
||||
created_at: new Date().toISOString()
|
||||
};
|
||||
|
||||
units.push(newUnit);
|
||||
|
||||
res.json({
|
||||
message: 'Birlik başarıyla eklendi.',
|
||||
unit: newUnit
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: 'Sunucu hatası.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/units', (req, res) => {
|
||||
try {
|
||||
const {
|
||||
id,
|
||||
name,
|
||||
address,
|
||||
stk,
|
||||
btk,
|
||||
commander
|
||||
} = req.body;
|
||||
|
||||
// Validasyon
|
||||
if (!id || !name || !address || !stk || !btk || !commander) {
|
||||
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
|
||||
}
|
||||
|
||||
// Komutan validasyonu
|
||||
const { full_name, rank, registration_number, tc_kimlik, phone } = commander;
|
||||
if (!full_name || !rank || !registration_number || !tc_kimlik || !phone) {
|
||||
return res.status(400).json({ message: 'Birlik sorumlusunun tüm bilgileri zorunludur.' });
|
||||
}
|
||||
|
||||
// TC Kimlik numarası validasyonu
|
||||
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
|
||||
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
|
||||
}
|
||||
|
||||
// Birlik bul
|
||||
const unitIndex = units.findIndex(u => u.id === parseInt(id));
|
||||
if (unitIndex === -1) {
|
||||
return res.status(404).json({ message: 'Birlik bulunamadı.' });
|
||||
}
|
||||
|
||||
// Birlik güncelle
|
||||
units[unitIndex] = {
|
||||
...units[unitIndex],
|
||||
name: name.trim(),
|
||||
address: address.trim(),
|
||||
stk: stk.trim().toUpperCase(),
|
||||
btk: btk.trim().toUpperCase(),
|
||||
commander: {
|
||||
full_name: full_name.trim(),
|
||||
rank: rank.trim(),
|
||||
registration_number: registration_number.trim(),
|
||||
tc_kimlik: tc_kimlik.trim(),
|
||||
phone: phone.trim()
|
||||
}
|
||||
};
|
||||
|
||||
res.json({
|
||||
message: 'Birlik başarıyla güncellendi.',
|
||||
unit: units[unitIndex]
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: 'Sunucu hatası.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/units', (req, res) => {
|
||||
try {
|
||||
const { id } = req.body;
|
||||
|
||||
if (!id) {
|
||||
return res.status(400).json({ message: 'Birlik ID zorunludur.' });
|
||||
}
|
||||
|
||||
// Birlik bul
|
||||
const unitIndex = units.findIndex(u => u.id === parseInt(id));
|
||||
if (unitIndex === -1) {
|
||||
return res.status(404).json({ message: 'Birlik bulunamadı.' });
|
||||
}
|
||||
|
||||
// Birlik sil
|
||||
const deletedUnit = units.splice(unitIndex, 1)[0];
|
||||
|
||||
res.json({
|
||||
message: 'Birlik başarıyla silindi.',
|
||||
unit: deletedUnit
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: 'Sunucu hatası.' });
|
||||
}
|
||||
});
|
||||
|
||||
// Goods Managers API endpoint'leri
|
||||
app.get('/api/goods-managers', (req, res) => {
|
||||
try {
|
||||
const goodsManagers = getGoodsManagers();
|
||||
res.json({ goodsManagers });
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: 'Mal sorumluları alınırken hata oluştu.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/goods-managers', async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
full_name,
|
||||
rank,
|
||||
registration_number,
|
||||
tc_kimlik,
|
||||
phone,
|
||||
unit_id,
|
||||
username,
|
||||
password,
|
||||
is_active = true
|
||||
} = req.body;
|
||||
|
||||
const newManager = addGoodsManager({
|
||||
full_name,
|
||||
rank,
|
||||
registration_number,
|
||||
tc_kimlik,
|
||||
phone,
|
||||
unit_id,
|
||||
unit_name: units.find(u => u.id === parseInt(unit_id))?.name || 'Bilinmeyen Birlik',
|
||||
username,
|
||||
password,
|
||||
is_active
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: 'Personel başarıyla eklendi.',
|
||||
goodsManager: newManager
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
if (error.message.includes('zorunludur') ||
|
||||
error.message.includes('zaten kayıtlı') ||
|
||||
error.message.includes('Geçersiz') ||
|
||||
error.message.includes('karakter')) {
|
||||
return res.status(400).json({ message: error.message });
|
||||
}
|
||||
res.status(500).json({ message: 'Sunucu hatası.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.put('/api/goods-managers', async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
id,
|
||||
full_name,
|
||||
rank,
|
||||
registration_number,
|
||||
tc_kimlik,
|
||||
phone,
|
||||
unit_id,
|
||||
username,
|
||||
password,
|
||||
is_active
|
||||
} = req.body;
|
||||
|
||||
const updatedManager = updateGoodsManager(id, {
|
||||
full_name,
|
||||
rank,
|
||||
registration_number,
|
||||
tc_kimlik,
|
||||
phone,
|
||||
unit_id,
|
||||
unit_name: units.find(u => u.id === parseInt(unit_id))?.name || 'Bilinmeyen Birlik',
|
||||
username,
|
||||
password,
|
||||
is_active
|
||||
});
|
||||
|
||||
res.json({
|
||||
message: 'Personel başarıyla güncellendi.',
|
||||
goodsManager: updatedManager
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
if (error.message.includes('zorunludur') ||
|
||||
error.message.includes('bulunamadı') ||
|
||||
error.message.includes('zaten kayıtlı') ||
|
||||
error.message.includes('Geçersiz') ||
|
||||
error.message.includes('karakter')) {
|
||||
return res.status(error.message.includes('bulunamadı') ? 404 : 400).json({ message: error.message });
|
||||
}
|
||||
res.status(500).json({ message: 'Sunucu hatası.' });
|
||||
}
|
||||
});
|
||||
|
||||
app.delete('/api/goods-managers', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.body;
|
||||
|
||||
if (!id) {
|
||||
return res.status(400).json({ message: 'Mal sorumlusu ID zorunludur.' });
|
||||
}
|
||||
|
||||
const deletedManager = deleteGoodsManager(id);
|
||||
|
||||
res.json({
|
||||
message: 'Mal sorumlusu başarıyla silindi.',
|
||||
goodsManager: deletedManager
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
if (error.message.includes('bulunamadı')) {
|
||||
return res.status(404).json({ message: error.message });
|
||||
}
|
||||
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);
|
||||
|
||||
// API'den gelen event'ları dinle ve broadcast et
|
||||
socket.on('api-fuel-slip-assigned', (data) => {
|
||||
console.log('📢 API event received: api-fuel-slip-assigned, broadcasting to all clients', data);
|
||||
io.emit('fuel-slip-assigned', data);
|
||||
});
|
||||
|
||||
socket.on('api-fuel-slip-updated', (data) => {
|
||||
console.log('📢 API event received: api-fuel-slip-updated, broadcasting to all clients', data);
|
||||
io.emit('fuel-slip-updated', data);
|
||||
});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log('❌ Bir kullanıcı ayrıldı:', socket.id);
|
||||
});
|
||||
});
|
||||
|
||||
// Let SvelteKit handle everything else
|
||||
app.use(handler);
|
||||
|
||||
// Sunucuyu başlat
|
||||
async function startServer() {
|
||||
try {
|
||||
// Ensure database directory exists first
|
||||
await ensureDbDirectory();
|
||||
console.log(`📄 Database file path: ${dbPath}`);
|
||||
|
||||
// Create database connection
|
||||
await createDatabaseConnection();
|
||||
|
||||
// Initialize database and tables
|
||||
await initializeDatabase();
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log(`🚀 Production server http://localhost:${PORT} adresinde çalışıyor`);
|
||||
console.log(`📱 Socket.IO sunucusu aktif`);
|
||||
console.log(`💾 Veritabanı: ${dbPath}`);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('❌ Sunucu başlatılamadı:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
startServer();
|
||||
592
src/server.js
592
src/server.js
@@ -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() {
|
||||
|
||||
@@ -7,7 +7,7 @@ export default defineConfig({
|
||||
port: 5173,
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://localhost:3002',
|
||||
target: 'http://localhost:3001',
|
||||
changeOrigin: true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user