update
This commit is contained in:
@@ -22,13 +22,17 @@ import patientServices, {
|
||||
import { QUERY_KEY } from "@/constant/config/enum";
|
||||
|
||||
import CustomButton from "@/components/customs/custom-button";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import InputForm from "@/components/utils/FormCustom/components/InputForm";
|
||||
import GridColumn from "@/components/layouts/GridColumn";
|
||||
import { toastWarn } from "@/common/funcs/toast";
|
||||
import specialtyServices, { SpecialtyItem } from "@/services/specialtyServices";
|
||||
import SelectMany from "@/components/utils/FormCustom/components/SelectMany";
|
||||
|
||||
const CreateConsultation = () => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const patientId = searchParams.get("patientId");
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [form, setForm] = useState<{
|
||||
@@ -36,17 +40,13 @@ const CreateConsultation = () => {
|
||||
chiefComplaint: string;
|
||||
symptomsText: string;
|
||||
vitalSigns: string;
|
||||
diagnosis: string;
|
||||
treatmentPlan: string;
|
||||
doctorNotes: string;
|
||||
specialtyIds: string[];
|
||||
}>({
|
||||
patientId: "",
|
||||
patientId: patientId || "",
|
||||
chiefComplaint: "",
|
||||
symptomsText: "",
|
||||
vitalSigns: "",
|
||||
diagnosis: "",
|
||||
treatmentPlan: "",
|
||||
doctorNotes: "",
|
||||
specialtyIds: [],
|
||||
});
|
||||
|
||||
/* =========================
|
||||
@@ -80,6 +80,24 @@ const CreateConsultation = () => {
|
||||
},
|
||||
});
|
||||
|
||||
/* =========================
|
||||
GET LIST SPECIALTY
|
||||
========================= */
|
||||
const specialtyQuery = useQuery<SpecialtyItem[]>({
|
||||
queryKey: [QUERY_KEY.table_list_specialty],
|
||||
|
||||
queryFn: async () => {
|
||||
const res = await httpRequest<SpecialtyItem[]>({
|
||||
showMessageFailed: true,
|
||||
http: specialtyServices.getSpecialty(),
|
||||
});
|
||||
|
||||
return res || [];
|
||||
},
|
||||
});
|
||||
|
||||
const specialties: SpecialtyItem[] = specialtyQuery.data || [];
|
||||
|
||||
/* =========================
|
||||
OPTIONS SELECT
|
||||
========================= */
|
||||
@@ -99,6 +117,10 @@ const CreateConsultation = () => {
|
||||
|
||||
http: consultationServices.createConsultations({
|
||||
patientId: form.patientId,
|
||||
chiefComplaint: form.chiefComplaint,
|
||||
symptomsText: form.symptomsText,
|
||||
vitalSigns: form.vitalSigns,
|
||||
specialtyIds: form.specialtyIds,
|
||||
}),
|
||||
});
|
||||
},
|
||||
@@ -123,7 +145,6 @@ const CreateConsultation = () => {
|
||||
<div
|
||||
className="
|
||||
max-w-[95vw]
|
||||
h-[485px]
|
||||
border
|
||||
rounded-lg
|
||||
bg-white
|
||||
@@ -158,6 +179,7 @@ const CreateConsultation = () => {
|
||||
<span className="text-red-500">*</span>
|
||||
</span>
|
||||
}
|
||||
readOnly={!!patientId}
|
||||
placeholder="Chọn bệnh nhân"
|
||||
value={form.patientId}
|
||||
options={patientOptions}
|
||||
@@ -180,6 +202,63 @@ const CreateConsultation = () => {
|
||||
getOptionValue={(item: PatientItem) => item.id}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-5 mb-2">
|
||||
<GridColumn col={3}>
|
||||
<InputForm
|
||||
label="Lý do khám"
|
||||
name="chiefComplaint"
|
||||
type="text"
|
||||
value={form.chiefComplaint}
|
||||
placeholder="Nhập lý do khám"
|
||||
isRequired
|
||||
onChangeValue={(v) =>
|
||||
setForm((prev) => ({ ...prev, chiefComplaint: String(v) }))
|
||||
}
|
||||
/>
|
||||
<InputForm
|
||||
type="text"
|
||||
label="Triệu chứng"
|
||||
name="symptomsText"
|
||||
placeholder="Nhập triệu chứng"
|
||||
isRequired
|
||||
value={form.symptomsText}
|
||||
onChangeValue={(v) =>
|
||||
setForm((prev) => ({ ...prev, symptomsText: String(v) }))
|
||||
}
|
||||
/>
|
||||
|
||||
<InputForm
|
||||
type="text"
|
||||
label="Chỉ số huyết áp, chỉ số mạch"
|
||||
name="vitalSigns"
|
||||
placeholder="Nhập chỉ số huyết áp, chỉ số mạch"
|
||||
value={form.vitalSigns}
|
||||
isRequired
|
||||
onChangeValue={(v) =>
|
||||
setForm((prev) => ({ ...prev, vitalSigns: String(v) }))
|
||||
}
|
||||
/>
|
||||
</GridColumn>
|
||||
</div>
|
||||
<div className="space-y-5 mb2">
|
||||
<SelectMany<SpecialtyItem>
|
||||
label="Chuyên khoa"
|
||||
text="chuyên khoa"
|
||||
title="Chọn chuyên khoa"
|
||||
placeholder="Chọn nhiều chuyên khoa..."
|
||||
options={specialties}
|
||||
selectedItems={form.specialtyIds}
|
||||
setSelectedItems={(value) =>
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
specialtyIds: value as string[],
|
||||
}))
|
||||
}
|
||||
showSelectedItems="default"
|
||||
getOptionLabel={(item) => item.name}
|
||||
getOptionValue={(item) => item.id}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* FOOTER */}
|
||||
@@ -207,12 +286,10 @@ const CreateConsultation = () => {
|
||||
<CustomButton
|
||||
disabled={
|
||||
!form.patientId ||
|
||||
// !form.chiefComplaint ||
|
||||
// !form.diagnosis ||
|
||||
// !form.doctorNotes ||
|
||||
// !form.symptomsText ||
|
||||
// !form.treatmentPlan ||
|
||||
// !form.vitalSigns ||
|
||||
!form.chiefComplaint ||
|
||||
!form.symptomsText ||
|
||||
!form.vitalSigns ||
|
||||
!form.specialtyIds ||
|
||||
createConsultationMutation.isPending
|
||||
}
|
||||
variant="midnightBlue"
|
||||
|
||||
@@ -134,10 +134,10 @@ const DetailConsultation = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* DẤU HIỆU SINH TỒN */}
|
||||
{/* CHỈ SỐ HUYẾT ÁP, CHỈ SỐ MẠCH */}
|
||||
<div className="space-y-1">
|
||||
<p className="text-[14px] font-medium text-[#697586]">
|
||||
DẤU HIỆU SINH TỒN
|
||||
CHỈ SỐ HUYẾT ÁP, CHỈ SỐ MẠCH
|
||||
</p>
|
||||
|
||||
<p className="text-[15px] font-medium text-[#202939]">
|
||||
@@ -189,6 +189,32 @@ const DetailConsultation = () => {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<p className="text-[14px] font-medium text-[#697586]">
|
||||
CÁC CHUYÊN KHOA ĐANG CHỜ KHÁM
|
||||
</p>
|
||||
|
||||
<p className="text-[15px] font-medium text-[#202939]">
|
||||
{consultation.specialtyClinics
|
||||
?.filter((specialty) => specialty.specialtyStatus === 1)
|
||||
.map((specialty) => specialty.specialtyName)
|
||||
.join(", ") || "---"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1">
|
||||
<p className="text-[14px] font-medium text-[#697586]">
|
||||
CÁC CHUYÊN KHOA ĐÃ KHÁM
|
||||
</p>
|
||||
|
||||
<p className="text-[15px] font-medium text-[#202939]">
|
||||
{consultation.specialtyClinics
|
||||
?.filter((specialty) => specialty.specialtyStatus === 3)
|
||||
.map((specialty) => specialty.specialtyName)
|
||||
.join(", ") || "---"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* TRẠNG THÁI */}
|
||||
<div className="space-y-1">
|
||||
<p className="text-[14px] font-medium text-[#697586]">
|
||||
@@ -200,29 +226,44 @@ const DetailConsultation = () => {
|
||||
listState={[
|
||||
{
|
||||
state: TYPE_STATUS.Draft,
|
||||
text: "Đang chờ",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#FFE4C4",
|
||||
text: "Đang chờ khám",
|
||||
textColor: "#92400E",
|
||||
backgroundColor: "#FEF3C7",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.InProgress,
|
||||
text: "Đang thực hiện",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#ff3300",
|
||||
text: "Đang khám tổng quát",
|
||||
textColor: "#1E3A8A",
|
||||
backgroundColor: "#DBEAFE",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.ToSpecialty,
|
||||
text: "Chờ khám chuyên khoa",
|
||||
textColor: "#6B21A8",
|
||||
backgroundColor: "#E9D5FF",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.PendingPrescription,
|
||||
text: "Chờ nhận thuốc/kính",
|
||||
textColor: "#9A3412",
|
||||
backgroundColor: "#FED7AA",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.Completed,
|
||||
text: "Hoàn thành",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#3d69eb",
|
||||
textColor: "#166534",
|
||||
backgroundColor: "#DCFCE7",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.Cancelled,
|
||||
text: "Đã hủy",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#cccc",
|
||||
textColor: "#991B1B",
|
||||
backgroundColor: "#FEE2E2",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import CustomButton from "@/components/customs/custom-button";
|
||||
import CustomDialog from "@/components/customs/custom-dialog";
|
||||
import CustomPopup from "@/components/customs/custom-popup";
|
||||
import DataWrapper from "@/components/customs/DataWrapper";
|
||||
import Search from "@/components/customs/custom-search";
|
||||
import StateActive from "@/components/customs/StateActive";
|
||||
@@ -27,8 +26,11 @@ import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
|
||||
import React, { useMemo, useState } from "react";
|
||||
|
||||
import { PATH } from "@/constant/config";
|
||||
import Pagination from "@/components/customs/custom-pagination";
|
||||
import moment from "moment";
|
||||
import specialtyServices, { SpecialtyItem } from "@/services/specialtyServices";
|
||||
|
||||
import FilterCustom from "@/components/customs/FilterCustom";
|
||||
|
||||
const MainPageConsultation = () => {
|
||||
const router = useRouter();
|
||||
@@ -49,6 +51,10 @@ const MainPageConsultation = () => {
|
||||
|
||||
const _keyword = searchParams.get("_keyword");
|
||||
|
||||
const _status = searchParams.get("_status");
|
||||
|
||||
const _specialtyId = searchParams.get("_specialtyId");
|
||||
|
||||
/* =========================
|
||||
STATE
|
||||
========================= */
|
||||
@@ -78,7 +84,7 @@ const MainPageConsultation = () => {
|
||||
|
||||
Search: _keyword || "",
|
||||
|
||||
SortBy: "id",
|
||||
SortBy: _specialtyId || undefined,
|
||||
|
||||
Desc: true,
|
||||
}),
|
||||
@@ -100,9 +106,35 @@ const MainPageConsultation = () => {
|
||||
DATA
|
||||
========================= */
|
||||
|
||||
const specialtyQuery = useQuery({
|
||||
queryKey: [QUERY_KEY.list_specialty_lookup],
|
||||
queryFn: async () => {
|
||||
const res = await httpRequest<SpecialtyItem[]>({
|
||||
http: specialtyServices.getSpecialty(),
|
||||
showMessageFailed: true,
|
||||
});
|
||||
|
||||
return res || [];
|
||||
},
|
||||
});
|
||||
|
||||
const consultationData = useMemo(() => {
|
||||
return consultationQuery.data?.items || [];
|
||||
}, [consultationQuery.data]);
|
||||
let data = consultationQuery.data?.items || [];
|
||||
|
||||
if (_status) {
|
||||
data = data.filter((item) => item.status === Number(_status));
|
||||
}
|
||||
|
||||
if (_specialtyId) {
|
||||
data = data.filter((item) =>
|
||||
item.specialtyClinics?.some(
|
||||
(specialty) => specialty.specialtyId === _specialtyId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return data;
|
||||
}, [consultationQuery.data, _status, _specialtyId]);
|
||||
|
||||
/* =========================
|
||||
UPDATE QUERY
|
||||
@@ -114,13 +146,18 @@ const MainPageConsultation = () => {
|
||||
const updateQuery = (key: string, value: string | number) => {
|
||||
const params = new URLSearchParams(searchParams.toString());
|
||||
|
||||
if (!value || value === "" || (key === "_page" && value === 1)) {
|
||||
if (!value || value === "") {
|
||||
params.delete(key);
|
||||
} else {
|
||||
params.set(key, String(value));
|
||||
}
|
||||
|
||||
if (key === "_pageSize") {
|
||||
if (
|
||||
key === "_pageSize" ||
|
||||
key === "_keyword" ||
|
||||
key === "_status" ||
|
||||
key === "_specialtyId"
|
||||
) {
|
||||
params.delete("_page");
|
||||
}
|
||||
|
||||
@@ -259,6 +296,51 @@ const MainPageConsultation = () => {
|
||||
placeholder="Tìm kiếm phiên khám..."
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FilterCustom<string | null>
|
||||
name="Chuyên khoa"
|
||||
value={_specialtyId}
|
||||
onChange={(value) => updateQuery("_specialtyId", value ?? "")}
|
||||
listOption={useMemo(() => {
|
||||
return (
|
||||
specialtyQuery.data?.map((item) => ({
|
||||
uuid: item.id,
|
||||
name: item.name,
|
||||
})) || []
|
||||
);
|
||||
}, [specialtyQuery.data])}
|
||||
/>
|
||||
<FilterCustom<number | null>
|
||||
name="Trạng thái"
|
||||
value={_status ? Number(_status) : null}
|
||||
onChange={(value) => updateQuery("_status", value ?? "")}
|
||||
listOption={[
|
||||
{
|
||||
uuid: TYPE_STATUS.Draft,
|
||||
name: "Đang chờ khám",
|
||||
},
|
||||
{
|
||||
uuid: TYPE_STATUS.InProgress,
|
||||
name: "Đang khám tổng quát",
|
||||
},
|
||||
{
|
||||
uuid: TYPE_STATUS.ToSpecialty,
|
||||
name: "Chờ khám chuyên khoa",
|
||||
},
|
||||
{
|
||||
uuid: TYPE_STATUS.PendingPrescription,
|
||||
name: "Chờ nhận thuốc/kính",
|
||||
},
|
||||
{
|
||||
uuid: TYPE_STATUS.Completed,
|
||||
name: "Hoàn thành",
|
||||
},
|
||||
{
|
||||
uuid: TYPE_STATUS.Cancelled,
|
||||
name: "Đã hủy",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* TABLE */}
|
||||
@@ -295,8 +377,13 @@ const MainPageConsultation = () => {
|
||||
|
||||
{
|
||||
title: "NGÀY KHÁM",
|
||||
|
||||
render: (item: ConsultationItem) => <span>{item.visitDate}</span>,
|
||||
render: (item: ConsultationItem) => (
|
||||
<span>
|
||||
{item.visitDate
|
||||
? moment(item.visitDate).format("DD/MM/YYYY")
|
||||
: "---"}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
@@ -330,7 +417,30 @@ const MainPageConsultation = () => {
|
||||
<span>{item.doctorNotes || "---"}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "CÁC CHUYÊN KHOA ĐANG CHỜ KHÁM",
|
||||
|
||||
render: (item: ConsultationItem) => {
|
||||
const waitingSpecialties = item.specialtyClinics
|
||||
?.filter((specialty) => specialty.specialtyStatus === 1)
|
||||
.map((specialty) => specialty.specialtyName)
|
||||
.join(", ");
|
||||
|
||||
return <span>{waitingSpecialties || "---"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "CÁC CHUYÊN KHOA ĐÃ KHÁM",
|
||||
|
||||
render: (item: ConsultationItem) => {
|
||||
const completedSpecialties = item.specialtyClinics
|
||||
?.filter((specialty) => specialty.specialtyStatus === 3)
|
||||
.map((specialty) => specialty.specialtyName)
|
||||
.join(", ");
|
||||
|
||||
return <span>{completedSpecialties || "---"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "TRẠNG THÁI",
|
||||
|
||||
@@ -340,29 +450,44 @@ const MainPageConsultation = () => {
|
||||
listState={[
|
||||
{
|
||||
state: TYPE_STATUS.Draft,
|
||||
text: "Đang chờ",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#FFE4C4",
|
||||
text: "Đang chờ khám",
|
||||
textColor: "#92400E",
|
||||
backgroundColor: "#FEF3C7",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.InProgress,
|
||||
text: "Đang thực hiện",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#ff3300",
|
||||
text: "Đang khám tổng quát",
|
||||
textColor: "#1E3A8A",
|
||||
backgroundColor: "#DBEAFE",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.ToSpecialty,
|
||||
text: "Chờ khám chuyên khoa",
|
||||
textColor: "#6B21A8",
|
||||
backgroundColor: "#E9D5FF",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.PendingPrescription,
|
||||
text: "Chờ nhận thuốc/kính",
|
||||
textColor: "#9A3412",
|
||||
backgroundColor: "#FED7AA",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.Completed,
|
||||
text: "Hoàn thành",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#3d69eb",
|
||||
textColor: "#166534",
|
||||
backgroundColor: "#DCFCE7",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.Cancelled,
|
||||
text: "Đã hủy",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#cccc",
|
||||
textColor: "#991B1B",
|
||||
backgroundColor: "#FEE2E2",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@@ -381,15 +506,32 @@ const MainPageConsultation = () => {
|
||||
|
||||
const isDisabled = isCancelled || isCompleted;
|
||||
|
||||
// Tìm chuyên khoa có specialtyStatus = 1
|
||||
const specialtyClinicActive = item.specialtyClinics?.find(
|
||||
(specialty) => specialty.specialtyStatus === 1,
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
{/* UPDATE */}
|
||||
<CustomButton
|
||||
size="sm"
|
||||
disabled={isDisabled}
|
||||
icon={<Pencil className="text-blue-400" />}
|
||||
href={`/consultation/update?_id=${item?.id}`}
|
||||
/>
|
||||
icon={
|
||||
specialtyClinicActive ? undefined : (
|
||||
<Pencil className="text-blue-400" />
|
||||
)
|
||||
}
|
||||
href={
|
||||
specialtyClinicActive
|
||||
? `/consultation/update-specialty?_id=${item.id}&specialtyClinicId=${specialtyClinicActive.id}`
|
||||
: `/consultation/update?_id=${item.id}`
|
||||
}
|
||||
>
|
||||
{specialtyClinicActive
|
||||
? `Cập nhật ${specialtyClinicActive.specialtyName}`
|
||||
: undefined}
|
||||
</CustomButton>
|
||||
|
||||
{/* CANCEL */}
|
||||
<CustomButton
|
||||
@@ -423,7 +565,7 @@ const MainPageConsultation = () => {
|
||||
pageSize={pageSize}
|
||||
onSetPage={(value) => updateQuery("_page", value)}
|
||||
onSetPageSize={(value) => updateQuery("_pageSize", value)}
|
||||
dependencies={[_pageSize, _keyword]}
|
||||
dependencies={[_pageSize, _keyword, _specialtyId, _status]}
|
||||
/>
|
||||
|
||||
{/* CANCEL DIALOG */}
|
||||
|
||||
@@ -18,6 +18,7 @@ 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";
|
||||
import moment from "moment";
|
||||
|
||||
const TableHistoryPatient = () => {
|
||||
const searchParams = useSearchParams();
|
||||
@@ -129,7 +130,13 @@ const TableHistoryPatient = () => {
|
||||
},
|
||||
{
|
||||
title: "NGÀY KHÁM",
|
||||
render: (item: ConsultationItem) => <span>{item.visitDate}</span>,
|
||||
render: (item: ConsultationItem) => (
|
||||
<span>
|
||||
{item.visitDate
|
||||
? moment(item.visitDate).format("DD/MM/YYYY")
|
||||
: "---"}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "DẤU HIỆU",
|
||||
@@ -151,27 +158,44 @@ const TableHistoryPatient = () => {
|
||||
listState={[
|
||||
{
|
||||
state: TYPE_STATUS.Draft,
|
||||
text: "Đang chờ",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#FFE4C4",
|
||||
text: "Đang chờ khám",
|
||||
textColor: "#92400E",
|
||||
backgroundColor: "#FEF3C7",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.InProgress,
|
||||
text: "Đang thực hiện",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#ff3300",
|
||||
text: "Đang khám tổng quát",
|
||||
textColor: "#1E3A8A",
|
||||
backgroundColor: "#DBEAFE",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.ToSpecialty,
|
||||
text: "Chờ khám chuyên khoa",
|
||||
textColor: "#6B21A8",
|
||||
backgroundColor: "#E9D5FF",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.PendingPrescription,
|
||||
text: "Chờ nhận thuốc/kính",
|
||||
textColor: "#9A3412",
|
||||
backgroundColor: "#FED7AA",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.Completed,
|
||||
text: "Hoàn thành",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#3d69eb",
|
||||
textColor: "#166534",
|
||||
backgroundColor: "#DCFCE7",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.Cancelled,
|
||||
text: "Đã hủy",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#cccccc",
|
||||
textColor: "#991B1B",
|
||||
backgroundColor: "#FEE2E2",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -27,6 +27,7 @@ interface IUpdateConsul {
|
||||
diagnosis: string;
|
||||
treatmentPlan: string;
|
||||
doctorNotes: string;
|
||||
isGlassesDelivered: boolean;
|
||||
}
|
||||
|
||||
/* =========================
|
||||
@@ -39,6 +40,7 @@ const defaultForm: IUpdateConsul = {
|
||||
diagnosis: "",
|
||||
treatmentPlan: "",
|
||||
doctorNotes: "",
|
||||
isGlassesDelivered: false,
|
||||
};
|
||||
|
||||
/* =========================
|
||||
@@ -103,6 +105,7 @@ const UpdateConsultation = () => {
|
||||
diagnosis: consul.diagnosis || "",
|
||||
treatmentPlan: consul.treatmentPlan || "",
|
||||
doctorNotes: consul.doctorNotes || "",
|
||||
isGlassesDelivered: consul.isGlassesDelivered,
|
||||
});
|
||||
}, [consulDetailQuery.data]);
|
||||
|
||||
@@ -126,6 +129,7 @@ const UpdateConsultation = () => {
|
||||
diagnosis: form.diagnosis,
|
||||
treatmentPlan: form.treatmentPlan,
|
||||
doctorNotes: form.doctorNotes,
|
||||
isGlassesDelivered: form?.isGlassesDelivered,
|
||||
}),
|
||||
});
|
||||
},
|
||||
|
||||
@@ -0,0 +1,341 @@
|
||||
"use client";
|
||||
|
||||
import CustomButton from "@/components/customs/custom-button";
|
||||
import GridColumn from "@/components/layouts/GridColumn";
|
||||
import FormCustom from "@/components/utils/FormCustom";
|
||||
import InputForm from "@/components/utils/FormCustom/components/InputForm";
|
||||
import TextArea from "@/components/utils/FormCustom/components/TextArea";
|
||||
import { PATH } from "@/constant/config";
|
||||
import { QUERY_KEY } from "@/constant/config/enum";
|
||||
import { httpRequest } from "@/services";
|
||||
import consultationServices, {
|
||||
ConsultationDetail,
|
||||
} from "@/services/consultationServices";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useParams, useRouter, useSearchParams } from "next/navigation";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
const UpdateSpecialtyClinicId = () => {
|
||||
const router = useRouter();
|
||||
const params = useParams();
|
||||
const searchParams = useSearchParams();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const consultationId = searchParams.get("_id") || "";
|
||||
const specialtyClinicId = searchParams.get("specialtyClinicId") || "";
|
||||
|
||||
const [form, setForm] = useState<{
|
||||
specialtyAssignmentId: string;
|
||||
specialtyNotes: string;
|
||||
diagnosis: string;
|
||||
procedureNotes: string;
|
||||
glassRequired: boolean;
|
||||
glassType: string;
|
||||
}>({
|
||||
specialtyAssignmentId: "",
|
||||
specialtyNotes: "",
|
||||
diagnosis: "",
|
||||
procedureNotes: "",
|
||||
glassRequired: false,
|
||||
glassType: "",
|
||||
});
|
||||
|
||||
/* =========================
|
||||
GET DETAIL API
|
||||
========================= */
|
||||
const consulDetailQuery = useQuery<ConsultationDetail>({
|
||||
queryKey: [QUERY_KEY.chi_tiet_phien_kham, consultationId],
|
||||
enabled: !!consultationId,
|
||||
queryFn: async () => {
|
||||
const res = await httpRequest<ConsultationDetail>({
|
||||
showMessageFailed: true,
|
||||
http: consultationServices.detailConsultations(consultationId),
|
||||
});
|
||||
|
||||
return (
|
||||
res || {
|
||||
id: "",
|
||||
patientId: "",
|
||||
sessionCode: "",
|
||||
visitDate: "",
|
||||
status: 1,
|
||||
chiefComplaint: null,
|
||||
symptomsText: null,
|
||||
vitalSigns: null,
|
||||
diagnosis: null,
|
||||
treatmentPlan: null,
|
||||
doctorNotes: null,
|
||||
createdBy: "",
|
||||
isDeleted: false,
|
||||
specialtyClinics: [
|
||||
{
|
||||
id: "",
|
||||
specialtyId: "",
|
||||
specialtyName: "",
|
||||
specialtyNotes: null,
|
||||
diagnosis: null,
|
||||
procedureNotes: null,
|
||||
glassRequired: null,
|
||||
glassType: null,
|
||||
examinerName: "",
|
||||
specialtyStatus: 1,
|
||||
sharedItems: [],
|
||||
},
|
||||
],
|
||||
aggregatedPrescriptionItems: [],
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
// Tìm chuyên khoa hiện tại từ data trả về
|
||||
const selectedSpecialtyClinic =
|
||||
consulDetailQuery.data?.specialtyClinics?.find(
|
||||
(item) => item.id === specialtyClinicId,
|
||||
);
|
||||
|
||||
/**
|
||||
* ĐIỀU KIỆN KIỂM TRA KHOA MẮT
|
||||
* Bạn hãy thay đổi điều kiện này tùy thuộc vào database của bạn.
|
||||
* Ví dụ: selectedSpecialtyClinic?.specialtyId === "MẮT" hoặc kiểm tra theo tên.
|
||||
*/
|
||||
const isEyeClinic =
|
||||
selectedSpecialtyClinic?.specialtyName?.toLowerCase().includes("mắt") ||
|
||||
selectedSpecialtyClinic?.specialtyId?.toLowerCase().includes("mat");
|
||||
|
||||
useEffect(() => {
|
||||
const consul = consulDetailQuery.data;
|
||||
if (!consul) return;
|
||||
|
||||
const specialtyClinic = consul.specialtyClinics?.find(
|
||||
(item) => item.id === specialtyClinicId,
|
||||
);
|
||||
|
||||
if (!specialtyClinic) return;
|
||||
|
||||
setForm({
|
||||
specialtyAssignmentId: specialtyClinic.id || "",
|
||||
specialtyNotes: specialtyClinic.specialtyNotes || "",
|
||||
diagnosis: specialtyClinic.diagnosis || "",
|
||||
procedureNotes: specialtyClinic.procedureNotes || "",
|
||||
glassRequired: specialtyClinic.glassRequired || false,
|
||||
glassType: specialtyClinic.glassType || "",
|
||||
});
|
||||
}, [consulDetailQuery.data, specialtyClinicId]);
|
||||
|
||||
/* =========================
|
||||
UPDATE MUTATION
|
||||
========================= */
|
||||
const specialtyResultsMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
if (!consultationId) {
|
||||
throw new Error("Không tìm thấy ID phiên khám!");
|
||||
}
|
||||
|
||||
return httpRequest({
|
||||
showMessageFailed: true,
|
||||
showMessageSuccess: true,
|
||||
msgSuccess: "Cập nhật phiên khám thành công!",
|
||||
http: consultationServices.specialtyResults(
|
||||
form.specialtyAssignmentId,
|
||||
{
|
||||
specialtyNotes: form.specialtyNotes,
|
||||
diagnosis: form.diagnosis,
|
||||
procedureNotes: form.procedureNotes,
|
||||
// Nếu không phải khoa mắt, gán mặc định false và chuỗi rỗng khi gửi API
|
||||
glassRequired: isEyeClinic ? form.glassRequired : false,
|
||||
glassType: isEyeClinic ? form.glassType : "",
|
||||
},
|
||||
),
|
||||
});
|
||||
},
|
||||
onSuccess(data) {
|
||||
if (!data) return;
|
||||
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [QUERY_KEY.table_list_consultation],
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [QUERY_KEY.chi_tiet_phien_kham, consultationId],
|
||||
});
|
||||
|
||||
router.push(PATH.CONSULTATION || "/consultation");
|
||||
},
|
||||
});
|
||||
|
||||
const handleSubmit = () => {
|
||||
specialtyResultsMutation.mutate();
|
||||
};
|
||||
|
||||
const isLoading =
|
||||
consulDetailQuery.isLoading || specialtyResultsMutation.isPending;
|
||||
|
||||
if (consulDetailQuery.isLoading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center p-10 font-medium text-gray-500">
|
||||
Đang tải dữ liệu phiên khám...
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<FormCustom form={form} setForm={setForm} onSubmit={handleSubmit}>
|
||||
<div className="flex flex-col gap-6 rounded-2xl bg-white p-6 shadow-xl">
|
||||
{/* HEADER */}
|
||||
<div className="flex items-center justify-between border-b pb-5">
|
||||
<div>
|
||||
<h2 className="text-[24px] font-bold text-[#111827]">
|
||||
Phiên khám chuyên khoa
|
||||
</h2>
|
||||
<p className="mt-1 text-sm text-[#697586]">
|
||||
Cập nhật kết quả chi tiết quá trình khám bệnh của bệnh nhân
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* CHUYÊN KHOA INFO */}
|
||||
<InputForm
|
||||
label="Chuyên khoa đảm nhận"
|
||||
name="specialtyAssignmentId"
|
||||
type="text"
|
||||
value={
|
||||
selectedSpecialtyClinic
|
||||
? `${selectedSpecialtyClinic.specialtyName}`
|
||||
: "Chưa có thông tin chuyên khoa"
|
||||
}
|
||||
placeholder="Thông tin chuyên khoa"
|
||||
isRequired
|
||||
readOnly
|
||||
/>
|
||||
|
||||
{/* KHỐI THÔNG TIN KHÁM CHUNG (Luôn cố định 3 cột đẹp mắt) */}
|
||||
<div className="mt-2">
|
||||
<h3 className="mb-4 text-sm font-semibold uppercase tracking-wider text-gray-400">
|
||||
Thông tin khám chung
|
||||
</h3>
|
||||
<GridColumn col={3}>
|
||||
<InputForm
|
||||
label="Ghi chú chuyên khoa"
|
||||
name="specialtyNotes"
|
||||
type="text"
|
||||
value={form.specialtyNotes}
|
||||
placeholder="Nhập ghi chú chuyên khoa"
|
||||
isRequired
|
||||
onChangeValue={(v) =>
|
||||
setForm((prev) => ({ ...prev, specialtyNotes: String(v) }))
|
||||
}
|
||||
/>
|
||||
<InputForm
|
||||
type="text"
|
||||
label="Chuẩn đoán chuyên khoa"
|
||||
name="diagnosis"
|
||||
placeholder="Nhập Chuẩn đoán"
|
||||
isRequired
|
||||
value={form.diagnosis}
|
||||
onChangeValue={(v) =>
|
||||
setForm((prev) => ({ ...prev, diagnosis: String(v) }))
|
||||
}
|
||||
/>
|
||||
<InputForm
|
||||
type="text"
|
||||
label="Ghi chú thủ thuật / can thiệp"
|
||||
name="procedureNotes"
|
||||
placeholder="Nhập ghi chú thủ thuật / can thiệp"
|
||||
value={form.procedureNotes}
|
||||
isRequired
|
||||
onChangeValue={(v) =>
|
||||
setForm((prev) => ({ ...prev, procedureNotes: String(v) }))
|
||||
}
|
||||
/>
|
||||
</GridColumn>
|
||||
</div>
|
||||
|
||||
{/* KHỐI THÔNG TIN KHÁM MẮT (Chỉ hiển thị khi là khoa mắt) */}
|
||||
{isEyeClinic && (
|
||||
<div className="mt-2 rounded-xl border border-blue-100 bg-[#f8fafc] p-5 transition-all">
|
||||
<h3 className="mb-4 text-sm font-bold uppercase tracking-wider text-blue-600">
|
||||
Chỉ định thị lực (Khoa Mắt)
|
||||
</h3>
|
||||
|
||||
<div className="flex flex-col gap-5">
|
||||
{/* Radio Chọn Có/Không */}
|
||||
<div>
|
||||
<label className="text-sm font-medium text-gray-700">
|
||||
Bệnh nhân có chỉ định đeo kính không?
|
||||
</label>
|
||||
<div className="mt-2.5 flex items-center gap-8">
|
||||
<label className="flex cursor-pointer items-center gap-2 text-sm font-medium text-gray-900">
|
||||
<input
|
||||
type="radio"
|
||||
name="glassRequired"
|
||||
className="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-500"
|
||||
checked={form.glassRequired === true}
|
||||
onChange={() =>
|
||||
setForm((prev) => ({ ...prev, glassRequired: true }))
|
||||
}
|
||||
/>
|
||||
Có chỉ định
|
||||
</label>
|
||||
|
||||
<label className="flex cursor-pointer items-center gap-2 text-sm font-medium text-gray-900">
|
||||
<input
|
||||
type="radio"
|
||||
name="glassRequired"
|
||||
className="h-4 w-4 border-gray-300 text-blue-600 focus:ring-blue-500"
|
||||
checked={form.glassRequired === false}
|
||||
onChange={() =>
|
||||
setForm((prev) => ({ ...prev, glassRequired: false }))
|
||||
}
|
||||
/>
|
||||
Không chỉ định
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* TextArea Loại Kính (Trải rộng ra 100% dòng tạo cảm giác thoáng đãng) */}
|
||||
{form.glassRequired && (
|
||||
<div className="mt-2 animate-fadeIn ">
|
||||
<TextArea
|
||||
name="glassType"
|
||||
placeholder="Nhập thông số chi tiết loại kính được chỉ định (Cận, viễn, loạn, độ kính...)"
|
||||
label="Thông số / Loại kính chỉ định"
|
||||
value={form.glassType}
|
||||
isRequired
|
||||
isBlur
|
||||
max={5000}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* BUTTON ACTION */}
|
||||
<div className="mt-4 flex items-center justify-end gap-3 border-t pt-5">
|
||||
<CustomButton
|
||||
type="button"
|
||||
variant="grey"
|
||||
rounded="md"
|
||||
onClick={() => router.back()}
|
||||
className="min-w-[120px]"
|
||||
>
|
||||
Hủy bỏ
|
||||
</CustomButton>
|
||||
<CustomButton
|
||||
type="submit"
|
||||
variant="midnightBlue"
|
||||
rounded="md"
|
||||
disabled={isLoading || !consultationId}
|
||||
className="min-w-[140px]"
|
||||
>
|
||||
{specialtyResultsMutation.isPending
|
||||
? "Đang cập nhật..."
|
||||
: "Cập nhật kết quả"}
|
||||
</CustomButton>
|
||||
</div>
|
||||
</div>
|
||||
</FormCustom>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateSpecialtyClinicId;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "./UpdateSpecialtyClinicId";
|
||||
@@ -20,18 +20,16 @@ import CustomButton from "@/components/customs/custom-button";
|
||||
import StateActive from "@/components/customs/StateActive";
|
||||
import DataWrapper from "@/components/customs/DataWrapper";
|
||||
import Table from "@/components/customs/custom-table";
|
||||
import CustomDialog from "@/components/customs/custom-dialog";
|
||||
import moment from "moment";
|
||||
// import CustomDialog from "@/components/customs/custom-dialog";
|
||||
|
||||
const DetailPatient = () => {
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
const queryClient = useQueryClient();
|
||||
// const queryClient = useQueryClient();
|
||||
|
||||
const patientId = params?.id as string;
|
||||
|
||||
// State quản lý đóng/mở Dialog xác nhận tạo phiên khám
|
||||
const [openCreateDialog, setOpenCreateDialog] = useState<boolean>(false);
|
||||
|
||||
/* =========================
|
||||
GET DETAIL PATIENT
|
||||
========================= */
|
||||
@@ -95,54 +93,9 @@ const DetailPatient = () => {
|
||||
},
|
||||
});
|
||||
|
||||
/* =========================
|
||||
CREATE MUTATION
|
||||
========================= */
|
||||
const createConsultationMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
return httpRequest({
|
||||
showMessageFailed: true,
|
||||
showMessageSuccess: true,
|
||||
msgSuccess: "Tạo phiên khám mới thành công!",
|
||||
// Gọi API với payload chứa patientId của bệnh nhân hiện tại
|
||||
http: consultationServices.createConsultations({
|
||||
patientId: patientId,
|
||||
}),
|
||||
});
|
||||
},
|
||||
onSuccess: (res: any) => {
|
||||
// Đóng dialog
|
||||
setOpenCreateDialog(false);
|
||||
|
||||
// Làm mới danh sách lịch sử phiên khám của bệnh nhân này
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [QUERY_KEY.table_list_consultation, patientId],
|
||||
});
|
||||
|
||||
if (res?.id) {
|
||||
router.push(`${PATH.CONSULTATION}/${res.id}`); // detail
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const patient = patientDetailQuery.data;
|
||||
const consultationData = consultationQuery.data?.items || [];
|
||||
|
||||
/* =========================
|
||||
HANDLERS DIALOG
|
||||
========================= */
|
||||
const handleOpenCreate = () => {
|
||||
setOpenCreateDialog(true);
|
||||
};
|
||||
|
||||
const handleCloseDialog = () => {
|
||||
setOpenCreateDialog(false);
|
||||
};
|
||||
|
||||
const handleCreateDialog = () => {
|
||||
createConsultationMutation.mutate();
|
||||
};
|
||||
|
||||
if (patientDetailQuery.isLoading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center p-10 font-medium text-gray-500">
|
||||
@@ -169,8 +122,11 @@ const DetailPatient = () => {
|
||||
variant="midnightBlue"
|
||||
fullWidth={false}
|
||||
icon={<ClipboardPlus size={18} />}
|
||||
onClick={handleOpenCreate}
|
||||
disabled={createConsultationMutation.isPending}
|
||||
onClick={() =>
|
||||
router.push(
|
||||
`${PATH.CONSULTATION}/create?patientId=${patient?.id}`,
|
||||
)
|
||||
}
|
||||
>
|
||||
Tạo phiên khám
|
||||
</CustomButton>
|
||||
@@ -209,7 +165,9 @@ const DetailPatient = () => {
|
||||
Ngày sinh
|
||||
</p>
|
||||
<p className="text-[15px] font-medium text-[#202939]">
|
||||
{patient?.dateOfBirth}
|
||||
{patient?.dateOfBirth
|
||||
? moment(patient?.dateOfBirth).format("DD/MM/YYYY")
|
||||
: "---"}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -289,7 +247,7 @@ const DetailPatient = () => {
|
||||
<div className="rounded-2xl border border-gray-200 bg-white p-6 shadow-sm">
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-black">
|
||||
Lịch sử phiên khám
|
||||
Lịch sử phiên khám của {patient?.fullName}
|
||||
</h2>
|
||||
<Link
|
||||
href={`/consultation/history?_id=${patientId}`}
|
||||
@@ -308,6 +266,14 @@ const DetailPatient = () => {
|
||||
rowKey={(item) => item.id}
|
||||
data={consultationData}
|
||||
column={[
|
||||
{
|
||||
title: "TÊN BỆNH NHÂN",
|
||||
|
||||
render: (item: ConsultationItem) => (
|
||||
<span>{item.patientName}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: "MÃ PHIÊN KHÁM",
|
||||
fixedLeft: true,
|
||||
@@ -320,65 +286,120 @@ const DetailPatient = () => {
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: "NGÀY KHÁM",
|
||||
render: (item: ConsultationItem) => (
|
||||
<span>{item.visitDate}</span>
|
||||
<span>
|
||||
{item.visitDate
|
||||
? moment(item.visitDate).format("DD/MM/YYYY")
|
||||
: "---"}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: "DẤU HIỆU",
|
||||
|
||||
render: (item: ConsultationItem) => (
|
||||
<span>{item.symptomsText || "---"}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: "CHUẨN ĐOÁN",
|
||||
|
||||
render: (item: ConsultationItem) => (
|
||||
<span>{item.diagnosis || "---"}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: "KẾ HOẠCH ĐIỀU TRỊ",
|
||||
|
||||
render: (item: ConsultationItem) => (
|
||||
<span>{item.treatmentPlan || "---"}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: "GHI CHÚ BÁC SĨ",
|
||||
|
||||
render: (item: ConsultationItem) => (
|
||||
<span>{item.doctorNotes || "---"}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "CÁC CHUYÊN KHOA ĐANG CHỜ KHÁM",
|
||||
|
||||
render: (item: ConsultationItem) => {
|
||||
const waitingSpecialties = item.specialtyClinics
|
||||
?.filter((specialty) => specialty.specialtyStatus === 1)
|
||||
.map((specialty) => specialty.specialtyName)
|
||||
.join(", ");
|
||||
|
||||
return <span>{waitingSpecialties || "---"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "CÁC CHUYÊN KHOA ĐÃ KHÁM",
|
||||
|
||||
render: (item: ConsultationItem) => {
|
||||
const completedSpecialties = item.specialtyClinics
|
||||
?.filter((specialty) => specialty.specialtyStatus === 3)
|
||||
.map((specialty) => specialty.specialtyName)
|
||||
.join(", ");
|
||||
|
||||
return <span>{completedSpecialties || "---"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: "TRẠNG THÁI",
|
||||
fixedRight: true,
|
||||
render: (item: ConsultationItem) => (
|
||||
<StateActive
|
||||
stateActive={item.status}
|
||||
listState={[
|
||||
{
|
||||
state: TYPE_STATUS.Draft,
|
||||
text: "Đang chờ",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#FFE4C4",
|
||||
text: "Đang chờ khám",
|
||||
textColor: "#92400E",
|
||||
backgroundColor: "#FEF3C7",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.InProgress,
|
||||
text: "Đang thực hiện",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#ff3300",
|
||||
text: "Đang khám tổng quát",
|
||||
textColor: "#1E3A8A",
|
||||
backgroundColor: "#DBEAFE",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.ToSpecialty,
|
||||
text: "Chờ khám chuyên khoa",
|
||||
textColor: "#6B21A8",
|
||||
backgroundColor: "#E9D5FF",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.PendingPrescription,
|
||||
text: "Chờ nhận thuốc/kính",
|
||||
textColor: "#9A3412",
|
||||
backgroundColor: "#FED7AA",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.Completed,
|
||||
text: "Hoàn thành",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#3d69eb",
|
||||
textColor: "#166534",
|
||||
backgroundColor: "#DCFCE7",
|
||||
},
|
||||
|
||||
{
|
||||
state: TYPE_STATUS.Cancelled,
|
||||
text: "Đã hủy",
|
||||
textColor: "#000",
|
||||
backgroundColor: "#cccc",
|
||||
textColor: "#991B1B",
|
||||
backgroundColor: "#FEE2E2",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@@ -388,20 +409,6 @@ const DetailPatient = () => {
|
||||
/>
|
||||
</DataWrapper>
|
||||
</div>
|
||||
|
||||
{/* DIALOG XÁC NHẬN */}
|
||||
<CustomDialog
|
||||
open={openCreateDialog}
|
||||
title="Tạo phiên khám"
|
||||
note={`Bạn có chắc chắn muốn tạo phiên khám cho bệnh nhân ${patient?.fullName} không?`}
|
||||
type="successPlay" // Giữ nguyên type của bạn, hoặc đổi thành "warning"/"info" tùy UI component quy định
|
||||
onClose={handleCloseDialog}
|
||||
onSubmit={handleCreateDialog}
|
||||
titleCancel="Đóng"
|
||||
titleSubmit={
|
||||
createConsultationMutation.isPending ? "Đang xử lý..." : "Xác nhận"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -221,7 +221,7 @@ const MainPagePatient = () => {
|
||||
href={`/patient/${item.id}`}
|
||||
className="text-blue-500 hover:underline"
|
||||
>
|
||||
{item.fullName}
|
||||
{item.fullName || "---"}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
@@ -230,26 +230,28 @@ const MainPagePatient = () => {
|
||||
title: "MÃ ĐỊNH DANH",
|
||||
|
||||
render: (item: PatientItem) => (
|
||||
<span>{item.identificationNumber}</span>
|
||||
<span>{item.identificationNumber || "---"}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: "SỐ ĐIỆN THOẠI",
|
||||
|
||||
render: (item: PatientItem) => <span>{item.phone}</span>,
|
||||
render: (item: PatientItem) => <span>{item.phone || "---"}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
title: "EMAIL",
|
||||
|
||||
render: (item: PatientItem) => <span>{item.email}</span>,
|
||||
render: (item: PatientItem) => <span>{item.email || "---"}</span>,
|
||||
},
|
||||
|
||||
{
|
||||
title: "GIỚI TÍNH",
|
||||
|
||||
render: (item: PatientItem) => <span>{item.gender}</span>,
|
||||
render: (item: PatientItem) => (
|
||||
<span>{item.gender || "---"}</span>
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
@@ -286,7 +286,7 @@ const PopupUpdatePatient = ({ onClose, id }: PopupUpdatePatientProps) => {
|
||||
}
|
||||
placeholder="Số điện thoại"
|
||||
name="phone"
|
||||
type="number"
|
||||
type="phone"
|
||||
isPhone
|
||||
value={form.phone}
|
||||
isRequired
|
||||
@@ -324,7 +324,7 @@ const PopupUpdatePatient = ({ onClose, id }: PopupUpdatePatientProps) => {
|
||||
label="SĐT khẩn cấp"
|
||||
placeholder="SĐT khẩn cấp"
|
||||
name="emergencyContactPhone"
|
||||
type="number"
|
||||
type="phone"
|
||||
isRequired
|
||||
isPhone
|
||||
value={form.emergencyContactPhone}
|
||||
|
||||
@@ -1,44 +1,26 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from "react";
|
||||
|
||||
import { Plus, Trash2 } from "lucide-react";
|
||||
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
import CustomButton from "@/components/customs/custom-button";
|
||||
|
||||
import FormCustom from "@/components/utils/FormCustom";
|
||||
|
||||
import InputForm from "@/components/utils/FormCustom/components/InputForm";
|
||||
|
||||
import TextArea from "@/components/utils/FormCustom/components/TextArea";
|
||||
|
||||
import SelectForm from "@/components/utils/FormCustom/components/SelectForm";
|
||||
|
||||
import UploadImage from "@/components/utils/UploadImage";
|
||||
|
||||
import { httpRequest } from "@/services";
|
||||
|
||||
import prescriptionServices from "@/services/prescriptionServices";
|
||||
|
||||
import consultationServices, {
|
||||
ConsultationItem,
|
||||
ConsultationResponse,
|
||||
} from "@/services/consultationServices";
|
||||
|
||||
import { QUERY_KEY, TYPE_STATUS } from "@/constant/config/enum";
|
||||
|
||||
import { QUERY_KEY } from "@/constant/config/enum";
|
||||
import { toastWarn } from "@/common/funcs/toast";
|
||||
|
||||
import { PATH } from "@/constant/config";
|
||||
|
||||
/* =========================
|
||||
TYPES
|
||||
========================= */
|
||||
|
||||
interface PrescriptionItem {
|
||||
medicineName: string;
|
||||
dosage: string;
|
||||
@@ -48,15 +30,15 @@ interface PrescriptionItem {
|
||||
}
|
||||
|
||||
interface PrescriptionForm {
|
||||
examinationSessionId: string;
|
||||
examinationSessionSpecialtyId: string;
|
||||
notes: string;
|
||||
prescriptionImg: string;
|
||||
items: PrescriptionItem[];
|
||||
}
|
||||
|
||||
/* =========================
|
||||
DEFAULT
|
||||
========================= */
|
||||
|
||||
const defaultMedicine: PrescriptionItem = {
|
||||
medicineName: "",
|
||||
dosage: "",
|
||||
@@ -68,29 +50,28 @@ const defaultMedicine: PrescriptionItem = {
|
||||
/* =========================
|
||||
COMPONENT
|
||||
========================= */
|
||||
|
||||
const CreatePrescription = () => {
|
||||
const router = useRouter();
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const queryKeys = [QUERY_KEY.table_list_consultation];
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
|
||||
const [form, setForm] = useState<PrescriptionForm>({
|
||||
examinationSessionId: "",
|
||||
examinationSessionSpecialtyId: "",
|
||||
notes: "",
|
||||
prescriptionImg: "",
|
||||
items: [defaultMedicine],
|
||||
});
|
||||
|
||||
/* =========================
|
||||
GET EXAMINATION SESSION
|
||||
GET EXAMINATION SESSION
|
||||
========================= */
|
||||
|
||||
const examinationSessionQuery = useQuery<ConsultationResponse>({
|
||||
queryKey: [QUERY_KEY.table_list_consultation],
|
||||
|
||||
queryFn: async () => {
|
||||
const res = await httpRequest<ConsultationResponse>({
|
||||
showMessageFailed: true,
|
||||
|
||||
http: consultationServices.getConsultations({
|
||||
Page: 1,
|
||||
PageSize: 100,
|
||||
@@ -112,92 +93,82 @@ const CreatePrescription = () => {
|
||||
});
|
||||
|
||||
const examinationSessionOptions =
|
||||
examinationSessionQuery.data?.items?.filter(
|
||||
(item) =>
|
||||
item.status === TYPE_STATUS.Draft ||
|
||||
item.status === TYPE_STATUS.InProgress,
|
||||
) || [];
|
||||
examinationSessionQuery.data?.items
|
||||
?.filter((session) => {
|
||||
const isWaitingPrescription = session.status === 4;
|
||||
const allSpecialtyCompleted = session.specialtyClinics?.every(
|
||||
(specialty) => specialty.specialtyStatus === 3,
|
||||
);
|
||||
return isWaitingPrescription && allSpecialtyCompleted;
|
||||
})
|
||||
.flatMap((session) =>
|
||||
session.specialtyClinics
|
||||
.filter(
|
||||
(specialty) =>
|
||||
specialty.specialtyStatus === 3 &&
|
||||
specialty.sharedItems.length === 0,
|
||||
)
|
||||
.map((specialty) => ({
|
||||
id: specialty.id,
|
||||
specialtyName: specialty.specialtyName,
|
||||
sessionCode: session.sessionCode,
|
||||
patientName: session.patientName,
|
||||
})),
|
||||
) || [];
|
||||
|
||||
/* =========================
|
||||
CREATE MUTATION
|
||||
CREATE MUTATION
|
||||
========================= */
|
||||
const funcCreatePrescription = useMutation({
|
||||
mutationFn: (payload: any) => {
|
||||
console.log("=== GỬI PAYLOAD LÊN API TẠO ĐƠN THUỐC ===", payload);
|
||||
|
||||
const createPrescriptionMutation = useMutation({
|
||||
mutationFn: async () => {
|
||||
/**
|
||||
* CREATE FORMDATA
|
||||
*/
|
||||
const formData = new FormData();
|
||||
|
||||
/**
|
||||
* BASIC INFO
|
||||
*/
|
||||
formData.append("ExaminationSessionId", form.examinationSessionId);
|
||||
|
||||
formData.append("Notes", form.notes);
|
||||
|
||||
/**
|
||||
* FILE
|
||||
*/
|
||||
if (file) {
|
||||
formData.append("PrescriptionFile", file);
|
||||
}
|
||||
|
||||
/**
|
||||
* ITEMS
|
||||
* BACKEND EXPECT:
|
||||
* Items = JSON.stringify([...])
|
||||
*/
|
||||
const validItems = form.items.filter((x) => x.medicineName.trim() !== "");
|
||||
|
||||
formData.append("Items", JSON.stringify(validItems));
|
||||
|
||||
/**
|
||||
* API
|
||||
*/
|
||||
return await httpRequest({
|
||||
return httpRequest({
|
||||
showMessageFailed: true,
|
||||
|
||||
showMessageSuccess: true,
|
||||
|
||||
msgSuccess: "Tạo đơn thuốc thành công!",
|
||||
|
||||
http: prescriptionServices.createPrescription(formData),
|
||||
http: prescriptionServices.createPrescription(payload),
|
||||
});
|
||||
},
|
||||
|
||||
onSuccess: () => {
|
||||
router.push(PATH.PRESCRIPTION);
|
||||
},
|
||||
onSuccess(data) {
|
||||
console.log("TẠO ĐƠN THUỐC THÀNH CÔNG:", data);
|
||||
|
||||
onError: (error: any) => {
|
||||
const message =
|
||||
error?.response?.data?.message || error?.message || "Có lỗi xảy ra";
|
||||
|
||||
toastWarn({
|
||||
msg: message,
|
||||
queryKeys.forEach((key) => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: [key],
|
||||
});
|
||||
});
|
||||
|
||||
console.log("CREATE PRESCRIPTION ERROR:", error);
|
||||
setForm({
|
||||
examinationSessionSpecialtyId: "",
|
||||
notes: "",
|
||||
prescriptionImg: "",
|
||||
items: [defaultMedicine],
|
||||
});
|
||||
setFile(null);
|
||||
|
||||
// Điều hướng quay lại danh sách
|
||||
router.back();
|
||||
},
|
||||
onError(error: any) {
|
||||
console.error("LỖI HỆ THỐNG API TẠO ĐƠN THUỐC:", error);
|
||||
},
|
||||
});
|
||||
|
||||
/* =========================
|
||||
CHANGE MEDICINE FIELD
|
||||
CHANGE MEDICINE FIELD
|
||||
========================= */
|
||||
|
||||
const handleChangeMedicine = (
|
||||
index: number,
|
||||
key: keyof PrescriptionItem,
|
||||
value: string,
|
||||
) => {
|
||||
const cloneItems = [...form.items];
|
||||
|
||||
cloneItems[index] = {
|
||||
...cloneItems[index],
|
||||
[key]: value,
|
||||
};
|
||||
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
items: cloneItems,
|
||||
@@ -205,33 +176,20 @@ const CreatePrescription = () => {
|
||||
};
|
||||
|
||||
/* =========================
|
||||
ADD MEDICINE
|
||||
ADD MEDICINE
|
||||
========================= */
|
||||
|
||||
const handleAddMedicine = () => {
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
|
||||
items: [
|
||||
...prev.items,
|
||||
{
|
||||
medicineName: "",
|
||||
dosage: "",
|
||||
frequency: "",
|
||||
duration: "",
|
||||
instructions: "",
|
||||
},
|
||||
],
|
||||
items: [...prev.items, { ...defaultMedicine }],
|
||||
}));
|
||||
};
|
||||
|
||||
/* =========================
|
||||
REMOVE MEDICINE
|
||||
REMOVE MEDICINE
|
||||
========================= */
|
||||
|
||||
const handleRemoveMedicine = (index: number) => {
|
||||
const newItems = form.items.filter((_, i) => i !== index);
|
||||
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
items: newItems,
|
||||
@@ -239,44 +197,103 @@ const CreatePrescription = () => {
|
||||
};
|
||||
|
||||
/* =========================
|
||||
SUBMIT
|
||||
SUBMIT VALIDATION
|
||||
========================= */
|
||||
const handleSubmit = async () => {
|
||||
try {
|
||||
// Kiểm tra dữ liệu đầu vào phía client
|
||||
if (!form.examinationSessionSpecialtyId) {
|
||||
return toastWarn({
|
||||
msg: "Vui lòng chọn phiên khám chuyên khoa",
|
||||
});
|
||||
}
|
||||
|
||||
const handleSubmit = () => {
|
||||
/**
|
||||
* VALIDATE
|
||||
*/
|
||||
if (!file) {
|
||||
return toastWarn({
|
||||
msg: "Vui lòng chọn ảnh đơn thuốc",
|
||||
});
|
||||
}
|
||||
|
||||
if (!form.examinationSessionId) {
|
||||
return toastWarn({
|
||||
msg: "Vui lòng chọn phiên khám",
|
||||
const validMedicineList = form.items.filter(
|
||||
(item) => item.medicineName && item.medicineName.trim() !== "",
|
||||
);
|
||||
|
||||
if (validMedicineList.length === 0) {
|
||||
return toastWarn({
|
||||
msg: "Vui lòng nhập ít nhất 1 loại thuốc hợp lệ",
|
||||
});
|
||||
}
|
||||
|
||||
// 1. Thực hiện gọi API upload ảnh
|
||||
setLoading(true);
|
||||
const uploadResponse: any = await prescriptionServices.uploadImage(
|
||||
file,
|
||||
"prescriptions",
|
||||
);
|
||||
|
||||
console.log("KẾT QUẢ PHẢN HỒI GỐC TỪ API UPLOAD:", uploadResponse);
|
||||
|
||||
// Trích xuất URL linh hoạt tùy thuộc vào bộ bọc interceptor của axiosClient
|
||||
let imageUrl = "";
|
||||
|
||||
// Trường hợp 1: axiosClient trả về thẳng dữ liệu (hoặc chuỗi URL) từ server
|
||||
if (typeof uploadResponse === "string") {
|
||||
imageUrl = uploadResponse;
|
||||
} else if (uploadResponse?.fileUrl) {
|
||||
imageUrl = uploadResponse.fileUrl;
|
||||
} else if (uploadResponse?.url) {
|
||||
imageUrl = uploadResponse.url;
|
||||
}
|
||||
// Trường hợp 2: axiosClient trả về nguyên bản cấu trúc AxiosResponse chứa thuộc tính .data
|
||||
else if (uploadResponse?.data) {
|
||||
const innerData = uploadResponse.data;
|
||||
if (typeof innerData === "string") {
|
||||
imageUrl = innerData;
|
||||
} else {
|
||||
imageUrl =
|
||||
innerData?.fileUrl ||
|
||||
innerData?.url ||
|
||||
innerData?.data?.fileUrl ||
|
||||
innerData?.data?.url ||
|
||||
"";
|
||||
}
|
||||
}
|
||||
|
||||
console.log("ĐƯỜNG DẪN ẢNH CUỐI CÙNG TRÍCH XUẤT ĐƯỢC:", imageUrl);
|
||||
|
||||
if (!imageUrl) {
|
||||
setLoading(false);
|
||||
return toastWarn({
|
||||
msg: "Không tìm thấy đường dẫn ảnh từ phản hồi của máy chủ",
|
||||
});
|
||||
}
|
||||
|
||||
// 2. Thiết lập cấu trúc dữ liệu Payload chuẩn xác theo interface của createPrescription
|
||||
const finalPayload = {
|
||||
examinationSessionSpecialtyId: form.examinationSessionSpecialtyId,
|
||||
notes: form.notes || "",
|
||||
prescriptionImg: imageUrl,
|
||||
items: validMedicineList.map((item) => ({
|
||||
medicineName: item.medicineName.trim(),
|
||||
dosage: item.dosage || "",
|
||||
frequency: item.frequency || "",
|
||||
duration: item.duration || "",
|
||||
instructions: item.instructions || "",
|
||||
})),
|
||||
};
|
||||
|
||||
// 3. Kích hoạt gọi Mutation gửi yêu cầu tạo đơn thuốc mới lên Server
|
||||
funcCreatePrescription.mutate(finalPayload);
|
||||
} catch (error) {
|
||||
console.error("LỖI XỬ LÝ SUBMIT HOẶC UPLOAD ĐƠN THUỐC:", error);
|
||||
toastWarn({
|
||||
msg: "Có lỗi xảy ra trong quá trình xử lý tải ảnh lên hoặc lưu đơn thuốc",
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
return toastWarn({
|
||||
msg: "Vui lòng chọn ảnh đơn thuốc",
|
||||
});
|
||||
}
|
||||
|
||||
const validMedicine = form.items.some((x) => x.medicineName.trim() !== "");
|
||||
|
||||
if (!validMedicine) {
|
||||
return toastWarn({
|
||||
msg: "Vui lòng nhập ít nhất 1 loại thuốc",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* MUTATE
|
||||
*/
|
||||
createPrescriptionMutation.mutate();
|
||||
};
|
||||
|
||||
/* =========================
|
||||
UI
|
||||
========================= */
|
||||
|
||||
return (
|
||||
<FormCustom form={form} setForm={setForm} onSubmit={handleSubmit}>
|
||||
<div className="flex flex-col gap-6 rounded-2xl bg-white p-6 shadow">
|
||||
@@ -286,7 +303,6 @@ const CreatePrescription = () => {
|
||||
<h2 className="text-[28px] font-semibold text-[#111827]">
|
||||
Tạo đơn thuốc
|
||||
</h2>
|
||||
|
||||
<p className="mt-1 text-sm text-[#697586]">
|
||||
Tạo mới đơn thuốc cho bệnh nhân
|
||||
</p>
|
||||
@@ -296,11 +312,11 @@ const CreatePrescription = () => {
|
||||
<CustomButton
|
||||
type="submit"
|
||||
variant="midnightBlue"
|
||||
disabled={createPrescriptionMutation.isPending}
|
||||
disabled={funcCreatePrescription.isPending || loading}
|
||||
className="min-w-[180px]"
|
||||
>
|
||||
{createPrescriptionMutation.isPending
|
||||
? "Đang tạo..."
|
||||
{funcCreatePrescription.isPending || loading
|
||||
? "Đang tạo đơn..."
|
||||
: "Tạo đơn thuốc"}
|
||||
</CustomButton>
|
||||
</div>
|
||||
@@ -317,30 +333,32 @@ const CreatePrescription = () => {
|
||||
<SelectForm
|
||||
label={
|
||||
<span className="text-[14px] font-medium text-[#374151]">
|
||||
Phiên khám
|
||||
Phiên khám chuyên khoa
|
||||
<span className="text-red-500">*</span>
|
||||
</span>
|
||||
}
|
||||
placeholder="Chọn phiên khám"
|
||||
value={form.examinationSessionId}
|
||||
placeholder="Chọn phiên khám chuyên khoa"
|
||||
value={form.examinationSessionSpecialtyId}
|
||||
options={examinationSessionOptions}
|
||||
onSelect={(item: ConsultationItem) =>
|
||||
onSelect={(item: any) =>
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
examinationSessionId: item.id,
|
||||
examinationSessionSpecialtyId: item.id,
|
||||
}))
|
||||
}
|
||||
onClean={() =>
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
examinationSessionId: "",
|
||||
examinationSessionSpecialtyId: "",
|
||||
}))
|
||||
}
|
||||
getOptionLabel={(item: ConsultationItem) => `${item.sessionCode}`}
|
||||
getOptionValue={(item: ConsultationItem) => item.id}
|
||||
getOptionLabel={(item: any) =>
|
||||
`${item.sessionCode} - ${item.specialtyName} (${item.patientName})`
|
||||
}
|
||||
getOptionValue={(item: any) => item.id}
|
||||
/>
|
||||
|
||||
{/* IMAGE */}
|
||||
{/* IMAGE UPLOAD */}
|
||||
<div className="flex flex-col gap-2">
|
||||
<UploadImage
|
||||
label={
|
||||
@@ -348,10 +366,10 @@ const CreatePrescription = () => {
|
||||
Hình ảnh đơn thuốc <span style={{ color: "red" }}>*</span>
|
||||
</span>
|
||||
}
|
||||
name="PrescriptionFile"
|
||||
name="prescriptionImg"
|
||||
file={file}
|
||||
setFile={setFile}
|
||||
path=""
|
||||
path={""}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ const DetailPrescription = () => {
|
||||
{data.prescriptionImg ? (
|
||||
<>
|
||||
<Image
|
||||
src={`${process.env.NEXT_PUBLIC_IMAGE}${data.prescriptionImg}`}
|
||||
src={`${data.prescriptionImg}`}
|
||||
alt="prescription"
|
||||
width={140}
|
||||
height={140}
|
||||
|
||||
@@ -142,7 +142,8 @@ const MainPrescription = () => {
|
||||
render: (item: any) =>
|
||||
item.prescriptionImg ? (
|
||||
<Image
|
||||
src={`${process.env.NEXT_PUBLIC_IMAGE}${item.prescriptionImg}`}
|
||||
// src={`${process.env.NEXT_PUBLIC_IMAGE}${item.prescriptionImg}`}
|
||||
src={item.prescriptionImg}
|
||||
alt="prescription"
|
||||
width={40}
|
||||
height={40}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
"use client";
|
||||
import Table from "@/components/customs/custom-table";
|
||||
import DataWrapper from "@/components/customs/DataWrapper";
|
||||
import { QUERY_KEY } from "@/constant/config/enum";
|
||||
import { httpRequest } from "@/services";
|
||||
import consultationServices, {
|
||||
ReportResponse,
|
||||
} from "@/services/consultationServices";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import moment from "moment";
|
||||
// import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
||||
import React, { useMemo } from "react";
|
||||
|
||||
const MainPageStatistical = () => {
|
||||
// const router = useRouter();
|
||||
// const pathname = usePathname();
|
||||
// const searchParams = useSearchParams();
|
||||
|
||||
// const _page = searchParams.get("_page");
|
||||
|
||||
// const _pageSize = searchParams.get("_pageSize");
|
||||
const reportQuery = useQuery<ReportResponse>({
|
||||
queryKey: [QUERY_KEY.table_list_report],
|
||||
|
||||
queryFn: async () => {
|
||||
const toDate = moment().format("YYYY-MM-DD");
|
||||
const fromDate = moment().subtract(14, "days").format("YYYY-MM-DD");
|
||||
|
||||
const res = await httpRequest<ReportResponse>({
|
||||
showMessageFailed: true,
|
||||
http: consultationServices.getConsultationsReport({
|
||||
FormDate: fromDate,
|
||||
ToDate: toDate,
|
||||
}),
|
||||
});
|
||||
|
||||
return res as ReportResponse;
|
||||
},
|
||||
});
|
||||
|
||||
const reportData = useMemo(() => {
|
||||
return reportQuery.data?.specialtyDetails || [];
|
||||
}, [reportQuery.data]);
|
||||
|
||||
// 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) {
|
||||
// params.delete(key);
|
||||
// } else {
|
||||
// params.set(key, String(value));
|
||||
// }
|
||||
|
||||
// const queryString = params.toString();
|
||||
|
||||
// router.push(queryString ? `${pathname}?${queryString}` : pathname);
|
||||
// };
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-4 rounded-lg bg-white p-6 shadow">
|
||||
{/* HEADER */}
|
||||
<div className="flex items-center justify-between">
|
||||
<h2 className="text-xl font-semibold text-black">
|
||||
Thống kê các phiên khám
|
||||
</h2>
|
||||
</div>
|
||||
<DataWrapper
|
||||
data={reportData}
|
||||
loading={reportQuery.isLoading}
|
||||
title="Không có dữ liệu"
|
||||
note="Vui lòng thử lại sau"
|
||||
>
|
||||
<Table
|
||||
rowKey={(item) => item.specialtyId}
|
||||
data={reportData}
|
||||
column={[
|
||||
{
|
||||
title: "MÃ CHUYÊN KHOA",
|
||||
render: (item) => <span>{item.specialtyId}</span>,
|
||||
},
|
||||
{
|
||||
title: "TÊN CHUYÊN KHOA",
|
||||
render: (item) => <span>{item.specialtyName}</span>,
|
||||
},
|
||||
{
|
||||
title: "SỐ CA KHÁM",
|
||||
render: (item) => <span>{item.totalCases}</span>,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</DataWrapper>
|
||||
{/* <Pagination
|
||||
total={reportData.length}
|
||||
page={page}
|
||||
pageSize={pageSize}
|
||||
onSetPage={(value) => updateQuery("_page", value)}
|
||||
onSetPageSize={(value) => updateQuery("_pageSize", value)}
|
||||
dependencies={[_pageSize]}
|
||||
/> */}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainPageStatistical;
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "./MainPageStatistical";
|
||||
Reference in New Issue
Block a user