Files
universal_is/client/src/pages/fuel/Limits/LimitEditForm.tsx
2025-12-23 09:53:04 +09:00

287 lines
12 KiB
TypeScript
Raw 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.

import { Button, Dialog, DialogBody, DialogContent, DialogSurface, DialogTitle, Field, Input, ProgressBar, Spinner } from '@fluentui/react-components'
import { DataPieColor } from '@fluentui/react-icons'
import axios from 'axios'
import { useEffect, useState } from 'react'
import { Controller, SubmitHandler, useFieldArray, useForm, useWatch } from 'react-hook-form'
import useSWR from 'swr'
type Month = {
month: number
value: number
}
type Inputs = {
id_boiler: string
id_fuel: string
year: number
months: Month[]
}
const months = [
{
id: 7,
month: 'jul',
label: 'Июль'
},
{
id: 8,
month: 'aug',
label: 'Август'
},
{
id: 9,
month: 'sep',
label: 'Сентябрь'
},
{
id: 10,
month: 'nov',
label: 'Октябрь'
},
{
id: 11,
month: 'oct',
label: 'Ноябрь'
},
{
id: 12,
month: 'dec',
label: 'Декабрь'
},
{
id: 1,
month: 'jan',
label: 'Январь'
},
{
id: 2,
month: 'feb',
label: 'Февраль'
},
{
id: 3,
month: 'mar',
label: 'Март'
},
{
id: 4,
month: 'apr',
label: 'Апрель'
},
{
id: 5,
month: 'may',
label: 'Май'
},
{
id: 6,
month: 'jun',
label: 'Июнь'
},
]
const LimitAddForm = ({
cityId,
open,
setOpen,
percentage
}: {
cityId: number | undefined
open: boolean
setOpen: (open: boolean) => void
percentage?: boolean
}) => {
const {
handleSubmit,
control,
setValue,
formState: { isSubmitting },
} = useForm<Inputs>({
defaultValues: {
months: Array.from({ length: 12 }, (_, i) => ({
month: i + 1,
value: 0,
}))
}
})
const { fields } = useFieldArray({
control,
name: 'months'
})
const onSubmit: SubmitHandler<Inputs> = async (data) => {
await axios.post(`/fuel/limits`, {
id_boiler: '06407B1C-C23F-44C8-BADF-4653060EB784',
id_fuel: 3,
year: 2025,
months: data.months
}, {
baseURL: import.meta.env.VITE_API_NEST_URL,
})
//mutateFuels([...fuels, data])
// setTimeout(() => {
// console.log("done")
// }, 1000)
await new Promise((resolve) => {
setTimeout(() => resolve(console.log("done")), 1000);
})
}
const [overallLimit, setOverallLimit] = useState(0)
const watchedMonths = useWatch({
control,
name: "months",
})
const { data: citySettings } = useSWR(
cityId ? `/fuel/city-settings?city_id=${cityId}` : null,
() =>
axios
.get(`/fuel/city-settings?city_id=${cityId}`, {
baseURL: import.meta.env.VITE_API_NEST_URL,
})
.then((res) => res.data)
)
const handlePartition = () => {
if (citySettings && Array.isArray(citySettings) && citySettings.length > 0) {
citySettings.map(s => {
setValue(`months.${Number(s.month - 1)}.value`, Number((Number((overallLimit / 100).toFixed(3)) * s.procent).toFixed(3)))
})
}
}
useEffect(() => {
if (watchedMonths) {
let sum = 0
watchedMonths.map(wm => sum = sum + wm.value)
setOverallLimit(Number(sum.toFixed(3)))
}
}, [watchedMonths])
return (
<Dialog open={open} onOpenChange={(_, data) => setOpen(data.open)}>
<DialogSurface>
<DialogBody>
{isSubmitting &&
<div style={{ position: 'absolute', inset: 0, zIndex: '1', background: '#00000030', display: 'flex', justifyContent: 'center', alignItems: 'center', width: '100%', height: '100%' }}>
<Spinner />
</div>
}
<DialogTitle>Распределение лимитов</DialogTitle>
<DialogContent
style={{
display: 'flex', flexDirection: 'column', gap: '1rem',
minWidth: 'fit-content', minHeight: 'fit-content'
}}
>
<form onSubmit={(e) => {
e.preventDefault()
e.stopPropagation()
handlePartition()
}} style={{ display: 'flex', width: '100%', gap: '0.25rem', justifyContent: 'flex-end' }}>
<Field style={{ display: 'flex' }} label='Лимит расхода котельного топлива за сезон' orientation='horizontal'>
<Input type='number' value={overallLimit.toString()} onChange={(_, data) => setOverallLimit(Number(data.value))} />
</Field>
<Button title='Распределить' type='submit' icon={<DataPieColor />}></Button>
</form>
<form onSubmit={handleSubmit(onSubmit)}>
<div style={{ display: 'flex', flexDirection: 'row', gap: '1rem', width: '100%' }}>
<div style={{ display: 'flex', flexDirection: 'column', width: '50%', gap: '0.25rem' }}>
{fields.map((f, index) => {
if (f.month >= 7 && f.month <= 12) {
return (
<Controller
key={f.month}
name={`months.${index}.value`}
control={control}
render={({ field }) => (
<Field style={{ gridTemplateColumns: '1fr auto' }} key={f.month} validationMessage={percentage ? `${(field.value / (overallLimit / 100)).toFixed(1)}%` : undefined} validationState='none' label={months.find(m => m.id === f.month)?.label} orientation='horizontal'>
<Input value={field.value.toString()} onChange={(_, data) => field.onChange(Number(data.value))} />
{percentage && <ProgressBar value={field.value / (overallLimit / 100) * 0.01} />}
</Field>
)}
/>
)
}
})}
<Field style={{ gridTemplateColumns: '1fr auto' }} validationMessage={percentage ? `${(watchedMonths.filter(month => month.month >= 7 && month.month <= 12)
.reduce((sum, month) => {
const value = Number(month.value) || 0;
return sum + value;
}, 0) / (overallLimit / 100)).toFixed(1)}%` : undefined} validationState='none' label={'2 полугодие'} orientation='horizontal'>
<Input disabled value={watchedMonths.filter(month => month.month >= 7 && month.month <= 12)
.reduce((sum, month) => {
const value = Number(month.value) || 0;
return sum + value;
}, 0).toFixed(3)} />
{percentage && <ProgressBar value={watchedMonths.filter(month => month.month >= 7 && month.month <= 12)
.reduce((sum, month) => {
const value = Number(month.value) || 0;
return sum + value;
}, 0) / (overallLimit / 100) * 0.01} />}
</Field>
</div>
<div style={{ display: 'flex', flexDirection: 'column', width: '50%', gap: '0.25rem' }}>
{fields.map((f, index) => {
if (f.month >= 1 && f.month <= 6) {
return (
<Controller
key={f.month}
name={`months.${index}.value`}
control={control}
render={({ field }) => (
<Field style={{ gridTemplateColumns: '1fr auto' }} key={f.month} validationMessage={percentage ? `${(field.value / (overallLimit / 100)).toFixed(1)}%` : undefined} validationState='none' label={months.find(m => m.id === f.month)?.label} orientation='horizontal'>
<Input value={field.value.toString()} onChange={(_, data) => field.onChange(Number(data.value))} />
{percentage && <ProgressBar value={field.value / (overallLimit / 100) * 0.01} />}
</Field>
)}
/>
)
}
})}
<Field style={{ gridTemplateColumns: '1fr auto' }} validationMessage={percentage ? `${(watchedMonths.filter(month => month.month >= 1 && month.month <= 6)
.reduce((sum, month) => {
const value = Number(month.value) || 0;
return sum + value;
}, 0) / (overallLimit / 100)).toFixed(1)}%` : undefined} validationState='none' label={'1 полугодие'} orientation='horizontal'>
<Input disabled value={watchedMonths.filter(month => month.month >= 1 && month.month <= 6)
.reduce((sum, month) => {
const value = Number(month.value) || 0;
return sum + value;
}, 0).toFixed(3)} />
{percentage && <ProgressBar value={watchedMonths.filter(month => month.month >= 1 && month.month <= 6)
.reduce((sum, month) => {
const value = Number(month.value) || 0;
return sum + value;
}, 0) / (overallLimit / 100) * 0.01} />}
</Field>
</div>
</div>
<div style={{ display: 'flex', marginTop: '1rem', justifyContent: 'flex-end' }}>
<Button type='submit' appearance='primary'>
Добавить
</Button>
</div>
</form>
</DialogContent>
</DialogBody>
</DialogSurface>
</Dialog>
)
}
export default LimitAddForm