style(frontend): 统一 API 模块代码风格

- 移除所有语句末尾分号
- 统一对象属性尾随逗号格式
- 优化类型定义导入顺序
- 提升代码一致性和可读性
This commit is contained in:
ianshaw
2025-12-25 08:41:30 -08:00
parent 34183b527b
commit f79b0f0fad
21 changed files with 802 additions and 751 deletions

View File

@@ -12,7 +12,7 @@ import type {
AccountUsageInfo,
WindowStats,
ClaudeModel,
AccountUsageStatsResponse,
AccountUsageStatsResponse
} from '@/types'
/**
@@ -36,8 +36,8 @@ export async function list(
params: {
page,
page_size: pageSize,
...filters,
},
...filters
}
})
return data
}
@@ -129,7 +129,7 @@ export async function refreshCredentials(id: number): Promise<Account> {
*/
export async function getStats(id: number, days: number = 30): Promise<AccountUsageStatsResponse> {
const { data } = await apiClient.get<AccountUsageStatsResponse>(`/admin/accounts/${id}/stats`, {
params: { days },
params: { days }
})
return data
}
@@ -254,7 +254,7 @@ export async function bulkUpdate(
results: Array<{ account_id: number; success: boolean; error?: string }>
}>('/admin/accounts/bulk-update', {
account_ids: accountIds,
...updates,
...updates
})
return data
}
@@ -277,7 +277,7 @@ export async function getTodayStats(id: number): Promise<WindowStats> {
*/
export async function setSchedulable(id: number, schedulable: boolean): Promise<Account> {
const { data } = await apiClient.post<Account>(`/admin/accounts/${id}/schedulable`, {
schedulable,
schedulable
})
return data
}
@@ -335,7 +335,7 @@ export const accountsAPI = {
batchCreate,
batchUpdateCredentials,
bulkUpdate,
syncFromCrs,
syncFromCrs
}
export default accountsAPI

View File

@@ -3,16 +3,22 @@
* Provides system-wide statistics and metrics
*/
import { apiClient } from '../client';
import type { DashboardStats, TrendDataPoint, ModelStat, ApiKeyUsageTrendPoint, UserUsageTrendPoint } from '@/types';
import { apiClient } from '../client'
import type {
DashboardStats,
TrendDataPoint,
ModelStat,
ApiKeyUsageTrendPoint,
UserUsageTrendPoint
} from '@/types'
/**
* Get dashboard statistics
* @returns Dashboard statistics including users, keys, accounts, and token usage
*/
export async function getStats(): Promise<DashboardStats> {
const { data } = await apiClient.get<DashboardStats>('/admin/dashboard/stats');
return data;
const { data } = await apiClient.get<DashboardStats>('/admin/dashboard/stats')
return data
}
/**
@@ -20,33 +26,33 @@ export async function getStats(): Promise<DashboardStats> {
* @returns Real-time system metrics
*/
export async function getRealtimeMetrics(): Promise<{
active_requests: number;
requests_per_minute: number;
average_response_time: number;
error_rate: number;
active_requests: number
requests_per_minute: number
average_response_time: number
error_rate: number
}> {
const { data } = await apiClient.get<{
active_requests: number;
requests_per_minute: number;
average_response_time: number;
error_rate: number;
}>('/admin/dashboard/realtime');
return data;
active_requests: number
requests_per_minute: number
average_response_time: number
error_rate: number
}>('/admin/dashboard/realtime')
return data
}
export interface TrendParams {
start_date?: string;
end_date?: string;
granularity?: 'day' | 'hour';
user_id?: number;
api_key_id?: number;
start_date?: string
end_date?: string
granularity?: 'day' | 'hour'
user_id?: number
api_key_id?: number
}
export interface TrendResponse {
trend: TrendDataPoint[];
start_date: string;
end_date: string;
granularity: string;
trend: TrendDataPoint[]
start_date: string
end_date: string
granularity: string
}
/**
@@ -55,21 +61,21 @@ export interface TrendResponse {
* @returns Usage trend data
*/
export async function getUsageTrend(params?: TrendParams): Promise<TrendResponse> {
const { data } = await apiClient.get<TrendResponse>('/admin/dashboard/trend', { params });
return data;
const { data } = await apiClient.get<TrendResponse>('/admin/dashboard/trend', { params })
return data
}
export interface ModelStatsParams {
start_date?: string;
end_date?: string;
user_id?: number;
api_key_id?: number;
start_date?: string
end_date?: string
user_id?: number
api_key_id?: number
}
export interface ModelStatsResponse {
models: ModelStat[];
start_date: string;
end_date: string;
models: ModelStat[]
start_date: string
end_date: string
}
/**
@@ -78,19 +84,19 @@ export interface ModelStatsResponse {
* @returns Model usage statistics
*/
export async function getModelStats(params?: ModelStatsParams): Promise<ModelStatsResponse> {
const { data } = await apiClient.get<ModelStatsResponse>('/admin/dashboard/models', { params });
return data;
const { data } = await apiClient.get<ModelStatsResponse>('/admin/dashboard/models', { params })
return data
}
export interface ApiKeyTrendParams extends TrendParams {
limit?: number;
limit?: number
}
export interface ApiKeyTrendResponse {
trend: ApiKeyUsageTrendPoint[];
start_date: string;
end_date: string;
granularity: string;
trend: ApiKeyUsageTrendPoint[]
start_date: string
end_date: string
granularity: string
}
/**
@@ -98,20 +104,24 @@ export interface ApiKeyTrendResponse {
* @param params - Query parameters for filtering
* @returns API key usage trend data
*/
export async function getApiKeyUsageTrend(params?: ApiKeyTrendParams): Promise<ApiKeyTrendResponse> {
const { data } = await apiClient.get<ApiKeyTrendResponse>('/admin/dashboard/api-keys-trend', { params });
return data;
export async function getApiKeyUsageTrend(
params?: ApiKeyTrendParams
): Promise<ApiKeyTrendResponse> {
const { data } = await apiClient.get<ApiKeyTrendResponse>('/admin/dashboard/api-keys-trend', {
params
})
return data
}
export interface UserTrendParams extends TrendParams {
limit?: number;
limit?: number
}
export interface UserTrendResponse {
trend: UserUsageTrendPoint[];
start_date: string;
end_date: string;
granularity: string;
trend: UserUsageTrendPoint[]
start_date: string
end_date: string
granularity: string
}
/**
@@ -120,18 +130,20 @@ export interface UserTrendResponse {
* @returns User usage trend data
*/
export async function getUserUsageTrend(params?: UserTrendParams): Promise<UserTrendResponse> {
const { data } = await apiClient.get<UserTrendResponse>('/admin/dashboard/users-trend', { params });
return data;
const { data } = await apiClient.get<UserTrendResponse>('/admin/dashboard/users-trend', {
params
})
return data
}
export interface BatchUserUsageStats {
user_id: number;
today_actual_cost: number;
total_actual_cost: number;
user_id: number
today_actual_cost: number
total_actual_cost: number
}
export interface BatchUsersUsageResponse {
stats: Record<string, BatchUserUsageStats>;
stats: Record<string, BatchUserUsageStats>
}
/**
@@ -141,19 +153,19 @@ export interface BatchUsersUsageResponse {
*/
export async function getBatchUsersUsage(userIds: number[]): Promise<BatchUsersUsageResponse> {
const { data } = await apiClient.post<BatchUsersUsageResponse>('/admin/dashboard/users-usage', {
user_ids: userIds,
});
return data;
user_ids: userIds
})
return data
}
export interface BatchApiKeyUsageStats {
api_key_id: number;
today_actual_cost: number;
total_actual_cost: number;
api_key_id: number
today_actual_cost: number
total_actual_cost: number
}
export interface BatchApiKeysUsageResponse {
stats: Record<string, BatchApiKeyUsageStats>;
stats: Record<string, BatchApiKeyUsageStats>
}
/**
@@ -161,11 +173,16 @@ export interface BatchApiKeysUsageResponse {
* @param apiKeyIds - Array of API key IDs
* @returns Usage stats map keyed by API key ID
*/
export async function getBatchApiKeysUsage(apiKeyIds: number[]): Promise<BatchApiKeysUsageResponse> {
const { data } = await apiClient.post<BatchApiKeysUsageResponse>('/admin/dashboard/api-keys-usage', {
api_key_ids: apiKeyIds,
});
return data;
export async function getBatchApiKeysUsage(
apiKeyIds: number[]
): Promise<BatchApiKeysUsageResponse> {
const { data } = await apiClient.post<BatchApiKeysUsageResponse>(
'/admin/dashboard/api-keys-usage',
{
api_key_ids: apiKeyIds
}
)
return data
}
export const dashboardAPI = {
@@ -176,7 +193,7 @@ export const dashboardAPI = {
getApiKeyUsageTrend,
getUserUsageTrend,
getBatchUsersUsage,
getBatchApiKeysUsage,
};
getBatchApiKeysUsage
}
export default dashboardAPI;
export default dashboardAPI

View File

@@ -3,14 +3,14 @@
* Handles API key group management for administrators
*/
import { apiClient } from '../client';
import { apiClient } from '../client'
import type {
Group,
GroupPlatform,
CreateGroupRequest,
UpdateGroupRequest,
PaginatedResponse,
} from '@/types';
PaginatedResponse
} from '@/types'
/**
* List all groups with pagination
@@ -23,19 +23,19 @@ export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
platform?: GroupPlatform;
status?: 'active' | 'inactive';
is_exclusive?: boolean;
platform?: GroupPlatform
status?: 'active' | 'inactive'
is_exclusive?: boolean
}
): Promise<PaginatedResponse<Group>> {
const { data } = await apiClient.get<PaginatedResponse<Group>>('/admin/groups', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
...filters
}
})
return data
}
/**
@@ -46,8 +46,8 @@ export async function list(
export async function getAll(platform?: GroupPlatform): Promise<Group[]> {
const { data } = await apiClient.get<Group[]>('/admin/groups/all', {
params: platform ? { platform } : undefined
});
return data;
})
return data
}
/**
@@ -56,7 +56,7 @@ export async function getAll(platform?: GroupPlatform): Promise<Group[]> {
* @returns List of groups for the specified platform
*/
export async function getByPlatform(platform: GroupPlatform): Promise<Group[]> {
return getAll(platform);
return getAll(platform)
}
/**
@@ -65,8 +65,8 @@ export async function getByPlatform(platform: GroupPlatform): Promise<Group[]> {
* @returns Group details
*/
export async function getById(id: number): Promise<Group> {
const { data } = await apiClient.get<Group>(`/admin/groups/${id}`);
return data;
const { data } = await apiClient.get<Group>(`/admin/groups/${id}`)
return data
}
/**
@@ -75,8 +75,8 @@ export async function getById(id: number): Promise<Group> {
* @returns Created group
*/
export async function create(groupData: CreateGroupRequest): Promise<Group> {
const { data } = await apiClient.post<Group>('/admin/groups', groupData);
return data;
const { data } = await apiClient.post<Group>('/admin/groups', groupData)
return data
}
/**
@@ -86,8 +86,8 @@ export async function create(groupData: CreateGroupRequest): Promise<Group> {
* @returns Updated group
*/
export async function update(id: number, updates: UpdateGroupRequest): Promise<Group> {
const { data } = await apiClient.put<Group>(`/admin/groups/${id}`, updates);
return data;
const { data } = await apiClient.put<Group>(`/admin/groups/${id}`, updates)
return data
}
/**
@@ -96,8 +96,8 @@ export async function update(id: number, updates: UpdateGroupRequest): Promise<G
* @returns Success confirmation
*/
export async function deleteGroup(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/groups/${id}`);
return data;
const { data } = await apiClient.delete<{ message: string }>(`/admin/groups/${id}`)
return data
}
/**
@@ -106,11 +106,8 @@ export async function deleteGroup(id: number): Promise<{ message: string }> {
* @param status - New status
* @returns Updated group
*/
export async function toggleStatus(
id: number,
status: 'active' | 'inactive'
): Promise<Group> {
return update(id, { status });
export async function toggleStatus(id: number, status: 'active' | 'inactive'): Promise<Group> {
return update(id, { status })
}
/**
@@ -119,18 +116,18 @@ export async function toggleStatus(
* @returns Group usage statistics
*/
export async function getStats(id: number): Promise<{
total_api_keys: number;
active_api_keys: number;
total_requests: number;
total_cost: number;
total_api_keys: number
active_api_keys: number
total_requests: number
total_cost: number
}> {
const { data } = await apiClient.get<{
total_api_keys: number;
active_api_keys: number;
total_requests: number;
total_cost: number;
}>(`/admin/groups/${id}/stats`);
return data;
total_api_keys: number
active_api_keys: number
total_requests: number
total_cost: number
}>(`/admin/groups/${id}/stats`)
return data
}
/**
@@ -145,13 +142,10 @@ export async function getGroupApiKeys(
page: number = 1,
pageSize: number = 20
): Promise<PaginatedResponse<any>> {
const { data } = await apiClient.get<PaginatedResponse<any>>(
`/admin/groups/${id}/api-keys`,
{
params: { page, page_size: pageSize },
}
);
return data;
const { data } = await apiClient.get<PaginatedResponse<any>>(`/admin/groups/${id}/api-keys`, {
params: { page, page_size: pageSize }
})
return data
}
export const groupsAPI = {
@@ -164,7 +158,7 @@ export const groupsAPI = {
delete: deleteGroup,
toggleStatus,
getStats,
getGroupApiKeys,
};
getGroupApiKeys
}
export default groupsAPI;
export default groupsAPI

View File

@@ -3,16 +3,17 @@
* Centralized exports for all admin API modules
*/
import dashboardAPI from './dashboard';
import usersAPI from './users';
import groupsAPI from './groups';
import accountsAPI from './accounts';
import proxiesAPI from './proxies';
import redeemAPI from './redeem';
import settingsAPI from './settings';
import systemAPI from './system';
import subscriptionsAPI from './subscriptions';
import usageAPI from './usage';
import dashboardAPI from './dashboard'
import usersAPI from './users'
import groupsAPI from './groups'
import accountsAPI from './accounts'
import proxiesAPI from './proxies'
import redeemAPI from './redeem'
import settingsAPI from './settings'
import systemAPI from './system'
import subscriptionsAPI from './subscriptions'
import usageAPI from './usage'
import geminiAPI from './gemini'
/**
* Unified admin API object for convenient access
@@ -28,8 +29,21 @@ export const adminAPI = {
system: systemAPI,
subscriptions: subscriptionsAPI,
usage: usageAPI,
};
gemini: geminiAPI
}
export { dashboardAPI, usersAPI, groupsAPI, accountsAPI, proxiesAPI, redeemAPI, settingsAPI, systemAPI, subscriptionsAPI, usageAPI };
export {
dashboardAPI,
usersAPI,
groupsAPI,
accountsAPI,
proxiesAPI,
redeemAPI,
settingsAPI,
systemAPI,
subscriptionsAPI,
usageAPI,
geminiAPI
}
export default adminAPI;
export default adminAPI

View File

@@ -3,13 +3,8 @@
* Handles proxy server management for administrators
*/
import { apiClient } from '../client';
import type {
Proxy,
CreateProxyRequest,
UpdateProxyRequest,
PaginatedResponse,
} from '@/types';
import { apiClient } from '../client'
import type { Proxy, CreateProxyRequest, UpdateProxyRequest, PaginatedResponse } from '@/types'
/**
* List all proxies with pagination
@@ -22,19 +17,19 @@ export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
protocol?: string;
status?: 'active' | 'inactive';
search?: string;
protocol?: string
status?: 'active' | 'inactive'
search?: string
}
): Promise<PaginatedResponse<Proxy>> {
const { data } = await apiClient.get<PaginatedResponse<Proxy>>('/admin/proxies', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
...filters
}
})
return data
}
/**
@@ -42,8 +37,8 @@ export async function list(
* @returns List of all active proxies
*/
export async function getAll(): Promise<Proxy[]> {
const { data } = await apiClient.get<Proxy[]>('/admin/proxies/all');
return data;
const { data } = await apiClient.get<Proxy[]>('/admin/proxies/all')
return data
}
/**
@@ -52,9 +47,9 @@ export async function getAll(): Promise<Proxy[]> {
*/
export async function getAllWithCount(): Promise<Proxy[]> {
const { data } = await apiClient.get<Proxy[]>('/admin/proxies/all', {
params: { with_count: 'true' },
});
return data;
params: { with_count: 'true' }
})
return data
}
/**
@@ -63,8 +58,8 @@ export async function getAllWithCount(): Promise<Proxy[]> {
* @returns Proxy details
*/
export async function getById(id: number): Promise<Proxy> {
const { data } = await apiClient.get<Proxy>(`/admin/proxies/${id}`);
return data;
const { data } = await apiClient.get<Proxy>(`/admin/proxies/${id}`)
return data
}
/**
@@ -73,8 +68,8 @@ export async function getById(id: number): Promise<Proxy> {
* @returns Created proxy
*/
export async function create(proxyData: CreateProxyRequest): Promise<Proxy> {
const { data } = await apiClient.post<Proxy>('/admin/proxies', proxyData);
return data;
const { data } = await apiClient.post<Proxy>('/admin/proxies', proxyData)
return data
}
/**
@@ -84,8 +79,8 @@ export async function create(proxyData: CreateProxyRequest): Promise<Proxy> {
* @returns Updated proxy
*/
export async function update(id: number, updates: UpdateProxyRequest): Promise<Proxy> {
const { data } = await apiClient.put<Proxy>(`/admin/proxies/${id}`, updates);
return data;
const { data } = await apiClient.put<Proxy>(`/admin/proxies/${id}`, updates)
return data
}
/**
@@ -94,8 +89,8 @@ export async function update(id: number, updates: UpdateProxyRequest): Promise<P
* @returns Success confirmation
*/
export async function deleteProxy(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/proxies/${id}`);
return data;
const { data } = await apiClient.delete<{ message: string }>(`/admin/proxies/${id}`)
return data
}
/**
@@ -104,11 +99,8 @@ export async function deleteProxy(id: number): Promise<{ message: string }> {
* @param status - New status
* @returns Updated proxy
*/
export async function toggleStatus(
id: number,
status: 'active' | 'inactive'
): Promise<Proxy> {
return update(id, { status });
export async function toggleStatus(id: number, status: 'active' | 'inactive'): Promise<Proxy> {
return update(id, { status })
}
/**
@@ -117,24 +109,24 @@ export async function toggleStatus(
* @returns Test result with IP info
*/
export async function testProxy(id: number): Promise<{
success: boolean;
message: string;
latency_ms?: number;
ip_address?: string;
city?: string;
region?: string;
country?: string;
success: boolean
message: string
latency_ms?: number
ip_address?: string
city?: string
region?: string
country?: string
}> {
const { data } = await apiClient.post<{
success: boolean;
message: string;
latency_ms?: number;
ip_address?: string;
city?: string;
region?: string;
country?: string;
}>(`/admin/proxies/${id}/test`);
return data;
success: boolean
message: string
latency_ms?: number
ip_address?: string
city?: string
region?: string
country?: string
}>(`/admin/proxies/${id}/test`)
return data
}
/**
@@ -143,20 +135,20 @@ export async function testProxy(id: number): Promise<{
* @returns Proxy usage statistics
*/
export async function getStats(id: number): Promise<{
total_accounts: number;
active_accounts: number;
total_requests: number;
success_rate: number;
average_latency: number;
total_accounts: number
active_accounts: number
total_requests: number
success_rate: number
average_latency: number
}> {
const { data } = await apiClient.get<{
total_accounts: number;
active_accounts: number;
total_requests: number;
success_rate: number;
average_latency: number;
}>(`/admin/proxies/${id}/stats`);
return data;
total_accounts: number
active_accounts: number
total_requests: number
success_rate: number
average_latency: number
}>(`/admin/proxies/${id}/stats`)
return data
}
/**
@@ -165,10 +157,8 @@ export async function getStats(id: number): Promise<{
* @returns List of accounts using the proxy
*/
export async function getProxyAccounts(id: number): Promise<PaginatedResponse<any>> {
const { data } = await apiClient.get<PaginatedResponse<any>>(
`/admin/proxies/${id}/accounts`
);
return data;
const { data } = await apiClient.get<PaginatedResponse<any>>(`/admin/proxies/${id}/accounts`)
return data
}
/**
@@ -176,21 +166,23 @@ export async function getProxyAccounts(id: number): Promise<PaginatedResponse<an
* @param proxies - Array of proxy data to create
* @returns Creation result with count of created and skipped
*/
export async function batchCreate(proxies: Array<{
protocol: string;
host: string;
port: number;
username?: string;
password?: string;
}>): Promise<{
created: number;
skipped: number;
export async function batchCreate(
proxies: Array<{
protocol: string
host: string
port: number
username?: string
password?: string
}>
): Promise<{
created: number
skipped: number
}> {
const { data } = await apiClient.post<{
created: number;
skipped: number;
}>('/admin/proxies/batch', { proxies });
return data;
created: number
skipped: number
}>('/admin/proxies/batch', { proxies })
return data
}
export const proxiesAPI = {
@@ -205,7 +197,7 @@ export const proxiesAPI = {
testProxy,
getStats,
getProxyAccounts,
batchCreate,
};
batchCreate
}
export default proxiesAPI;
export default proxiesAPI

