import type { ApiResponse } from '@/types'; const API_BASE_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000/api/v1'; // 管理员 API 请求 async function adminRequest(path: string, options: RequestInit = {}): Promise { const token = localStorage.getItem('token'); if (!token) { throw new Error('请先登录后再操作'); } const response = await fetch(`${API_BASE_URL}${path}`, { ...options, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, ...options.headers, }, }); if (!response.ok) { const error = await response.json().catch(() => ({ message: '请求失败' })); if (response.status === 401) { // Token 过期或无效,清除本地存储 localStorage.removeItem('token'); localStorage.removeItem('user'); throw new Error('登录已过期,请重新登录'); } throw new Error(error.message || `HTTP ${response.status}`); } const data: ApiResponse = await response.json(); if (data.code !== 200) { throw new Error(data.message || '请求失败'); } return data.data; } // 用户管理 export interface AdminUser { id: string; username: string; email: string; role: 'admin' | 'user'; status: 'active' | 'banned'; createdAt: string; lastLogin: string; favoritesCount: number; } // 数据源配置 export interface DataSourceConfig { id: string; name: string; type: 'akshare' | 'tushare' | 'custom'; url: string; apiKey?: string; enabled: boolean; syncInterval: number; lastSync?: string; status: 'connected' | 'disconnected' | 'error'; } // 数据检查项 export interface DataCheckItem { id: string; name: string; type: 'stock' | 'sector' | 'index' | 'kline'; total: number; current: number; lastUpdate: string; status: 'complete' | 'incomplete' | 'missing'; details?: string; } // 同步任务 export interface SyncTask { id: string; type: string; status: 'pending' | 'running' | 'completed' | 'failed'; progress: number; currentTask: string; totalRecords: number; processedRecords: number; createdAt: string; completedAt?: string; error?: string; } // 管理员 API export const adminApi = { // ========== 数据源管理 ========== // 获取数据源列表 getDataSources(): Promise { return adminRequest('/admin/data-sources'); }, // 更新数据源配置 updateDataSource(id: string, config: Partial): Promise { return adminRequest(`/admin/data-sources/${id}`, { method: 'PUT', body: JSON.stringify(config), }); }, // 测试数据源连接 testDataSource(id: string): Promise<{ success: boolean; message: string }> { return adminRequest(`/admin/data-sources/${id}/test`, { method: 'POST', }); }, // 手动触发同步 triggerSync(sourceId: string): Promise<{ taskId: string }> { return adminRequest(`/admin/data-sources/${sourceId}/sync`, { method: 'POST', }); }, // ========== AKShare 特定接口 ========== // 获取 AKShare 状态 getAKShareStatus(): Promise<{ connected: boolean; version?: string; supportedApis: string[]; }> { return adminRequest('/admin/akshare/status'); }, // 获取 AKShare 配置 getAKShareConfig(): Promise<{ baseUrl: string; timeout: number; retryTimes: number; rateLimit: number; }> { return adminRequest('/admin/akshare/config'); }, // 更新 AKShare 配置 updateAKShareConfig(config: { baseUrl?: string; timeout?: number; retryTimes?: number; rateLimit?: number; }): Promise { return adminRequest('/admin/akshare/config', { method: 'PUT', body: JSON.stringify(config), }); }, // ========== 数据检测与缓冲 ========== // 获取数据完整性检查 getDataCheck(): Promise { return adminRequest('/admin/data-check'); }, // 执行数据完整性检查 runDataCheck(): Promise<{ taskId: string }> { return adminRequest('/admin/data-check', { method: 'POST', }); }, // 获取同步任务进度 getSyncTask(taskId: string): Promise { return adminRequest(`/admin/sync-tasks/${taskId}`); }, // 一键缓冲缺失数据(自动补全一年内的数据) bufferMissingData(options?: { startDate?: string; endDate?: string; types?: ('stock' | 'sector' | 'kline')[]; }): Promise<{ taskId: string }> { // 默认缓冲一年内数据 const endDate = new Date(); const startDate = new Date(); startDate.setFullYear(startDate.getFullYear() - 1); return adminRequest('/admin/buffer', { method: 'POST', body: JSON.stringify({ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0], types: ['stock', 'sector', 'kline'], autoCalculate: true, // 自动计算动量指标 ...options, }), }); }, // 缓冲特定股票数据 bufferStockData(stockCode: string, days: number = 365): Promise<{ taskId: string }> { return adminRequest('/admin/buffer/stock', { method: 'POST', body: JSON.stringify({ stockCode, days }), }); }, // 缓冲所有股票基础数据 bufferAllStocks(): Promise<{ taskId: string }> { return adminRequest('/admin/buffer/stocks', { method: 'POST', }); }, // 缓冲版块数据 bufferSectors(): Promise<{ taskId: string }> { return adminRequest('/admin/buffer/sectors', { method: 'POST', }); }, // 缓冲K线数据 bufferKLines(options?: { stockCodes?: string[]; startDate?: string; endDate?: string; }): Promise<{ taskId: string }> { const endDate = new Date(); const startDate = new Date(); startDate.setFullYear(startDate.getFullYear() - 1); return adminRequest('/admin/buffer/kline', { method: 'POST', body: JSON.stringify({ startDate: startDate.toISOString().split('T')[0], endDate: endDate.toISOString().split('T')[0], ...options, }), }); }, // 计算动量指标 calculateMomentum(options?: { stockCodes?: string[]; days?: number; }): Promise<{ taskId: string }> { return adminRequest('/admin/calculate/momentum', { method: 'POST', body: JSON.stringify({ days: 20, ...options, }), }); }, // ========== 用户管理 ========== // 获取用户列表 getUsers(params?: { page?: number; pageSize?: number; search?: string; role?: string; status?: string; }): Promise<{ users: AdminUser[]; total: number; page: number; pageSize: number; }> { const queryParams = new URLSearchParams(); if (params?.page) queryParams.append('page', params.page.toString()); if (params?.pageSize) queryParams.append('pageSize', params.pageSize.toString()); if (params?.search) queryParams.append('search', params.search); if (params?.role && params.role !== 'all') queryParams.append('role', params.role); if (params?.status && params.status !== 'all') queryParams.append('status', params.status); return adminRequest(`/admin/users?${queryParams.toString()}`); }, // 更新用户状态(封禁/解封) updateUserStatus(userId: string, status: 'active' | 'banned'): Promise { return adminRequest(`/admin/users/${userId}/status`, { method: 'PUT', body: JSON.stringify({ status }), }); }, // 删除用户 deleteUser(userId: string): Promise { return adminRequest(`/admin/users/${userId}`, { method: 'DELETE', }); }, // 批量操作用户 batchUpdateUsers(userIds: string[], action: 'ban' | 'unban' | 'delete'): Promise { return adminRequest('/admin/users/batch', { method: 'POST', body: JSON.stringify({ userIds, action }), }); }, // ========== 数据导入 ========== // 上传导入文件 uploadImportFile(file: File, type: string): Promise<{ taskId: string; filename: string }> { const formData = new FormData(); formData.append('file', file); formData.append('type', type); const token = localStorage.getItem('token'); return fetch(`${API_BASE_URL}/admin/import`, { method: 'POST', headers: { 'Authorization': token ? `Bearer ${token}` : '', }, body: formData, }).then(async (response) => { if (!response.ok) { const error = await response.json().catch(() => ({ message: '上传失败' })); throw new Error(error.message); } const data = await response.json(); if (data.code !== 200) { throw new Error(data.message); } return data.data; }); }, // 获取导入任务列表 getImportTasks(): Promise<{ id: string; name: string; fileName: string; status: string; progress: number; totalRecords: number; importedRecords: number; createdAt: string; }[]> { return adminRequest('/admin/import/tasks'); }, // ========== AI 配置 ========== // 获取 AI 配置 getAIConfig(): Promise<{ provider: string; model: string; apiUrl: string; temperature: number; maxTokens: number; enabled: boolean; }> { return adminRequest('/admin/ai-config'); }, // 更新 AI 配置 updateAIConfig(config: { provider?: string; model?: string; apiKey?: string; apiUrl?: string; temperature?: number; maxTokens?: number; enabled?: boolean; }): Promise { return adminRequest('/admin/ai-config', { method: 'PUT', body: JSON.stringify(config), }); }, // 测试 AI 连接 testAIConnection(): Promise<{ success: boolean; message: string }> { return adminRequest('/admin/ai-config/test', { method: 'POST', }); }, // 获取动量计算配置 getMomentumConfig(): Promise<{ calculationPeriod: number; weightPriceChange: number; weightVolume: number; weightTechnical: number; thresholdStrong: number; thresholdWeak: number; }> { return adminRequest('/admin/momentum-config'); }, // 更新动量计算配置 updateMomentumConfig(config: { calculationPeriod?: number; weightPriceChange?: number; weightVolume?: number; weightTechnical?: number; thresholdStrong?: number; thresholdWeak?: number; }): Promise { return adminRequest('/admin/momentum-config', { method: 'PUT', body: JSON.stringify(config), }); }, // ========== 系统统计 ========== // 获取系统统计 getSystemStats(): Promise<{ totalUsers: number; totalStocks: number; totalSectors: number; dataCompleteness: number; lastSync: string; apiStatus: { akshare: boolean; database: boolean; redis: boolean; }; }> { return adminRequest('/admin/stats'); }, // 获取数据保留策略 getDataRetention(): Promise<{ stockQuotesDays: number; klineDays: number; logsDays: number; }> { return adminRequest('/admin/data-retention'); }, // 更新数据保留策略 updateDataRetention(policy: { stockQuotesDays?: number; klineDays?: number; logsDays?: number; }): Promise { return adminRequest('/admin/data-retention', { method: 'PUT', body: JSON.stringify(policy), }); }, }; // WebSocket 连接用于实时获取同步进度 export function createSyncTaskWebSocket(taskId: string): WebSocket { const wsUrl = (import.meta.env.VITE_WS_URL || 'ws://localhost:3000').replace(/^http/, 'ws'); const token = localStorage.getItem('token'); return new WebSocket(`${wsUrl}/ws/sync-tasks/${taskId}?token=${token}`); } // Ensure export export default adminApi;