diff --git a/web/package-lock.json b/web/package-lock.json
index 1a7ae02..2873032 100644
--- a/web/package-lock.json
+++ b/web/package-lock.json
@@ -20,7 +20,8 @@
"react-dom": "^18.2.0",
"react-router": "^6.30.0",
"react-router-dom": "^6.30.0",
- "react-toastify": "^11.0.5"
+ "react-toastify": "^11.0.5",
+ "xlsx": "^0.18.5"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
@@ -1562,6 +1563,15 @@
"@types/react": "*"
}
},
+ "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==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/agent-base": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
@@ -1687,6 +1697,19 @@
"node": ">= 6"
}
},
+ "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==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "adler-32": "~1.3.0",
+ "crc-32": "~1.2.0"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -1732,6 +1755,15 @@
"node": ">=6"
}
},
+ "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==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
@@ -1787,6 +1819,18 @@
"node": ">=10"
}
},
+ "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==",
+ "license": "Apache-2.0",
+ "bin": {
+ "crc32": "bin/crc32.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/css-selector-tokenizer": {
"version": "0.8.0",
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
@@ -2088,6 +2132,15 @@
"node": ">= 6"
}
},
+ "node_modules/frac": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
+ "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -3012,6 +3065,18 @@
"node": ">=0.10.0"
}
},
+ "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==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "frac": "~1.1.2"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
"node_modules/stackframe": {
"version": "1.3.4",
"resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz",
@@ -3284,6 +3349,45 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT"
},
+ "node_modules/wmf": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
+ "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
+ "license": "Apache-2.0",
+ "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==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/xlsx": {
+ "version": "0.18.5",
+ "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz",
+ "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
+ "license": "Apache-2.0",
+ "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/yaml": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz",
diff --git a/web/package.json b/web/package.json
index f2eee39..507cd1e 100644
--- a/web/package.json
+++ b/web/package.json
@@ -21,7 +21,8 @@
"react-dom": "^18.2.0",
"react-router": "^6.30.0",
"react-router-dom": "^6.30.0",
- "react-toastify": "^11.0.5"
+ "react-toastify": "^11.0.5",
+ "xlsx": "^0.18.5"
},
"devDependencies": {
"@biomejs/biome": "^1.9.4",
diff --git a/web/src/components/RealtimeTable/constants/FORM_1/AHR.js b/web/src/components/RealtimeTable/constants/FORM_1/AHR.js
index 210e4dd..b79a8d5 100644
--- a/web/src/components/RealtimeTable/constants/FORM_1/AHR.js
+++ b/web/src/components/RealtimeTable/constants/FORM_1/AHR.js
@@ -811,7 +811,7 @@ export const config = {
header: ' ',
accessorKey: 'data.header.name',
columnLetter: 'F',
- size: 150,
+ size: 250,
filterFn: 'contains',
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_1/AHR_P_NO_LOCAL.js b/web/src/components/RealtimeTable/constants/FORM_1/AHR_P_NO_LOCAL.js
index e17f504..3634808 100644
--- a/web/src/components/RealtimeTable/constants/FORM_1/AHR_P_NO_LOCAL.js
+++ b/web/src/components/RealtimeTable/constants/FORM_1/AHR_P_NO_LOCAL.js
@@ -799,7 +799,7 @@ export const config = {
header: '',
accessorKey: 'data.header.name',
columnLetter: 'F',
- size: 150,
+ size: 250,
filterFn: 'contains',
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_1/CAP.js b/web/src/components/RealtimeTable/constants/FORM_1/CAP.js
index 525c098..0626d06 100644
--- a/web/src/components/RealtimeTable/constants/FORM_1/CAP.js
+++ b/web/src/components/RealtimeTable/constants/FORM_1/CAP.js
@@ -819,7 +819,7 @@ export const config = {
header: '',
accessorKey: 'data.header.name',
columnLetter: 'F',
- size: 150,
+ size: 250,
filterFn: 'contains',
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_1/CAP_NO_LOCAL.js b/web/src/components/RealtimeTable/constants/FORM_1/CAP_NO_LOCAL.js
index 5a64a3b..57d3dbc 100644
--- a/web/src/components/RealtimeTable/constants/FORM_1/CAP_NO_LOCAL.js
+++ b/web/src/components/RealtimeTable/constants/FORM_1/CAP_NO_LOCAL.js
@@ -819,7 +819,7 @@ export const config = {
header: '',
accessorKey: 'data.header.name',
columnLetter: 'F',
- size: 150,
+ size: 250,
filterFn: 'contains',
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_1/OPER.js b/web/src/components/RealtimeTable/constants/FORM_1/OPER.js
index 8029453..25853fa 100644
--- a/web/src/components/RealtimeTable/constants/FORM_1/OPER.js
+++ b/web/src/components/RealtimeTable/constants/FORM_1/OPER.js
@@ -815,7 +815,7 @@ export const config = {
header: '',
accessorKey: 'data.header.name',
columnLetter: 'F',
- size: 150,
+ size: 250,
filterFn: 'contains',
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_1/SMETA.js b/web/src/components/RealtimeTable/constants/FORM_1/SMETA.js
index 6c80682..5fccbcb 100644
--- a/web/src/components/RealtimeTable/constants/FORM_1/SMETA.js
+++ b/web/src/components/RealtimeTable/constants/FORM_1/SMETA.js
@@ -207,7 +207,7 @@ export const config = {
header: '',
accessorKey: 'data.name',
columnLetter: 'C',
- size: 150,
+ size: 250,
filterFn: 'contains',
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_2/AHR.js b/web/src/components/RealtimeTable/constants/FORM_2/AHR.js
index b9a33fa..343ac01 100644
--- a/web/src/components/RealtimeTable/constants/FORM_2/AHR.js
+++ b/web/src/components/RealtimeTable/constants/FORM_2/AHR.js
@@ -720,7 +720,7 @@ export const config = {
header: "Наименование",
accessorKey: "data.header.name",
columnLetter: "D",
- size: 150,
+ size: 250,
filterFn: "contains",
},
{
diff --git a/web/src/components/RealtimeTable/constants/FORM_2/AHR_LIMIT.js b/web/src/components/RealtimeTable/constants/FORM_2/AHR_LIMIT.js
index 319db9c..4d4afd5 100644
--- a/web/src/components/RealtimeTable/constants/FORM_2/AHR_LIMIT.js
+++ b/web/src/components/RealtimeTable/constants/FORM_2/AHR_LIMIT.js
@@ -106,7 +106,7 @@ export const config = {
header: '',
accessorKey: 'data.name',
columnLetter: 'D',
- size: 150,
+ size: 250,
filterFn: 'contains',
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_2/CAP.js b/web/src/components/RealtimeTable/constants/FORM_2/CAP.js
index 776be69..0d67692 100644
--- a/web/src/components/RealtimeTable/constants/FORM_2/CAP.js
+++ b/web/src/components/RealtimeTable/constants/FORM_2/CAP.js
@@ -833,7 +833,7 @@ export const config = {
header: "",
accessorKey: "data.header.name",
columnLetter: "F",
- size: 150,
+ size: 250,
filterFn: "contains",
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_2/OPER.js b/web/src/components/RealtimeTable/constants/FORM_2/OPER.js
index 1fd41cf..3b28800 100644
--- a/web/src/components/RealtimeTable/constants/FORM_2/OPER.js
+++ b/web/src/components/RealtimeTable/constants/FORM_2/OPER.js
@@ -833,7 +833,7 @@ export const config = {
header: "",
accessorKey: "data.header.name",
columnLetter: "F",
- size: 150,
+ size: 250,
filterFn: "contains",
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_2/SMETA.js b/web/src/components/RealtimeTable/constants/FORM_2/SMETA.js
index 83e2ad5..9cb3e33 100644
--- a/web/src/components/RealtimeTable/constants/FORM_2/SMETA.js
+++ b/web/src/components/RealtimeTable/constants/FORM_2/SMETA.js
@@ -125,7 +125,7 @@ export const config = {
header: '',
accessorKey: 'data.name',
columnLetter: 'C',
- size: 150,
+ size: 250,
filterFn: 'contains',
},
],
diff --git a/web/src/components/RealtimeTable/constants/FORM_4/AHR.js b/web/src/components/RealtimeTable/constants/FORM_4/AHR.js
index 29ba442..b9aaa1f 100644
--- a/web/src/components/RealtimeTable/constants/FORM_4/AHR.js
+++ b/web/src/components/RealtimeTable/constants/FORM_4/AHR.js
@@ -797,7 +797,7 @@ export const config = {
header: '',
accessorKey: 'data.header.name',
columnLetter: 'D',
- size: 150,
+ size: 250,
filterFn: 'contains',
muiTableHeadCellProps: {
sx: {
diff --git a/web/src/components/RealtimeTable/constants/FORM_4/CAP.js b/web/src/components/RealtimeTable/constants/FORM_4/CAP.js
index 4ef9681..0bace3b 100644
--- a/web/src/components/RealtimeTable/constants/FORM_4/CAP.js
+++ b/web/src/components/RealtimeTable/constants/FORM_4/CAP.js
@@ -797,7 +797,7 @@ export const config = {
header: '',
accessorKey: 'data.header.name',
columnLetter: 'D',
- size: 150,
+ size: 250,
filterFn: 'contains',
muiTableHeadCellProps: {
sx: {
diff --git a/web/src/components/RealtimeTable/constants/FORM_4/OPER.js b/web/src/components/RealtimeTable/constants/FORM_4/OPER.js
index 548277b..c3652fa 100644
--- a/web/src/components/RealtimeTable/constants/FORM_4/OPER.js
+++ b/web/src/components/RealtimeTable/constants/FORM_4/OPER.js
@@ -797,7 +797,7 @@ export const config = {
header: '',
accessorKey: 'data.header.name',
columnLetter: 'D',
- size: 150,
+ size: 250,
filterFn: 'contains',
muiTableHeadCellProps: {
sx: {
diff --git a/web/src/components/RealtimeTable/constants/FORM_4/SMETA.js b/web/src/components/RealtimeTable/constants/FORM_4/SMETA.js
index 18c2e05..f480da2 100644
--- a/web/src/components/RealtimeTable/constants/FORM_4/SMETA.js
+++ b/web/src/components/RealtimeTable/constants/FORM_4/SMETA.js
@@ -209,7 +209,7 @@ export const config = {
header: "",
accessorKey: "data.name",
columnLetter: "C",
- size: 150,
+ size: 250,
filterFn: "contains",
muiTableHeadCellProps: {
sx: {
diff --git a/web/src/components/RealtimeTable/constants/FORM_4/STRUCTURE.js b/web/src/components/RealtimeTable/constants/FORM_4/STRUCTURE.js
index 73c3d5f..a4697bb 100644
--- a/web/src/components/RealtimeTable/constants/FORM_4/STRUCTURE.js
+++ b/web/src/components/RealtimeTable/constants/FORM_4/STRUCTURE.js
@@ -843,7 +843,7 @@ export const config = {
header: '',
accessorKey: 'data.header.name',
columnLetter: 'F',
- size: 150,
+ size: 250,
filterFn: 'contains',
muiTableHeadCellProps: {
sx: {
diff --git a/web/src/pages/Svod2Page/Svod2Page.jsx b/web/src/pages/Svod2Page/Svod2Page.jsx
index 81af2e4..626cf50 100644
--- a/web/src/pages/Svod2Page/Svod2Page.jsx
+++ b/web/src/pages/Svod2Page/Svod2Page.jsx
@@ -3,9 +3,12 @@ import { Alert, Box, Button, Paper, Tab, Tabs, Typography } from '@mui/material'
import { MaterialReactTable, useMaterialReactTable } from 'material-react-table';
import { MRT_Localization_RU } from 'material-react-table/locales/ru';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import { toast } from 'react-toastify';
import { HeaderSwitch } from '../../components/HeaderMenu/HeaderSwitch';
import { PrimaryButton } from '../../components/common/Buttons/Buttons';
+import { ExportWithTextButton } from '../../components/common/Buttons/ButtonsActions';
+import { exportSummaryTableToXlsx } from '../../utils/exportSummaryTable';
import { useSvod } from '../SvodPage/SvodContext';
import { SvodFilters } from '../SvodPage/SvodFilters';
@@ -356,6 +359,7 @@ const matchesSearch = (row, query) => {
export default function Svod2Page() {
const { getSheetFilters, updateSheetFilters, getSummary, invalidateSummary } = useSvod();
const [sheet, setSheet] = useState('GO');
+ const [exporting, setExporting] = useState(false);
const [tableStateBySheet, setTableStateBySheet] = useState(createInitialTableState);
const [columnFiltersBySheet, setColumnFiltersBySheet] = useState(() => Object.fromEntries(SHEETS.map(({ value }) => [value, []])));
const latestSummaryRequestRef = useRef(Object.fromEntries(SHEETS.map(({ value }) => [value, 0])));
@@ -529,6 +533,16 @@ export default function Svod2Page() {
noRecordsToDisplay: 'Нет данных для выбранных параметров',
},
});
+ const exportSummary = useCallback(async () => {
+ setExporting(true);
+ try {
+ await exportSummaryTableToXlsx(table, `Свод_2_${sheet}_${year}`);
+ } catch (_error) {
+ toast.error('Не удалось экспортировать свод');
+ } finally {
+ setExporting(false);
+ }
+ }, [sheet, table, year]);
let content = ;
if (!hasCurrentData && !loading && !error) {
content = (
@@ -589,15 +603,23 @@ export default function Svod2Page() {
)}
{hasCurrentData ? (
- }
- disabled={loading || selectedOrganizations.length === 0}
- onClick={refreshSummary}
- sx={{ ml: 'auto', height: '2.5rem', flexShrink: 0 }}>
- Обновить
-
+ <>
+
+ }
+ disabled={loading || selectedOrganizations.length === 0}
+ onClick={refreshSummary}
+ sx={{ height: '2.5rem', flexShrink: 0 }}>
+ Обновить
+
+ >
) : (
{
+ setExporting(true);
+ try {
+ await exportSummaryTableToXlsx(table, `Свод_1_${sheet}_${year}`);
+ } catch (_error) {
+ toast.error('Не удалось экспортировать свод');
+ } finally {
+ setExporting(false);
+ }
+ }, [sheet, table, year]);
return (
)}
+
{sheet === 'FORM_3' ? (
-