forked from VinokurovVE/tests
Reports: city autocomplete, mutation, refresh
This commit is contained in:
@ -99,17 +99,33 @@ export function useFileType(fileName?: string | null, file?: Blob | null) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useReport(city_id?: number) {
|
export function useReport(city_id?: number | null) {
|
||||||
const { data, error, isLoading } = useSWR(
|
const { data, error, isLoading } = useSWR(
|
||||||
city_id ? `/info/reports/${city_id}?to_export=false` : null,
|
city_id ? `/info/reports/${city_id}?to_export=false` : null,
|
||||||
fetcher,
|
(url) => fetcher(url, BASE_URL.info),
|
||||||
{
|
{
|
||||||
revalidateOnFocus: false
|
revalidateOnFocus: false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
report: JSON.parse(data),
|
report: data ? JSON.parse(data) : [],
|
||||||
|
isLoading,
|
||||||
|
isError: error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useReportExport(city_id?: number | null, to_export?: boolean) {
|
||||||
|
const { data, error, isLoading } = useSWR(
|
||||||
|
city_id && to_export ? `/info/reports/${city_id}?to_export=${to_export}` : null,
|
||||||
|
(url) => fetcher(url, BASE_URL.info, 'blob'),
|
||||||
|
{
|
||||||
|
revalidateOnFocus: false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
reportExported: data ? data : null,
|
||||||
isLoading,
|
isLoading,
|
||||||
isError: error
|
isError: error
|
||||||
}
|
}
|
||||||
@ -150,7 +166,7 @@ export function useRegions(limit?: number, page?: number, search?: string | null
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCities(limit?: number, page?: number, search?: string) {
|
export function useCities(limit?: number, page?: number, search?: string | null) {
|
||||||
const { data, error, isLoading } = useSWR(
|
const { data, error, isLoading } = useSWR(
|
||||||
`/general/cities?limit=${limit || 10}&page=${page || 1}${search ? `&search=${search}` : ''}`,
|
`/general/cities?limit=${limit || 10}&page=${page || 1}${search ? `&search=${search}` : ''}`,
|
||||||
(url) => fetcher(url, BASE_URL.fuel),
|
(url) => fetcher(url, BASE_URL.fuel),
|
||||||
|
@ -1,82 +1,134 @@
|
|||||||
import { useState } from "react"
|
import { Fragment, useEffect, useState } from "react"
|
||||||
import { Box, Button } from "@mui/material"
|
import { Autocomplete, Box, Button, CircularProgress, IconButton, TextField } from "@mui/material"
|
||||||
import axiosInstance from "../http/axiosInstance"
|
import axiosInstance from "../http/axiosInstance"
|
||||||
import { DataGrid } from "@mui/x-data-grid"
|
import { DataGrid } from "@mui/x-data-grid"
|
||||||
import { BASE_URL } from "../constants"
|
import { BASE_URL } from "../constants"
|
||||||
|
import { useCities, useReport, useReportExport } from "../hooks/swrHooks"
|
||||||
|
import { useDebounce } from "@uidotdev/usehooks"
|
||||||
|
import { ICity } from "../interfaces/fuel"
|
||||||
|
import { Update } from "@mui/icons-material"
|
||||||
|
import { mutate } from "swr"
|
||||||
|
|
||||||
export default function Reports() {
|
export default function Reports() {
|
||||||
const [state, setState] = useState(null)
|
const [download, setDownload] = useState(false)
|
||||||
|
|
||||||
const fetch = async () => {
|
const [options, setOptions] = useState<ICity[]>([])
|
||||||
await axiosInstance.get(`/info/reports/0?to_export=true`, {
|
const [search, setSearch] = useState<string | null>("")
|
||||||
responseType: 'blob',
|
const debouncedSearch = useDebounce(search, 500)
|
||||||
baseURL: BASE_URL.info
|
const [selectedOption, setSelectedOption] = useState<ICity | null>(null)
|
||||||
}).then(response => {
|
const { cities, isLoading } = useCities(10, 1, debouncedSearch)
|
||||||
const url = window.URL.createObjectURL(response.data)
|
|
||||||
|
const { report, isLoading: reportLoading } = useReport(selectedOption?.id)
|
||||||
|
|
||||||
|
const { reportExported } = useReportExport(selectedOption?.id, download)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (cities) {
|
||||||
|
setOptions([...cities])
|
||||||
|
}
|
||||||
|
}, [cities])
|
||||||
|
|
||||||
|
const refreshReport = async () => {
|
||||||
|
mutate(`/info/reports/${selectedOption?.id}?to_export=false`)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedOption && reportExported && download) {
|
||||||
|
const url = window.URL.createObjectURL(reportExported)
|
||||||
const link = document.createElement('a')
|
const link = document.createElement('a')
|
||||||
link.href = url
|
link.href = url
|
||||||
link.setAttribute('download', 'report.xlsx')
|
link.setAttribute('download', 'report.xlsx')
|
||||||
document.body.appendChild(link);
|
document.body.appendChild(link);
|
||||||
link.click();
|
link.click();
|
||||||
link.remove();
|
link.remove();
|
||||||
})
|
setDownload(false)
|
||||||
}
|
}
|
||||||
|
}, [selectedOption, reportExported, download])
|
||||||
|
|
||||||
const fetchBlob = async () => {
|
const exportReport = async () => {
|
||||||
await axiosInstance.get(`/info/reports/0`).then(response => {
|
setDownload(true)
|
||||||
setState(JSON.parse(response.data))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
<Box sx={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
||||||
<Box>
|
<Box sx={{ display: 'flex', gap: '16px' }}>
|
||||||
<Button onClick={() => fetchBlob()}>
|
<Autocomplete
|
||||||
Получить отчет
|
fullWidth
|
||||||
</Button>
|
onInputChange={(_, value) => setSearch(value)}
|
||||||
|
onChange={(_, value) => setSelectedOption(value)}
|
||||||
|
isOptionEqualToValue={(option: ICity, value: ICity) => option.id === value.id}
|
||||||
|
getOptionLabel={(option: ICity) => option.name ? option.name : ""}
|
||||||
|
options={options}
|
||||||
|
loading={isLoading}
|
||||||
|
value={selectedOption}
|
||||||
|
renderInput={(params) => (
|
||||||
|
<TextField
|
||||||
|
{...params}
|
||||||
|
size='small'
|
||||||
|
label="Населенный пункт"
|
||||||
|
InputProps={{
|
||||||
|
...params.InputProps,
|
||||||
|
endAdornment: (
|
||||||
|
<Fragment>
|
||||||
|
{isLoading ? <CircularProgress color="inherit" size={20} /> : null}
|
||||||
|
{params.InputProps.endAdornment}
|
||||||
|
</Fragment>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<Button onClick={() => fetch()}>
|
<IconButton onClick={() => refreshReport()}>
|
||||||
|
<Update />
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<Button onClick={() => exportReport()}>
|
||||||
Экспорт
|
Экспорт
|
||||||
</Button>
|
</Button>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
{state &&
|
<DataGrid
|
||||||
<DataGrid
|
autoHeight
|
||||||
autoHeight
|
style={{ width: "100%" }}
|
||||||
style={{ width: "100%" }}
|
loading={reportLoading}
|
||||||
rows={[...new Set(Object.keys(state).flatMap(key => Object.keys(state[key])))].map(id => {
|
rows={
|
||||||
const row: any = { id: Number(id) };
|
report ?
|
||||||
Object.keys(state).forEach(key => {
|
[...new Set(Object.keys(report).flatMap(key => Object.keys(report[key])))].map(id => {
|
||||||
row[key] = state[key][id];
|
const row: any = { id: Number(id) };
|
||||||
});
|
Object.keys(report).forEach(key => {
|
||||||
return row;
|
row[key] = report[key][id];
|
||||||
})}
|
});
|
||||||
columns={[
|
return row;
|
||||||
{ field: 'id', headerName: '№', width: 70 },
|
})
|
||||||
...Object.keys(state).map(key => ({
|
:
|
||||||
field: key,
|
[]
|
||||||
headerName: key.charAt(0).toUpperCase() + key.slice(1),
|
}
|
||||||
width: 150
|
columns={[
|
||||||
}))
|
{ field: 'id', headerName: '№', width: 70 },
|
||||||
]}
|
...Object.keys(report).map(key => ({
|
||||||
initialState={{
|
field: key,
|
||||||
pagination: {
|
headerName: key.charAt(0).toUpperCase() + key.slice(1),
|
||||||
paginationModel: { page: 0, pageSize: 10 },
|
width: 150
|
||||||
},
|
}))
|
||||||
}}
|
]}
|
||||||
pageSizeOptions={[10, 20, 50, 100]}
|
initialState={{
|
||||||
checkboxSelection={false}
|
pagination: {
|
||||||
disableRowSelectionOnClick
|
paginationModel: { page: 0, pageSize: 10 },
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
pageSizeOptions={[10, 20, 50, 100]}
|
||||||
|
checkboxSelection={false}
|
||||||
|
disableRowSelectionOnClick
|
||||||
|
|
||||||
processRowUpdate={(updatedRow) => {
|
processRowUpdate={(updatedRow) => {
|
||||||
return updatedRow
|
return updatedRow
|
||||||
}}
|
}}
|
||||||
|
|
||||||
onProcessRowUpdateError={() => {
|
onProcessRowUpdateError={() => {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
|
||||||
</Box>
|
</Box>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user