Logic fixed

This commit is contained in:
2025-11-08 16:55:41 +03:00
parent 495e6ae1a2
commit b091a0e3fc
16 changed files with 788 additions and 497 deletions

View File

@@ -1,4 +1,4 @@
# Yakıt Takip Modülü
# Yakıt Takip Uygulaması
Akaryakıt istasyonu için geliştirilmiş modern ve kullanıcı dostu yönetim sistemi.
@@ -206,4 +206,4 @@ Proje hakkında sorularınız için lütfen iletişime geçin.
---
**Yakıt Takip Modülü** - Modern Akaryakıt İstasyonu Yönetim Sistemi
**Yakıt Takip Uygulaması** - Modern Akaryakıt İstasyonu Yönetim Sistemi

View File

@@ -1,4 +1,4 @@
# Yakıt Takip Modülü - Kapsamlı Proje Dokümantasyonu
# Yakıt Takip Uygulaması - Kapsamlı Proje Dokümantasyonu
## 📋 İçerik Tablosu
1. [Proje Genel Bakış](#proje-genel-bakış)
@@ -18,7 +18,7 @@
## 🎯 Proje Genel Bakış
Yakıt Takip Modülü, akaryakıt istasyonları için geliştirilmiş, modern ve kullanıcı dostu bir yönetim sistemidir. Sistem, yakıt ikmal süreçlerini dijitalleştirerek verimliliği artırmayı ve süreç takibini kolaylaştırmayı hedefler.
Yakıt Takip Uygulaması, akaryakıt istasyonları için geliştirilmiş, modern ve kullanıcı dostu bir yönetim sistemidir. Sistem, yakıt ikmal süreçlerini dijitalleştirerek verimliliği artırmayı ve süreç takibini kolaylaştırmayı hedefler.
### Ana Hedefler
- **Dijital Dönüşüm**: Kağıt bazlı süreçlerin dijitalleştirilmesi
@@ -1732,6 +1732,6 @@ echo "Recovery completed. Services restarting..."
---
**Bu dokümantasyon Yakıt Takip Modülü projesinin kapsamlı süreçlerini ve teknik detaylarını içermektedir. Güncel kalmak için düzenli olarak gözden geçirilmeli ve güncellenmelidir.**
**Bu dokümantasyon Yakıt Takip Uygulaması projesinin kapsamlı süreçlerini ve teknik detaylarını içermektedir. Güncel kalmak için düzenli olarak gözden geçirilmeli ve güncellenmelidir.**
*Son güncelleme: 2024-11-05*

View File

@@ -1,6 +1,6 @@
# Yakıt Takip Modülü - Dokümantasyon
# Yakıt Takip Uygulaması - Dokümantasyon
Bu klasörde Yakıt Takip Modülü'nün tüm dokümantasyon dosyaları bulunmaktadır.
Bu klasörde Yakıt Takip Uygulaması'nın tüm dokümantasyon dosyaları bulunmaktadır.
## 📚 Dokümantasyon Dosyaları

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8" />
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⛽</text></svg>" />
<meta name="viewport" content="width=device-width" />
<title>Yakıt Takip Modülü</title>
<title>Yakıt Takip Uygulaması</title>
<!-- Font Awesome CDN -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
%sveltekit.head%

View File

@@ -2,8 +2,8 @@
import { onMount } from 'svelte';
export let user = null;
let personnel = [];
let units = [];
let personnel = [];
let units = [];
let loading = true;
let error = '';
let showAddModal = false;
@@ -11,15 +11,15 @@
let selectedPersonnel = null;
// Form değişkenleri
let formData = {
full_name: '',
rank: '',
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
let formData = {
full_name: '',
rank: '',
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
onMount(async () => {
const userData = localStorage.getItem('user');
@@ -36,10 +36,10 @@
async function loadPersonnel() {
try {
const response = await fetch('/api/fuel-personnel');
const response = await fetch('/api/unit-personnel');
if (response.ok) {
const data = await response.json();
personnel = data.fuelPersonnel || [];
personnel = data.goodsManagers || [];
} else {
error = 'Personel bilgileri yüklenemedi.';
}
@@ -68,18 +68,18 @@
return units.find((unit) => unit.id === id)?.name || 'Belirtilmemiş';
}
function resetForm() {
formData = {
full_name: '',
rank: '',
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
selectedPersonnel = null;
}
function resetForm() {
formData = {
full_name: '',
rank: '',
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
selectedPersonnel = null;
}
function openAddModal() {
resetForm();
@@ -88,15 +88,15 @@
function openEditModal(person) {
selectedPersonnel = person;
formData = {
full_name: person.full_name,
rank: person.rank,
registration_number: person.registration_number,
tc_kimlik: person.tc_kimlik,
phone: person.phone,
unit_id: person.unit_id || '',
is_active: person.is_active
};
formData = {
full_name: person.full_name,
rank: person.rank,
registration_number: person.registration_number,
tc_kimlik: person.tc_kimlik,
phone: person.phone,
unit_id: person.unit_id || '',
is_active: person.is_active
};
showEditModal = true;
}
@@ -107,10 +107,10 @@
}
async function handleAddPersonnel() {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone || !formData.unit_id) {
error = 'Tüm alanlar zorunludur.';
return;
}
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone || !formData.unit_id) {
error = 'Tüm alanlar zorunludur.';
return;
}
if (!/^[0-9]{11}$/.test(formData.tc_kimlik)) {
error = 'TC Kimlik numarası 11 haneli olmalıdır.';
@@ -118,7 +118,7 @@
}
try {
const response = await fetch('/api/fuel-personnel', {
const response = await fetch('/api/unit-personnel', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -142,10 +142,10 @@
}
async function handleUpdatePersonnel() {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone || !formData.unit_id) {
error = 'Tüm alanlar zorunludur.';
return;
}
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone || !formData.unit_id) {
error = 'Tüm alanlar zorunludur.';
return;
}
if (!/^[0-9]{11}$/.test(formData.tc_kimlik)) {
error = 'TC Kimlik numarası 11 haneli olmalıdır.';
@@ -153,7 +153,7 @@
}
try {
const response = await fetch('/api/fuel-personnel', {
const response = await fetch('/api/unit-personnel', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
@@ -185,7 +185,7 @@
}
try {
const response = await fetch('/api/fuel-personnel', {
const response = await fetch('/api/unit-personnel', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
@@ -209,7 +209,7 @@
async function togglePersonnelStatus(person) {
try {
const response = await fetch('/api/fuel-personnel', {
const response = await fetch('/api/unit-personnel', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',

View File

@@ -5,7 +5,6 @@
export let user = null;
let personnel = [];
let units = [];
let loading = true;
let error = '';
let showAddModal = false;
@@ -19,27 +18,13 @@ let formData = {
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
onMount(async () => {
await loadUnits();
await loadPersonnel();
});
async function loadUnits() {
try {
const response = await fetch('/api/units');
if (response.ok) {
const data = await response.json();
units = data.units || [];
}
} catch (err) {
console.error('Load units error:', err);
}
}
async function loadPersonnel() {
try {
const response = await fetch('/api/fuel-personnel');
@@ -64,7 +49,6 @@ function resetForm() {
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
selectedPersonnel = null;
@@ -83,7 +67,6 @@ function openEditModal(person) {
registration_number: person.registration_number,
tc_kimlik: person.tc_kimlik,
phone: person.phone,
unit_id: person.unit_id || '',
is_active: person.is_active
};
showEditModal = true;
@@ -96,7 +79,7 @@ function openEditModal(person) {
}
async function handleAddPersonnel() {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone || !formData.unit_id) {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone) {
error = 'Tüm alanlar zorunludur.';
return;
}
@@ -131,7 +114,7 @@ function openEditModal(person) {
}
async function handleUpdatePersonnel() {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone || !formData.unit_id) {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone) {
error = 'Tüm alanlar zorunludur.';
return;
}
@@ -295,16 +278,25 @@ function openEditModal(person) {
<span class="detail-value">{person.tc_kimlik}</span>
</div>
</div>
<div class="detail-item">
<div class="detail-icon">
<i class="fas fa-phone"></i>
</div>
<div class="detail-content">
<span class="detail-label">İrtibat:</span>
<span class="detail-value">{person.phone}</span>
</div>
</div>
</div>
<div class="detail-item">
<div class="detail-icon">
<i class="fas fa-phone"></i>
</div>
<div class="detail-content">
<span class="detail-label">İrtibat:</span>
<span class="detail-value">{person.phone}</span>
</div>
</div>
<div class="detail-item">
<div class="detail-icon">
<i class="fas fa-gas-pump"></i>
</div>
<div class="detail-content">
<span class="detail-label">Görev Yeri:</span>
<span class="detail-value">Fuel Station</span>
</div>
</div>
</div>
<div class="personnel-actions">
<button class="btn btn-sm btn-secondary" on:click={() => openEditModal(person)}>
@@ -399,20 +391,6 @@ function openEditModal(person) {
required
/>
</div>
<div class="form-group">
<label for="unit_id">Birlik</label>
<select
id="unit_id"
class="form-input"
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="modal-actions">
<button type="button" class="btn btn-secondary" on:click={closeModal}>İptal</button>
<button type="submit" class="btn btn-primary">Kaydet</button>
@@ -487,20 +465,6 @@ function openEditModal(person) {
required
/>
</div>
<div class="form-group">
<label for="edit-unit_id">Birlik</label>
<select
id="edit-unit_id"
class="form-input"
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 class="checkbox-label">
<input

View File

@@ -4,7 +4,8 @@
// Props
export let user = null;
let vehicles = [];
let vehicles = [];
let units = [];
let loading = true;
let error = '';
let showAddModal = false;
@@ -12,21 +13,35 @@
let selectedVehicle = null;
// Form değişkenleri
let formData = {
brand: '',
model: '',
year: new Date().getFullYear(),
plate: '',
fuel_type: 'Benzin',
fuel_capacity: 50,
current_fuel: 0,
yazlik_mukannen: 0,
kislik_mukannen: 0
};
let formData = {
brand: '',
model: '',
year: new Date().getFullYear(),
plate: '',
unit_id: '',
fuel_type: 'Benzin',
fuel_capacity: 50,
current_fuel: 0,
yazlik_mukannen: 0,
kislik_mukannen: 0
};
onMount(async () => {
await loadVehicles();
});
onMount(async () => {
await loadUnits();
await loadVehicles();
});
async function loadUnits() {
try {
const response = await fetch('/api/units');
if (response.ok) {
const data = await response.json();
units = data.units || [];
}
} catch (err) {
console.error('Load units error:', err);
}
}
async function loadVehicles() {
try {
@@ -45,18 +60,19 @@
}
}
function resetForm() {
formData = {
brand: '',
model: '',
year: new Date().getFullYear(),
plate: '',
fuel_type: 'Benzin',
fuel_capacity: 50,
current_fuel: 0,
yazlik_mukannen: 0,
kislik_mukannen: 0
};
function resetForm() {
formData = {
brand: '',
model: '',
year: new Date().getFullYear(),
plate: '',
unit_id: '',
fuel_type: 'Benzin',
fuel_capacity: 50,
current_fuel: 0,
yazlik_mukannen: 0,
kislik_mukannen: 0
};
selectedVehicle = null;
}
@@ -65,19 +81,20 @@
showAddModal = true;
}
function openEditModal(vehicle) {
selectedVehicle = vehicle;
formData = {
brand: vehicle.brand,
model: vehicle.model,
year: vehicle.year,
plate: vehicle.plate,
fuel_type: vehicle.fuel_type || 'Benzin',
fuel_capacity: vehicle.fuel_capacity || 50,
current_fuel: vehicle.current_fuel || 0,
yazlik_mukannen: vehicle.yazlik_mukannen || 0,
kislik_mukannen: vehicle.kislik_mukannen || 0
};
function openEditModal(vehicle) {
selectedVehicle = vehicle;
formData = {
brand: vehicle.brand,
model: vehicle.model,
year: vehicle.year,
plate: vehicle.plate,
unit_id: vehicle.unit_id ? vehicle.unit_id.toString() : '',
fuel_type: vehicle.fuel_type || 'Benzin',
fuel_capacity: vehicle.fuel_capacity || 50,
current_fuel: vehicle.current_fuel || 0,
yazlik_mukannen: vehicle.yazlik_mukannen || 0,
kislik_mukannen: vehicle.kislik_mukannen || 0
};
showEditModal = true;
}
@@ -87,30 +104,43 @@
resetForm();
}
function validateMukannen(value) {
// Sadece pozitif tam sayı kabul et
return /^[0-9]*$/.test(value) && value >= 0;
function validateMukannen(value) {
if (value === '' || value === null || value === undefined) {
return true;
}
const normalizedValue = typeof value === 'number' ? value : parseFloat(value.toString().replace(',', '.'));
return !isNaN(normalizedValue) && normalizedValue >= 0;
}
function getUnitName(unitId, unitList = units) {
const id = parseInt(unitId);
return unitList.find((unit) => unit.id === id)?.name || 'Belirtilmemiş';
}
async function handleAddVehicle() {
if (!formData.brand || !formData.model || !formData.year || !formData.plate || !formData.fuel_type || !formData.fuel_capacity) {
if (!formData.brand || !formData.model || !formData.year || !formData.plate || !formData.unit_id || !formData.fuel_type || !formData.fuel_capacity) {
error = 'Tüm zorunlu alanları doldurun.';
return;
}
if (!validateMukannen(formData.yazlik_mukannen) || !validateMukannen(formData.kislik_mukannen)) {
error = 'Mukannen değerleri sadece rakam içermelidir.';
error = 'Mukannen değerleri sayısal olmalı ve negatif olamaz.';
return;
}
try {
const response = await fetch('/api/vehicles', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
});
try {
const payload = {
...formData,
unit_id: parseInt(formData.unit_id)
};
const response = await fetch('/api/vehicles', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
const data = await response.json();
@@ -128,27 +158,29 @@
}
async function handleUpdateVehicle() {
if (!formData.brand || !formData.model || !formData.year || !formData.plate || !formData.fuel_type || !formData.fuel_capacity) {
if (!formData.brand || !formData.model || !formData.year || !formData.plate || !formData.unit_id || !formData.fuel_type || !formData.fuel_capacity) {
error = 'Tüm zorunlu alanları doldurun.';
return;
}
if (!validateMukannen(formData.yazlik_mukannen) || !validateMukannen(formData.kislik_mukannen)) {
error = 'Mukannen değerleri sadece rakam içermelidir.';
error = 'Mukannen değerleri sayısal olmalı ve negatif olamaz.';
return;
}
try {
const response = await fetch('/api/vehicles', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: selectedVehicle.id,
...formData
}),
});
try {
const payload = {
id: selectedVehicle.id,
...formData,
unit_id: parseInt(formData.unit_id)
};
const response = await fetch('/api/vehicles', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
const data = await response.json();
@@ -253,6 +285,9 @@
<span class="plate-badge"><i class="fas fa-car"></i> {vehicle.plate}</span>
</div>
</div>
<p class="vehicle-unit">
<i class="fas fa-building"></i> {vehicle.unit_name || getUnitName(vehicle.unit_id, units)}
</p>
<div class="vehicle-actions">
<button class="btn btn-sm btn-secondary" on:click={() => openEditModal(vehicle)}>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -318,17 +353,31 @@
required
/>
</div>
<div class="form-group">
<label for="plate">Plaka</label>
<input
id="plate"
type="text"
class="form-input"
bind:value={formData.plate}
placeholder="34ABC123"
required
/>
</div>
<div class="form-group">
<label for="plate">Plaka</label>
<input
id="plate"
type="text"
class="form-input"
bind:value={formData.plate}
placeholder="34ABC123"
required
/>
</div>
<div class="form-group">
<label for="unit_id">Birlik</label>
<select
id="unit_id"
class="form-input"
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="fuel_type">Yakıt Tipi</label>
<select
@@ -379,10 +428,9 @@
class="form-input"
bind:value={formData.yazlik_mukannen}
min="0"
step="1"
step="0.01"
placeholder="0"
pattern="[0-9]*"
inputmode="numeric"
inputmode="decimal"
/>
</div>
<div class="form-group">
@@ -393,10 +441,9 @@
class="form-input"
bind:value={formData.kislik_mukannen}
min="0"
step="1"
step="0.01"
placeholder="0"
pattern="[0-9]*"
inputmode="numeric"
inputmode="decimal"
/>
</div>
<div class="modal-actions">
@@ -451,17 +498,31 @@
required
/>
</div>
<div class="form-group">
<label for="edit-plate">Plaka</label>
<input
id="edit-plate"
type="text"
class="form-input"
bind:value={formData.plate}
placeholder="34ABC123"
required
/>
</div>
<div class="form-group">
<label for="edit-plate">Plaka</label>
<input
id="edit-plate"
type="text"
class="form-input"
bind:value={formData.plate}
placeholder="34ABC123"
required
/>
</div>
<div class="form-group">
<label for="edit-unit_id">Birlik</label>
<select
id="edit-unit_id"
class="form-input"
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="edit-fuel_type">Yakıt Tipi</label>
<select
@@ -512,10 +573,9 @@
class="form-input"
bind:value={formData.yazlik_mukannen}
min="0"
step="1"
step="0.01"
placeholder="0"
pattern="[0-9]*"
inputmode="numeric"
inputmode="decimal"
/>
</div>
<div class="form-group">
@@ -526,10 +586,9 @@
class="form-input"
bind:value={formData.kislik_mukannen}
min="0"
step="1"
step="0.01"
placeholder="0"
pattern="[0-9]*"
inputmode="numeric"
inputmode="decimal"
/>
</div>
<div class="modal-actions">
@@ -664,6 +723,15 @@
margin-bottom: 1rem;
}
.vehicle-unit {
margin: 0 0 1rem;
color: var(--text-secondary);
font-weight: 600;
display: flex;
align-items: center;
gap: 0.4rem;
}
.vehicle-info h3 {
font-size: 1.2rem;
font-weight: 600;
@@ -826,4 +894,4 @@
flex-direction: column;
}
}
</style>
</style>

View File

@@ -44,7 +44,7 @@
</script>
<svelte:head>
<title>Yakıt Takip Modülü</title>
<title>Yakıt Takip Uygulaması</title>
<meta name="description" content="Akaryakıt İstasyonu Yönetim Sistemi" />
</svelte:head>

View File

@@ -83,7 +83,7 @@
<img src="/logo.png" alt="YTP Logo" class="app-logo" />
</div>
<h1 class="app-title">Giriş</h1>
<p class="app-subtitle">Yakıt Takip Modülü</p>
<p class="app-subtitle">Yakıt Takip Uygulaması</p>
</div>
<form on:submit|preventDefault={handleLogin} class="space-y-6">

View File

@@ -0,0 +1,5 @@
import { json } from '@sveltejs/kit';
export function GET() {
return json({ status: 'ok' });
}

View File

@@ -159,7 +159,7 @@
fetch("/api/vehicles"),
fetch("/api/units"),
fetch("/api/fuel-personnel"),
fetch("/api/goods-managers")
fetch("/api/unit-personnel")
]);
if (vehiclesRes.ok) {

View File

@@ -44,10 +44,10 @@ let formData = {
async function loadGoodsManagers() {
try {
const response = await fetch('/api/fuel-personnel');
const response = await fetch('/api/unit-personnel');
if (response.ok) {
const data = await response.json();
personnel = data.fuelPersonnel || [];
personnel = data.goodsManagers || [];
} else {
error = 'Personel bilgileri yüklenemedi.';
}
@@ -77,15 +77,15 @@ function getUnitName(unitId) {
}
function resetForm() {
formData = {
full_name: '',
rank: '',
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
formData = {
full_name: '',
rank: '',
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
selectedManager = null;
}
@@ -96,15 +96,15 @@ function resetForm() {
function openEditModal(manager) {
selectedManager = manager;
formData = {
full_name: manager.full_name,
rank: manager.rank,
registration_number: manager.registration_number,
tc_kimlik: manager.tc_kimlik,
phone: manager.phone,
unit_id: manager.unit_id || '',
is_active: manager.is_active
};
formData = {
full_name: manager.full_name,
rank: manager.rank,
registration_number: manager.registration_number,
tc_kimlik: manager.tc_kimlik,
phone: manager.phone,
unit_id: manager.unit_id || '',
is_active: manager.is_active
};
showEditModal = true;
}
@@ -120,13 +120,13 @@ async function handleAddManager() {
return;
}
if (!/^[0-9]{11}$/.test(formData.tc_kimlik)) {
error = 'TC Kimlik numarası 11 haneli olmalıdır.';
return;
}
if (!/^[0-9]{11}$/.test(formData.tc_kimlik)) {
error = 'TC Kimlik numarası 11 haneli olmalıdır.';
return;
}
try {
const response = await fetch('/api/fuel-personnel', {
const response = await fetch('/api/unit-personnel', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -155,13 +155,13 @@ async function handleUpdateManager() {
return;
}
if (!/^[0-9]{11}$/.test(formData.tc_kimlik)) {
error = 'TC Kimlik numarası 11 haneli olmalıdır.';
return;
}
if (!/^[0-9]{11}$/.test(formData.tc_kimlik)) {
error = 'TC Kimlik numarası 11 haneli olmalıdır.';
return;
}
try {
const response = await fetch('/api/fuel-personnel', {
const response = await fetch('/api/unit-personnel', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
@@ -193,7 +193,7 @@ async function handleUpdateManager() {
}
try {
const response = await fetch('/api/fuel-personnel', {
const response = await fetch('/api/unit-personnel', {
method: 'DELETE',
headers: {
'Content-Type': 'application/json',
@@ -217,7 +217,7 @@ async function handleUpdateManager() {
async function toggleManagerStatus(manager) {
try {
const response = await fetch('/api/fuel-personnel', {
const response = await fetch('/api/unit-personnel', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
@@ -895,6 +895,6 @@ async function handleUpdateManager() {
.detail-value {
text-align: left;
}
}
}
</style>

View File

@@ -11,8 +11,7 @@
import { goto } from '$app/navigation';
let user = null;
let personnel = [];
let units = [];
let personnel = [];
let loading = true;
let error = '';
let showAddModal = false;
@@ -26,7 +25,6 @@
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
@@ -38,25 +36,9 @@
}
user = JSON.parse(userData);
await loadUnits();
await loadPersonnel();
});
async function loadUnits() {
try {
const response = await fetch('/api/units');
if (response.ok) {
const data = await response.json();
units = data.units;
} else {
error = 'Birlik listesi yüklenemedi.';
}
} catch (err) {
error = 'Bağlantı hatası.';
console.error('Load units error:', err);
}
}
async function loadPersonnel() {
try {
const response = await fetch('/api/fuel-personnel');
@@ -81,7 +63,6 @@
registration_number: '',
tc_kimlik: '',
phone: '',
unit_id: '',
is_active: true
};
selectedPersonnel = null;
@@ -100,7 +81,6 @@
registration_number: person.registration_number,
tc_kimlik: person.tc_kimlik,
phone: person.phone,
unit_id: person.unit_id || '',
is_active: person.is_active
};
showEditModal = true;
@@ -113,7 +93,7 @@
}
async function handleAddPersonnel() {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone || !formData.unit_id) {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone) {
error = 'Tüm alanlar zorunludur.';
return;
}
@@ -148,7 +128,7 @@
}
async function handleUpdatePersonnel() {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone || !formData.unit_id) {
if (!formData.full_name || !formData.rank || !formData.registration_number || !formData.tc_kimlik || !formData.phone) {
error = 'Tüm alanlar zorunludur.';
return;
}
@@ -328,15 +308,24 @@
<span class="detail-value">{person.tc_kimlik}</span>
</div>
</div>
<div class="detail-item">
<div class="detail-icon">
<i class="fas fa-phone"></i>
</div>
<div class="detail-content">
<span class="detail-label">İrtibat:</span>
<span class="detail-value">{person.phone}</span>
</div>
<div class="detail-item">
<div class="detail-icon">
<i class="fas fa-phone"></i>
</div>
<div class="detail-content">
<span class="detail-label">İrtibat:</span>
<span class="detail-value">{person.phone}</span>
</div>
</div>
<div class="detail-item">
<div class="detail-icon">
<i class="fas fa-gas-pump"></i>
</div>
<div class="detail-content">
<span class="detail-label">Görev Yeri:</span>
<span class="detail-value">Fuel Station</span>
</div>
</div>
</div>
<div class="personnel-actions">
@@ -445,20 +434,6 @@
required
/>
</div>
<div class="form-group">
<label for="unit_id">Birlik</label>
<select
id="unit_id"
class="form-input"
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="modal-actions">
<button type="button" class="btn btn-secondary" on:click={closeModal}>İptal</button>
<button type="submit" class="btn btn-primary">Kaydet</button>
@@ -533,20 +508,6 @@
required
/>
</div>
<div class="form-group">
<label for="edit-unit_id">Birlik</label>
<select
id="edit-unit_id"
class="form-input"
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 class="checkbox-label">
<input
@@ -931,4 +892,4 @@
gap: 0.25rem;
}
}
</style>
</style>

View File

@@ -12,6 +12,7 @@
let user = null;
let vehicles = [];
let units = [];
let loading = true;
let error = '';
let showAddModal = false;
@@ -19,12 +20,13 @@
let selectedVehicle = null;
// Form değişkenleri
let formData = {
brand: '',
model: '',
year: new Date().getFullYear(),
plate: ''
};
let formData = {
brand: '',
model: '',
year: new Date().getFullYear(),
plate: '',
unit_id: ''
};
onMount(async () => {
const userData = localStorage.getItem('user');
@@ -33,10 +35,31 @@
return;
}
user = JSON.parse(userData);
await loadVehicles();
user = JSON.parse(userData);
await loadUnits();
await loadVehicles();
});
async function loadUnits() {
try {
const response = await fetch('/api/units');
if (response.ok) {
const data = await response.json();
units = data.units || [];
} else {
error = 'Birlikler yüklenemedi.';
}
} catch (err) {
error = 'Bağlantı hatası.';
console.error('Load units error:', err);
}
}
function getUnitName(unitId, unitList = units) {
const id = parseInt(unitId);
return unitList.find((unit) => unit.id === id)?.name || 'Belirtilmemiş';
}
async function loadVehicles() {
try {
const response = await fetch('/api/vehicles');
@@ -55,12 +78,13 @@
}
function resetForm() {
formData = {
brand: '',
model: '',
year: new Date().getFullYear(),
plate: ''
};
formData = {
brand: '',
model: '',
year: new Date().getFullYear(),
plate: '',
unit_id: ''
};
selectedVehicle = null;
}
@@ -71,12 +95,13 @@
function openEditModal(vehicle) {
selectedVehicle = vehicle;
formData = {
brand: vehicle.brand,
model: vehicle.model,
year: vehicle.year,
plate: vehicle.plate
};
formData = {
brand: vehicle.brand,
model: vehicle.model,
year: vehicle.year,
plate: vehicle.plate,
unit_id: vehicle.unit_id ? vehicle.unit_id.toString() : ''
};
showEditModal = true;
}
@@ -87,19 +112,23 @@
}
async function handleAddVehicle() {
if (!formData.brand || !formData.model || !formData.year || !formData.plate) {
if (!formData.brand || !formData.model || !formData.year || !formData.plate || !formData.unit_id) {
error = 'Tüm alanlar zorunludur.';
return;
}
try {
const response = await fetch('/api/vehicles', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(formData),
});
try {
const payload = {
...formData,
unit_id: parseInt(formData.unit_id)
};
const response = await fetch('/api/vehicles', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
const data = await response.json();
@@ -117,22 +146,24 @@
}
async function handleUpdateVehicle() {
if (!formData.brand || !formData.model || !formData.year || !formData.plate) {
if (!formData.brand || !formData.model || !formData.year || !formData.plate || !formData.unit_id) {
error = 'Tüm alanlar zorunludur.';
return;
}
try {
const response = await fetch('/api/vehicles', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: selectedVehicle.id,
...formData
}),
});
try {
const payload = {
id: selectedVehicle.id,
...formData,
unit_id: parseInt(formData.unit_id)
};
const response = await fetch('/api/vehicles', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
const data = await response.json();
@@ -242,6 +273,9 @@
<span class="plate-badge"><i class="fas fa-car"></i> {vehicle.plate}</span>
</div>
</div>
<p class="vehicle-unit">
<i class="fas fa-building"></i> {vehicle.unit_name || getUnitName(vehicle.unit_id, units)}
</p>
<div class="vehicle-actions">
<button class="btn btn-sm btn-secondary" on:click={() => openEditModal(vehicle)}>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -318,6 +352,20 @@
required
/>
</div>
<div class="form-group">
<label for="unit_id">Birlik</label>
<select
id="unit_id"
class="form-input"
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="modal-actions">
<button type="button" class="btn btn-secondary" on:click={closeModal}>İptal</button>
<button type="submit" class="btn btn-primary">Kaydet</button>
@@ -381,6 +429,20 @@
required
/>
</div>
<div class="form-group">
<label for="edit-unit_id">Birlik</label>
<select
id="edit-unit_id"
class="form-input"
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="modal-actions">
<button type="button" class="btn btn-secondary" on:click={closeModal}>İptal</button>
<button type="submit" class="btn btn-primary">Güncelle</button>
@@ -501,6 +563,15 @@
margin-bottom: 1rem;
}
.vehicle-unit {
margin: 0 0 1rem;
color: var(--text-secondary);
font-weight: 600;
display: flex;
align-items: center;
gap: 0.4rem;
}
.vehicle-info h3 {
font-size: 1.2rem;
font-weight: 600;
@@ -657,4 +728,4 @@
flex-direction: column;
}
}
</style>
</style>

View File

@@ -17,7 +17,8 @@
let personnel = [];
let fuelSlips = [];
let approvedRejectedSlips = [];
let goodsManagers = [];
let receivingPersonnel = [];
let filteredReceivingPersonnel = [];
let loading = true;
let error = '';
let showCreateModal = false;
@@ -37,7 +38,7 @@
liters: '',
km: '',
personnel_id: '',
goods_manager_id: 2, // Varsayılan mal sorumlusu
goods_manager_id: '',
notes: ''
};
@@ -77,12 +78,12 @@
async function loadData() {
try {
// Paralel veri yükleme
const [vehiclesRes, unitsRes, personnelRes, slipsRes, goodsManagersRes] = await Promise.all([
const [vehiclesRes, unitsRes, personnelRes, slipsRes, unitPersonnelRes] = await Promise.all([
fetch('/api/vehicles'),
fetch('/api/units'),
fetch('/api/fuel-personnel'),
fetch('/api/fuel-slips'),
fetch('/api/goods-managers')
fetch('/api/unit-personnel')
]);
if (vehiclesRes.ok) {
@@ -117,9 +118,10 @@
});
}
if (goodsManagersRes.ok) {
const goodsData = await goodsManagersRes.json();
goodsManagers = goodsData.goodsManagers?.filter(gm => gm.is_active) || [];
if (unitPersonnelRes.ok) {
const receiversData = await unitPersonnelRes.json();
receivingPersonnel = receiversData.unitPersonnel?.filter(person => person.is_active) || [];
syncReceiverSelection();
}
} catch (err) {
@@ -130,6 +132,41 @@
}
}
function getUnitPersonnelByUnit(unitId) {
if (!unitId) {
return [];
}
const normalizedUnit = parseInt(unitId);
return receivingPersonnel.filter(person => person.unit_id === normalizedUnit);
}
function syncReceiverSelection(unitId = formData.unit_id) {
const candidates = getUnitPersonnelByUnit(unitId);
filteredReceivingPersonnel = candidates;
if (!unitId) {
formData.goods_manager_id = '';
return;
}
if (candidates.length === 0) {
formData.goods_manager_id = '';
return;
}
const hasCurrent = candidates.some(person => person.id.toString() === formData.goods_manager_id?.toString());
if (!hasCurrent) {
formData.goods_manager_id = candidates[0].id.toString();
}
}
function handleUnitChange(event) {
const value = event.target.value;
formData.unit_id = value;
syncReceiverSelection(value);
}
function resetForm() {
formData = {
date: new Date().toISOString().split('T')[0],
@@ -140,9 +177,10 @@
liters: '',
km: '',
personnel_id: '',
goods_manager_id: goodsManagers.length > 0 ? goodsManagers[0].id : '',
goods_manager_id: '',
notes: ''
};
syncReceiverSelection('');
}
function openCreateModal() {
@@ -378,7 +416,13 @@
</div>
<div class="form-group">
<label for="unit_id">Birlik</label>
<select id="unit_id" class="form-select" bind:value={formData.unit_id} required>
<select
id="unit_id"
class="form-select"
bind:value={formData.unit_id}
on:change={handleUnitChange}
required
>
<option value="">Birlik Seçin</option>
{#each units as unit}
<option value={unit.id}>{unit.name}</option>
@@ -437,10 +481,20 @@
</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>
<select
id="goods_manager_id"
class="form-select"
bind:value={formData.goods_manager_id}
disabled={!formData.unit_id || filteredReceivingPersonnel.length === 0}
required
>
{#if !formData.unit_id}
<option value="">Önce birlik seçin</option>
{:else if filteredReceivingPersonnel.length === 0}
<option value="">Bu birliğe kayıtlı personel yok</option>
{/if}
{#each filteredReceivingPersonnel as person}
<option value={person.id}>{person.rank} {person.full_name}</option>
{/each}
</select>
</div>
@@ -1042,4 +1096,4 @@
min-width: auto;
}
}
</style>
</style>

View File

@@ -11,7 +11,8 @@ import {
getGoodsManagers,
addGoodsManager,
updateGoodsManager,
deleteGoodsManager
deleteGoodsManager,
findGoodsManagerById
} from './lib/data/goodsManagers.js';
// Units veritabanı
@@ -65,6 +66,19 @@ let units = [
let nextUnitId = 4;
const getUnitById = (unitId) => {
if (unitId === null || unitId === undefined) {
return null;
}
const id = parseInt(unitId);
return units.find((unit) => unit.id === id) || null;
};
const getUnitNameById = (unitId) => {
return getUnitById(unitId)?.name || 'Belirtilmemiş';
};
// Vehicles veritabanı
let vehicles = [
{
@@ -73,6 +87,7 @@ let vehicles = [
model: 'Actros 1851',
year: 2020,
plate: '34 ABC 123',
unit_id: 1,
fuel_type: 'Dizel',
fuel_capacity: 500,
current_fuel: 300,
@@ -87,6 +102,7 @@ let vehicles = [
model: 'FH16 750',
year: 2021,
plate: '34 XYZ 789',
unit_id: 2,
fuel_type: 'Dizel',
fuel_capacity: 600,
current_fuel: 450,
@@ -101,6 +117,7 @@ let vehicles = [
model: 'R730',
year: 2019,
plate: '34 DEF 456',
unit_id: 3,
fuel_type: 'Dizel',
fuel_capacity: 550,
current_fuel: 200,
@@ -111,6 +128,11 @@ let vehicles = [
}
];
vehicles = vehicles.map((vehicle) => ({
...vehicle,
unit_name: getUnitNameById(vehicle.unit_id)
}));
let nextVehicleId = 4;
// Fuel Personnel veritabanı
@@ -119,7 +141,7 @@ let fuelPersonnel = [
id: 1,
full_name: 'Ahmet Demir',
rank: 'Üsteğmen',
registration_number: '111222',
registration_number: 'FP-111222',
tc_kimlik: '11111111111',
phone: '05321112233',
is_active: true,
@@ -129,7 +151,7 @@ let fuelPersonnel = [
id: 2,
full_name: 'Mustafa Çelik',
rank: 'Astsubay',
registration_number: '333444',
registration_number: 'FP-333444',
tc_kimlik: '22222222222',
phone: '05334455566',
is_active: true,
@@ -139,6 +161,59 @@ let fuelPersonnel = [
let nextFuelPersonnelId = 3;
// Unit personnel listesi (teslim alanlar)
let unitPersonnel = [
{
id: 1,
full_name: 'Serkan Yılmaz',
rank: 'Teğmen',
registration_number: 'UP-1001',
tc_kimlik: '12312312312',
phone: '05320001122',
unit_id: 1,
is_active: true,
created_at: new Date().toISOString()
},
{
id: 2,
full_name: 'Barış Aksoy',
rank: 'Astsubay',
registration_number: 'UP-2001',
tc_kimlik: '98798798798',
phone: '05323334455',
unit_id: 2,
is_active: true,
created_at: new Date().toISOString()
},
{
id: 3,
full_name: 'Hakan Güler',
rank: 'Üstçavuş',
registration_number: 'UP-3001',
tc_kimlik: '55544433322',
phone: '05324445566',
unit_id: 3,
is_active: true,
created_at: new Date().toISOString()
}
];
let nextUnitPersonnelId = 4;
function parseMukannenValue(value) {
if (value === null || value === undefined || value === '') {
return 0;
}
if (typeof value === 'number') {
return value;
}
const parsed = parseFloat(value.toString().replace(',', '.'));
return isNaN(parsed) ? 0 : parsed;
}
const app = express();
const server = createServer(app);
const io = new Server(server, {
@@ -746,14 +821,144 @@ app.delete('/api/goods-managers', async (req, res) => {
// GET - Tüm yakıt personelini listele
app.get('/api/fuel-personnel', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
res.json({ fuelPersonnel });
});
// POST - Yeni yakıt personeli ekle
app.post('/api/fuel-personnel', async (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
try {
const {
full_name,
rank,
registration_number,
tc_kimlik,
phone,
is_active = true
} = req.body;
if (!full_name || !rank || !registration_number || !tc_kimlik || !phone) {
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
}
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
}
const existingPersonnel = fuelPersonnel.find(p =>
p.registration_number === registration_number || p.tc_kimlik === tc_kimlik
);
if (existingPersonnel) {
return res.status(400).json({ message: 'Bu personel zaten kayıtlı.' });
}
const newPersonnel = {
id: nextFuelPersonnelId++,
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
tc_kimlik: tc_kimlik.trim(),
phone: phone.trim(),
is_active: Boolean(is_active),
created_at: new Date().toISOString()
};
fuelPersonnel.push(newPersonnel);
res.json({
message: 'Yakıt personeli başarıyla eklendi.',
fuelPersonnel: newPersonnel
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// PUT - Yakıt personeli güncelle
app.put('/api/fuel-personnel', (req, res) => {
try {
const {
id,
full_name,
rank,
registration_number,
tc_kimlik,
phone,
is_active
} = req.body;
if (!id || !full_name || !rank || !registration_number || !tc_kimlik || !phone) {
return res.status(400).json({ message: 'Tüm alanlar zorunludur.' });
}
if (!/^[0-9]{11}$/.test(tc_kimlik)) {
return res.status(400).json({ message: 'TC Kimlik numarası 11 haneli olmalıdır.' });
}
const personnelIndex = fuelPersonnel.findIndex(p => p.id === parseInt(id));
if (personnelIndex === -1) {
return res.status(404).json({ message: 'Personel bulunamadı.' });
}
const duplicate = fuelPersonnel.find(p =>
p.id !== parseInt(id) && (p.registration_number === registration_number || p.tc_kimlik === tc_kimlik)
);
if (duplicate) {
return res.status(400).json({ message: 'Aynı sicil veya TC Kimlik başka bir personelde mevcut.' });
}
fuelPersonnel[personnelIndex] = {
...fuelPersonnel[personnelIndex],
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
tc_kimlik: tc_kimlik.trim(),
phone: phone.trim(),
is_active: Boolean(is_active)
};
res.json({
message: 'Yakıt personeli güncellendi.',
fuelPersonnel: fuelPersonnel[personnelIndex]
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// DELETE - Yakıt personeli sil
app.delete('/api/fuel-personnel', (req, res) => {
try {
const { id } = req.body;
if (!id) {
return res.status(400).json({ message: 'Personel ID zorunludur.' });
}
const personnelIndex = fuelPersonnel.findIndex(p => p.id === parseInt(id));
if (personnelIndex === -1) {
return res.status(404).json({ message: 'Personel bulunamadı.' });
}
const deletedPersonnel = fuelPersonnel.splice(personnelIndex, 1)[0];
res.json({
message: 'Yakıt personeli silindi.',
fuelPersonnel: deletedPersonnel
});
} catch (error) {
res.status(500).json({ message: 'Sunucu hatası.' });
}
});
// Unit Personnel API endpoint'leri (Teslim Alan personeller)
app.get('/api/unit-personnel', (req, res) => {
res.json({ unitPersonnel });
});
app.post('/api/unit-personnel', (req, res) => {
try {
const {
full_name,
@@ -765,35 +970,23 @@ app.post('/api/fuel-personnel', async (req, res) => {
is_active = true
} = req.body;
// Validasyon
if (!full_name || !rank || !registration_number || !tc_kimlik || !phone || !unit_id) {
return res.status(400).json({ message: 'Tüm alanlar 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.' });
}
// Sicil numarası tekrar kontrolü
const existingPersonnel = fuelPersonnel.find(p =>
p.registration_number === registration_number
const duplicate = unitPersonnel.find(p =>
p.registration_number === registration_number || p.tc_kimlik === tc_kimlik
);
if (existingPersonnel) {
return res.status(400).json({ message: 'Bu sicil numarası zaten kayıtlı.' });
if (duplicate) {
return res.status(400).json({ message: 'Bu personel zaten kayıtlı.' });
}
// TC Kimlik numarası tekrar kontrolü
const existingTc = fuelPersonnel.find(p =>
p.tc_kimlik === tc_kimlik
);
if (existingTc) {
return res.status(400).json({ message: 'Bu TC Kimlik numarası zaten kayıtlı.' });
}
// Yeni personel oluştur
const newPersonnel = {
id: nextFuelPersonnelId++,
id: nextUnitPersonnelId++,
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
@@ -804,46 +997,11 @@ app.post('/api/fuel-personnel', async (req, res) => {
created_at: new Date().toISOString()
};
// Birlik personeli için kullanıcı oluştur
try {
// Kullanıcı adını TC kimlik numarasından oluştur
const username = `bp_${tc_kimlik}`;
const defaultPassword = tc_kimlik.substring(0, 6); // İlk 6 hane varsayılan şifre
const hashedPassword = await bcrypt.hash(defaultPassword, 10);
// Kullanıcı adı benzersizliğini kontrol et
const existingUser = await new Promise((resolve, reject) => {
db.get('SELECT id FROM users WHERE username = ?', [username], (err, row) => {
if (err) reject(err);
else resolve(row);
});
});
if (existingUser) {
return res.status(400).json({ message: 'Bu personel için zaten kullanıcı hesabı mevcut.' });
}
// Birlik personeli olarak kullanıcı ekle
await new Promise((resolve, reject) => {
db.run('INSERT INTO users (username, password, role, full_name) VALUES (?, ?, ?, ?)',
[username, hashedPassword, 'birlik_personeli', full_name], (err) => {
if (err) reject(err);
else resolve();
});
});
console.log(`✅ Birlik personeli kullanıcı oluşturuldu: ${username}`);
} catch (userError) {
console.error('❌ Birlik personeli kullanıcı oluşturma hatası:', userError);
return res.status(500).json({ message: 'Personel için kullanıcı hesabı oluşturulamadı.' });
}
fuelPersonnel.push(newPersonnel);
unitPersonnel.push(newPersonnel);
res.json({
message: 'Personel başarıyla eklendi.',
fuelPersonnel: newPersonnel
personnel: newPersonnel
});
} catch (error) {
@@ -851,10 +1009,7 @@ app.post('/api/fuel-personnel', async (req, res) => {
}
});
// PUT - Yakıt personeli güncelle
app.put('/api/fuel-personnel', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
app.put('/api/unit-personnel', (req, res) => {
try {
const {
id,
@@ -867,41 +1022,28 @@ app.put('/api/fuel-personnel', (req, res) => {
is_active
} = req.body;
// Validasyon
if (!id || !full_name || !rank || !registration_number || !tc_kimlik || !phone || !unit_id) {
return res.status(400).json({ message: 'Tüm alanlar 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.' });
}
// Personel bul
const personnelIndex = fuelPersonnel.findIndex(p => p.id === parseInt(id));
const personnelIndex = unitPersonnel.findIndex(p => p.id === parseInt(id));
if (personnelIndex === -1) {
return res.status(404).json({ message: 'Personel bulunamadı.' });
}
// Sicil numarası tekrar kontrolü (başka personel için)
const existingRegNumber = fuelPersonnel.find(p =>
p.id !== parseInt(id) && p.registration_number === registration_number
const duplicate = unitPersonnel.find(p =>
p.id !== parseInt(id) && (p.registration_number === registration_number || p.tc_kimlik === tc_kimlik)
);
if (existingRegNumber) {
return res.status(400).json({ message: 'Bu sicil numarası başka bir personelde kayıtlı.' });
if (duplicate) {
return res.status(400).json({ message: 'Bu sicil veya TC Kimlik başka bir personelde mevcut.' });
}
// TC Kimlik numarası tekrar kontrolü (başka personel için)
const existingTc = fuelPersonnel.find(p =>
p.id !== parseInt(id) && p.tc_kimlik === tc_kimlik
);
if (existingTc) {
return res.status(400).json({ message: 'Bu TC Kimlik numarası başka bir personelde kayıtlı.' });
}
// Personeli güncelle
fuelPersonnel[personnelIndex] = {
...fuelPersonnel[personnelIndex],
unitPersonnel[personnelIndex] = {
...unitPersonnel[personnelIndex],
full_name: full_name.trim(),
rank: rank.trim(),
registration_number: registration_number.trim(),
@@ -912,8 +1054,8 @@ app.put('/api/fuel-personnel', (req, res) => {
};
res.json({
message: 'Personel başarıyla güncellendi.',
fuelPersonnel: fuelPersonnel[personnelIndex]
message: 'Personel güncellendi.',
personnel: unitPersonnel[personnelIndex]
});
} catch (error) {
@@ -921,10 +1063,7 @@ app.put('/api/fuel-personnel', (req, res) => {
}
});
// DELETE - Yakıt personeli sil
app.delete('/api/fuel-personnel', (req, res) => {
// Yetki kontrolü (temporary - will be implemented with proper session)
app.delete('/api/unit-personnel', (req, res) => {
try {
const { id } = req.body;
@@ -932,18 +1071,16 @@ app.delete('/api/fuel-personnel', (req, res) => {
return res.status(400).json({ message: 'Personel ID zorunludur.' });
}
// Personel bul
const personnelIndex = fuelPersonnel.findIndex(p => p.id === parseInt(id));
const personnelIndex = unitPersonnel.findIndex(p => p.id === parseInt(id));
if (personnelIndex === -1) {
return res.status(404).json({ message: 'Personel bulunamadı.' });
}
// Personel sil
const deletedPersonnel = fuelPersonnel.splice(personnelIndex, 1)[0];
const deletedPersonnel = unitPersonnel.splice(personnelIndex, 1)[0];
res.json({
message: 'Personel başarıyla silindi.',
fuelPersonnel: deletedPersonnel
message: 'Personel silindi.',
personnel: deletedPersonnel
});
} catch (error) {
@@ -951,6 +1088,7 @@ app.delete('/api/fuel-personnel', (req, res) => {
}
});
// Fuel Slips API endpoint'leri
// GET - Yakıt fişlerini listele
@@ -1028,21 +1166,29 @@ app.post('/api/fuel-slips', async (req, res) => {
return res.status(400).json({ message: 'Litre ve KM değerleri geçersiz.' });
}
const unitId = parseInt(slipData.unit_id);
const vehicleId = parseInt(slipData.vehicle_id);
const personnelId = parseInt(slipData.personnel_id);
const goodsManagerId = parseInt(slipData.goods_manager_id);
const fuelManagerId = parseInt(slipData.fuel_manager_id);
// 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 vehicle = vehicles.find(v => v.id === vehicleId);
const unit = units.find(u => u.id === unitId);
const person = fuelPersonnel.find(p => p.id === personnelId && p.is_active);
const receivingPerson = unitPersonnel.find(p => p.id === goodsManagerId && p.is_active);
if (!person) {
return res.status(400).json({ message: 'Teslim eden personel bulunamadı veya pasif durumda.' });
}
if (!receivingPerson) {
return res.status(400).json({ message: 'Teslim alan personel bulunamadı veya pasif durumda.' });
}
if (receivingPerson.unit_id !== unitId) {
return res.status(400).json({ message: 'Seçilen personel bu birliğe bağlı değil.' });
}
const vehicleInfo = vehicle ? {
brand: vehicle.brand,
@@ -1058,15 +1204,19 @@ app.post('/api/fuel-slips', async (req, res) => {
const personnelInfo = person ? {
full_name: person.full_name,
rank: person.rank
rank: person.rank,
unit_id: person.unit_id,
registration_number: person.registration_number
} : {
full_name: 'Bilinmeyen Personel',
rank: ''
};
const goodsManagerInfo = goodsManager ? {
full_name: goodsManager.full_name,
rank: goodsManager.rank
const goodsManagerInfo = receivingPerson ? {
full_name: receivingPerson.full_name,
rank: receivingPerson.rank,
unit_id: receivingPerson.unit_id,
unit_name: getUnitNameById(receivingPerson.unit_id)
} : {
full_name: 'Bilinmeyen Mal Sorumlusu',
rank: ''
@@ -1085,18 +1235,18 @@ app.post('/api/fuel-slips', async (req, res) => {
const params = [
slipData.date,
slipData.force_command,
slipData.unit_id,
unit?.name || `Birim ${slipData.unit_id}`,
slipData.vehicle_id,
unitId,
unit?.name || `Birim ${unitId}`,
vehicleId,
JSON.stringify(vehicleInfo),
slipData.fuel_type,
parseFloat(slipData.liters),
parseInt(slipData.km),
slipData.personnel_id,
personnelId,
JSON.stringify(personnelInfo),
slipData.goods_manager_id,
goodsManagerId,
JSON.stringify(goodsManagerInfo),
slipData.fuel_manager_id,
fuelManagerId,
JSON.stringify(fuelManagerInfo),
'pending',
slipData.notes || ''
@@ -1112,18 +1262,18 @@ app.post('/api/fuel-slips', async (req, res) => {
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,
unit_id: unitId,
unit_name: unit?.name || `Birim ${unitId}`,
vehicle_id: vehicleId,
vehicle_info: vehicleInfo,
fuel_type: slipData.fuel_type,
liters: parseFloat(slipData.liters),
km: parseInt(slipData.km),
personnel_id: slipData.personnel_id,
personnel_id: personnelId,
personnel_info: personnelInfo,
goods_manager_id: slipData.goods_manager_id,
goods_manager_id: goodsManagerId,
goods_manager_info: goodsManagerInfo,
fuel_manager_id: slipData.fuel_manager_id,
fuel_manager_id: fuelManagerId,
fuel_manager_info: fuelManagerInfo,
status: 'pending',
notes: slipData.notes || '',
@@ -1297,6 +1447,7 @@ app.post('/api/vehicles', (req, res) => {
model,
year,
plate,
unit_id,
fuel_type,
fuel_capacity,
current_fuel,
@@ -1308,10 +1459,15 @@ app.post('/api/vehicles', (req, res) => {
} = req.body;
// Validasyon
if (!brand || !model || !year || !plate || !fuel_type || !fuel_capacity) {
if (!brand || !model || !year || !plate || !unit_id || !fuel_type || !fuel_capacity) {
return res.status(400).json({ message: 'Tüm zorunlu alanları doldurun.' });
}
const targetUnit = units.find(u => u.id === parseInt(unit_id));
if (!targetUnit) {
return res.status(400).json({ message: 'Geçerli bir birlik seçin.' });
}
if (year < 1990 || year > new Date().getFullYear() + 1) {
return res.status(400).json({ message: 'Geçerli bir yıl girin.' });
}
@@ -1329,18 +1485,21 @@ app.post('/api/vehicles', (req, res) => {
}
// Yeni araç oluştur
const unitName = targetUnit.name;
const newVehicle = {
id: nextVehicleId++,
brand: brand.trim(),
model: model.trim(),
year: parseInt(year),
plate: plate.trim().toUpperCase(),
unit_id: parseInt(unit_id),
fuel_type: fuel_type.trim(),
fuel_capacity: parseInt(fuel_capacity),
current_fuel: parseInt(current_fuel) || 0,
yazlik_mukannen: parseInt(yazlik_mukannen) || 0,
kislik_mukannen: parseInt(kislik_mukannen) || 0,
status: status.trim(),
yazlik_mukannen: parseMukannenValue(yazlik_mukannen),
kislik_mukannen: parseMukannenValue(kislik_mukannen),
status: (status || 'Aktif').trim(),
unit_name: unitName,
driver_id: driver_id ? parseInt(driver_id) : null,
driver_name: driver_name ? driver_name.trim() : null,
created_at: new Date().toISOString()
@@ -1369,6 +1528,7 @@ app.put('/api/vehicles', (req, res) => {
model,
year,
plate,
unit_id,
fuel_type,
fuel_capacity,
current_fuel,
@@ -1380,10 +1540,15 @@ app.put('/api/vehicles', (req, res) => {
} = req.body;
// Validasyon
if (!id || !brand || !model || !year || !plate || !fuel_type || !fuel_capacity) {
if (!id || !brand || !model || !year || !plate || !unit_id || !fuel_type || !fuel_capacity) {
return res.status(400).json({ message: 'Tüm zorunlu alanları doldurun.' });
}
const targetUnit = units.find(u => u.id === parseInt(unit_id));
if (!targetUnit) {
return res.status(400).json({ message: 'Geçerli bir birlik seçin.' });
}
if (year < 1990 || year > new Date().getFullYear() + 1) {
return res.status(400).json({ message: 'Geçerli bir yıl girin.' });
}
@@ -1407,18 +1572,21 @@ app.put('/api/vehicles', (req, res) => {
}
// Araç güncelle
const unitName = targetUnit.name;
vehicles[vehicleIndex] = {
...vehicles[vehicleIndex],
brand: brand.trim(),
model: model.trim(),
year: parseInt(year),
plate: plate.trim().toUpperCase(),
unit_id: parseInt(unit_id),
fuel_type: fuel_type.trim(),
fuel_capacity: parseInt(fuel_capacity),
current_fuel: parseInt(current_fuel) || 0,
yazlik_mukannen: parseInt(yazlik_mukannen) || 0,
kislik_mukannen: parseInt(kislik_mukannen) || 0,
yazlik_mukannen: parseMukannenValue(yazlik_mukannen),
kislik_mukannen: parseMukannenValue(kislik_mukannen),
status: (status || 'Aktif').trim(),
unit_name: unitName,
driver_id: driver_id ? parseInt(driver_id) : null,
driver_name: driver_name ? driver_name.trim() : null
};
@@ -1516,4 +1684,4 @@ async function startServer() {
}
}
startServer();
startServer();