NestJS backend rewrite; migrate client to FluentUI V9

This commit is contained in:
2025-09-18 15:48:08 +09:00
parent 32ff36a12c
commit 34529cea68
62 changed files with 5642 additions and 3679 deletions

View File

@ -1,5 +1,4 @@
import { ActionIcon, Button, Checkbox, Flex, Modal, Radio, ScrollAreaAutosize, Select, Stack, Text } from '@mantine/core'
import { IconHelp, IconWindowMaximize, IconWindowMinimize } from '@tabler/icons-react'
import { IconHelp, IconWindowMaximize, IconWindowMinimize, IconX } from '@tabler/icons-react'
import React, { useEffect, useRef, useState } from 'react'
import { clearPrintArea, PrintScale, setPreviousView, setPrintScale, setPrintScaleLine, useMapStore } from '../../../store/map'
import { PrintFormat, PrintOrientation, printResolutions, setPrintOrientation, setPrintResolution, usePrintStore } from '../../../store/print'
@ -9,6 +8,7 @@ import { useObjectsStore } from '../../../store/objects'
import jsPDF from 'jspdf'
import { getCenter } from 'ol/extent'
import ScaleLine from 'ol/control/ScaleLine'
import { Button, Checkbox, Dropdown, Field, Option, Radio, RadioGroup, Text } from '@fluentui/react-components'
const MapPrint = ({
id,
@ -140,94 +140,128 @@ const MapPrint = ({
}
}, [printScaleLine, printArea])
const [opened, setOpened] = useState(false)
useEffect(() => {
if (!!printArea) {
setOpened(true)
}
}, [printArea])
useEffect(() => {
if (!opened) {
clearPrintArea(id)
map?.setTarget(mapElement.current as HTMLDivElement)
map?.addInteraction(printAreaDraw)
}
}, [opened])
return (
<Modal.Root
scrollAreaComponent={ScrollAreaAutosize}
keepMounted size='auto'
opened={!!printArea}
onClose={() => {
clearPrintArea(id)
map?.setTarget(mapElement.current as HTMLDivElement)
map?.addInteraction(printAreaDraw)
}} fullScreen={fullscreen}>
<Modal.Overlay />
<Modal.Content style={{ transition: 'all .3s ease' }}>
<Modal.Header>
<Modal.Title>
<div
style={{
display: opened ? 'flex' : 'none',
position: fullscreen ? 'fixed' : 'fixed',
zIndex: '9999',
width: '100%',
height: '100%',
inset: 0,
justifyContent: 'center',
alignItems: 'center',
}}
>
<div style={{
display: 'flex',
flexDirection: 'column',
transition: 'all .3s ease',
width: fullscreen ? '100%' : 'auto',
height: fullscreen ? '100%' : 'fit-content',
background: 'var(--colorNeutralBackground1)',
border: '1px solid var(--colorNeutralShadowKey)',
}}>
<div style={{ display: 'flex', padding: '1rem', alignItems: 'center' }}>
<Text>
Предпросмотр области печати
</Modal.Title>
</Text>
<Flex ml='auto' gap='md'>
<ActionIcon title='Помощь' ml='auto' variant='transparent'>
<IconHelp color='gray' />
</ActionIcon>
<ActionIcon title={fullscreen ? 'Свернуть' : 'Развернуть'} variant='transparent' onClick={() => setFullscreen(!fullscreen)}>
{fullscreen ? <IconWindowMinimize color='gray' /> : <IconWindowMaximize color='gray' />}
</ActionIcon>
<Modal.CloseButton title='Закрыть' />
</Flex>
</Modal.Header>
<Modal.Body>
<Stack align='center'>
<Text w='100%'>Область печати можно передвигать.</Text>
<div style={{ display: 'flex', marginLeft: 'auto', gap: '1.5rem' }}>
<Button appearance='subtle' title='Помощь' style={{ marginLeft: 'auto' }} icon={<IconHelp color='gray' />} />
<div id='print-portal' style={{
width: printOrientation === 'horizontal' ? '594px' : '420px',
height: printOrientation === 'horizontal' ? '420px' : '594px'
}}>
<Button appearance='subtle' title={fullscreen ? 'Свернуть' : 'Развернуть'} style={{ marginLeft: 'auto' }} icon={fullscreen ? <IconWindowMinimize color='gray' /> : <IconWindowMaximize color='gray' />} onClick={() => setFullscreen(!fullscreen)} />
</div>
<Button appearance='subtle' title='Закрыть' icon={<IconX />} onClick={() => setOpened(false)} />
</div>
</div>
<Flex w='100%' wrap='wrap' gap='lg' justify='space-between'>
<Radio.Group
label='Ориентация'
value={printOrientation}
onChange={(value) => setPrintOrientation(value as PrintOrientation)}
>
<Stack>
<Radio value='horizontal' label='Горизонтальная' />
<Radio value='vertical' label='Вертикальная' />
</Stack>
</Radio.Group>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', height: 'fit-content', overflow: 'auto' }}>
<Text>Область печати можно передвигать.</Text>
<Select
allowDeselect={false}
label="Разрешение"
placeholder="Выберите разрешение"
data={printResolutions}
<div id='print-portal' style={{
width: printOrientation === 'horizontal' ? '594px' : '420px',
height: printOrientation === 'horizontal' ? '420px' : '594px',
flexShrink: '0'
}}>
</div>
<div style={{ display: 'flex', width: '100%', flexWrap: 'wrap', gap: '1rem', padding: '1rem', justifyContent: 'space-between', alignItems: 'flex-start' }}>
<Field label={'Ориентация'}>
<RadioGroup value={printOrientation} onChange={(_, data) => setPrintOrientation(data.value as PrintOrientation)}>
<Radio value='horizontal' label='Горизонтальная' />
<Radio value='vertical' label='Вертикальная' />
</RadioGroup>
</Field>
<Field label="Разрешение">
<Dropdown
defaultValue={printResolution.toString()}
value={printResolution.toString()}
onChange={(value) => setPrintResolution(Number(value))}
/>
selectedOptions={[printResolution.toString()]}
onOptionSelect={(_, data) => setPrintResolution(Number(data.optionValue))}
>
{printResolutions.map((res) => (
<Option key={res} text={res} value={res}>
{res}
</Option>
))}
</Dropdown>
</Field>
<Select
allowDeselect={false}
label="Масштаб"
placeholder="Выберите масштаб"
data={scaleOptions}
value={printScale}
onChange={(value) => setPrintScale(id, value as PrintScale)}
/>
<Checkbox
checked={printScaleLine}
label="Масштабная линия"
onChange={(event) => setPrintScaleLine(id, event.currentTarget.checked)}
/>
</Flex>
<Field label="Масштаб">
<Dropdown
defaultValue={printScale.toString()}
value={printScale.toString()}
defaultSelectedOptions={[printScale]}
selectedOptions={[printScale]}
onOptionSelect={(_, data) => setPrintScale(id, data.optionValue as PrintScale)}
>
{scaleOptions.map((opt) => (
<Option key={opt.value} text={opt.label} value={opt.value}>
{opt.label}
</Option>
))}
</Dropdown>
</Field>
<Flex w='100%' gap='sm' align='center'>
<Button ml='auto' onClick={() => {
if (previousView) {
exportToPDF(printFormat, printResolution, printOrientation)
}
}}>
Печать
</Button>
</Flex>
</Stack>
</Modal.Body>
</Modal.Content>
</Modal.Root>
<Checkbox
checked={printScaleLine}
label="Масштабная линия"
onChange={(event) => setPrintScaleLine(id, event.currentTarget.checked)}
/>
</div>
<div style={{ display: 'flex', width: '100%', gap: '1rem', padding: '1rem', alignItems: 'center' }}>
<Button style={{ marginLeft: 'auto' }} onClick={() => {
if (previousView) {
exportToPDF(printFormat, printResolution, printOrientation)
}
}}>
Печать
</Button>
</div>
</div>
</div>
</div>
)
}