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:
@@ -104,6 +104,27 @@ export const CompetitorRadar = () => {
|
||||
<div className="text-[11px] text-slate-500 ml-7">
|
||||
🏆 {f.wins} ihale · 💰 {formatTL(f.total)} {f.share ? `· %${f.share} pay` : ''} {f.sectors[0] ? `· ${f.sectors[0]}` : ''}
|
||||
</div>
|
||||
{/* Kazanan istihbaratı: ne kadar aşağı veriyor, kaç rakibe karşı kazanıyor */}
|
||||
<div className="text-[11px] mt-1 ml-7 flex flex-wrap gap-1.5">
|
||||
{f.kirimOrani != null && (
|
||||
<span className="bg-emerald-50 text-emerald-800 border border-emerald-200 px-1.5 py-0.5 rounded font-bold"
|
||||
title="Sözleşme bedelinin yaklaşık maliyete göre ortalama kırımı">
|
||||
↓ %{f.kirimOrani} kırım
|
||||
</span>
|
||||
)}
|
||||
{f.ortTeklif != null && (
|
||||
<span className="bg-blue-50 text-blue-800 border border-blue-200 px-1.5 py-0.5 rounded font-bold"
|
||||
title="Kazandığı ihalelerde ortalama geçerli teklif sayısı">
|
||||
⚔ ort. {f.ortTeklif} teklif
|
||||
</span>
|
||||
)}
|
||||
{f.tekTeklifOrani != null && f.tekTeklifOrani > 0 && (
|
||||
<span className="bg-amber-50 text-amber-800 border border-amber-200 px-1.5 py-0.5 rounded font-bold"
|
||||
title="Tek teklifle (rakipsiz) kazandığı ihalelerin oranı">
|
||||
%{f.tekTeklifOrani} tek teklif
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => addFromReal(f)}
|
||||
|
||||
Reference in New Issue
Block a user