CPV/OKAS ham kod sınıflandırması: yayınlanmadan önce tamamlanan bir gate + sidebar filtresi
- server/cpv-classify.mjs (yeni): existing (kalem kodu) → keyword (66 kural, 45 OKAS_BOLUM kodunun tamamı kapsanıyor) → AI (analyzeSpec, sadece sözlükte gerçekten var olan kod kabul edilir) hibrit sınıflandırma - server/index.js: cache.tenders'a eklenmeden ÖNCE her ihale için CPV sınıflandırması await'leniyor (mevcut "sektör" alanının aksine, sonradan zenginleştirilmiyor) — hem ilk yükleme hem arka plan tamamlama yolunda - İKN bazlı kalıcı SQLite önbellek (history-store.mjs) — aynı ilan bir daha asla yeniden sınıflandırılmıyor - /api/meta/filtreler artık cpvBolumler döndürüyor - Frontend: Sektörler'in hemen altına CPV Kodu filtresi (arama + çoklu seçim), ihale kartında CPV rozeti, landing page'de yeni özellik: "AB uyumlu CPV sınıflandırması — Türkiye'de ilk"
This commit is contained in:
@@ -15,6 +15,7 @@ export const TenderList = () => {
|
||||
selectedCity,
|
||||
selectedAlimTuru,
|
||||
selectedSektorler,
|
||||
selectedCpvler,
|
||||
selectedKurumTipi,
|
||||
quickFilter,
|
||||
onlyValidOnly,
|
||||
@@ -53,6 +54,7 @@ export const TenderList = () => {
|
||||
if (selectedCity && normTr(tender.sehir) !== normTr(selectedCity)) return false;
|
||||
if (selectedAlimTuru && tender.alimTuru !== selectedAlimTuru) return false;
|
||||
if (selectedSektorler.length && !selectedSektorler.includes(tender.sektor)) return false;
|
||||
if (selectedCpvler.length && !(tender.cpvBolum || []).some(b => selectedCpvler.includes(b))) return false;
|
||||
if (selectedKurumTipi && tender.kurumTipi !== selectedKurumTipi) return false;
|
||||
|
||||
return true;
|
||||
@@ -62,7 +64,7 @@ export const TenderList = () => {
|
||||
if (sortBy === 'distant') return b.tarih.localeCompare(a.tarih);
|
||||
return 0;
|
||||
});
|
||||
}, [tenders, searchQuery, selectedCity, selectedAlimTuru, selectedSektorler, selectedKurumTipi, quickFilter, sortBy]);
|
||||
}, [tenders, searchQuery, selectedCity, selectedAlimTuru, selectedSektorler, selectedCpvler, selectedKurumTipi, quickFilter, sortBy]);
|
||||
|
||||
const totalPages = Math.max(1, Math.ceil(filteredTenders.length / itemsPerPage));
|
||||
const paginatedTenders = filteredTenders.slice((currentPage - 1) * itemsPerPage, currentPage * itemsPerPage);
|
||||
@@ -70,7 +72,7 @@ export const TenderList = () => {
|
||||
const handleExportExcel = () => {
|
||||
confetti({ particleCount: 80, spread: 60, origin: { y: 0.6 } });
|
||||
|
||||
const headers = ['IKN', 'Baslik', 'Kurum', 'Sehir', 'Tarih', 'Alim Turu', 'Sektor'];
|
||||
const headers = ['IKN', 'Baslik', 'Kurum', 'Sehir', 'Tarih', 'Alim Turu', 'Sektor', 'CPV'];
|
||||
const rows = filteredTenders.map(t => [
|
||||
t.ikn,
|
||||
`"${t.baslik.replace(/"/g, '""')}"`,
|
||||
@@ -78,7 +80,8 @@ export const TenderList = () => {
|
||||
t.sehir,
|
||||
t.tarih,
|
||||
t.alimTuru,
|
||||
t.sektor
|
||||
t.sektor,
|
||||
`"${(t.cpvLabel || (t.cpv || []).join(', ') || '').replace(/"/g, '""')}"`
|
||||
]);
|
||||
|
||||
const csvContent = 'data:text/csv;charset=utf-8,\uFEFF' + [headers.join(','), ...rows.map(r => r.join(','))].join('\n');
|
||||
|
||||
Reference in New Issue
Block a user