View File

@@ -3,13 +3,13 @@
* Handles redeem code generation and management for administrators
*/
import { apiClient } from '../client';
import { apiClient } from '../client'
import type {
RedeemCode,
GenerateRedeemCodesRequest,
RedeemCodeType,
PaginatedResponse,
} from '@/types';
PaginatedResponse
} from '@/types'
/**
* List all redeem codes with pagination
@@ -22,19 +22,19 @@ export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
type?: RedeemCodeType;
status?: 'active' | 'used' | 'expired' | 'unused';
search?: string;
type?: RedeemCodeType
status?: 'active' | 'used' | 'expired' | 'unused'
search?: string
}
): Promise<PaginatedResponse<RedeemCode>> {
const { data } = await apiClient.get<PaginatedResponse<RedeemCode>>('/admin/redeem-codes', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
...filters
}
})
return data
}
/**
@@ -43,8 +43,8 @@ export async function list(
* @returns Redeem code details
*/
export async function getById(id: number): Promise<RedeemCode> {
const { data } = await apiClient.get<RedeemCode>(`/admin/redeem-codes/${id}`);
return data;
const { data } = await apiClient.get<RedeemCode>(`/admin/redeem-codes/${id}`)
return data
}
/**
@@ -66,19 +66,19 @@ export async function generate(
const payload: GenerateRedeemCodesRequest = {
count,
type,
value,
};
value
}
// 订阅类型专用字段
if (type === 'subscription') {
payload.group_id = groupId;
payload.group_id = groupId
if (validityDays && validityDays > 0) {
payload.validity_days = validityDays;
payload.validity_days = validityDays
}
}
const { data } = await apiClient.post<RedeemCode[]>('/admin/redeem-codes/generate', payload);
return data;
const { data } = await apiClient.post<RedeemCode[]>('/admin/redeem-codes/generate', payload)
return data
}
/**
@@ -87,8 +87,8 @@ export async function generate(
* @returns Success confirmation
*/
export async function deleteCode(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/redeem-codes/${id}`);
return data;
const { data } = await apiClient.delete<{ message: string }>(`/admin/redeem-codes/${id}`)
return data
}
/**
@@ -97,14 +97,14 @@ export async function deleteCode(id: number): Promise<{ message: string }> {
* @returns Success confirmation
*/
export async function batchDelete(ids: number[]): Promise<{
deleted: number;
message: string;
deleted: number
message: string
}> {
const { data } = await apiClient.post<{
deleted: number;
message: string;
}>('/admin/redeem-codes/batch-delete', { ids });
return data;
deleted: number
message: string
}>('/admin/redeem-codes/batch-delete', { ids })
return data
}
/**
@@ -113,8 +113,8 @@ export async function batchDelete(ids: number[]): Promise<{
* @returns Updated redeem code
*/
export async function expire(id: number): Promise<RedeemCode> {
const { data } = await apiClient.post<RedeemCode>(`/admin/redeem-codes/${id}/expire`);
return data;
const { data } = await apiClient.post<RedeemCode>(`/admin/redeem-codes/${id}/expire`)
return data
}
/**
@@ -122,22 +122,22 @@ export async function expire(id: number): Promise<RedeemCode> {
* @returns Statistics about redeem codes
*/
export async function getStats(): Promise<{
total_codes: number;
active_codes: number;
used_codes: number;
expired_codes: number;
total_value_distributed: number;
by_type: Record<RedeemCodeType, number>;
total_codes: number
active_codes: number
used_codes: number
expired_codes: number
total_value_distributed: number
by_type: Record<RedeemCodeType, number>
}> {
const { data } = await apiClient.get<{
total_codes: number;
active_codes: number;
used_codes: number;
expired_codes: number;
total_value_distributed: number;
by_type: Record<RedeemCodeType, number>;
}>('/admin/redeem-codes/stats');
return data;
total_codes: number
active_codes: number
used_codes: number
expired_codes: number
total_value_distributed: number
by_type: Record<RedeemCodeType, number>
}>('/admin/redeem-codes/stats')
return data
}
/**
@@ -146,14 +146,14 @@ export async function getStats(): Promise<{
* @returns CSV data as blob
*/
export async function exportCodes(filters?: {
type?: RedeemCodeType;
status?: 'active' | 'used' | 'expired';
type?: RedeemCodeType
status?: 'active' | 'used' | 'expired'
}): Promise<Blob> {
const response = await apiClient.get('/admin/redeem-codes/export', {
params: filters,
responseType: 'blob',
});
return response.data;
responseType: 'blob'
})
return response.data
}
export const redeemAPI = {
@@ -164,7 +164,7 @@ export const redeemAPI = {
batchDelete,
expire,
getStats,
exportCodes,
};
exportCodes
}
export default redeemAPI;
export default redeemAPI

View File

@@ -3,37 +3,37 @@
* Handles system settings management for administrators
*/
import { apiClient } from '../client';
import { apiClient } from '../client'
/**
* System settings interface
*/
export interface SystemSettings {
// Registration settings
registration_enabled: boolean;
email_verify_enabled: boolean;
registration_enabled: boolean
email_verify_enabled: boolean
// Default settings
default_balance: number;
default_concurrency: number;
default_balance: number
default_concurrency: number
// OEM settings
site_name: string;
site_logo: string;
site_subtitle: string;
api_base_url: string;
contact_info: string;
doc_url: string;
site_name: string
site_logo: string
site_subtitle: string
api_base_url: string
contact_info: string
doc_url: string
// SMTP settings
smtp_host: string;
smtp_port: number;
smtp_username: string;
smtp_password: string;
smtp_from_email: string;
smtp_from_name: string;
smtp_use_tls: boolean;
smtp_host: string
smtp_port: number
smtp_username: string
smtp_password: string
smtp_from_email: string
smtp_from_name: string
smtp_use_tls: boolean
// Cloudflare Turnstile settings
turnstile_enabled: boolean;
turnstile_site_key: string;
turnstile_secret_key: string;
turnstile_enabled: boolean
turnstile_site_key: string
turnstile_secret_key: string
}
/**
@@ -41,8 +41,8 @@ export interface SystemSettings {
* @returns System settings
*/
export async function getSettings(): Promise<SystemSettings> {
const { data } = await apiClient.get<SystemSettings>('/admin/settings');
return data;
const { data } = await apiClient.get<SystemSettings>('/admin/settings')
return data
}
/**
@@ -51,19 +51,19 @@ export async function getSettings(): Promise<SystemSettings> {
* @returns Updated settings
*/
export async function updateSettings(settings: Partial<SystemSettings>): Promise<SystemSettings> {
const { data } = await apiClient.put<SystemSettings>('/admin/settings', settings);
return data;
const { data } = await apiClient.put<SystemSettings>('/admin/settings', settings)
return data
}
/**
* Test SMTP connection request
*/
export interface TestSmtpRequest {
smtp_host: string;
smtp_port: number;
smtp_username: string;
smtp_password: string;
smtp_use_tls: boolean;
smtp_host: string
smtp_port: number
smtp_username: string
smtp_password: string
smtp_use_tls: boolean
}
/**
@@ -72,22 +72,22 @@ export interface TestSmtpRequest {
* @returns Test result message
*/
export async function testSmtpConnection(config: TestSmtpRequest): Promise<{ message: string }> {
const { data } = await apiClient.post<{ message: string }>('/admin/settings/test-smtp', config);
return data;
const { data } = await apiClient.post<{ message: string }>('/admin/settings/test-smtp', config)
return data
}
/**
* Send test email request
*/
export interface SendTestEmailRequest {
email: string;
smtp_host: string;
smtp_port: number;
smtp_username: string;
smtp_password: string;
smtp_from_email: string;
smtp_from_name: string;
smtp_use_tls: boolean;
email: string
smtp_host: string
smtp_port: number
smtp_username: string
smtp_password: string
smtp_from_email: string
smtp_from_name: string
smtp_use_tls: boolean
}
/**
@@ -96,16 +96,19 @@ export interface SendTestEmailRequest {
* @returns Test result message
*/
export async function sendTestEmail(request: SendTestEmailRequest): Promise<{ message: string }> {
const { data } = await apiClient.post<{ message: string }>('/admin/settings/send-test-email', request);
return data;
const { data } = await apiClient.post<{ message: string }>(
'/admin/settings/send-test-email',
request
)
return data
}
/**
* Admin API Key status response
*/
export interface AdminApiKeyStatus {
exists: boolean;
masked_key: string;
exists: boolean
masked_key: string
}
/**
@@ -113,8 +116,8 @@ export interface AdminApiKeyStatus {
* @returns Status indicating if key exists and masked version
*/
export async function getAdminApiKey(): Promise<AdminApiKeyStatus> {
const { data } = await apiClient.get<AdminApiKeyStatus>('/admin/settings/admin-api-key');
return data;
const { data } = await apiClient.get<AdminApiKeyStatus>('/admin/settings/admin-api-key')
return data
}
/**
@@ -122,8 +125,8 @@ export async function getAdminApiKey(): Promise<AdminApiKeyStatus> {
* @returns The new full API key (only shown once)
*/
export async function regenerateAdminApiKey(): Promise<{ key: string }> {
const { data } = await apiClient.post<{ key: string }>('/admin/settings/admin-api-key/regenerate');
return data;
const { data } = await apiClient.post<{ key: string }>('/admin/settings/admin-api-key/regenerate')
return data
}
/**
@@ -131,8 +134,8 @@ export async function regenerateAdminApiKey(): Promise<{ key: string }> {
* @returns Success message
*/
export async function deleteAdminApiKey(): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>('/admin/settings/admin-api-key');
return data;
const { data } = await apiClient.delete<{ message: string }>('/admin/settings/admin-api-key')
return data
}
export const settingsAPI = {
@@ -142,7 +145,7 @@ export const settingsAPI = {
sendTestEmail,
getAdminApiKey,
regenerateAdminApiKey,
deleteAdminApiKey,
};
deleteAdminApiKey
}
export default settingsAPI;
export default settingsAPI

View File

@@ -3,15 +3,15 @@
* Handles user subscription management for administrators
*/
import { apiClient } from '../client';
import { apiClient } from '../client'
import type {
UserSubscription,
SubscriptionProgress,
AssignSubscriptionRequest,
BulkAssignSubscriptionRequest,
ExtendSubscriptionRequest,
PaginatedResponse,
} from '@/types';
PaginatedResponse
} from '@/types'
/**
* List all subscriptions with pagination
@@ -24,19 +24,22 @@ export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
status?: 'active' | 'expired' | 'revoked';
user_id?: number;
group_id?: number;
status?: 'active' | 'expired' | 'revoked'
user_id?: number
group_id?: number
}
): Promise<PaginatedResponse<UserSubscription>> {
const { data } = await apiClient.get<PaginatedResponse<UserSubscription>>('/admin/subscriptions', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
const { data } = await apiClient.get<PaginatedResponse<UserSubscription>>(
'/admin/subscriptions',
{
params: {
page,
page_size: pageSize,
...filters
}
}
)
return data
}
/**
@@ -45,8 +48,8 @@ export async function list(
* @returns Subscription details
*/
export async function getById(id: number): Promise<UserSubscription> {
const { data } = await apiClient.get<UserSubscription>(`/admin/subscriptions/${id}`);
return data;
const { data } = await apiClient.get<UserSubscription>(`/admin/subscriptions/${id}`)
return data
}
/**
@@ -55,8 +58,8 @@ export async function getById(id: number): Promise<UserSubscription> {
* @returns Subscription progress with usage stats
*/
export async function getProgress(id: number): Promise<SubscriptionProgress> {
const { data } = await apiClient.get<SubscriptionProgress>(`/admin/subscriptions/${id}/progress`);
return data;
const { data } = await apiClient.get<SubscriptionProgress>(`/admin/subscriptions/${id}/progress`)
return data
}
/**
@@ -65,8 +68,8 @@ export async function getProgress(id: number): Promise<SubscriptionProgress> {
* @returns Created subscription
*/
export async function assign(request: AssignSubscriptionRequest): Promise<UserSubscription> {
const { data } = await apiClient.post<UserSubscription>('/admin/subscriptions/assign', request);
return data;
const { data } = await apiClient.post<UserSubscription>('/admin/subscriptions/assign', request)
return data
}
/**
@@ -74,9 +77,14 @@ export async function assign(request: AssignSubscriptionRequest): Promise<UserSu
* @param request - Bulk assignment request
* @returns Created subscriptions
*/
export async function bulkAssign(request: BulkAssignSubscriptionRequest): Promise<UserSubscription[]> {
const { data } = await apiClient.post<UserSubscription[]>('/admin/subscriptions/bulk-assign', request);
return data;
export async function bulkAssign(
request: BulkAssignSubscriptionRequest
): Promise<UserSubscription[]> {
const { data } = await apiClient.post<UserSubscription[]>(
'/admin/subscriptions/bulk-assign',
request
)
return data
}
/**
@@ -85,9 +93,15 @@ export async function bulkAssign(request: BulkAssignSubscriptionRequest): Promis
* @param request - Extension request with days
* @returns Updated subscription
*/
export async function extend(id: number, request: ExtendSubscriptionRequest): Promise<UserSubscription> {
const { data } = await apiClient.post<UserSubscription>(`/admin/subscriptions/${id}/extend`, request);
return data;
export async function extend(
id: number,
request: ExtendSubscriptionRequest
): Promise<UserSubscription> {
const { data } = await apiClient.post<UserSubscription>(
`/admin/subscriptions/${id}/extend`,
request
)
return data
}
/**
@@ -96,8 +110,8 @@ export async function extend(id: number, request: ExtendSubscriptionRequest): Pr
* @returns Success confirmation
*/
export async function revoke(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/subscriptions/${id}`);
return data;
const { data } = await apiClient.delete<{ message: string }>(`/admin/subscriptions/${id}`)
return data
}
/**
@@ -115,10 +129,10 @@ export async function listByGroup(
const { data } = await apiClient.get<PaginatedResponse<UserSubscription>>(
`/admin/groups/${groupId}/subscriptions`,
{
params: { page, page_size: pageSize },
params: { page, page_size: pageSize }
}
);
return data;
)
return data
}
/**
@@ -136,10 +150,10 @@ export async function listByUser(
const { data } = await apiClient.get<PaginatedResponse<UserSubscription>>(
`/admin/users/${userId}/subscriptions`,
{
params: { page, page_size: pageSize },
params: { page, page_size: pageSize }
}
);
return data;
)
return data
}
export const subscriptionsAPI = {
@@ -151,7 +165,7 @@ export const subscriptionsAPI = {
extend,
revoke,
listByGroup,
listByUser,
};
listByUser
}
export default subscriptionsAPI;
export default subscriptionsAPI

View File

@@ -2,31 +2,31 @@
* System API endpoints for admin operations
*/
import { apiClient } from '../client';
import { apiClient } from '../client'
export interface ReleaseInfo {
name: string;
body: string;
published_at: string;
html_url: string;
name: string
body: string
published_at: string
html_url: string
}
export interface VersionInfo {
current_version: string;
latest_version: string;
has_update: boolean;
release_info?: ReleaseInfo;
cached: boolean;
warning?: string;
build_type: string; // "source" for manual builds, "release" for CI builds
current_version: string
latest_version: string
has_update: boolean
release_info?: ReleaseInfo
cached: boolean
warning?: string
build_type: string // "source" for manual builds, "release" for CI builds
}
/**
* Get current version
*/
export async function getVersion(): Promise<{ version: string }> {
const { data } = await apiClient.get<{ version: string }>('/admin/system/version');
return data;
const { data } = await apiClient.get<{ version: string }>('/admin/system/version')
return data
}
/**
@@ -35,14 +35,14 @@ export async function getVersion(): Promise<{ version: string }> {
*/
export async function checkUpdates(force = false): Promise<VersionInfo> {
const { data } = await apiClient.get<VersionInfo>('/admin/system/check-updates', {
params: force ? { force: 'true' } : undefined,
});
return data;
params: force ? { force: 'true' } : undefined
})
return data
}
export interface UpdateResult {
message: string;
need_restart: boolean;
message: string
need_restart: boolean
}
/**
@@ -50,24 +50,24 @@ export interface UpdateResult {
* Downloads and applies the latest version
*/
export async function performUpdate(): Promise<UpdateResult> {
const { data } = await apiClient.post<UpdateResult>('/admin/system/update');
return data;
const { data } = await apiClient.post<UpdateResult>('/admin/system/update')
return data
}
/**
* Rollback to previous version
*/
export async function rollback(): Promise<UpdateResult> {
const { data } = await apiClient.post<UpdateResult>('/admin/system/rollback');
return data;
const { data } = await apiClient.post<UpdateResult>('/admin/system/rollback')
return data
}
/**
* Restart the service
*/
export async function restartService(): Promise<{ message: string }> {
const { data } = await apiClient.post<{ message: string }>('/admin/system/restart');
return data;
const { data } = await apiClient.post<{ message: string }>('/admin/system/restart')
return data
}
export const systemAPI = {
@@ -75,7 +75,7 @@ export const systemAPI = {
checkUpdates,
performUpdate,
rollback,
restartService,
};
restartService
}
export default systemAPI;
export default systemAPI

