Add "detay" script to package.json and enhance ListemSekmeleri component functionality
All checks were successful
Deploy / deploy (push) Successful in 16m29s
All checks were successful
Deploy / deploy (push) Successful in 16m29s
- Introduced a new "detay" script in package.json for additional processing. - Refactored ListemSekmeleri component to improve tab functionality and state management. - Updated UI elements for better user interaction and clarity, including renaming "Seçtiklerim" to "Kendi Listem" for consistency across the application. - Made adjustments to related components for improved integration and user experience.
This commit is contained in:
267
scripts/detay.ts
Normal file
267
scripts/detay.ts
Normal file
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* Canlı YÖK Atlas API'sinden program detay verilerini çekip DB'ye işler:
|
||||
*
|
||||
* 1. Kontenjan türü kırılımı (son yerleştirme yılı, ör. 2025):
|
||||
* Genel / Okul Birincisi / Şehit-Gazi / Deprem / 34 Yaş Üstü Kadın
|
||||
* için kontenjan + yerleşen. Kaynak: POST /api/tercih-kilavuz/search
|
||||
* (gk1/gkY1, obk1/obkY1, sgy1/sgyY1, dprm1/dprmY1, y34_1/y34Y1 —
|
||||
* "1" son yerleştirme yılı demek; kayıttaki `yil` kılavuz yılıdır,
|
||||
* veri yılı = yil - 1).
|
||||
*
|
||||
* 2. Yerleşen son kişinin netleri (yıl bazında, tüm puan türleri):
|
||||
* Kaynak: POST /api/netler/search → `netler` tablosu.
|
||||
*
|
||||
* Not: YÖK Atlas 2026'da SPA'ya geçti; eski content/lisans-dynamic/*.php
|
||||
* panelleri (ve onlarla birlikte kadın-erkek dağılımı) yayından kalktı.
|
||||
* Cinsiyet verisi yeni API'lerin hiçbirinde yok.
|
||||
*
|
||||
* Kullanım: npx tsx scripts/detay.ts
|
||||
*/
|
||||
import path from "node:path";
|
||||
import Database from "better-sqlite3";
|
||||
|
||||
const KILAVUZ_API = "https://yokatlas.yok.gov.tr/api/tercih-kilavuz/search";
|
||||
const NETLER_API = "https://yokatlas.yok.gov.tr/api/netler/search";
|
||||
const PAGE_SIZE = 500;
|
||||
const DELAY_MS = 300;
|
||||
|
||||
type KilavuzRecord = {
|
||||
kilavuzKodu: number;
|
||||
eskiKilavuzKodu?: number | null;
|
||||
yil: number;
|
||||
gk1?: number | null;
|
||||
gkY1?: number | null;
|
||||
obk1?: number | null;
|
||||
obkY1?: number | null;
|
||||
sgy1?: number | null;
|
||||
sgyY1?: number | null;
|
||||
dprm1?: number | null;
|
||||
dprmY1?: number | null;
|
||||
y34_1?: number | null;
|
||||
y34Y1?: number | null;
|
||||
};
|
||||
|
||||
type NetlerRecord = {
|
||||
kilavuzKodu: number;
|
||||
yil: number;
|
||||
puanTuru: string | null;
|
||||
tabanPuan?: number | null;
|
||||
obp?: number | null;
|
||||
katsayi?: number | null;
|
||||
tytTrkNet?: number | null;
|
||||
tytSosNet?: number | null;
|
||||
tytMatNet?: number | null;
|
||||
tytFenNet?: number | null;
|
||||
aytMatNet?: number | null;
|
||||
aytFizNet?: number | null;
|
||||
aytKimNet?: number | null;
|
||||
aytBioNet?: number | null;
|
||||
aytTdeNet?: number | null;
|
||||
aytTrh1Net?: number | null;
|
||||
aytCog1Net?: number | null;
|
||||
aytTrh2Net?: number | null;
|
||||
aytCog2Net?: number | null;
|
||||
aytDinNet?: number | null;
|
||||
aytFelNet?: number | null;
|
||||
ydtYdilNet?: number | null;
|
||||
};
|
||||
|
||||
type ApiPage<T> = { content: T[]; totalPages: number; totalElements: number };
|
||||
|
||||
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
|
||||
|
||||
async function fetchPage<T>(api: string, page: number): Promise<ApiPage<T>> {
|
||||
const res = await fetch(api, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
filters: {},
|
||||
page,
|
||||
size: PAGE_SIZE,
|
||||
sortBy: "kilavuzKodu",
|
||||
direction: "ASC",
|
||||
}),
|
||||
});
|
||||
if (!res.ok) throw new Error(`${api} ${res.status} (sayfa ${page})`);
|
||||
return (await res.json()) as ApiPage<T>;
|
||||
}
|
||||
|
||||
function num(v: unknown): number | null {
|
||||
return typeof v === "number" && Number.isFinite(v) ? v : null;
|
||||
}
|
||||
|
||||
const NET_COLS = [
|
||||
"puanTuru",
|
||||
"tabanPuan",
|
||||
"obp",
|
||||
"katsayi",
|
||||
"tytTrkNet",
|
||||
"tytSosNet",
|
||||
"tytMatNet",
|
||||
"tytFenNet",
|
||||
"aytMatNet",
|
||||
"aytFizNet",
|
||||
"aytKimNet",
|
||||
"aytBioNet",
|
||||
"aytTdeNet",
|
||||
"aytTrh1Net",
|
||||
"aytCog1Net",
|
||||
"aytTrh2Net",
|
||||
"aytCog2Net",
|
||||
"aytDinNet",
|
||||
"aytFelNet",
|
||||
"ydtYdilNet",
|
||||
] as const;
|
||||
|
||||
async function main() {
|
||||
const db = new Database(path.join(process.cwd(), "data", "yokatlas.db"));
|
||||
db.pragma("journal_mode = WAL");
|
||||
|
||||
// ── 1. Kontenjan türü kırılımı ─────────────────────────────────────────
|
||||
const first = await fetchPage<KilavuzRecord>(KILAVUZ_API, 0);
|
||||
// API kaydındaki yil kılavuz yılı; "1" ekli alanlar bir önceki
|
||||
// yerleştirme dönemine ait (2026 kılavuzu → 2025 verisi)
|
||||
const veriYili = first.content[0].yil - 1;
|
||||
|
||||
const kontCols = [
|
||||
`gk${veriYili}`,
|
||||
`gkY${veriYili}`,
|
||||
`obk${veriYili}`,
|
||||
`obkY${veriYili}`,
|
||||
`sgy${veriYili}`,
|
||||
`sgyY${veriYili}`,
|
||||
`dprm${veriYili}`,
|
||||
`dprmY${veriYili}`,
|
||||
`y34k${veriYili}`,
|
||||
`y34kY${veriYili}`,
|
||||
];
|
||||
const mevcut = new Set(
|
||||
(db.prepare("PRAGMA table_info(programs)").all() as { name: string }[]).map(
|
||||
(c) => c.name
|
||||
)
|
||||
);
|
||||
for (const col of kontCols) {
|
||||
if (!mevcut.has(col)) {
|
||||
db.exec(`ALTER TABLE programs ADD COLUMN ${col} INTEGER`);
|
||||
}
|
||||
}
|
||||
|
||||
const updateKont = db.prepare(`
|
||||
UPDATE programs SET ${kontCols.map((c) => `${c} = ?`).join(", ")}
|
||||
WHERE id = ?
|
||||
`);
|
||||
const exists = db.prepare("SELECT 1 FROM programs WHERE id = ?");
|
||||
|
||||
// Kılavuz kodu yıllar arasında değişebiliyor (eskiKilavuzKodu); netler
|
||||
// API'si yeni kodla döndüğü için eşleşen DB id'sini haritada tutuyoruz.
|
||||
const dbId = new Map<number, string>();
|
||||
let kontUpdated = 0;
|
||||
let kontMissing = 0;
|
||||
|
||||
const processKilavuz = db.transaction((records: KilavuzRecord[]) => {
|
||||
for (const r of records) {
|
||||
if (!r.kilavuzKodu) continue;
|
||||
let id = String(r.kilavuzKodu);
|
||||
if (!exists.get(id)) {
|
||||
const eski = r.eskiKilavuzKodu ? String(r.eskiKilavuzKodu) : null;
|
||||
if (eski && exists.get(eski)) {
|
||||
id = eski;
|
||||
} else {
|
||||
kontMissing++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
dbId.set(r.kilavuzKodu, id);
|
||||
updateKont.run(
|
||||
num(r.gk1),
|
||||
num(r.gkY1),
|
||||
num(r.obk1),
|
||||
num(r.obkY1),
|
||||
num(r.sgy1),
|
||||
num(r.sgyY1),
|
||||
num(r.dprm1),
|
||||
num(r.dprmY1),
|
||||
num(r.y34_1),
|
||||
num(r.y34Y1),
|
||||
id
|
||||
);
|
||||
kontUpdated++;
|
||||
}
|
||||
});
|
||||
|
||||
console.log(
|
||||
`Kontenjan kırılımı (${veriYili}): ${first.totalElements} kayıt, ${first.totalPages} sayfa…`
|
||||
);
|
||||
processKilavuz(first.content);
|
||||
for (let p = 1; p < first.totalPages; p++) {
|
||||
await sleep(DELAY_MS);
|
||||
processKilavuz((await fetchPage<KilavuzRecord>(KILAVUZ_API, p)).content);
|
||||
process.stdout.write(`\rkontenjan sayfa ${p + 1}/${first.totalPages}`);
|
||||
}
|
||||
console.log(
|
||||
`\nKontenjan kırılımı: ${kontUpdated} güncellendi, ${kontMissing} DB'de yok`
|
||||
);
|
||||
|
||||
// ── 2. Yerleşen son kişinin netleri ────────────────────────────────────
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS netler (
|
||||
program_id TEXT NOT NULL,
|
||||
yil INTEGER NOT NULL,
|
||||
${NET_COLS.map((c) => `${c} ${c === "puanTuru" ? "TEXT" : "REAL"}`).join(
|
||||
",\n "
|
||||
)},
|
||||
PRIMARY KEY (program_id, yil)
|
||||
);
|
||||
`);
|
||||
|
||||
const insertNet = db.prepare(`
|
||||
INSERT OR REPLACE INTO netler (program_id, yil, ${NET_COLS.join(", ")})
|
||||
VALUES (${["?", "?", ...NET_COLS.map(() => "?")].join(", ")})
|
||||
`);
|
||||
|
||||
let netRows = 0;
|
||||
const processNetler = db.transaction((records: NetlerRecord[]) => {
|
||||
for (const r of records) {
|
||||
if (!r.kilavuzKodu || !r.yil) continue;
|
||||
const id = dbId.get(r.kilavuzKodu) ?? String(r.kilavuzKodu);
|
||||
insertNet.run(
|
||||
id,
|
||||
r.yil,
|
||||
r.puanTuru?.trim() ?? null,
|
||||
...NET_COLS.slice(1).map((c) => num(r[c as keyof NetlerRecord]))
|
||||
);
|
||||
netRows++;
|
||||
}
|
||||
});
|
||||
|
||||
const netFirst = await fetchPage<NetlerRecord>(NETLER_API, 0);
|
||||
console.log(
|
||||
`Netler: ${netFirst.totalElements} kayıt, ${netFirst.totalPages} sayfa…`
|
||||
);
|
||||
processNetler(netFirst.content);
|
||||
for (let p = 1; p < netFirst.totalPages; p++) {
|
||||
await sleep(DELAY_MS);
|
||||
processNetler((await fetchPage<NetlerRecord>(NETLER_API, p)).content);
|
||||
process.stdout.write(`\rnetler sayfa ${p + 1}/${netFirst.totalPages}`);
|
||||
}
|
||||
console.log(`\nNetler: ${netRows} satır yazıldı`);
|
||||
|
||||
const ozet = db
|
||||
.prepare(
|
||||
`SELECT
|
||||
(SELECT COUNT(*) FROM programs WHERE gkY${veriYili} IS NOT NULL) AS kontlu,
|
||||
(SELECT COUNT(*) FROM netler) AS net,
|
||||
(SELECT COUNT(DISTINCT program_id) FROM netler) AS netli_program`
|
||||
)
|
||||
.get() as { kontlu: number; net: number; netli_program: number };
|
||||
console.log(
|
||||
`Özet → kontenjan kırılımı olan program: ${ozet.kontlu}, ` +
|
||||
`net satırı: ${ozet.net} (${ozet.netli_program} program)`
|
||||
);
|
||||
db.close();
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user