feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
This commit is contained in:
@@ -0,0 +1,510 @@
|
||||
import { Page } from '@playwright/test';
|
||||
|
||||
export interface MockConfig {
|
||||
enabled: boolean;
|
||||
mode: 'full' | 'partial' | 'none';
|
||||
mockPaths: string[];
|
||||
delay: number;
|
||||
logCalls: boolean;
|
||||
validateResponses: boolean;
|
||||
dataSource: 'memory' | 'file' | 'database';
|
||||
}
|
||||
|
||||
export interface MockStatus {
|
||||
enabled: boolean;
|
||||
mode: string;
|
||||
activeMocks: string[];
|
||||
callCount: number;
|
||||
}
|
||||
|
||||
export interface MockData {
|
||||
users?: any[];
|
||||
roles?: any[];
|
||||
menus?: any[];
|
||||
operationLogs?: any[];
|
||||
auth?: any;
|
||||
}
|
||||
|
||||
export class MockManager {
|
||||
private config: MockConfig;
|
||||
private mockData: Map<string, any> = new Map();
|
||||
private callHistory: Array<{ timestamp: number; url: string; method: string; response: any }> = [];
|
||||
|
||||
constructor(config: MockConfig) {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
enableMock(): void {
|
||||
this.config.enabled = true;
|
||||
console.log('✅ Mock已启用');
|
||||
}
|
||||
|
||||
disableMock(): void {
|
||||
this.config.enabled = false;
|
||||
console.log('❌ Mock已禁用');
|
||||
}
|
||||
|
||||
configureMock(config: Partial<MockConfig>): void {
|
||||
this.config = { ...this.config, ...config };
|
||||
console.log('⚙️ Mock配置已更新:', this.config);
|
||||
}
|
||||
|
||||
resetMockData(): void {
|
||||
this.mockData.clear();
|
||||
this.callHistory = [];
|
||||
console.log('🔄 Mock数据已重置');
|
||||
}
|
||||
|
||||
presetTestData(data: MockData): void {
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
this.mockData.set(key, value);
|
||||
});
|
||||
console.log('📦 测试数据已预设:', Object.keys(data));
|
||||
}
|
||||
|
||||
clearPresets(): void {
|
||||
this.mockData.clear();
|
||||
console.log('🗑️ 预设数据已清除');
|
||||
}
|
||||
|
||||
getMockStatus(): MockStatus {
|
||||
return {
|
||||
enabled: this.config.enabled,
|
||||
mode: this.config.mode,
|
||||
activeMocks: Array.from(this.mockData.keys()),
|
||||
callCount: this.callHistory.length
|
||||
};
|
||||
}
|
||||
|
||||
getMockData(key: string): any {
|
||||
return this.mockData.get(key);
|
||||
}
|
||||
|
||||
recordCall(url: string, method: string, response: any): void {
|
||||
if (this.config.logCalls) {
|
||||
this.callHistory.push({
|
||||
timestamp: Date.now(),
|
||||
url,
|
||||
method,
|
||||
response
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
getCallHistory(): Array<{ timestamp: number; url: string; method: string; response: any }> {
|
||||
return this.callHistory;
|
||||
}
|
||||
|
||||
async interceptAPIRequest(page: Page): Promise<void> {
|
||||
if (!this.config.enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
await page.route('**/sys/**', async (route) => {
|
||||
const request = route.request();
|
||||
const url = request.url();
|
||||
const method = request.method();
|
||||
|
||||
const shouldMock = this.shouldMockRequest(url, method);
|
||||
|
||||
if (shouldMock) {
|
||||
const mockResponse = await this.getMockResponse(url, method, request.postData());
|
||||
|
||||
if (mockResponse) {
|
||||
this.recordCall(url, method, mockResponse);
|
||||
|
||||
await route.fulfill({
|
||||
status: mockResponse.status || 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(mockResponse.body)
|
||||
});
|
||||
|
||||
console.log(`🎭 Mock响应: ${method} ${url}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await route.continue();
|
||||
});
|
||||
}
|
||||
|
||||
private shouldMockRequest(url: string, method: string): boolean {
|
||||
if (!this.config.enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.config.mode === 'full') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.config.mode === 'partial') {
|
||||
return this.config.mockPaths.some(path => url.includes(path));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async getMockResponse(url: string, method: string, postData?: string): Promise<any> {
|
||||
if (this.config.delay > 0) {
|
||||
await new Promise(resolve => setTimeout(resolve, this.config.delay));
|
||||
}
|
||||
|
||||
if (url.includes('/sys/auth/login') && method === 'POST') {
|
||||
const credentials = JSON.parse(postData || '{}');
|
||||
|
||||
if (credentials.username === 'admin' && credentials.password === 'admin123') {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '登录成功',
|
||||
data: {
|
||||
token: 'mock-token-123456',
|
||||
refreshToken: 'mock-refresh-token-789012',
|
||||
user: {
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
email: 'admin@example.com',
|
||||
phone: '13800138000',
|
||||
status: 'active',
|
||||
createBy: 'system',
|
||||
updateBy: 'admin',
|
||||
createdAt: '2024-01-01T00:00:00.000Z',
|
||||
updatedAt: '2024-01-01T00:00:00.000Z'
|
||||
},
|
||||
permissions: ['*:*:*', 'dashboard:view', 'sys:user:list', 'sys:user:create', 'sys:user:update', 'sys:user:delete', 'sys:role:list', 'sys:role:create', 'sys:role:update', 'sys:role:delete', 'sys:menu:list', 'sys:menu:create', 'sys:menu:update', 'sys:menu:delete', 'sys:operationLog:query']
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '401',
|
||||
message: '用户名或密码错误',
|
||||
data: null
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (url.includes('/sys/auth/logout') && method === 'POST') {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '登出成功',
|
||||
data: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/auth/refresh') && method === 'POST') {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '刷新成功',
|
||||
data: {
|
||||
token: 'new-mock-token-123456',
|
||||
refreshToken: 'new-mock-refresh-token-789012'
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/user') && method === 'GET') {
|
||||
const users = this.mockData.get('users') || [];
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '查询成功',
|
||||
data: {
|
||||
records: users,
|
||||
total: users.length,
|
||||
current: 1,
|
||||
size: 10
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/user') && method === 'POST') {
|
||||
const newUser = JSON.parse(postData || '{}');
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '创建成功',
|
||||
data: {
|
||||
...newUser,
|
||||
id: Math.floor(Math.random() * 10000) + 1,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/user/') && method === 'PUT') {
|
||||
const updatedUser = JSON.parse(postData || '{}');
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '更新成功',
|
||||
data: {
|
||||
...updatedUser,
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/user/') && method === 'DELETE') {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '删除成功',
|
||||
data: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/role') && method === 'GET') {
|
||||
const roles = this.mockData.get('roles') || [];
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '查询成功',
|
||||
data: {
|
||||
records: roles,
|
||||
total: roles.length,
|
||||
current: 1,
|
||||
size: 10
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/role') && method === 'POST') {
|
||||
const newRole = JSON.parse(postData || '{}');
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '创建成功',
|
||||
data: {
|
||||
...newRole,
|
||||
id: Math.floor(Math.random() * 1000) + 1,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/role/') && method === 'PUT') {
|
||||
const updatedRole = JSON.parse(postData || '{}');
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '更新成功',
|
||||
data: {
|
||||
...updatedRole,
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/role/') && method === 'DELETE') {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '删除成功',
|
||||
data: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/menu') && method === 'GET') {
|
||||
const menus = this.mockData.get('menus') || [];
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '查询成功',
|
||||
data: {
|
||||
records: menus,
|
||||
total: menus.length,
|
||||
size: 10,
|
||||
current: 1
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/menu/user/') && method === 'GET') {
|
||||
const userIdMatch = url.match(/\/sys\/menu\/user\/(\d+)/);
|
||||
const userId = userIdMatch ? parseInt(userIdMatch[1]) : 1;
|
||||
|
||||
const userMenus = [
|
||||
{
|
||||
id: 1,
|
||||
code: 'dashboard',
|
||||
name: '仪表盘',
|
||||
path: '/dashboard',
|
||||
icon: 'DashboardOutlined',
|
||||
parentId: 0,
|
||||
sortOrder: 1,
|
||||
status: 'active',
|
||||
createdAt: '2024-01-01T00:00:00.000Z',
|
||||
updatedAt: '2024-01-01T00:00:00.000Z',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
code: 'user',
|
||||
name: '用户管理',
|
||||
path: '/users',
|
||||
icon: 'UserOutlined',
|
||||
parentId: 0,
|
||||
sortOrder: 2,
|
||||
status: 'active',
|
||||
createdAt: '2024-01-01T00:00:00.000Z',
|
||||
updatedAt: '2024-01-01T00:00:00.000Z',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
code: 'role',
|
||||
name: '角色管理',
|
||||
path: '/roles',
|
||||
icon: 'TeamOutlined',
|
||||
parentId: 0,
|
||||
sortOrder: 3,
|
||||
status: 'active',
|
||||
createdAt: '2024-01-01T00:00:00.000Z',
|
||||
updatedAt: '2024-01-01T00:00:00.000Z',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
code: 'menu',
|
||||
name: '菜单管理',
|
||||
path: '/menus',
|
||||
icon: 'MenuOutlined',
|
||||
parentId: 0,
|
||||
sortOrder: 4,
|
||||
status: 'active',
|
||||
createdAt: '2024-01-01T00:00:00.000Z',
|
||||
updatedAt: '2024-01-01T00:00:00.000Z',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
code: 'permission',
|
||||
name: '权限管理',
|
||||
path: '/permissions',
|
||||
icon: 'SafetyOutlined',
|
||||
parentId: 0,
|
||||
sortOrder: 5,
|
||||
status: 'active',
|
||||
createdAt: '2024-01-01T00:00:00.000Z',
|
||||
updatedAt: '2024-01-01T00:00:00.000Z',
|
||||
children: []
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
code: 'operationLog',
|
||||
name: '操作日志',
|
||||
path: '/operation-logs',
|
||||
icon: 'FileTextOutlined',
|
||||
parentId: 0,
|
||||
sortOrder: 6,
|
||||
status: 'active',
|
||||
createdAt: '2024-01-01T00:00:00.000Z',
|
||||
updatedAt: '2024-01-01T00:00:00.000Z',
|
||||
children: []
|
||||
}
|
||||
];
|
||||
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '查询成功',
|
||||
data: userMenus
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/menu') && method === 'POST') {
|
||||
const newMenu = JSON.parse(postData || '{}');
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '创建成功',
|
||||
data: {
|
||||
...newMenu,
|
||||
id: Math.floor(Math.random() * 1000) + 1,
|
||||
createdAt: new Date().toISOString(),
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/menu/') && method === 'PUT') {
|
||||
const updatedMenu = JSON.parse(postData || '{}');
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '更新成功',
|
||||
data: {
|
||||
...updatedMenu,
|
||||
updatedAt: new Date().toISOString()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/menu/') && method === 'DELETE') {
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '删除成功',
|
||||
data: null
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (url.includes('/sys/operationLog') && method === 'GET') {
|
||||
const operationLogs = this.mockData.get('operationLogs') || [];
|
||||
return {
|
||||
status: 200,
|
||||
body: {
|
||||
code: '200',
|
||||
message: '查询成功',
|
||||
data: {
|
||||
records: operationLogs,
|
||||
total: operationLogs.length,
|
||||
current: 1,
|
||||
size: 10
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user