feat: Добавлена сортировка пациентов по фамилии
This commit is contained in:
parent
342e021211
commit
05bfec81fc
@ -1,6 +1,6 @@
|
||||
from typing import Sequence, Optional
|
||||
from typing import Sequence, Optional, Tuple, Literal
|
||||
|
||||
from sqlalchemy import select, desc
|
||||
from sqlalchemy import select, desc, or_, func
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.domain.models import Lens
|
||||
@ -10,10 +10,80 @@ class LensesRepository:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.db = db
|
||||
|
||||
async def get_all(self) -> Sequence[Lens]:
|
||||
stmt = select(Lens).order_by(Lens.id)
|
||||
async def get_all(
|
||||
self,
|
||||
skip: int = 0,
|
||||
limit: int = 10,
|
||||
search: str = None,
|
||||
sort_order: Literal["asc", "desc"] = "desc",
|
||||
tor: float = None,
|
||||
diameter: float = None,
|
||||
preset_refraction: float = None,
|
||||
periphery_toricity: float = None,
|
||||
side: str = "all",
|
||||
issued: bool = None,
|
||||
trial: float = None,
|
||||
) -> Tuple[Sequence[Lens], int]:
|
||||
stmt = select(Lens)
|
||||
count_stmt = select(func.count()).select_from(Lens)
|
||||
|
||||
if search:
|
||||
search = f"%{search}%"
|
||||
stmt = stmt.filter(
|
||||
or_(
|
||||
Lens.tor.cast(str).ilike(search),
|
||||
Lens.diameter.cast(str).ilike(search),
|
||||
Lens.preset_refraction.cast(str).ilike(search),
|
||||
Lens.periphery_toricity.cast(str).ilike(search),
|
||||
Lens.side.ilike(search),
|
||||
Lens.fvc.cast(str).ilike(search),
|
||||
Lens.trial.cast(str).ilike(search),
|
||||
)
|
||||
)
|
||||
count_stmt = count_stmt.filter(
|
||||
or_(
|
||||
Lens.tor.cast(str).ilike(search),
|
||||
Lens.diameter.cast(str).ilike(search),
|
||||
Lens.preset_refraction.cast(str).ilike(search),
|
||||
Lens.periphery_toricity.cast(str).ilike(search),
|
||||
Lens.side.ilike(search),
|
||||
Lens.fvc.cast(str).ilike(search),
|
||||
Lens.trial.cast(str).ilike(search),
|
||||
)
|
||||
)
|
||||
|
||||
if tor is not None:
|
||||
stmt = stmt.filter(Lens.tor == tor)
|
||||
count_stmt = count_stmt.filter(Lens.tor == tor)
|
||||
if diameter is not None:
|
||||
stmt = stmt.filter(Lens.diameter == diameter)
|
||||
count_stmt = count_stmt.filter(Lens.diameter == diameter)
|
||||
if preset_refraction is not None:
|
||||
stmt = stmt.filter(Lens.preset_refraction == preset_refraction)
|
||||
count_stmt = count_stmt.filter(Lens.preset_refraction == preset_refraction)
|
||||
if periphery_toricity is not None:
|
||||
stmt = stmt.filter(Lens.periphery_toricity == periphery_toricity)
|
||||
count_stmt = count_stmt.filter(Lens.periphery_toricity == periphery_toricity)
|
||||
if side != "all":
|
||||
stmt = stmt.filter(Lens.side == side)
|
||||
count_stmt = count_stmt.filter(Lens.side == side)
|
||||
if issued is not None:
|
||||
stmt = stmt.filter(Lens.issued == issued)
|
||||
count_stmt = count_stmt.filter(Lens.issued == issued)
|
||||
if trial is not None:
|
||||
stmt = stmt.filter(Lens.trial == trial)
|
||||
count_stmt = count_stmt.filter(Lens.trial == trial)
|
||||
|
||||
stmt = stmt.order_by(Lens.id.desc() if sort_order == "desc" else Lens.id.asc())
|
||||
|
||||
stmt = stmt.offset(skip).limit(limit)
|
||||
result = await self.db.execute(stmt)
|
||||
return result.scalars().all()
|
||||
lenses = result.scalars().all()
|
||||
|
||||
count_result = await self.db.execute(count_stmt)
|
||||
total_count = count_result.scalar()
|
||||
|
||||
return lenses, total_count
|
||||
|
||||
async def get_all_not_issued(self) -> Sequence[Lens]:
|
||||
stmt = select(Lens).filter_by(issued=False).order_by(desc(Lens.id))
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from typing import Literal
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.database.session import get_db
|
||||
from app.domain.entities.lens import LensEntity
|
||||
from app.domain.entities.responses.paginated_lens import PaginatedLensesResponseEntity
|
||||
from app.infrastructure.dependencies import get_current_user
|
||||
from app.infrastructure.lenses_service import LensesService
|
||||
|
||||
@ -11,16 +14,40 @@ router = APIRouter()
|
||||
|
||||
@router.get(
|
||||
"/",
|
||||
response_model=list[LensEntity],
|
||||
summary="Get all lenses",
|
||||
description="Returns a list of all lenses",
|
||||
response_model=PaginatedLensesResponseEntity,
|
||||
summary="Get all lenses with pagination and filtering",
|
||||
description="Returns a paginated list of lenses with optional search, sorting, and advanced filtering",
|
||||
)
|
||||
async def get_all_lenses(
|
||||
db: AsyncSession = Depends(get_db),
|
||||
user=Depends(get_current_user),
|
||||
page: int = Query(1, ge=1, description="Page number"),
|
||||
page_size: int = Query(10, ge=1, le=100, description="Number of lenses per page"),
|
||||
search: str = Query(None, description="Search term for filtering lenses"),
|
||||
sort_order: Literal["asc", "desc"] = Query("desc", description="Sort order by id (asc or desc)"),
|
||||
tor: float = Query(None, description="Filter by tor"),
|
||||
diameter: float = Query(None, description="Filter by diameter"),
|
||||
preset_refraction: float = Query(None, description="Filter by preset refraction"),
|
||||
periphery_toricity: float = Query(None, description="Filter by periphery toricity"),
|
||||
side: Literal["левая", "правая", "all"] = Query("all", description="Filter by side"),
|
||||
issued: bool = Query(None, description="Filter by issued status"),
|
||||
trial: float = Query(None, description="Filter by trial"),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
lenses_service = LensesService(db)
|
||||
return await lenses_service.get_all_lenses()
|
||||
lenses, total_count = await lenses_service.get_all_lenses(
|
||||
page=page,
|
||||
page_size=page_size,
|
||||
search=search,
|
||||
sort_order=sort_order,
|
||||
tor=tor,
|
||||
diameter=diameter,
|
||||
preset_refraction=preset_refraction,
|
||||
periphery_toricity=periphery_toricity,
|
||||
side=side,
|
||||
issued=issued,
|
||||
trial=trial,
|
||||
)
|
||||
return {"lenses": lenses, "total_count": total_count}
|
||||
|
||||
|
||||
@router.get(
|
||||
|
||||
8
api/app/domain/entities/responses/paginated_lens.py
Normal file
8
api/app/domain/entities/responses/paginated_lens.py
Normal file
@ -0,0 +1,8 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.domain.entities.lens import LensEntity
|
||||
|
||||
|
||||
class PaginatedLensesResponseEntity(BaseModel):
|
||||
lenses: list[LensEntity]
|
||||
total_count: int
|
||||
@ -1,4 +1,4 @@
|
||||
from typing import Optional
|
||||
from typing import Optional, Tuple, Literal
|
||||
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@ -16,13 +16,35 @@ class LensesService:
|
||||
self.lenses_repository = LensesRepository(db)
|
||||
self.lens_types_repository = LensTypesRepository(db)
|
||||
|
||||
async def get_all_lenses(self) -> list[LensEntity]:
|
||||
lenses = await self.lenses_repository.get_all()
|
||||
|
||||
return [
|
||||
self.model_to_entity(lens)
|
||||
for lens in lenses
|
||||
]
|
||||
async def get_all_lenses(
|
||||
self,
|
||||
page: int = 1,
|
||||
page_size: int = 10,
|
||||
search: str = None,
|
||||
sort_order: Literal["asc", "desc"] = "desc",
|
||||
tor: float = None,
|
||||
diameter: float = None,
|
||||
preset_refraction: float = None,
|
||||
periphery_toricity: float = None,
|
||||
side: str = "all",
|
||||
issued: bool = None,
|
||||
trial: float = None,
|
||||
) -> Tuple[list[LensEntity], int]:
|
||||
skip = (page - 1) * page_size
|
||||
lenses, total_count = await self.lenses_repository.get_all(
|
||||
skip=skip,
|
||||
limit=page_size,
|
||||
search=search,
|
||||
sort_order=sort_order,
|
||||
tor=tor,
|
||||
diameter=diameter,
|
||||
preset_refraction=preset_refraction,
|
||||
periphery_toricity=periphery_toricity,
|
||||
side=side,
|
||||
issued=issued,
|
||||
trial=trial,
|
||||
)
|
||||
return [self.model_to_entity(lens) for lens in lenses], total_count
|
||||
|
||||
async def get_all_not_issued_lenses(self) -> list[LensEntity]:
|
||||
lenses = await self.lenses_repository.get_all_not_issued()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { Component } from "react";
|
||||
import {Result} from "antd";
|
||||
import {Alert, Result} from "antd";
|
||||
|
||||
class ErrorBoundary extends Component {
|
||||
state = { hasError: false };
|
||||
@ -14,7 +14,12 @@ class ErrorBoundary extends Component {
|
||||
|
||||
render() {
|
||||
if (this.state.hasError) {
|
||||
return <Result status="500" title="500" subTitle="Something went wrong."/>;
|
||||
return (
|
||||
<>
|
||||
<Result status="500" title="500" subTitle="Произошла ошибка в работе приложения."/>
|
||||
</>
|
||||
|
||||
);
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
|
||||
@ -12,7 +12,8 @@ import {
|
||||
Grid,
|
||||
Table,
|
||||
Popconfirm,
|
||||
Typography, Result
|
||||
Typography,
|
||||
Result
|
||||
} from "antd";
|
||||
import {
|
||||
PlusOutlined,
|
||||
@ -27,28 +28,25 @@ import LensFormModal from "./Components/LensFormModal/LensFormModal.jsx";
|
||||
import SelectViewMode from "../../../../Widgets/SelectViewMode/SelectViewMode.jsx";
|
||||
import LoadingIndicator from "../../../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
|
||||
import useLenses from "./useLenses.js";
|
||||
import useLensesUI from "./useLensesUI.js";
|
||||
|
||||
const {Option} = Select;
|
||||
const {useBreakpoint} = Grid;
|
||||
const {Title} = Typography;
|
||||
const { Option } = Select;
|
||||
const { useBreakpoint } = Grid;
|
||||
const { Title } = Typography;
|
||||
|
||||
const LensesTab = () => {
|
||||
const lensesData = useLenses();
|
||||
const lensesUI = useLensesUI(lensesData.lenses);
|
||||
|
||||
const screens = useBreakpoint();
|
||||
|
||||
const viewModes = [
|
||||
{
|
||||
value: "tile",
|
||||
label: "Плитка",
|
||||
icon: <BuildOutlined style={lensesUI.viewModIconStyle}/>
|
||||
icon: <BuildOutlined style={lensesData.viewModIconStyle}/>
|
||||
},
|
||||
{
|
||||
value: "table",
|
||||
label: "Таблица",
|
||||
icon: <TableOutlined style={lensesUI.viewModIconStyle}/>
|
||||
icon: <TableOutlined style={lensesData.viewModIconStyle}/>
|
||||
}
|
||||
];
|
||||
|
||||
@ -94,8 +92,8 @@ const LensesTab = () => {
|
||||
dataIndex: "side",
|
||||
key: "side",
|
||||
filters: [
|
||||
{text: "Левая", value: "левая"},
|
||||
{text: "Правая", value: "правая"},
|
||||
{ text: "Левая", value: "левая" },
|
||||
{ text: "Правая", value: "правая" },
|
||||
],
|
||||
onFilter: (value, record) => record.side === value,
|
||||
},
|
||||
@ -105,8 +103,8 @@ const LensesTab = () => {
|
||||
key: "issued",
|
||||
render: (issued) => (issued ? "Да" : "Нет"),
|
||||
filters: [
|
||||
{text: "Да", value: true},
|
||||
{text: "Нет", value: false},
|
||||
{ text: "Да", value: true },
|
||||
{ text: "Нет", value: false },
|
||||
],
|
||||
onFilter: (value, record) => record.issued === value,
|
||||
},
|
||||
@ -115,9 +113,8 @@ const LensesTab = () => {
|
||||
key: "actions",
|
||||
fixed: 'right',
|
||||
render: (text, record) => (
|
||||
<div style={lensesUI.tableActionButtonsStyle}>
|
||||
<Button onClick={() => lensesUI.handleEditLens(record)}>Изменить</Button>
|
||||
|
||||
<div style={lensesData.tableActionButtonsStyle}>
|
||||
<Button onClick={() => lensesData.handleEditLens(record)}>Изменить</Button>
|
||||
<Popconfirm
|
||||
title="Вы уверены, что хотите удалить линзу?"
|
||||
onConfirm={() => lensesData.handleDeleteLens(record.id)}
|
||||
@ -145,22 +142,22 @@ const LensesTab = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div style={lensesUI.containerStyle}>
|
||||
<div style={lensesData.containerStyle}>
|
||||
<Title level={1}><FolderViewOutlined/> Линзы</Title>
|
||||
<Row gutter={[16, 16]} style={lensesUI.filterBarStyle}>
|
||||
<Row gutter={[16, 16]} style={lensesData.filterBarStyle}>
|
||||
<Col xs={24} md={24} sm={24} xl={15}>
|
||||
<Input
|
||||
placeholder="Поиск линзы"
|
||||
value={lensesUI.searchText}
|
||||
onChange={(e) => lensesUI.handleSetSearchText(e.target.value)}
|
||||
style={lensesUI.formItemStyle}
|
||||
value={lensesData.searchText}
|
||||
onChange={(e) => lensesData.handleSetSearchText(e.target.value)}
|
||||
style={lensesData.formItemStyle}
|
||||
allowClear
|
||||
/>
|
||||
</Col>
|
||||
<Col xs={24} md={12} sm={24} xl={5}>
|
||||
<Button
|
||||
onClick={lensesUI.toggleAdvancedSearch}
|
||||
icon={lensesUI.showAdvancedSearch ? <UpOutlined/> : <DownOutlined/>}
|
||||
onClick={lensesData.toggleAdvancedSearch}
|
||||
icon={lensesData.showAdvancedSearch ? <UpOutlined/> : <DownOutlined/>}
|
||||
block
|
||||
>
|
||||
Расширенный поиск
|
||||
@ -168,8 +165,8 @@ const LensesTab = () => {
|
||||
</Col>
|
||||
<Col xs={24} md={12} sm={24} xl={4}>
|
||||
<SelectViewMode
|
||||
viewMode={lensesUI.viewMode}
|
||||
setViewMode={lensesUI.handleSetViewMode}
|
||||
viewMode={lensesData.viewMode}
|
||||
setViewMode={lensesData.handleSetViewMode}
|
||||
localStorageKey={"viewModeLenses"}
|
||||
toolTipText={"Формат отображения линз"}
|
||||
viewModes={viewModes}
|
||||
@ -177,100 +174,93 @@ const LensesTab = () => {
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
{lensesUI.showAdvancedSearch && (
|
||||
{lensesData.showAdvancedSearch && (
|
||||
<Card
|
||||
title="Расширенный поиск"
|
||||
style={lensesUI.advancedSearchCardStyle}
|
||||
style={lensesData.advancedSearchCardStyle}
|
||||
>
|
||||
<Row gutter={16}>
|
||||
<Col xs={24} sm={12}>
|
||||
<Form layout="vertical">
|
||||
<Form.Item label="Тор">
|
||||
<InputNumber
|
||||
value={lensesUI.searchParams.tor || 0}
|
||||
onChange={(value) => lensesUI.handleParamChange("tor", value)}
|
||||
style={lensesUI.formItemStyle}
|
||||
value={lensesData.searchParams.tor || 0}
|
||||
onChange={(value) => lensesData.handleParamChange("tor", value)}
|
||||
style={lensesData.formItemStyle}
|
||||
defaultValue={0}
|
||||
step={0.1}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Диаметр">
|
||||
<InputNumber
|
||||
value={lensesUI.searchParams.diameter || 0}
|
||||
onChange={(value) => lensesUI.handleParamChange("diameter", value)}
|
||||
style={lensesUI.formItemStyle}
|
||||
value={lensesData.searchParams.diameter || 0}
|
||||
onChange={(value) => lensesData.handleParamChange("diameter", value)}
|
||||
style={lensesData.formItemStyle}
|
||||
defaultValue={0}
|
||||
step={0.1}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Рефракция">
|
||||
<InputNumber
|
||||
value={lensesUI.searchParams.preset_refraction || 0}
|
||||
onChange={(value) => lensesUI.handleParamChange("preset_refraction", value)}
|
||||
style={lensesUI.formItemStyle}
|
||||
value={lensesData.searchParams.preset_refraction || 0}
|
||||
onChange={(value) => lensesData.handleParamChange("preset_refraction", value)}
|
||||
style={lensesData.formItemStyle}
|
||||
defaultValue={0}
|
||||
step={0.1}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Периферическая торичность">
|
||||
<InputNumber
|
||||
value={lensesUI.searchParams.periphery_toricity || 0}
|
||||
onChange={(value) => lensesUI.handleParamChange("periphery_toricity", value)}
|
||||
style={lensesUI.formItemStyle}
|
||||
value={lensesData.searchParams.periphery_toricity || 0}
|
||||
onChange={(value) => lensesData.handleParamChange("periphery_toricity", value)}
|
||||
style={lensesData.formItemStyle}
|
||||
defaultValue={0}
|
||||
step={0.1}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Col>
|
||||
|
||||
<Col xs={24} sm={12}>
|
||||
<Form layout="vertical">
|
||||
<Form.Item label="Сторона">
|
||||
<Select
|
||||
value={lensesUI.searchParams.side}
|
||||
onChange={(value) => lensesUI.handleParamChange("side", value)}
|
||||
style={lensesUI.formItemStyle}
|
||||
value={lensesData.searchParams.side}
|
||||
onChange={(value) => lensesData.handleParamChange("side", value)}
|
||||
style={lensesData.formItemStyle}
|
||||
>
|
||||
<Option value="all">Все</Option>
|
||||
<Option value="левая">Левая</Option>
|
||||
<Option value="правая">Правая</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Выдана">
|
||||
<Select
|
||||
value={lensesUI.searchParams.issued}
|
||||
onChange={(value) => lensesUI.handleParamChange("issued", value)}
|
||||
style={lensesUI.formItemStyle}
|
||||
value={lensesData.searchParams.issued}
|
||||
onChange={(value) => lensesData.handleParamChange("issued", value)}
|
||||
style={lensesData.formItemStyle}
|
||||
>
|
||||
<Option value="all">Все</Option>
|
||||
<Option value={true}>Да</Option>
|
||||
<Option value={false}>Нет</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Острота зрения (Trial)">
|
||||
<InputNumber
|
||||
value={lensesUI.searchParams.trial || 0}
|
||||
onChange={(value) => lensesUI.handleParamChange("trial", value)}
|
||||
style={lensesUI.formItemStyle}
|
||||
value={lensesData.searchParams.trial || 0}
|
||||
onChange={(value) => lensesData.handleParamChange("trial", value)}
|
||||
style={lensesData.formItemStyle}
|
||||
defaultValue={0}
|
||||
step={0.1}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Row>
|
||||
<Col xs={24} sm={12} offset={screens.sm ? 12 : 0}
|
||||
style={{textAlign: screens.sm ? "right" : "center", marginTop: "1.7rem"}}>
|
||||
style={{ textAlign: screens.sm ? "right" : "center", marginTop: "1.7rem" }}>
|
||||
<Button
|
||||
type="primary"
|
||||
block={!screens.sm}
|
||||
onClick={() => {
|
||||
lensesUI.handleParamChange({
|
||||
lensesData.handleParamChange({
|
||||
tor: null,
|
||||
diameter: null,
|
||||
preset_refraction: null,
|
||||
@ -293,45 +283,45 @@ const LensesTab = () => {
|
||||
|
||||
{lensesData.isLoading ? (
|
||||
<LoadingIndicator/>
|
||||
) : lensesUI.viewMode === "tile" ? (
|
||||
) : lensesData.viewMode === "tile" ? (
|
||||
<List
|
||||
grid={{gutter: 16, xs: 1, sm: 1, md: 2, lg: 3, xl: 4}}
|
||||
dataSource={lensesUI.filteredLenses}
|
||||
grid={{ gutter: 16, xs: 1, sm: 1, md: 2, lg: 3, xl: 4 }}
|
||||
dataSource={lensesData.filteredLenses}
|
||||
renderItem={(lens) => (
|
||||
<List.Item>
|
||||
<LensCard
|
||||
lens={lens}
|
||||
handleDeleteLens={() => lensesData.handleDeleteLens(lens.id)}
|
||||
handleEditLens={() => lensesUI.handleEditLens(lens)}
|
||||
handleEditLens={() => lensesData.handleEditLens(lens)}
|
||||
/>
|
||||
</List.Item>
|
||||
)}
|
||||
pagination={lensesUI.pagination}
|
||||
pagination={lensesData.pagination}
|
||||
/>
|
||||
) : (
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={lensesUI.filteredLenses}
|
||||
dataSource={lensesData.filteredLenses}
|
||||
scroll={{
|
||||
x: "max-content"
|
||||
}}
|
||||
showSorterTooltip={false}
|
||||
pagination={lensesUI.pagination}
|
||||
pagination={lensesData.pagination}
|
||||
/>
|
||||
)}
|
||||
|
||||
<FloatButton
|
||||
icon={<PlusOutlined/>}
|
||||
type="primary"
|
||||
onClick={lensesUI.handleAddLens}
|
||||
onClick={lensesData.handleAddLens}
|
||||
tooltip="Добавить линзу"
|
||||
/>
|
||||
|
||||
<LensFormModal
|
||||
visible={lensesUI.isModalVisible}
|
||||
onCancel={lensesUI.handleCloseModal}
|
||||
visible={lensesData.isModalVisible}
|
||||
onCancel={lensesData.handleCloseModal}
|
||||
onSubmit={lensesData.handleModalSubmit}
|
||||
lens={lensesUI.selectedLens}
|
||||
lens={lensesData.selectedLens}
|
||||
isProcessing={lensesData.isProcessing}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -1,28 +1,100 @@
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { notification } from "antd";
|
||||
import {
|
||||
useAddLensMutation,
|
||||
useDeleteLensMutation,
|
||||
useGetLensesQuery,
|
||||
useUpdateLensMutation
|
||||
} from "../../../../../Api/lensesApi.js";
|
||||
import {notification} from "antd";
|
||||
import {closeModal} from "../../../../../Redux/Slices/lensesSlice.js";
|
||||
|
||||
import {
|
||||
closeModal,
|
||||
openModal,
|
||||
selectLens,
|
||||
setCurrentPage,
|
||||
setPageSize,
|
||||
setSearchParams,
|
||||
setSearchText,
|
||||
setShowAdvancedSearch,
|
||||
setViewMode
|
||||
} from "../../../../../Redux/Slices/lensesSlice.js";
|
||||
import { getCachedInfo } from "../../../../../Utils/cachedInfoUtils.js";
|
||||
|
||||
const useLenses = () => {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const {
|
||||
searchText,
|
||||
viewMode,
|
||||
currentPage,
|
||||
pageSize,
|
||||
selectedLens,
|
||||
isModalVisible,
|
||||
showAdvancedSearch,
|
||||
searchParams,
|
||||
} = useSelector(state => state.lensesUI);
|
||||
|
||||
const {data: lenses = [], isLoading, isError} = useGetLensesQuery(undefined, {
|
||||
pollingInterval: 20000,
|
||||
});
|
||||
const { data = { lenses: [], total_count: 0 }, isLoading, isError } = useGetLensesQuery(
|
||||
{ page: currentPage, pageSize, search: searchText || undefined },
|
||||
{
|
||||
pollingInterval: 20000,
|
||||
refetchOnMountOrArgChange: true,
|
||||
}
|
||||
);
|
||||
|
||||
const [addLens, {isLoading: isAdding}] = useAddLensMutation();
|
||||
const [updateLens, {isLoading: isUpdating}] = useUpdateLensMutation();
|
||||
const [deleteLens, {isLoading: isDeleting}] = useDeleteLensMutation();
|
||||
const [addLens, { isLoading: isAdding }] = useAddLensMutation();
|
||||
const [updateLens, { isLoading: isUpdating }] = useUpdateLensMutation();
|
||||
const [deleteLens, { isLoading: isDeleting }] = useDeleteLensMutation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Линзы";
|
||||
const cachedViewMode = getCachedInfo("viewModeLenses");
|
||||
if (cachedViewMode) dispatch(setViewMode(cachedViewMode));
|
||||
}, [dispatch]);
|
||||
|
||||
const containerStyle = { padding: 20 };
|
||||
const filterBarStyle = { marginBottom: 20 };
|
||||
const formItemStyle = { width: "100%" };
|
||||
const viewModIconStyle = { marginRight: 8 };
|
||||
const tableActionButtonsStyle = { display: "flex", gap: "8px" };
|
||||
const advancedSearchCardStyle = { marginBottom: 20 };
|
||||
|
||||
const handleSetSearchText = (value) => {
|
||||
dispatch(setSearchText(value));
|
||||
dispatch(setCurrentPage(1)); // Сбрасываем на первую страницу при изменении поиска
|
||||
};
|
||||
|
||||
const handleCloseModal = () => dispatch(closeModal());
|
||||
|
||||
const handleSetCurrentPage = (page) => dispatch(setCurrentPage(page));
|
||||
const handleSetPageSize = (size) => dispatch(setPageSize(size));
|
||||
const handleSetViewMode = (mode) => dispatch(setViewMode(mode));
|
||||
|
||||
const handleAddLens = () => {
|
||||
dispatch(selectLens(null));
|
||||
dispatch(openModal());
|
||||
};
|
||||
|
||||
const handleEditLens = (lens) => {
|
||||
dispatch(selectLens(lens));
|
||||
dispatch(openModal());
|
||||
};
|
||||
|
||||
const handleParamChange = (param, value) => {
|
||||
if (typeof param === "object") {
|
||||
dispatch(setSearchParams(param));
|
||||
} else {
|
||||
dispatch(setSearchParams({ ...searchParams, [param]: value }));
|
||||
}
|
||||
};
|
||||
|
||||
const toggleAdvancedSearch = () => {
|
||||
dispatch(setShowAdvancedSearch(!showAdvancedSearch));
|
||||
};
|
||||
|
||||
const handlePaginationChange = (page, pageSize) => {
|
||||
handleSetCurrentPage(page);
|
||||
handleSetPageSize(pageSize);
|
||||
};
|
||||
|
||||
const handleDeleteLens = async (lensId) => {
|
||||
try {
|
||||
@ -43,10 +115,9 @@ const useLenses = () => {
|
||||
|
||||
const handleModalSubmit = async (lensData) => {
|
||||
dispatch(closeModal());
|
||||
|
||||
try {
|
||||
if (selectedLens) {
|
||||
await updateLens({id: selectedLens.id, ...lensData}).unwrap();
|
||||
await updateLens({ id: selectedLens.id, ...lensData }).unwrap();
|
||||
notification.success({
|
||||
message: "Линза обновлена",
|
||||
description: "Линза успешно обновлена.",
|
||||
@ -69,14 +140,72 @@ const useLenses = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const filteredLenses = useMemo(() => {
|
||||
return data.lenses.filter((lens) => {
|
||||
const textMatch = Object.values(lens).some((value) =>
|
||||
value?.toString().toLowerCase().includes(searchText.toLowerCase())
|
||||
);
|
||||
|
||||
const advancedMatch = Object.entries(searchParams).every(([key, value]) => {
|
||||
if (value === null || value === '') return true;
|
||||
if (key === 'side') {
|
||||
if (value === 'all') return true;
|
||||
return lens.side === value;
|
||||
}
|
||||
if (key === 'issued') {
|
||||
return lens.issued === value || value === "all";
|
||||
}
|
||||
return lens[key] === value;
|
||||
});
|
||||
|
||||
return textMatch && advancedMatch && (searchParams.issued || lens.issued === false);
|
||||
}).sort((a, b) => {
|
||||
return b.id - a.id; // Сортировка по убыванию id
|
||||
});
|
||||
}, [data.lenses, searchText, searchParams]);
|
||||
|
||||
const pagination = {
|
||||
current: currentPage,
|
||||
pageSize: pageSize,
|
||||
total: data.total_count,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ["5", "10", "20", "50"],
|
||||
onChange: (page, newPageSize) => {
|
||||
handlePaginationChange(page, newPageSize);
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
lenses,
|
||||
lenses: data.lenses,
|
||||
filteredLenses: filteredLenses.map(lens => ({ ...lens, key: lens.id })),
|
||||
isLoading,
|
||||
isError,
|
||||
isProcessing: isAdding || isUpdating || isDeleting,
|
||||
searchText,
|
||||
viewMode,
|
||||
currentPage,
|
||||
pageSize,
|
||||
selectedLens,
|
||||
isModalVisible,
|
||||
showAdvancedSearch,
|
||||
searchParams,
|
||||
pagination,
|
||||
containerStyle,
|
||||
filterBarStyle,
|
||||
formItemStyle,
|
||||
viewModIconStyle,
|
||||
tableActionButtonsStyle,
|
||||
advancedSearchCardStyle,
|
||||
handleSetSearchText,
|
||||
handleAddLens,
|
||||
handleEditLens,
|
||||
handleCloseModal,
|
||||
handleDeleteLens,
|
||||
handleModalSubmit,
|
||||
}
|
||||
handleParamChange,
|
||||
toggleAdvancedSearch,
|
||||
handleSetViewMode,
|
||||
};
|
||||
};
|
||||
|
||||
export default useLenses;
|
||||
@ -1,128 +0,0 @@
|
||||
import {useEffect, useMemo} from "react";
|
||||
import {getCachedInfo} from "../../../../../Utils/cachedInfoUtils.js";
|
||||
import {
|
||||
closeModal,
|
||||
openModal,
|
||||
selectLens, setCurrentPage, setPageSize,
|
||||
setSearchParams,
|
||||
setSearchText, setShowAdvancedSearch,
|
||||
setViewMode
|
||||
} from "../../../../../Redux/Slices/lensesSlice.js";
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
|
||||
|
||||
const useLensesUI = (lenses) => {
|
||||
const dispatch = useDispatch();
|
||||
const {
|
||||
searchText,
|
||||
viewMode,
|
||||
currentPage,
|
||||
pageSize,
|
||||
selectedLens,
|
||||
isModalVisible,
|
||||
showAdvancedSearch,
|
||||
searchParams,
|
||||
} = useSelector(state => state.lensesUI);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Линзы";
|
||||
const cachedViewMode = getCachedInfo("viewModeLenses");
|
||||
if (cachedViewMode) dispatch(setViewMode(cachedViewMode));
|
||||
}, [dispatch]);
|
||||
|
||||
const containerStyle = {padding: 20};
|
||||
const filterBarStyle = {marginBottom: 20};
|
||||
const formItemStyle = {width: "100%"};
|
||||
const viewModIconStyle = {marginRight: 8};
|
||||
const tableActionButtonsStyle = {display: "flex", gap: "8px"};
|
||||
|
||||
const handleSetSearchText = (value) => dispatch(setSearchText(value));
|
||||
const handleCloseModal = () => dispatch(closeModal());
|
||||
const handleSetCurrentPage = (page) => dispatch(setCurrentPage(page));
|
||||
const handleSetPageSize = (size) => dispatch(setPageSize(size));
|
||||
const handleSetViewMode = (mode) => dispatch(setViewMode(mode));
|
||||
|
||||
const handleAddLens = () => {
|
||||
dispatch(selectLens(null));
|
||||
dispatch(openModal());
|
||||
};
|
||||
|
||||
const handleEditLens = (lens) => {
|
||||
dispatch(selectLens(lens));
|
||||
dispatch(openModal());
|
||||
};
|
||||
|
||||
const handleParamChange = (param, value) => {
|
||||
dispatch(setSearchParams({...searchParams, [param]: value}));
|
||||
};
|
||||
|
||||
const toggleAdvancedSearch = () => {
|
||||
dispatch(setShowAdvancedSearch(!showAdvancedSearch));
|
||||
};
|
||||
|
||||
const handlePaginationChange = (page, pageSize) => {
|
||||
handleSetCurrentPage(page);
|
||||
handleSetPageSize(pageSize);
|
||||
};
|
||||
|
||||
const filteredLenses = useMemo(() => {
|
||||
return lenses.filter((lens) => {
|
||||
const textMatch = Object.values(lens).some((value) =>
|
||||
value?.toString().toLowerCase().includes(searchText.toLowerCase())
|
||||
);
|
||||
|
||||
const advancedMatch = Object.entries(searchParams).every(([key, value]) => {
|
||||
if (value === null || value === '') return true;
|
||||
if (key === 'side') {
|
||||
if (value === 'all') return true;
|
||||
return lens.side === value;
|
||||
}
|
||||
if (key === 'issued') {
|
||||
return lens.issued === value || value === "all";
|
||||
}
|
||||
return lens[key] === value;
|
||||
});
|
||||
|
||||
return textMatch && advancedMatch && (searchParams.issued || lens.issued === false);
|
||||
}).sort((a, b) => {
|
||||
return b.id - a.id;
|
||||
});
|
||||
}, [lenses, searchText, searchParams]);
|
||||
|
||||
const pagination = {
|
||||
currentPage: currentPage,
|
||||
pageSize: pageSize,
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ["5", "10", "20", "50"],
|
||||
onChange: (page, newPageSize) => {
|
||||
handlePaginationChange(page, newPageSize);
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
searchText,
|
||||
viewMode,
|
||||
currentPage,
|
||||
pageSize,
|
||||
selectedLens,
|
||||
isModalVisible,
|
||||
showAdvancedSearch,
|
||||
searchParams,
|
||||
pagination,
|
||||
containerStyle,
|
||||
filterBarStyle,
|
||||
formItemStyle,
|
||||
viewModIconStyle,
|
||||
tableActionButtonsStyle,
|
||||
filteredLenses: filteredLenses.map(lens => ({...lens, key: lens.id})),
|
||||
handleSetSearchText,
|
||||
handleAddLens,
|
||||
handleEditLens,
|
||||
handleCloseModal,
|
||||
handleParamChange,
|
||||
toggleAdvancedSearch,
|
||||
handleSetViewMode,
|
||||
}
|
||||
};
|
||||
|
||||
export default useLensesUI;
|
||||
Loading…
x
Reference in New Issue
Block a user