Report test; Map printing test
This commit is contained in:
BIN
client/public/template.docx
Normal file
BIN
client/public/template.docx
Normal file
Binary file not shown.
BIN
client/public/template_table.docx
Normal file
BIN
client/public/template_table.docx
Normal file
Binary file not shown.
BIN
client/public/test.png
Normal file
BIN
client/public/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 MiB |
@ -14,13 +14,13 @@ import { addInteractions, handleImageDrop, loadFeatures, processFigure, processL
|
|||||||
import useSWR, { SWRConfiguration } from 'swr'
|
import useSWR, { SWRConfiguration } from 'swr'
|
||||||
import { fetcher } from '../../http/axiosInstance'
|
import { fetcher } from '../../http/axiosInstance'
|
||||||
import { BASE_URL } from '../../constants'
|
import { BASE_URL } from '../../constants'
|
||||||
import { ActionIcon, Autocomplete, CloseButton, Flex, Select as MantineSelect, MantineStyleProp, rem, useMantineColorScheme, Portal, Menu, Button, Group, Divider, LoadingOverlay, Stack, Container } from '@mantine/core'
|
import { ActionIcon, Autocomplete, CloseButton, Flex, Select as MantineSelect, MantineStyleProp, rem, useMantineColorScheme, Portal, Menu, Button, Group, Divider, LoadingOverlay, Stack, Container, Modal, Transition } from '@mantine/core'
|
||||||
import { IconBoxMultiple, IconBoxPadding, IconChevronDown, IconPlus, IconSearch, IconUpload } from '@tabler/icons-react'
|
import { IconBoxMultiple, IconBoxPadding, IconChevronDown, IconPlus, IconSearch, IconUpload } from '@tabler/icons-react'
|
||||||
import { ICitySettings, IFigure, ILine } from '../../interfaces/gis'
|
import { ICitySettings, IFigure, ILine } from '../../interfaces/gis'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import MapToolbar from './MapToolbar/MapToolbar'
|
import MapToolbar from './MapToolbar/MapToolbar'
|
||||||
import MapStatusbar from './MapStatusbar/MapStatusbar'
|
import MapStatusbar from './MapStatusbar/MapStatusbar'
|
||||||
import { setAlignMode, setSatMapsProvider, setTypeRoles, useMapStore, setMapLabel } from '../../store/map'
|
import { setAlignMode, setSatMapsProvider, setTypeRoles, useMapStore, setMapLabel, clearPrintArea } from '../../store/map'
|
||||||
import { useThrottle } from '@uidotdev/usehooks'
|
import { useThrottle } from '@uidotdev/usehooks'
|
||||||
import ObjectTree from '../Tree/ObjectTree'
|
import ObjectTree from '../Tree/ObjectTree'
|
||||||
import { setCurrentObjectId, setSelectedDistrict, setSelectedRegion, setSelectedYear, useObjectsStore } from '../../store/objects'
|
import { setCurrentObjectId, setSelectedDistrict, setSelectedRegion, setSelectedYear, useObjectsStore } from '../../store/objects'
|
||||||
@ -73,6 +73,7 @@ const MapComponent = ({
|
|||||||
nodeLayerSource, drawingLayerSource,
|
nodeLayerSource, drawingLayerSource,
|
||||||
satLayer, staticMapLayer, figuresLayer, linesLayer,
|
satLayer, staticMapLayer, figuresLayer, linesLayer,
|
||||||
regionsLayer, districtBoundLayer, baseLayer,
|
regionsLayer, districtBoundLayer, baseLayer,
|
||||||
|
printArea, printSource, printAreaDraw
|
||||||
} = useMapStore().id[id]
|
} = useMapStore().id[id]
|
||||||
|
|
||||||
// Tab settings
|
// Tab settings
|
||||||
@ -383,6 +384,17 @@ const MapComponent = ({
|
|||||||
// }
|
// }
|
||||||
// }, [searchParams, figuresData, linesData])
|
// }, [searchParams, figuresData, linesData])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedDistrict === null) {
|
||||||
|
setSelectedYear(id, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedRegion === null) {
|
||||||
|
setSelectedYear(id, null)
|
||||||
|
setSelectedDistrict(id, null)
|
||||||
|
}
|
||||||
|
}, [selectedDistrict, selectedRegion, id])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const districtBoundSource = districtBoundLayer.getSource()
|
const districtBoundSource = districtBoundLayer.getSource()
|
||||||
|
|
||||||
@ -505,8 +517,42 @@ const MapComponent = ({
|
|||||||
}
|
}
|
||||||
}, [colorScheme])
|
}, [colorScheme])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (map) {
|
||||||
|
if (mode === 'print') {
|
||||||
|
map.addInteraction(printAreaDraw)
|
||||||
|
} else {
|
||||||
|
map.removeInteraction(printAreaDraw)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [mode, map, printAreaDraw])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (printArea) {
|
||||||
|
map?.setTarget('print-portal')
|
||||||
|
// map?.setView(new View({
|
||||||
|
// extent: printArea
|
||||||
|
// }))
|
||||||
|
printSource.clear()
|
||||||
|
map?.getView().setCenter(getCenter(printArea))
|
||||||
|
map?.getView().fit(printArea, {
|
||||||
|
size: [640, 320]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [printArea, map])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Modal keepMounted size='auto' opened={!!printArea} onClose={() => {
|
||||||
|
clearPrintArea(id)
|
||||||
|
map?.setTarget(mapElement.current as HTMLDivElement)
|
||||||
|
}} title="Предпросмотр области">
|
||||||
|
<div id='print-portal' style={{ width: '640px', height: '320px' }}>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
|
||||||
{active &&
|
{active &&
|
||||||
<Portal target='#header-portal'>
|
<Portal target='#header-portal'>
|
||||||
<Flex gap={'sm'} direction={'row'}>
|
<Flex gap={'sm'} direction={'row'}>
|
||||||
@ -636,12 +682,25 @@ const MapComponent = ({
|
|||||||
<TabsPane defaultTab='parameters' tabs={paramsPane} />
|
<TabsPane defaultTab='parameters' tabs={paramsPane} />
|
||||||
</Flex>
|
</Flex>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<Transition
|
||||||
|
mounted={!!selectedRegion && !!selectedDistrict && !!selectedYear}
|
||||||
|
transition="slide-right"
|
||||||
|
duration={200}
|
||||||
|
timingFunction="ease"
|
||||||
|
>
|
||||||
|
{(styles) => <Flex direction='column' h={'100%'} w={'100%'} style={{ ...mapControlsStyle, ...styles }}>
|
||||||
|
<TabsPane defaultTab='objects' tabs={objectsPane} />
|
||||||
|
<Divider />
|
||||||
|
<TabsPane defaultTab='parameters' tabs={paramsPane} />
|
||||||
|
</Flex>}
|
||||||
|
</Transition>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack w='100%' align='center'>
|
<Stack w='100%' align='center'>
|
||||||
<Flex style={mapControlsStyle} w='fit-content'>
|
<Stack style={mapControlsStyle} w='fit-content'>
|
||||||
<MapMode map_id={id} />
|
<MapMode map_id={id} />
|
||||||
</Flex>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Stack w='100%' maw='340px' align='flex-end' justify='space-between'>
|
<Stack w='100%' maw='340px' align='flex-end' justify='space-between'>
|
||||||
@ -649,9 +708,14 @@ const MapComponent = ({
|
|||||||
<MapToolbar map_id={id} />
|
<MapToolbar map_id={id} />
|
||||||
}
|
}
|
||||||
|
|
||||||
{selectedRegion && selectedDistrict && selectedYear &&
|
<Transition
|
||||||
<MapLegend selectedDistrict={selectedDistrict} selectedYear={selectedYear} />
|
mounted={!!selectedRegion && !!selectedDistrict && !!selectedYear}
|
||||||
}
|
transition="slide-left"
|
||||||
|
duration={200}
|
||||||
|
timingFunction="ease"
|
||||||
|
>
|
||||||
|
{(styles) => <MapLegend style={styles} selectedDistrict={selectedDistrict} selectedYear={selectedYear} />}
|
||||||
|
</Transition>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
import { Accordion, ColorSwatch, Flex, ScrollAreaAutosize, Stack, Text, useMantineColorScheme } from '@mantine/core'
|
import { Accordion, ColorSwatch, Flex, MantineStyleProp, ScrollAreaAutosize, Stack, Text, useMantineColorScheme } from '@mantine/core'
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import { fetcher } from '../../../http/axiosInstance';
|
import { fetcher } from '../../../http/axiosInstance';
|
||||||
import { BASE_URL } from '../../../constants';
|
import { BASE_URL } from '../../../constants';
|
||||||
|
|
||||||
const MapLegend = ({
|
const MapLegend = ({
|
||||||
selectedDistrict,
|
selectedDistrict,
|
||||||
selectedYear
|
selectedYear,
|
||||||
|
style
|
||||||
}: {
|
}: {
|
||||||
selectedDistrict: number | null,
|
selectedDistrict: number | null,
|
||||||
selectedYear: number | null
|
selectedYear: number | null,
|
||||||
|
style: MantineStyleProp
|
||||||
}) => {
|
}) => {
|
||||||
const { colorScheme } = useMantineColorScheme();
|
const { colorScheme } = useMantineColorScheme();
|
||||||
|
|
||||||
@ -29,7 +31,7 @@ const MapLegend = ({
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollAreaAutosize offsetScrollbars maw='300px' w='100%' fz='xs' mt='auto' style={{ zIndex: 1, backdropFilter: 'blur(8px)', backgroundColor: colorScheme === 'light' ? '#FFFFFFAA' : '#000000AA', borderRadius: '4px' }}>
|
<ScrollAreaAutosize offsetScrollbars maw='300px' w='100%' fz='xs' mt='auto' style={{...style, zIndex: 1, backdropFilter: 'blur(8px)', backgroundColor: colorScheme === 'light' ? '#FFFFFFAA' : '#000000AA', borderRadius: '4px' }}>
|
||||||
<Stack gap='sm' p='sm'>
|
<Stack gap='sm' p='sm'>
|
||||||
<Text fz='xs'>
|
<Text fz='xs'>
|
||||||
Легенда
|
Легенда
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Center, SegmentedControl } from '@mantine/core'
|
import { Center, SegmentedControl } from '@mantine/core'
|
||||||
import { getMode, Mode, setMode } from '../../store/map'
|
import { getMode, Mode, setMode } from '../../store/map'
|
||||||
import { IconEdit, IconEye } from '@tabler/icons-react'
|
import { IconEdit, IconEye, IconPrinter } from '@tabler/icons-react'
|
||||||
|
|
||||||
const MapMode = ({
|
const MapMode = ({
|
||||||
map_id
|
map_id
|
||||||
@ -25,6 +25,15 @@ const MapMode = ({
|
|||||||
</Center>
|
</Center>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: 'print',
|
||||||
|
label: (
|
||||||
|
<Center style={{ gap: 10 }}>
|
||||||
|
<IconPrinter size={16} />
|
||||||
|
<span>Печать</span>
|
||||||
|
</Center>
|
||||||
|
),
|
||||||
|
},
|
||||||
]} />
|
]} />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import { fromCircle, fromExtent } from "ol/geom/Polygon";
|
|||||||
import { measureStyleFunction, modifyStyle } from "./Measure/MeasureStyles";
|
import { measureStyleFunction, modifyStyle } from "./Measure/MeasureStyles";
|
||||||
import { getCurrentTool, getDraw, getDrawingLayerSource, getImageLayer, getMap, getMeasureClearPrevious, getMeasureDraw, getMeasureModify, getMeasureSource, getMeasureType, getOverlayLayerSource, getSnap, getTipPoint, getTranslate, setDraw, setFile, setMeasureDraw, setPolygonExtent, setRectCoords, setSnap, setTranslate } from "../../store/map";
|
import { getCurrentTool, getDraw, getDrawingLayerSource, getImageLayer, getMap, getMeasureClearPrevious, getMeasureDraw, getMeasureModify, getMeasureSource, getMeasureType, getOverlayLayerSource, getSnap, getTipPoint, getTranslate, setDraw, setFile, setMeasureDraw, setPolygonExtent, setRectCoords, setSnap, setTranslate } from "../../store/map";
|
||||||
import Collection from "ol/Collection";
|
import Collection from "ol/Collection";
|
||||||
|
import { GeometryFunction, SketchCoordType } from "ol/interaction/Draw";
|
||||||
|
|
||||||
const calculateAngle = (coords: [number, number][]) => {
|
const calculateAngle = (coords: [number, number][]) => {
|
||||||
const [start, end] = coords;
|
const [start, end] = coords;
|
||||||
@ -341,9 +342,47 @@ export const updateImageSource = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const fixedAspectRatioBox: GeometryFunction = (
|
||||||
|
coordinates: SketchCoordType,
|
||||||
|
geometry: SimpleGeometry | undefined,
|
||||||
|
): SimpleGeometry => {
|
||||||
|
// Ensure coordinates is an array of at least two points
|
||||||
|
if (!Array.isArray(coordinates) || coordinates.length < 2) {
|
||||||
|
return geometry ?? new Polygon([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [start, end] = coordinates as Coordinate[]; // Ensure it's a Coordinate array
|
||||||
|
const minX = start[0];
|
||||||
|
const minY = start[1];
|
||||||
|
const maxX = end[0];
|
||||||
|
let maxY = end[1];
|
||||||
|
|
||||||
|
const width = maxX - minX;
|
||||||
|
const height = width / 2; // Enforce 2:1 aspect ratio
|
||||||
|
maxY = minY + height;
|
||||||
|
|
||||||
|
// Define the rectangle's coordinates
|
||||||
|
const boxCoords: Coordinate[][] = [[
|
||||||
|
[minX, minY],
|
||||||
|
[maxX, minY],
|
||||||
|
[maxX, maxY],
|
||||||
|
[minX, maxY],
|
||||||
|
[minX, minY], // Close the polygon
|
||||||
|
]];
|
||||||
|
|
||||||
|
if (geometry) {
|
||||||
|
geometry.setCoordinates(boxCoords);
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
return new Polygon(boxCoords);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const addInteractions = (
|
export const addInteractions = (
|
||||||
map_id: string
|
map_id: string
|
||||||
) => {
|
) => {
|
||||||
|
console.log("Adding interactions")
|
||||||
const currentTool = getCurrentTool(map_id)
|
const currentTool = getCurrentTool(map_id)
|
||||||
const clearPrevious = getMeasureClearPrevious(map_id)
|
const clearPrevious = getMeasureClearPrevious(map_id)
|
||||||
const measureType = getMeasureType(map_id)
|
const measureType = getMeasureType(map_id)
|
||||||
|
@ -152,10 +152,10 @@ const pages = [
|
|||||||
component: <PrintReport />,
|
component: <PrintReport />,
|
||||||
drawer: true,
|
drawer: true,
|
||||||
dashboard: true,
|
dashboard: true,
|
||||||
enabled: true,
|
enabled: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "DB Manager",
|
label: "Тест БД",
|
||||||
path: "/db-manager",
|
path: "/db-manager",
|
||||||
icon: <IconComponents />,
|
icon: <IconComponents />,
|
||||||
component: <DBManager />,
|
component: <DBManager />,
|
||||||
|
@ -9,7 +9,7 @@ import { pages } from '../constants/app';
|
|||||||
|
|
||||||
function DashboardLayout() {
|
function DashboardLayout() {
|
||||||
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure()
|
const [mobileOpened, { toggle: toggleMobile }] = useDisclosure()
|
||||||
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(true)
|
const [desktopOpened, { toggle: toggleDesktop }] = useDisclosure(false)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
const getPageTitle = () => {
|
const getPageTitle = () => {
|
||||||
|
@ -17,12 +17,12 @@ function MapTest() {
|
|||||||
region: 11,
|
region: 11,
|
||||||
district: 145,
|
district: 145,
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
id: uuidv4(),
|
// id: uuidv4(),
|
||||||
year: 2023,
|
// year: 2023,
|
||||||
region: 11,
|
// region: 11,
|
||||||
district: 146,
|
// district: 146,
|
||||||
},
|
// },
|
||||||
]
|
]
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { Button, Flex } from "@mantine/core";
|
import { Button, Flex } from "@mantine/core";
|
||||||
|
import { useState } from "react";
|
||||||
|
import createReport from 'docx-templates'
|
||||||
|
|
||||||
const xslTemplate = `<?xml version="1.0" encoding="utf-8"?>
|
const xslTemplate = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
<xsl:stylesheet version="1.0" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
<xsl:stylesheet version="1.0" xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
|
||||||
@ -904,6 +906,106 @@ const xslTemplate = `<?xml version="1.0" encoding="utf-8"?>
|
|||||||
</xsl:stylesheet>`
|
</xsl:stylesheet>`
|
||||||
|
|
||||||
const PrintReport = () => {
|
const PrintReport = () => {
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const generateDocx = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Fetch the DOCX template from the public folder
|
||||||
|
const response = await fetch("/template.docx");
|
||||||
|
const response_table = await fetch("/template_table.docx");
|
||||||
|
const templateArrayBuffer = await response.arrayBuffer();
|
||||||
|
const templateArrayBuffer_table = await response_table.arrayBuffer();
|
||||||
|
|
||||||
|
// Convert ArrayBuffer to Uint8Array (Fix TypeScript error)
|
||||||
|
const templateUint8Array = new Uint8Array(templateArrayBuffer);
|
||||||
|
const templateUint8Array_table = new Uint8Array(templateArrayBuffer_table);
|
||||||
|
|
||||||
|
// Fetch the image (Example: Load from public folder)
|
||||||
|
const imageResponse = await fetch("/test.png"); // Change this to your image path
|
||||||
|
const imageBlob = await imageResponse.blob();
|
||||||
|
const imageArrayBuffer = await imageBlob.arrayBuffer();
|
||||||
|
const imageUint8Array = new Uint8Array(imageArrayBuffer);
|
||||||
|
|
||||||
|
// Generate the DOCX file with the replacement
|
||||||
|
const report = await createReport({
|
||||||
|
template: templateUint8Array, // Ensure it's Uint8Array
|
||||||
|
data: {
|
||||||
|
test: "Hello World",
|
||||||
|
myImage: {
|
||||||
|
width: 6, // Width in cm
|
||||||
|
height: 6, // Height in cm
|
||||||
|
data: imageUint8Array, // Image binary data
|
||||||
|
extension: ".png", // Specify the image format
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const report_table = await createReport({
|
||||||
|
template: templateUint8Array_table, // Ensure it's Uint8Array
|
||||||
|
data: {
|
||||||
|
test: "Hello World",
|
||||||
|
rows: [
|
||||||
|
{
|
||||||
|
first: 'A',
|
||||||
|
second: 'B',
|
||||||
|
third: 'C',
|
||||||
|
fourth: 'D',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
first: 'E',
|
||||||
|
second: 'F',
|
||||||
|
third: 'G',
|
||||||
|
fourth: 'H',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
first: 'I',
|
||||||
|
second: 'J',
|
||||||
|
third: 'K',
|
||||||
|
fourth: 'L',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert Uint8Array to a Blob
|
||||||
|
const blob = new Blob([report], {
|
||||||
|
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
});
|
||||||
|
|
||||||
|
const blob_table = new Blob([report_table], {
|
||||||
|
type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a download link and trigger the download
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement("a");
|
||||||
|
a.href = url;
|
||||||
|
a.download = "report.docx";
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
|
||||||
|
// Create a download link and trigger the download
|
||||||
|
const url_table = URL.createObjectURL(blob_table);
|
||||||
|
const a_table = document.createElement("a");
|
||||||
|
a_table.href = url_table;
|
||||||
|
a_table.download = "report_table.docx";
|
||||||
|
document.body.appendChild(a_table);
|
||||||
|
a_table.click();
|
||||||
|
document.body.removeChild(a_table);
|
||||||
|
|
||||||
|
// Revoke the object URL after download
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
URL.revokeObjectURL(url_table);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error generating DOCX:", error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleGenerateExcel = () => {
|
const handleGenerateExcel = () => {
|
||||||
// Define the example XML data
|
// Define the example XML data
|
||||||
const xmlData = `
|
const xmlData = `
|
||||||
@ -958,7 +1060,8 @@ const PrintReport = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex p='sm'>
|
<Flex p='sm' gap='sm'>
|
||||||
|
<Button onClick={generateDocx} disabled={loading}>{loading ? "Генерация отчета..." : "Сохранить в docx"}</Button>
|
||||||
<Button onClick={handleGenerateExcel}>Сохранить в Excel</Button>
|
<Button onClick={handleGenerateExcel}>Сохранить в Excel</Button>
|
||||||
</Flex>
|
</Flex>
|
||||||
)
|
)
|
||||||
|
@ -22,11 +22,11 @@ import { click, pointerMove } from 'ol/events/condition';
|
|||||||
import { measureStyleFunction, modifyStyle } from '../components/map/Measure/MeasureStyles';
|
import { measureStyleFunction, modifyStyle } from '../components/map/Measure/MeasureStyles';
|
||||||
import MapBrowserEvent from 'ol/MapBrowserEvent';
|
import MapBrowserEvent from 'ol/MapBrowserEvent';
|
||||||
import { transform } from 'ol/proj';
|
import { transform } from 'ol/proj';
|
||||||
import { applyTransformations, calculateTransformations, zoomToFeature } from '../components/map/mapUtils';
|
import { applyTransformations, calculateTransformations, fixedAspectRatioBox, zoomToFeature } from '../components/map/mapUtils';
|
||||||
import { setCurrentObjectId, setSelectedRegion } from './objects';
|
import { setCurrentObjectId, setSelectedRegion } from './objects';
|
||||||
import View from 'ol/View';
|
import View from 'ol/View';
|
||||||
|
|
||||||
export type Mode = 'edit' | 'view'
|
export type Mode = 'edit' | 'view' | 'print'
|
||||||
|
|
||||||
interface MapState {
|
interface MapState {
|
||||||
id: Record<string, {
|
id: Record<string, {
|
||||||
@ -77,6 +77,11 @@ interface MapState {
|
|||||||
overlayLayer: VectorLayer;
|
overlayLayer: VectorLayer;
|
||||||
regionSelect: Select;
|
regionSelect: Select;
|
||||||
lineSelect: Select;
|
lineSelect: Select;
|
||||||
|
printArea: Extent | null;
|
||||||
|
printLayer: VectorLayer;
|
||||||
|
printSource: VectorSource;
|
||||||
|
printAreaDraw: Draw;
|
||||||
|
printPreviewSize: number[];
|
||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,6 +211,24 @@ export const initializeMapState = (
|
|||||||
|
|
||||||
const alignModeLayer = new VectorLayer({ source: new VectorSource(), properties: { id: uuidv4(), type: 'align', name: 'Подгонка' } })
|
const alignModeLayer = new VectorLayer({ source: new VectorSource(), properties: { id: uuidv4(), type: 'align', name: 'Подгонка' } })
|
||||||
|
|
||||||
|
|
||||||
|
const printSource = new VectorSource()
|
||||||
|
const printLayer = new VectorLayer({
|
||||||
|
source: printSource
|
||||||
|
})
|
||||||
|
const printAreaDraw = new Draw({
|
||||||
|
source: printSource,
|
||||||
|
type: 'Circle',
|
||||||
|
geometryFunction: fixedAspectRatioBox
|
||||||
|
})
|
||||||
|
|
||||||
|
printAreaDraw.on('drawend', (e) => {
|
||||||
|
const extent = e.feature.getGeometry()?.getExtent()
|
||||||
|
if (extent) {
|
||||||
|
setPrintArea(id, extent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const map = new Map({
|
const map = new Map({
|
||||||
controls: [],
|
controls: [],
|
||||||
layers: [
|
layers: [
|
||||||
@ -222,7 +245,8 @@ export const initializeMapState = (
|
|||||||
overlayLayer,
|
overlayLayer,
|
||||||
nodeLayer,
|
nodeLayer,
|
||||||
measureLayer,
|
measureLayer,
|
||||||
alignModeLayer
|
alignModeLayer,
|
||||||
|
printLayer
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -364,13 +388,38 @@ export const initializeMapState = (
|
|||||||
nodeLayer: nodeLayer,
|
nodeLayer: nodeLayer,
|
||||||
overlayLayer: overlayLayer,
|
overlayLayer: overlayLayer,
|
||||||
regionSelect: regionSelect,
|
regionSelect: regionSelect,
|
||||||
lineSelect: lineSelect
|
lineSelect: lineSelect,
|
||||||
|
printArea: null,
|
||||||
|
printLayer: printLayer,
|
||||||
|
printSource: printSource,
|
||||||
|
printAreaDraw: printAreaDraw,
|
||||||
|
printPreviewSize: [640, 320]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const clearPrintArea = (id: string) => useMapStore.setState((state) => {
|
||||||
|
state.id[id].printSource.clear()
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], printArea: null }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
export const setPrintArea = (id: string, extent: Extent | null) => useMapStore.setState((state) => {
|
||||||
|
return {
|
||||||
|
id: {
|
||||||
|
...state.id,
|
||||||
|
[id]: { ...state.id[id], printArea: extent }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
export const getFiguresLayer = (id: string) => useMapStore.getState().id[id].figuresLayer
|
export const getFiguresLayer = (id: string) => useMapStore.getState().id[id].figuresLayer
|
||||||
export const getLinesLayer = (id: string) => useMapStore.getState().id[id].linesLayer
|
export const getLinesLayer = (id: string) => useMapStore.getState().id[id].linesLayer
|
||||||
export const getMeasureModify = (id: string) => useMapStore.getState().id[id].measureModify
|
export const getMeasureModify = (id: string) => useMapStore.getState().id[id].measureModify
|
||||||
|
Reference in New Issue
Block a user