diff --git a/src/components/NotificationCenter.jsx b/src/components/NotificationCenter.jsx
index fb04eff..2d8a298 100644
--- a/src/components/NotificationCenter.jsx
+++ b/src/components/NotificationCenter.jsx
@@ -40,7 +40,7 @@ export default function NotificationCenter({ show, onClose }) {
// 初始化WebSocket连接
useEffect(() => {
// 只有在用户已登录的情况下才连接WebSocket
- if (isAuthenticated && !isConnected) {
+ if (isAuthenticated) {
initWebSocket()
.then(() => {
dispatch(setWebSocketConnected(true));
@@ -59,14 +59,7 @@ export default function NotificationCenter({ show, onClose }) {
});
}
- // 组件卸载时关闭WebSocket连接
- return () => {
- if (isConnected) {
- closeWebSocket();
- dispatch(setWebSocketConnected(false));
- }
- };
- }, [isAuthenticated, isConnected, dispatch]);
+ }, [isAuthenticated, dispatch]);
// 当通知中心显示时,获取最新通知
useEffect(() => {
@@ -125,6 +118,7 @@ export default function NotificationCenter({ show, onClose }) {
};
const handleViewDetail = (notification) => {
+ onClose();
navigate('/permissions');
// setSelectedRequest(notification);
// setShowSlideOver(true);
diff --git a/src/layouts/HeaderWithNav.jsx b/src/layouts/HeaderWithNav.jsx
index 2578e59..73a0963 100644
--- a/src/layouts/HeaderWithNav.jsx
+++ b/src/layouts/HeaderWithNav.jsx
@@ -88,7 +88,6 @@ export default function HeaderWithNav() {
diff --git a/src/services/websocket.js b/src/services/websocket.js
index 095d875..9aa8e5a 100644
--- a/src/services/websocket.js
+++ b/src/services/websocket.js
@@ -1,4 +1,8 @@
-import { addNotification, markNotificationAsRead } from '../store/notificationCenter/notificationCenter.slice';
+import {
+ addNotification,
+ markNotificationAsRead,
+ setWebSocketConnected,
+} from '../store/notificationCenter/notificationCenter.slice';
import store from '../store/store'; // 修改为默认导出
import CryptoJS from 'crypto-js';
@@ -38,6 +42,7 @@ export const initWebSocket = () => {
let token = '';
if (!encryptedToken) {
console.error('No token found, cannot connect to notification service');
+ store.dispatch(setWebSocketConnected(false));
reject(new Error('No token found'));
return;
}
@@ -53,6 +58,9 @@ export const initWebSocket = () => {
console.log('WebSocket connection established');
reconnectAttempts = 0; // 连接成功后重置重连计数器
+ // 更新Redux中的连接状态
+ store.dispatch(setWebSocketConnected(true));
+
// 订阅通知频道
subscribeToNotifications();
@@ -79,6 +87,8 @@ export const initWebSocket = () => {
// 错误处理
socket.onerror = (error) => {
console.error('WebSocket error:', error);
+ // 更新Redux中的连接状态
+ store.dispatch(setWebSocketConnected(false));
reject(error);
};
@@ -86,6 +96,9 @@ export const initWebSocket = () => {
socket.onclose = (event) => {
console.log(`WebSocket connection closed: ${event.code} ${event.reason}`);
+ // 更新Redux中的连接状态
+ store.dispatch(setWebSocketConnected(false));
+
// 清除ping定时器
if (pingInterval) clearInterval(pingInterval);
@@ -99,15 +112,21 @@ export const initWebSocket = () => {
console.log('Attempting to reconnect WebSocket...');
initWebSocket().catch((err) => {
console.error('Failed to reconnect WebSocket:', err);
+ // 重连失败时更新Redux中的连接状态
+ store.dispatch(setWebSocketConnected(false));
});
}, RECONNECT_DELAY);
} else {
console.log('Maximum reconnection attempts reached. Giving up.');
+ // 达到最大重连次数时更新Redux中的连接状态
+ store.dispatch(setWebSocketConnected(false));
}
}
};
} catch (error) {
console.error('Error initializing WebSocket:', error);
+ // 更新Redux中的连接状态
+ store.dispatch(setWebSocketConnected(false));
reject(error);
}
});
@@ -173,6 +192,9 @@ export const closeWebSocket = () => {
clearInterval(pingInterval);
pingInterval = null;
}
+
+ // 更新Redux中的连接状态
+ store.dispatch(setWebSocketConnected(false));
};
/**
@@ -235,7 +257,7 @@ const processNotification = (data) => {
} else {
timeDisplay = `${diffDays}天前`;
}
-
+
return {
id: notificationData.id,
type: notificationData.category,
diff --git a/src/store/notificationCenter/notificationCenter.thunks.js b/src/store/notificationCenter/notificationCenter.thunks.js
index bedac39..b9ce17f 100644
--- a/src/store/notificationCenter/notificationCenter.thunks.js
+++ b/src/store/notificationCenter/notificationCenter.thunks.js
@@ -9,7 +9,7 @@ export const fetchNotifications = createAsyncThunk(
async (_, { rejectWithValue }) => {
try {
const response = await get('/notifications/');
- return response;
+ return processNotification(response);
} catch (error) {
const errorMessage = error.response?.data?.message || 'Failed to fetch notifications';
return rejectWithValue(errorMessage);
@@ -27,7 +27,7 @@ export const markNotificationRead = createAsyncThunk(
const response = await post(`/notifications/${notificationId}/mark-as-read/`);
return { id: notificationId, ...response };
} catch (error) {
- const errorMessage = error.response?.data?.message || 'Failed to mark notification as read';
+ const errorMessage = error.response?.data?.message || 'Failed to mark notification as read';
return rejectWithValue(errorMessage);
}
}
@@ -48,3 +48,88 @@ export const markAllNotificationsRead = createAsyncThunk(
}
}
);
+
+/**
+ * 处理通知数据,转换为应用内通知格式
+ * @param {Object|Array} data 通知数据或通知数组
+ * @returns {Object|Array} 处理后的通知数据
+ */
+export const processNotification = (data) => {
+ // 处理数组类型的通知数据
+ if (Array.isArray(data)) {
+ return data.map((item) => processNotificationItem(item));
+ }
+
+ // 处理WebSocket格式的通知数据 (带有data字段的对象)
+ if (data && data.data) {
+ return processNotificationItem(data.data);
+ }
+
+ // 处理单个通知对象
+ return processNotificationItem(data);
+};
+
+/**
+ * 处理单个通知项
+ * @param {Object} notification 单个通知数据
+ * @returns {Object} 处理后的通知数据
+ */
+const processNotificationItem = (notification) => {
+ // 确保我们有一个有效的通知对象
+ if (!notification) return null;
+
+ // 提取通知数据,兼容不同的API格式
+ const notificationData = notification.data || notification;
+
+ // 设置图标
+ let icon = 'bi-info-circle';
+ const type = notificationData.category || notificationData.type;
+ if (type === 'system') {
+ icon = 'bi-info-circle';
+ } else if (type === 'permission' || type === 'permission_request') {
+ icon = 'bi-shield';
+ }
+
+ // 计算时间显示
+ const createdAt = new Date(notificationData.created_at);
+ const now = new Date();
+
+ // 检查是否是今天
+ const isToday =
+ createdAt.getDate() === now.getDate() &&
+ createdAt.getMonth() === now.getMonth() &&
+ createdAt.getFullYear() === now.getFullYear();
+
+ // 如果是今天,只显示时间;否则显示年月日和时间
+ let timeDisplay;
+ if (isToday) {
+ timeDisplay = createdAt.toLocaleTimeString('zh-CN', {
+ hour: '2-digit',
+ minute: '2-digit',
+ });
+ } else {
+ timeDisplay = createdAt.toLocaleString('zh-CN', {
+ year: 'numeric',
+ month: '2-digit',
+ day: '2-digit',
+ hour: '2-digit',
+ minute: '2-digit',
+ });
+ }
+
+ return {
+ id: notificationData.id,
+ type: type,
+ icon,
+ title: notificationData.title,
+ content: notificationData.content,
+ time: timeDisplay,
+ hasDetail: true,
+ isRead: notificationData.is_read,
+ created_at: notificationData.created_at,
+ sender: notificationData.sender,
+ receiver: notificationData.receiver,
+ related_resource: notificationData.related_resource,
+ metadata: notificationData.metadata || {},
+ };
+};