feat: Добавлена сортировка пациентов по фамилии
This commit is contained in:
parent
1d8888da87
commit
342e021211
@ -1,4 +1,4 @@
|
||||
from typing import Sequence, Optional, Tuple
|
||||
from typing import Sequence, Optional, Tuple, Literal
|
||||
|
||||
from sqlalchemy import select, func, or_
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@ -10,7 +10,8 @@ class PatientsRepository:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.db = db
|
||||
|
||||
async def get_all(self, skip: int = 0, limit: int = 10, search: str = None) -> Tuple[Sequence[Patient], int]:
|
||||
async def get_all(self, skip: int = 0, limit: int = 10, search: str = None,
|
||||
sort_order: Literal["asc", "desc"] = "asc") -> Tuple[Sequence[Patient], int]:
|
||||
stmt = select(Patient)
|
||||
|
||||
if search:
|
||||
@ -25,6 +26,11 @@ class PatientsRepository:
|
||||
)
|
||||
)
|
||||
|
||||
if sort_order == "desc":
|
||||
stmt = stmt.order_by(Patient.last_name.desc())
|
||||
else:
|
||||
stmt = stmt.order_by(Patient.last_name.asc())
|
||||
|
||||
stmt = stmt.offset(skip).limit(limit)
|
||||
result = await self.db.execute(stmt)
|
||||
patients = result.scalars().all()
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
from typing import Literal
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
@ -20,11 +22,12 @@ async def get_all_patients(
|
||||
page: int = Query(1, ge=1, description="Page number"),
|
||||
page_size: int = Query(10, ge=1, le=100, description="Number of patients per page"),
|
||||
search: str = Query(None, description="Search term for filtering patients"),
|
||||
sort_order: Literal["asc", "desc"] = Query("asc", description="Sort order by first_name (asc or desc)"),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
user=Depends(get_current_user),
|
||||
):
|
||||
patients_service = PatientsService(db)
|
||||
patients, total_count = await patients_service.get_all_patients(page, page_size, search)
|
||||
patients, total_count = await patients_service.get_all_patients(page, page_size, search, sort_order)
|
||||
return {"patients": patients, "total_count": total_count}
|
||||
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
from typing import Optional, Tuple
|
||||
from typing import Optional, Tuple, Literal
|
||||
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
@ -13,10 +13,10 @@ class PatientsService:
|
||||
def __init__(self, db: AsyncSession):
|
||||
self.patient_repository = PatientsRepository(db)
|
||||
|
||||
async def get_all_patients(self, page: int = 1, page_size: int = 10, search: str = None) -> Tuple[
|
||||
async def get_all_patients(self, page: int = 1, page_size: int = 10, search: str = None, sort_order: Literal["asc", "desc"] = "asc") -> Tuple[
|
||||
list[PatientEntity], int]:
|
||||
skip = (page - 1) * page_size
|
||||
patients, total_count = await self.patient_repository.get_all(skip=skip, limit=page_size, search=search)
|
||||
patients, total_count = await self.patient_repository.get_all(skip=skip, limit=page_size, search=search, sort_order=sort_order)
|
||||
return (
|
||||
[self.model_to_entity(patient) for patient in patients],
|
||||
total_count
|
||||
|
||||
@ -7,9 +7,14 @@ export const patientsApi = createApi({
|
||||
tagTypes: ['Patient'],
|
||||
endpoints: (builder) => ({
|
||||
getPatients: builder.query({
|
||||
query: ({ page, pageSize, search }) => ({
|
||||
query: ({ page, pageSize, search, sortOrder }) => ({
|
||||
url: '/patients/',
|
||||
params: { page, page_size: pageSize, search: search || undefined },
|
||||
params: {
|
||||
page,
|
||||
page_size: pageSize,
|
||||
search: search || undefined,
|
||||
sort_order: sortOrder || undefined,
|
||||
},
|
||||
}),
|
||||
providesTags: ['Patients'],
|
||||
}),
|
||||
|
||||
@ -18,7 +18,7 @@ import {
|
||||
SortAscendingOutlined,
|
||||
SortDescendingOutlined,
|
||||
TableOutlined,
|
||||
TeamOutlined,
|
||||
TeamOutlined
|
||||
} from "@ant-design/icons";
|
||||
import PatientListCard from "../../Dummies/PatientListCard.jsx";
|
||||
import PatientFormModal from "../../Dummies/PatientFormModal/PatientFormModal.jsx";
|
||||
@ -37,24 +37,20 @@ const PatientsPage = () => {
|
||||
title: "Фамилия",
|
||||
dataIndex: "last_name",
|
||||
key: "last_name",
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: "Имя",
|
||||
dataIndex: "first_name",
|
||||
key: "first_name",
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: "Отчество",
|
||||
dataIndex: "patronymic",
|
||||
key: "patronymic",
|
||||
sorter: true,
|
||||
},
|
||||
{
|
||||
title: "Дата рождения",
|
||||
dataIndex: "birthday",
|
||||
sorter: true,
|
||||
render: patientsData.formatDate,
|
||||
},
|
||||
{
|
||||
@ -118,26 +114,23 @@ const PatientsPage = () => {
|
||||
placeholder="Поиск пациента"
|
||||
value={patientsData.searchText}
|
||||
onChange={(e) => patientsData.handleSetSearchText(e.target.value)}
|
||||
onPressEnter={patientsData.handleSearch}
|
||||
style={patientsData.formItemStyle}
|
||||
allowClear
|
||||
onClear={patientsData.handleClearSearch}
|
||||
/>
|
||||
</Col>
|
||||
{patientsData.viewMode === "tile" && (
|
||||
<Col xs={24} md={5} sm={6} xl={3} xxl={2}>
|
||||
<Tooltip title={"Сортировка пациентов"}>
|
||||
<Select
|
||||
value={patientsData.sortOrder}
|
||||
onChange={patientsData.handleSetSortOrder}
|
||||
style={patientsData.formItemStyle}
|
||||
>
|
||||
<Option value="asc"><SortAscendingOutlined/> А-Я</Option>
|
||||
<Option value="desc"><SortDescendingOutlined/> Я-А</Option>
|
||||
</Select>
|
||||
</Tooltip>
|
||||
</Col>
|
||||
)}
|
||||
<Col xs={24} md={5} sm={6} xl={3} xxl={2}>
|
||||
<Tooltip title={"Сортировка пациентов"}>
|
||||
<Select
|
||||
value={patientsData.sortOrder}
|
||||
onChange={patientsData.handleSetSortOrder}
|
||||
style={patientsData.formItemStyle}
|
||||
>
|
||||
<Option value="asc"><SortAscendingOutlined/> А-Я</Option>
|
||||
<Option value="desc"><SortDescendingOutlined/> Я-А</Option>
|
||||
</Select>
|
||||
</Tooltip>
|
||||
</Col>
|
||||
<Col xs={24} md={patientsData.viewMode === "tile" ? 5 : 10}
|
||||
sm={patientsData.viewMode === "tile" ? 8 : 14}
|
||||
xl={patientsData.viewMode === "tile" ? 3 : 5}
|
||||
|
||||
@ -29,7 +29,7 @@ const usePatients = () => {
|
||||
const [tempSearchText, setTempSearchText] = useState("");
|
||||
|
||||
const { data = { patients: [], total_count: 0 }, isLoading, isError } = useGetPatientsQuery(
|
||||
{ page: currentPage, pageSize, search: tempSearchText || undefined },
|
||||
{ page: currentPage, pageSize, search: tempSearchText || undefined, sortOrder },
|
||||
{
|
||||
pollingInterval: 20000, // Автообновление каждые 20 секунд
|
||||
refetchOnMountOrArgChange: true, // Обновление при изменении параметров
|
||||
@ -76,7 +76,11 @@ const usePatients = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const handleSetSortOrder = (value) => dispatch(setSortOrder(value));
|
||||
const handleSetSortOrder = (value) => {
|
||||
dispatch(setSortOrder(value));
|
||||
dispatch(setCurrentPage(1)); // Сбрасываем на первую страницу при изменении сортировки
|
||||
};
|
||||
|
||||
const handleSetCurrentPage = (page) => dispatch(setCurrentPage(page));
|
||||
const handleSetPageSize = (size) => dispatch(setPageSize(size));
|
||||
const handleSetViewMode = (mode) => dispatch(setViewMode(mode));
|
||||
@ -131,6 +135,8 @@ const usePatients = () => {
|
||||
handleClearSearch,
|
||||
handleDeletePatient,
|
||||
handleSetSortOrder,
|
||||
handleSetCurrentPage,
|
||||
handleSetPageSize,
|
||||
handleSetViewMode,
|
||||
handleCloseModal,
|
||||
handleAddPatient,
|
||||
|
||||
@ -1,58 +1,50 @@
|
||||
import {createSlice} from '@reduxjs/toolkit'
|
||||
import {cacheInfo} from "../../Utils/cachedInfoUtils.js";
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
const initialState = {
|
||||
searchText: '',
|
||||
sortOrder: 'asc',
|
||||
viewMode: 'tile',
|
||||
isModalVisible: false,
|
||||
selectedPatient: null,
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
selectedPatient: null,
|
||||
isModalVisible: false
|
||||
};
|
||||
|
||||
const patientsSlice = createSlice({
|
||||
name: 'patientsUI',
|
||||
initialState,
|
||||
reducers: {
|
||||
setSearchText: (state, action) => {
|
||||
state.searchText = action.payload;
|
||||
},
|
||||
setSortOrder: (state, action) => {
|
||||
setSortOrder(state, action) {
|
||||
state.sortOrder = action.payload;
|
||||
},
|
||||
setViewMode: (state, action) => {
|
||||
setViewMode(state, action) {
|
||||
state.viewMode = action.payload;
|
||||
cacheInfo("viewModePatients", action.payload);
|
||||
},
|
||||
setCurrentPage: (state, action) => {
|
||||
state.currentPage = action.payload;
|
||||
},
|
||||
setPageSize: (state, action) => {
|
||||
state.pageSize = action.payload;
|
||||
},
|
||||
openModal: (state) => {
|
||||
openModal(state) {
|
||||
state.isModalVisible = true;
|
||||
},
|
||||
closeModal: (state) => {
|
||||
closeModal(state) {
|
||||
state.isModalVisible = false;
|
||||
state.selectedPatient = null;
|
||||
},
|
||||
selectPatient: (state, action) => {
|
||||
selectPatient(state, action) {
|
||||
state.selectedPatient = action.payload;
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
setCurrentPage(state, action) {
|
||||
state.currentPage = action.payload;
|
||||
},
|
||||
setPageSize(state, action) {
|
||||
state.pageSize = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const {
|
||||
setSearchText,
|
||||
setSortOrder,
|
||||
setViewMode,
|
||||
setCurrentPage,
|
||||
setPageSize,
|
||||
openModal,
|
||||
closeModal,
|
||||
selectPatient
|
||||
selectPatient,
|
||||
setCurrentPage,
|
||||
setPageSize,
|
||||
} = patientsSlice.actions;
|
||||
|
||||
export default patientsSlice.reducer;
|
||||
Loading…
x
Reference in New Issue
Block a user