import React, { useState, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { clearNotifications, markAllNotificationsAsRead, markNotificationAsRead, setWebSocketConnected, } from '../store/notificationCenter/notificationCenter.slice'; import { fetchNotifications, markNotificationRead, markAllNotificationsRead, } from '../store/notificationCenter/notificationCenter.thunks'; import RequestDetailSlideOver from '../pages/Permissions/components/RequestDetailSlideOver'; import { approvePermissionThunk, rejectPermissionThunk } from '../store/permissions/permissions.thunks'; import { showNotification } from '../store/notification.slice'; import { initWebSocket, acknowledgeNotification, closeWebSocket } from '../services/websocket'; import { formatDate } from '../utils/dateUtils'; import { useNavigate } from 'react-router-dom'; export default function NotificationCenter({ show, onClose }) { const [showAll, setShowAll] = useState(false); const dispatch = useDispatch(); const { notifications, unreadCount, isConnected, loading } = useSelector((state) => state.notificationCenter); const [selectedRequest, setSelectedRequest] = useState(null); const [showSlideOver, setShowSlideOver] = useState(false); const [showResponseInput, setShowResponseInput] = useState(false); const [currentRequestId, setCurrentRequestId] = useState(null); const [isApproving, setIsApproving] = useState(false); const [responseMessage, setResponseMessage] = useState(''); const { isAuthenticated } = useSelector((state) => state.auth); const [loadingNotificationId, setLoadingNotificationId] = useState(null); const [isMarkingAllAsRead, setIsMarkingAllAsRead] = useState(false); const [isClearingAll, setIsClearingAll] = useState(false); const displayedNotifications = showAll ? notifications : notifications.slice(0, 5); const navigate = useNavigate(); // 初始化WebSocket连接 useEffect(() => { // 只有在用户已登录的情况下才连接WebSocket if (isAuthenticated && !isConnected) { initWebSocket() .then(() => { dispatch(setWebSocketConnected(true)); console.log('Successfully connected to notification WebSocket'); }) .catch((error) => { console.error('Failed to connect to notification WebSocket:', error); dispatch(setWebSocketConnected(false)); // 可以在这里显示连接失败的通知 dispatch( showNotification({ message: '通知服务连接失败,部分功能可能不可用', type: 'warning', }) ); }); } // 组件卸载时关闭WebSocket连接 return () => { if (isConnected) { closeWebSocket(); dispatch(setWebSocketConnected(false)); } }; }, [isAuthenticated, isConnected, dispatch]); // 当通知中心显示时,获取最新通知 useEffect(() => { if (show && isAuthenticated) { dispatch(fetchNotifications()); } }, [show, isAuthenticated, dispatch]); const handleClearAll = () => { setIsClearingAll(true); // 假设这个操作可能需要一点时间 setTimeout(() => { dispatch(clearNotifications()); setIsClearingAll(false); }, 300); }; const handleMarkAllAsRead = () => { // 设置正在处理标志 setIsMarkingAllAsRead(true); // 通过API将所有通知标记为已读,成功后更新本地状态 dispatch(markAllNotificationsRead()) .unwrap() .then(() => { dispatch(markAllNotificationsAsRead()); }) .catch((error) => { console.error('Failed to mark all notifications as read:', error); }) .finally(() => { setIsMarkingAllAsRead(false); }); }; const handleMarkAsRead = (notificationId) => { // 设置正在加载的通知ID setLoadingNotificationId(notificationId); // 通过API更新已读状态,成功后再更新本地状态 dispatch(markNotificationRead(notificationId)) .unwrap() .then(() => { // API调用成功后,更新本地状态 dispatch(markNotificationAsRead(notificationId)); // 同时发送确认消息到服务器 acknowledgeNotification(notificationId); }) .catch((error) => { console.error('Failed to mark notification as read:', error); }) .finally(() => { // 清除加载状态 setLoadingNotificationId(null); }); }; const handleViewDetail = (notification) => { navigate('/permissions'); // setSelectedRequest(notification); // setShowSlideOver(true); }; const handleCloseSlideOver = () => { setShowSlideOver(false); setTimeout(() => { setSelectedRequest(null); }, 300); }; const handleOpenResponseInput = (requestId, approving) => { setCurrentRequestId(requestId); setIsApproving(approving); setShowResponseInput(true); }; const handleCloseResponseInput = () => { setShowResponseInput(false); setCurrentRequestId(null); setResponseMessage(''); }; const handleProcessRequest = () => { if (!currentRequestId) return; const params = { id: currentRequestId, responseMessage, }; if (isApproving) { dispatch(approvePermissionThunk(params)); } else { dispatch(rejectPermissionThunk(params)); } }; if (!show) return null; return ( <>
通知中心
{unreadCount > 0 && {unreadCount}}
{displayedNotifications.length === 0 ? (

暂无通知

) : ( displayedNotifications.map((notification) => (
{notification.title}
{formatDate(notification.created_at)}

{notification.content}

{notification.type === 'permission_request' && ( )} {!notification.is_read && ( )}
)) )}
{notifications.length > 5 && (
)}
{/* 使用滑动面板组件 */} handleOpenResponseInput(id, true)} onReject={(id) => handleOpenResponseInput(id, false)} processingId={currentRequestId} approveRejectStatus={showResponseInput ? 'loading' : 'idle'} isApproving={isApproving} /> {/* 回复输入弹窗 */} {showResponseInput && (
{isApproving ? '批准' : '拒绝'}申请
)} ); }