mne-nuzhno-prilozhenie-kotor/server.js

191 lines
7.7 KiB
JavaScript
Raw Permalink 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.

const http = require("http");
const fs = require("fs");
const path = require("path");
const XLSX = require("xlsx");
const formidable = require("formidable");
const PORT = process.env.PORT || 3000;
function readExcelFile(filePath) {
const wb = XLSX.readFile(filePath);
const sheets = {};
wb.SheetNames.forEach(function (name) {
const data = XLSX.utils.sheet_to_json(wb.Sheets[name], { header: 1, defval: "" });
sheets[name] = data;
});
return { name: path.basename(filePath), sheets: sheets, sheetNames: wb.SheetNames };
}
function compareFiles(fileA, fileB) {
const a = readExcelFile(fileA);
const b = readExcelFile(fileB);
var report = [];
report.push("Сравнение: " + a.name + " vs " + b.name);
report.push("=".repeat(60));
report.push("");
var allSheets = Array.from(new Set(a.sheetNames.concat(b.sheetNames)));
allSheets.forEach(function (sheetName) {
var inA = a.sheetNames.indexOf(sheetName) >= 0;
var inB = b.sheetNames.indexOf(sheetName) >= 0;
if (!inA) {
report.push("Лист «" + sheetName + "»: есть ТОЛЬКО во втором файле (" + b.name + ")");
report.push(" Строк: " + (b.sheets[sheetName] ? b.sheets[sheetName].length : 0));
report.push("");
return;
}
if (!inB) {
report.push("Лист «" + sheetName + "»: есть ТОЛЬКО в первом файле (" + a.name + ")");
report.push(" Строк: " + (a.sheets[sheetName] ? a.sheets[sheetName].length : 0));
report.push("");
return;
}
var rowsA = a.sheets[sheetName];
var rowsB = b.sheets[sheetName];
var maxRows = Math.max(rowsA.length, rowsB.length);
var maxCols = 0;
rowsA.forEach(function (r) { if (r.length > maxCols) maxCols = r.length; });
rowsB.forEach(function (r) { if (r.length > maxCols) maxCols = r.length; });
var changes = [];
var added = 0, removed = 0, modified = 0;
for (var i = 0; i < maxRows; i++) {
var rowA = rowsA[i] || [];
var rowB = rowsB[i] || [];
var maxC = Math.max(rowA.length, rowB.length);
for (var j = 0; j < maxC; j++) {
var valA = String(rowA[j] != null ? rowA[j] : "").trim();
var valB = String(rowB[j] != null ? rowB[j] : "").trim();
if (valA === valB) continue;
var colLetter = String.fromCharCode(65 + (j % 26));
if (j >= 26) colLetter = String.fromCharCode(64 + Math.floor(j / 26)) + colLetter;
var cellRef = colLetter + (i + 1);
if (valA === "" && valB !== "") {
changes.push(" + " + cellRef + ": «" + valB + "»");
added++;
} else if (valA !== "" && valB === "") {
changes.push(" - " + cellRef + ": было «" + valA + "»");
removed++;
} else {
changes.push(" ~ " + cellRef + ": «" + valA + "» → «" + valB + "»");
modified++;
}
}
}
report.push("Лист «" + sheetName + "» — " + rowsA.length + "×" + rowsA[0].length + " vs " + rowsB.length + "×" + (rowsB[0] ? rowsB[0].length : 0));
if (changes.length === 0) {
report.push(" Отличий нет.");
} else {
report.push(" Изменений: " + (added + removed + modified) + " (+" + added + " / -" + removed + " / ~" + modified + ")");
report.push("");
report.push.apply(report, changes);
}
report.push("");
});
return {
fileNameA: a.name,
fileNameB: b.name,
sheetsA: a.sheetNames.length,
sheetsB: b.sheetNames.length,
report: report.join("\n")
};
}
http.createServer(function (req, res) {
if (req.method === "POST" && req.url === "/api/compare") {
var form = formidable({ uploadDir: __dirname, keepExtensions: true, maxFileSize: 100 * 1024 * 1024 });
form.parse(req, function (err, fields, files) {
if (err) {
res.writeHead(400, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: false, error: "Ошибка загрузки: " + err.message }));
}
var f1 = files.file1 && files.file1[0];
var f2 = files.file2 && files.file2[0];
if (!f1 || !f2) {
res.writeHead(400, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: false, error: "Загрузите оба файла" }));
}
try {
var result = compareFiles(f1.filepath, f2.filepath);
try { fs.unlinkSync(f1.filepath); } catch (e) {}
try { fs.unlinkSync(f2.filepath); } catch (e) {}
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: true, data: result }));
} catch (e) {
res.writeHead(500, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: false, error: "Ошибка чтения файла: " + e.message }));
}
});
return;
}
if (req.method === "POST" && req.url === "/api/analyze") {
var form2 = formidable({ uploadDir: __dirname, keepExtensions: true, maxFileSize: 100 * 1024 * 1024 });
form2.parse(req, function (err, fields, files) {
if (err) {
res.writeHead(400, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: false, error: "Ошибка загрузки: " + err.message }));
}
var f = files.file && files.file[0];
if (!f) {
res.writeHead(400, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ ok: false, error: "Загрузите файл" }));
}
try {
var wb = XLSX.readFile(f.filepath);
var analysis = [];
analysis.push("Анализ файла: " + path.basename(f.filepath));
analysis.push("=".repeat(60));
analysis.push("Листов: " + wb.SheetNames.length);
analysis.push("Имена листов: " + wb.SheetNames.join(", "));
analysis.push("");
wb.SheetNames.forEach(function (name) {
var data = XLSX.utils.sheet_to_json(wb.Sheets[name], { header: 1, defval: "" });
var rows = data.length;
var cols = 0;
data.forEach(function (r) { if (r.length > cols) cols = r.length; });
var nonEmpty = 0;
data.forEach(function (r) {
r.forEach(function (c) { if (String(c).trim() !== "") nonEmpty++; });
});
analysis.push("Лист «" + name + "»:");
analysis.push(" Размер: " + rows + " строк × " + cols + " столбцов");
analysis.push(" Заполненных ячеек: " + nonEmpty);
if (rows > 0 && cols > 0) {
analysis.push(" Заголовок (строка 1): " + data[0].map(function (c) { return String(c).trim(); }).filter(Boolean).join(" | "));
}
analysis.push("");
});
try { fs.unlinkSync(f.filepath); } catch (e) {}
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: true, data: { report: analysis.join("\n") } }));
} catch (e) {
res.writeHead(500, { "Content-Type": "application/json" });
res.end(JSON.stringify({ ok: false, error: "Ошибка чтения файла: " + e.message }));
}
});
return;
}
var file = req.url === "/" ? "/index.html" : req.url.split("?")[0];
var full = path.join(__dirname, file);
if (full.startsWith(__dirname) && fs.existsSync(full) && fs.statSync(full).isFile()) {
var ext = path.extname(full);
var type = ext === ".css" ? "text/css" : ext === ".js" ? "application/javascript" : "text/html";
res.writeHead(200, { "Content-Type": type + "; charset=utf-8" });
return res.end(fs.readFileSync(full));
}
res.writeHead(404);
res.end("Not found");
}).listen(PORT, function () {
console.log("Сервер на порту " + PORT);
});