mirror of
https://github.com/sergeyyarkov/asu_tools_service.git
synced 2026-10-11 02:19:09 +03:00
выгрузка БД в excel
This commit is contained in:
parent
44fd57ef2c
commit
de712c847b
202
handlers/asu_table/getAsuTable.handler.js
Normal file
202
handlers/asu_table/getAsuTable.handler.js
Normal file
@ -0,0 +1,202 @@
|
||||
import { equipmentRepository } from "#root/repositories/equipment.repository.js";
|
||||
import ExcelJS from "exceljs";
|
||||
|
||||
/** @import { HttpRouteHandler } from "#root/http-server/types/http-server.js" */
|
||||
|
||||
/**
|
||||
* URL: /api/asu_table_xls
|
||||
* Method: GET
|
||||
* Description: Генерирует файл Excel на основе БД АСУ промплощадки
|
||||
*
|
||||
* @type {HttpRouteHandler}
|
||||
*/
|
||||
export default async (ctx) => {
|
||||
const { res } = ctx;
|
||||
|
||||
const wb = new ExcelJS.Workbook();
|
||||
const ws = wb.addWorksheet("Перечень систем", {
|
||||
views: [{ state: "frozen", ySplit: 1, zoomScale: 70 }]
|
||||
});
|
||||
|
||||
const filename = encodeURIComponent("АСУ промплощадка.xlsx");
|
||||
const equipmentData = await equipmentRepository.getAll();
|
||||
|
||||
const excelData = [];
|
||||
|
||||
/** @type {Map<string, { row: number }} */
|
||||
const addedBaseLocationNames = new Map();
|
||||
|
||||
/** @type {{ colStart: string, colEnd: string, from: number; to: number }[]} */
|
||||
const mergeRanges = [];
|
||||
|
||||
let currentRow = 2;
|
||||
|
||||
for (const system of equipmentData) {
|
||||
const subsystems = system.subsystems || [];
|
||||
|
||||
if (subsystems.length === 0) {
|
||||
excelData.push([system.name, ...new Array(8).fill("", 0, 8)]);
|
||||
currentRow++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Заголовок для расположения систем
|
||||
if (!addedBaseLocationNames.has(system.baseLocationName)) {
|
||||
addedBaseLocationNames.set(system.baseLocationName, { row: currentRow });
|
||||
excelData.push([system.baseLocationName]);
|
||||
mergeRanges.push({ colStart: "A", colEnd: "I", from: currentRow, to: currentRow });
|
||||
currentRow++;
|
||||
}
|
||||
|
||||
const startRow = currentRow;
|
||||
|
||||
// Добавление систем подсистем в таблицу excel
|
||||
subsystems.forEach((subsystem) => {
|
||||
const hasDocLink = Boolean(subsystem?.docLink);
|
||||
const hasElectroPlan = Boolean(subsystem?.electrDiagLink);
|
||||
const plcs = subsystem?.plcs || [];
|
||||
const hmis = subsystem?.hmis || [];
|
||||
const fgs = subsystem?.fgs || [];
|
||||
const pcs = subsystem?.pcs || [];
|
||||
|
||||
excelData.push([
|
||||
system.name,
|
||||
subsystem.name,
|
||||
`${system.baseLocationName} ${subsystem.locationName}`,
|
||||
hasDocLink ? { text: "Документация", hyperlink: subsystem?.docLink } : "",
|
||||
hasElectroPlan ? { text: "Электроплан", hyperlink: subsystem?.electrDiagLink } : "",
|
||||
plcs.map((plc) => `${plc.name || ""}`).join("\n"),
|
||||
hmis.map((hmi) => `${hmi.name || ""}`).join("\n"),
|
||||
fgs.map((fg) => `${fg.name || ""}`).join("\n"),
|
||||
pcs.map((pc) => `${pc.name || ""}`).join("\n")
|
||||
]);
|
||||
|
||||
currentRow++;
|
||||
});
|
||||
|
||||
mergeRanges.push({ colStart: "A", colEnd: "A", from: startRow, to: currentRow - 1 });
|
||||
}
|
||||
|
||||
ws.getRow(1).values = [
|
||||
"Наименование системы",
|
||||
"Наименование внутренних подсистем.",
|
||||
"Расположение",
|
||||
"Документация",
|
||||
"Электроплан",
|
||||
"PLC",
|
||||
"HMI",
|
||||
"ПЧ",
|
||||
"Промышленные ПК"
|
||||
];
|
||||
|
||||
ws.autoFilter = `A1:I${excelData.length + 1}`;
|
||||
|
||||
ws.addRows(excelData);
|
||||
|
||||
mergeRanges.forEach((r) => ws.mergeCells(`${r.colStart}${r.from}:${r.colEnd}${r.to}`));
|
||||
|
||||
ws.getColumn(1).width = 50;
|
||||
ws.getColumn(2).width = 50;
|
||||
ws.getColumn(3).width = 35;
|
||||
ws.getColumn(4).width = 17;
|
||||
ws.getColumn(5).width = 17;
|
||||
ws.getColumn(6).width = 45;
|
||||
ws.getColumn(7).width = 45;
|
||||
ws.getColumn(8).width = 45;
|
||||
ws.getColumn(9).width = 30;
|
||||
ws.getRow(1).height = 45;
|
||||
|
||||
ws.eachRow((row, rowNumber) => {
|
||||
row.eachCell({ includeEmpty: true }, (cell) => {
|
||||
cell.alignment = {
|
||||
wrapText: true,
|
||||
vertical: "middle",
|
||||
horizontal: "center"
|
||||
};
|
||||
|
||||
if (rowNumber > 1) {
|
||||
cell.font = {
|
||||
name: "Calibri",
|
||||
size: 12
|
||||
};
|
||||
cell.border = {
|
||||
top: { style: "thin", color: { argb: "FF000000" } },
|
||||
left: { style: "thin", color: { argb: "FF000000" } },
|
||||
right: { style: "thin", color: { argb: "FF000000" } },
|
||||
bottom: { style: "thin", color: { argb: "FF000000" } }
|
||||
};
|
||||
cell.fill = {
|
||||
type: "pattern",
|
||||
pattern: "solid",
|
||||
fgColor: { argb: "FFF4F4F4" }
|
||||
};
|
||||
|
||||
if (cell.value === null || cell.value === undefined || cell.value === "") {
|
||||
cell.fill = {
|
||||
type: "pattern",
|
||||
pattern: "solid",
|
||||
fgColor: { argb: "FFFCE4D6" }
|
||||
};
|
||||
}
|
||||
|
||||
// Ссылки
|
||||
if (cell.value && typeof cell.value === "object" && "hyperlink" in cell.value) {
|
||||
cell.font = {
|
||||
name: "Calibri",
|
||||
size: 11,
|
||||
color: { argb: "FF0563C1" },
|
||||
underline: "single"
|
||||
};
|
||||
}
|
||||
} else {
|
||||
cell.font = {
|
||||
name: "Calibri",
|
||||
size: 11,
|
||||
color: { argb: "FFFFFFFF" }
|
||||
};
|
||||
|
||||
cell.border = {
|
||||
top: { style: "thin", color: { argb: "FF000000" } },
|
||||
right: { style: "thin", color: { argb: "FF000000" } },
|
||||
bottom: { style: "thin", color: { argb: "FF000000" } }
|
||||
};
|
||||
|
||||
cell.fill = {
|
||||
type: "pattern",
|
||||
pattern: "solid",
|
||||
fgColor: { argb: "FFF27A2B" }
|
||||
};
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
addedBaseLocationNames.forEach((baseLocationHeaderRow) => {
|
||||
const row = ws.getRow(baseLocationHeaderRow.row);
|
||||
row.height = 30;
|
||||
row.eachCell((cell) => {
|
||||
cell.font = {
|
||||
name: "Tahoma",
|
||||
bold: true,
|
||||
size: 11
|
||||
};
|
||||
cell.border = {
|
||||
top: { style: "medium", color: { argb: "FF000000" } },
|
||||
bottom: { style: "medium", color: { argb: "FF000000" } }
|
||||
};
|
||||
cell.fill = {
|
||||
type: "pattern",
|
||||
pattern: "solid",
|
||||
fgColor: { argb: "FF92D050" }
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
const excelBuffer = await wb.xlsx.writeBuffer();
|
||||
|
||||
res.res.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
res.res.setHeader("Content-Disposition", `attachment; filename=${filename}; filename*=UTF-8''${filename}`);
|
||||
res.res.setHeader("Content-Length", excelBuffer.byteLength);
|
||||
res.res.end(excelBuffer);
|
||||
|
||||
return;
|
||||
};
|
||||
3
handlers/asu_table/index.js
Normal file
3
handlers/asu_table/index.js
Normal file
@ -0,0 +1,3 @@
|
||||
import getAsuTableHandler from "./getAsuTable.handler.js";
|
||||
|
||||
export const asuTableHandlers = { getAsuTableHandler };
|
||||
@ -1 +1,2 @@
|
||||
export * from "./reports/index.js";
|
||||
export * from "./asu_table/index.js";
|
||||
|
||||
2
http-server/types/http-server.d.ts
vendored
2
http-server/types/http-server.d.ts
vendored
@ -61,5 +61,5 @@ export interface HttpResponse {
|
||||
res: http.ServerResponse;
|
||||
}
|
||||
|
||||
export type HttpRouteHandler = (ctx: HttpContext) => any;
|
||||
export type HttpRouteHandler = (ctx: HttpContext) => Promise<unknown>;
|
||||
export type HttpCreateServer = (options: HttpServerOptions) => HttpServer;
|
||||
|
||||
3
index.js
3
index.js
@ -1,7 +1,7 @@
|
||||
import path from "node:path";
|
||||
import fsp from "node:fs/promises";
|
||||
import { createServer } from "./http-server/index.js";
|
||||
import { reportsHandlers } from "#handlers/index.js";
|
||||
import { reportsHandlers, asuTableHandlers } from "#handlers/index.js";
|
||||
import packageJson from "./package.json" with { type: "json" };
|
||||
import db from "./db.js";
|
||||
|
||||
@ -40,6 +40,7 @@ server.router.prefix("/api", (router) => {
|
||||
}
|
||||
});
|
||||
router.define("POST", "/reports_sync", reportsHandlers.syncParsedHandler);
|
||||
router.define("GET", "/asu_table_xls", asuTableHandlers.getAsuTableHandler);
|
||||
});
|
||||
|
||||
server.router.define("GET", "/", ({ res }) => res.sendText("Сервис инструментов таблицы АСУ."));
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"ignoreDeprecations": "6.0",
|
||||
"checkJs": true,
|
||||
"allowJs": true,
|
||||
"lib": ["ESNext"],
|
||||
|
||||
1048
package-lock.json
generated
1048
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,11 +14,13 @@
|
||||
"license": "ISC",
|
||||
"description": "API сервис инструментов таблицы АСУ.",
|
||||
"dependencies": {
|
||||
"exceljs": "^4.4.0",
|
||||
"formidable": "^3.5.4",
|
||||
"mssql": "^12.2.0",
|
||||
"p-limit": "^7.3.0",
|
||||
"serialize-error": "^13.0.1",
|
||||
"xlsx": "^0.18.5",
|
||||
"xlsx-js-style": "^1.2.0",
|
||||
"yup": "^1.7.1"
|
||||
},
|
||||
"imports": {
|
||||
|
||||
52
repositories/equipment.repository.js
Normal file
52
repositories/equipment.repository.js
Normal file
@ -0,0 +1,52 @@
|
||||
import { UOW } from "./index.js";
|
||||
|
||||
export const equipmentRepository = {
|
||||
async getAll() {
|
||||
const request = UOW.request;
|
||||
const result = await request.query(`
|
||||
SELECT systemsTbl.id as id,
|
||||
systemsTbl.name as name,
|
||||
baseLocTbl.name as baseLocationName,
|
||||
(select subSystemsTbl.id as id,
|
||||
subSystemsTbl.name as name,
|
||||
subSystemsTbl.doc_link as docLink,
|
||||
subSystemsTbl.electr_diag_link as electrDiagLink,
|
||||
locTbl.name as locationName,
|
||||
(select plcTbl.plc_name as name
|
||||
FROM asu_system_api_plc as plcTbl
|
||||
left join asu_system_api_subsystemlist_plc as jtPLC on jtPLC.subsystemlist_id = subSystemsTbl.id
|
||||
where jtPLC.plc_id = plcTbl.id
|
||||
FOR JSON PATH) as plcs,
|
||||
|
||||
(select hmiTbl.hmi_name as name
|
||||
FROM asu_system_api_hmi as hmiTbl
|
||||
left join asu_system_api_subsystemlist_hmi as jtHMI on jtHMI.subsystemlist_id = subSystemsTbl.id
|
||||
where jtHMI.hmi_id = hmiTbl.id
|
||||
FOR JSON PATH) as hmis,
|
||||
|
||||
(select fgTbl.fg_name as name
|
||||
FROM asu_system_api_fg as fgTbl
|
||||
left join asu_system_api_subsystemlist_fg as jtFG on jtFG.subsystemlist_id = subSystemsTbl.id
|
||||
where jtFG.fg_id = fgTbl.id
|
||||
FOR JSON PATH) as fgs,
|
||||
|
||||
(select pcTbl.pc_name as name
|
||||
FROM asu_system_api_pc as pcTbl
|
||||
left join asu_system_api_subsystemlist_pc as jtPC on jtPC.subsystemlist_id = subSystemsTbl.id
|
||||
where jtPC.pc_id = pcTbl.id
|
||||
FOR JSON PATH) as pcs
|
||||
|
||||
from asu_system_api_subsystemlist as subSystemsTbl
|
||||
inner join asu_system_api_systemlist_subsystem_name as jt on subSystemsTbl.id = jt.subsystemlist_id
|
||||
left join asu_system_api_location as locTbl on locTbl.id = subSystemsTbl.location_id
|
||||
where jt.systemlist_id = systemsTbl.id
|
||||
FOR JSON PATH) as subsystems
|
||||
from asu_system_api_systemlist as systemsTbl
|
||||
inner join asu_system_api_baselocation as baseLocTbl on systemsTbl.location_id = baseLocTbl.id FOR JSON PATH
|
||||
`);
|
||||
|
||||
const jsonStringData = result.recordset.map((row) => Object.values(row)[0]).join("");
|
||||
|
||||
return JSON.parse(jsonStringData || "[]");
|
||||
}
|
||||
};
|
||||
@ -1,2 +1,3 @@
|
||||
export * from "./uow.js";
|
||||
export * from "./report.repository.js";
|
||||
export * from "./equipment.repository.js";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user