feat(team-admin): TeamAdminLayout 加消息中心铃铛 + 主题切换 — 跟超管侧栏对齐
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m8s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m8s
之前团管侧栏 footer 只有头像 + 退出,缺这两个常用按钮。 观察者团管访问 /admin/assets 走 AdminLayout 是有这俩的, 团管在 /team/* 反而没有,体验不一致。 照搬 AdminLayout 同款实现: - 消息中心铃铛:60s 轮询 + visibilitychange 立即拉,有未读右上角红点 - 主题切换:深色/浅色切换,月亮/太阳 SVG Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
dccb4cb5e1
commit
ab790fbe65
@ -1,6 +1,8 @@
|
||||
import { NavLink, Outlet, useNavigate } from 'react-router-dom';
|
||||
import { useAuthStore } from '../store/auth';
|
||||
import { useState } from 'react';
|
||||
import { useThemeStore } from '../store/theme';
|
||||
import { useNotificationStore } from '../store/notification';
|
||||
import { useState, useEffect } from 'react';
|
||||
import logoImg from '../assets/logo_32.png';
|
||||
import styles from './AdminLayout.module.css';
|
||||
|
||||
@ -14,9 +16,23 @@ const navItems = [
|
||||
export function TeamAdminLayout() {
|
||||
const user = useAuthStore((s) => s.user);
|
||||
const logout = useAuthStore((s) => s.logout);
|
||||
const theme = useThemeStore((s) => s.theme);
|
||||
const toggleTheme = useThemeStore((s) => s.toggleTheme);
|
||||
const unreadCount = useNotificationStore((s) => s.unreadCount);
|
||||
const fetchUnreadCount = useNotificationStore((s) => s.fetchUnreadCount);
|
||||
const navigate = useNavigate();
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
|
||||
// 60s 轮询未读数 + tab 重新可见时立即拉一次(和 AdminLayout 一致)
|
||||
useEffect(() => {
|
||||
if (!user) return;
|
||||
fetchUnreadCount();
|
||||
const tick = setInterval(fetchUnreadCount, 60_000);
|
||||
const onVis = () => { if (!document.hidden) fetchUnreadCount(); };
|
||||
document.addEventListener('visibilitychange', onVis);
|
||||
return () => { clearInterval(tick); document.removeEventListener('visibilitychange', onVis); };
|
||||
}, [user, fetchUnreadCount]);
|
||||
|
||||
const handleLogout = () => {
|
||||
logout();
|
||||
navigate('/login', { replace: true });
|
||||
@ -80,6 +96,50 @@ export function TeamAdminLayout() {
|
||||
</nav>
|
||||
|
||||
<div className={styles.sidebarFooter}>
|
||||
{/* 消息中心铃铛 — 有未读时右上角红点 */}
|
||||
<button
|
||||
className={styles.themeToggle}
|
||||
onClick={() => navigate('/notifications')}
|
||||
title={unreadCount > 0 ? `${unreadCount} 条未读消息` : '消息中心'}
|
||||
aria-label="消息中心"
|
||||
style={{ position: 'relative' }}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" />
|
||||
<path d="M13.73 21a2 2 0 0 1-3.46 0" />
|
||||
</svg>
|
||||
{!collapsed && <span>消息中心{unreadCount > 0 ? ` (${unreadCount})` : ''}</span>}
|
||||
{unreadCount > 0 && (
|
||||
<span style={{
|
||||
position: 'absolute',
|
||||
top: 6, left: collapsed ? 22 : 22,
|
||||
width: 8, height: 8, borderRadius: '50%',
|
||||
background: 'var(--color-danger)',
|
||||
boxShadow: '0 0 0 2px var(--color-bg-sidebar)',
|
||||
}} />
|
||||
)}
|
||||
</button>
|
||||
|
||||
{/* 主题切换 — 月亮/太阳 SVG */}
|
||||
<button
|
||||
className={styles.themeToggle}
|
||||
onClick={toggleTheme}
|
||||
title={theme === 'dark' ? '切换到浅色主题' : '切换到深色主题'}
|
||||
aria-label={theme === 'dark' ? '切换到浅色主题' : '切换到深色主题'}
|
||||
>
|
||||
{theme === 'dark' ? (
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
<circle cx="12" cy="12" r="4" />
|
||||
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" />
|
||||
</svg>
|
||||
)}
|
||||
{!collapsed && <span>{theme === 'dark' ? '浅色' : '深色'}</span>}
|
||||
</button>
|
||||
|
||||
<div className={styles.userInfo}>
|
||||
<div className={styles.userAvatar}>{user?.username.charAt(0).toUpperCase()}</div>
|
||||
{!collapsed && (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user