feat: Добавлена фильтрация пациентов по поисковой строке

This commit is contained in:
Андрей Дувакин 2025-06-07 15:20:22 +05:00
parent a2635ed03e
commit 1d8888da87
3 changed files with 138 additions and 139 deletions

View File

@ -9,28 +9,28 @@ import {
Button, Button,
Popconfirm, Popconfirm,
Typography, Typography,
Result, Tooltip Result,
Tooltip
} from "antd"; } from "antd";
import { import {
BuildOutlined, BuildOutlined,
PlusOutlined, PlusOutlined,
SortAscendingOutlined, SortAscendingOutlined,
SortDescendingOutlined, TableOutlined, SortDescendingOutlined,
TeamOutlined TableOutlined,
TeamOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import PatientListCard from "../../Dummies/PatientListCard.jsx"; import PatientListCard from "../../Dummies/PatientListCard.jsx";
import PatientFormModal from "../../Dummies/PatientFormModal/PatientFormModal.jsx"; import PatientFormModal from "../../Dummies/PatientFormModal/PatientFormModal.jsx";
import SelectViewMode from "../../Widgets/SelectViewMode/SelectViewMode.jsx"; import SelectViewMode from "../../Widgets/SelectViewMode/SelectViewMode.jsx";
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx"; import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
import usePatients from "./usePatients.js"; import usePatients from "./usePatients.js";
import usePatientsUI from "./usePatientsUI.js";
const {Option} = Select; const {Option} = Select;
const {Title} = Typography; const {Title} = Typography;
const PatientsPage = () => { const PatientsPage = () => {
const patientsData = usePatients(); const patientsData = usePatients();
const patientsUI = usePatientsUI(patientsData.patients, patientsData.totalCount);
const columns = [ const columns = [
{ {
@ -55,7 +55,7 @@ const PatientsPage = () => {
title: "Дата рождения", title: "Дата рождения",
dataIndex: "birthday", dataIndex: "birthday",
sorter: true, sorter: true,
render: patientsUI.formatDate, render: patientsData.formatDate,
}, },
{ {
title: "Телефон", title: "Телефон",
@ -71,7 +71,7 @@ const PatientsPage = () => {
render: (_, record) => ( render: (_, record) => (
<Row gutter={[8, 8]}> <Row gutter={[8, 8]}>
<Col xs={24} xl={12}> <Col xs={24} xl={12}>
<Button block onClick={() => patientsUI.handleEditPatient(record)}>Изменить</Button> <Button block onClick={() => patientsData.handleEditPatient(record)}>Изменить</Button>
</Col> </Col>
<Col xs={24} xl={12}> <Col xs={24} xl={12}>
<Popconfirm <Popconfirm
@ -92,12 +92,12 @@ const PatientsPage = () => {
{ {
value: "tile", value: "tile",
label: "Плитка", label: "Плитка",
icon: <BuildOutlined style={patientsUI.viewModIconStyle}/> icon: <BuildOutlined style={patientsData.viewModIconStyle}/>
}, },
{ {
value: "table", value: "table",
label: "Таблица", label: "Таблица",
icon: <TableOutlined style={patientsUI.viewModIconStyle}/> icon: <TableOutlined style={patientsData.viewModIconStyle}/>
} }
]; ];
@ -110,25 +110,27 @@ const PatientsPage = () => {
); );
return ( return (
<div style={patientsUI.containerStyle}> <div style={patientsData.containerStyle}>
<Title level={1}><TeamOutlined/> Пациенты</Title> <Title level={1}><TeamOutlined/> Пациенты</Title>
<Row gutter={[16, 16]} style={patientsUI.filterBarStyle}> <Row gutter={[16, 16]} style={patientsData.filterBarStyle}>
<Col xs={24} md={14} sm={10} xl={18} xxl={19}> <Col xs={24} md={14} sm={10} xl={18} xxl={19}>
<Input <Input
placeholder="Поиск пациента" placeholder="Поиск пациента"
value={patientsUI.searchText} value={patientsData.searchText}
onChange={(e) => patientsUI.handleSetSearchText(e.target.value)} onChange={(e) => patientsData.handleSetSearchText(e.target.value)}
style={patientsUI.formItemStyle} onPressEnter={patientsData.handleSearch}
style={patientsData.formItemStyle}
allowClear allowClear
onClear={patientsData.handleClearSearch}
/> />
</Col> </Col>
{patientsUI.viewMode === "tile" && ( {patientsData.viewMode === "tile" && (
<Col xs={24} md={5} sm={6} xl={3} xxl={2}> <Col xs={24} md={5} sm={6} xl={3} xxl={2}>
<Tooltip title={"Сортировка пациентов"}> <Tooltip title={"Сортировка пациентов"}>
<Select <Select
value={patientsUI.sortOrder} value={patientsData.sortOrder}
onChange={patientsUI.handleSetSortOrder} onChange={patientsData.handleSetSortOrder}
style={patientsUI.formItemStyle} style={patientsData.formItemStyle}
> >
<Option value="asc"><SortAscendingOutlined/> А-Я</Option> <Option value="asc"><SortAscendingOutlined/> А-Я</Option>
<Option value="desc"><SortDescendingOutlined/> Я-А</Option> <Option value="desc"><SortDescendingOutlined/> Я-А</Option>
@ -136,13 +138,13 @@ const PatientsPage = () => {
</Tooltip> </Tooltip>
</Col> </Col>
)} )}
<Col xs={24} md={patientsUI.viewMode === "tile" ? 5 : 10} <Col xs={24} md={patientsData.viewMode === "tile" ? 5 : 10}
sm={patientsUI.viewMode === "tile" ? 8 : 14} sm={patientsData.viewMode === "tile" ? 8 : 14}
xl={patientsUI.viewMode === "tile" ? 3 : 5} xl={patientsData.viewMode === "tile" ? 3 : 5}
xxl={patientsUI.viewMode === "tile" ? 3 : 5}> xxl={patientsData.viewMode === "tile" ? 3 : 5}>
<SelectViewMode <SelectViewMode
viewMode={patientsUI.viewMode} viewMode={patientsData.viewMode}
setViewMode={patientsUI.handleSetViewMode} setViewMode={patientsData.handleSetViewMode}
localStorageKey={"viewModePatients"} localStorageKey={"viewModePatients"}
toolTipText={"Формат отображения пациентов"} toolTipText={"Формат отображения пациентов"}
viewModes={viewModes} viewModes={viewModes}
@ -150,33 +152,33 @@ const PatientsPage = () => {
</Col> </Col>
</Row> </Row>
{patientsData.isLoading ? <LoadingIndicator/> : patientsUI.viewMode === "tile" ? ( {patientsData.isLoading ? <LoadingIndicator/> : patientsData.viewMode === "tile" ? (
<List <List
grid={{gutter: 16, column: 3}} grid={{gutter: 16, column: 3}}
dataSource={patientsUI.filteredPatients} dataSource={patientsData.filteredPatients}
renderItem={patient => ( renderItem={patient => (
<List.Item> <List.Item>
<PatientListCard <PatientListCard
patient={patient} patient={patient}
handleEditPatient={patientsUI.handleEditPatient} handleEditPatient={patientsData.handleEditPatient}
handleDeletePatient={patientsData.handleDeletePatient} handleDeletePatient={patientsData.handleDeletePatient}
/> />
</List.Item> </List.Item>
)} )}
pagination={patientsUI.pagination} pagination={patientsData.pagination}
/> />
) : ( ) : (
<Table <Table
columns={columns} columns={columns}
dataSource={patientsUI.filteredPatients} dataSource={patientsData.filteredPatients}
pagination={patientsUI.pagination} pagination={patientsData.pagination}
/> />
)} )}
<FloatButton <FloatButton
icon={<PlusOutlined/>} icon={<PlusOutlined/>}
type="primary" type="primary"
onClick={patientsUI.handleAddPatient} onClick={patientsData.handleAddPatient}
tooltip="Добавить пациента" tooltip="Добавить пациента"
/> />

View File

@ -1,22 +1,64 @@
import { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { notification } from "antd"; import { notification } from "antd";
import { import {
useDeletePatientMutation,
useGetPatientsQuery, useGetPatientsQuery,
useDeletePatientMutation,
} from "../../../Api/patientsApi.js"; } from "../../../Api/patientsApi.js";
import { useSelector } from "react-redux"; import {
closeModal,
openModal,
selectPatient,
setCurrentPage,
setPageSize,
setSortOrder,
setViewMode
} from "../../../Redux/Slices/patientsSlice.js";
import { getCachedInfo } from "../../../Utils/cachedInfoUtils.js";
const usePatients = () => { const usePatients = () => {
const { currentPage, pageSize, searchText } = useSelector(state => state.patientsUI); const dispatch = useDispatch();
const {
sortOrder,
viewMode,
isModalVisible,
currentPage,
pageSize,
} = useSelector(state => state.patientsUI);
const [tempSearchText, setTempSearchText] = useState("");
const { data = { patients: [], total_count: 0 }, isLoading, isError } = useGetPatientsQuery( const { data = { patients: [], total_count: 0 }, isLoading, isError } = useGetPatientsQuery(
{ page: currentPage, pageSize, search: searchText }, { page: currentPage, pageSize, search: tempSearchText || undefined },
{ {
pollingInterval: 20000, pollingInterval: 20000, // Автообновление каждые 20 секунд
refetchOnMountOrArgChange: true, // Обновление при изменении параметров
} }
); );
const [deletePatient] = useDeletePatientMutation(); const [deletePatient] = useDeletePatientMutation();
useEffect(() => {
document.title = "Пациенты";
const cachedViewMode = getCachedInfo("viewModePatients");
if (cachedViewMode) dispatch(setViewMode(cachedViewMode));
}, [dispatch]);
const containerStyle = { padding: 20 };
const filterBarStyle = { marginBottom: 20 };
const formItemStyle = { width: "100%" };
const viewModIconStyle = { marginRight: 8 };
const handleSetTempSearchText = (value) => {
setTempSearchText(value);
dispatch(setCurrentPage(1)); // Сбрасываем на первую страницу при изменении поиска
};
const handleClearSearch = () => {
setTempSearchText("");
dispatch(setCurrentPage(1));
};
const handleDeletePatient = async (patientId) => { const handleDeletePatient = async (patientId) => {
try { try {
await deletePatient(patientId).unwrap(); await deletePatient(patientId).unwrap();
@ -34,12 +76,67 @@ const usePatients = () => {
} }
}; };
const handleSetSortOrder = (value) => dispatch(setSortOrder(value));
const handleSetCurrentPage = (page) => dispatch(setCurrentPage(page));
const handleSetPageSize = (size) => dispatch(setPageSize(size));
const handleSetViewMode = (mode) => dispatch(setViewMode(mode));
const handleCloseModal = () => dispatch(closeModal());
const handlePaginationChange = (page, pageSize) => {
handleSetCurrentPage(page);
handleSetPageSize(pageSize);
};
const handleAddPatient = () => {
dispatch(selectPatient(null));
dispatch(openModal());
};
const handleEditPatient = (patient) => {
dispatch(selectPatient(patient));
dispatch(openModal());
};
const formatDate = (date) => new Date(date).toLocaleDateString();
const pagination = {
current: currentPage,
pageSize: pageSize,
total: data.total_count,
showSizeChanger: true,
pageSizeOptions: ["5", "10", "20", "50"],
onChange: (page, newPageSize) => {
handlePaginationChange(page, newPageSize);
},
};
return { return {
searchText: tempSearchText,
sortOrder,
viewMode,
isModalVisible,
currentPage,
pageSize,
containerStyle,
filterBarStyle,
formItemStyle,
viewModIconStyle,
pagination,
patients: data.patients, patients: data.patients,
totalCount: data.total_count, totalCount: data.total_count,
isLoading, isLoading,
isError, isError,
filteredPatients: data.patients.map(p => ({ ...p, key: p.id })),
handleSetSearchText: handleSetTempSearchText,
handleClearSearch,
handleDeletePatient, handleDeletePatient,
handleSetSortOrder,
handleSetViewMode,
handleCloseModal,
handleAddPatient,
handleEditPatient,
formatDate,
handlePaginationChange,
}; };
}; };

View File

@ -1,100 +0,0 @@
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { debounce } from "lodash";
import {
closeModal,
openModal,
selectPatient,
setCurrentPage,
setPageSize,
setSearchText,
setSortOrder,
setViewMode
} from "../../../Redux/Slices/patientsSlice.js";
import { getCachedInfo } from "../../../Utils/cachedInfoUtils.js";
const usePatientsUI = (patients, totalCount) => {
const dispatch = useDispatch();
const {
searchText,
sortOrder,
viewMode,
isModalVisible,
currentPage,
pageSize,
} = useSelector(state => state.patientsUI);
useEffect(() => {
document.title = "Пациенты";
const cachedViewMode = getCachedInfo("viewModePatients");
if (cachedViewMode) dispatch(setViewMode(cachedViewMode));
}, [dispatch]);
const containerStyle = { padding: 20 };
const filterBarStyle = { marginBottom: 20 };
const formItemStyle = { width: "100%" };
const viewModIconStyle = { marginRight: 8 };
const handleSetSearchText = debounce((value) => {
dispatch(setSearchText(value));
dispatch(setCurrentPage(1)); // Сбрасываем на первую страницу при новом поиске
}, 300);
const handleSetSortOrder = (value) => dispatch(setSortOrder(value));
const handleSetCurrentPage = (page) => dispatch(setCurrentPage(page));
const handleSetPageSize = (size) => dispatch(setPageSize(size));
const handleSetViewMode = (mode) => dispatch(setViewMode(mode));
const handleCloseModal = () => dispatch(closeModal());
const handlePaginationChange = (page, pageSize) => {
handleSetCurrentPage(page);
handleSetPageSize(pageSize);
};
const handleAddPatient = () => {
dispatch(selectPatient(null));
dispatch(openModal());
};
const handleEditPatient = (patient) => {
dispatch(selectPatient(patient));
dispatch(openModal());
};
const formatDate = (date) => new Date(date).toLocaleDateString();
const pagination = {
current: currentPage,
pageSize: pageSize,
total: totalCount,
showSizeChanger: true,
pageSizeOptions: ["5", "10", "20", "50"],
onChange: (page, newPageSize) => {
handlePaginationChange(page, newPageSize);
},
};
return {
searchText,
sortOrder,
viewMode,
isModalVisible,
currentPage,
pageSize,
containerStyle,
filterBarStyle,
formItemStyle,
viewModIconStyle,
pagination,
filteredPatients: patients.map(p => ({ ...p, key: p.id })),
handleSetSearchText,
handleSetSortOrder,
handleSetViewMode,
handleCloseModal,
handleAddPatient,
handleEditPatient,
formatDate,
handlePaginationChange,
};
};
export default usePatientsUI;