feat: 支持视频上传、预览及移动端适配
Some checks failed
test/timeline-frontend/pipeline/head There was a failure building this commit
Some checks failed
test/timeline-frontend/pipeline/head There was a failure building this commit
1. 功能增强: - 支持视频文件的上传、存储及缩略图自动生成 - 新增视频播放组件,支持在画廊和时间线中预览视频 - 引入 STOMP 协议支持 WebSocket 实时通知功能 - 增加分享页面(SSR 友好),支持通过 shareId 访问公开内容 2. 移动端优化: - 新增 BottomNav 底部导航组件,优化移动端交互体验 - 引入 useIsMobile 钩子,实现响应式布局切换 - 优化时间线卡片在小屏幕下的显示效果 3. 架构与组件: - 新增 ClientOnly 组件解决 SSR 激活不一致问题 - 新增 ResponsiveGrid 响应式网格布局组件 - 完善 Nginx 配置,增加 MinIO 对象存储代理 - 优化图片懒加载组件 TimelineImage,支持低分辨率占位图
This commit is contained in:
85
src/hooks/useNotifications.ts
Normal file
85
src/hooks/useNotifications.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
|
||||
import { useEffect, useState, useCallback } from 'react';
|
||||
import { useModel, request } from '@umijs/max';
|
||||
import { notification as antdNotification } from 'antd';
|
||||
import { Notification, NotificationType } from '@/types';
|
||||
|
||||
export const useNotifications = () => {
|
||||
const { initialState } = useModel('@@initialState');
|
||||
const { stompClient } = useModel('stomp');
|
||||
const [notifications, setNotifications] = useState<Notification[]>([]);
|
||||
const [unreadCount, setUnreadCount] = useState(0);
|
||||
|
||||
const fetchUnreadNotifications = useCallback(async () => {
|
||||
if (!initialState?.currentUser) return;
|
||||
try {
|
||||
const res = await request<Notification[]>('/user-api/message/unread');
|
||||
setNotifications(res);
|
||||
setUnreadCount(res.length);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch unread notifications', error);
|
||||
}
|
||||
}, [initialState?.currentUser]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchUnreadNotifications();
|
||||
}, [fetchUnreadNotifications]);
|
||||
|
||||
useEffect(() => {
|
||||
if (initialState?.currentUser && stompClient?.connected) {
|
||||
const subscription = stompClient.subscribe(
|
||||
'/user/queue/notification',
|
||||
(message) => {
|
||||
try {
|
||||
const newNotification: Notification = JSON.parse(message.body);
|
||||
setNotifications((prev) => [newNotification, ...prev]);
|
||||
setUnreadCount((prev) => prev + 1);
|
||||
|
||||
antdNotification.open({
|
||||
message: getNotificationTitle(newNotification.type),
|
||||
description: newNotification.content,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to parse notification', error);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}
|
||||
}, [initialState?.currentUser, stompClient]);
|
||||
|
||||
const markAsRead = useCallback(async (ids: number[]) => {
|
||||
try {
|
||||
await request('/api/user/notifications/read', {
|
||||
method: 'POST',
|
||||
data: ids,
|
||||
});
|
||||
setNotifications((prev) =>
|
||||
prev.map((n) => (ids.includes(n.id) ? { ...n, read: true } : n))
|
||||
);
|
||||
setUnreadCount((prev) => prev - ids.length);
|
||||
} catch (error) {
|
||||
console.error('Failed to mark notifications as read', error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const getNotificationTitle = (type: NotificationType) => {
|
||||
switch (type) {
|
||||
case NotificationType.FRIEND_REQUEST:
|
||||
return '好友请求';
|
||||
case NotificationType.FRIEND_ACCEPTED:
|
||||
return '好友请求已接受';
|
||||
case NotificationType.NEW_COMMENT:
|
||||
return '有新的评论';
|
||||
case NotificationType.NEW_LIKE:
|
||||
return '有新的点赞';
|
||||
default:
|
||||
return '系统通知';
|
||||
}
|
||||
};
|
||||
|
||||
return { notifications, unreadCount, markAsRead };
|
||||
};
|
||||
Reference in New Issue
Block a user