feat(admin): 添加用户管理相关文件

添加用户管理视图、API和状态管理文件
This commit is contained in:
张翔
2026-03-28 14:37:29 +08:00
commit 08ea5fbe98
1643 changed files with 255646 additions and 0 deletions
@@ -0,0 +1,249 @@
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { mount, VueWrapper } from '@vue/test-utils';
import { createPinia, setActivePinia } from 'pinia';
import { createRouter, createMemoryHistory } from 'vue-router';
import { useAppStore } from '@/stores/app.store';
import { useAuthStore } from '@/stores/auth.store';
const mockRoutes = [
{
path: '/',
name: 'Layout',
component: { template: '<div></div>' },
children: [
{
path: '/dashboard',
name: 'Dashboard',
component: { template: '<div></div>' },
meta: { title: '仪表盘', icon: 'DashboardOutlined' }
},
{
path: '/users',
name: 'Users',
component: { template: '<div></div>' },
meta: { title: '用户管理', icon: 'UserOutlined' }
},
{
path: '/system',
name: 'System',
component: { template: '<div></div>' },
meta: { title: '系统管理', icon: 'SettingOutlined' },
children: [
{
path: '/system/roles',
name: 'Roles',
component: { template: '<div></div>' },
meta: { title: '角色管理', icon: 'LockOutlined' }
},
{
path: '/system/menus',
name: 'Menus',
component: { template: '<div></div>' },
meta: { title: '菜单管理', icon: 'MenuOutlined' }
}
]
},
{
path: '/hidden',
name: 'Hidden',
component: { template: '<div></div>' },
meta: { title: '隐藏菜单', icon: 'SettingOutlined', hidden: true }
}
]
}
];
const router = createRouter({
history: createMemoryHistory(),
routes: mockRoutes
});
vi.mock('@/router', () => ({
resetRouter: vi.fn(),
default: router
}));
vi.mock('vue-router', async (importOriginal) => {
const actual = await importOriginal<typeof import('vue-router')>();
return {
...actual,
useRouter: () => router,
useRoute: () => router.currentRoute.value
};
});
import Sidebar from '@/components/Sidebar.vue';
describe('Sidebar 组件', () => {
let wrapper: VueWrapper;
let appStore: ReturnType<typeof useAppStore>;
let authStore: ReturnType<typeof useAuthStore>;
beforeEach(() => {
setActivePinia(createPinia());
appStore = useAppStore();
authStore = useAuthStore();
authStore.user = {
id: 1,
username: 'admin',
email: 'admin@example.com',
phone: '13800138000',
status: 'ACTIVE',
permissions: ['dashboard:view', 'user:view', 'role:view', 'menu:view']
};
wrapper = mount(Sidebar, {
global: {
plugins: [router],
stubs: {
'MenuOutlined': true,
'DashboardOutlined': true,
'UserOutlined': true,
'LockOutlined': true,
'SettingOutlined': true
}
}
});
vi.clearAllMocks();
});
describe('初始状态', () => {
it('应该正确渲染组件', () => {
expect(wrapper.exists()).toBe(true);
});
it('应该显示侧边栏', () => {
expect(wrapper.find('.sidebar').exists()).toBe(true);
});
it('应该显示菜单', () => {
expect(wrapper.find('.sidebar-menu').exists()).toBe(true);
});
});
describe('侧边栏折叠', () => {
it('应该响应侧边栏折叠状态', () => {
appStore.toggleSidebar();
expect(wrapper.vm.collapsed).toBe(true);
});
it('折叠时应该显示图标而不是文字', async () => {
appStore.setSidebarCollapsed(true);
await wrapper.vm.$nextTick();
expect(wrapper.vm.collapsed).toBe(true);
});
});
describe('菜单项生成', () => {
it('应该根据路由生成菜单项', () => {
const menuItems = wrapper.vm.menuItems;
expect(menuItems).toBeDefined();
expect(Array.isArray(menuItems)).toBe(true);
});
it('应该隐藏标记为hidden的菜单项', () => {
const menuItems = wrapper.vm.menuItems;
const hiddenItem = menuItems.find((item: any) => item.key === 'Hidden');
expect(hiddenItem).toBeUndefined();
});
it('应该包含仪表盘菜单项', () => {
const menuItems = wrapper.vm.menuItems;
const dashboardItem = menuItems.find((item: any) => item.key === 'Dashboard');
expect(dashboardItem).toBeDefined();
expect(dashboardItem.label).toBe('仪表盘');
});
});
describe('菜单选择', () => {
it('应该能够选择菜单项', async () => {
await wrapper.vm.handleMenuSelect({ key: 'Dashboard' });
expect(wrapper.emitted('menuSelect')).toBeTruthy();
expect(wrapper.emitted('menuSelect')?.[0]).toEqual(['Dashboard']);
});
it('选择菜单项应该导航到对应路由', async () => {
const pushSpy = vi.spyOn(router, 'push');
await wrapper.vm.handleMenuSelect({ key: 'Dashboard' });
expect(pushSpy).toHaveBeenCalledWith('/dashboard');
pushSpy.mockRestore();
});
});
describe('权限控制', () => {
it('应该检查用户权限', () => {
const hasPermission = wrapper.vm.hasPermission('user:view');
expect(hasPermission).toBe(true);
});
it('没有权限的菜单项应该被隐藏', () => {
authStore.user = {
id: 1,
username: 'admin',
email: 'admin@example.com',
phone: '13800138000',
status: 'ACTIVE',
permissions: []
};
const hasPermission = wrapper.vm.hasPermission('user:view');
expect(hasPermission).toBe(false);
});
it('未定义权限的菜单项应该显示', () => {
const hasPermission = wrapper.vm.hasPermission(undefined);
expect(hasPermission).toBe(true);
});
});
describe('路由监听', () => {
it('应该更新选中的菜单项', () => {
expect(wrapper.vm.selectedKeys).toContain('Dashboard');
});
it('应该展开包含当前路由的父菜单', () => {
const openKeys = wrapper.vm.openKeys;
expect(Array.isArray(openKeys)).toBe(true);
});
});
describe('主题和模式', () => {
it('应该接受主题属性', () => {
const wrapperWithLightTheme = mount(Sidebar, {
props: { theme: 'light' },
global: {
plugins: [router],
stubs: {
'a-layout-sider': {
template: '<div class="sidebar-stub"><slot /></div>'
},
'a-menu': {
template: '<div class="menu-stub"><slot /></div>'
}
}
}
});
expect(wrapperWithLightTheme.exists()).toBe(true);
});
it('应该接受模式属性', () => {
const wrapperWithVerticalMode = mount(Sidebar, {
props: { mode: 'vertical' },
global: {
plugins: [router],
stubs: {
'a-layout-sider': {
template: '<div class="sidebar-stub"><slot /></div>'
},
'a-menu': {
template: '<div class="menu-stub"><slot /></div>'
}
}
}
});
expect(wrapperWithVerticalMode.exists()).toBe(true);
});
});
});