Files
张翔 08ea5fbe98 feat(admin): 添加用户管理相关文件
添加用户管理视图、API和状态管理文件
2026-03-28 14:37:29 +08:00

511 lines
12 KiB
TypeScript

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;
}
}