сделал просмотр информации о пациенте
This commit is contained in:
parent
e87baafae9
commit
2f39baa8d3
@ -1,5 +1,5 @@
|
|||||||
import {Routes, Route, Navigate} from "react-router-dom";
|
import {Routes, Route, Navigate} from "react-router-dom";
|
||||||
import PrivateRoute from "./components/PrivateRoute.jsx";
|
import PrivateRoute from "./components/patients/PrivateRoute.jsx";
|
||||||
import LoginPage from "./pages/LoginPage.jsx";
|
import LoginPage from "./pages/LoginPage.jsx";
|
||||||
import MainLayout from "./layouts/MainLayout.jsx";
|
import MainLayout from "./layouts/MainLayout.jsx";
|
||||||
import PatientsPage from "./pages/PatientsPage.jsx";
|
import PatientsPage from "./pages/PatientsPage.jsx";
|
||||||
|
|||||||
@ -1,64 +0,0 @@
|
|||||||
import {Card, Modal} from "antd";
|
|
||||||
import PropTypes from "prop-types";
|
|
||||||
import {DeleteOutlined, EditOutlined} from "@ant-design/icons";
|
|
||||||
|
|
||||||
const PatientListCard = ({patient, handleEditPatient, handleDeletePatient}) => {
|
|
||||||
const birthday = new Date(patient.birthday)
|
|
||||||
|
|
||||||
const deletePatientConfirm = () => {
|
|
||||||
Modal.confirm({
|
|
||||||
title: "Удаление пациента",
|
|
||||||
content: `Вы уверены, что хотите удалить пациента ${patient.last_name} ${patient.first_name}?`,
|
|
||||||
okText: "Да, удалить",
|
|
||||||
cancelText: "Отмена",
|
|
||||||
onOk: () => handleDeletePatient(patient.id),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Card
|
|
||||||
type="inner"
|
|
||||||
title={`${patient.last_name} ${patient.first_name}`}
|
|
||||||
actions={[
|
|
||||||
<EditOutlined
|
|
||||||
onClick={() => {
|
|
||||||
handleEditPatient(patient);
|
|
||||||
}}
|
|
||||||
key={"editPatient"}
|
|
||||||
/>,
|
|
||||||
<DeleteOutlined
|
|
||||||
onClick={deletePatientConfirm}
|
|
||||||
key={"deletePatient"}
|
|
||||||
style={{color: "red"}}
|
|
||||||
/>
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<p><strong>📅 Дата рождения:</strong> {birthday.toLocaleString('ru-RU', {
|
|
||||||
month: 'long',
|
|
||||||
day: 'numeric',
|
|
||||||
year: 'numeric'
|
|
||||||
})}</p>
|
|
||||||
{patient.phone && <p><strong>📞 Телефон:</strong> {patient.phone}</p>}
|
|
||||||
{patient.email && <p><strong>✉️ Email:</strong> {patient.email}</p>}
|
|
||||||
</Card>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
PatientListCard.propTypes = {
|
|
||||||
patient: PropTypes.shape({
|
|
||||||
id: PropTypes.number.isRequired,
|
|
||||||
last_name: PropTypes.string.isRequired,
|
|
||||||
first_name: PropTypes.string.isRequired,
|
|
||||||
patronymic: PropTypes.string,
|
|
||||||
birthday: PropTypes.string.isRequired,
|
|
||||||
address: PropTypes.string,
|
|
||||||
email: PropTypes.string,
|
|
||||||
phone: PropTypes.string,
|
|
||||||
diagnosis: PropTypes.string,
|
|
||||||
correction: PropTypes.string,
|
|
||||||
}).isRequired,
|
|
||||||
handleEditPatient: PropTypes.func.isRequired,
|
|
||||||
handleDeletePatient: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default PatientListCard;
|
|
||||||
@ -8,7 +8,7 @@ import dayjs from "dayjs";
|
|||||||
|
|
||||||
const {TextArea} = Input;
|
const {TextArea} = Input;
|
||||||
|
|
||||||
const PatientModal = ({visible, onCancel, onSubmit, patient}) => {
|
const PatientFormModal = ({visible, onCancel, onSubmit, patient}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -128,7 +128,7 @@ const PatientModal = ({visible, onCancel, onSubmit, patient}) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
PatientModal.propTypes = {
|
PatientFormModal.propTypes = {
|
||||||
visible: PropTypes.bool.isRequired,
|
visible: PropTypes.bool.isRequired,
|
||||||
onCancel: PropTypes.func.isRequired,
|
onCancel: PropTypes.func.isRequired,
|
||||||
onSubmit: PropTypes.func.isRequired,
|
onSubmit: PropTypes.func.isRequired,
|
||||||
@ -145,4 +145,4 @@ PatientModal.propTypes = {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default PatientModal;
|
export default PatientFormModal;
|
||||||
92
web-app/src/components/patients/PatientListCard.jsx
Normal file
92
web-app/src/components/patients/PatientListCard.jsx
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import {Card, Modal, Tooltip} from "antd";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import {DeleteOutlined, EditOutlined, EyeOutlined} from "@ant-design/icons";
|
||||||
|
import {useState} from "react";
|
||||||
|
import PatientViewModal from "./PatientViewModal.jsx";
|
||||||
|
|
||||||
|
const PatientListCard = ({patient, handleEditPatient, handleDeletePatient}) => {
|
||||||
|
const [showModalInfo, setShowModalInfo] = useState(false);
|
||||||
|
|
||||||
|
const birthday = new Date(patient.birthday)
|
||||||
|
|
||||||
|
const deletePatientConfirm = () => {
|
||||||
|
Modal.confirm({
|
||||||
|
title: "Удаление пациента",
|
||||||
|
content: `Вы уверены, что хотите удалить пациента ${patient.last_name} ${patient.first_name}?`,
|
||||||
|
okText: "Да, удалить",
|
||||||
|
cancelText: "Отмена",
|
||||||
|
onOk: () => handleDeletePatient(patient.id),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleViewPatient = () => {
|
||||||
|
setShowModalInfo(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const actions = [
|
||||||
|
<Tooltip title="Просмотр пациента" key={"viewPatient"}>
|
||||||
|
<EyeOutlined
|
||||||
|
onClick={handleViewPatient}
|
||||||
|
/>
|
||||||
|
</Tooltip>,
|
||||||
|
|
||||||
|
<Tooltip title="Редактирование пациента" key={"editPatient"}>
|
||||||
|
<EditOutlined
|
||||||
|
onClick={() => {
|
||||||
|
handleEditPatient(patient);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>,
|
||||||
|
<Tooltip title="Удаление пациента" key={"deletePatient"}>
|
||||||
|
<DeleteOutlined
|
||||||
|
onClick={deletePatientConfirm}
|
||||||
|
style={{color: "red"}}
|
||||||
|
/>
|
||||||
|
</Tooltip>,
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Card
|
||||||
|
type="inner"
|
||||||
|
title={`${patient.last_name} ${patient.first_name}`}
|
||||||
|
actions={actions}
|
||||||
|
>
|
||||||
|
<p><strong>📅 Дата рождения:</strong> {birthday.toLocaleString('ru-RU', {
|
||||||
|
month: 'long',
|
||||||
|
day: 'numeric',
|
||||||
|
year: 'numeric'
|
||||||
|
})}</p>
|
||||||
|
{patient.phone && <p><strong>📞 Телефон:</strong> {patient.phone}</p>}
|
||||||
|
{patient.email && <p><strong>✉️ Email:</strong> {patient.email}</p>}
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{showModalInfo && (
|
||||||
|
<PatientViewModal
|
||||||
|
visible={showModalInfo}
|
||||||
|
onCancel={() => setShowModalInfo(false)}
|
||||||
|
patient={patient}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
PatientListCard.propTypes = {
|
||||||
|
patient: PropTypes.shape({
|
||||||
|
id: PropTypes.number.isRequired,
|
||||||
|
last_name: PropTypes.string.isRequired,
|
||||||
|
first_name: PropTypes.string.isRequired,
|
||||||
|
patronymic: PropTypes.string,
|
||||||
|
birthday: PropTypes.string.isRequired,
|
||||||
|
address: PropTypes.string,
|
||||||
|
email: PropTypes.string,
|
||||||
|
phone: PropTypes.string,
|
||||||
|
diagnosis: PropTypes.string,
|
||||||
|
correction: PropTypes.string,
|
||||||
|
}).isRequired,
|
||||||
|
handleEditPatient: PropTypes.func.isRequired,
|
||||||
|
handleDeletePatient: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PatientListCard;
|
||||||
88
web-app/src/components/patients/PatientViewModal.jsx
Normal file
88
web-app/src/components/patients/PatientViewModal.jsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import {Button, Col, Modal, Row, Typography, Divider} from "antd";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
|
||||||
|
const { Text, Title } = Typography;
|
||||||
|
|
||||||
|
const PatientViewModal = ({ visible, onCancel, patient }) => {
|
||||||
|
if (!patient) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="Просмотр пациента"
|
||||||
|
open={visible}
|
||||||
|
onCancel={onCancel}
|
||||||
|
footer={
|
||||||
|
<Button onClick={onCancel} type="primary">
|
||||||
|
Закрыть
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Row gutter={24}>
|
||||||
|
<Col xs={24} md={12}>
|
||||||
|
<div style={{ marginBottom: 12 }}>
|
||||||
|
<Title level={5}>👤 ФИО</Title>
|
||||||
|
<Text>{`${patient.last_name} ${patient.first_name} ${patient.patronymic || ''}`}</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginBottom: 12 }}>
|
||||||
|
<Title level={5}>🎂 Дата рождения</Title>
|
||||||
|
<Text>
|
||||||
|
{new Date(patient.birthday).toLocaleDateString('ru-RU', {
|
||||||
|
day: 'numeric',
|
||||||
|
month: 'long',
|
||||||
|
year: 'numeric',
|
||||||
|
})}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
<Col xs={24} md={12}>
|
||||||
|
<div style={{ marginBottom: 12 }}>
|
||||||
|
<Title level={5}>📞 Телефон</Title>
|
||||||
|
<Text>{patient.phone || 'Не указан'}</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginBottom: 12 }}>
|
||||||
|
<Title level={5}>✉️ Email</Title>
|
||||||
|
<Text>{patient.email || 'Не указан'}</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginBottom: 12 }}>
|
||||||
|
<Title level={5}>🏠 Адрес</Title>
|
||||||
|
<Text>{patient.address || 'Не указан'}</Text>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<div style={{ marginBottom: 12 }}>
|
||||||
|
<Title level={5}>🩺 Диагноз</Title>
|
||||||
|
<Text>{patient.diagnosis || 'Не указан'}</Text>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={{ marginBottom: 12 }}>
|
||||||
|
<Title level={5}>👓 Коррекция</Title>
|
||||||
|
<Text>{patient.correction || 'Не указ'}</Text>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
PatientViewModal.propTypes = {
|
||||||
|
visible: PropTypes.bool.isRequired,
|
||||||
|
onCancel: PropTypes.func.isRequired,
|
||||||
|
patient: PropTypes.shape({
|
||||||
|
first_name: PropTypes.string,
|
||||||
|
last_name: PropTypes.string,
|
||||||
|
patronymic: PropTypes.string,
|
||||||
|
birthday: PropTypes.string,
|
||||||
|
address: PropTypes.string,
|
||||||
|
email: PropTypes.string,
|
||||||
|
phone: PropTypes.string,
|
||||||
|
diagnosis: PropTypes.string,
|
||||||
|
correction: PropTypes.string,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PatientViewModal;
|
||||||
@ -1,5 +1,5 @@
|
|||||||
import {Navigate, Outlet} from "react-router-dom";
|
import {Navigate, Outlet} from "react-router-dom";
|
||||||
import {useAuth} from "../AuthContext.jsx";
|
import {useAuth} from "../../AuthContext.jsx";
|
||||||
|
|
||||||
const PrivateRoute = () => {
|
const PrivateRoute = () => {
|
||||||
const {user} = useAuth();
|
const {user} = useAuth();
|
||||||
@ -4,6 +4,7 @@
|
|||||||
const LensPage = () => {
|
const LensPage = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,8 @@ import {Input, Select, List, FloatButton, Row, Col, Spin, notification} from "an
|
|||||||
import {LoadingOutlined, PlusOutlined} from "@ant-design/icons";
|
import {LoadingOutlined, PlusOutlined} from "@ant-design/icons";
|
||||||
import {useAuth} from "../AuthContext.jsx";
|
import {useAuth} from "../AuthContext.jsx";
|
||||||
import getAllPatients from "../api/patients/GetAllPatients.jsx";
|
import getAllPatients from "../api/patients/GetAllPatients.jsx";
|
||||||
import PatientListCard from "../components/PatientListCard.jsx";
|
import PatientListCard from "../components/patients/PatientListCard.jsx";
|
||||||
import PatientModal from "../components/PatientModal.jsx";
|
import PatientFormModal from "../components/patients/PatientFormModal.jsx";
|
||||||
import updatePatient from "../api/patients/UpdatePatient.jsx";
|
import updatePatient from "../api/patients/UpdatePatient.jsx";
|
||||||
import addPatient from "../api/patients/AddPatient.jsx";
|
import addPatient from "../api/patients/AddPatient.jsx";
|
||||||
import deletePatient from "../api/patients/DeletePatient.jsx";
|
import deletePatient from "../api/patients/DeletePatient.jsx";
|
||||||
@ -39,7 +39,7 @@ const PatientsPage = () => {
|
|||||||
const cachedData = localStorage.getItem("patientsData");
|
const cachedData = localStorage.getItem("patientsData");
|
||||||
const cacheTimestamp = localStorage.getItem("patientsTimestamp");
|
const cacheTimestamp = localStorage.getItem("patientsTimestamp");
|
||||||
|
|
||||||
if (cachedData && cacheTimestamp && (Date.now() - parseInt(cacheTimestamp)) < 5 * 60 * 1000) {
|
if (cachedData && cacheTimestamp && (Date.now() - parseInt(cacheTimestamp)) < 60 * 1000) {
|
||||||
setPatients(JSON.parse(cachedData));
|
setPatients(JSON.parse(cachedData));
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
return;
|
return;
|
||||||
@ -221,7 +221,7 @@ const PatientsPage = () => {
|
|||||||
onClick={handleAddPatient}
|
onClick={handleAddPatient}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PatientModal
|
<PatientFormModal
|
||||||
visible={isModalVisible}
|
visible={isModalVisible}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
onSubmit={handleModalPatientSubmit}
|
onSubmit={handleModalPatientSubmit}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user