FUEL: init; CustomTable update; updated interfaces/types
This commit is contained in:
@ -3,7 +3,7 @@ import { IconPlus } from '@tabler/icons-react';
|
||||
import { CreateField } from '../interfaces/create';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import FormFields from './FormFields';
|
||||
import { Badge, Button, createTableColumn, DataGrid, DataGridBody, DataGridCell, DataGridHeader, DataGridHeaderCell, DataGridRow, Dialog, DialogSurface, DialogTitle, DialogTrigger, Input, Select, TableCellLayout, TableColumnDefinition } from '@fluentui/react-components';
|
||||
import { Badge, Button, createTableColumn, DataGrid, DataGridBody, DataGridCell, DataGridHeader, DataGridHeaderCell, DataGridRow, Dialog, DialogSurface, DialogTitle, DialogTrigger, Input, Select, Spinner, TableCellLayout, TableColumnDefinition } from '@fluentui/react-components';
|
||||
import { IColumn } from '../interfaces/DataGrid/columns';
|
||||
|
||||
type CustomTableProps<T> = {
|
||||
@ -13,6 +13,7 @@ type CustomTableProps<T> = {
|
||||
submitHandler?: (data: T) => Promise<AxiosResponse>
|
||||
onEditCell?: (rowId: number, columnId: string, value: any) => any
|
||||
searchable?: boolean
|
||||
isLoading?: boolean
|
||||
}
|
||||
|
||||
const CustomTable = <T extends object>({
|
||||
@ -20,7 +21,8 @@ const CustomTable = <T extends object>({
|
||||
columns,
|
||||
createFields,
|
||||
submitHandler,
|
||||
searchable = false
|
||||
searchable = false,
|
||||
isLoading = false
|
||||
}: CustomTableProps<T>) => {
|
||||
const [data, setData] = useState<(T & { id: number })[]>(initialData);
|
||||
const [searchText, setSearchText] = useState('');
|
||||
@ -38,7 +40,7 @@ const CustomTable = <T extends object>({
|
||||
)
|
||||
}
|
||||
|
||||
const columnDefinitions: TableColumnDefinition<any>[] = columns.map(column => (
|
||||
const columnDefinitions: TableColumnDefinition<any>[] = columns.filter(column => column.hidden !== true).map(column => (
|
||||
createTableColumn<any>({
|
||||
columnId: column.name,
|
||||
renderHeaderCell: () => column.header,
|
||||
@ -170,27 +172,33 @@ const CustomTable = <T extends object>({
|
||||
}
|
||||
</div>
|
||||
|
||||
<DataGrid
|
||||
items={data}
|
||||
columns={columnDefinitions}
|
||||
resizableColumns
|
||||
focusMode="cell"
|
||||
>
|
||||
<DataGridHeader>
|
||||
<DataGridRow>
|
||||
{({ renderHeaderCell }) => (
|
||||
<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>
|
||||
)}
|
||||
</DataGridRow>
|
||||
</DataGridHeader>
|
||||
<DataGridBody>
|
||||
{({ item, rowId }) => (
|
||||
<DataGridRow key={rowId}>
|
||||
{({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
|
||||
{isLoading ?
|
||||
<Spinner />
|
||||
:
|
||||
<DataGrid
|
||||
items={data}
|
||||
columns={columnDefinitions}
|
||||
resizableColumns
|
||||
sortable
|
||||
getRowId={(item) => item.name}
|
||||
focusMode="cell"
|
||||
>
|
||||
<DataGridHeader>
|
||||
<DataGridRow>
|
||||
{({ renderHeaderCell }) => (
|
||||
<DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>
|
||||
)}
|
||||
</DataGridRow>
|
||||
)}
|
||||
</DataGridBody>
|
||||
</DataGrid>
|
||||
</DataGridHeader>
|
||||
<DataGridBody<CustomTableProps<T>>>
|
||||
{({ item, rowId }) => (
|
||||
<DataGridRow key={rowId}>
|
||||
{({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}
|
||||
</DataGridRow>
|
||||
)}
|
||||
</DataGridBody>
|
||||
</DataGrid>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -2,7 +2,6 @@ import { IconComponents, IconDeviceDesktopAnalytics, IconFlame, IconLogin, IconL
|
||||
import SignIn from "../pages/auth/SignIn";
|
||||
import SignUp from "../pages/auth/SignUp";
|
||||
import PasswordReset from "../pages/auth/PasswordReset";
|
||||
import ComponentTest from "../pages/ComponentTest";
|
||||
import MonitorPage from "../pages/MonitorPage";
|
||||
import Settings from "../pages/Settings";
|
||||
import Users from "../pages/Users";
|
||||
@ -10,13 +9,16 @@ import Roles from "../pages/Roles";
|
||||
import Documents from "../pages/Documents";
|
||||
import Reports from "../pages/Reports";
|
||||
import Servers from "../pages/Servers";
|
||||
import Boilers from "../pages/Boilers";
|
||||
import Boilers from "../pages/fuel/Fuel/Boilers";
|
||||
import MapTest from "../pages/MapTest";
|
||||
import PrintReport from "../pages/PrintReport";
|
||||
import DBManager from "../pages/DBManager";
|
||||
import MapLineTest from "../components/map/MapLineTest";
|
||||
import FuelPage from "../pages/Fuel";
|
||||
import { Building24Color, Cloud24Color, Database24Color, Document24Color, Form24Color, Map24Filled, Map24Regular, PeopleList24Color, Shield24Color } from "@fluentui/react-icons"
|
||||
import { Building24Color, Cloud24Color, Database24Color, Diversity24Color, Document24Color, Form24Color, Gauge24Color, Map24Filled, Map24Regular, PeopleList24Color, Shield24Color } from "@fluentui/react-icons"
|
||||
import LimitsPage from "../pages/fuel/Limits";
|
||||
import ReportsPage from "../pages/fuel/Reports";
|
||||
import FuelsPage from "../pages/fuel/Fuel/Fuels";
|
||||
|
||||
// Определение страниц с путями и компонентом для рендера
|
||||
|
||||
@ -115,13 +117,40 @@ const pages = [
|
||||
},
|
||||
{
|
||||
label: "Котельные",
|
||||
path: "/boilers",
|
||||
path: "/fuel/boilers",
|
||||
icon: <Building24Color />,
|
||||
component: <Boilers />,
|
||||
drawer: true,
|
||||
dashboard: true,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
label: "Виды топлива",
|
||||
path: "/fuel/fuels",
|
||||
icon: <Diversity24Color />,
|
||||
component: <FuelsPage />,
|
||||
drawer: true,
|
||||
dashboard: true,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
label: "Лимиты",
|
||||
path: "/fuel/limits",
|
||||
icon: <Gauge24Color />,
|
||||
component: <LimitsPage />,
|
||||
drawer: true,
|
||||
dashboard: true,
|
||||
enabled: true,
|
||||
},
|
||||
{
|
||||
label: "Отчеты",
|
||||
path: "/fuel/reports",
|
||||
icon: <Form24Color />,
|
||||
component: <ReportsPage />,
|
||||
drawer: true,
|
||||
dashboard: true,
|
||||
enabled: true,
|
||||
},
|
||||
// {
|
||||
// label: "ИКС",
|
||||
// path: "/map-test",
|
||||
@ -149,15 +178,6 @@ const pages = [
|
||||
dashboard: true,
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
label: "Component test",
|
||||
path: "/component-test",
|
||||
icon: <IconComponents />,
|
||||
component: <ComponentTest />,
|
||||
drawer: true,
|
||||
dashboard: true,
|
||||
enabled: false,
|
||||
},
|
||||
{
|
||||
label: "Print report test",
|
||||
path: "/print-report-test",
|
||||
|
||||
@ -14,4 +14,9 @@ export interface IBoiler {
|
||||
boiler_code: string;
|
||||
id_city: number;
|
||||
activity: boolean;
|
||||
}
|
||||
|
||||
export type FuelType = {
|
||||
id: number
|
||||
name: string
|
||||
}
|
||||
@ -24,6 +24,13 @@ export interface IObjectValue {
|
||||
date_po: string | null
|
||||
}
|
||||
|
||||
export type IObjectParamFormat =
|
||||
'bit' |
|
||||
'int' | 'smallint' | 'bigint' | 'tinyint' |
|
||||
'smalldatetime' | 'calculate' |
|
||||
'TCB' | 'GTCB' |
|
||||
'year' | 'uniqueidentifier' | 'group' | 'groupcalculate' | 'array' | string
|
||||
|
||||
export interface IObjectParam {
|
||||
id_object: string
|
||||
id_param: number
|
||||
@ -31,7 +38,7 @@ export interface IObjectParam {
|
||||
date_s: string | null
|
||||
date_po: string | null
|
||||
id_user: number
|
||||
format: string
|
||||
format: IObjectParamFormat
|
||||
vtable: string
|
||||
exact_format: string | null
|
||||
unit: string | null
|
||||
|
||||
@ -2,14 +2,13 @@ import { IconMathMax, IconPlus, IconTableMinus } from "@tabler/icons-react";
|
||||
import { FuelExpenseDtoHeaders, FuelLimitDtoHeaders } from "../dto/fuel/fuel.dto";
|
||||
import useSWR from "swr";
|
||||
import { fetcher } from "../http/axiosInstanceNest";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { SubmitHandler, useForm } from "react-hook-form";
|
||||
|
||||
import { AgGridReact } from "ag-grid-react";
|
||||
import { AllCommunityModule, ColDef, ModuleRegistry } from 'ag-grid-community'
|
||||
import { CalendarStrings, DatePicker, defaultDatePickerStrings } from "@fluentui/react-datepicker-compat"
|
||||
import { Button, Dialog, DialogSurface, DialogTitle, DialogTrigger, Field, Input, Spinner, Tab, TabList } from "@fluentui/react-components";
|
||||
import { useAppStore } from "../store/app";
|
||||
|
||||
ModuleRegistry.registerModules([AllCommunityModule])
|
||||
|
||||
@ -94,16 +93,6 @@ export default function FuelPage() {
|
||||
|
||||
const { data, isLoading } = useSWR(currentTab.get, () => fetcher(currentTab.get), { revalidateOnFocus: false })
|
||||
|
||||
const { colorScheme } = useAppStore()
|
||||
|
||||
useEffect(() => {
|
||||
if (colorScheme === 'dark') {
|
||||
document.body.dataset.agThemeMode = 'dark'
|
||||
} else {
|
||||
document.body.dataset.agThemeMode = 'light'
|
||||
}
|
||||
}, [colorScheme])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', flexDirection: 'column', width: '100%' }}>
|
||||
@ -137,7 +126,6 @@ export default function FuelPage() {
|
||||
<div style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
overflow: 'auto'
|
||||
}}>
|
||||
{tables.map((table, index) => {
|
||||
if (table.value === currentTab.value) {
|
||||
@ -147,12 +135,11 @@ export default function FuelPage() {
|
||||
<Spinner />
|
||||
</div>
|
||||
:
|
||||
<div style={{ overflow: 'auto', width: '100%', height: '100%', padding: '1rem' }}>
|
||||
<div style={{ width: 'auto', height: '100%', padding: '1rem' }}>
|
||||
<AgGridReact
|
||||
key={index}
|
||||
//rowData={data}
|
||||
// rowData={[
|
||||
// Object.keys(table.headers).reduce((obj, key) => ({ ...obj, [key]: 'test' }), {}),
|
||||
// Object.keys(table.headers).reduce((obj, key) => ({ ...obj, [key]: 'test1' }), {}),
|
||||
// Object.keys(table.headers).reduce((obj, key) => ({ ...obj, [key]: 'test' }), {})
|
||||
// ]}
|
||||
rowData={data}
|
||||
|
||||
198
client/src/pages/fuel/Fuel/Boilers.tsx
Normal file
198
client/src/pages/fuel/Fuel/Boilers.tsx
Normal file
@ -0,0 +1,198 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { Combobox, CompoundButton, Option, Text } from '@fluentui/react-components'
|
||||
import useSWR from 'swr'
|
||||
import axios from 'axios'
|
||||
import { AgGridReact, CustomCellRendererProps } from 'ag-grid-react'
|
||||
import { AllCommunityModule, ModuleRegistry } from 'ag-grid-community'
|
||||
import FuelRenderer from './FuelRenderer'
|
||||
|
||||
ModuleRegistry.registerModules([AllCommunityModule])
|
||||
|
||||
function Boilers() {
|
||||
const [, setBoilersPage] = useState(1)
|
||||
const [boilerSearch, setBoilerSearch] = useState("")
|
||||
const [, setDebouncedBoilerSearch] = useState("")
|
||||
// const { boilers } = useBoilers(10, boilersPage, debouncedBoilerSearch)
|
||||
|
||||
const { data: regions } = useSWR('/general/regions', () => axios.get('/general/regions', {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
|
||||
const [regionId, setRegionId] = useState<number | undefined>(undefined)
|
||||
|
||||
const { data: cities } = useSWR(regionId ? `/general/cities?region_id=${regionId}` : null, () => axios.get(`/general/cities?region_id=${regionId}`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
|
||||
const [cityId, setCityId] = useState<number | undefined>(undefined)
|
||||
|
||||
const { data: boilers, isLoading: boilersLoading } = useSWR(cityId !== undefined ? `/fuel/boilers?city_id=${cityId}&offset=0&limit=100` : null, () => axios.get(`/fuel/boilers?city_id=${cityId}&offset=0&limit=100`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
|
||||
useEffect(() => {
|
||||
const handler = setTimeout(() => {
|
||||
setDebouncedBoilerSearch(boilerSearch)
|
||||
}, 500)
|
||||
|
||||
return () => {
|
||||
clearTimeout(handler)
|
||||
}
|
||||
}, [boilerSearch])
|
||||
|
||||
useEffect(() => {
|
||||
setBoilersPage(1)
|
||||
setBoilerSearch("")
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: '1rem',
|
||||
width: '100%',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
{/* <Portal mountNode={document.querySelector('#header-portal')}>
|
||||
|
||||
</Portal> */}
|
||||
|
||||
<div style={{ display: 'flex', gap: '1rem' }}>
|
||||
<Combobox
|
||||
placeholder="Выберите регион"
|
||||
clearable
|
||||
onOptionSelect={(_, data) => {
|
||||
if (data.optionValue) {
|
||||
setRegionId(Number(data.optionValue))
|
||||
} else {
|
||||
setCityId(undefined)
|
||||
setRegionId(undefined)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{regions && Array.isArray(regions) && regions.map((option) => (
|
||||
<Option key={option.id} text={option.name} value={option.id}>
|
||||
{option.name}
|
||||
</Option>
|
||||
))}
|
||||
</Combobox>
|
||||
|
||||
{cities && <Combobox
|
||||
clearable
|
||||
placeholder="Выберите населенный пункт"
|
||||
onOptionSelect={(_, data) => {
|
||||
if (data.optionValue) {
|
||||
setCityId(Number(data.optionValue))
|
||||
} else {
|
||||
setCityId(undefined)
|
||||
}
|
||||
}}
|
||||
>
|
||||
{cities && Array.isArray(cities) && cities.map((option) => (
|
||||
<Option key={option.id} text={option.name} value={option.id}>
|
||||
{option.name}
|
||||
</Option>
|
||||
))}
|
||||
</Combobox>}
|
||||
</div>
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
<Text size={400} weight='medium'>
|
||||
{cityId && cities && Array.isArray(cities) && cities.find(city => city.id === cityId).name}
|
||||
</Text>
|
||||
|
||||
{cityId &&
|
||||
<div style={{ display: 'flex', width: '100%', gap: '1rem', justifyContent: 'space-between' }}>
|
||||
<BoilersCard title='Всего объектов' value={boilers && Array.isArray(boilers) ? boilers.length.toString() : ''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Общий остаток' value={''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Лимит на сезон' value={''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Требуют внимания' value={''} subtitle='' />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<AgGridReact
|
||||
// rowData={[
|
||||
// Object.keys(table.headers).reduce((obj, key) => ({ ...obj, [key]: 'test1' }), {}),
|
||||
// Object.keys(table.headers).reduce((obj, key) => ({ ...obj, [key]: 'test' }), {})
|
||||
// ]}
|
||||
key={`boilers-${cityId}`}
|
||||
loading={boilersLoading}
|
||||
overlayLoadingTemplate='Загрузка...'
|
||||
overlayNoRowsTemplate='Нет данных'
|
||||
rowData={boilers}
|
||||
columnDefs={[
|
||||
{
|
||||
field: 'boiler_name',
|
||||
headerName: 'Наименование'
|
||||
},
|
||||
{
|
||||
field: 'boiler_code',
|
||||
headerName: 'Идент. код'
|
||||
},
|
||||
{
|
||||
field: 'id_fuels',
|
||||
headerName: 'Вид топлива',
|
||||
//editable: true,
|
||||
//cellEditor: FuelTypeEditor,
|
||||
autoHeight: true,
|
||||
cellRenderer: FuelRenderer,
|
||||
cellStyle: (_) => {
|
||||
return { padding: '1px' }
|
||||
}
|
||||
//enableCellChangeFlash: true
|
||||
},
|
||||
{
|
||||
field: 'activity',
|
||||
headerName: 'Активный',
|
||||
cellRenderer: (params: CustomCellRendererProps) => (<span>{params.value === true ? 'Да' : 'Нет'}</span>)
|
||||
}
|
||||
]}
|
||||
defaultColDef={{
|
||||
flex: 1,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const BoilersCard = ({
|
||||
title,
|
||||
value,
|
||||
subtitle,
|
||||
}: {
|
||||
title: string
|
||||
value: string
|
||||
subtitle: string
|
||||
}) => {
|
||||
return (
|
||||
<CompoundButton
|
||||
onClick={() => { }}
|
||||
style={{ display: 'flex', width: '100%', justifyContent: 'flex-start', flexDirection: 'column', gap: '2rem', alignItems: 'flex-start', cursor: 'pointer', userSelect: 'none' }}
|
||||
//icon={icon}
|
||||
>
|
||||
|
||||
<Text weight='bold' size={300}>
|
||||
{title}
|
||||
</Text>
|
||||
|
||||
<Text weight='bold' size={500}>
|
||||
{value}
|
||||
</Text>
|
||||
|
||||
<Text weight='regular' size={200} style={{ color: 'gray' }}>
|
||||
{subtitle}
|
||||
</Text>
|
||||
</CompoundButton>
|
||||
)
|
||||
}
|
||||
|
||||
export default Boilers
|
||||
47
client/src/pages/fuel/Fuel/Flow.tsx
Normal file
47
client/src/pages/fuel/Fuel/Flow.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { Text } from '@fluentui/react-components'
|
||||
|
||||
const FlowPage = () => {
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: '1rem',
|
||||
width: '100%',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
{/* <Portal mountNode={document.querySelector('#header-portal')}>
|
||||
|
||||
</Portal> */}
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
<Text size={600} weight='bold'>
|
||||
Приход и расход топлива
|
||||
</Text>
|
||||
|
||||
<Text size={400} weight='medium'>
|
||||
|
||||
</Text>
|
||||
|
||||
|
||||
{/* {cityId &&
|
||||
<div style={{ display: 'flex', width: '100%', gap: '1rem', justifyContent: 'space-between' }}>
|
||||
<BoilersCard title='Всего объектов' value={boilers && Array.isArray(boilers) ? boilers.length.toString() : ''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Общий остаток' value={''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Лимит на сезон' value={''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Требуют внимания' value={''} subtitle='' />
|
||||
</div>
|
||||
} */}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FlowPage
|
||||
53
client/src/pages/fuel/Fuel/FuelRenderer.tsx
Normal file
53
client/src/pages/fuel/Fuel/FuelRenderer.tsx
Normal file
@ -0,0 +1,53 @@
|
||||
import { Button, Spinner, Table, TableBody, TableCell, TableCellActions, TableCellLayout, TableRow } from '@fluentui/react-components';
|
||||
import { Add12Regular, DeleteRegular, EditRegular } from '@fluentui/react-icons';
|
||||
import type { CustomCellRendererProps } from 'ag-grid-react';
|
||||
import axios from 'axios';
|
||||
import useSWR from 'swr';
|
||||
|
||||
export default (params: CustomCellRendererProps) => {
|
||||
const { data: fuelTypes } = useSWR('/fuel/fuel-types', () => axios.get(`/fuel/fuel-types`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
|
||||
if (fuelTypes) {
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', padding: '0.25rem', gap: '0.5rem' }}>
|
||||
{Array.isArray(params.value) && params.value.length > 0 &&
|
||||
<Table style={{ width: '100%' }} size='small'>
|
||||
<TableBody>
|
||||
{Array.isArray(params.value) && params.value.map(fuel => (
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<TableCellLayout truncate>
|
||||
{fuel.name}
|
||||
</TableCellLayout>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<TableCellLayout truncate>
|
||||
{fuelTypes && Array.isArray(fuelTypes) &&
|
||||
fuelTypes.find(ft => ft.id === fuel.id_fuels).name
|
||||
}
|
||||
</TableCellLayout>
|
||||
|
||||
<TableCellActions>
|
||||
<Button icon={<EditRegular />} appearance='subtle' />
|
||||
<Button icon={<DeleteRegular color='red' />} appearance='subtle' />
|
||||
</TableCellActions>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
}
|
||||
|
||||
<Button style={{ width: 'min-content' }} appearance='primary' icon={<Add12Regular />} size='small'>
|
||||
Добавить
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Spinner />
|
||||
)
|
||||
}
|
||||
}
|
||||
43
client/src/pages/fuel/Fuel/FuelTypeEditor.tsx
Normal file
43
client/src/pages/fuel/Fuel/FuelTypeEditor.tsx
Normal file
@ -0,0 +1,43 @@
|
||||
import { Combobox, Option, Spinner } from "@fluentui/react-components";
|
||||
import { CustomCellEditorProps } from "ag-grid-react";
|
||||
import axios from "axios";
|
||||
import useSWR from "swr";
|
||||
|
||||
export default ({ value, onValueChange }: CustomCellEditorProps) => {
|
||||
const { data: fuelTypes } = useSWR('/fuel/fuel-types', () => axios.get(`/fuel/fuel-types`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
|
||||
if (fuelTypes) {
|
||||
return (
|
||||
<Combobox
|
||||
autoFocus
|
||||
placeholder="Тип топлива"
|
||||
clearable
|
||||
value={fuelTypes.find((f: {
|
||||
id: number
|
||||
name: string
|
||||
}) => f.id === value).name}
|
||||
style={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
marginTop: '-4px'
|
||||
}}
|
||||
size='small'
|
||||
onOptionSelect={(_, data) => {
|
||||
onValueChange(data.optionValue === '' || data.optionValue === undefined ? null : data.optionValue)
|
||||
}}
|
||||
>
|
||||
{fuelTypes && Array.isArray(fuelTypes) && fuelTypes.map((option) => (
|
||||
<Option key={option.id} text={option.name} value={option.id}>
|
||||
{option.name}
|
||||
</Option>
|
||||
))}
|
||||
</Combobox>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Spinner />
|
||||
)
|
||||
}
|
||||
}
|
||||
25
client/src/pages/fuel/Fuel/FuelTypeRenderer.tsx
Normal file
25
client/src/pages/fuel/Fuel/FuelTypeRenderer.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { Spinner } from '@fluentui/react-components';
|
||||
import type { CustomCellRendererProps } from 'ag-grid-react';
|
||||
import axios from 'axios';
|
||||
import useSWR from 'swr';
|
||||
|
||||
export default (params: CustomCellRendererProps) => {
|
||||
const { data: fuelTypes } = useSWR('/fuel/fuel-types', () => axios.get(`/fuel/fuel-types`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
|
||||
if (fuelTypes) {
|
||||
return (
|
||||
<span>
|
||||
{fuelTypes.find((t: {
|
||||
id: number
|
||||
name: string
|
||||
}) => t.id === params.value).name}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Spinner />
|
||||
)
|
||||
}
|
||||
}
|
||||
34
client/src/pages/fuel/Fuel/FuelTypes.tsx
Normal file
34
client/src/pages/fuel/Fuel/FuelTypes.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
import { Text } from '@fluentui/react-components'
|
||||
|
||||
const FuelTypesPage = () => {
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: '1rem',
|
||||
width: '100%',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
{/* <Portal mountNode={document.querySelector('#header-portal')}>
|
||||
|
||||
</Portal> */}
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
<Text size={600} weight='bold'>
|
||||
Виды топлива
|
||||
</Text>
|
||||
|
||||
<Text size={400} weight='medium'>
|
||||
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default FuelTypesPage
|
||||
185
client/src/pages/fuel/Fuel/Fuels.tsx
Normal file
185
client/src/pages/fuel/Fuel/Fuels.tsx
Normal file
@ -0,0 +1,185 @@
|
||||
import { Button, Combobox, Dialog, DialogActions, DialogBody, DialogContent, DialogSurface, DialogTitle, DialogTrigger, Field, Input, Option, Tab, TabList, Text } from '@fluentui/react-components'
|
||||
import useSWR from 'swr'
|
||||
import axios from 'axios'
|
||||
import { AgGridReact } from 'ag-grid-react'
|
||||
import { Controller, SubmitHandler, useForm } from 'react-hook-form'
|
||||
import { useState } from 'react'
|
||||
import { FuelType } from '../../../interfaces/fuel'
|
||||
|
||||
type Inputs = {
|
||||
id_fuel_type: string
|
||||
name: string
|
||||
}
|
||||
|
||||
const FuelsPage = () => {
|
||||
const [selectedIdFuels, setSelectedIdFuels] = useState<number | null>(null)
|
||||
|
||||
const { data: fuelTypes } = useSWR('/fuel/fuel-types', () => axios.get(`/fuel/fuel-types`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => {
|
||||
setSelectedIdFuels(res.data[0].id)
|
||||
return res.data
|
||||
}))
|
||||
|
||||
const { data: fuels, mutate: mutateFuels, isLoading: fuelsLoading } = useSWR(selectedIdFuels ? `/fuel/fuels?id_fuels=${selectedIdFuels}` : null, () => axios.get(`/fuel/fuels?id_fuels=${selectedIdFuels}`, {
|
||||
baseURL: import.meta.env.VITE_API_NEST_URL
|
||||
}).then(res => res.data))
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
control,
|
||||
//formState: { errors, isSubmitting },
|
||||
} = useForm<Inputs>()
|
||||
|
||||
const onSubmit: SubmitHandler<Inputs> = (data) => {
|
||||
console.log(data)
|
||||
mutateFuels([...fuels, data])
|
||||
|
||||
setTimeout(() => {
|
||||
console.log("done")
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: '1rem',
|
||||
width: '100%',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
<Text size={600} weight='bold'>
|
||||
Виды топлива
|
||||
</Text>
|
||||
|
||||
<Dialog>
|
||||
<DialogTrigger>
|
||||
<Button appearance='primary' style={{ width: 'min-content' }}>
|
||||
Добавить
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
|
||||
<DialogSurface>
|
||||
{fuelTypes &&
|
||||
<form onSubmit={handleSubmit(onSubmit)} >
|
||||
<DialogBody>
|
||||
<DialogTitle>Добавление вида топлива</DialogTitle>
|
||||
|
||||
<DialogContent style={{ display: 'flex', flexDirection: 'column', gap: '0.5rem' }}>
|
||||
<Controller
|
||||
name='id_fuel_type'
|
||||
control={control}
|
||||
rules={{
|
||||
required: true
|
||||
}}
|
||||
render={({ field: { value, onChange } }) => {
|
||||
return (
|
||||
<Field label={'Тип топлива'}>
|
||||
<Combobox
|
||||
autoFocus
|
||||
placeholder="Тип топлива"
|
||||
clearable
|
||||
value={fuelTypes.find((f: {
|
||||
id: number
|
||||
name: string
|
||||
}) => f.id.toString() == value)?.name || ''}
|
||||
size='medium'
|
||||
onOptionSelect={(_, data) => {
|
||||
onChange(data.optionValue)
|
||||
//onValueChange(data.optionValue === '' || data.optionValue === undefined ? null : data.optionValue)
|
||||
}}
|
||||
>
|
||||
{fuelTypes && Array.isArray(fuelTypes) && fuelTypes.map((option) => (
|
||||
<Option key={option.id} text={option.name} value={option.id}>
|
||||
{option.name}
|
||||
</Option>
|
||||
))}
|
||||
</Combobox>
|
||||
</Field>
|
||||
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
<Field label={'Наименование'}>
|
||||
<Input {...register('name', { required: true })} />
|
||||
</Field>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions>
|
||||
<Button type='submit' appearance='primary'>
|
||||
Добавить
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</DialogBody>
|
||||
</form>
|
||||
}
|
||||
|
||||
</DialogSurface>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
{fuelTypes && Array.isArray(fuelTypes) &&
|
||||
<TabList selectedValue={selectedIdFuels} onTabSelect={(_, data) => {
|
||||
setSelectedIdFuels(Number(data.value))
|
||||
}}>
|
||||
{fuelTypes && Array.isArray(fuelTypes) && fuelTypes.map((ft: FuelType) => (
|
||||
<Tab id={ft.id.toString()} value={ft.id}>
|
||||
{ft.name}
|
||||
</Tab>
|
||||
))
|
||||
}
|
||||
</TabList>}
|
||||
|
||||
<AgGridReact
|
||||
key={`fuels`}
|
||||
loading={fuelsLoading}
|
||||
overlayLoadingTemplate='Загрузка...'
|
||||
overlayNoRowsTemplate='Нет данных'
|
||||
rowData={fuels}
|
||||
columnDefs={[
|
||||
{
|
||||
field: 'name',
|
||||
headerName: 'Наименование'
|
||||
},
|
||||
{
|
||||
field: 'tnt',
|
||||
headerName: 'Перевод в натуральный показатель'
|
||||
},
|
||||
{
|
||||
field: 'tut',
|
||||
headerName: 'Перевод в условный показатель'
|
||||
},
|
||||
{
|
||||
field: 'koef',
|
||||
headerName: 'Коэффициент'
|
||||
},
|
||||
{
|
||||
field: 'Gk',
|
||||
headerName: 'Гк'
|
||||
},
|
||||
// {
|
||||
// field: 'id_fuels',
|
||||
// headerName: 'Вид топлива',
|
||||
// editable: true,
|
||||
// cellEditor: FuelTypeEditor,
|
||||
// cellRenderer: FuelTypeRenderer,
|
||||
// enableCellChangeFlash: true
|
||||
// },
|
||||
]}
|
||||
defaultColDef={{
|
||||
flex: 1,
|
||||
}}
|
||||
/>
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
||||
export default FuelsPage
|
||||
7
client/src/pages/fuel/Limits.tsx
Normal file
7
client/src/pages/fuel/Limits.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
const LimitsPage = () => {
|
||||
return (
|
||||
<div>LimitsPage</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default LimitsPage
|
||||
69
client/src/pages/fuel/Reports.tsx
Normal file
69
client/src/pages/fuel/Reports.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import { Button, CompoundButton, Text } from '@fluentui/react-components'
|
||||
|
||||
const ReportsPage = () => {
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: '1rem',
|
||||
width: '100%',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
{/* <Portal mountNode={document.querySelector('#header-portal')}>
|
||||
|
||||
</Portal> */}
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
<Text size={600} weight='bold'>
|
||||
Отчеты
|
||||
</Text>
|
||||
|
||||
<Text size={400} weight='medium'>
|
||||
|
||||
</Text>
|
||||
|
||||
<CompoundButton
|
||||
onClick={() => { }}
|
||||
style={{ display: 'flex', width: '100%', justifyContent: 'flex-start', flexDirection: 'column', gap: '2rem', alignItems: 'flex-start', cursor: 'pointer', userSelect: 'none' }}
|
||||
//icon={icon}
|
||||
>
|
||||
|
||||
<Text weight='bold' size={300}>
|
||||
Параметры отчета
|
||||
</Text>
|
||||
|
||||
<Text weight='bold' size={500}>
|
||||
|
||||
</Text>
|
||||
|
||||
<Text weight='regular' size={200} style={{ color: 'gray' }}>
|
||||
|
||||
</Text>
|
||||
|
||||
<Button>
|
||||
|
||||
</Button>
|
||||
</CompoundButton>
|
||||
|
||||
{/* {cityId &&
|
||||
<div style={{ display: 'flex', width: '100%', gap: '1rem', justifyContent: 'space-between' }}>
|
||||
<BoilersCard title='Всего объектов' value={boilers && Array.isArray(boilers) ? boilers.length.toString() : ''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Общий остаток' value={''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Лимит на сезон' value={''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Требуют внимания' value={''} subtitle='' />
|
||||
</div>
|
||||
} */}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ReportsPage
|
||||
9
client/src/pages/fuel/Transport/Drivers.tsx
Normal file
9
client/src/pages/fuel/Transport/Drivers.tsx
Normal file
@ -0,0 +1,9 @@
|
||||
const DriversPage = () => {
|
||||
return (
|
||||
<div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default DriversPage
|
||||
7
client/src/pages/fuel/Transport/Routes.tsx
Normal file
7
client/src/pages/fuel/Transport/Routes.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
const RoutesPage = () => {
|
||||
return (
|
||||
<div>RoutesPage</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RoutesPage
|
||||
7
client/src/pages/fuel/Transport/Transport.tsx
Normal file
7
client/src/pages/fuel/Transport/Transport.tsx
Normal file
@ -0,0 +1,7 @@
|
||||
const TransportPage = () => {
|
||||
return (
|
||||
<div>TransportPage</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default TransportPage
|
||||
69
client/src/pages/fuel/Transport/Waybills.tsx
Normal file
69
client/src/pages/fuel/Transport/Waybills.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import { Button, CompoundButton, Text } from '@fluentui/react-components'
|
||||
|
||||
const WaybillsPage = () => {
|
||||
return (
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
padding: '1rem',
|
||||
width: '100%',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
{/* <Portal mountNode={document.querySelector('#header-portal')}>
|
||||
|
||||
</Portal> */}
|
||||
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
width: '100%',
|
||||
flexDirection: 'column',
|
||||
gap: '1rem'
|
||||
}}>
|
||||
<Text size={600} weight='bold'>
|
||||
Путевые листы
|
||||
</Text>
|
||||
|
||||
<Text size={400} weight='medium'>
|
||||
Управление маршрутами и учет расхода топлива
|
||||
</Text>
|
||||
|
||||
<CompoundButton
|
||||
onClick={() => { }}
|
||||
style={{ display: 'flex', width: '100%', justifyContent: 'flex-start', flexDirection: 'column', gap: '2rem', alignItems: 'flex-start', cursor: 'pointer', userSelect: 'none' }}
|
||||
//icon={icon}
|
||||
>
|
||||
|
||||
<Text weight='bold' size={300}>
|
||||
Параметры отчета
|
||||
</Text>
|
||||
|
||||
<Text weight='bold' size={500}>
|
||||
|
||||
</Text>
|
||||
|
||||
<Text weight='regular' size={200} style={{ color: 'gray' }}>
|
||||
|
||||
</Text>
|
||||
|
||||
<Button>
|
||||
|
||||
</Button>
|
||||
</CompoundButton>
|
||||
|
||||
{/* {cityId &&
|
||||
<div style={{ display: 'flex', width: '100%', gap: '1rem', justifyContent: 'space-between' }}>
|
||||
<BoilersCard title='Всего объектов' value={boilers && Array.isArray(boilers) ? boilers.length.toString() : ''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Общий остаток' value={''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Лимит на сезон' value={''} subtitle='' />
|
||||
|
||||
<BoilersCard title='Требуют внимания' value={''} subtitle='' />
|
||||
</div>
|
||||
} */}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default WaybillsPage
|
||||
Reference in New Issue
Block a user