From fd9fddbac9794413bcefd3c7344c9949e9f54393 Mon Sep 17 00:00:00 2001 From: Mikan <72257910+Mikan-DS@users.noreply.github.com> Date: Tue, 3 Jun 2025 01:46:44 +0300 Subject: [PATCH] export CVS --- package-lock.json | 122 +++++++----------------------- package.json | 4 +- src/pages/dashboards/DataPage.tsx | 34 ++++++--- 3 files changed, 50 insertions(+), 110 deletions(-) diff --git a/package-lock.json b/package-lock.json index 95501b8..ed89522 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,12 @@ "name": "profi-frontend", "version": "0.0.0", "dependencies": { + "@types/file-saver": "^2.0.7", "file-saver": "^2.0.5", "react": "^19.1.0", "react-dom": "^19.1.0", "react-markdown": "^10.1.0", - "react-router-dom": "^7.6.0", - "xlsx": "^0.18.5" + "react-router-dom": "^7.6.0" }, "devDependencies": { "@eslint/js": "^9.25.0", @@ -1314,6 +1314,11 @@ "@types/estree": "*" } }, + "node_modules/@types/file-saver": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz", + "integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==" + }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -1341,6 +1346,17 @@ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==" }, + "node_modules/@types/node": { + "version": "22.15.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.29.tgz", + "integrity": "sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==", + "dev": true, + "optional": true, + "peer": true, + "dependencies": { + "undici-types": "~6.21.0" + } + }, "node_modules/@types/react": { "version": "19.1.4", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.4.tgz", @@ -1625,14 +1641,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/adler-32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", - "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", - "engines": { - "node": ">=0.8" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1777,18 +1785,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/cfb": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", - "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", - "dependencies": { - "adler-32": "~1.3.0", - "crc-32": "~1.2.0" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1841,14 +1837,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/codepage": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", - "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", - "engines": { - "node": ">=0.8" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1896,17 +1884,6 @@ "node": ">=18" } }, - "node_modules/crc-32": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", - "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "bin": { - "crc32": "bin/crc32.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2348,14 +2325,6 @@ "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", "dev": true }, - "node_modules/frac": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", - "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", - "engines": { - "node": ">=0.8" - } - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3800,17 +3769,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/ssf": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", - "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", - "dependencies": { - "frac": "~1.1.2" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/stringify-entities": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", @@ -3995,6 +3953,14 @@ "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "optional": true, + "peer": true + }, "node_modules/unified": { "version": "11.0.5", "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.5.tgz", @@ -4256,22 +4222,6 @@ "node": ">= 8" } }, - "node_modules/wmf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", - "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/word": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", - "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", - "engines": { - "node": ">=0.8" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -4281,26 +4231,6 @@ "node": ">=0.10.0" } }, - "node_modules/xlsx": { - "version": "0.18.5", - "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", - "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", - "dependencies": { - "adler-32": "~1.3.0", - "cfb": "~1.2.1", - "codepage": "~1.15.0", - "crc-32": "~1.2.1", - "ssf": "~0.11.2", - "wmf": "~1.0.1", - "word": "~0.3.0" - }, - "bin": { - "xlsx": "bin/xlsx.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/package.json b/package.json index 21edec5..79f3d16 100644 --- a/package.json +++ b/package.json @@ -11,12 +11,12 @@ "deploy": "python ../build_front_end.py" }, "dependencies": { + "@types/file-saver": "^2.0.7", "file-saver": "^2.0.5", "react": "^19.1.0", "react-dom": "^19.1.0", "react-markdown": "^10.1.0", - "react-router-dom": "^7.6.0", - "xlsx": "^0.18.5" + "react-router-dom": "^7.6.0" }, "devDependencies": { "@eslint/js": "^9.25.0", diff --git a/src/pages/dashboards/DataPage.tsx b/src/pages/dashboards/DataPage.tsx index 4554264..75c8c83 100644 --- a/src/pages/dashboards/DataPage.tsx +++ b/src/pages/dashboards/DataPage.tsx @@ -6,8 +6,8 @@ import {useState} from "react"; import {LoadingData} from "../../components/LoadingData.tsx"; import {useTableFilters} from "../../hooks/useTableFilters.ts"; import {Filters} from "../../components/Filters.tsx"; -import {utils, write} from "xlsx"; import { saveAs } from 'file-saver' +import * as buffer from "buffer"; export function DataPage() { const { applicationName, endpointName } = useParams<{ applicationName: string; endpointName: string }>(); @@ -26,21 +26,31 @@ export function DataPage() { } = useTableFilters(schema, dataPage.items) // Функция для экспорта данных в Excel (пока пустая) - const handleExport = () => { - if (!filteredData || filteredData.length === 0) { + const handleExport = async () => { + if (!filteredData || filteredData.length === 0 || !schema) { alert('Нет данных для экспорта') return } - // Создаем рабочий лист из данных - const worksheet = utils.json_to_sheet(filteredData) - const workbook = utils.book_new() - utils.book_append_sheet(workbook, worksheet, 'FilteredData') + const visibleFields = schema.filter(field => visibleColumns[field.name]) + const header = visibleFields.map(field => `"${field.title.replace(/"/g, '""')}"`).join(';') - // Генерируем бинарный файл - const excelBuffer = write(workbook, { bookType: 'xlsx', type: 'array' }) - const blob = new Blob([excelBuffer], { type: 'application/octet-stream' }) - saveAs(blob, 'filtered_data.xlsx') + const rows = filteredData + .map(item => { + const row = visibleFields.map(field => { + const val = item[field.name] + const strVal = val !== undefined && val !== null ? String(val) : '' + return `"${strVal.replace(/"/g, '""')}"` + + }) + return row.join(';') + }) + + const csvContent = [header, ...rows].join('\n') + // Создаем ссылку для скачивания + const blob = new Blob(["\uFEFF" + csvContent], { type: 'text/csv;charset=utf-8'}) + + saveAs(blob, "Отчёт.csv") }; // Функция для добавления новых данных (пока пустая) @@ -61,7 +71,7 @@ export function DataPage() { return (