Add hierarchical region data to candidate and center records
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { readFile, writeFile } from 'node:fs/promises';
|
||||
import { resolve } from 'node:path';
|
||||
|
||||
const input = resolve(process.argv[2] || 'ok_data_level3.csv');
|
||||
const output = resolve(process.argv[3] || 'src/data/china-regions.mjs');
|
||||
|
||||
function parseCsvLine(line) {
|
||||
const values = [];
|
||||
let value = '';
|
||||
let quoted = false;
|
||||
for (let index = 0; index < line.length; index += 1) {
|
||||
const char = line[index];
|
||||
if (char === '"') {
|
||||
if (quoted && line[index + 1] === '"') { value += '"'; index += 1; }
|
||||
else quoted = !quoted;
|
||||
} else if (char === ',' && !quoted) {
|
||||
values.push(value);
|
||||
value = '';
|
||||
} else value += char;
|
||||
}
|
||||
values.push(value);
|
||||
return values;
|
||||
}
|
||||
|
||||
const source = await readFile(input, 'utf8');
|
||||
const rows = source.replace(/^\uFEFF/, '').trim().split(/\r?\n/).slice(1).map(line => {
|
||||
const [id, pid, deep, , , , extId, extName] = parseCsvLine(line);
|
||||
return { id, pid, deep: Number(deep), code: extId.slice(0, 6), name: extName };
|
||||
});
|
||||
|
||||
const provinces = rows.filter(item => item.deep === 0 && item.code !== '0').map(province => ({
|
||||
code: province.code,
|
||||
name: province.name,
|
||||
cities: rows.filter(city => city.deep === 1 && city.pid === province.id).map(city => ({
|
||||
code: city.code,
|
||||
name: city.name,
|
||||
districts: rows.filter(district => district.deep === 2 && district.pid === city.id).map(district => ({
|
||||
code: district.code,
|
||||
name: district.name
|
||||
}))
|
||||
}))
|
||||
}));
|
||||
|
||||
const hotan = provinces.find(item => item.code === '650000')?.cities.find(item => item.code === '653200');
|
||||
for (const district of [
|
||||
{ code: '653228', name: '和康县' },
|
||||
{ code: '653229', name: '和安县' }
|
||||
]) {
|
||||
if (hotan && !hotan.districts.some(item => item.code === district.code)) hotan.districts.push(district);
|
||||
}
|
||||
hotan?.districts.sort((a, b) => a.code.localeCompare(b.code));
|
||||
|
||||
const banner = `// Generated from AreaCity-JsSpider-StatsGov release 2025.251231.260403.\n// Source snapshot: 国家地名信息库 2025-12-31; generated 2026-07-20.\n// Manual official additions: 和康县 653228, 和安县 653229.\n`;
|
||||
await writeFile(output, `${banner}export const chinaRegionsVersion = '2025-12-31';\nexport const chinaRegions = ${JSON.stringify(provinces)};\n`, 'utf8');
|
||||
console.log(`Generated ${provinces.length} provinces at ${output}`);
|
||||
@@ -0,0 +1,27 @@
|
||||
import { pbkdf2Sync, randomBytes } from 'node:crypto';
|
||||
import { rm } from 'node:fs/promises';
|
||||
import { isAbsolute, join, relative, resolve } from 'node:path';
|
||||
import { createDatabase } from '../database.mjs';
|
||||
import { createSeedDatabase } from '../src/data/seed.mjs';
|
||||
|
||||
const root = resolve(process.cwd());
|
||||
const databasePath = join(root, 'data', 'exam.sqlite');
|
||||
const relativePath = relative(root, databasePath);
|
||||
if (!relativePath || relativePath.startsWith('..') || isAbsolute(relativePath)) throw new Error('拒绝重建工作区以外的数据库');
|
||||
|
||||
for (const path of [databasePath, `${databasePath}-shm`, `${databasePath}-wal`]) await rm(path, { force: true });
|
||||
|
||||
function hashPassword(password, salt = randomBytes(16).toString('hex')) {
|
||||
const hash = pbkdf2Sync(password, salt, 120000, 32, 'sha256').toString('hex');
|
||||
return `${salt}:${hash}`;
|
||||
}
|
||||
|
||||
process.env.DATABASE_CLIENT = 'sqlite';
|
||||
process.env.SQLITE_PATH = databasePath;
|
||||
const database = await createDatabase({
|
||||
root,
|
||||
seed: () => createSeedDatabase({ nowIso: () => new Date().toISOString(), hashPassword })
|
||||
});
|
||||
const state = await database.read();
|
||||
await database.close();
|
||||
console.log(`Rebuilt ${databasePath} (schema ${state.meta.version}, ${state.candidateProfiles.length} candidates, ${state.testCenters.length} centers)`);
|
||||
Reference in New Issue
Block a user