/** * API 客户端模块 * 提供统一的 HTTP 请求封装和认证管理 */ (function() { 'use strict'; /** * API 客户端类 */ class APIClient { constructor() { this.baseURL = window.API_CONFIG?.baseURL || ''; this.version = window.API_CONFIG?.version || '/api'; this.timeout = window.API_CONFIG?.timeout || 30000; } /** * 获取完整 URL */ getUrl(endpoint) { return `${this.baseURL}${this.version}${endpoint}`; } /** * 获取认证 Token */ getToken() { return localStorage.getItem('smart_center_token'); } /** * 检查是否已登录 */ isAuthenticated() { const token = this.getToken(); return !!token; } /** * 发送 HTTP 请求 */ async request(endpoint, options = {}) { const url = this.getUrl(endpoint); const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json', ...options.headers }; // 添加认证 Token const token = this.getToken(); if (token) { headers['Authorization'] = `Bearer ${token}`; } try { const response = await fetch(url, { ...options, headers, signal: AbortSignal.timeout(this.timeout) }); const data = await response.json(); if (!response.ok) { throw new Error(data.message || `HTTP ${response.status}`); } return data; } catch (error) { console.error(`API 请求失败 [${endpoint}]:`, error); throw error; } } /** * GET 请求 */ async get(endpoint, params = {}) { const queryString = new URLSearchParams(params).toString(); const url = queryString ? `${endpoint}?${queryString}` : endpoint; return this.request(url, { method: 'GET' }); } /** * POST 请求 */ async post(endpoint, data = {}) { return this.request(endpoint, { method: 'POST', body: JSON.stringify(data) }); } /** * PUT 请求 */ async put(endpoint, data = {}) { return this.request(endpoint, { method: 'PUT', body: JSON.stringify(data) }); } /** * DELETE 请求 */ async delete(endpoint) { return this.request(endpoint, { method: 'DELETE' }); } /** * 上传文件 */ async upload(endpoint, formData) { const url = this.getUrl(endpoint); const headers = {}; const token = this.getToken(); if (token) { headers['Authorization'] = `Bearer ${token}`; } try { const response = await fetch(url, { method: 'POST', headers, body: formData, signal: AbortSignal.timeout(this.timeout) }); const data = await response.json(); if (!response.ok) { throw new Error(data.message || `HTTP ${response.status}`); } return data; } catch (error) { console.error(`文件上传失败 [${endpoint}]:`, error); throw error; } } /** * 登录 */ async login(username, password) { const data = await this.post('/auth/login', { username, password }); if (data.token) { localStorage.setItem('smart_center_token', data.token); } return data; } /** * 注册 */ async register(userData) { return this.post('/auth/register', userData); } /** * 登出 */ async logout() { try { await this.post('/auth/logout'); } finally { localStorage.removeItem('smart_center_token'); } } /** * 获取用户信息 */ async getUserInfo() { return this.get('/user/info'); } /** * 发送聊天消息 */ async sendMessage(message, attachments = []) { if (attachments.length > 0) { // 多模态消息 const formData = new FormData(); formData.append('message', message); for (const file of attachments) { formData.append('files', file); } return this.upload('/chat/multimodal', formData); } else { // 纯文本消息 return this.post('/chat/send', { message }); } } /** * 获取模块列表 */ async getModuleList() { return this.get('/modules/list'); } /** * 获取模块详情 */ async getModuleDetail(moduleName) { return this.get(`/modules/detail/${moduleName}`); } } // 创建全局实例 window.APIClient = APIClient; window.apiClient = new APIClient(); console.log('✅ APIClient 已加载'); })(); /** * ============================================================================ * 多维鹰智能中控台 - 前端API统一调用客户端 (增强版) * ============================================================================ * * 版本: v1.0.0 * 创建时间: 2026-04-18 * * 使用方法: * 1. 在HTML中引入: * 2. 调用方法: await API.login(email, password) */ (function(global) { 'use strict'; // ==================== 配置常量 ==================== const CONFIG = { API_BASE_URL: '', // 相对路径,自动使用当前域名 SMART_PROCESSOR_ENDPOINT: '/smart-processor/command', DEFAULT_TIMEOUT: 30000, DEFAULT_RETRY: 3, TOKEN_STORAGE_KEY: 'access_token', USER_ID_STORAGE_KEY: 'user_id', // ✅ 双端口并行配置:根据API类型智能路由 BACKEND_ROUTES: { // 认证授权 → 8000端口(真实的JWT token) auth: 'https://api-gateway.duoweiying.cn/auth', oauth2: 'https://api-gateway.duoweiying.cn/oauth2', // 通用API → 8001端口(api-gateway.py提供的各种接口) api: 'https://api-gateway.duoweiying.cn/api' } }; // ==================== 状态管理 ==================== let globalConfig = { ...CONFIG }; // ✅ 初始化时从window.API_CONFIG读取配置 if (typeof window !== 'undefined' && window.API_CONFIG) { // 优先使用processorEndpoint(如果存在) if (window.API_CONFIG.processorEndpoint) { globalConfig.SMART_PROCESSOR_ENDPOINT = window.API_CONFIG.processorEndpoint; globalConfig.API_BASE_URL = ''; // processorEndpoint已包含完整URL } else { globalConfig.API_BASE_URL = window.API_CONFIG.baseURL || ''; } // ✅ 双端口配置:支持自定义后端路由 if (window.API_CONFIG.backendRoutes) { // 如果前端配置了backendRoutes,完全使用配置 globalConfig.BACKEND_ROUTES = { ...globalConfig.BACKEND_ROUTES, ...window.API_CONFIG.backendRoutes }; } else if (window.API_CONFIG.apiGatewayBaseURL) { // 兼容旧配置:单个网关URL const gatewayURL = window.API_CONFIG.apiGatewayBaseURL; globalConfig.BACKEND_ROUTES.auth = `${gatewayURL}/auth`; globalConfig.BACKEND_ROUTES.oauth2 = `${gatewayURL}/oauth2`; globalConfig.BACKEND_ROUTES.api = `${gatewayURL}/api`; } } let requestInterceptors = []; let responseInterceptors = []; // ==================== 工具函数 ==================== function getToken() { return localStorage.getItem(globalConfig.TOKEN_STORAGE_KEY) || sessionStorage.getItem(globalConfig.TOKEN_STORAGE_KEY); } function saveToken(token) { localStorage.setItem(globalConfig.TOKEN_STORAGE_KEY, token); } function getUserId() { return localStorage.getItem(globalConfig.USER_ID_STORAGE_KEY); } function saveUserId(userId) { localStorage.setItem(globalConfig.USER_ID_STORAGE_KEY, userId); } function clearAuth() { localStorage.removeItem(globalConfig.TOKEN_STORAGE_KEY); localStorage.removeItem(globalConfig.USER_ID_STORAGE_KEY); sessionStorage.removeItem(globalConfig.TOKEN_STORAGE_KEY); } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function generateRequestId(action) { return `${action}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } // ==================== 核心调用函数 ==================== async function callSmartProcessor(action, params = {}, options = {}) { const { scene = 'user_dashboard', timeout = globalConfig.DEFAULT_TIMEOUT, retry = globalConfig.DEFAULT_RETRY } = options; const requestBody = { scene: scene, action: action, params: params, context: { token: getToken(), userId: getUserId(), timestamp: Date.now() }, requestId: generateRequestId(action) }; for (const interceptor of requestInterceptors) { await interceptor(requestBody); } let lastError; for (let attempt = 1; attempt <= retry; attempt++) { try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); const response = await fetch(`${globalConfig.API_BASE_URL}${globalConfig.SMART_PROCESSOR_ENDPOINT}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${getToken()}` }, body: JSON.stringify(requestBody), signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw createError(`HTTP ${response.status}`, 'HTTP_ERROR', response.status); } const result = await response.json(); for (const interceptor of responseInterceptors) { await interceptor(result); } if (result.success) { console.log(`✅ [智能处理器] ${action} 成功`, result.data); return result.data; } else { console.warn(`⚠️ [智能处理器] ${action} 失败:`, result.error); throw createError(result.error || '操作失败', 'PROCESSOR_ERROR'); } } catch (error) { lastError = error; console.warn(`❌ [智能处理器] ${action} 尝试 ${attempt}/${retry} 失败:`, error.message); if (attempt < retry && error.name !== 'AbortError') { await delay(1000 * Math.pow(2, attempt - 1)); } } } throw lastError; } // ==================== 智能路由:根据URL前缀自动选择端口 ==================== /** * 根据API路径智能选择后端端口 * @param {string} url - API路径(如 /auth/token, /api/ai/chat) * @returns {string} 后端基础URL(不包含路径前缀) */ function resolveBackendURL(url) { // ✅ 智能路由规则:只返回域名,不返回路径前缀 if (url.startsWith('/auth/') || url === '/auth/token') { // 认证授权 → 8000端口 return 'https://api-gateway.duoweiying.cn'; } else if (url.startsWith('/oauth2/')) { // OAuth2 → 8000端口 return 'https://api-gateway.duoweiying.cn'; } else if (url.startsWith('/api/')) { // 通用API → 8001端口 return 'https://api-gateway.duoweiying.cn'; } else if (url.startsWith('/smart-processor/')) { // 智能处理器 → 8000端口 return 'https://api-gateway.duoweiying.cn'; } else { // 默认使用网关域名 return 'https://api-gateway.duoweiying.cn'; } } async function callBackendAPI(url, method = 'GET', data = null, options = {}) { const { contentType = 'application/json', timeout = globalConfig.DEFAULT_TIMEOUT, retry = globalConfig.DEFAULT_RETRY } = options; const fetchOptions = { method: method, headers: { 'Authorization': `Bearer ${getToken()}` } }; if (data) { if (contentType === 'application/json') { fetchOptions.headers['Content-Type'] = 'application/json'; fetchOptions.body = JSON.stringify(data); } else if (contentType === 'application/x-www-form-urlencoded') { fetchOptions.headers['Content-Type'] = 'application/x-www-form-urlencoded'; fetchOptions.body = new URLSearchParams(data).toString(); } } let lastError; for (let attempt = 1; attempt <= retry; attempt++) { try { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); // ✅ 智能路由:根据URL前缀自动选择8000或8001端口 const apiBaseURL = resolveBackendURL(url); console.log(`🔀 [智能路由] ${method} ${url} → ${apiBaseURL}`); const response = await fetch(`${apiBaseURL}${url}`, { ...fetchOptions, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw createError( errorData.detail || `HTTP ${response.status}`, 'API_ERROR', response.status ); } const result = await response.json(); for (const interceptor of responseInterceptors) { await interceptor(result); } return result; } catch (error) { lastError = error; console.warn(`❌ [后端API] ${method} ${url} 尝试 ${attempt}/${retry} 失败:`, error.message); if (attempt < retry && error.name !== 'AbortError') { await delay(1000 * Math.pow(2, attempt - 1)); } } } throw lastError; } function createError(message, code, statusCode = null) { const error = new Error(message); error.code = code; error.statusCode = statusCode; error.name = 'APIError'; return error; } // ==================== A类:智能处理器调用 ==================== async function aiChat(message, mode = 'chat') { return await callSmartProcessor('ai_chat', { message: message, mode: mode }); } async function generateContent(prompt, type = 'article') { return await callSmartProcessor('generate_content_response', { user_message: prompt, content_type: type }); } async function analyzeImage(imageUrl, analysisType = 'general') { return await callSmartProcessor('analyze_image', { image_url: imageUrl, analysis_type: analysisType }); } async function analyzeVideo(videoUrl) { return await callSmartProcessor('analyze_video', { video_url: videoUrl }); } async function generateScript(params) { return await callSmartProcessor('generate_script', params); } async function generateVideo(params) { return await callSmartProcessor('generate_video', params); } async function checkVideoStatus(taskId) { return await callSmartProcessor('check_video_status', { task_id: taskId }); } async function publishVideo(params) { return await callSmartProcessor('publish_video', params); } async function queryTaskStatus() { return await callSmartProcessor('query_task_status', {}); } async function getTaskDetail(taskId) { return await callSmartProcessor('get_task_detail', { task_id: taskId }); } async function cancelTask(taskId) { return await callSmartProcessor('cancel_task', { task_id: taskId }); } async function getStats(period = 'week') { return await callSmartProcessor('get_stats', { period: period }); } async function getRecommendations(type = 'content') { return await callSmartProcessor('get_recommendations', { type: type }); } // ==================== B类:直接调用后端API ==================== async function login(username, password) { try { // ✅ 修复:调用8001端口的/api/auth/login接口(已验证可用) const formData = { username: username, password: password }; // ✅ 修改:从 /auth/token 改为 /api/auth/login const result = await callBackendAPI('/api/auth/login', 'POST', formData, { contentType: 'application/json' }); if (result.access_token) { saveToken(result.access_token); if (result.user_id) { saveUserId(result.user_id); } } console.log('✅ 登录成功'); return result; } catch (error) { console.error('❌ 登录失败:', error.message); throw error; } } async function register(userData) { try { const result = await callBackendAPI('/auth/register', 'POST', { username: userData.username, email: userData.email, password: userData.password }, { contentType: 'application/json' }); console.log('✅ 注册成功'); return result; } catch (error) { console.error('❌ 注册失败:', error.message); throw error; } } async function sendVerifyCode(email) { return await callBackendAPI('/auth/send-verify-code', 'POST', { email: email }); } async function resetPassword(resetData) { return await callBackendAPI('/auth/reset-password', 'POST', { email: resetData.email, verify_code: resetData.verify_code, new_password: resetData.new_password }); } async function forgotPassword(email, verifyCode, newPassword) { if (!verifyCode) { await sendVerifyCode(email); return { needVerifyCode: true, message: '验证码已发送到邮箱' }; } await resetPassword({ email: email, verify_code: verifyCode, new_password: newPassword }); return { success: true, message: '密码重置成功' }; } function oauthLogin(platform) { const clientId = getClientId(platform); const redirectUri = encodeURIComponent(window.location.origin + '/oauth/callback'); const scope = 'openid profile email'; const authUrl = `${globalConfig.API_BASE_URL}/oauth2/authorize?` + `client_id=${clientId}&` + `redirect_uri=${redirectUri}&` + `response_type=code&` + `scope=${encodeURIComponent(scope)}`; console.log('🔄 跳转到OAuth授权页面:', authUrl); window.location.href = authUrl; } function logout() { clearAuth(); console.log('✅ 已退出登录'); } async function getUserInfo() { // ✅ 使用8001端口的mock用户信息接口(立即可用) // 如需使用8000端口的真实JWT认证,需先修复数据库连接 return await callBackendAPI('/api/auth/userinfo', 'GET'); } async function updateProfile(profileData) { return await callBackendAPI('/users/' + getUserId(), 'PUT', profileData); } async function getUserPreferences() { return await callSmartProcessor('get_user_preferences', {}); } async function updatePreferences(preferences) { return await callSmartProcessor('update_user_preferences', preferences); } async function uploadMedia(file, mediaType = 'image') { try { const formData = new FormData(); formData.append('file', file); formData.append('media_type', mediaType); const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), globalConfig.DEFAULT_TIMEOUT * 3); const response = await fetch(`${globalConfig.API_BASE_URL}/universal/media/upload`, { method: 'POST', headers: { 'Authorization': `Bearer ${getToken()}` }, body: formData, signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw createError('文件上传失败', 'UPLOAD_ERROR', response.status); } const result = await response.json(); console.log('✅ 文件上传成功:', result.file_url); return result; } catch (error) { console.error('❌ 文件上传失败:', error.message); throw error; } } async function uploadImage(file) { return await uploadMedia(file, 'image'); } async function uploadVideo(file) { return await uploadMedia(file, 'video'); } async function uploadFile(file, type = 'image') { return await uploadMedia(file, type); } // ==================== 辅助函数 ==================== function getClientId(platform) { const config = { wechat: 'your_wechat_client_id', qq: 'your_qq_client_id', weibo: 'your_weibo_client_id' }; return config[platform] || ''; } function configure(config) { globalConfig = { ...globalConfig, ...config }; console.log('✅ API配置已更新:', globalConfig); } function addRequestInterceptor(interceptor) { requestInterceptors.push(interceptor); } function addResponseInterceptor(interceptor) { responseInterceptors.push(interceptor); } // ==================== 导出API对象 ==================== const API = { // 核心方法 callSmartProcessor, callBackendAPI, configure, // 拦截器 interceptors: { request: { use: addRequestInterceptor }, response: { use: addResponseInterceptor } }, // A类:智能处理器调用 aiChat, generateContent, analyzeImage, analyzeVideo, generateScript, generateVideo, checkVideoStatus, publishVideo, queryTaskStatus, getTaskDetail, cancelTask, getStats, getRecommendations, // B类:直接调用后端API login, register, forgotPassword, oauthLogin, logout, getUserInfo, updateProfile, getUserPreferences, updatePreferences, uploadMedia, uploadImage, uploadVideo, uploadFile, // 工具方法 getToken, setToken: saveToken, getUserId, isAuthenticated: () => !!getToken() }; // 挂载到全局 global.API = API; console.log('✅ 多维鹰API客户端已加载 v1.0.0'); console.log('可用方法:', Object.keys(API).filter(k => typeof API[k] === 'function')); })(typeof window !== 'undefined' ? window : global);