export function createSeedDatabase({ nowIso, hashPassword }) { const adminId = 'usr_admin'; const schoolAdminId = 'usr_school_admin'; const schoolAdmin2Id = 'usr_school_admin_2'; const candidateId = 'usr_demo'; const examId = 'exam_autumn_2026'; const registrationId = 'reg_demo_2026'; const testPasswordHash = hashPassword('12345678'); const database = { meta: { version: 15, createdAt: nowIso() }, settings: { selfRegistrationEnabled: false }, organization: { name: '海州市教育考试中心', code: 'HZ-EDU-032', phone: '0518-8602 3158', address: '江苏省连云港市海州区文教路 18 号' }, schools: [ { id: 'school_hz1', name: '海州市第一中学', code: 'HZ01', address: '江苏省连云港市海州区学府路 8 号', active: true }, { id: 'school_hz3', name: '海州市第三中学', code: 'HZ03', address: '江苏省连云港市连云区育才路 16 号', active: true } ], classes: [ { id: 'class_hz1_301', schoolId: 'school_hz1', name: '高三(1)班', grade: '高三', active: true }, { id: 'class_hz1_302', schoolId: 'school_hz1', name: '高三(2)班', grade: '高三', active: true }, { id: 'class_hz3_301', schoolId: 'school_hz3', name: '高三(1)班', grade: '高三', active: true } ], users: [ { id: adminId, username: 'admin', passwordHash: testPasswordHash, role: 'admin', adminLevel: 'super', displayName: '林老师', active: true, createdAt: nowIso() }, { id: 'usr_supervisor', username: 'supervisor', passwordHash: testPasswordHash, role: 'admin', adminLevel: 'super', displayName: '赵督导', active: true, createdAt: nowIso() }, { id: schoolAdminId, username: 'school_admin', passwordHash: testPasswordHash, role: 'admin', adminLevel: 'school', schoolId: 'school_hz1', displayName: '王校管', active: true, createdAt: nowIso() }, { id: schoolAdmin2Id, username: 'school_admin_2', passwordHash: testPasswordHash, role: 'admin', adminLevel: 'school', schoolId: 'school_hz1', displayName: '陈校管', active: true, createdAt: nowIso() }, { id: 'usr_class_admin', username: 'class_admin', passwordHash: testPasswordHash, role: 'admin', adminLevel: 'class', schoolId: 'school_hz1', classId: 'class_hz1_302', displayName: '孙班管', active: true, createdAt: nowIso() }, { id: 'usr_class_admin_2', username: 'class_admin_2', passwordHash: testPasswordHash, role: 'admin', adminLevel: 'class', schoolId: 'school_hz1', classId: 'class_hz1_302', displayName: '李班管', active: true, createdAt: nowIso() }, { id: candidateId, username: '2026-HZ01-F-0001', candidateNumber: '2026-HZ01-F-0001', passwordHash: testPasswordHash, role: 'candidate', displayName: '周雨桐', active: true, mustChangePassword: false, createdAt: nowIso() } ], candidateProfiles: [ { id: 'profile_demo', userId: candidateId, name: '周雨桐', gender: '女', idNumber: '320101200808164821', 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, status: 'approved', reviewNote: '身份信息与学籍信息核验一致', reviewedAt: '2026-07-18T08:30:00.000Z', updatedAt: '2026-07-17T09:20:00.000Z' } ], notices: [ { id: 'notice_1', title: '2026 年秋季统一考试报名安排', summary: '报名时间为 7 月 1 日至 7 月 31 日,请考生完成实名认证后选报科目。', content: '2026 年秋季统一考试报名现已开放。考生须在规定时间内登录平台,核对个人信息并选择报考科目。逾期不再补报。', category: '报名通知', pinned: true, status: 'published', publishAt: '2026-07-01T01:00:00.000Z', author: '考试中心' }, { id: 'notice_2', title: '准考证下载与考场规则说明', summary: '准考证开放下载后,请使用 A4 纸打印并妥善保管。', content: '准考证下载时间为 7 月 20 日至 8 月 16 日。考生须携带身份证和纸质准考证入场,开考 15 分钟后不得进入考点。', category: '考试须知', pinned: false, status: 'published', publishAt: '2026-07-15T02:30:00.000Z', author: '考试中心' }, { id: 'notice_3', title: '市第三中学考点交通提示', summary: '考试期间考点周边实行临时交通管制,请提前规划路线。', content: '建议考生至少提前 50 分钟到达考点。考点不提供停车位,请优先选择公共交通出行。', category: '考点公告', pinned: false, status: 'published', publishAt: '2026-07-18T06:00:00.000Z', author: '考务组' } ], 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: '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: [] } ], 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' } ], results: [], testCenters: [ { id: 'center_hz1', schoolId: 'school_hz1', code: 'HZ01-C01', name: '海州市第一中学考点', provinceCode: '320000', provinceName: '江苏省', cityCode: '320700', cityName: '连云港市', districtCode: '320706', districtName: '海州区', address: '学府路 8 号', contact: '0518-8602 1101', managerName: '王立新', managerPhone: '13800001101', emergencyPhone: '0518-8602 1190', gateOpenTime: '07:00', transport: '地铁 2 号线学府路站 2 号口,步行约 600 米', status: 'active', notes: '南门为考生唯一入口,无障碍通道位于东侧。', rooms: '教学楼 A:001、002;实验楼:机考 01', updatedAt: nowIso() }, { id: 'center_hz3', schoolId: 'school_hz3', code: 'HZ03-C01', name: '海州市第三中学考点', provinceCode: '320000', provinceName: '江苏省', cityCode: '320700', cityName: '连云港市', districtCode: '320703', districtName: '连云区', address: '育才路 16 号', contact: '0518-8602 3301', managerName: '李文峰', managerPhone: '13800003301', emergencyPhone: '0518-8602 3390', gateOpenTime: '07:10', transport: '公交 18、32 路育才路站,考点不提供社会车辆停车位', status: 'active', notes: '西门设置临时物品存放区。', rooms: '笃学楼:001、002', updatedAt: nowIso() } ], testRooms: [ { id: 'room_hz1_001', centerId: 'center_hz1', code: '001', name: '第 001 考场', building: '教学楼 A', floor: '1 层', capacity: 30, seatPlan: '按现场桌贴从前至后编排', roomType: 'standard', status: 'active', notes: '' }, { id: 'room_hz1_002', centerId: 'center_hz1', code: '002', name: '第 002 考场', building: '教学楼 A', floor: '1 层', capacity: 30, seatPlan: '按现场桌贴从前至后编排', roomType: 'standard', status: 'active', notes: '' }, { id: 'room_hz1_pc01', centerId: 'center_hz1', code: 'PC01', name: '机考 01 考场', building: '实验楼', floor: '3 层', capacity: 40, seatPlan: '按终端编号编排', roomType: 'computer', status: 'active', notes: '配备备用终端 4 台' }, { id: 'room_hz3_001', centerId: 'center_hz3', code: '001', name: '第 001 考场', building: '笃学楼', floor: '1 层', capacity: 30, seatPlan: '按现场桌贴编排', roomType: 'standard', status: 'active', notes: '' }, { id: 'room_hz3_002', centerId: 'center_hz3', code: '002', name: '第 002 考场', building: '笃学楼', floor: '1 层', capacity: 30, seatPlan: '无障碍席位优先编排', roomType: 'accessible', status: 'active', notes: '靠近无障碍通道' } ], centerChangeRequests: [], centerChangeRooms: [], admissionNumberRules: [ { id: 'admit_rule_district_room_seat', code: 'district_room_seat', name: '县区编号 + 考场号 + 座位号', description: '适合县区统一组织,号码直接反映县区、考试考场与座位。', separator: '', example: '32070603108', active: true, createdAt: nowIso(), segments: [ { source: 'district_code', label: '县区编号', width: 6 }, { source: 'exam_room_code', label: '考场号', width: 3 }, { source: 'seat', label: '座位号', width: 2 } ] }, { id: 'admit_rule_district_room_sequence', code: 'district_room_sequence', name: '县区号 + 考场号 + 流水号', description: '以县区为流水边界,适合不希望座位号直接出现在号码中的场景。', separator: '', example: '3207060310028', active: true, createdAt: nowIso(), segments: [ { source: 'district_code', label: '县区号', width: 6 }, { source: 'exam_room_code', label: '考场号', width: 3 }, { source: 'sequence', label: '流水号', width: 4 } ] }, { id: 'admit_rule_center_school_room_seat', code: 'center_school_room_seat', name: '考点学校代码 + 考场号 + 座位号', description: '号码前缀取考点所属学校代码,便于考点现场快速识别。', separator: '', example: 'HZ0303108', active: true, createdAt: nowIso(), segments: [ { source: 'center_school_code', label: '考点学校代码' }, { source: 'exam_room_code', label: '考场号', width: 3 }, { source: 'seat', label: '座位号', width: 2 } ] }, { id: 'admit_rule_candidate_school_room_seat', code: 'candidate_school_room_seat', name: '考生学校代码 + 考场号 + 座位号', description: '号码前缀保留考生学籍学校代码,适合按生源学校归档。', separator: '', example: 'HZ0103108', active: true, createdAt: nowIso(), segments: [ { source: 'candidate_school_code', label: '考生学校代码' }, { source: 'exam_room_code', label: '考场号', width: 3 }, { source: 'seat', label: '座位号', width: 2 } ] } ], arrangementPlans: [], candidateAccountBatches: [], candidateAccountBatchItems: [], numberRules: [ { id: 'rule_default', name: '年度学校性别流水号', separator: '-', active: true, createdBy: adminId, updatedAt: nowIso(), segments: [ { id: 'segment_year', position: 1, type: 'year', value: '', width: 4 }, { id: 'segment_school', position: 2, type: 'school_code', value: '', width: 0 }, { id: 'segment_gender', position: 3, type: 'gender', value: '', width: 0 }, { id: 'segment_sequence', position: 4, type: 'sequence', value: '', width: 4 } ] } ], workflows: [ { id: 'workflow_profile', businessType: 'profile_change', name: '考生信息修改审批', active: true, updatedBy: adminId, updatedAt: nowIso(), steps: [ { id: 'workflow_profile_step_1', position: 1, name: '学校学籍复核', adminLevel: 'school' }, { id: 'workflow_profile_step_2', position: 2, name: '考试中心终审', adminLevel: 'super' } ] }, { id: 'workflow_registration', businessType: 'registration_review', name: '考试报名审核', active: true, updatedBy: adminId, updatedAt: nowIso(), steps: [ { id: 'workflow_registration_step_1', position: 1, name: '学校报名初审', adminLevel: 'school' }, { id: 'workflow_registration_step_2', position: 2, name: '考试中心终审', adminLevel: 'super' } ] }, { id: 'workflow_center', businessType: 'center_change', name: '考点考场变更审批', active: true, updatedBy: adminId, updatedAt: nowIso(), steps: [ { id: 'workflow_center_step_1', position: 1, name: '考试中心考务终审', adminLevel: 'super' } ] }, { id: 'workflow_account_batch', businessType: 'candidate_account_batch', name: '批量报名号申领审批', active: true, updatedBy: adminId, updatedAt: nowIso(), steps: [ { id: 'workflow_account_batch_step_1', position: 1, name: '考试中心账号终审', adminLevel: 'super' } ] }, { id: 'workflow_score_appeal', businessType: 'score_appeal', name: '考生成绩复议', active: true, updatedBy: adminId, updatedAt: nowIso(), steps: [ { id: 'workflow_score_appeal_step_1', position: 1, name: '班级情况核验', adminLevel: 'class' }, { id: 'workflow_score_appeal_step_2', position: 2, name: '学校成绩复核', adminLevel: 'school' }, { id: 'workflow_score_appeal_step_3', position: 3, name: '考试中心终审', adminLevel: 'super' } ] } ], workflowInstances: [], workflowActions: [], admissionRecords: [], auditLogs: [ { id: 'log_1', actorId: adminId, action: '发布通知', detail: '发布《市第三中学考点交通提示》', createdAt: '2026-07-18T06:00:00.000Z' } ] }; const schoolDefinitions = [ { 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 号' } ]; for (const school of schoolDefinitions) { 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 }); } for (let classIndex = 1; classIndex <= 3; classIndex += 1) { const classId = `class_${school.key}_30${classIndex}`; if (!database.classes.some(item => item.id === classId)) { database.classes.push({ id: classId, schoolId: school.id, name: `高三(${classIndex})班`, grade: '高三', active: true }); } } } for (const school of schoolDefinitions) { 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}`; 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, displayName: `${school.name}高三${classIndex}班测试班管`, active: true, createdAt: nowIso() }); } } for (const school of schoolDefinitions) { let center = database.testCenters.find(item => item.schoolId === school.id); if (!center) { center = { id: `center_${school.key}`, schoolId: school.id, code: `${school.code}-C01`, name: `${school.name}考点`, provinceCode: '320000', provinceName: '江苏省', cityCode: '320700', cityName: '连云港市', districtCode: school.districtCode, districtName: school.districtName, address: school.address, contact: '0518-8602 0000', managerName: '测试负责人', managerPhone: '13800000000', emergencyPhone: '0518-8602 0120', gateOpenTime: '07:00', transport: '测试数据:请以正式考点通知为准', status: 'active', notes: '仅供手动导入测试数据使用', rooms: '', updatedAt: nowIso() }; database.testCenters.push(center); } for (let roomIndex = 1; roomIndex <= 4; roomIndex += 1) { const roomId = `room_${school.key}_test_${roomIndex}`; if (!database.testRooms.some(item => item.id === roomId)) { database.testRooms.push({ id: roomId, centerId: center.id, code: `T0${roomIndex}`, name: `测试第 ${roomIndex} 考场`, building: '测试教学楼', floor: `${Math.ceil(roomIndex / 2)} 层`, capacity: 30, seatPlan: '等待正式编排', roomType: 'standard', status: 'active', notes: '未编排' }); } } } // 测试库停留在考场编排前:不预置编排计划、准考证或成绩。 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 registrationWorkflowId = 'workflow_registration'; for (let index = 0; index < 360; index += 1) { const serial = index + 1001; const school = schoolDefinitions[index % schoolDefinitions.length]; const classIndex = Math.floor(index / schoolDefinitions.length) % 3 + 1; const classId = `class_${school.key}_30${classIndex}`; const gender = index % 2 === 0 ? '男' : '女'; const genderCode = gender === '男' ? 'M' : 'F'; const userId = `usr_bulk_${String(index + 1).padStart(4, '0')}`; 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 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')}`; database.users.push({ id: userId, username: candidateNumber, candidateNumber, passwordHash: testPasswordHash, role: 'candidate', displayName: name, active: true, mustChangePassword: false, createdAt }); 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, provinceCode: '320000', provinceName: '江苏省', cityCode: '320700', cityName: '连云港市', districtCode: school.districtCode, districtName: school.districtName, address: `${school.address}测试宿舍 ${index % 20 + 1} 号`, 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 }); 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}`; database.registrations.push({ id: registrationIdBulk, userId, examId, subjectIds: subjectSets[index % subjectSets.length], status, paymentStatus, paidAt: paymentStatus === 'paid' ? '2026-07-25T08: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' }); 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 }); 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' }); } } } return database; }