This commit is contained in:
2026-07-02 12:52:03 +05:00
parent 6fa93e15cc
commit d8a19ab484
2 changed files with 49 additions and 12 deletions

View File

@@ -15,20 +15,28 @@ const HEADER_MAP = {
'код оо': 'school_code',
'серия': 'passport_series',
'номер': 'passport_number',
'документ': 'document',
'первичный балл': 'primary_score',
'оценка': 'grade'
'оценка': 'grade',
'тестовый балл': 'grade'
};
function normalize(s) {
return String(s || '').trim().toLowerCase();
}
function parseXls(filePath) {
function parseXls(filePath, originalName) {
const workbook = XLSX.readFile(filePath);
const sheetName = workbook.SheetNames[0];
const sheet = workbook.Sheets[sheetName];
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: '' });
let fileSubjectCode = null;
if (originalName) {
const m = originalName.match(/^(\d{2})_/);
if (m) fileSubjectCode = m[1];
}
const parsedSubjects = [];
const studentsMap = new Map();
const results = [];
@@ -50,6 +58,9 @@ function parseXls(filePath) {
const subjectInfo = detectSubject(firstCell);
if (subjectInfo) {
if (!subjectInfo.code && fileSubjectCode) {
subjectInfo.code = fileSubjectCode;
}
currentSubject = subjectInfo;
parsedSubjects.push(subjectInfo);
colIdx = null;
@@ -106,17 +117,32 @@ function uniqSubjects(subjects) {
function detectSubject(firstCell) {
if (!firstCell) return null;
const match = firstCell.match(/^(\d{2})\s*-\s*(.+?)\s+(\d{4}\.\d{2}\.\d{2})$/);
if (!match) return null;
const code = match[1];
const name = match[2];
const date = match[3];
// Old format: "09 - Английский язык 2024.06.05"
const oldMatch = firstCell.match(/^(\d{2})\s*-\s*(.+?)\s+(\d{4}\.\d{2}\.\d{2})$/);
if (oldMatch) {
const code = oldMatch[1];
const name = oldMatch[2];
const date = oldMatch[3];
if (SUBJECT_NAMES.some(sn => sn.toLowerCase() === name.toLowerCase())) {
return { code, name, date };
}
return null;
}
// New format: "Английский язык п.: 2026.06.06, у.: 2026.06.06"
const newMatch = firstCell.match(/^(.+?)\s+п\.:\s*(\d{4}\.\d{2}\.\d{2})/);
if (newMatch) {
const name = newMatch[1].trim();
const date = newMatch[2];
if (SUBJECT_NAMES.some(sn => sn.toLowerCase() === name.toLowerCase())) {
return { code: null, name, date };
}
}
return null;
}
function isSummaryRowText(firstCell) {
return /^(средни|всего|итого)/i.test(firstCell);
}
@@ -149,6 +175,17 @@ function extractStudentData(row, colIdx) {
const last_name = get('last_name');
if (!last_name || last_name.length < 2) return null;
let passport_series = get('passport_series');
let passport_number = get('passport_number');
if (!passport_series && !passport_number) {
const doc = get('document');
if (doc) {
const parts = doc.split(/\s+/);
passport_series = parts[0] || '';
passport_number = parts.slice(1).join('') || '';
}
}
const toInt = (v) => {
const n = parseInt(v, 10);
return isNaN(n) ? null : n;
@@ -160,8 +197,8 @@ function extractStudentData(row, colIdx) {
patronymic: get('patronymic'),
class: get('class'),
school_code: get('school_code'),
passport_series: get('passport_series'),
passport_number: get('passport_number'),
passport_series,
passport_number,
primary_score: toInt(get('primary_score')),
grade: toInt(get('grade'))
};

View File

@@ -23,7 +23,7 @@ router.post('/import', upload.single('xlsfile'), (req, res) => {
try {
if (!req.file) return res.status(400).json({ error: 'Файл не загружен' });
const parsed = parseXls(req.file.path);
const parsed = parseXls(req.file.path, req.file.originalname);
const studentIdByKey = {};
dbBegin();