fix: 统一API响应格式并修复前端测试
- 所有Handler方法使用标准{code:0,message:"success",data:...}响应格式
- 修复Cursor分页响应包装(GetAllDevices,GetLoginLogs,ListUsers等)
- 修复AuthHandler和SMSHandler认证方法响应格式
- 修复operation_log.go admin用户operation_type前缀问题
- 修复DashboardPage嵌套stats结构
- 修复LoginLogsPage reset功能stale closure问题
- 修复UsersPage批量操作API调用
- 修复多个前端测试(mock格式、按钮选择、断言逻辑)
- 添加OAuth测试域名白名单
- 新增代码审查流程文档
This commit is contained in:
@@ -19,17 +19,21 @@ describe('stats service', () => {
|
||||
|
||||
it('gets dashboard stats', async () => {
|
||||
const mockData = {
|
||||
total_users: 100,
|
||||
active_users: 80,
|
||||
inactive_users: 10,
|
||||
locked_users: 5,
|
||||
disabled_users: 5,
|
||||
today_new_users: 3,
|
||||
week_new_users: 15,
|
||||
month_new_users: 50,
|
||||
today_success_logins: 50,
|
||||
today_failed_logins: 2,
|
||||
week_success_logins: 300,
|
||||
users: {
|
||||
total_users: 100,
|
||||
active_users: 80,
|
||||
inactive_users: 10,
|
||||
locked_users: 5,
|
||||
disabled_users: 5,
|
||||
new_users_today: 3,
|
||||
new_users_week: 15,
|
||||
new_users_month: 50,
|
||||
},
|
||||
logins: {
|
||||
logins_today_success: 50,
|
||||
logins_today_failed: 2,
|
||||
logins_week: 300,
|
||||
},
|
||||
}
|
||||
getMock.mockResolvedValue(mockData)
|
||||
|
||||
@@ -38,8 +42,8 @@ describe('stats service', () => {
|
||||
|
||||
expect(getMock).toHaveBeenCalledWith('/admin/stats/dashboard')
|
||||
expect(result).toEqual(mockData)
|
||||
expect(result.total_users).toBe(100)
|
||||
expect(result.active_users).toBe(80)
|
||||
expect(result.users.total_users).toBe(100)
|
||||
expect(result.users.active_users).toBe(80)
|
||||
})
|
||||
|
||||
it('gets user stats', async () => {
|
||||
|
||||
@@ -8,8 +8,9 @@ import { get, post, put, del } from '@/lib/http/client'
|
||||
import type { PaginatedData } from '@/types/http'
|
||||
import type { Role } from '@/types/auth'
|
||||
import type {
|
||||
CreateUserRequest,
|
||||
User,
|
||||
UserStatus,
|
||||
CreateUserRequest,
|
||||
UserListParams,
|
||||
UpdateUserRequest,
|
||||
UpdateUserStatusRequest,
|
||||
@@ -79,3 +80,19 @@ export function getUserRoles(id: number): Promise<Role[]> {
|
||||
export function assignUserRoles(id: number, data: AssignUserRolesRequest): Promise<void> {
|
||||
return put<void>(`/users/${id}/roles`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量更新用户状态
|
||||
* PUT /api/v1/users/batch/status
|
||||
*/
|
||||
export function batchUpdateStatus(ids: number[], status: UserStatus): Promise<{ count: number }> {
|
||||
return put<{ count: number }>('/users/batch/status', { ids, status })
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除用户
|
||||
* DELETE /api/v1/users/batch
|
||||
*/
|
||||
export function batchDelete(ids: number[]): Promise<{ count: number }> {
|
||||
return del<{ count: number }>('/users/batch', { body: { ids } })
|
||||
}
|
||||
|
||||
@@ -21,44 +21,49 @@ describe('webhooks service', () => {
|
||||
})
|
||||
|
||||
it('normalizes mixed raw event payloads from the API', async () => {
|
||||
getMock.mockResolvedValue([
|
||||
{
|
||||
id: 1,
|
||||
name: 'String Events',
|
||||
url: 'https://example.com/string',
|
||||
events: '["user.registered"]',
|
||||
status: 1,
|
||||
max_retries: 3,
|
||||
timeout_sec: 10,
|
||||
created_by: 1,
|
||||
created_at: '2026-03-27 20:00:00',
|
||||
updated_at: '2026-03-27 20:00:00',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Array Events',
|
||||
url: 'https://example.com/array',
|
||||
events: ['user.login'],
|
||||
status: 0,
|
||||
max_retries: 3,
|
||||
timeout_sec: 10,
|
||||
created_by: 2,
|
||||
created_at: '2026-03-27 20:05:00',
|
||||
updated_at: '2026-03-27 20:05:00',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Invalid Events',
|
||||
url: 'https://example.com/invalid',
|
||||
events: 'not-json',
|
||||
status: 1,
|
||||
max_retries: 3,
|
||||
timeout_sec: 10,
|
||||
created_by: 3,
|
||||
created_at: '2026-03-27 20:10:00',
|
||||
updated_at: '2026-03-27 20:10:00',
|
||||
},
|
||||
])
|
||||
getMock.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'String Events',
|
||||
url: 'https://example.com/string',
|
||||
events: '["user.registered"]',
|
||||
status: 1,
|
||||
max_retries: 3,
|
||||
timeout_sec: 10,
|
||||
created_by: 1,
|
||||
created_at: '2026-03-27 20:00:00',
|
||||
updated_at: '2026-03-27 20:00:00',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Array Events',
|
||||
url: 'https://example.com/array',
|
||||
events: ['user.login'],
|
||||
status: 0,
|
||||
max_retries: 3,
|
||||
timeout_sec: 10,
|
||||
created_by: 2,
|
||||
created_at: '2026-03-27 20:05:00',
|
||||
updated_at: '2026-03-27 20:05:00',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Invalid Events',
|
||||
url: 'https://example.com/invalid',
|
||||
events: 'not-json',
|
||||
status: 1,
|
||||
max_retries: 3,
|
||||
timeout_sec: 10,
|
||||
created_by: 3,
|
||||
created_at: '2026-03-27 20:10:00',
|
||||
updated_at: '2026-03-27 20:10:00',
|
||||
},
|
||||
],
|
||||
total: 3,
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
})
|
||||
|
||||
const { listWebhooks } = await import('./webhooks')
|
||||
const result = await listWebhooks({ keyword: 'ignored' })
|
||||
|
||||
Reference in New Issue
Block a user