diff --git a/next.config.ts b/next.config.ts index 078e9e1..8f2b429 100644 --- a/next.config.ts +++ b/next.config.ts @@ -4,6 +4,16 @@ const nextConfig: NextConfig = { turbopack: { root: process.cwd(), }, + images: { + remotePatterns: [ + { + protocol: "http", + hostname: "127.0.0.1", + port: "5264", + pathname: "/uploads/**", + }, + ], + }, }; export default nextConfig; diff --git a/src/app/consultation/history/page.tsx b/src/app/consultation/history/page.tsx new file mode 100644 index 0000000..0f10967 --- /dev/null +++ b/src/app/consultation/history/page.tsx @@ -0,0 +1,14 @@ +"use client"; +import BaseLayout from "@/components/layouts/BaseLayout"; +import TableHistoryPatient from "@/components/page/consultation/TableHistoryPatient"; +import React from "react"; + +const page = () => { + return ( + + + + ); +}; + +export default page; diff --git a/src/common/funcs/optionConvert.ts b/src/common/funcs/optionConvert.ts index 0ad0a05..68f54ac 100644 --- a/src/common/funcs/optionConvert.ts +++ b/src/common/funcs/optionConvert.ts @@ -63,6 +63,19 @@ export default function fancyTimeFormat(duration: number) { return ret; } +export function checkTime(i: any) { + if (Math.abs(i) < 10) { + i = "0" + i; + } + return i; +} + +export const timeSubmit = (date: Date | null | undefined, isTo?: boolean) => { + return date + ? `${date.getFullYear()}-${checkTime(date.getMonth() + 1)}-${checkTime(date.getDate())}T${isTo ? "23:59:59" : "00:00:00"}` + : null; +}; + export function getKeyCert(): { time: string; keyCert: string; diff --git a/src/components/layouts/BaseLayout/BaseLayout.tsx b/src/components/layouts/BaseLayout/BaseLayout.tsx index 7b0c758..d9c7e6a 100644 --- a/src/components/layouts/BaseLayout/BaseLayout.tsx +++ b/src/components/layouts/BaseLayout/BaseLayout.tsx @@ -11,6 +11,16 @@ export const ContextBaseLayout = React.createContext({}); const BaseLayout = ({ children, title, breadcrumb }: PropsBaseLayout) => { const [showFull, setShowFull] = React.useState(false); const [openMenuMobile, setOpenMenuMobile] = React.useState(false); + // Khi mount trên client, mở sidebar mặc định nếu là màn hình desktop (xl) + // React.useEffect(() => { + // try { + // if (window?.innerWidth >= 1280) { + // setShowFull(true); + // } + // } catch (e) { + // // ignore + // } + // }, []); return ( { return (
{/* PROFILE */} - {

Chi tiết tài khoản

-
+
*/} {/* CHANGE PASSWORD */} - {

Thay đổi mật khẩu

-
+
*/} {/* LOGOUT */}
{ const router = useRouter(); @@ -111,6 +112,9 @@ const CreateConsultation = () => { }); const handleSubmit = () => { + if (!form?.patientId) { + return toastWarn({ msg: "Vui lòng chọn bệnh nhân" }); + } createConsultationMutation.mutate(); }; @@ -118,14 +122,14 @@ const CreateConsultation = () => {
@@ -139,56 +143,13 @@ const CreateConsultation = () => { " >

- Thêm phiên khám + Tạo phiên khám

-
- router.back()} - > - Hủy bỏ - - - - {createConsultationMutation.isPending - ? "Đang tạo..." - : "Tạo phiên khám"} - -
{/* BODY */} -
+
{ getOptionValue={(item: PatientItem) => item.id} />
- {/* - - - - - - - - - - - */}
{/* FOOTER */} +
+ router.back()} + > + Hủy bỏ + + + + {createConsultationMutation.isPending + ? "Đang tạo..." + : "Tạo phiên khám"} + +
); diff --git a/src/components/page/consultation/MainPageConsultation/MainPageConsultation.tsx b/src/components/page/consultation/MainPageConsultation/MainPageConsultation.tsx index 615d3cb..05ccd4a 100644 --- a/src/components/page/consultation/MainPageConsultation/MainPageConsultation.tsx +++ b/src/components/page/consultation/MainPageConsultation/MainPageConsultation.tsx @@ -272,20 +272,6 @@ const MainPageConsultation = () => { rowKey={(item) => item.id} data={consultationData} column={[ - { - fixedLeft: true, - - title: "ID PHIÊN KHÁM", - - render: (item: ConsultationItem) => ( - - {item.id} - - ), - }, { title: "TÊN BỆNH NHÂN", @@ -296,9 +282,14 @@ const MainPageConsultation = () => { { title: "MÃ PHIÊN KHÁM", - + fixedLeft: true, render: (item: ConsultationItem) => ( - {item.sessionCode} + + {item.sessionCode} + ), }, diff --git a/src/components/page/consultation/TableHistoryPatient/TableHistoryPatient.tsx b/src/components/page/consultation/TableHistoryPatient/TableHistoryPatient.tsx new file mode 100644 index 0000000..12d1bec --- /dev/null +++ b/src/components/page/consultation/TableHistoryPatient/TableHistoryPatient.tsx @@ -0,0 +1,196 @@ +"use client"; + +import React from "react"; +import { usePathname, useRouter, useSearchParams } from "next/navigation"; +import { useQuery } from "@tanstack/react-query"; +import Link from "next/link"; + +import consultationServices, { + ConsultationItem, + ConsultationResponse, +} from "@/services/consultationServices"; +import { httpRequest } from "@/services"; + +import { QUERY_KEY, TYPE_STATUS } from "@/constant/config/enum"; + +import DataWrapper from "@/components/customs/DataWrapper"; +import Table from "@/components/customs/custom-table"; +import StateActive from "@/components/customs/StateActive"; +import Pagination from "@/components/customs/custom-pagination"; +import Search from "@/components/customs/custom-search"; + +const TableHistoryPatient = () => { + const searchParams = useSearchParams(); + const router = useRouter(); + const pathname = usePathname(); + const patientId = searchParams.get("_id"); + + const consultationQuery = useQuery({ + queryKey: [QUERY_KEY.table_list_consultation, patientId, "full-history"], + enabled: !!patientId, + queryFn: async () => { + const res = await httpRequest({ + showMessageFailed: true, + http: consultationServices.getConsultations({ + Page: 1, + PageSize: 1000, + PatientId: patientId || "", + }), + }); + + return ( + res || { + items: [], + page: 1, + pageSize: 10, + total: 0, + totalPages: 0, + } + ); + }, + }); + + const _page = searchParams.get("_page"); + + const _pageSize = searchParams.get("_pageSize"); + + const _keyword = searchParams.get("_keyword"); + + const page = _page ? Number(_page) : 1; + const pageSize = _pageSize ? Number(_pageSize) : 10; + + const updateQuery = (key: string, value: string | number) => { + const params = new URLSearchParams(searchParams.toString()); + + if (!value || value === "" || (key === "_page" && value === 1)) { + params.delete(key); + } else { + params.set(key, String(value)); + } + + if (key === "_pageSize") { + params.delete("_page"); + } + + const queryString = params.toString(); + + router.push(queryString ? `?${queryString}` : pathname); + }; + + const data = consultationQuery.data?.items || []; + + // lấy tên bệnh nhân từ record đầu tiên (nếu backend có trả) + const patientName = data?.[0]?.patientName || "Bệnh nhân"; + + return ( +
+
+

+ Lịch sử phiên khám của {patientName} +

+ + +
+
+
+ updateQuery("_keyword", value)} + placeholder="Tìm kiếm phiên khám..." + /> +
+
+ + + item.id} + data={data} + column={[ + { + title: "MÃ PHIÊN KHÁM", + render: (item: ConsultationItem) => ( + + {item.sessionCode} + + ), + }, + { + title: "NGÀY KHÁM", + render: (item: ConsultationItem) => {item.visitDate}, + }, + { + title: "DẤU HIỆU", + render: (item: ConsultationItem) => ( + {item.symptomsText || "---"} + ), + }, + { + title: "CHẨN ĐOÁN", + render: (item: ConsultationItem) => ( + {item.diagnosis || "---"} + ), + }, + { + title: "TRẠNG THÁI", + render: (item: ConsultationItem) => ( + + ), + }, + ]} + /> + + + updateQuery("_page", value)} + onSetPageSize={(value) => updateQuery("_pageSize", value)} + dependencies={[_pageSize, _keyword]} + /> + + ); +}; + +export default TableHistoryPatient; diff --git a/src/components/page/consultation/TableHistoryPatient/index.ts b/src/components/page/consultation/TableHistoryPatient/index.ts new file mode 100644 index 0000000..2b62655 --- /dev/null +++ b/src/components/page/consultation/TableHistoryPatient/index.ts @@ -0,0 +1 @@ +export { default } from "./TableHistoryPatient"; diff --git a/src/components/page/consultation/UpdateConsultation/UpdateConsultation.tsx b/src/components/page/consultation/UpdateConsultation/UpdateConsultation.tsx index a667205..cdf1620 100644 --- a/src/components/page/consultation/UpdateConsultation/UpdateConsultation.tsx +++ b/src/components/page/consultation/UpdateConsultation/UpdateConsultation.tsx @@ -174,34 +174,12 @@ const UpdateConsultation = () => {

- Chỉnh sửa phiên khám + Phiên khám

Cập nhật thông tin chi tiết quá trình khám bệnh

-
- router.back()} - className="min-w-[120px]" - > - Hủy bỏ - - - {updateConsultationMutation.isPending - ? "Đang cập nhật..." - : "Cập nhật"} - -
{/* GENERAL INFO (PATIENT) */} @@ -251,9 +229,9 @@ const UpdateConsultation = () => { @@ -297,6 +275,28 @@ const UpdateConsultation = () => { } /> +
+ router.back()} + className="min-w-[120px]" + > + Hủy bỏ + + + {updateConsultationMutation.isPending + ? "Đang cập nhật..." + : "Cập nhật"} + +
); diff --git a/src/components/page/patient/DetailPatient/DetailPatient.tsx b/src/components/page/patient/DetailPatient/DetailPatient.tsx index a2f4c31..b760a01 100644 --- a/src/components/page/patient/DetailPatient/DetailPatient.tsx +++ b/src/components/page/patient/DetailPatient/DetailPatient.tsx @@ -119,9 +119,8 @@ const DetailPatient = () => { queryKey: [QUERY_KEY.table_list_consultation, patientId], }); - // Nếu API trả về thông tin phiên khám vừa tạo (có chứa id), chuyển thẳng tới trang update if (res?.id) { - router.push(`${PATH.CONSULTATION}/update/${res.id}`); + router.push(`${PATH.CONSULTATION}/${res.id}`); // detail } }, }); @@ -293,7 +292,7 @@ const DetailPatient = () => { Lịch sử phiên khám Tất cả @@ -310,23 +309,17 @@ const DetailPatient = () => { data={consultationData} column={[ { + title: "MÃ PHIÊN KHÁM", fixedLeft: true, - title: "ID PHIÊN KHÁM", render: (item: ConsultationItem) => ( - {item.id} + {item.sessionCode} ), }, - { - title: "MÃ PHIÊN KHÁM", - render: (item: ConsultationItem) => ( - {item.sessionCode} - ), - }, { title: "NGÀY KHÁM", render: (item: ConsultationItem) => ( diff --git a/src/components/page/patient/PopupCreatePatient/PopupCreatePatient.tsx b/src/components/page/patient/PopupCreatePatient/PopupCreatePatient.tsx index 09cf363..0c594a2 100644 --- a/src/components/page/patient/PopupCreatePatient/PopupCreatePatient.tsx +++ b/src/components/page/patient/PopupCreatePatient/PopupCreatePatient.tsx @@ -14,6 +14,8 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import { httpRequest } from "@/services"; import patientServices from "@/services/patientServices"; +import { toastWarn } from "@/common/funcs/toast"; +import { timeSubmit } from "@/common/funcs/optionConvert"; export interface ICreatePatient { identificationNumber: string; @@ -77,6 +79,16 @@ const PopupCreatePatient = ({ onClose }: PropsPopupCreatePatient) => { }); const handleSubmit = () => { + if (!form.gender) { + return toastWarn({ msg: "Vui lòng chọn giới tính!" }); + } + const today = new Date(timeSubmit(new Date())!); + const birthDay = new Date(form.dateOfBirth); + + if (today < birthDay) { + return toastWarn({ msg: "Ngày sinh không hợp lệ!" }); + } + createPatientMutation.mutate(); }; @@ -241,29 +253,31 @@ const PopupCreatePatient = ({ onClose }: PropsPopupCreatePatient) => { } placeholder="Số điện thoại" name="phone" - type="text" + type="phone" + isPhone value={form.phone} isRequired /> - Email - * - - } + label={Email} placeholder="Email" name="email" - type="text" + type="email" + isEmail value={form.email} - isRequired />