- 统一品牌为 Nex:侧边栏、托盘 tooltip、HTML 标题、favicon (PNG 替代 SVG) - 重构关于页面为三卡片布局(品牌/版本/链接),版本状态 Tag 绝对定位右上角 - 新增 GET /api/version 后端接口,返回 version/commit/build_time - 新增前端版本一致性诊断:匹配/不匹配/不可判断三种状态 - 同步 delta specs 到主 specs 并归档变更
117 lines
3.3 KiB
TypeScript
117 lines
3.3 KiB
TypeScript
import { useState } from 'react'
|
|
import { Outlet, useLocation, useNavigate } from 'react-router'
|
|
import {
|
|
ServerIcon,
|
|
ChartLineIcon,
|
|
SettingIcon,
|
|
InfoCircleIcon,
|
|
ChevronLeftIcon,
|
|
ChevronRightIcon,
|
|
} from 'tdesign-icons-react'
|
|
import { Layout, Menu, Button } from 'tdesign-react'
|
|
import { APP_NAME } from '@/constants/app'
|
|
|
|
const { MenuItem } = Menu
|
|
|
|
export function AppLayout() {
|
|
const location = useLocation()
|
|
const navigate = useNavigate()
|
|
const [collapsed, setCollapsed] = useState(false)
|
|
|
|
const getPageTitle = () => {
|
|
if (location.pathname === '/providers') return '供应商管理'
|
|
if (location.pathname === '/stats') return '用量统计'
|
|
if (location.pathname === '/settings') return '设置'
|
|
if (location.pathname === '/about') return '关于'
|
|
return APP_NAME
|
|
}
|
|
|
|
const asideWidth = collapsed ? '64px' : '232px'
|
|
|
|
return (
|
|
<Layout style={{ minHeight: '100vh' }}>
|
|
<Layout.Aside
|
|
width={asideWidth}
|
|
style={{
|
|
overflow: 'hidden',
|
|
height: '100vh',
|
|
position: 'fixed',
|
|
left: 0,
|
|
top: 0,
|
|
bottom: 0,
|
|
}}
|
|
>
|
|
<Menu
|
|
value={location.pathname}
|
|
onChange={(value) => navigate(value as string)}
|
|
collapsed={collapsed}
|
|
width={['232px', '64px']}
|
|
logo={
|
|
<div
|
|
style={{
|
|
height: 64,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 10,
|
|
fontSize: '1.25rem',
|
|
fontWeight: 600,
|
|
}}
|
|
>
|
|
<img src='/icon.png' alt={`${APP_NAME} logo`} style={{ width: 28, height: 28 }} />
|
|
{!collapsed && APP_NAME}
|
|
</div>
|
|
}
|
|
operations={
|
|
<Button
|
|
aria-label={collapsed ? '展开侧边栏' : '收起侧边栏'}
|
|
variant='text'
|
|
shape='square'
|
|
icon={collapsed ? <ChevronRightIcon /> : <ChevronLeftIcon />}
|
|
onClick={() => setCollapsed(!collapsed)}
|
|
/>
|
|
}
|
|
style={{ height: '100%' }}
|
|
>
|
|
<MenuItem value='/providers' icon={<ServerIcon />}>
|
|
供应商管理
|
|
</MenuItem>
|
|
<MenuItem value='/stats' icon={<ChartLineIcon />}>
|
|
用量统计
|
|
</MenuItem>
|
|
<MenuItem value='/settings' icon={<SettingIcon />}>
|
|
设置
|
|
</MenuItem>
|
|
<MenuItem value='/about' icon={<InfoCircleIcon />}>
|
|
关于
|
|
</MenuItem>
|
|
</Menu>
|
|
</Layout.Aside>
|
|
<Layout style={{ marginLeft: asideWidth }}>
|
|
<Layout.Header
|
|
style={{
|
|
padding: '0 2rem',
|
|
background: 'var(--td-bg-color-container)',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
borderBottom: '1px solid var(--td-component-stroke)',
|
|
}}
|
|
>
|
|
<h1 style={{ margin: 0, fontSize: '1.25rem' }}>{getPageTitle()}</h1>
|
|
</Layout.Header>
|
|
<Layout.Content
|
|
style={{
|
|
padding: '2rem',
|
|
maxWidth: '1400px',
|
|
width: '100%',
|
|
margin: '0 auto',
|
|
boxSizing: 'border-box',
|
|
}}
|
|
>
|
|
<Outlet />
|
|
</Layout.Content>
|
|
</Layout>
|
|
</Layout>
|
|
)
|
|
}
|