feat(admin): add user balance/concurrency history modal

- Add new API endpoint GET /admin/users/:id/balance-history with pagination and type filter
- Add SumPositiveBalanceByUser for calculating total recharged amount
- Create UserBalanceHistoryModal component with:
  - User info header (email, username, created_at, current balance, notes, total recharged)
  - Type filter dropdown (all/balance/admin_balance/concurrency/admin_concurrency/subscription)
  - Quick deposit/withdraw buttons
  - Paginated history list with icons and colored values
- Add instant tooltip on balance column for better UX
- Add z-index prop to BaseDialog for modal stacking control
- Update i18n translations (zh/en)
This commit is contained in:
bayma888
2026-02-03 00:16:10 +08:00
parent c3d1891ccd
commit 606e29d390
12 changed files with 588 additions and 4 deletions

View File

@@ -59,3 +59,6 @@ export {
}
export default adminAPI
// Re-export types used by components
export type { BalanceHistoryItem } from './users'

View File

@@ -174,6 +174,53 @@ export async function getUserUsageStats(
return data
}
/**
* Balance history item returned from the API
*/
export interface BalanceHistoryItem {
id: number
code: string
type: string
value: number
status: string
used_by: number | null
used_at: string | null
created_at: string
group_id: number | null
validity_days: number
notes: string
user?: { id: number; email: string } | null
group?: { id: number; name: string } | null
}
// Balance history response extends pagination with total_recharged summary
export interface BalanceHistoryResponse extends PaginatedResponse<BalanceHistoryItem> {
total_recharged: number
}
/**
* Get user's balance/concurrency change history
* @param id - User ID
* @param page - Page number
* @param pageSize - Items per page
* @param type - Optional type filter (balance, admin_balance, concurrency, admin_concurrency, subscription)
* @returns Paginated balance history with total_recharged
*/
export async function getUserBalanceHistory(
id: number,
page: number = 1,
pageSize: number = 20,
type?: string
): Promise<BalanceHistoryResponse> {
const params: Record<string, any> = { page, page_size: pageSize }
if (type) params.type = type
const { data } = await apiClient.get<BalanceHistoryResponse>(
`/admin/users/${id}/balance-history`,
{ params }
)
return data
}
export const usersAPI = {
list,
getById,
@@ -184,7 +231,8 @@ export const usersAPI = {
updateConcurrency,
toggleStatus,
getUserApiKeys,
getUserUsageStats
getUserUsageStats,
getUserBalanceHistory
}
export default usersAPI