diff --git a/src/API/hooks.ts b/src/API/hooks.ts index 1ddc72b..54beb14 100644 --- a/src/API/hooks.ts +++ b/src/API/hooks.ts @@ -182,7 +182,6 @@ export function useApiDocumentation( throw new Error(`$ref not found in response schema for ${pathKey}`); } - console.log(schemaRef.match(/#\/definitions\/(\w+)/)) // Получить название определения const defNameMatch = schemaRef.match(/#\/definitions\/(\w+)/); diff --git a/src/components/FilteredTable.tsx b/src/components/FilteredTable.tsx index 60228eb..ba7f958 100644 --- a/src/components/FilteredTable.tsx +++ b/src/components/FilteredTable.tsx @@ -1,190 +1,22 @@ -import {useState, useMemo, useEffect} from 'react' import { FieldInfo } from '../types/common' +import {VisibilityState} from "../types/filters.ts"; interface FilteredTableProps { schema: FieldInfo[] - data: object[] - showFilters?: boolean + filteredData: object[] + visibleColumns: VisibilityState } /** * Компонент динамической фильтрованной таблицы. * Позволяет фильтровать данные по различным условиям, в зависимости от типа поля. */ -export function FilteredTable({ schema, data, showFilters = false }: FilteredTableProps) { - const [filters, setFilters] = useState>({}) - const [visibleColumns, setVisibleColumns] = useState>({}) - - // Изначальный массив данных для фильтрации - const initialData = useMemo(() => data, [data]) - - // Массив отфильтрованных данных - const filteredData = useMemo(() => { - return initialData.filter(item => { - return schema.every(field => { - const value = item[field.name] - const filter = filters[field.name] - if (!filter) return true - - // Обработка по типу - if (field.type === 'string') { - if (filter.searchText) { - if (typeof value !== 'string') return false - if (!value.toLowerCase().includes(filter.searchText.toLowerCase())) return false - } - if (filter.exactMatch && filter.searchText) { - return value.toLowerCase() === filter.searchText.toLowerCase() - - } - if (filter.empty !== undefined) { - const isEmpty = value === '' || value === null || value === undefined - if (filter.empty && !isEmpty) return false - if (filter.notEmpty && isEmpty) return false - } - } else if (field.type === 'date') { - const dateValue = new Date(value).getTime() - if (filter.fromDate) { - const fromTime = new Date(filter.fromDate).getTime() - if (dateValue < fromTime) return false - } - if (filter.toDate) { - const toTime = new Date(filter.toDate).getTime() - if (dateValue > toTime) return false - } - } else if (field.type === 'number') { - const numValue = Number(value) - if (filter.gte !== undefined && numValue < filter.gte) return false - if (filter.lte !== undefined && numValue > filter.lte) return false - } - return true - }) - }) - }, [initialData, filters, schema]) - - // Обработчик изменения фильтров - const handleFilterChange = (name: string, filterPart: unknown) => { - setFilters(prev => ({ - ...prev, - [name]: { - ...prev[name], - ...filterPart - } - })) - } - - // Обработчик переключения видимости колонок - const handleColumnToggle = (name: string) => { - setVisibleColumns(prev => ({ - ...prev, - [name]: !prev[name] - })) - } - - useEffect(() => { - - let newVisibleColumns:Record = {} - - for (const field of schema) { - newVisibleColumns = {...newVisibleColumns, [field.name]:true} - - } - setVisibleColumns(newVisibleColumns) - }, [schema]); - - console.log(visibleColumns) +export function FilteredTable({ schema, filteredData, visibleColumns}: FilteredTableProps) { return (
- {showFilters && ( -
- {schema.map(field => ( -
- - {field.type === 'string' && ( -
- handleFilterChange(field.name, {searchText: e.target.value})} - /> - -
- - -
-
- )} - {field.type === 'date' && ( -
- handleFilterChange(field.name, { fromDate: e.target.value })} - /> - handleFilterChange(field.name, { toDate: e.target.value })} - /> -
- )} - {field.type === 'number' && ( -
- - handleFilterChange(field.name, { gte: e.target.value !== '' ? Number(e.target.value) : undefined }) - } - /> - - handleFilterChange(field.name, { lte: e.target.value !== '' ? Number(e.target.value) : undefined }) - } - /> -
- )} -
- ))} -
- )} @@ -200,13 +32,13 @@ export function FilteredTable({ schema, data, showFilters = false }: FilteredTab {filteredData.length > 0 ? ( - filteredData.map((item, i) => ( - + filteredData.map((item) => ( + {schema.map( (field) => visibleColumns[field.name] && ( ) )} diff --git a/src/components/Filters.tsx b/src/components/Filters.tsx new file mode 100644 index 0000000..cc5ac96 --- /dev/null +++ b/src/components/Filters.tsx @@ -0,0 +1,107 @@ +import {FieldInfo} from "../types/common.ts"; +import {FiltersState, VisibilityState} from "../types/filters.ts"; + +interface FiltersProps{ + schema: FieldInfo[]; + visibleColumns: VisibilityState; + handleColumnToggle(name: string): void; + handleFilterChange(name: string, filterPart: unknown):void; + filters: FiltersState; + isShow?: boolean; +} + +export function Filters({schema, visibleColumns, handleColumnToggle, handleFilterChange, filters, isShow=false}:FiltersProps ){ + + if (!isShow){ + return null; + } + + return ( +
+ {schema.map(field => ( +
+ + {field.type === 'string' && ( +
+ handleFilterChange(field.name, {searchText: e.target.value})} + /> + +
+ + +
+
+ )} + {field.type === 'date' && ( +
+ handleFilterChange(field.name, {fromDate: e.target.value})} + /> + handleFilterChange(field.name, {toDate: e.target.value})} + /> +
+ )} + {field.type === 'number' && ( +
+ + handleFilterChange(field.name, {gte: e.target.value !== '' ? Number(e.target.value) : undefined}) + } + /> + + handleFilterChange(field.name, {lte: e.target.value !== '' ? Number(e.target.value) : undefined}) + } + /> +
+ )} +
+ ))} +
+ ); +} \ No newline at end of file diff --git a/src/hooks/useTableFilters.ts b/src/hooks/useTableFilters.ts new file mode 100644 index 0000000..29a0f0c --- /dev/null +++ b/src/hooks/useTableFilters.ts @@ -0,0 +1,104 @@ + +import { useState, useMemo, useCallback } from 'react' +import { FieldInfo } from '../types/common' +import {FiltersState, VisibilityState} from "../types/filters.ts"; + + + +/** + * Хук для управления фильтрами и видимостью колонок таблицы. + * @param schema Схема полей таблицы. + * @param initialData + * @returns Объекты состояния фильтров и видимости, а также функции для их изменения. + */ +export function useTableFilters(schema: FieldInfo[]| null, initialData: unknown[] | null) { + const [filters, setFilters] = useState({}) + const [visibleColumns, setVisibleColumns] = useState({}) + + // Инициализация видимости колонок + useMemo(() => { + if (!schema){ + return; + } + + const initialVisibility: VisibilityState = {} + schema.forEach(field => { + initialVisibility[field.name] = true + }) + setVisibleColumns(initialVisibility) + }, [schema]) + + // Обновление фильтров + const handleFilterChange = useCallback((name: string, filterPart: unknown) => { + setFilters(prev => ({ + ...prev, + [name]: { + ...prev[name], + ...filterPart + } + })) + }, []) + + // Переключатель видимости колонки + const handleColumnToggle = useCallback((name: string) => { + setVisibleColumns(prev => ({ + ...prev, + [name]: !prev[name] + })) + }, []) + + // Логика фильтрации данных, вынесенная из компонента + const filteredData = useMemo(() => { + if (!initialData || !schema){ + return ; + } + return initialData.filter(item => { + return schema.every(field => { + const value = item[field.name] + const filter = filters[field.name] + if (!filter) return true + + // Обработка по типу + if (field.type === 'string') { + if (filter.searchText) { + if (typeof value !== 'string') return false + if (!value.toLowerCase().includes(filter.searchText.toLowerCase())) return false + } + if (filter.exactMatch && filter.searchText) { + return value.toLowerCase() === filter.searchText.toLowerCase() + } + if (filter.empty !== undefined) { + const isEmpty = value === '' || value === null || value === undefined + if (filter.empty && !isEmpty) return false + if (filter.notEmpty && isEmpty) return false + } + } else if (field.format === 'date') { + const dateValue = new Date(value as string).getTime() + if (filter.fromDate) { + const fromTime = new Date(filter.fromDate).getTime() + if (dateValue < fromTime) return false + } + if (filter.toDate) { + const toTime = new Date(filter.toDate).getTime() + if (dateValue > toTime) return false + } + } else if (field.type === 'number') { + const numValue = Number(value) + if (filter.gte !== undefined && numValue < filter.gte) return false + if (filter.lte !== undefined && numValue > filter.lte) return false + } + return true + }) + }) + }, [initialData, filters, schema]) + + return { + filters, + setFilters, + visibleColumns, + setVisibleColumns, + handleFilterChange, + handleColumnToggle, + filteredData + } +} \ No newline at end of file diff --git a/src/pages/dashboards/DataPage.tsx b/src/pages/dashboards/DataPage.tsx index 0757b07..a2cfe31 100644 --- a/src/pages/dashboards/DataPage.tsx +++ b/src/pages/dashboards/DataPage.tsx @@ -4,6 +4,8 @@ import { FieldInfo } from "../../types/common.ts"; import {FilteredTable} from "../../components/FilteredTable.tsx"; import {useState} from "react"; import {LoadingData} from "../../components/LoadingData.tsx"; +import {useTableFilters} from "../../hooks/useTableFilters.ts"; +import {Filters} from "../../components/Filters.tsx"; export function DataPage() { const { applicationName, endpointName } = useParams<{ applicationName: string; endpointName: string }>(); @@ -13,7 +15,13 @@ export function DataPage() { const [filterShow, setFilterShow] = useState(false); - + const { + filters, + handleFilterChange, + visibleColumns, + handleColumnToggle, + filteredData + } = useTableFilters(schema, dataPage.items) // Функция для экспорта данных в Excel (пока пустая) const handleExport = () => { @@ -22,7 +30,7 @@ export function DataPage() { // Функция для добавления новых данных (пока пустая) const handleAdd = () => { - // Логика для добавления данных + alert("Недостаточно прав!") }; // Функция для фильтрации данных (пока пустая) @@ -43,10 +51,14 @@ export function DataPage() { + + + + diff --git a/src/types/filters.ts b/src/types/filters.ts new file mode 100644 index 0000000..f8b0976 --- /dev/null +++ b/src/types/filters.ts @@ -0,0 +1,3 @@ +export type FiltersState = Record +export type VisibilityState = Record +
- {item[field.name] || "-"} + {item[field.name] ?? "-"}