Add structured admission plans and school role management

This commit is contained in:
2026-07-21 14:04:19 +08:00 Unverified
parent 1b6e860013
commit 5e0bee60e2
23 changed files with 483 additions and 82 deletions
+35 -17
View File
@@ -60,7 +60,7 @@ export function buildSeedOperations(state) {
const nullable = value => value == null || value === '' ? null : value;
add(
'UPDATE schema_metadata SET schema_version = 18, app_version = ?, self_registration_enabled = ?, created_at = ? WHERE id = 1',
'UPDATE schema_metadata SET schema_version = 19, app_version = ?, self_registration_enabled = ?, created_at = ? WHERE id = 1',
Number(state.meta?.version || 1), state.settings?.selfRegistrationEnabled ? 1 : 0,
state.meta?.createdAt || new Date().toISOString()
);
@@ -71,8 +71,9 @@ export function buildSeedOperations(state) {
for (const school of state.schools) {
add(
'INSERT INTO schools (id, name, code, address, active) VALUES (?, ?, ?, ?, ?)',
school.id, school.name, school.code, nullable(school.address), school.active === false ? 0 : 1
'INSERT INTO schools (id, name, code, address, is_source_school, is_admission_school, active) VALUES (?, ?, ?, ?, ?, ?, ?)',
school.id, school.name, school.code, nullable(school.address), school.isSourceSchool === false ? 0 : 1,
school.isAdmissionSchool === false ? 0 : 1, school.active === false ? 0 : 1
);
}
@@ -101,8 +102,9 @@ export function buildSeedOperations(state) {
id, user_id, name, gender, id_number, phone, email, school, grade, school_id, class_id,
province_code, province_name, city_code, city_name, district_code, district_name, address,
emergency_contact, emergency_phone, native_place, birth_date, ethnicity, postal_code, guardian_name,
guardian_phone, profile_completed, status, review_note, reviewed_at, reviewer_id, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
guardian_phone, specialty_category, specialty_type, specialty_types, specialty_certificate, policy_eligibility,
profile_completed, status, review_note, reviewed_at, reviewer_id, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
profile.id, profile.userId, profile.name, nullable(profile.gender), profile.idNumber, profile.phone,
nullable(profile.email), nullable(profile.school), nullable(profile.grade), nullable(profile.schoolId),
nullable(profile.classId), nullable(profile.provinceCode), nullable(profile.provinceName),
@@ -110,6 +112,8 @@ export function buildSeedOperations(state) {
nullable(profile.address),
nullable(profile.emergencyContact), nullable(profile.emergencyPhone), nullable(profile.nativePlace), nullable(profile.birthDate),
nullable(profile.ethnicity), nullable(profile.postalCode), nullable(profile.guardianName), nullable(profile.guardianPhone),
nullable(profile.specialtyCategory), nullable(profile.specialtyType), JSON.stringify(profile.specialtyTypes || []),
nullable(profile.specialtyCertificate), nullable(profile.policyEligibility),
profile.profileCompleted ? 1 : 0, profile.status, nullable(profile.reviewNote),
nullable(profile.reviewedAt), nullable(profile.reviewerId), profile.updatedAt
);
@@ -151,12 +155,12 @@ export function buildSeedOperations(state) {
add(
`INSERT INTO registrations (
id, user_id, exam_id, status, payment_status, paid_at, paid_by, created_at, reviewed_at, review_note,
registration_number, number_rule_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
registration_number, number_rule_id, feature_score
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
registration.id, registration.userId, registration.examId, registration.status,
registration.paymentStatus, nullable(registration.paidAt), nullable(registration.paidBy), registration.createdAt,
nullable(registration.reviewedAt), nullable(registration.reviewNote),
nullable(registration.registrationNumber), nullable(registration.numberRuleId)
nullable(registration.registrationNumber), nullable(registration.numberRuleId), Number(registration.featureScore || 0)
);
for (const subjectId of registration.subjectIds) {
add('INSERT INTO registration_subjects (registration_id, subject_id) VALUES (?, ?)', registration.id, subjectId);
@@ -466,6 +470,8 @@ function stateFromRows(rows) {
name: row.name,
code: row.code,
address: row.address || '',
isSourceSchool: row.is_source_school == null ? true : Boolean(row.is_source_school),
isAdmissionSchool: row.is_admission_school == null ? true : Boolean(row.is_admission_school),
active: Boolean(row.active)
})),
classes: rows.classes.map(row => ({
@@ -522,6 +528,8 @@ function stateFromRows(rows) {
postalCode: row.postal_code || '',
guardianName: row.guardian_name || '',
guardianPhone: row.guardian_phone || '',
specialtyCategory: row.specialty_category || '',
specialtyType: row.specialty_type || '',
specialtyTypes: parseJson(row.specialty_types, []),
specialtyCertificate: row.specialty_certificate || '',
policyEligibility: row.policy_eligibility || '',
@@ -578,6 +586,7 @@ function stateFromRows(rows) {
reviewNote: row.review_note || '',
registrationNumber: row.registration_number || '',
numberRuleId: row.number_rule_id || null,
featureScore: Number(row.feature_score || 0),
admitCard: admitCards.get(row.id) || null
})),
results: rows.results.map(row => ({
@@ -956,7 +965,7 @@ function createRepository({ client, location, read, transaction, close }) {
province_code = ?, province_name = ?, city_code = ?, city_name = ?, district_code = ?, district_name = ?, address = ?,
school_id = ?, class_id = ?, emergency_contact = ?, emergency_phone = ?, status = ?, review_note = ?,
native_place = ?, birth_date = ?, ethnicity = ?, postal_code = ?, guardian_name = ?, guardian_phone = ?,
specialty_types = ?, specialty_certificate = ?, policy_eligibility = ?,
specialty_category = ?, specialty_type = ?, specialty_types = ?, specialty_certificate = ?, policy_eligibility = ?,
profile_completed = ?, reviewed_at = ?, reviewer_id = ?, updated_at = ?
WHERE id = ?`,
profile.name, optional(profile.gender), profile.idNumber, profile.phone, optional(profile.email),
@@ -965,7 +974,8 @@ function createRepository({ client, location, read, transaction, close }) {
optional(profile.address), optional(profile.schoolId),
optional(profile.classId), optional(profile.emergencyContact), optional(profile.emergencyPhone), profile.status,
optional(profile.reviewNote), optional(profile.nativePlace), optional(profile.birthDate), optional(profile.ethnicity),
optional(profile.postalCode), optional(profile.guardianName), optional(profile.guardianPhone), JSON.stringify(profile.specialtyTypes || []),
optional(profile.postalCode), optional(profile.guardianName), optional(profile.guardianPhone), optional(profile.specialtyCategory),
optional(profile.specialtyType), JSON.stringify(profile.specialtyTypes || []),
optional(profile.specialtyCertificate), optional(profile.policyEligibility), profile.profileCompleted ? 1 : 0, optional(profile.reviewedAt),
optional(profile.reviewerId), profile.updatedAt, profile.id
),
@@ -1011,12 +1021,12 @@ function createRepository({ client, location, read, transaction, close }) {
const operations = [operation(
`INSERT INTO registrations (
id, user_id, exam_id, status, payment_status, paid_at, paid_by, created_at, reviewed_at, review_note,
registration_number, number_rule_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
registration_number, number_rule_id, feature_score
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
registration.id, registration.userId, registration.examId, registration.status,
registration.paymentStatus, optional(registration.paidAt), optional(registration.paidBy), registration.createdAt,
optional(registration.reviewedAt), optional(registration.reviewNote),
optional(registration.registrationNumber), optional(registration.numberRuleId)
optional(registration.registrationNumber), optional(registration.numberRuleId), Number(registration.featureScore || 0)
)];
for (const subjectId of registration.subjectIds) {
operations.push(operation(
@@ -1230,6 +1240,12 @@ function createRepository({ client, location, read, transaction, close }) {
auditOperation(log)
]);
},
async updateFeatureScore(registration, log) {
await transaction([
operation('UPDATE registrations SET feature_score = ? WHERE id = ?', Number(registration.featureScore || 0), registration.id),
auditOperation(log)
]);
},
async saveAdmissionRecord(record, log = null) {
const operations = [operation('DELETE FROM admission_records WHERE id = ?', record.id), operation(
`INSERT INTO admission_records (
@@ -1259,12 +1275,14 @@ function createRepository({ client, location, read, transaction, close }) {
async saveSchool(school, isNew, log) {
const change = isNew
? operation(
'INSERT INTO schools (id, name, code, address, active) VALUES (?, ?, ?, ?, ?)',
school.id, school.name, school.code, optional(school.address), school.active ? 1 : 0
'INSERT INTO schools (id, name, code, address, is_source_school, is_admission_school, active) VALUES (?, ?, ?, ?, ?, ?, ?)',
school.id, school.name, school.code, optional(school.address), school.isSourceSchool ? 1 : 0,
school.isAdmissionSchool ? 1 : 0, school.active ? 1 : 0
)
: operation(
'UPDATE schools SET name = ?, code = ?, address = ?, active = ? WHERE id = ?',
school.name, school.code, optional(school.address), school.active ? 1 : 0, school.id
'UPDATE schools SET name = ?, code = ?, address = ?, is_source_school = ?, is_admission_school = ?, active = ? WHERE id = ?',
school.name, school.code, optional(school.address), school.isSourceSchool ? 1 : 0,
school.isAdmissionSchool ? 1 : 0, school.active ? 1 : 0, school.id
);
await transaction([change, auditOperation(log)]);
},