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