asu_tools_service/router/reports/parseExcel.handler.js
2026-03-02 16:30:21 +03:00

128 lines
3.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { BadRequestError } from "#root/errors/index.js";
import db from "#root/db.js";
import xlsx from "xlsx";
const sheetName = "Отчеты";
/** @type {xlsx.ParsingOptions} */
const xlsxParseOptions = {
sheets: sheetName,
cellHTML: false,
cellFormula: false,
cellDates: true,
dateNF: "yyyy-mm-dd"
};
/**
* URL: /api/reports_excel_file_parse
* Method: POST
* Description: Читает Excel файл отчетов и возвращает его в формате JSON. Принимает на вход файл
* отчетов в формате Excel.
*
* @type {HTTPRouteHandler}
*/
export default async (ctx) => {
const { res } = ctx;
if (!ctx.data) throw new BadRequestError("Cannot proceed uploaded file");
const [, files] = ctx.data;
const excelFilePath = files?.report?.at(0)?.filepath;
/** @type {{ markedReports: ReportModel[], reports: ReportModel[] }} */
const ret = { reports: [], markedReports: [] };
let foundEqupments = 0;
ctx.res.res.setHeaders(
new Headers({
Connection: "keep-alive",
"Cache-Control": "no-cache",
"Content-Type": "text/event-stream"
})
);
if (excelFilePath) {
const workbook = xlsx.readFile(excelFilePath, xlsxParseOptions);
const sheet = workbook.Sheets[sheetName];
if (!sheet) throw new Error("Invalid reports workbook.", { cause: { statusCode: 400 } });
const data = xlsx.utils.sheet_to_json(sheet, { raw: false, blankrows: true });
for (let i = 0; i < data.length; i++) {
const cols = Object.keys(data[i]);
if (i === 0) continue;
/** Несинхронизированные помеченные отчеты */
if ("__EMPTY_3" in data[i] && data[i]["__EMPTY_3"] === "r") {
ret.markedReports.push({
date: data[i][cols[0]],
equipment: data[i][cols[1]],
reason_call: data[i][cols[3]].split("\r\r\n")[1] || "",
job_description: data[i][cols[4]].split("\r\r\n")[1] || "",
root_cause: data[i]["__EMPTY_2"] || "",
applicantName: data[i][cols[3]].split("\r\r\n")[0] || "",
executorNames: data[i][cols[4]].split("\r\r\n")[0] || ""
});
continue;
}
/** Остальные отчеты */
ret.reports.push({
date: data[i][cols[0]],
equipment: data[i][cols[1]],
reason_call: parseReasonCallAndJobDesc(data[i][cols[3]]),
job_description: parseReasonCallAndJobDesc(data[i][cols[4]]),
root_cause: data[i]["__EMPTY_2"] || "",
applicantName: parseNames(data[i][cols[3]]),
executorNames: parseNames(data[i][cols[4]])
});
}
/** @param {ReportModel} report */
const checkReportAssigments = async (report) => {
const equipment = await db
.request()
.query(`select id, name from dbo.asu_system_api_subsystemlist where name like N'%${report.equipment}%';`);
if (equipment.recordset.length !== 0) foundEqupments++;
res.sendSSEJson(report, "reportParseProgress");
return equipment;
};
console.log("Total reports:", ret.reports.concat(ret.markedReports).length);
await Promise.allSettled(ret.reports.concat(ret.markedReports).map((r) => checkReportAssigments(r)));
ctx.res.sendSSEJson({ foundEqupments }, "reportParseDone");
console.log("Parse done");
} else {
throw new BadRequestError();
}
res.res.end();
};
function parseReasonCallAndJobDesc(str = "") {
const splitted = splitLongSpacedSentence(str);
if (splitted.length > 1) return splitted.slice(1).join(" ");
return str.split("\r\n").slice(1).join(" ");
}
function parseNames(str = "") {
const splitted = splitLongSpacedSentence(str);
if (splitted.length > 1) return splitted[0];
return str.split("\r\n")[0];
}
/**
* @param {string} str
* @param {number} min
*/
function splitLongSpacedSentence(str, min = 5) {
return str.split(new RegExp(`\\s{${min},}`));
}