已完成迁移验收和清理。

删除全部 Node.js 后端、.mjs 测试、辅助脚本、package*.json、node_modules 和迁移对照工具。
浏览器前端保留并迁入 [Eis.Web/wwwroot](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Web/wwwroot/index.html),统一改为 .js 模块。
修复一个隐藏遗漏:.NET 仍依赖 schema.mjs,且 MySQL 结构解析可能被转义反引号截断。现已改为原生 [SQLite SQL](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Infrastructure/Data/Schema.sqlite.sql) 和 [MySQL SQL](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Infrastructure/Data/Schema.mysql.sql) 资源。
更新了 [DatabaseInitializer.cs](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Infrastructure/Data/DatabaseInitializer.cs)、项目配置、README 和迁移文档。
data 目录和现有数据库未修改;测试仅使用系统临时 SQLite 数据库。
This commit is contained in:
2026-07-23 17:49:57 +08:00 Unverified
parent f3ffc18aae
commit b139834396
79 changed files with 695 additions and 18757 deletions
-55
View File
@@ -1,55 +0,0 @@
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}`);
-44
View File
@@ -1,44 +0,0 @@
import { pbkdf2Sync } from 'node:crypto';
import { writeFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join, resolve } from 'node:path';
import { gzipSync } from 'node:zlib';
import { buildSeedOperations } from '../database.mjs';
import { createSeedDatabase } from '../src/data/seed.mjs';
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const outputPath = join(root, 'src', 'Eis.Infrastructure', 'Data', 'demo-seed-operations.json.gz');
const generatedAt = '2026-07-23T00:00:00.000Z';
const deterministicSalt = 'eis-dotnet-demo-seed';
const hashPassword = password => {
const hash = pbkdf2Sync(password, deterministicSalt, 120000, 32, 'sha256').toString('hex');
return `${deterministicSalt}:${hash}`;
};
const database = createSeedDatabase({
nowIso: () => generatedAt,
hashPassword
});
database.meta.version = 20;
const operations = buildSeedOperations(database);
const payload = {
version: 1,
schemaVersion: 20,
generatedAt,
summary: {
schools: database.schools.length,
users: database.users.length,
candidates: database.candidateProfiles.length,
registrations: database.registrations.length,
results: database.results.length,
admissionRecords: database.admissionRecords.length,
firstRoundPreferences: database.admissionRecords.filter(
item => item.kind === 'preference' && Number(item.payload?.round || 1) === 1
).length,
operations: operations.length
},
operations
};
const compressed = gzipSync(Buffer.from(JSON.stringify(payload)), { level: 9 });
await writeFile(outputPath, compressed);
console.log(JSON.stringify({ outputPath, compressedBytes: compressed.length, ...payload.summary }));
File diff suppressed because it is too large Load Diff
+10 -1
View File
@@ -81,6 +81,9 @@ try {
$migration = Invoke-RestMethod -Uri "$baseUrl/health/migration" -TimeoutSec 5
$homeResponse = Invoke-WebRequest -Uri "$baseUrl/" -TimeoutSec 5
$applicationScript = Invoke-WebRequest -Uri "$baseUrl/js/app.js" -TimeoutSec 10
$clientApiModule = Invoke-WebRequest -Uri "$baseUrl/js/client/api.js" -TimeoutSec 10
$regionDataModule = Invoke-WebRequest -Uri "$baseUrl/js/data/china-regions.js" -TimeoutSec 10
$ckeditor = Invoke-WebRequest -Uri "$baseUrl/vendor/ckeditor5/ckeditor5.js" -TimeoutSec 10
$session = [Microsoft.PowerShell.Commands.WebRequestSession]::new()
$loginBody = @{
@@ -99,13 +102,18 @@ try {
-WebSession $session `
-TimeoutSec 5
$missing = Invoke-WebRequest `
-Uri "$baseUrl/api/removed-node-route" `
-Uri "$baseUrl/api/removed-legacy-route" `
-SkipHttpErrorCheck `
-TimeoutSec 5
if ($live.status -ne 'healthy' -or
$migration.legacyApiRemoved -ne $true -or
$homeResponse.StatusCode -ne 200 -or
$homeResponse.Content -notmatch '/js/app\.js' -or
$applicationScript.RawContentLength -lt 100000 -or
$applicationScript.Content -notmatch "from './client/api\.js'" -or
$clientApiModule.RawContentLength -lt 1000 -or
$regionDataModule.RawContentLength -lt 100000 -or
$ckeditor.RawContentLength -lt 100000 -or
$login.user.role -ne 'admin' -or
$login.user.adminLevel -ne 'super' -or
@@ -119,6 +127,7 @@ try {
Live = $live.status
LegacyRemoved = $migration.legacyApiRemoved
HomeStatus = $homeResponse.StatusCode
FrontendBytes = $applicationScript.RawContentLength
CkeditorBytes = $ckeditor.RawContentLength
LoginRole = $login.user.role
CurrentUser = $currentUser.user.username