PUT /api/candidate/profile

行政区划、学校班级、特长类别校验
证件号码唯一性
自动创建资料审核工作流
资料和用户显示名称原子更新

POST /api/candidate/registrations
资料审核状态、报名时间和科目校验
重复报名防护
自动选择负载最低的审批管理员
报名、科目和审批流原子写入
This commit is contained in:
2026-07-22 19:55:19 +08:00 Unverified
parent 07efa6813b
commit aecb0a04e7
16 changed files with 995 additions and 36 deletions
@@ -0,0 +1,20 @@
using Eis.Infrastructure.Candidate;
namespace Eis.Infrastructure.Tests.Candidate;
public sealed class RegionCatalogTests
{
[Fact]
public void ResolvesCodesFromEmbeddedAuthoritativeSnapshot()
{
var catalog = new RegionCatalog();
var region = catalog.Resolve("320000", "320700", "320706");
Assert.NotNull(region);
Assert.Equal("江苏省", region.ProvinceName);
Assert.Equal("连云港市", region.CityName);
Assert.Equal("海州区", region.DistrictName);
Assert.Null(catalog.Resolve("320000", "320700", "invalid"));
}
}
@@ -0,0 +1,24 @@
import { DatabaseSync } from 'node:sqlite';
const databasePath = process.argv[2];
const candidateNumber = process.argv[3];
if (!databasePath || !candidateNumber) throw new Error('缺少 SQLite 路径或报名号');
const database = new DatabaseSync(databasePath);
const user = database.prepare("SELECT id FROM users WHERE candidate_number = ? AND role = 'candidate'").get(candidateNumber);
if (!user) throw new Error('未找到冒烟测试考生');
const reviewer = database.prepare("SELECT id FROM users WHERE role = 'admin' AND active = 1 ORDER BY created_at, id LIMIT 1").get();
database.prepare(
"UPDATE candidate_profiles SET status = 'approved', review_note = '', reviewed_at = ?, reviewer_id = ? WHERE user_id = ?"
).run('2026-07-22T00:00:00.000Z', reviewer?.id || null, user.id);
const exam = database.prepare("SELECT id FROM exams WHERE status = 'published' AND archived_at IS NULL ORDER BY created_at, id LIMIT 1").get();
if (!exam) throw new Error('未找到已发布考试');
database.prepare(
'UPDATE exams SET registration_start = ?, registration_end = ? WHERE id = ?'
).run('2000-01-01T00:00:00.000Z', '2099-12-31T23:59:59.999Z', exam.id);
const subject = database.prepare('SELECT id FROM exam_subjects WHERE exam_id = ? ORDER BY position, id LIMIT 1').get(exam.id);
if (!subject) throw new Error('考试缺少科目');
database.close();
console.log(JSON.stringify({ examId: exam.id, subjectId: subject.id }));