feat: 新增 useNotifications hook 以处理用户通知,并创建 Home 页面展示财务概览及相关功能。

This commit is contained in:
2026-01-28 16:05:54 +08:00
parent 71472e00b6
commit d0ffdae94e
2 changed files with 18 additions and 3 deletions

View File

@@ -12,12 +12,23 @@ interface NotificationContextType {
const NotificationContext = createContext<NotificationContextType | undefined>(undefined); const NotificationContext = createContext<NotificationContextType | undefined>(undefined);
// 检查用户是否已登录
const isAuthenticated = (): boolean => {
const token = localStorage.getItem('token');
return !!token;
};
export const NotificationProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { export const NotificationProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [notifications, setNotifications] = useState<Notification[]>([]); const [notifications, setNotifications] = useState<Notification[]>([]);
const [unreadCount, setUnreadCount] = useState<number>(0); const [unreadCount, setUnreadCount] = useState<number>(0);
const [loading, setLoading] = useState<boolean>(false); const [loading, setLoading] = useState<boolean>(false);
const fetchNotifications = useCallback(async () => { const fetchNotifications = useCallback(async () => {
// 未登录时跳过请求,避免 401 错误
if (!isAuthenticated()) {
return;
}
try { try {
// Fetch unread count // Fetch unread count
const countRes = await notificationService.getUnreadCount(); const countRes = await notificationService.getUnreadCount();
@@ -32,6 +43,10 @@ export const NotificationProvider: React.FC<{ children: React.ReactNode }> = ({
setNotifications(listRes.data.notifications); setNotifications(listRes.data.notifications);
} }
} catch (error) { } catch (error) {
// 静默处理认证错误,避免控制台噪音
if (error instanceof Error && error.message.includes('Authorization')) {
return;
}
console.error('Failed to fetch notifications:', error); console.error('Failed to fetch notifications:', error);
} }
}, []); }, []);

View File

@@ -324,9 +324,9 @@ function Home() {
<h1 className="greeting-text"> <h1 className="greeting-text">
{greeting}<span className="greeting-highlight"></span> {greeting}<span className="greeting-highlight"></span>
</h1> </h1>
<p className="greeting-insight animate-slide-up delay-100"> <div className="greeting-insight animate-slide-up delay-100">
<Icon icon="solar:bell-bing-bold-duotone" width="16" className="insight-icon" /> <Icon icon="solar:bell-bing-bold-duotone" width="16" className="insight-icon" />
{streakInfo?.message || insight} <span>{streakInfo?.message || insight}</span>
<div className="insight-actions" style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center' }}> <div className="insight-actions" style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center' }}>
{streakInfo && streakInfo.currentStreak > 0 && ( {streakInfo && streakInfo.currentStreak > 0 && (
<div <div
@@ -339,7 +339,7 @@ function Home() {
</div> </div>
)} )}
</div> </div>
</p> </div>
</div> </div>
<div className="header-actions animate-slide-up delay-200"> <div className="header-actions animate-slide-up delay-200">
<button className="health-score-btn" onClick={() => setShowHealthModal(true)}> <button className="health-score-btn" onClick={() => setShowHealthModal(true)}>