优化平台运营概览并对齐管理端布局

统一管理端侧栏与顶栏 56px 高度;运营概览按 P2-08 重做 KPI、增长趋势、套餐分布与操作日志。
This commit is contained in:
yml2213
2026-07-15 13:45:38 +08:00
parent f6f7fd478e
commit 425cd1f0e2
5 changed files with 426 additions and 134 deletions
+5 -10
View File
@@ -1,19 +1,14 @@
import { Outlet } from 'react-router-dom'
import { Layout } from 'antd'
import AdminSidebar from './AdminSidebar'
const { Content } = Layout
const AdminLayout = () => {
return (
<Layout className="h-screen">
<div className="flex h-screen overflow-hidden bg-neutral-50">
<AdminSidebar />
<Layout>
<Content className="overflow-auto bg-neutral-50 p-6">
<Outlet />
</Content>
</Layout>
</Layout>
<div className="flex-1 min-w-0 h-full overflow-hidden">
<Outlet />
</div>
</div>
)
}
+61 -29
View File
@@ -1,14 +1,13 @@
import { useLocation, useNavigate } from 'react-router-dom'
import { Layout, Menu, Dropdown, Avatar } from 'antd'
import { DashboardOutlined, TeamOutlined, GiftOutlined, ToolOutlined, LogoutOutlined, UserOutlined } from '@ant-design/icons'
import {
DashboardOutlined, TeamOutlined, GiftOutlined, ToolOutlined, LogoutOutlined,
} from '@ant-design/icons'
import { useAuth } from '@/stores/auth'
const { Sider } = Layout
const menuItems = [
{ key: '/admin/dashboard', icon: <DashboardOutlined />, label: '运营概览' },
{ key: '/admin/tenants', icon: <TeamOutlined />, label: '租户管理' },
{ key: '/admin/plans', icon: <GiftOutlined />, label: '套餐管理' },
{ key: '/admin/plans', icon: <GiftOutlined />, label: '套餐定价' },
{ key: '/admin/ops', icon: <ToolOutlined />, label: '系统运维' },
]
@@ -18,6 +17,7 @@ const AdminSidebar = () => {
const { user, logout } = useAuth()
const selectedKey = menuItems.find(item => location.pathname.startsWith(item.key))?.key || '/admin/dashboard'
const initial = (user?.nickname || '管').slice(0, 1)
const handleLogout = () => {
logout()
@@ -25,33 +25,65 @@ const AdminSidebar = () => {
}
return (
<Sider width={220} className="!bg-white border-r border-neutral-200 flex flex-col">
<div className="h-14 flex items-center px-5 border-b border-neutral-100">
<DashboardOutlined className="text-lg text-[#2563eb] mr-2.5" />
<span className="text-base font-semibold text-neutral-900"></span>
<aside
className="shrink-0 flex flex-col h-full bg-white border-r border-neutral-200"
style={{ width: 220 }}
>
<div
className="flex items-center gap-2.5 px-4 shrink-0 border-b border-neutral-200"
style={{ height: 'var(--header-height)' }}
>
<div className="w-8 h-8 rounded-lg bg-[#2563eb] flex items-center justify-center shrink-0">
<DashboardOutlined className="text-white text-sm" />
</div>
<span className="font-semibold text-neutral-900 text-base truncate"></span>
</div>
<Menu
mode="inline"
selectedKeys={[selectedKey]}
items={menuItems}
onClick={({ key }) => navigate(key)}
className="border-e-0 mt-2 flex-1"
/>
<div className="border-t border-neutral-100 p-3">
<Dropdown
menu={{ items: [{ key: 'logout', icon: <LogoutOutlined />, label: '退出登录', onClick: handleLogout }] }}
trigger={['click']}
<nav className="flex-1 overflow-y-auto py-3 px-2">
<ul className="flex flex-col gap-0.5 m-0 p-0 list-none">
{menuItems.map(item => {
const active = selectedKey === item.key
return (
<li key={item.key}>
<button
type="button"
onClick={() => navigate(item.key)}
className={`w-full flex items-center gap-2.5 px-3 py-2 rounded-lg text-sm truncate transition-colors border-0 cursor-pointer ${
active
? 'bg-[#dbeafe] text-[#2563eb] font-medium'
: 'bg-transparent text-neutral-600 hover:bg-neutral-50'
}`}
>
<span className="text-base leading-none">{item.icon}</span>
<span className="truncate">{item.label}</span>
</button>
</li>
)
})}
</ul>
</nav>
<div
className="flex items-center gap-2.5 px-4 shrink-0 border-t border-neutral-200"
style={{ height: 52 }}
>
<div className="w-8 h-8 rounded-full bg-[#dbeafe] text-[#2563eb] flex items-center justify-center text-sm font-semibold shrink-0">
{initial}
</div>
<div className="flex-1 min-w-0">
<div className="text-sm font-medium text-neutral-800 truncate">{user?.nickname || '管理员'}</div>
<div className="text-[11px] text-neutral-400"></div>
</div>
<button
type="button"
title="退出登录"
onClick={handleLogout}
className="w-8 h-8 rounded-md flex items-center justify-center text-neutral-400 hover:bg-neutral-100 hover:text-neutral-600 border-0 bg-transparent cursor-pointer"
>
<div className="flex items-center gap-2 cursor-pointer hover:bg-neutral-50 rounded p-1.5">
<Avatar size={28} icon={<UserOutlined />} className="!bg-blue-100 !text-blue-500" />
<div className="min-w-0">
<div className="text-xs font-medium text-neutral-700 truncate">{user?.nickname || '管理员'}</div>
<div className="text-xs text-neutral-400">线</div>
</div>
</div>
</Dropdown>
<LogoutOutlined />
</button>
</div>
</Sider>
</aside>
)
}