diff --git a/frontend/src/pages/usr/UserList/UserToolbar.tsx b/frontend/src/pages/usr/UserList/UserToolbar.tsx new file mode 100644 index 0000000..bd73d30 --- /dev/null +++ b/frontend/src/pages/usr/UserList/UserToolbar.tsx @@ -0,0 +1,70 @@ +// REQ-USR-003: 用户列表工具栏(刷新/新增/导出Excel/设置齿轮占位,BR8/BR9/BR13/D7/D10) +import { Button } from 'antd'; +import { + FileExcelOutlined, + PlusCircleOutlined, + ReloadOutlined, + SettingOutlined, +} from '@ant-design/icons'; +import { TEXT_ADD, TEXT_EXPORT, TEXT_REFRESH } from './constants'; +import styles from './UserList.module.css'; + +export interface UserToolbarProps { + onRefresh(): void; + onAdd(): void; + onExport(): void; + exporting: boolean; + loading?: boolean; +} + +export default function UserToolbar({ + onRefresh, + onAdd, + onExport, + exporting, + loading = false, +}: UserToolbarProps) { + return ( +
+ + + + + + + {/* 设置齿轮:列显隐 / 偏好预留占位,无后端动作(D7) */} + + + +
+ ); +} diff --git a/frontend/tests/unit/UserToolbar.test.tsx b/frontend/tests/unit/UserToolbar.test.tsx new file mode 100644 index 0000000..8e34379 --- /dev/null +++ b/frontend/tests/unit/UserToolbar.test.tsx @@ -0,0 +1,72 @@ +// REQ-USR-003: UserToolbar 工具栏单测(BR8/BR9/BR13/D7/D10) +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { renderShell } from './renderShell'; +import UserToolbar from '../../src/pages/usr/UserList/UserToolbar'; + +function setup(over?: { exporting?: boolean; loading?: boolean }) { + const onRefresh = vi.fn(); + const onAdd = vi.fn(); + const onExport = vi.fn(); + renderShell( + , + { preloadedAuth: { token: 't', user: { id: 1, sUserName: 'a', sUserType: 'x', sLanguage: '中文' } } }, + ); + return { onRefresh, onAdd, onExport }; +} + +describe('UserToolbar', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders 刷新/新增/导出Excel/设置 buttons', () => { + setup(); + expect(screen.getByTestId('btn-refresh')).toBeInTheDocument(); + expect(screen.getByText('刷新')).toBeInTheDocument(); + expect(screen.getByText('新增')).toBeInTheDocument(); + expect(screen.getByText('导出Excel')).toBeInTheDocument(); + expect(screen.getByTestId('btn-gear')).toBeInTheDocument(); + }); + + it('click 刷新 calls onRefresh / click 新增 calls onAdd (BR8/BR13)', async () => { + const user = userEvent.setup(); + const { onRefresh, onAdd } = setup(); + await user.click(screen.getByTestId('btn-refresh')); + expect(onRefresh).toHaveBeenCalledTimes(1); + await user.click(screen.getByTestId('btn-add')); + expect(onAdd).toHaveBeenCalledTimes(1); + }); + + it('click 导出Excel calls onExport (BR9)', async () => { + const user = userEvent.setup(); + const { onExport } = setup(); + await user.click(screen.getByTestId('btn-export')); + expect(onExport).toHaveBeenCalledTimes(1); + }); + + it('exporting disables 导出Excel and shows loading (BR9)', async () => { + const user = userEvent.setup(); + const { onExport } = setup({ exporting: true }); + const btn = screen.getByTestId('btn-export'); + expect(btn).toBeDisabled(); + await user.click(btn); + expect(onExport).not.toHaveBeenCalled(); + }); + + it('gear setting is placeholder (no callback) (D7)', async () => { + const user = userEvent.setup(); + const { onRefresh, onAdd, onExport } = setup(); + await user.click(screen.getByTestId('btn-gear')); + expect(onRefresh).not.toHaveBeenCalled(); + expect(onAdd).not.toHaveBeenCalled(); + expect(onExport).not.toHaveBeenCalled(); + }); +});