feat: lensIssuesApi
fix(IssuesPage): Исправлены фильтры и пагинация.
This commit is contained in:
parent
f0a712eb9d
commit
b8bc7023a0
@ -1,6 +1,5 @@
|
||||
import {createApi} from "@reduxjs/toolkit/query/react";
|
||||
import {baseQueryWithAuth} from "./baseQuery.js";
|
||||
|
||||
import { createApi } from "@reduxjs/toolkit/query/react";
|
||||
import { baseQueryWithAuth } from "./baseQuery.js";
|
||||
|
||||
export const lensIssuesApi = createApi({
|
||||
reducerPath: 'lensIssuesApi',
|
||||
@ -18,24 +17,34 @@ export const lensIssuesApi = createApi({
|
||||
start_date: startDate || undefined,
|
||||
end_date: endDate || undefined,
|
||||
},
|
||||
providesTags: ['LensIssues'],
|
||||
}),
|
||||
providesTags: ['LensIssue'],
|
||||
providesTags: ['LensIssues'],
|
||||
transformResponse: (response) => {
|
||||
if (!response || !Array.isArray(response.issues)) {
|
||||
console.warn('Unexpected lens issues API response:', response);
|
||||
if (!response) {
|
||||
console.warn('Empty lens issues API response:', response);
|
||||
return { issues: [], total_count: 0 };
|
||||
}
|
||||
return response;
|
||||
if (Array.isArray(response.results) && typeof response.count === 'number') {
|
||||
return { issues: response.results, total_count: response.count };
|
||||
}
|
||||
if (Array.isArray(response.issues) && typeof response.total_count === 'number') {
|
||||
return response;
|
||||
}
|
||||
console.warn('Unexpected lens issues API response:', response);
|
||||
return { issues: [], total_count: 0 };
|
||||
},
|
||||
transformErrorResponse: (response) => {
|
||||
console.error('Lens issues API error:', response);
|
||||
return response.data?.detail || 'Unknown error';
|
||||
},
|
||||
}),
|
||||
addLensIssues: builder.mutation({
|
||||
query: (lensIssues) => ({
|
||||
url: `/lens_issues/`,
|
||||
url: '/lens_issues/',
|
||||
method: 'POST',
|
||||
body: lensIssues
|
||||
body: lensIssues,
|
||||
}),
|
||||
invalidatesTags: ['LensIssues']
|
||||
invalidatesTags: ['LensIssues'],
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
@ -31,7 +31,13 @@ ChartJS.register(CategoryScale, LinearScale, BarElement, Title, Tooltip, Legend)
|
||||
|
||||
const HomePage = () => {
|
||||
const homePageData = useHomePage();
|
||||
const homePageUI = useHomePageUI(homePageData.appointments, homePageData.scheduledAppointments, homePageData.patients);
|
||||
const homePageUI = useHomePageUI(
|
||||
homePageData.appointments,
|
||||
homePageData.scheduledAppointments,
|
||||
homePageData.patients,
|
||||
homePageData.upcomingAppointments,
|
||||
homePageData.upcomingScheduledAppointments
|
||||
);
|
||||
|
||||
if (homePageData.isError) {
|
||||
return (
|
||||
@ -94,7 +100,7 @@ const HomePage = () => {
|
||||
<Statistic
|
||||
title="Приемы за месяц"
|
||||
value={
|
||||
homePageData.appointments.filter((a) => dayjs(a.appointment_datetime).isSame(dayjs(), "month")).length
|
||||
homePageData.appointments.length
|
||||
}
|
||||
/>
|
||||
</Card>
|
||||
@ -107,7 +113,7 @@ const HomePage = () => {
|
||||
</Row>
|
||||
|
||||
<Card
|
||||
title={`События на сегодня (${dayjs().format("DD.MM.YYYY")})`}
|
||||
title={`События на сегодня (${dayjs().tz("Europe/Moscow").format("DD.MM.YYYY")})`}
|
||||
style={homePageUI.sectionStyle}
|
||||
>
|
||||
<List
|
||||
@ -119,7 +125,7 @@ const HomePage = () => {
|
||||
>
|
||||
<Space>
|
||||
<Typography.Text strong>
|
||||
{dayjs(item.appointment_datetime || item.scheduled_datetime).format("HH:mm")}
|
||||
{dayjs(item.appointment_datetime || item.scheduled_datetime).tz("Europe/Moscow").format("HH:mm")}
|
||||
</Typography.Text>
|
||||
<Typography.Text>
|
||||
{item.patient ? `${item.patient.last_name} ${item.patient.first_name}` : "Без пациента"} -{" "}
|
||||
|
||||
@ -1,32 +1,35 @@
|
||||
import { Grid } from "antd";
|
||||
import {Grid} from "antd";
|
||||
import {useEffect, useMemo} from "react";
|
||||
import dayjs from "dayjs";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import timezone from "dayjs/plugin/timezone";
|
||||
import isBetween from "dayjs/plugin/isBetween";
|
||||
import {useSelector} from "react-redux"; // Import isBetween plugin
|
||||
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
dayjs.extend(isBetween);
|
||||
|
||||
const { useBreakpoint } = Grid;
|
||||
const {useBreakpoint} = Grid;
|
||||
|
||||
const useHomePageUI = (appointments, scheduledAppointments, patients) => {
|
||||
const useHomePageUI = (appointments, scheduledAppointments, patients, upcomingAppointments, upcomingScheduledAppointments) => {
|
||||
const screens = useBreakpoint();
|
||||
|
||||
const containerStyle = { padding: screens.xs ? 16 : 24 };
|
||||
const sectionStyle = { marginBottom: 24 };
|
||||
const cardStyle = { height: "100%" };
|
||||
const listItemStyle = { cursor: "pointer", padding: "12px", borderRadius: 4 };
|
||||
const buttonStyle = { width: screens.xs ? "100%" : "auto" };
|
||||
const chartContainerStyle = { padding: 16, background: "#fff", borderRadius: 4 };
|
||||
const containerStyle = {padding: screens.xs ? 16 : 24};
|
||||
const sectionStyle = {marginBottom: 24};
|
||||
const cardStyle = {height: "100%"};
|
||||
const listItemStyle = {cursor: "pointer", padding: "12px", borderRadius: 4};
|
||||
const buttonStyle = {width: screens.xs ? "100%" : "auto"};
|
||||
const chartContainerStyle = {padding: 16, background: "#fff", borderRadius: 4};
|
||||
|
||||
useEffect(() => {
|
||||
document.title = "Главная страница";
|
||||
}, []);
|
||||
|
||||
const todayEvents = useMemo(() => {
|
||||
return [...appointments, ...scheduledAppointments].filter((event) =>
|
||||
return [...upcomingAppointments, ...upcomingScheduledAppointments].filter((event) =>
|
||||
dayjs(event.appointment_datetime || event.scheduled_datetime).isSame(dayjs(), "day")
|
||||
);
|
||||
}, [appointments, scheduledAppointments]);
|
||||
}, [upcomingAppointments, upcomingScheduledAppointments]);
|
||||
|
||||
const upcomingBirthdays = useMemo(() => {
|
||||
return patients.filter((p) =>
|
||||
@ -38,7 +41,12 @@ const useHomePageUI = (appointments, scheduledAppointments, patients) => {
|
||||
const data = Array(7).fill(0);
|
||||
appointments
|
||||
.filter((app) =>
|
||||
dayjs(app.appointment_datetime).isBetween(dayjs().startOf("week"), dayjs().endOf("week"), "day", "[]")
|
||||
dayjs(app.appointment_datetime).isBetween(
|
||||
dayjs().startOf("week"),
|
||||
dayjs().endOf("week"),
|
||||
"day",
|
||||
"[]"
|
||||
)
|
||||
)
|
||||
.forEach((app) => {
|
||||
const dayIndex = dayjs(app.appointment_datetime).day();
|
||||
@ -51,7 +59,12 @@ const useHomePageUI = (appointments, scheduledAppointments, patients) => {
|
||||
const data = Array(7).fill(0);
|
||||
scheduledAppointments
|
||||
.filter((app) =>
|
||||
dayjs(app.scheduled_datetime).isBetween(dayjs().startOf("week"), dayjs().endOf("week"), "day", "[]")
|
||||
dayjs(app.scheduled_datetime).isBetween(
|
||||
dayjs().startOf("week"),
|
||||
dayjs().endOf("week"),
|
||||
"day",
|
||||
"[]"
|
||||
)
|
||||
)
|
||||
.forEach((app) => {
|
||||
const dayIndex = dayjs(app.scheduled_datetime).day();
|
||||
@ -64,12 +77,12 @@ const useHomePageUI = (appointments, scheduledAppointments, patients) => {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: { beginAtZero: true, title: { display: true, text: "Количество приемов" } },
|
||||
x: { title: { display: true, text: "День недели" } },
|
||||
y: {beginAtZero: true, title: {display: true, text: "Количество приемов"}},
|
||||
x: {title: {display: true, text: "День недели"}},
|
||||
},
|
||||
plugins: {
|
||||
legend: { display: false },
|
||||
title: { display: true, text: "Приемы за неделю" },
|
||||
legend: {display: true, position: "top"},
|
||||
title: {display: true, text: "Приемы за неделю"},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ import LensIssueFormModal from "./Components/LensIssueFormModal/LensIssueFormMod
|
||||
import SelectViewMode from "../../Widgets/SelectViewMode/SelectViewMode.jsx";
|
||||
import LoadingIndicator from "../../Widgets/LoadingIndicator/LoadingIndicator.jsx";
|
||||
import useIssues from "./useIssues.js";
|
||||
import { useMemo } from "react";
|
||||
|
||||
const { Title } = Typography;
|
||||
const { useBreakpoint } = Grid;
|
||||
@ -86,7 +87,7 @@ const IssuesPage = () => {
|
||||
/>
|
||||
);
|
||||
|
||||
const timeLineItems = issuesData.issues.map(issue => ({
|
||||
const timeLineItems = useMemo(() => issuesData.issues.map(issue => ({
|
||||
label: dayjs(issue.issue_date).format("DD.MM.YYYY"),
|
||||
children: (
|
||||
<Row gutter={[16, 16]} align="middle">
|
||||
@ -107,7 +108,7 @@ const IssuesPage = () => {
|
||||
</Col>
|
||||
</Row>
|
||||
),
|
||||
}));
|
||||
})), [issuesData]);
|
||||
|
||||
const TimeLineView = () => {
|
||||
const paginatedItems = timeLineItems.slice(
|
||||
@ -129,7 +130,7 @@ const IssuesPage = () => {
|
||||
<Pagination
|
||||
current={issuesData.currentPage}
|
||||
pageSize={issuesData.pageSize}
|
||||
total={timeLineItems.length}
|
||||
total={issuesData.total_count}
|
||||
onChange={issuesData.handlePaginationChange}
|
||||
showSizeChanger={true}
|
||||
pageSizeOptions={["5", "10", "20", "50"]}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { notification } from "antd";
|
||||
import {useEffect, useState} from "react";
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import {notification} from "antd";
|
||||
import {
|
||||
useAddLensIssuesMutation,
|
||||
useGetLensIssuesQuery,
|
||||
} from "../../../Api/lensIssuesApi.js";
|
||||
import { useGetAllPatientsQuery } from "../../../Api/patientsApi.js";
|
||||
import {useGetAllPatientsQuery} from "../../../Api/patientsApi.js";
|
||||
import {
|
||||
closeModal,
|
||||
openModal,
|
||||
@ -17,7 +17,7 @@ import {
|
||||
setStartFilterDate,
|
||||
setViewMode
|
||||
} from "../../../Redux/Slices/lensIssuesSlice.js";
|
||||
import { getCachedInfo } from "../../../Utils/cachedInfoUtils.js";
|
||||
import {getCachedInfo} from "../../../Utils/cachedInfoUtils.js";
|
||||
import dayjs from "dayjs";
|
||||
import {useGetNotIssuedLensesQuery} from "../../../Api/lensesApi.js";
|
||||
|
||||
@ -37,23 +37,25 @@ const useIssues = () => {
|
||||
const [tempSearchText, setTempSearchText] = useState(searchText);
|
||||
|
||||
const {
|
||||
data: issuesData = { issues: [], total_count: 0 },
|
||||
data: issuesData = {issues: [], total_count: 0},
|
||||
isLoading: isIssuesLoading,
|
||||
isError: isIssuesError,
|
||||
error: issuesError
|
||||
error: issuesError,
|
||||
refetch
|
||||
} = useGetLensIssuesQuery({
|
||||
page: currentPage,
|
||||
pageSize,
|
||||
search: searchText || undefined,
|
||||
sortOrder: 'desc',
|
||||
startDate: startFilterDate || undefined,
|
||||
endDate: endFilterDate || undefined,
|
||||
startDate: startFilterDate ? dayjs(startFilterDate).format('YYYY-MM-DD') : undefined,
|
||||
endDate: endFilterDate ? dayjs(endFilterDate).format('YYYY-MM-DD') : undefined,
|
||||
}, {
|
||||
pollingInterval: 20000,
|
||||
});
|
||||
const { data: patients = [], isLoading: isPatientsLoading, isError: isPatientsError } = useGetAllPatientsQuery();
|
||||
const { data: lenses = [], isLoading: isLensesLoading, isError: isLensesError } = useGetNotIssuedLensesQuery();
|
||||
const [addIssue, { isLoading: isAdding }] = useAddLensIssuesMutation();
|
||||
|
||||
const {data: patients = [], isLoading: isPatientsLoading, isError: isPatientsError} = useGetAllPatientsQuery();
|
||||
const {data: lenses = [], isLoading: isLensesLoading, isError: isLensesError} = useGetNotIssuedLensesQuery();
|
||||
const [addIssue, {isLoading: isAdding}] = useAddLensIssuesMutation();
|
||||
|
||||
const isLoading = isIssuesLoading || isPatientsLoading || isLensesLoading;
|
||||
const isError = isIssuesError || isPatientsError || isLensesError;
|
||||
@ -93,10 +95,10 @@ const useIssues = () => {
|
||||
const filterDates = [startFilterDateConverted, endFilterDateConverted];
|
||||
const isFilterDates = startFilterDate && endFilterDate;
|
||||
|
||||
const containerStyle = { padding: 20 };
|
||||
const filterBarStyle = { marginBottom: 20 };
|
||||
const formItemStyle = { width: "100%" };
|
||||
const viewModIconStyle = { marginRight: 8 };
|
||||
const containerStyle = {padding: 20};
|
||||
const filterBarStyle = {marginBottom: 20};
|
||||
const formItemStyle = {width: "100%"};
|
||||
const viewModIconStyle = {marginRight: 8};
|
||||
const advancedSearchCardStyle = {
|
||||
marginBottom: 20,
|
||||
boxShadow: "0 1px 6px rgba(0, 0, 0, 0.15)",
|
||||
@ -108,19 +110,23 @@ const useIssues = () => {
|
||||
const handleSearch = () => {
|
||||
dispatch(setSearchText(tempSearchText));
|
||||
dispatch(setCurrentPage(1));
|
||||
refetch();
|
||||
};
|
||||
|
||||
const handleClearSearch = () => {
|
||||
setTempSearchText('');
|
||||
dispatch(setSearchText(''));
|
||||
dispatch(setCurrentPage(1));
|
||||
refetch();
|
||||
};
|
||||
|
||||
const handleSetViewMode = (mode) => dispatch(setViewMode(mode));
|
||||
const handleSetCurrentPage = (page) => dispatch(setCurrentPage(page));
|
||||
const handleSetCurrentPage = (page) => {
|
||||
dispatch(setCurrentPage(page));
|
||||
};
|
||||
|
||||
const handleSetPageSize = (size) => {
|
||||
dispatch(setPageSize(size));
|
||||
dispatch(setCurrentPage(1));
|
||||
};
|
||||
const handleCloseModal = () => dispatch(closeModal());
|
||||
const handleSelectIssue = (issue) => dispatch(selectIssue(issue));
|
||||
@ -134,6 +140,7 @@ const useIssues = () => {
|
||||
const handlePaginationChange = (page, pageSize) => {
|
||||
handleSetCurrentPage(page);
|
||||
handleSetPageSize(pageSize);
|
||||
refetch();
|
||||
};
|
||||
|
||||
const handleFilterDateChange = (dates) => {
|
||||
@ -142,6 +149,7 @@ const useIssues = () => {
|
||||
dispatch(setStartFilterDate(start.toISOString()));
|
||||
dispatch(setEndFilterDate(end.toISOString()));
|
||||
dispatch(setCurrentPage(1));
|
||||
refetch();
|
||||
}
|
||||
};
|
||||
|
||||
@ -149,6 +157,7 @@ const useIssues = () => {
|
||||
dispatch(setStartFilterDate(null));
|
||||
dispatch(setEndFilterDate(null));
|
||||
dispatch(setCurrentPage(1));
|
||||
refetch();
|
||||
};
|
||||
|
||||
const pagination = {
|
||||
@ -158,18 +167,22 @@ const useIssues = () => {
|
||||
showSizeChanger: true,
|
||||
pageSizeOptions: ["5", "10", "20", "50"],
|
||||
onChange: handlePaginationChange,
|
||||
onShowSizeChange: handlePaginationChange,
|
||||
};
|
||||
|
||||
const handleSubmitFormModal = async (issueDate, patientId, lensId) => {
|
||||
dispatch(closeModal());
|
||||
try {
|
||||
await addIssue({ issue_date: issueDate, patient_id: patientId, lens_id: lensId }).unwrap();
|
||||
const formattedIssueDate = dayjs(issueDate).format('YYYY-MM-DD');
|
||||
await addIssue({issue_date: formattedIssueDate, patient_id: patientId, lens_id: lensId}).unwrap();
|
||||
notification.success({
|
||||
message: "Линза выдана",
|
||||
description: "Линза успешно выдана пациенту.",
|
||||
placement: "topRight",
|
||||
});
|
||||
refetch();
|
||||
} catch (error) {
|
||||
console.error('Add lens issue error:', error);
|
||||
notification.error({
|
||||
message: "Ошибка выдачи линзы",
|
||||
description: error?.data?.detail || "Не удалось выдать линзу пациенту.",
|
||||
@ -180,6 +193,7 @@ const useIssues = () => {
|
||||
|
||||
return {
|
||||
issues: issuesData.issues,
|
||||
total_count: issuesData.total_count,
|
||||
patients,
|
||||
lenses,
|
||||
isLoading,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user