1
0

feat: 统一品牌标识、关于页面三卡片布局与版本诊断功能

- 统一品牌为 Nex:侧边栏、托盘 tooltip、HTML 标题、favicon (PNG 替代 SVG)
- 重构关于页面为三卡片布局(品牌/版本/链接),版本状态 Tag 绝对定位右上角
- 新增 GET /api/version 后端接口,返回 version/commit/build_time
- 新增前端版本一致性诊断:匹配/不匹配/不可判断三种状态
- 同步 delta specs 到主 specs 并归档变更
This commit is contained in:
2026-05-05 03:28:22 +08:00
parent 9e33e570af
commit 8eea30ea11
42 changed files with 1316 additions and 111 deletions

View File

@@ -1,25 +1,37 @@
import { render, screen } from '@testing-library/react'
import { BrowserRouter } from 'react-router'
import userEvent from '@testing-library/user-event'
import { MemoryRouter } from 'react-router'
import { describe, it, expect } from 'vitest'
import { AppLayout } from '@/components/AppLayout'
const renderWithRouter = (component: React.ReactNode) => {
return render(<BrowserRouter>{component}</BrowserRouter>)
return render(<MemoryRouter initialEntries={['/providers']}>{component}</MemoryRouter>)
}
describe('AppLayout', () => {
it('renders sidebar with app name', () => {
renderWithRouter(<AppLayout />)
const appNames = screen.getAllByText('AI Gateway')
expect(appNames.length).toBeGreaterThan(0)
expect(screen.getByText('Nex')).toBeInTheDocument()
expect(screen.getByAltText('Nex logo')).toBeInTheDocument()
})
it('keeps logo visible when sidebar is collapsed', async () => {
const user = userEvent.setup()
renderWithRouter(<AppLayout />)
await user.click(screen.getByLabelText('收起侧边栏'))
expect(screen.getByAltText('Nex logo')).toBeInTheDocument()
expect(screen.queryByText('Nex')).not.toBeInTheDocument()
expect(screen.getByLabelText('展开侧边栏')).toBeInTheDocument()
})
it('renders navigation menu items', () => {
renderWithRouter(<AppLayout />)
expect(screen.getByText('供应商管理')).toBeInTheDocument()
expect(screen.getByText('用量统计')).toBeInTheDocument()
expect(screen.getAllByText('供应商管理').length).toBeGreaterThan(0)
expect(screen.getAllByText('用量统计').length).toBeGreaterThan(0)
})
it('renders settings menu item', () => {
@@ -28,6 +40,12 @@ describe('AppLayout', () => {
expect(screen.getByText('设置')).toBeInTheDocument()
})
it('renders about menu item', () => {
renderWithRouter(<AppLayout />)
expect(screen.getByText('关于')).toBeInTheDocument()
})
it('renders content outlet', () => {
const { container } = renderWithRouter(<AppLayout />)