mirror of
https://github.com/sergeyyarkov/asu_tools_service.git
synced 2026-10-11 10:29:22 +03:00
error handling
This commit is contained in:
parent
dae69f46a5
commit
7955b224b0
@ -1,6 +1,6 @@
|
|||||||
import { ctxAsyncLocalStorage } from "#root/context.js";
|
import { ctxAsyncLocalStorage } from "#root/context.js";
|
||||||
import handleExcelReportsFileParse from "./reportsFileParse.handler.js";
|
import handleExcelReportsFileParse from "./reports/parseExcel.handler.js";
|
||||||
import handleReportsSyncParsed from "./reportsSyncParsed.handler.js";
|
import handleReportsSyncParsed from "./reports/syncParsed.handler.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {HTTPRouteMap}
|
* @type {HTTPRouteMap}
|
||||||
@ -24,17 +24,27 @@ export async function routeHandler(url) {
|
|||||||
const ctx = ctxAsyncLocalStorage.getStore();
|
const ctx = ctxAsyncLocalStorage.getStore();
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
|
||||||
|
try {
|
||||||
if (url.pathname in ROUTE_MAP) {
|
if (url.pathname in ROUTE_MAP) {
|
||||||
if (req.headers["content-type"] === "application/json") {
|
|
||||||
ctx.data = await getJsonData();
|
|
||||||
}
|
|
||||||
|
|
||||||
const route = ROUTE_MAP[url.pathname];
|
const route = ROUTE_MAP[url.pathname];
|
||||||
if (route.method === req.method) route.handle(ctx);
|
if (req.headers["content-type"] === "application/json") ctx.data = await getJsonData();
|
||||||
|
if (route.method === req.method) await route.handle(ctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.sendText("Указанный URL не имеет обработчика.", 200);
|
res.sendText("Указанный URL не имеет обработчика.", 200);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
res.sendJson(
|
||||||
|
{
|
||||||
|
error: {
|
||||||
|
message: error?.message || "Internal Server Error",
|
||||||
|
stack: error?.stack || null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
error?.cause?.statusCode || 500,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getJsonData() {
|
function getJsonData() {
|
||||||
@ -49,4 +59,4 @@ function getJsonData() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export * from "./reportsFileParse.handler.js";
|
export * from "./reports/parseExcel.handler.js";
|
||||||
|
|||||||
115
router/reports/parseExcel.handler.js
Normal file
115
router/reports/parseExcel.handler.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import path from "node:path";
|
||||||
|
import xlsx from "xlsx";
|
||||||
|
import formidable from "formidable";
|
||||||
|
import db from "#root/db.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Читает Excel файл отчетов и возвращает его в формате JSON
|
||||||
|
*
|
||||||
|
* @type {HTTPRouteHandler}
|
||||||
|
*/
|
||||||
|
export default async ({ req, res }) => {
|
||||||
|
const sheetName = "Отчеты";
|
||||||
|
|
||||||
|
/** @type {{ markedReports: ReportModel[], reports: ReportModel[] }} */
|
||||||
|
const ret = { reports: [], markedReports: [] };
|
||||||
|
|
||||||
|
/** @type {xlsx.ParsingOptions} */
|
||||||
|
const xlsxParseOptions = {
|
||||||
|
sheets: sheetName,
|
||||||
|
cellHTML: false,
|
||||||
|
cellFormula: false,
|
||||||
|
cellDates: true,
|
||||||
|
dateNF: "yyyy-mm-dd",
|
||||||
|
};
|
||||||
|
|
||||||
|
const form = formidable({
|
||||||
|
maxFields: 1,
|
||||||
|
maxFiles: 1,
|
||||||
|
filename: (_, ext) => `gpp-reports${ext}`,
|
||||||
|
keepExtensions: true,
|
||||||
|
uploadDir: path.join(process.cwd(), "./uploads"),
|
||||||
|
filter: ({ mimetype }) => mimetype && mimetype.includes("application/vnd.ms-excel"),
|
||||||
|
});
|
||||||
|
|
||||||
|
const [, files] = await form.parse(req);
|
||||||
|
const excelFilePath = files?.report?.at(0)?.filepath;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parseReasonCallAndJobDesc = (str = "") => {
|
||||||
|
const splitted = splitLongSpacedSentence(str);
|
||||||
|
if (splitted.length > 1) return splitted.slice(1).join(" ");
|
||||||
|
return str.split("\r\n").slice(1).join(" ");
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseNames = (str = "") => {
|
||||||
|
const splitted = splitLongSpacedSentence(str);
|
||||||
|
if (splitted.length > 1) return splitted[0];
|
||||||
|
return str.split("\r\n")[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Остальные отчеты */
|
||||||
|
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]]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Bad request", { cause: { statusCode: 400 } });
|
||||||
|
}
|
||||||
|
|
||||||
|
res.sendJson({ data: ret });
|
||||||
|
};
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * @param {string} filepath
|
||||||
|
// */
|
||||||
|
// function reportsExcelFileToJson(filepath) {
|
||||||
|
// try {
|
||||||
|
|
||||||
|
// } catch (error) {
|
||||||
|
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} str
|
||||||
|
* @param {number} min
|
||||||
|
*/
|
||||||
|
function splitLongSpacedSentence(str, min = 5) {
|
||||||
|
return str.split(new RegExp(`\\s{${min},}`));
|
||||||
|
}
|
||||||
@ -1,112 +0,0 @@
|
|||||||
import path from "node:path";
|
|
||||||
import xlsx from "xlsx";
|
|
||||||
import formidable from "formidable";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Читает Excel файл отчетов и возвращает его в формате JSON
|
|
||||||
*
|
|
||||||
* @type {HTTPRouteHandler}
|
|
||||||
*/
|
|
||||||
export default async ({ req, res }) => {
|
|
||||||
const sheetName = "Отчеты";
|
|
||||||
|
|
||||||
/** @type {{ markedReports: ReportModel[], reports: ReportModel[] }} */
|
|
||||||
const ret = { reports: [], markedReports: [] };
|
|
||||||
|
|
||||||
/** @type {xlsx.ParsingOptions} */
|
|
||||||
const xlsxParseOptions = {
|
|
||||||
sheets: sheetName,
|
|
||||||
cellHTML: false,
|
|
||||||
cellFormula: false,
|
|
||||||
cellDates: true,
|
|
||||||
dateNF: "yyyy-mm-dd",
|
|
||||||
};
|
|
||||||
|
|
||||||
const form = formidable({
|
|
||||||
maxFields: 1,
|
|
||||||
maxFiles: 1,
|
|
||||||
filename: (_, ext) => `gpp-reports${ext}`,
|
|
||||||
keepExtensions: true,
|
|
||||||
uploadDir: path.join(process.cwd(), "./uploads"),
|
|
||||||
filter: ({ mimetype }) => mimetype && mimetype.includes("application/vnd.ms-excel"),
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
const [, files] = await form.parse(req);
|
|
||||||
const excelFilePath = files?.report?.at(0)?.filepath;
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const parseReasonCallAndJobDesc = (str = "") => {
|
|
||||||
const splitted = splitLongSpacedSentence(str);
|
|
||||||
if (splitted.length > 1) return splitted.slice(1).join(" ");
|
|
||||||
return str.split("\r\n").slice(1).join(" ");
|
|
||||||
};
|
|
||||||
|
|
||||||
const parseNames = (str = "") => {
|
|
||||||
const splitted = splitLongSpacedSentence(str);
|
|
||||||
if (splitted.length > 1) return splitted[0];
|
|
||||||
return str.split("\r\n")[0];
|
|
||||||
};
|
|
||||||
|
|
||||||
/** Остальные отчеты */
|
|
||||||
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]]),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw new Error("Bad request", { cause: { statusCode: 400 } });
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
res.sendJson(
|
|
||||||
{ error: error?.stack || error?.message || "Server error" },
|
|
||||||
error?.cause?.statusCode || 500,
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.sendJson({ data: ret });
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} str
|
|
||||||
* @param {number} min
|
|
||||||
*/
|
|
||||||
function splitLongSpacedSentence(str, min = 5) {
|
|
||||||
return str.split(new RegExp(`\\s{${min},}`));
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user