feat: canlı veri — ilan.gov.tr açık ihale + EKAP doğrudan temin (22/d)

- server/index.js: ilan.gov.tr proxy (açık ihale + kira/satış), TLS zincir düzeltmesi
- server/dt-worker.mjs: EKAP doğrudan temin toplayıcı (Playwright, imzasız oturum içi fetch)
- server/dt-store.mjs + il-plaka.mjs: DT verisini tender modeline çevirme
- src/services/tenderApi.js + AppContext: mock veri yerine canlı API
- Doğrudan Temin sekmesi 256 gerçek 22/d kaydıyla dolu
This commit is contained in:
2026-08-26 20:45:02 +03:00
parent d9570fe422
commit 89cfd03d92
14 changed files with 1000 additions and 66 deletions
+38
View File
@@ -0,0 +1,38 @@
/**
* ihaleist canlı veri istemcisi.
* Backend proxy (server/index.js) üzerinden ilan.gov.tr resmi ihale ilanlarını çeker.
* Dev'de Vite proxy'si /api isteklerini localhost:3001'e yönlendirir.
*/
export async function fetchLiveTenders({ refresh = false } = {}) {
const res = await fetch(`/api/tenders${refresh ? '?refresh=1' : ''}`);
if (!res.ok) throw new Error(`API hatası: HTTP ${res.status}`);
const data = await res.json();
if (!data.success) throw new Error(data.error || 'API başarısız yanıt döndü');
return data;
}
export async function fetchTenderDetail(tenderId) {
const res = await fetch(`/api/tenders/${tenderId}/detail`);
if (!res.ok) throw new Error(`Detay API hatası: HTTP ${res.status}`);
const data = await res.json();
if (!data.success) throw new Error(data.error || 'Detay alınamadı');
return data;
}
// Kullanıcının ihale üzerindeki durumunu (kanban, takip vb.) canlı veriyle birleştirir.
const USER_FIELDS = ['kanbanStatus', 'takipte', 'incelendi', 'atananPersonel'];
export function mergeUserState(liveTenders, previousTenders) {
const prevById = new Map((previousTenders || []).map((t) => [t.id, t]));
return liveTenders.map((tender) => {
const prev = prevById.get(tender.id);
if (!prev) return tender;
const merged = { ...tender };
for (const f of USER_FIELDS) {
if (prev[f] !== undefined && prev[f] !== null && prev[f] !== false) merged[f] = prev[f];
}
if (prev.aciklama && !merged.aciklama) merged.aciklama = prev.aciklama;
return merged;
});
}