feat: OKAS kod aramasi, toplu ihale dokumani yukleme, kazanan istihbarati
Uc ozellik, 27+1 depo taramasinda gorulen fikirlerden; kod kopyalanmadi
(ilgili depolar lisanssiz), uygulamalar sifirdan yazildi.
1) OKAS koduyla arama (fikir: firatbadur/ihaletakip-api'nin kullandigi
IhtiyacKalemleri/GetAll ucu). EKAP'in kendi OKAS katalogunda ad ile
(TR/EN) arama: "ortoped" → 33141700 Ortopedik malzemeler, 33183000
Ortopedik destek cihazlari. Secilen kodla EKAP'ta ihale aramasi
(okasBransKodList). Olculen: 33141700 altinda 335 ihale, basliklari
"VETERINER ILAC VE SARF MALZEME" — basliktan gorunmeyen turden.
- ekap-v2.mjs: okasAra(), searchByOkas(); sonuc normalize ortak
- GET /api/okas/ara?q= (1 sa onbellek); /api/urun-ara?okas=kod,kod
- Urun Arama modalinda "OKAS koduyla" modu (katalog onerisi + cok kod)
- Sol menude CPV bolumunun ustunde OKAS kutusu: kod secilince modal
o kodla acilip hemen arar
2) Toplu ihale dokumani yukleme (fikir: barkem-tayyar/ihale'nin izlenen
klasor + extractIkn deseni). Belge Kasasi'na coklu dosya secimi: her
dosyanin IKN'si METNINDEN bulunur ("Ihale Kayit Numarasi (IKN):
2026/1166496"), kullaniciya sorulmaz; ihaleye baglanir ve teklif
cetveli kalemleri otomatik havuza yazilir. Onlarca sartnameyi tek
seferde atarak kalem havuzunu hizla doldurmak icin.
- kalem-cikar.mjs#iknCikar + istemci esi (PDF tarayicida okunuyor)
- Yukleme ucu: otoIkn → ofis metninden IKN; donuste ikn alani
- Dosya basina sonuc satiri: IKN / kalem sayisi / "IKN bulunamadi"
Dogrulandi: ikn parametresiz docx → 2026/1588948 bulundu, 2 kalem.
3) Kazanan istihbarati (fikir: gulmezeren2-byte/ihalent, MIT). Rakip
Radari'nda firma basina kirim orani (1 − sozlesme/yaklasik maliyet,
ortalama), ortalama gecerli teklif sayisi (rekabet derinligi) ve tek
teklifle kazanma orani. Veri yoksa null — 0 ile karismasin; bedel >
maliyet×1,5 olan bozuk satirlar orana katilmiyor.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, {useState, useEffect } from 'react';
|
||||
import { useApp } from '../context/AppContext';
|
||||
import { INSTITUTION_TYPES_LIST, CITIES_LIST } from '../data/constants';
|
||||
import {
|
||||
@@ -24,6 +24,8 @@ export const LeftSidebar = () => {
|
||||
setSelectedCpvler,
|
||||
toggleCpv,
|
||||
cpvBolumListesi,
|
||||
setIsUrunAramaOpen,
|
||||
setUrunAramaBaslangic,
|
||||
selectedKurumTipi,
|
||||
setSelectedKurumTipi,
|
||||
selectedCity,
|
||||
@@ -33,6 +35,23 @@ export const LeftSidebar = () => {
|
||||
|
||||
const [sektorAra, setSektorAra] = useState('');
|
||||
const [cpvAra, setCpvAra] = useState('');
|
||||
// OKAS kataloğu: idarenin kendi kodu. "ortopedi" başlıkta geçmese de kod yakalar.
|
||||
const [okasQ, setOkasQ] = useState('');
|
||||
const [okasSonuc, setOkasSonuc] = useState([]);
|
||||
useEffect(() => {
|
||||
const t = okasQ.trim();
|
||||
if (t.length < 2) { setOkasSonuc([]); return; }
|
||||
let iptal = false;
|
||||
const z = setTimeout(() => import('../services/kalem')
|
||||
.then(({ okasAra }) => okasAra(t))
|
||||
.then((k) => { if (!iptal) setOkasSonuc(k.slice(0, 12)); })
|
||||
.catch(() => {}), 350);
|
||||
return () => { iptal = true; clearTimeout(z); };
|
||||
}, [okasQ]);
|
||||
const okasIleAra = (k) => {
|
||||
setUrunAramaBaslangic({ okasKod: k.kod, okasAd: k.ad });
|
||||
setIsUrunAramaOpen(true);
|
||||
};
|
||||
const [openSections, setOpenSections] = useState({
|
||||
alimTuru: true,
|
||||
sektorler: true,
|
||||
@@ -264,6 +283,27 @@ export const LeftSidebar = () => {
|
||||
<p className="text-[11px] text-slate-500 mb-2 leading-relaxed">
|
||||
CPV, AB'nin ihale konusunu sınıflandırdığı standart koddur. Türkiye'deki NACE/faaliyet kodunun yerine geçmez — NACE firmanızı, CPV ihalenin konusunu sınıflandırır.
|
||||
</p>
|
||||
{/* OKAS: EKAP'ta idarenin seçtiği kod. Bulunan kodla EKAP'ta arama açılır. */}
|
||||
<div className="mb-2 relative">
|
||||
<input
|
||||
value={okasQ}
|
||||
onChange={(e) => setOkasQ(e.target.value)}
|
||||
placeholder="OKAS kodu bul: ortopedik, röntgen…"
|
||||
className="w-full border border-indigo-200 bg-indigo-50/40 rounded-lg px-2 py-1.5 text-xs focus:outline-hidden focus:ring-2 focus:ring-indigo-500/30"
|
||||
/>
|
||||
{okasSonuc.length > 0 && (
|
||||
<div className="absolute z-20 left-0 right-0 mt-1 bg-white border border-slate-200 rounded-lg shadow-lg max-h-52 overflow-y-auto">
|
||||
{okasSonuc.map((k) => (
|
||||
<button key={k.kod} type="button" onClick={() => { okasIleAra(k); setOkasQ(''); }}
|
||||
title="Bu OKAS koduyla EKAP'ta ara"
|
||||
className="w-full text-left px-2 py-1.5 text-[11px] hover:bg-indigo-50 flex items-baseline gap-1.5">
|
||||
<span className="font-mono font-bold text-indigo-700 shrink-0">{k.kod}</span>
|
||||
<span className="text-slate-700 truncate">{k.ad}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<input
|
||||
value={cpvAra}
|
||||
onChange={(e) => setCpvAra(e.target.value)}
|
||||
|
||||
Reference in New Issue
Block a user