测试数据生成

This commit is contained in:
2026-07-21 17:52:34 +08:00 Unverified
parent 5477a261f8
commit 607b71e4f0
5 changed files with 199 additions and 75 deletions
+154 -70
View File
@@ -1,4 +1,4 @@
export function createSeedDatabase({ nowIso, hashPassword }) {
export function createSeedDatabase({ nowIso, hashPassword, candidateCount = 1200 }) {
const adminId = 'usr_admin';
const schoolAdminId = 'usr_school_admin';
const schoolAdmin2Id = 'usr_school_admin_2';
@@ -6,6 +6,39 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
const examId = 'exam_autumn_2026';
const registrationId = 'reg_demo_2026';
const testPasswordHash = hashPassword('12345678');
const mainSubjectDefinitions = [
{ id: 'sub_chinese', name: '语文', date: '2026-06-20', start: '09:00', end: '11:00', fullScore: 120 },
{ id: 'sub_math', name: '数学', date: '2026-06-20', start: '14:30', end: '16:30', fullScore: 120 },
{ id: 'sub_english', name: '外语', date: '2026-06-21', start: '09:00', end: '11:00', fullScore: 120 },
{ id: 'sub_history', name: '历史', date: '2026-06-21', start: '14:30', end: '15:45', fullScore: 75 },
{ id: 'sub_politics', name: '政治', date: '2026-06-21', start: '16:10', end: '17:25', fullScore: 75 },
{ id: 'sub_physics', name: '物理', date: '2026-06-22', start: '09:00', end: '10:20', fullScore: 80 },
{ id: 'sub_chemistry', name: '化学', date: '2026-06-22', start: '10:45', end: '12:00', fullScore: 70 },
{ id: 'sub_experiment', name: '实验', date: '2026-06-22', start: '14:30', end: '15:00', fullScore: 20 },
{ id: 'sub_it', name: '信息技术', date: '2026-06-22', start: '15:30', end: '16:00', fullScore: 10 }
].map((subject, index) => ({
...subject, fee: 0, passRule: 'fixed_score', passValue: subject.fullScore * 0.6,
passScore: subject.fullScore * 0.6, order: index + 1
}));
const mainSubjectIds = mainSubjectDefinitions.map(subject => subject.id);
const mainCandidateCount = Math.max(1, Math.trunc(Number(candidateCount) || 1200));
const specialtyCandidateCount = Math.min(150, mainCandidateCount);
// 固定种子使每次导入得到相同的近似正态成绩,便于复现测试。
let randomState = 0x20260620;
const seededRandom = () => {
randomState = (randomState + 0x6D2B79F5) >>> 0;
let value = randomState;
value = Math.imul(value ^ (value >>> 15), value | 1);
value ^= value + Math.imul(value ^ (value >>> 7), value | 61);
return ((value ^ (value >>> 14)) >>> 0) / 4294967296;
};
const normalRandom = () => {
const first = Math.max(seededRandom(), Number.EPSILON);
return Math.sqrt(-2 * Math.log(first)) * Math.cos(2 * Math.PI * seededRandom());
};
const normalScore = fullScore => Number(Math.min(fullScore, Math.max(0, fullScore * 0.72 + fullScore * 0.14 * normalRandom())).toFixed(1));
const scoreGrade = (score, fullScore) => score >= fullScore * 0.9 ? 'A' : score >= fullScore * 0.75 ? 'B' : score >= fullScore * 0.6 ? 'C' : 'D';
const database = {
meta: { version: 15, createdAt: nowIso() },
settings: { selfRegistrationEnabled: false },
@@ -16,8 +49,8 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
address: '江苏省连云港市海州区文教路 18 号'
},
schools: [
{ id: 'school_hz1', name: '海州市第一中学', code: 'HZ01', address: '江苏省连云港市海州区学府路 8 号', active: true },
{ id: 'school_hz3', name: '海州市第三中学', code: 'HZ03', address: '江苏省连云港市连云区育才路 16 号', active: true }
{ id: 'school_hz1', name: '海州市第一中学', code: 'HZ01', address: '江苏省连云港市海州区学府路 8 号', isSourceSchool: true, isAdmissionSchool: false, active: true },
{ id: 'school_hz3', name: '海州市第三中学', code: 'HZ03', address: '江苏省连云港市连云区育才路 16 号', isSourceSchool: true, isAdmissionSchool: false, active: true }
],
classes: [
{ id: 'class_hz1_301', schoolId: 'school_hz1', name: '高三(1)班', grade: '高三', active: true },
@@ -39,7 +72,8 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
phone: '13800138000', email: 'zhou@example.com', school: '海州市第一中学', grade: '高三(2)班', schoolId: 'school_hz1', classId: 'class_hz1_302',
provinceCode: '320000', provinceName: '江苏省', cityCode: '320700', cityName: '连云港市', districtCode: '320706', districtName: '海州区',
address: '学府路 8 号', emergencyContact: '周建国', emergencyPhone: '13900139000',
nativePlace: '江苏海州', birthDate: '2008-08-16', ethnicity: '汉族', postalCode: '222000', guardianName: '周建国', guardianPhone: '13900139000', profileCompleted: false,
nativePlace: '江苏海州', birthDate: '2008-08-16', ethnicity: '汉族', postalCode: '222000', guardianName: '周建国', guardianPhone: '13900139000',
specialtyCategory: 'arts', specialtyType: 'fine_arts', specialtyTypes: ['fine_arts'], specialtyCertificate: 'ART-DEMO-0001', policyEligibility: '特长生资格已核验', profileCompleted: true,
status: 'approved', reviewNote: '身份信息与学籍信息核验一致', reviewedAt: '2026-07-18T08:30:00.000Z', updatedAt: '2026-07-17T09:20:00.000Z'
}
],
@@ -50,33 +84,29 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
],
exams: [
{
id: examId, code: 'EX-2026-AUT', name: '2026 年秋季统一考试', description: '面向全市普通高中高三在籍学生的统一学业考试。',
registrationStart: '2026-07-01T00:00:00.000Z', registrationEnd: '2026-07-31T15:59:59.000Z',
examStart: '2026-08-16T01:00:00.000Z', examEnd: '2026-08-18T09:00:00.000Z',
admitDownloadStart: '2026-07-19T00:00:00.000Z', admitDownloadEnd: '2026-08-16T00:45:00.000Z',
location: '海州市各指定考点', passPolicy: 'rank_percent', passValue: 60, status: 'published', createdAt: '2026-06-18T02:00:00.000Z',
subjects: [
{ id: 'sub_chinese', name: '语文', date: '2026-08-16', start: '09:00', end: '11:30', fee: 30, fullScore: 150, passRule: 'fixed_score', passValue: 90, passScore: 90 },
{ id: 'sub_math', name: '数学', date: '2026-08-16', start: '15:00', end: '17:00', fee: 30, fullScore: 150, passRule: 'rank_percent', passValue: 60, passScore: null },
{ id: 'sub_physics', name: '物理', date: '2026-08-17', start: '09:00', end: '10:30', fee: 25, fullScore: 100, passScore: 60 },
{ id: 'sub_history', name: '历史', date: '2026-08-17', start: '09:00', end: '10:30', fee: 25, fullScore: 100, passScore: 60 },
{ id: 'sub_english', name: '外语', date: '2026-08-17', start: '15:00', end: '16:30', fee: 30, fullScore: 150, passScore: 90 },
{ id: 'sub_chemistry', name: '化学', date: '2026-08-18', start: '09:00', end: '10:15', fee: 25, fullScore: 100, passScore: 60 },
{ id: 'sub_biology', name: '生物', date: '2026-08-18', start: '15:00', end: '16:15', fee: 25, fullScore: 100, passScore: 60 }
]
id: examId, code: 'EX-2026-ZK', name: '2026 年海州市初中学业水平考试', description: '演示数据主考试:覆盖成绩发布、特长生和第一轮志愿填报。',
registrationStart: '2026-04-01T00:00:00.000Z', registrationEnd: '2026-04-30T15:59:59.000Z',
examStart: '2026-06-20T01:00:00.000Z', examEnd: '2026-06-22T08:00:00.000Z',
admitDownloadStart: '2026-06-10T00:00:00.000Z', admitDownloadEnd: '2026-06-20T00:45:00.000Z',
location: '海州市各指定考点', passPolicy: 'rank_percent', passValue: 60, status: 'published', createdAt: '2026-03-18T02:00:00.000Z',
subjects: mainSubjectDefinitions
},
{
id: 'exam_mock_2026', code: 'EX-2026-MOCK-2', name: '第二次全市模拟考试', description: '秋季统一考试前的全流程模拟考试。',
registrationStart: '2026-10-01T00:00:00.000Z', registrationEnd: '2026-10-20T15:59:59.000Z',
examStart: '2026-11-08T01:00:00.000Z', examEnd: '2026-11-10T09:00:00.000Z',
admitDownloadStart: '2026-11-01T00:00:00.000Z', admitDownloadEnd: '2026-11-08T00:45:00.000Z',
location: '考点待公布', passPolicy: 'rank_percent', passValue: 60, status: 'draft', createdAt: nowIso(), subjects: []
location: '考点待公布', passPolicy: 'rank_percent', passValue: 60, status: 'draft', createdAt: nowIso(), subjects: [
{ id: 'mock_sub_chinese', name: '语文', date: '2026-11-08', start: '09:00', end: '11:00', fee: 0, fullScore: 120, passRule: 'fixed_score', passValue: 72, passScore: 72 },
{ id: 'mock_sub_math', name: '数学', date: '2026-11-08', start: '14:30', end: '16:30', fee: 0, fullScore: 120, passRule: 'fixed_score', passValue: 72, passScore: 72 },
{ id: 'mock_sub_english', name: '外语', date: '2026-11-09', start: '09:00', end: '11:00', fee: 0, fullScore: 120, passRule: 'fixed_score', passValue: 72, passScore: 72 }
]
}
],
registrations: [
{
id: registrationId, userId: candidateId, examId, subjectIds: ['sub_chinese', 'sub_math', 'sub_physics', 'sub_english', 'sub_chemistry'],
status: 'approved', paymentStatus: 'paid', paidAt: '2026-07-18T09:00:00.000Z', paidBy: 'usr_class_admin', createdAt: '2026-07-08T05:18:00.000Z', reviewedAt: '2026-07-18T08:32:00.000Z', registrationNumber: '2026-HZ01-F-0001', numberRuleId: 'rule_default'
id: registrationId, userId: candidateId, examId, subjectIds: mainSubjectIds,
status: 'approved', paymentStatus: 'paid', paidAt: '2026-05-18T09:00:00.000Z', paidBy: 'usr_class_admin', createdAt: '2026-04-08T05:18:00.000Z', reviewedAt: '2026-04-18T08:32:00.000Z', reviewNote: '报名审核通过', registrationNumber: '2026-HZ01-F-0001', numberRuleId: 'rule_default', featureScore: 90
}
],
results: [],
@@ -171,15 +201,21 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
]
};
const schoolDefinitions = [
const sourceSchools = [
{ key: 'hz1', id: 'school_hz1', code: 'HZ01', name: '海州市第一中学', districtCode: '320706', districtName: '海州区', address: '学府路 8 号' },
{ key: 'hz3', id: 'school_hz3', code: 'HZ03', name: '海州市第三中学', districtCode: '320703', districtName: '连云区', address: '育才路 16 号' },
{ key: 'hz5', id: 'school_hz5', code: 'HZ05', name: '海州市第五中学', districtCode: '320707', districtName: '赣榆区', address: '青口路 28 号' },
{ key: 'hz7', id: 'school_hz7', code: 'HZ07', name: '海州市第七中学', districtCode: '320723', districtName: '灌云县', address: '胜利路 66 号' }
{ key: 'hz7', id: 'school_hz7', code: 'HZ07', name: '海州市第七中学', districtCode: '320723', districtName: '灌云县', address: '胜利路 66 号' },
{ key: 'hz9', id: 'school_hz9', code: 'HZ09', name: '海州市第九中学', districtCode: '320724', districtName: '灌南县', address: '新安路 39 号' }
];
for (const school of schoolDefinitions) {
const admissionSchools = [
{ key: 'admission_1', id: 'school_admission_1', code: 'AD01', name: '海州市高级中学', address: '江苏省连云港市海州区苍梧路 100 号' },
{ key: 'admission_2', id: 'school_admission_2', code: 'AD02', name: '海州市实验高级中学', address: '江苏省连云港市连云区海棠路 88 号' },
{ key: 'admission_3', id: 'school_admission_3', code: 'AD03', name: '海州市外国语高级中学', address: '江苏省连云港市赣榆区黄海路 66 号' }
];
for (const school of sourceSchools) {
if (!database.schools.some(item => item.id === school.id)) {
database.schools.push({ id: school.id, name: school.name, code: school.code, address: `江苏省连云港市${school.districtName}${school.address}`, active: true });
database.schools.push({ id: school.id, name: school.name, code: school.code, address: `江苏省连云港市${school.districtName}${school.address}`, isSourceSchool: true, isAdmissionSchool: false, active: true });
}
for (let classIndex = 1; classIndex <= 3; classIndex += 1) {
const classId = `class_${school.key}_30${classIndex}`;
@@ -189,14 +225,25 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
}
}
for (const school of schoolDefinitions) {
const generatedSchoolAdminId = `usr_test_school_admin_${school.key}`;
for (const school of admissionSchools) {
database.schools.push({ id: school.id, name: school.name, code: school.code, address: school.address, isSourceSchool: false, isAdmissionSchool: true, active: true });
database.users.push({
id: generatedSchoolAdminId, username: `test_school_admin_${school.key}`, passwordHash: testPasswordHash,
role: 'admin', adminLevel: 'school', schoolId: school.id, displayName: `${school.name}测试校管`, active: true, createdAt: nowIso()
id: `usr_${school.key}`, username: `${school.key}_admin`, passwordHash: testPasswordHash, role: 'admission_school',
schoolId: school.id, displayName: `${school.name}招生办`, active: true, mustChangePassword: false, createdAt: nowIso()
});
}
for (const school of sourceSchools) {
if (school.id !== 'school_hz1') {
const generatedSchoolAdminId = `usr_test_school_admin_${school.key}`;
database.users.push({
id: generatedSchoolAdminId, username: `test_school_admin_${school.key}`, passwordHash: testPasswordHash,
role: 'admin', adminLevel: 'school', schoolId: school.id, displayName: `${school.name}测试校管`, active: true, createdAt: nowIso()
});
}
for (let classIndex = 1; classIndex <= 3; classIndex += 1) {
const classId = `class_${school.key}_30${classIndex}`;
if (classId === 'class_hz1_302') continue;
database.users.push({
id: `usr_test_class_admin_${school.key}_${classIndex}`, username: `test_class_admin_${school.key}_${classIndex}`,
passwordHash: testPasswordHash, role: 'admin', adminLevel: 'class', schoolId: school.id, classId,
@@ -205,7 +252,7 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
}
}
for (const school of schoolDefinitions) {
for (const school of sourceSchools) {
let center = database.testCenters.find(item => item.schoolId === school.id);
if (!center) {
center = {
@@ -228,21 +275,20 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
}
}
// 测试库停留在考场编排前:不预置编排计划准考证或成绩
// 测试库停留在考场编排前:不预置编排计划准考证;主考试成绩与志愿已完成
const familyNames = ['赵', '钱', '孙', '李', '周', '吴', '郑', '王', '冯', '陈', '褚', '卫'];
const givenNames = ['子涵', '梓萱', '宇航', '雨欣', '浩然', '思远', '佳宁', '晨曦', '明轩', '若彤', '嘉诚', '欣怡'];
const subjectSets = [
['sub_chinese', 'sub_math', 'sub_english'],
['sub_chinese', 'sub_math', 'sub_physics', 'sub_chemistry'],
['sub_chinese', 'sub_math', 'sub_history', 'sub_biology'],
['sub_chinese', 'sub_math', 'sub_english', 'sub_physics', 'sub_chemistry'],
['sub_chinese', 'sub_math', 'sub_english', 'sub_history', 'sub_biology']
const specialtyDefinitions = [
{ category: 'sports', type: 'track_field', label: '田径' },
{ category: 'sports', type: 'basketball', label: '篮球' },
{ category: 'arts', type: 'fine_arts', label: '美术' },
{ category: 'arts', type: 'vocal_music', label: '声乐' },
{ category: 'arts', type: 'dance', label: '舞蹈' }
];
const registrationWorkflowId = 'workflow_registration';
for (let index = 0; index < 360; index += 1) {
for (let index = 0; index < mainCandidateCount - 1; index += 1) {
const serial = index + 1001;
const school = schoolDefinitions[index % schoolDefinitions.length];
const classIndex = Math.floor(index / schoolDefinitions.length) % 3 + 1;
const school = sourceSchools[index % sourceSchools.length];
const classIndex = Math.floor(index / sourceSchools.length) % 3 + 1;
const classId = `class_${school.key}_30${classIndex}`;
const gender = index % 2 === 0 ? '男' : '女';
const genderCode = gender === '男' ? 'M' : 'F';
@@ -250,7 +296,7 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
const profileId = `profile_bulk_${String(index + 1).padStart(4, '0')}`;
const registrationIdBulk = `reg_bulk_${String(index + 1).padStart(4, '0')}`;
const candidateNumber = `2026-${school.code}-${genderCode}-${String(serial).padStart(4, '0')}`;
const createdAt = new Date(Date.UTC(2026, 6, 2 + (index % 20), 1 + (index % 8), index % 60)).toISOString();
const createdAt = new Date(Date.UTC(2026, 3, 2 + (index % 20), 1 + (index % 8), index % 60)).toISOString();
const name = `${familyNames[index % familyNames.length]}${givenNames[Math.floor(index / familyNames.length) % givenNames.length]}${Math.floor(index / 144) + 1}`;
const idNumber = `3207002008${String(index % 12 + 1).padStart(2, '0')}${String(index % 28 + 1).padStart(2, '0')}${String(index + 1).padStart(4, '0')}`;
const phone = `138${String(10000000 + index).padStart(8, '0')}`;
@@ -258,6 +304,8 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
id: userId, username: candidateNumber, candidateNumber, passwordHash: testPasswordHash, role: 'candidate',
displayName: name, active: true, mustChangePassword: false, createdAt
});
const isSpecialtyCandidate = index < specialtyCandidateCount - 1;
const specialty = isSpecialtyCandidate ? specialtyDefinitions[index % specialtyDefinitions.length] : null;
database.candidateProfiles.push({
id: profileId, userId, name, gender, idNumber, phone, email: `candidate${String(index + 1).padStart(4, '0')}@example.test`,
school: school.name, grade: `高三(${classIndex})班`, schoolId: school.id, classId,
@@ -266,41 +314,77 @@ export function createSeedDatabase({ nowIso, hashPassword }) {
emergencyContact: `${familyNames[index % familyNames.length]}家长`, emergencyPhone: `139${String(10000000 + index).padStart(8, '0')}`,
nativePlace: `江苏${school.districtName}`, birthDate: `2008-${String(index % 12 + 1).padStart(2, '0')}-${String(index % 28 + 1).padStart(2, '0')}`,
ethnicity: index % 19 === 0 ? '回族' : '汉族', postalCode: '222000', guardianName: `${familyNames[index % familyNames.length]}家长`,
guardianPhone: `139${String(10000000 + index).padStart(8, '0')}`, profileCompleted: true, status: 'approved',
reviewNote: '批量测试数据:学籍核验通过', reviewedAt: '2026-06-30T08:00:00.000Z', reviewerId: adminId, updatedAt: createdAt
guardianPhone: `139${String(10000000 + index).padStart(8, '0')}`,
specialtyCategory: specialty?.category || '', specialtyType: specialty?.type || '', specialtyTypes: specialty ? [specialty.type] : [],
specialtyCertificate: specialty ? `SPECIAL-2026-${String(index + 2).padStart(4, '0')}` : '', policyEligibility: specialty ? `${specialty.label}特长生资格已核验` : '',
profileCompleted: true, status: 'approved', reviewNote: '批量演示数据:学籍核验通过',
reviewedAt: '2026-04-30T08:00:00.000Z', reviewerId: adminId, updatedAt: createdAt
});
const scenario = index % 4;
const status = scenario === 0 ? 'pending' : scenario === 1 ? 'rejected' : 'approved';
const paymentStatus = scenario === 3 ? 'paid' : 'unpaid';
const classAdminId = `usr_test_class_admin_${school.key}_${classIndex}`;
const schoolAdmin = `usr_test_school_admin_${school.key}`;
const paymentStatus = index % 2 === 0 ? 'paid' : 'unpaid';
const classAdminId = classId === 'class_hz1_302' ? 'usr_class_admin' : `usr_test_class_admin_${school.key}_${classIndex}`;
database.registrations.push({
id: registrationIdBulk, userId, examId, subjectIds: subjectSets[index % subjectSets.length], status, paymentStatus,
paidAt: paymentStatus === 'paid' ? '2026-07-25T08:30:00.000Z' : null,
id: registrationIdBulk, userId, examId, subjectIds: mainSubjectIds, status: 'approved', paymentStatus,
paidAt: paymentStatus === 'paid' ? '2026-05-18T08:30:00.000Z' : null,
paidBy: paymentStatus === 'paid' ? classAdminId : null,
createdAt, reviewedAt: status === 'pending' ? null : '2026-07-22T08:00:00.000Z',
reviewNote: status === 'rejected' ? '测试场景:报名资料被退回' : status === 'approved' ? '测试场景:报名审核通过' : '',
registrationNumber: candidateNumber, numberRuleId: 'rule_default'
createdAt, reviewedAt: '2026-04-30T08:00:00.000Z', reviewNote: '批量演示数据:报名审核通过',
registrationNumber: candidateNumber, numberRuleId: 'rule_default',
featureScore: specialty ? Number((80 + seededRandom() * 20).toFixed(1)) : 0
});
if (status === 'pending' || status === 'rejected') {
const instanceId = `flow_reg_bulk_${String(index + 1).padStart(4, '0')}`;
database.workflowInstances.push({
id: instanceId, workflowId: registrationWorkflowId, businessType: 'registration_review', businessId: registrationIdBulk,
status, currentStep: 1, assigneeId: status === 'pending' ? schoolAdmin : null, createdAt,
completedAt: status === 'rejected' ? '2026-07-22T08:00:00.000Z' : null
}
const admissionCreatedAt = '2026-07-01T00:00:00.000Z';
database.admissionRecords.push({
id: 'admission_setting_main_2026', kind: 'setting', examId, userId: adminId, schoolId: null, status: 'closed',
payload: {
enabled: true, preferenceStart: '2026-07-01T00:00:00.000Z', preferenceEnd: '2026-07-15T15:59:59.000Z',
maxChoices: 3, maxSubmissions: 1, round: 1, autoPublish: true, progress: '第一轮志愿已全部填报完毕,等待投档'
},
createdAt: admissionCreatedAt, updatedAt: '2026-07-16T00:00:00.000Z'
});
for (const school of admissionSchools) {
database.admissionRecords.push({
id: `admission_plan_${school.key}`, kind: 'plan', examId, userId: `usr_${school.key}`, schoolId: school.id, status: 'approved',
payload: {
categories: [
{ code: 'general', name: '普通生', quota: mainCandidateCount, specialtyCategory: '', specialtyType: '', indicatorAllocations: [] },
{ code: 'sports', name: '体育特长生', quota: specialtyCandidateCount, specialtyCategory: 'sports', specialtyType: '', indicatorAllocations: [] },
{ code: 'arts', name: '艺术特长生', quota: specialtyCandidateCount, specialtyCategory: 'arts', specialtyType: '', indicatorAllocations: [] }
],
note: '演示数据招生计划', submittedBy: `${school.name}招生办`, reviewedBy: '林老师', reviewedAt: admissionCreatedAt, publicVisible: true
},
createdAt: admissionCreatedAt, updatedAt: admissionCreatedAt
});
}
const mainRegistrations = database.registrations.filter(registration => registration.examId === examId);
for (const [candidateIndex, registration] of mainRegistrations.entries()) {
const profile = database.candidateProfiles.find(item => item.userId === registration.userId);
const isSpecialtyCandidate = Boolean(profile?.specialtyCategory);
for (const subject of mainSubjectDefinitions) {
const score = normalScore(subject.fullScore);
database.results.push({
id: `result_main_${String(candidateIndex + 1).padStart(4, '0')}_${subject.id.slice(4)}`,
registrationId: registration.id, subjectId: subject.id, score, grade: scoreGrade(score, subject.fullScore),
published: true, updatedAt: '2026-06-30T08:00:00.000Z', publishedAt: '2026-06-30T08:00:00.000Z'
});
database.workflowActions.push({
id: `flow_action_submit_bulk_${String(index + 1).padStart(4, '0')}`, instanceId, actorId: userId, action: 'submit',
note: '提交考试报名', fromAssigneeId: null, toAssigneeId: schoolAdmin, createdAt
});
if (status === 'rejected') {
database.workflowActions.push({
id: `flow_action_reject_bulk_${String(index + 1).padStart(4, '0')}`, instanceId, actorId: schoolAdmin, action: 'reject',
note: '测试场景:报名资料被退回', fromAssigneeId: schoolAdmin, toAssigneeId: null, createdAt: '2026-07-22T08:00:00.000Z'
});
}
}
const rotatedAdmissionSchools = admissionSchools.map((_, offset) => admissionSchools[(candidateIndex + offset) % admissionSchools.length]);
database.admissionRecords.push({
id: `preference_main_${String(candidateIndex + 1).padStart(4, '0')}`, kind: 'preference', examId,
userId: registration.userId, schoolId: null, status: 'submitted',
payload: {
round: 1, submissionCount: 1, submittedAt: new Date(Date.UTC(2026, 6, 5 + (candidateIndex % 10), 1 + (candidateIndex % 8), candidateIndex % 60)).toISOString(),
choices: rotatedAdmissionSchools.map(school => ({ schoolId: school.id, categoryCode: 'general', preferenceType: 'general' }))
},
createdAt: admissionCreatedAt, updatedAt: '2026-07-15T08:00:00.000Z'
});
database.admissionRecords.push({
id: `qualification_main_${String(candidateIndex + 1).padStart(4, '0')}`, kind: 'indicator_qualification', examId,
userId: registration.userId, schoolId: profile.schoolId, status: 'confirmed',
payload: { eligible: isSpecialtyCandidate, confirmedAt: '2026-06-28T08:00:00.000Z', note: isSpecialtyCandidate ? '特长资格核验通过' : '普通生' },
createdAt: '2026-06-28T08:00:00.000Z', updatedAt: '2026-06-28T08:00:00.000Z'
});
}
return database;