View File

@@ -3,39 +3,35 @@
* Handles admin-level usage logs and statistics retrieval
*/
import { apiClient } from '../client';
import type {
UsageLog,
UsageQueryParams,
PaginatedResponse,
} from '@/types';
import { apiClient } from '../client'
import type { UsageLog, UsageQueryParams, PaginatedResponse } from '@/types'
// ==================== Types ====================
export interface AdminUsageStatsResponse {
total_requests: number;
total_input_tokens: number;
total_output_tokens: number;
total_cache_tokens: number;
total_tokens: number;
total_cost: number;
total_actual_cost: number;
average_duration_ms: number;
total_requests: number
total_input_tokens: number
total_output_tokens: number
total_cache_tokens: number
total_tokens: number
total_cost: number
total_actual_cost: number
average_duration_ms: number
}
export interface SimpleUser {
id: number;
email: string;
id: number
email: string
}
export interface SimpleApiKey {
id: number;
name: string;
user_id: number;
id: number
name: string
user_id: number
}
export interface AdminUsageQueryParams extends UsageQueryParams {
user_id?: number;
user_id?: number
}
// ==================== API Functions ====================
@@ -47,9 +43,9 @@ export interface AdminUsageQueryParams extends UsageQueryParams {
*/
export async function list(params: AdminUsageQueryParams): Promise<PaginatedResponse<UsageLog>> {
const { data } = await apiClient.get<PaginatedResponse<UsageLog>>('/admin/usage', {
params,
});
return data;
params
})
return data
}
/**
@@ -58,16 +54,16 @@ export async function list(params: AdminUsageQueryParams): Promise<PaginatedResp
* @returns Usage statistics
*/
export async function getStats(params: {
user_id?: number;
api_key_id?: number;
period?: string;
start_date?: string;
end_date?: string;
user_id?: number
api_key_id?: number
period?: string
start_date?: string
end_date?: string
}): Promise<AdminUsageStatsResponse> {
const { data } = await apiClient.get<AdminUsageStatsResponse>('/admin/usage/stats', {
params,
});
return data;
params
})
return data
}
/**
@@ -77,9 +73,9 @@ export async function getStats(params: {
*/
export async function searchUsers(keyword: string): Promise<SimpleUser[]> {
const { data } = await apiClient.get<SimpleUser[]>('/admin/usage/search-users', {
params: { q: keyword },
});
return data;
params: { q: keyword }
})
return data
}
/**
@@ -89,24 +85,24 @@ export async function searchUsers(keyword: string): Promise<SimpleUser[]> {
* @returns List of matching API keys (max 30)
*/
export async function searchApiKeys(userId?: number, keyword?: string): Promise<SimpleApiKey[]> {
const params: Record<string, unknown> = {};
const params: Record<string, unknown> = {}
if (userId !== undefined) {
params.user_id = userId;
params.user_id = userId
}
if (keyword) {
params.q = keyword;
params.q = keyword
}
const { data } = await apiClient.get<SimpleApiKey[]>('/admin/usage/search-api-keys', {
params,
});
return data;
params
})
return data
}
export const adminUsageAPI = {
list,
getStats,
searchUsers,
searchApiKeys,
};
searchApiKeys
}
export default adminUsageAPI;
export default adminUsageAPI

