|
@@ -1,4 +1,4 @@
|
|
-import React, { useState } from "react";
|
|
|
|
|
|
+import React, { useState, useRef, useEffect } from "react";
|
|
import { Modal, Button, Tabs, Empty, message } from "antd";
|
|
import { Modal, Button, Tabs, Empty, message } from "antd";
|
|
import type { TabsProps } from "antd";
|
|
import type { TabsProps } from "antd";
|
|
import axios from "axios";
|
|
import axios from "axios";
|
|
@@ -11,18 +11,90 @@ import { renderNoticeLength } from "@/utils/utils";
|
|
interface MessageModalProps {
|
|
interface MessageModalProps {
|
|
visible: boolean;
|
|
visible: boolean;
|
|
onClose: () => void;
|
|
onClose: () => void;
|
|
|
|
+ fetchNoticeList: (id?: number, isRead?: number) => Promise<any[]>;
|
|
}
|
|
}
|
|
|
|
|
|
const MessageModal: React.FC<MessageModalProps> = ({
|
|
const MessageModal: React.FC<MessageModalProps> = ({
|
|
visible,
|
|
visible,
|
|
onClose,
|
|
onClose,
|
|
|
|
+ fetchNoticeList,
|
|
}) => {
|
|
}) => {
|
|
const [activeKey, setActiveKey] = useState(MESSAGE_TAB.UNREAD);
|
|
const [activeKey, setActiveKey] = useState(MESSAGE_TAB.UNREAD);
|
|
const { notifications, changeNotification } = useNotificationStore();
|
|
const { notifications, changeNotification } = useNotificationStore();
|
|
|
|
+ const [loading, setLoading] = useState(false);
|
|
|
|
+ const [hasMore, setHasMore] = useState(true); // 新增状态,用于标记是否还有更多数据
|
|
|
|
+ const observerRef = useRef<HTMLDivElement>(null);
|
|
|
|
+
|
|
const unreadNotifications = notifications.filter(
|
|
const unreadNotifications = notifications.filter(
|
|
(notification) => notification.is_read === MESSAGE_STATUS.UNREAD
|
|
(notification) => notification.is_read === MESSAGE_STATUS.UNREAD
|
|
);
|
|
);
|
|
|
|
|
|
|
|
+ // 根据activeKey获取对应的isRead值
|
|
|
|
+ const getIsReadStatus = (tabKey: string) => {
|
|
|
|
+ switch (tabKey) {
|
|
|
|
+ case MESSAGE_TAB.UNREAD:
|
|
|
|
+ return MESSAGE_STATUS.UNREAD;
|
|
|
|
+ case MESSAGE_TAB.HAS_READ:
|
|
|
|
+ return MESSAGE_STATUS.HAS_READ;
|
|
|
|
+ default:
|
|
|
|
+ return undefined; // 全部消息时不传isRead参数
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ useEffect(() => {
|
|
|
|
+ const observer = new IntersectionObserver(
|
|
|
|
+ async (entries) => {
|
|
|
|
+ const target = entries[0];
|
|
|
|
+ if (target.isIntersecting && !loading && hasMore) {
|
|
|
|
+ const filteredNotifications = getFilteredNotifications();
|
|
|
|
+ if (filteredNotifications.length > 0) {
|
|
|
|
+ setLoading(true);
|
|
|
|
+ const lastId =
|
|
|
|
+ filteredNotifications[filteredNotifications.length - 1].id;
|
|
|
|
+ try {
|
|
|
|
+ const isRead = getIsReadStatus(activeKey);
|
|
|
|
+ const newMessages = await fetchNoticeList(lastId, isRead);
|
|
|
|
+ if (newMessages.length === 0) {
|
|
|
|
+ setHasMore(false);
|
|
|
|
+ setLoading(false);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error("Failed to fetch more messages:", error);
|
|
|
|
+ }
|
|
|
|
+ setLoading(false);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ {
|
|
|
|
+ threshold: 0.1,
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+
|
|
|
|
+ if (observerRef.current) {
|
|
|
|
+ observer.observe(observerRef.current);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return () => observer.disconnect();
|
|
|
|
+ }, [loading, fetchNoticeList, activeKey, hasMore]); // 添加hasMore作为依赖
|
|
|
|
+
|
|
|
|
+ // 获取过滤后的通知列表
|
|
|
|
+ const getFilteredNotifications = () => {
|
|
|
|
+ let filteredNotifications = notifications;
|
|
|
|
+
|
|
|
|
+ if (activeKey === MESSAGE_TAB.UNREAD) {
|
|
|
|
+ filteredNotifications = notifications.filter(
|
|
|
|
+ (notification) => notification.is_read === MESSAGE_STATUS.UNREAD
|
|
|
|
+ );
|
|
|
|
+ } else if (activeKey === MESSAGE_TAB.HAS_READ) {
|
|
|
|
+ filteredNotifications = notifications.filter(
|
|
|
|
+ (notification) => notification.is_read === MESSAGE_STATUS.HAS_READ
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return filteredNotifications;
|
|
|
|
+ };
|
|
|
|
+
|
|
const tabItems: TabsProps["items"] = [
|
|
const tabItems: TabsProps["items"] = [
|
|
{
|
|
{
|
|
key: MESSAGE_TAB.ALL,
|
|
key: MESSAGE_TAB.ALL,
|
|
@@ -47,6 +119,12 @@ const MessageModal: React.FC<MessageModalProps> = ({
|
|
},
|
|
},
|
|
];
|
|
];
|
|
|
|
|
|
|
|
+ // 简化 Tab 切换处理函数
|
|
|
|
+ const handleTabChange = (key: string) => {
|
|
|
|
+ setActiveKey(key);
|
|
|
|
+ setHasMore(true); // 切换tab时重置hasMore状态
|
|
|
|
+ };
|
|
|
|
+
|
|
return (
|
|
return (
|
|
<Modal
|
|
<Modal
|
|
title={
|
|
title={
|
|
@@ -84,83 +162,83 @@ const MessageModal: React.FC<MessageModalProps> = ({
|
|
activeKey={activeKey}
|
|
activeKey={activeKey}
|
|
items={tabItems}
|
|
items={tabItems}
|
|
className="mb-4"
|
|
className="mb-4"
|
|
- onChange={(key) => {
|
|
|
|
- setActiveKey(key);
|
|
|
|
- }}
|
|
|
|
|
|
+ onChange={handleTabChange}
|
|
/>
|
|
/>
|
|
<div className="space-y-4 max-h-[100%] overflow-auto">
|
|
<div className="space-y-4 max-h-[100%] overflow-auto">
|
|
{(() => {
|
|
{(() => {
|
|
- let filteredNotifications = notifications;
|
|
|
|
-
|
|
|
|
- if (activeKey === MESSAGE_TAB.UNREAD) {
|
|
|
|
- filteredNotifications = notifications.filter(
|
|
|
|
- (notification) => notification.is_read === MESSAGE_STATUS.UNREAD
|
|
|
|
- );
|
|
|
|
- } else if (activeKey === MESSAGE_TAB.HAS_READ) {
|
|
|
|
- filteredNotifications = notifications.filter(
|
|
|
|
- (notification) =>
|
|
|
|
- notification.is_read === MESSAGE_STATUS.HAS_READ
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
|
|
+ const filteredNotifications = getFilteredNotifications();
|
|
|
|
|
|
return (
|
|
return (
|
|
<>
|
|
<>
|
|
- {filteredNotifications.length === 0 && (
|
|
|
|
|
|
+ {filteredNotifications.length === 0 ? (
|
|
<div className="flex justify-center items-center h-full">
|
|
<div className="flex justify-center items-center h-full">
|
|
<Empty description="暂无消息" />
|
|
<Empty description="暂无消息" />
|
|
</div>
|
|
</div>
|
|
- )}
|
|
|
|
- {filteredNotifications.map((message, index) => (
|
|
|
|
- <div
|
|
|
|
- key={index}
|
|
|
|
- className="p-4 bg-gray-50 rounded-lg shadow-sm flex flex-col gap-4"
|
|
|
|
- >
|
|
|
|
- <div className="flex justify-between items-center">
|
|
|
|
- <div className="flex gap-1 items-center">
|
|
|
|
- <div className="p-1 bg-blue-500 rounded-full w-6 h-6 text-white flex justify-center items-center">
|
|
|
|
- <FileText size={14} />
|
|
|
|
- </div>
|
|
|
|
- <div className="font-bold">病例时效提醒</div>
|
|
|
|
- </div>
|
|
|
|
- <div className="text-gray-500 text-xs">
|
|
|
|
- {dayjs(message.timestamp).format("YYYY-MM-DD HH:mm")}
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- <div className="flex items-start space-x-4">
|
|
|
|
- <div className="flex-1">
|
|
|
|
- <div className="flex">
|
|
|
|
- <h4 className="text-sm font-semibold">
|
|
|
|
- {message.title}
|
|
|
|
- </h4>
|
|
|
|
|
|
+ ) : (
|
|
|
|
+ <>
|
|
|
|
+ {filteredNotifications.map((message, index) => (
|
|
|
|
+ <div
|
|
|
|
+ key={index}
|
|
|
|
+ className="p-4 bg-gray-50 rounded-lg shadow-sm flex flex-col gap-4"
|
|
|
|
+ >
|
|
|
|
+ <div className="flex justify-between items-center">
|
|
|
|
+ <div className="flex gap-1 items-center">
|
|
|
|
+ <div className="p-1 bg-blue-500 rounded-full w-6 h-6 text-white flex justify-center items-center">
|
|
|
|
+ <FileText size={14} />
|
|
|
|
+ </div>
|
|
|
|
+ <div className="font-bold">病例时效提醒</div>
|
|
|
|
+ </div>
|
|
|
|
+ <div className="text-gray-500 text-xs">
|
|
|
|
+ {dayjs(message.push_time).format(
|
|
|
|
+ "YYYY-MM-DD HH:mm:ss"
|
|
|
|
+ )}
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
- <p className="text-gray-700 mt-1 indent-[1.75rem]">
|
|
|
|
- {message.content}
|
|
|
|
- </p>
|
|
|
|
- <p className="text-gray-700 mt-1 indent-[1.75rem]">
|
|
|
|
- {message.footer || "祝您工作顺利!"}
|
|
|
|
- </p>
|
|
|
|
- <div className="mt-2 flex space-x-2 justify-end">
|
|
|
|
- <Button
|
|
|
|
- type="primary"
|
|
|
|
- size="middle"
|
|
|
|
- onClick={() => {
|
|
|
|
- axios.post("/notification/bazb/clearMsg", {
|
|
|
|
- msgId: message.id,
|
|
|
|
- });
|
|
|
|
- changeNotification({
|
|
|
|
- type: "clear",
|
|
|
|
- notification: [message.id],
|
|
|
|
- });
|
|
|
|
- }}
|
|
|
|
- >
|
|
|
|
- 知道了
|
|
|
|
- </Button>
|
|
|
|
- <Button size="middle">去查看</Button>
|
|
|
|
|
|
+ <div className="flex items-start space-x-4">
|
|
|
|
+ <div className="flex-1">
|
|
|
|
+ <div className="flex">
|
|
|
|
+ <h4 className="text-sm font-semibold">
|
|
|
|
+ {message.title}
|
|
|
|
+ </h4>
|
|
|
|
+ </div>
|
|
|
|
+ <p className="text-gray-700 mt-1 indent-[1.75rem]">
|
|
|
|
+ {message.content}
|
|
|
|
+ </p>
|
|
|
|
+ <p className="text-gray-700 mt-1 indent-[1.75rem]">
|
|
|
|
+ {message.footer || "祝您工作顺利!"}
|
|
|
|
+ </p>
|
|
|
|
+ <div className="mt-2 flex space-x-2 justify-end">
|
|
|
|
+ <Button
|
|
|
|
+ type="primary"
|
|
|
|
+ size="middle"
|
|
|
|
+ onClick={() => {
|
|
|
|
+ axios.post("/notification/bazb/clearMsg", {
|
|
|
|
+ msgId: message.id,
|
|
|
|
+ });
|
|
|
|
+ changeNotification({
|
|
|
|
+ type: "clear",
|
|
|
|
+ notification: [message.id],
|
|
|
|
+ });
|
|
|
|
+ }}
|
|
|
|
+ >
|
|
|
|
+ 知道了
|
|
|
|
+ </Button>
|
|
|
|
+ <Button size="middle">去查看</Button>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- ))}
|
|
|
|
|
|
+ ))}
|
|
|
|
+ {loading && (
|
|
|
|
+ <div className="flex justify-center items-center py-4">
|
|
|
|
+ <div className="text-gray-500">加载中...</div>
|
|
|
|
+ </div>
|
|
|
|
+ )}
|
|
|
|
+ {hasMore && (
|
|
|
|
+ <div ref={observerRef} style={{ height: "20px" }} />
|
|
|
|
+ )}
|
|
|
|
+ </>
|
|
|
|
+ )}
|
|
</>
|
|
</>
|
|
);
|
|
);
|
|
})()}
|
|
})()}
|