Track admin users pagination in frontend data layer

This commit is contained in:
RWDai
2026-05-20 16:51:46 +08:00
parent 5130da9710
commit 1be703b56e
2 changed files with 48 additions and 6 deletions

View File

@@ -3,7 +3,7 @@ import { cachedRequest } from '@/utils/cache'
import type { UserSession as SessionRecord } from '@/types/session' import type { UserSession as SessionRecord } from '@/types/session'
import type { BillingPlan, UserPlanEntitlement } from './billing' import type { BillingPlan, UserPlanEntitlement } from './billing'
export type UserRole = 'admin' | 'user' export type UserRole = 'admin' | 'audit_admin' | 'user'
export type ListPolicyMode = 'inherit' | 'unrestricted' | 'specific' | 'deny_all' export type ListPolicyMode = 'inherit' | 'unrestricted' | 'specific' | 'deny_all'
export type RateLimitPolicyMode = 'inherit' | 'system' | 'custom' export type RateLimitPolicyMode = 'inherit' | 'system' | 'custom'
export type FeatureSettings = Record<string, unknown> export type FeatureSettings = Record<string, unknown>
@@ -264,8 +264,29 @@ export interface GetAllUsersOptions {
cacheTtlMs?: number cacheTtlMs?: number
} }
export interface AdminUsersListResponse {
items: User[]
total: number
skip: number
limit: number
has_more: boolean
}
function normalizeAdminUsersListResponse(payload: User[] | AdminUsersListResponse): AdminUsersListResponse {
if (Array.isArray(payload)) {
return {
items: payload,
total: payload.length,
skip: 0,
limit: payload.length,
has_more: false,
}
}
return payload
}
export const usersApi = { export const usersApi = {
async getAllUsers(options: GetAllUsersOptions = {}): Promise<User[]> { async getAllUsersPage(options: GetAllUsersOptions = {}): Promise<AdminUsersListResponse> {
const cacheTtlMs = options.cacheTtlMs ?? 0 const cacheTtlMs = options.cacheTtlMs ?? 0
const params: Record<string, string | number> = {} const params: Record<string, string | number> = {}
const search = options.search?.trim() const search = options.search?.trim()
@@ -292,15 +313,20 @@ export const usersApi = {
return cachedRequest( return cachedRequest(
cacheKey, cacheKey,
async () => { async () => {
const response = await apiClient.get<User[]>('/api/admin/users', { const response = await apiClient.get<User[] | AdminUsersListResponse>('/api/admin/users', {
params: Object.keys(params).length > 0 ? params : undefined, params: Object.keys(params).length > 0 ? params : undefined,
}) })
return response.data return normalizeAdminUsersListResponse(response.data)
}, },
cacheTtlMs, cacheTtlMs,
) )
}, },
async getAllUsers(options: GetAllUsersOptions = {}): Promise<User[]> {
const response = await this.getAllUsersPage(options)
return response.items
},
async getUser(userId: string): Promise<User> { async getUser(userId: string): Promise<User> {
const response = await apiClient.get<User>(`/api/admin/users/${userId}`) const response = await apiClient.get<User>(`/api/admin/users/${userId}`)
return response.data return response.data

View File

@@ -12,6 +12,7 @@ import {
type ResolveUserBatchSelectionResponse, type ResolveUserBatchSelectionResponse,
type UserBatchActionRequest, type UserBatchActionRequest,
type UserBatchActionResponse, type UserBatchActionResponse,
type UserRole,
type UserGroup, type UserGroup,
type UserGroupMember, type UserGroupMember,
type UpsertUserGroupRequest, type UpsertUserGroupRequest,
@@ -24,21 +25,32 @@ import { parseApiError } from '@/utils/errorParser'
export const useUsersStore = defineStore('users', () => { export const useUsersStore = defineStore('users', () => {
const users = ref<User[]>([]) const users = ref<User[]>([])
const total = ref(0)
const skip = ref(0)
const limit = ref(0)
const hasMore = ref(false)
const loading = ref(false) const loading = ref(false)
const error = ref<string | null>(null) const error = ref<string | null>(null)
async function fetchUsers(options: { async function fetchUsers(options: {
cacheTtlMs?: number cacheTtlMs?: number
search?: string search?: string
role?: 'admin' | 'user' role?: UserRole
is_active?: boolean is_active?: boolean
group_id?: string group_id?: string
skip?: number
limit?: number
} = {}) { } = {}) {
loading.value = true loading.value = true
error.value = null error.value = null
try { try {
users.value = await usersApi.getAllUsers(options) const response = await usersApi.getAllUsersPage(options)
users.value = response.items
total.value = response.total
skip.value = response.skip
limit.value = response.limit
hasMore.value = response.has_more
} catch (err: unknown) { } catch (err: unknown) {
error.value = parseApiError(err, '获取用户列表失败') error.value = parseApiError(err, '获取用户列表失败')
} finally { } finally {
@@ -296,6 +308,10 @@ export const useUsersStore = defineStore('users', () => {
return { return {
users, users,
total,
skip,
limit,
hasMore,
loading, loading,
error, error,
fetchUsers, fetchUsers,