View File

@@ -3,8 +3,8 @@
* Handles user management for administrators
*/
import { apiClient } from '../client';
import type { User, UpdateUserRequest, PaginatedResponse } from '@/types';
import { apiClient } from '../client'
import type { User, UpdateUserRequest, PaginatedResponse } from '@/types'
/**
* List all users with pagination
@@ -17,19 +17,19 @@ export async function list(
page: number = 1,
pageSize: number = 20,
filters?: {
status?: 'active' | 'disabled';
role?: 'admin' | 'user';
search?: string;
status?: 'active' | 'disabled'
role?: 'admin' | 'user'
search?: string
}
): Promise<PaginatedResponse<User>> {
const { data } = await apiClient.get<PaginatedResponse<User>>('/admin/users', {
params: {
page,
page_size: pageSize,
...filters,
},
});
return data;
...filters
}
})
return data
}
/**
@@ -38,8 +38,8 @@ export async function list(
* @returns User details
*/
export async function getById(id: number): Promise<User> {
const { data } = await apiClient.get<User>(`/admin/users/${id}`);
return data;
const { data } = await apiClient.get<User>(`/admin/users/${id}`)
return data
}
/**
@@ -48,14 +48,14 @@ export async function getById(id: number): Promise<User> {
* @returns Created user
*/
export async function create(userData: {
email: string;
password: string;
balance?: number;
concurrency?: number;
allowed_groups?: number[] | null;
email: string
password: string
balance?: number
concurrency?: number
allowed_groups?: number[] | null
}): Promise<User> {
const { data } = await apiClient.post<User>('/admin/users', userData);
return data;
const { data } = await apiClient.post<User>('/admin/users', userData)
return data
}
/**
@@ -65,8 +65,8 @@ export async function create(userData: {
* @returns Updated user
*/
export async function update(id: number, updates: UpdateUserRequest): Promise<User> {
const { data } = await apiClient.put<User>(`/admin/users/${id}`, updates);
return data;
const { data } = await apiClient.put<User>(`/admin/users/${id}`, updates)
return data
}
/**
@@ -75,8 +75,8 @@ export async function update(id: number, updates: UpdateUserRequest): Promise<Us
* @returns Success confirmation
*/
export async function deleteUser(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/admin/users/${id}`);
return data;
const { data } = await apiClient.delete<{ message: string }>(`/admin/users/${id}`)
return data
}
/**
@@ -96,9 +96,9 @@ export async function updateBalance(
const { data } = await apiClient.post<User>(`/admin/users/${id}/balance`, {
balance,
operation,
notes: notes || '',
});
return data;
notes: notes || ''
})
return data
}
/**
@@ -108,7 +108,7 @@ export async function updateBalance(
* @returns Updated user
*/
export async function updateConcurrency(id: number, concurrency: number): Promise<User> {
return update(id, { concurrency });
return update(id, { concurrency })
}
/**
@@ -118,7 +118,7 @@ export async function updateConcurrency(id: number, concurrency: number): Promis
* @returns Updated user
*/
export async function toggleStatus(id: number, status: 'active' | 'disabled'): Promise<User> {
return update(id, { status });
return update(id, { status })
}
/**
@@ -127,8 +127,8 @@ export async function toggleStatus(id: number, status: 'active' | 'disabled'): P
* @returns List of user's API keys
*/
export async function getUserApiKeys(id: number): Promise<PaginatedResponse<any>> {
const { data } = await apiClient.get<PaginatedResponse<any>>(`/admin/users/${id}/api-keys`);
return data;
const { data } = await apiClient.get<PaginatedResponse<any>>(`/admin/users/${id}/api-keys`)
return data
}
/**
@@ -141,18 +141,18 @@ export async function getUserUsageStats(
id: number,
period: string = 'month'
): Promise<{
total_requests: number;
total_cost: number;
total_tokens: number;
total_requests: number
total_cost: number
total_tokens: number
}> {
const { data } = await apiClient.get<{
total_requests: number;
total_cost: number;
total_tokens: number;
total_requests: number
total_cost: number
total_tokens: number
}>(`/admin/users/${id}/usage`, {
params: { period },
});
return data;
params: { period }
})
return data
}
export const usersAPI = {
@@ -165,7 +165,7 @@ export const usersAPI = {
updateConcurrency,
toggleStatus,
getUserApiKeys,
getUserUsageStats,
};
getUserUsageStats
}
export default usersAPI;
export default usersAPI

View File

@@ -3,29 +3,37 @@
* Handles user login, registration, and logout operations
*/
import { apiClient } from './client';
import type { LoginRequest, RegisterRequest, AuthResponse, User, SendVerifyCodeRequest, SendVerifyCodeResponse, PublicSettings } from '@/types';
import { apiClient } from './client'
import type {
LoginRequest,
RegisterRequest,
AuthResponse,
User,
SendVerifyCodeRequest,
SendVerifyCodeResponse,
PublicSettings
} from '@/types'
/**
* Store authentication token in localStorage
*/
export function setAuthToken(token: string): void {
localStorage.setItem('auth_token', token);
localStorage.setItem('auth_token', token)
}
/**
* Get authentication token from localStorage
*/
export function getAuthToken(): string | null {
return localStorage.getItem('auth_token');
return localStorage.getItem('auth_token')
}
/**
* Clear authentication token from localStorage
*/
export function clearAuthToken(): void {
localStorage.removeItem('auth_token');
localStorage.removeItem('auth_user');
localStorage.removeItem('auth_token')
localStorage.removeItem('auth_user')
}
/**
@@ -34,13 +42,13 @@ export function clearAuthToken(): void {
* @returns Authentication response with token and user data
*/
export async function login(credentials: LoginRequest): Promise<AuthResponse> {
const { data } = await apiClient.post<AuthResponse>('/auth/login', credentials);
const { data } = await apiClient.post<AuthResponse>('/auth/login', credentials)
// Store token and user data
setAuthToken(data.access_token);
localStorage.setItem('auth_user', JSON.stringify(data.user));
setAuthToken(data.access_token)
localStorage.setItem('auth_user', JSON.stringify(data.user))
return data;
return data
}
/**
@@ -49,13 +57,13 @@ export async function login(credentials: LoginRequest): Promise<AuthResponse> {
* @returns Authentication response with token and user data
*/
export async function register(userData: RegisterRequest): Promise<AuthResponse> {
const { data } = await apiClient.post<AuthResponse>('/auth/register', userData);
const { data } = await apiClient.post<AuthResponse>('/auth/register', userData)
// Store token and user data
setAuthToken(data.access_token);
localStorage.setItem('auth_user', JSON.stringify(data.user));
setAuthToken(data.access_token)
localStorage.setItem('auth_user', JSON.stringify(data.user))
return data;
return data
}
/**
@@ -63,8 +71,8 @@ export async function register(userData: RegisterRequest): Promise<AuthResponse>
* @returns User profile data
*/
export async function getCurrentUser(): Promise<User> {
const { data } = await apiClient.get<User>('/auth/me');
return data;
const { data } = await apiClient.get<User>('/auth/me')
return data
}
/**
@@ -72,7 +80,7 @@ export async function getCurrentUser(): Promise<User> {
* Clears authentication token and user data from localStorage
*/
export function logout(): void {
clearAuthToken();
clearAuthToken()
// Optionally redirect to login page
// window.location.href = '/login';
}
@@ -82,7 +90,7 @@ export function logout(): void {
* @returns True if user has valid token
*/
export function isAuthenticated(): boolean {
return getAuthToken() !== null;
return getAuthToken() !== null
}
/**
@@ -90,8 +98,8 @@ export function isAuthenticated(): boolean {
* @returns Public settings including registration and Turnstile config
*/
export async function getPublicSettings(): Promise<PublicSettings> {
const { data } = await apiClient.get<PublicSettings>('/settings/public');
return data;
const { data } = await apiClient.get<PublicSettings>('/settings/public')
return data
}
/**
@@ -99,9 +107,11 @@ export async function getPublicSettings(): Promise<PublicSettings> {
* @param request - Email and optional Turnstile token
* @returns Response with countdown seconds
*/
export async function sendVerifyCode(request: SendVerifyCodeRequest): Promise<SendVerifyCodeResponse> {
const { data } = await apiClient.post<SendVerifyCodeResponse>('/auth/send-verify-code', request);
return data;
export async function sendVerifyCode(
request: SendVerifyCodeRequest
): Promise<SendVerifyCodeResponse> {
const { data } = await apiClient.post<SendVerifyCodeResponse>('/auth/send-verify-code', request)
return data
}
export const authAPI = {
@@ -114,7 +124,7 @@ export const authAPI = {
getAuthToken,
clearAuthToken,
getPublicSettings,
sendVerifyCode,
};
sendVerifyCode
}
export default authAPI;
export default authAPI

View File

@@ -3,70 +3,70 @@
* Base client with interceptors for authentication and error handling
*/
import axios, { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from 'axios';
import type { ApiResponse } from '@/types';
import axios, { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from 'axios'
import type { ApiResponse } from '@/types'
// ==================== Axios Instance Configuration ====================
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api/v1';
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || '/api/v1'
export const apiClient: AxiosInstance = axios.create({
baseURL: API_BASE_URL,
timeout: 30000,
headers: {
'Content-Type': 'application/json',
},
});
'Content-Type': 'application/json'
}
})
// ==================== Request Interceptor ====================
apiClient.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
// Attach token from localStorage
const token = localStorage.getItem('auth_token');
const token = localStorage.getItem('auth_token')
if (token && config.headers) {
config.headers.Authorization = `Bearer ${token}`;
config.headers.Authorization = `Bearer ${token}`
}
return config;
return config
},
(error) => {
return Promise.reject(error);
return Promise.reject(error)
}
);
)
// ==================== Response Interceptor ====================
apiClient.interceptors.response.use(
(response) => {
// Unwrap standard API response format { code, message, data }
const apiResponse = response.data as ApiResponse<unknown>;
const apiResponse = response.data as ApiResponse<unknown>
if (apiResponse && typeof apiResponse === 'object' && 'code' in apiResponse) {
if (apiResponse.code === 0) {
// Success - return the data portion
response.data = apiResponse.data;
response.data = apiResponse.data
} else {
// API error
return Promise.reject({
status: response.status,
code: apiResponse.code,
message: apiResponse.message || 'Unknown error',
});
message: apiResponse.message || 'Unknown error'
})
}
}
return response;
return response
},
(error: AxiosError<ApiResponse<unknown>>) => {
// Handle common errors
if (error.response) {
const { status, data } = error.response;
const { status, data } = error.response
// 401: Unauthorized - clear token and redirect to login
if (status === 401) {
localStorage.removeItem('auth_token');
localStorage.removeItem('auth_user');
localStorage.removeItem('auth_token')
localStorage.removeItem('auth_user')
// Only redirect if not already on login page
if (!window.location.pathname.includes('/login')) {
window.location.href = '/login';
window.location.href = '/login'
}
}
@@ -74,16 +74,16 @@ apiClient.interceptors.response.use(
return Promise.reject({
status,
code: data?.code,
message: data?.message || error.message,
});
message: data?.message || error.message
})
}
// Network error
return Promise.reject({
status: 0,
message: 'Network error. Please check your connection.',
});
message: 'Network error. Please check your connection.'
})
}
);
)
export default apiClient;
export default apiClient

View File

@@ -3,8 +3,8 @@
* Handles group-related operations for regular users
*/
import { apiClient } from './client';
import type { Group } from '@/types';
import { apiClient } from './client'
import type { Group } from '@/types'
/**
* Get available groups that the current user can bind to API keys
@@ -14,12 +14,12 @@ import type { Group } from '@/types';
* @returns List of available groups
*/
export async function getAvailable(): Promise<Group[]> {
const { data } = await apiClient.get<Group[]>('/groups/available');
return data;
const { data } = await apiClient.get<Group[]>('/groups/available')
return data
}
export const userGroupsAPI = {
getAvailable,
};
getAvailable
}
export default userGroupsAPI;
export default userGroupsAPI

View File

@@ -4,20 +4,20 @@
*/
// Re-export the HTTP client
export { apiClient } from './client';
export { apiClient } from './client'
// Auth API
export { authAPI } from './auth';
export { authAPI } from './auth'
// User APIs
export { keysAPI } from './keys';
export { usageAPI } from './usage';
export { userAPI } from './user';
export { redeemAPI, type RedeemHistoryItem } from './redeem';
export { userGroupsAPI } from './groups';
export { keysAPI } from './keys'
export { usageAPI } from './usage'
export { userAPI } from './user'
export { redeemAPI, type RedeemHistoryItem } from './redeem'
export { userGroupsAPI } from './groups'
// Admin APIs
export { adminAPI } from './admin';
export { adminAPI } from './admin'
// Default export
export { default } from './client';
export { default } from './client'

View File

@@ -3,13 +3,8 @@
* Handles CRUD operations for user API keys
*/
import { apiClient } from './client';
import type {
ApiKey,
CreateApiKeyRequest,
UpdateApiKeyRequest,
PaginatedResponse,
} from '@/types';
import { apiClient } from './client'
import type { ApiKey, CreateApiKeyRequest, UpdateApiKeyRequest, PaginatedResponse } from '@/types'
/**
* List all API keys for current user
@@ -17,11 +12,14 @@ import type {
* @param pageSize - Items per page (default: 10)
* @returns Paginated list of API keys
*/
export async function list(page: number = 1, pageSize: number = 10): Promise<PaginatedResponse<ApiKey>> {
export async function list(
page: number = 1,
pageSize: number = 10
): Promise<PaginatedResponse<ApiKey>> {
const { data } = await apiClient.get<PaginatedResponse<ApiKey>>('/keys', {
params: { page, page_size: pageSize },
});
return data;
params: { page, page_size: pageSize }
})
return data
}
/**
@@ -30,8 +28,8 @@ export async function list(page: number = 1, pageSize: number = 10): Promise<Pag
* @returns API key details
*/
export async function getById(id: number): Promise<ApiKey> {
const { data } = await apiClient.get<ApiKey>(`/keys/${id}`);
return data;
const { data } = await apiClient.get<ApiKey>(`/keys/${id}`)
return data
}
/**
@@ -41,17 +39,21 @@ export async function getById(id: number): Promise<ApiKey> {
* @param customKey - Optional custom key value
* @returns Created API key
*/
export async function create(name: string, groupId?: number | null, customKey?: string): Promise<ApiKey> {
const payload: CreateApiKeyRequest = { name };
export async function create(
name: string,
groupId?: number | null,
customKey?: string
): Promise<ApiKey> {
const payload: CreateApiKeyRequest = { name }
if (groupId !== undefined) {
payload.group_id = groupId;
payload.group_id = groupId
}
if (customKey) {
payload.custom_key = customKey;
payload.custom_key = customKey
}
const { data } = await apiClient.post<ApiKey>('/keys', payload);
return data;
const { data } = await apiClient.post<ApiKey>('/keys', payload)
return data
}
/**
@@ -61,8 +63,8 @@ export async function create(name: string, groupId?: number | null, customKey?:
* @returns Updated API key
*/
export async function update(id: number, updates: UpdateApiKeyRequest): Promise<ApiKey> {
const { data } = await apiClient.put<ApiKey>(`/keys/${id}`, updates);
return data;
const { data } = await apiClient.put<ApiKey>(`/keys/${id}`, updates)
return data
}
/**
@@ -71,8 +73,8 @@ export async function update(id: number, updates: UpdateApiKeyRequest): Promise<
* @returns Success confirmation
*/
export async function deleteKey(id: number): Promise<{ message: string }> {
const { data } = await apiClient.delete<{ message: string }>(`/keys/${id}`);
return data;
const { data } = await apiClient.delete<{ message: string }>(`/keys/${id}`)
return data
}
/**
@@ -81,11 +83,8 @@ export async function deleteKey(id: number): Promise<{ message: string }> {
* @param status - New status
* @returns Updated API key
*/
export async function toggleStatus(
id: number,
status: 'active' | 'inactive'
): Promise<ApiKey> {
return update(id, { status });
export async function toggleStatus(id: number, status: 'active' | 'inactive'): Promise<ApiKey> {
return update(id, { status })
}
export const keysAPI = {
@@ -94,7 +93,7 @@ export const keysAPI = {
create,
update,
delete: deleteKey,
toggleStatus,
};
toggleStatus
}
export default keysAPI;
export default keysAPI

View File

@@ -3,24 +3,24 @@
* Handles redeem code redemption for users
*/
import { apiClient } from './client';
import type { RedeemCodeRequest } from '@/types';
import { apiClient } from './client'
import type { RedeemCodeRequest } from '@/types'
export interface RedeemHistoryItem {
id: number;
code: string;
type: string;
value: number;
status: string;
used_at: string;
created_at: string;
id: number
code: string
type: string
value: number
status: string
used_at: string
created_at: string
// 订阅类型专用字段
group_id?: number;
validity_days?: number;
group_id?: number
validity_days?: number
group?: {
id: number;
name: string;
};
id: number
name: string
}
}
/**
@@ -29,23 +29,23 @@ export interface RedeemHistoryItem {
* @returns Redemption result with updated balance or concurrency
*/
export async function redeem(code: string): Promise<{
message: string;
type: string;
value: number;
new_balance?: number;
new_concurrency?: number;
message: string
type: string
value: number
new_balance?: number
new_concurrency?: number
}> {
const payload: RedeemCodeRequest = { code };
const payload: RedeemCodeRequest = { code }
const { data } = await apiClient.post<{
message: string;
type: string;
value: number;
new_balance?: number;
new_concurrency?: number;
}>('/redeem', payload);
message: string
type: string
value: number
new_balance?: number
new_concurrency?: number
}>('/redeem', payload)
return data;
return data
}
/**
@@ -53,13 +53,13 @@ export async function redeem(code: string): Promise<{
* @returns List of redeemed codes
*/
export async function getHistory(): Promise<RedeemHistoryItem[]> {
const { data } = await apiClient.get<RedeemHistoryItem[]>('/redeem/history');
return data;
const { data } = await apiClient.get<RedeemHistoryItem[]>('/redeem/history')
return data
}
export const redeemAPI = {
redeem,
getHistory,
};
getHistory
}
export default redeemAPI;
export default redeemAPI

View File

@@ -1,87 +1,87 @@
/**
* Setup API endpoints
*/
import axios from 'axios';
import axios from 'axios'
// Create a separate client for setup endpoints (not under /api/v1)
const setupClient = axios.create({
baseURL: '',
timeout: 30000,
headers: {
'Content-Type': 'application/json',
},
});
'Content-Type': 'application/json'
}
})
export interface SetupStatus {
needs_setup: boolean;
step: string;
needs_setup: boolean
step: string
}
export interface DatabaseConfig {
host: string;
port: number;
user: string;
password: string;
dbname: string;
sslmode: string;
host: string
port: number
user: string
password: string
dbname: string
sslmode: string
}
export interface RedisConfig {
host: string;
port: number;
password: string;
db: number;
host: string
port: number
password: string
db: number
}
export interface AdminConfig {
email: string;
password: string;
email: string
password: string
}
export interface ServerConfig {
host: string;
port: number;
mode: string;
host: string
port: number
mode: string
}
export interface InstallRequest {
database: DatabaseConfig;
redis: RedisConfig;
admin: AdminConfig;
server: ServerConfig;
database: DatabaseConfig
redis: RedisConfig
admin: AdminConfig
server: ServerConfig
}
export interface InstallResponse {
message: string;
restart: boolean;
message: string
restart: boolean
}
/**
* Get setup status
*/
export async function getSetupStatus(): Promise<SetupStatus> {
const response = await setupClient.get('/setup/status');
return response.data.data;
const response = await setupClient.get('/setup/status')
return response.data.data
}
/**
* Test database connection
*/
export async function testDatabase(config: DatabaseConfig): Promise<void> {
await setupClient.post('/setup/test-db', config);
await setupClient.post('/setup/test-db', config)
}
/**
* Test Redis connection
*/
export async function testRedis(config: RedisConfig): Promise<void> {
await setupClient.post('/setup/test-redis', config);
await setupClient.post('/setup/test-redis', config)
}
/**
* Perform installation
*/
export async function install(config: InstallRequest): Promise<InstallResponse> {
const response = await setupClient.post('/setup/install', config);
return response.data.data;
const response = await setupClient.post('/setup/install', config)
return response.data.data
}

View File

@@ -3,64 +3,68 @@
* API for regular users to view their own subscriptions and progress
*/
import { apiClient } from './client';
import type { UserSubscription, SubscriptionProgress } from '@/types';
import { apiClient } from './client'
import type { UserSubscription, SubscriptionProgress } from '@/types'
/**
* Subscription summary for user dashboard
*/
export interface SubscriptionSummary {
active_count: number;
active_count: number
subscriptions: Array<{
id: number;
group_name: string;
status: string;
daily_progress: number | null;
weekly_progress: number | null;
monthly_progress: number | null;
expires_at: string | null;
days_remaining: number | null;
}>;
id: number
group_name: string
status: string
daily_progress: number | null
weekly_progress: number | null
monthly_progress: number | null
expires_at: string | null
days_remaining: number | null
}>
}
/**
* Get list of current user's subscriptions
*/
export async function getMySubscriptions(): Promise<UserSubscription[]> {
const response = await apiClient.get<UserSubscription[]>('/subscriptions');
return response.data;
const response = await apiClient.get<UserSubscription[]>('/subscriptions')
return response.data
}
/**
* Get current user's active subscriptions
*/
export async function getActiveSubscriptions(): Promise<UserSubscription[]> {
const response = await apiClient.get<UserSubscription[]>('/subscriptions/active');
return response.data;
const response = await apiClient.get<UserSubscription[]>('/subscriptions/active')
return response.data
}
/**
* Get progress for all user's active subscriptions
*/
export async function getSubscriptionsProgress(): Promise<SubscriptionProgress[]> {
const response = await apiClient.get<SubscriptionProgress[]>('/subscriptions/progress');
return response.data;
const response = await apiClient.get<SubscriptionProgress[]>('/subscriptions/progress')
return response.data
}
/**
* Get subscription summary for dashboard display
*/
export async function getSubscriptionSummary(): Promise<SubscriptionSummary> {
const response = await apiClient.get<SubscriptionSummary>('/subscriptions/summary');
return response.data;
const response = await apiClient.get<SubscriptionSummary>('/subscriptions/summary')
return response.data
}
/**
* Get progress for a specific subscription
*/
export async function getSubscriptionProgress(subscriptionId: number): Promise<SubscriptionProgress> {
const response = await apiClient.get<SubscriptionProgress>(`/subscriptions/${subscriptionId}/progress`);
return response.data;
export async function getSubscriptionProgress(
subscriptionId: number
): Promise<SubscriptionProgress> {
const response = await apiClient.get<SubscriptionProgress>(
`/subscriptions/${subscriptionId}/progress`
)
return response.data
}
export default {
@@ -68,5 +72,5 @@ export default {
getActiveSubscriptions,
getSubscriptionsProgress,
getSubscriptionSummary,
getSubscriptionProgress,
};
getSubscriptionProgress
}

View File

@@ -3,59 +3,59 @@
* Handles usage logs and statistics retrieval
*/
import { apiClient } from './client';
import { apiClient } from './client'
import type {
UsageLog,
UsageQueryParams,
UsageStatsResponse,
PaginatedResponse,
TrendDataPoint,
ModelStat,
} from '@/types';
ModelStat
} from '@/types'
// ==================== Dashboard Types ====================
export interface UserDashboardStats {
total_api_keys: number;
active_api_keys: number;
total_requests: number;
total_input_tokens: number;
total_output_tokens: number;
total_cache_creation_tokens: number;
total_cache_read_tokens: number;
total_tokens: number;
total_cost: number; // 标准计费
total_actual_cost: number; // 实际扣除
today_requests: number;
today_input_tokens: number;
today_output_tokens: number;
today_cache_creation_tokens: number;
today_cache_read_tokens: number;
today_tokens: number;
today_cost: number; // 今日标准计费
today_actual_cost: number; // 今日实际扣除
average_duration_ms: number;
rpm: number; // 近5分钟平均每分钟请求数
tpm: number; // 近5分钟平均每分钟Token数
total_api_keys: number
active_api_keys: number
total_requests: number
total_input_tokens: number
total_output_tokens: number
total_cache_creation_tokens: number
total_cache_read_tokens: number
total_tokens: number
total_cost: number // 标准计费
total_actual_cost: number // 实际扣除
today_requests: number
today_input_tokens: number
today_output_tokens: number
today_cache_creation_tokens: number
today_cache_read_tokens: number
today_tokens: number
today_cost: number // 今日标准计费
today_actual_cost: number // 今日实际扣除
average_duration_ms: number
rpm: number // 近5分钟平均每分钟请求数
tpm: number // 近5分钟平均每分钟Token数
}
export interface TrendParams {
start_date?: string;
end_date?: string;
granularity?: 'day' | 'hour';
start_date?: string
end_date?: string
granularity?: 'day' | 'hour'
}
export interface TrendResponse {
trend: TrendDataPoint[];
start_date: string;
end_date: string;
granularity: string;
trend: TrendDataPoint[]
start_date: string
end_date: string
granularity: string
}
export interface ModelStatsResponse {
models: ModelStat[];
start_date: string;
end_date: string;
models: ModelStat[]
start_date: string
end_date: string
}
/**
@@ -72,17 +72,17 @@ export async function list(
): Promise<PaginatedResponse<UsageLog>> {
const params: UsageQueryParams = {
page,
page_size: pageSize,
};
page_size: pageSize
}
if (apiKeyId !== undefined) {
params.api_key_id = apiKeyId;
params.api_key_id = apiKeyId
}
const { data } = await apiClient.get<PaginatedResponse<UsageLog>>('/usage', {
params,
});
return data;
params
})
return data
}
/**
@@ -92,9 +92,9 @@ export async function list(
*/
export async function query(params: UsageQueryParams): Promise<PaginatedResponse<UsageLog>> {
const { data } = await apiClient.get<PaginatedResponse<UsageLog>>('/usage', {
params,
});
return data;
params
})
return data
}
/**
@@ -107,16 +107,16 @@ export async function getStats(
period: string = 'today',
apiKeyId?: number
): Promise<UsageStatsResponse> {
const params: Record<string, unknown> = { period };
const params: Record<string, unknown> = { period }
if (apiKeyId !== undefined) {
params.api_key_id = apiKeyId;
params.api_key_id = apiKeyId
}
const { data } = await apiClient.get<UsageStatsResponse>('/usage/stats', {
params,
});
return data;
params
})
return data
}
/**
@@ -133,17 +133,17 @@ export async function getStatsByDateRange(
): Promise<UsageStatsResponse> {
const params: Record<string, unknown> = {
start_date: startDate,
end_date: endDate,
};
end_date: endDate
}
if (apiKeyId !== undefined) {
params.api_key_id = apiKeyId;
params.api_key_id = apiKeyId
}
const { data } = await apiClient.get<UsageStatsResponse>('/usage/stats', {
params,
});
return data;
params
})
return data
}
/**
@@ -162,17 +162,17 @@ export async function getByDateRange(
start_date: startDate,
end_date: endDate,
page: 1,
page_size: 100,
};
page_size: 100
}
if (apiKeyId !== undefined) {
params.api_key_id = apiKeyId;
params.api_key_id = apiKeyId
}
const { data } = await apiClient.get<PaginatedResponse<UsageLog>>('/usage', {
params,
});
return data;
params
})
return data
}
/**
@@ -181,8 +181,8 @@ export async function getByDateRange(
* @returns Usage log details
*/
export async function getById(id: number): Promise<UsageLog> {
const { data } = await apiClient.get<UsageLog>(`/usage/${id}`);
return data;
const { data } = await apiClient.get<UsageLog>(`/usage/${id}`)
return data
}
// ==================== Dashboard API ====================
@@ -192,8 +192,8 @@ export async function getById(id: number): Promise<UsageLog> {
* @returns Dashboard statistics for current user
*/
export async function getDashboardStats(): Promise<UserDashboardStats> {
const { data } = await apiClient.get<UserDashboardStats>('/usage/dashboard/stats');
return data;
const { data } = await apiClient.get<UserDashboardStats>('/usage/dashboard/stats')
return data
}
/**
@@ -202,8 +202,8 @@ export async function getDashboardStats(): Promise<UserDashboardStats> {
* @returns Usage trend data for current user
*/
export async function getDashboardTrend(params?: TrendParams): Promise<TrendResponse> {
const { data } = await apiClient.get<TrendResponse>('/usage/dashboard/trend', { params });
return data;
const { data } = await apiClient.get<TrendResponse>('/usage/dashboard/trend', { params })
return data
}
/**
@@ -211,19 +211,22 @@ export async function getDashboardTrend(params?: TrendParams): Promise<TrendResp
* @param params - Query parameters for filtering
* @returns Model usage statistics for current user
*/
export async function getDashboardModels(params?: { start_date?: string; end_date?: string }): Promise<ModelStatsResponse> {
const { data } = await apiClient.get<ModelStatsResponse>('/usage/dashboard/models', { params });
return data;
export async function getDashboardModels(params?: {
start_date?: string
end_date?: string
}): Promise<ModelStatsResponse> {
const { data } = await apiClient.get<ModelStatsResponse>('/usage/dashboard/models', { params })
return data
}
export interface BatchApiKeyUsageStats {
api_key_id: number;
today_actual_cost: number;
total_actual_cost: number;
api_key_id: number
today_actual_cost: number
total_actual_cost: number
}
export interface BatchApiKeysUsageResponse {
stats: Record<string, BatchApiKeyUsageStats>;
stats: Record<string, BatchApiKeyUsageStats>
}
/**
@@ -231,11 +234,16 @@ export interface BatchApiKeysUsageResponse {
* @param apiKeyIds - Array of API key IDs
* @returns Usage stats map keyed by API key ID
*/
export async function getDashboardApiKeysUsage(apiKeyIds: number[]): Promise<BatchApiKeysUsageResponse> {
const { data } = await apiClient.post<BatchApiKeysUsageResponse>('/usage/dashboard/api-keys-usage', {
api_key_ids: apiKeyIds,
});
return data;
export async function getDashboardApiKeysUsage(
apiKeyIds: number[]
): Promise<BatchApiKeysUsageResponse> {
const { data } = await apiClient.post<BatchApiKeysUsageResponse>(
'/usage/dashboard/api-keys-usage',
{
api_key_ids: apiKeyIds
}
)
return data
}
export const usageAPI = {
@@ -249,7 +257,7 @@ export const usageAPI = {
getDashboardStats,
getDashboardTrend,
getDashboardModels,
getDashboardApiKeysUsage,
};
getDashboardApiKeysUsage
}
export default usageAPI;
export default usageAPI

View File

@@ -3,16 +3,16 @@
* Handles user profile management and password changes
*/
import { apiClient } from './client';
import type { User, ChangePasswordRequest } from '@/types';
import { apiClient } from './client'
import type { User, ChangePasswordRequest } from '@/types'
/**
* Get current user profile
* @returns User profile data
*/
export async function getProfile(): Promise<User> {
const { data } = await apiClient.get<User>('/user/profile');
return data;
const { data } = await apiClient.get<User>('/user/profile')
return data
}
/**
@@ -21,11 +21,11 @@ export async function getProfile(): Promise<User> {
* @returns Updated user profile data
*/
export async function updateProfile(profile: {
username?: string;
wechat?: string;
username?: string
wechat?: string
}): Promise<User> {
const { data } = await apiClient.put<User>('/user', profile);
return data;
const { data } = await apiClient.put<User>('/user', profile)
return data
}
/**
@@ -39,17 +39,17 @@ export async function changePassword(
): Promise<{ message: string }> {
const payload: ChangePasswordRequest = {
old_password: oldPassword,
new_password: newPassword,
};
new_password: newPassword
}
const { data } = await apiClient.put<{ message: string }>('/user/password', payload);
return data;
const { data } = await apiClient.put<{ message: string }>('/user/password', payload)
return data
}
export const userAPI = {
getProfile,
updateProfile,
changePassword,
};
changePassword
}
export default userAPI;
export default userAPI