diff --git a/app.js b/app.js index 7123cab..ca0470e 100644 --- a/app.js +++ b/app.js @@ -533,6 +533,66 @@ class CLIProxyManager { codexCopyLink.addEventListener('click', () => this.copyCodexLink()); } + // Anthropic OAuth + const anthropicOauthBtn = document.getElementById('anthropic-oauth-btn'); + const anthropicOpenLink = document.getElementById('anthropic-open-link'); + const anthropicCopyLink = document.getElementById('anthropic-copy-link'); + + if (anthropicOauthBtn) { + anthropicOauthBtn.addEventListener('click', () => this.startAnthropicOAuth()); + } + if (anthropicOpenLink) { + anthropicOpenLink.addEventListener('click', () => this.openAnthropicLink()); + } + if (anthropicCopyLink) { + anthropicCopyLink.addEventListener('click', () => this.copyAnthropicLink()); + } + + // Gemini CLI OAuth + const geminiCliOauthBtn = document.getElementById('gemini-cli-oauth-btn'); + const geminiCliOpenLink = document.getElementById('gemini-cli-open-link'); + const geminiCliCopyLink = document.getElementById('gemini-cli-copy-link'); + + if (geminiCliOauthBtn) { + geminiCliOauthBtn.addEventListener('click', () => this.startGeminiCliOAuth()); + } + if (geminiCliOpenLink) { + geminiCliOpenLink.addEventListener('click', () => this.openGeminiCliLink()); + } + if (geminiCliCopyLink) { + geminiCliCopyLink.addEventListener('click', () => this.copyGeminiCliLink()); + } + + // Qwen OAuth + const qwenOauthBtn = document.getElementById('qwen-oauth-btn'); + const qwenOpenLink = document.getElementById('qwen-open-link'); + const qwenCopyLink = document.getElementById('qwen-copy-link'); + + if (qwenOauthBtn) { + qwenOauthBtn.addEventListener('click', () => this.startQwenOAuth()); + } + if (qwenOpenLink) { + qwenOpenLink.addEventListener('click', () => this.openQwenLink()); + } + if (qwenCopyLink) { + qwenCopyLink.addEventListener('click', () => this.copyQwenLink()); + } + + // iFlow OAuth + const iflowOauthBtn = document.getElementById('iflow-oauth-btn'); + const iflowOpenLink = document.getElementById('iflow-open-link'); + const iflowCopyLink = document.getElementById('iflow-copy-link'); + + if (iflowOauthBtn) { + iflowOauthBtn.addEventListener('click', () => this.startIflowOAuth()); + } + if (iflowOpenLink) { + iflowOpenLink.addEventListener('click', () => this.openIflowLink()); + } + if (iflowCopyLink) { + iflowCopyLink.addEventListener('click', () => this.copyIflowLink()); + } + // 使用统计 const refreshUsageStats = document.getElementById('refresh-usage-stats'); const requestsHourBtn = document.getElementById('requests-hour-btn'); @@ -2586,6 +2646,595 @@ class CLIProxyManager { } } + // ===== Anthropic OAuth 相关方法 ===== + + // 开始 Anthropic OAuth 流程 + async startAnthropicOAuth() { + try { + const response = await this.makeRequest('/anthropic-auth-url?is_webui=1'); + const authUrl = response.url; + const state = this.extractStateFromUrl(authUrl); + + // 显示授权链接 + const urlInput = document.getElementById('anthropic-oauth-url'); + const content = document.getElementById('anthropic-oauth-content'); + const status = document.getElementById('anthropic-oauth-status'); + + if (urlInput) { + urlInput.value = authUrl; + } + if (content) { + content.style.display = 'block'; + } + if (status) { + status.textContent = i18n.t('auth_login.anthropic_oauth_status_waiting'); + status.style.color = 'var(--warning-text)'; + } + + // 开始轮询认证状态 + this.startAnthropicOAuthPolling(state); + + } catch (error) { + this.showNotification(`${i18n.t('auth_login.anthropic_oauth_start_error')} ${error.message}`, 'error'); + } + } + + // 打开 Anthropic 授权链接 + openAnthropicLink() { + const urlInput = document.getElementById('anthropic-oauth-url'); + if (urlInput && urlInput.value) { + window.open(urlInput.value, '_blank'); + } + } + + // 复制 Anthropic 授权链接 + async copyAnthropicLink() { + const urlInput = document.getElementById('anthropic-oauth-url'); + if (urlInput && urlInput.value) { + try { + await navigator.clipboard.writeText(urlInput.value); + this.showNotification('链接已复制到剪贴板', 'success'); + } catch (error) { + // 降级方案:使用传统的复制方法 + urlInput.select(); + document.execCommand('copy'); + this.showNotification('链接已复制到剪贴板', 'success'); + } + } + } + + // 开始轮询 Anthropic OAuth 状态 + startAnthropicOAuthPolling(state) { + if (!state) { + this.showNotification('无法获取认证状态参数', 'error'); + return; + } + + const pollInterval = setInterval(async () => { + try { + const response = await this.makeRequest(`/get-auth-status?state=${encodeURIComponent(state)}`); + const status = response.status; + const statusElement = document.getElementById('anthropic-oauth-status'); + + if (status === 'ok') { + // 认证成功 + clearInterval(pollInterval); + // 隐藏授权链接相关内容,恢复到初始状态 + this.resetAnthropicOAuthUI(); + // 显示成功通知 + this.showNotification(i18n.t('auth_login.anthropic_oauth_status_success'), 'success'); + // 刷新认证文件列表 + this.loadAuthFiles(); + } else if (status === 'error') { + // 认证失败 + clearInterval(pollInterval); + const errorMessage = response.error || 'Unknown error'; + // 显示错误信息 + if (statusElement) { + statusElement.textContent = `${i18n.t('auth_login.anthropic_oauth_status_error')} ${errorMessage}`; + statusElement.style.color = 'var(--error-text)'; + } + this.showNotification(`${i18n.t('auth_login.anthropic_oauth_status_error')} ${errorMessage}`, 'error'); + // 3秒后重置UI,让用户能够重新开始 + setTimeout(() => { + this.resetAnthropicOAuthUI(); + }, 3000); + } else if (status === 'wait') { + // 继续等待 + if (statusElement) { + statusElement.textContent = i18n.t('auth_login.anthropic_oauth_status_waiting'); + statusElement.style.color = 'var(--warning-text)'; + } + } + } catch (error) { + clearInterval(pollInterval); + const statusElement = document.getElementById('anthropic-oauth-status'); + if (statusElement) { + statusElement.textContent = `${i18n.t('auth_login.anthropic_oauth_polling_error')} ${error.message}`; + statusElement.style.color = 'var(--error-text)'; + } + this.showNotification(`${i18n.t('auth_login.anthropic_oauth_polling_error')} ${error.message}`, 'error'); + // 3秒后重置UI,让用户能够重新开始 + setTimeout(() => { + this.resetAnthropicOAuthUI(); + }, 3000); + } + }, 2000); // 每2秒轮询一次 + + // 设置超时,5分钟后停止轮询 + setTimeout(() => { + clearInterval(pollInterval); + }, 5 * 60 * 1000); + } + + // 重置 Anthropic OAuth UI 到初始状态 + resetAnthropicOAuthUI() { + const urlInput = document.getElementById('anthropic-oauth-url'); + const content = document.getElementById('anthropic-oauth-content'); + const status = document.getElementById('anthropic-oauth-status'); + + // 清空并隐藏授权链接输入框 + if (urlInput) { + urlInput.value = ''; + } + + // 隐藏整个授权链接内容区域 + if (content) { + content.style.display = 'none'; + } + + // 清空状态显示 + if (status) { + status.textContent = ''; + status.style.color = ''; + status.className = ''; + } + } + + // ===== Gemini CLI OAuth 相关方法 ===== + + // 开始 Gemini CLI OAuth 流程 + async startGeminiCliOAuth() { + try { + // 获取项目 ID(可选) + const projectId = document.getElementById('gemini-cli-project-id').value.trim(); + + // 构建请求 URL + let requestUrl = '/gemini-cli-auth-url?is_webui=1'; + if (projectId) { + requestUrl += `&project_id=${encodeURIComponent(projectId)}`; + } + + const response = await this.makeRequest(requestUrl); + const authUrl = response.url; + const state = this.extractStateFromUrl(authUrl); + + // 显示授权链接 + const urlInput = document.getElementById('gemini-cli-oauth-url'); + const content = document.getElementById('gemini-cli-oauth-content'); + const status = document.getElementById('gemini-cli-oauth-status'); + + if (urlInput) { + urlInput.value = authUrl; + } + if (content) { + content.style.display = 'block'; + } + if (status) { + status.textContent = i18n.t('auth_login.gemini_cli_oauth_status_waiting'); + status.style.color = 'var(--warning-text)'; + } + + // 开始轮询认证状态 + this.startGeminiCliOAuthPolling(state); + + } catch (error) { + this.showNotification(`${i18n.t('auth_login.gemini_cli_oauth_start_error')} ${error.message}`, 'error'); + } + } + + // 打开 Gemini CLI 授权链接 + openGeminiCliLink() { + const urlInput = document.getElementById('gemini-cli-oauth-url'); + if (urlInput && urlInput.value) { + window.open(urlInput.value, '_blank'); + } + } + + // 复制 Gemini CLI 授权链接 + async copyGeminiCliLink() { + const urlInput = document.getElementById('gemini-cli-oauth-url'); + if (urlInput && urlInput.value) { + try { + await navigator.clipboard.writeText(urlInput.value); + this.showNotification('链接已复制到剪贴板', 'success'); + } catch (error) { + // 降级方案:使用传统的复制方法 + urlInput.select(); + document.execCommand('copy'); + this.showNotification('链接已复制到剪贴板', 'success'); + } + } + } + + // 开始轮询 Gemini CLI OAuth 状态 + startGeminiCliOAuthPolling(state) { + if (!state) { + this.showNotification('无法获取认证状态参数', 'error'); + return; + } + + const pollInterval = setInterval(async () => { + try { + const response = await this.makeRequest(`/get-auth-status?state=${encodeURIComponent(state)}`); + const status = response.status; + const statusElement = document.getElementById('gemini-cli-oauth-status'); + + if (status === 'ok') { + // 认证成功 + clearInterval(pollInterval); + // 隐藏授权链接相关内容,恢复到初始状态 + this.resetGeminiCliOAuthUI(); + // 显示成功通知 + this.showNotification(i18n.t('auth_login.gemini_cli_oauth_status_success'), 'success'); + // 刷新认证文件列表 + this.loadAuthFiles(); + } else if (status === 'error') { + // 认证失败 + clearInterval(pollInterval); + const errorMessage = response.error || 'Unknown error'; + // 显示错误信息 + if (statusElement) { + statusElement.textContent = `${i18n.t('auth_login.gemini_cli_oauth_status_error')} ${errorMessage}`; + statusElement.style.color = 'var(--error-text)'; + } + this.showNotification(`${i18n.t('auth_login.gemini_cli_oauth_status_error')} ${errorMessage}`, 'error'); + // 3秒后重置UI,让用户能够重新开始 + setTimeout(() => { + this.resetGeminiCliOAuthUI(); + }, 3000); + } else if (status === 'wait') { + // 继续等待 + if (statusElement) { + statusElement.textContent = i18n.t('auth_login.gemini_cli_oauth_status_waiting'); + statusElement.style.color = 'var(--warning-text)'; + } + } + } catch (error) { + clearInterval(pollInterval); + const statusElement = document.getElementById('gemini-cli-oauth-status'); + if (statusElement) { + statusElement.textContent = `${i18n.t('auth_login.gemini_cli_oauth_polling_error')} ${error.message}`; + statusElement.style.color = 'var(--error-text)'; + } + this.showNotification(`${i18n.t('auth_login.gemini_cli_oauth_polling_error')} ${error.message}`, 'error'); + // 3秒后重置UI,让用户能够重新开始 + setTimeout(() => { + this.resetGeminiCliOAuthUI(); + }, 3000); + } + }, 2000); // 每2秒轮询一次 + + // 设置超时,5分钟后停止轮询 + setTimeout(() => { + clearInterval(pollInterval); + }, 5 * 60 * 1000); + } + + // 重置 Gemini CLI OAuth UI 到初始状态 + resetGeminiCliOAuthUI() { + const urlInput = document.getElementById('gemini-cli-oauth-url'); + const content = document.getElementById('gemini-cli-oauth-content'); + const status = document.getElementById('gemini-cli-oauth-status'); + + // 清空并隐藏授权链接输入框 + if (urlInput) { + urlInput.value = ''; + } + + // 隐藏整个授权链接内容区域 + if (content) { + content.style.display = 'none'; + } + + // 清空状态显示 + if (status) { + status.textContent = ''; + status.style.color = ''; + status.className = ''; + } + } + + // ===== Qwen OAuth 相关方法 ===== + + // 开始 Qwen OAuth 流程 + async startQwenOAuth() { + try { + const response = await this.makeRequest('/qwen-auth-url?is_webui=1'); + const authUrl = response.url; + const state = this.extractStateFromUrl(authUrl); + + // 显示授权链接 + const urlInput = document.getElementById('qwen-oauth-url'); + const content = document.getElementById('qwen-oauth-content'); + const status = document.getElementById('qwen-oauth-status'); + + if (urlInput) { + urlInput.value = authUrl; + } + if (content) { + content.style.display = 'block'; + } + if (status) { + status.textContent = i18n.t('auth_login.qwen_oauth_status_waiting'); + status.style.color = 'var(--warning-text)'; + } + + // 开始轮询认证状态 + this.startQwenOAuthPolling(response.state); + + } catch (error) { + this.showNotification(`${i18n.t('auth_login.qwen_oauth_start_error')} ${error.message}`, 'error'); + } + } + + // 打开 Qwen 授权链接 + openQwenLink() { + const urlInput = document.getElementById('qwen-oauth-url'); + if (urlInput && urlInput.value) { + window.open(urlInput.value, '_blank'); + } + } + + // 复制 Qwen 授权链接 + async copyQwenLink() { + const urlInput = document.getElementById('qwen-oauth-url'); + if (urlInput && urlInput.value) { + try { + await navigator.clipboard.writeText(urlInput.value); + this.showNotification('链接已复制到剪贴板', 'success'); + } catch (error) { + // 降级方案:使用传统的复制方法 + urlInput.select(); + document.execCommand('copy'); + this.showNotification('链接已复制到剪贴板', 'success'); + } + } + } + + // 开始轮询 Qwen OAuth 状态 + startQwenOAuthPolling(state) { + if (!state) { + this.showNotification('无法获取认证状态参数', 'error'); + return; + } + + const pollInterval = setInterval(async () => { + try { + const response = await this.makeRequest(`/get-auth-status?state=${encodeURIComponent(state)}`); + const status = response.status; + const statusElement = document.getElementById('qwen-oauth-status'); + + if (status === 'ok') { + // 认证成功 + clearInterval(pollInterval); + // 隐藏授权链接相关内容,恢复到初始状态 + this.resetQwenOAuthUI(); + // 显示成功通知 + this.showNotification(i18n.t('auth_login.qwen_oauth_status_success'), 'success'); + // 刷新认证文件列表 + this.loadAuthFiles(); + } else if (status === 'error') { + // 认证失败 + clearInterval(pollInterval); + const errorMessage = response.error || 'Unknown error'; + // 显示错误信息 + if (statusElement) { + statusElement.textContent = `${i18n.t('auth_login.qwen_oauth_status_error')} ${errorMessage}`; + statusElement.style.color = 'var(--error-text)'; + } + this.showNotification(`${i18n.t('auth_login.qwen_oauth_status_error')} ${errorMessage}`, 'error'); + // 3秒后重置UI,让用户能够重新开始 + setTimeout(() => { + this.resetQwenOAuthUI(); + }, 3000); + } else if (status === 'wait') { + // 继续等待 + if (statusElement) { + statusElement.textContent = i18n.t('auth_login.qwen_oauth_status_waiting'); + statusElement.style.color = 'var(--warning-text)'; + } + } + } catch (error) { + clearInterval(pollInterval); + const statusElement = document.getElementById('qwen-oauth-status'); + if (statusElement) { + statusElement.textContent = `${i18n.t('auth_login.qwen_oauth_polling_error')} ${error.message}`; + statusElement.style.color = 'var(--error-text)'; + } + this.showNotification(`${i18n.t('auth_login.qwen_oauth_polling_error')} ${error.message}`, 'error'); + // 3秒后重置UI,让用户能够重新开始 + setTimeout(() => { + this.resetQwenOAuthUI(); + }, 3000); + } + }, 2000); // 每2秒轮询一次 + + // 设置超时,5分钟后停止轮询 + setTimeout(() => { + clearInterval(pollInterval); + }, 5 * 60 * 1000); + } + + // 重置 Qwen OAuth UI 到初始状态 + resetQwenOAuthUI() { + const urlInput = document.getElementById('qwen-oauth-url'); + const content = document.getElementById('qwen-oauth-content'); + const status = document.getElementById('qwen-oauth-status'); + + // 清空并隐藏授权链接输入框 + if (urlInput) { + urlInput.value = ''; + } + + // 隐藏整个授权链接内容区域 + if (content) { + content.style.display = 'none'; + } + + // 清空状态显示 + if (status) { + status.textContent = ''; + status.style.color = ''; + status.className = ''; + } + } + + // ===== iFlow OAuth 相关方法 ===== + + // 开始 iFlow OAuth 流程 + async startIflowOAuth() { + try { + const response = await this.makeRequest('/iflow-auth-url?is_webui=1'); + const authUrl = response.url; + const state = this.extractStateFromUrl(authUrl); + + // 显示授权链接 + const urlInput = document.getElementById('iflow-oauth-url'); + const content = document.getElementById('iflow-oauth-content'); + const status = document.getElementById('iflow-oauth-status'); + + if (urlInput) { + urlInput.value = authUrl; + } + if (content) { + content.style.display = 'block'; + } + if (status) { + status.textContent = i18n.t('auth_login.iflow_oauth_status_waiting'); + status.style.color = 'var(--warning-text)'; + } + + // 开始轮询认证状态 + this.startIflowOAuthPolling(state); + + } catch (error) { + this.showNotification(`${i18n.t('auth_login.iflow_oauth_start_error')} ${error.message}`, 'error'); + } + } + + // 打开 iFlow 授权链接 + openIflowLink() { + const urlInput = document.getElementById('iflow-oauth-url'); + if (urlInput && urlInput.value) { + window.open(urlInput.value, '_blank'); + } + } + + // 复制 iFlow 授权链接 + async copyIflowLink() { + const urlInput = document.getElementById('iflow-oauth-url'); + if (urlInput && urlInput.value) { + try { + await navigator.clipboard.writeText(urlInput.value); + this.showNotification('链接已复制到剪贴板', 'success'); + } catch (error) { + // 降级方案:使用传统的复制方法 + urlInput.select(); + document.execCommand('copy'); + this.showNotification('链接已复制到剪贴板', 'success'); + } + } + } + + // 开始轮询 iFlow OAuth 状态 + startIflowOAuthPolling(state) { + if (!state) { + this.showNotification('无法获取认证状态参数', 'error'); + return; + } + + const pollInterval = setInterval(async () => { + try { + const response = await this.makeRequest(`/get-auth-status?state=${encodeURIComponent(state)}`); + const status = response.status; + const statusElement = document.getElementById('iflow-oauth-status'); + + if (status === 'ok') { + // 认证成功 + clearInterval(pollInterval); + // 隐藏授权链接相关内容,恢复到初始状态 + this.resetIflowOAuthUI(); + // 显示成功通知 + this.showNotification(i18n.t('auth_login.iflow_oauth_status_success'), 'success'); + // 刷新认证文件列表 + this.loadAuthFiles(); + } else if (status === 'error') { + // 认证失败 + clearInterval(pollInterval); + const errorMessage = response.error || 'Unknown error'; + // 显示错误信息 + if (statusElement) { + statusElement.textContent = `${i18n.t('auth_login.iflow_oauth_status_error')} ${errorMessage}`; + statusElement.style.color = 'var(--error-text)'; + } + this.showNotification(`${i18n.t('auth_login.iflow_oauth_status_error')} ${errorMessage}`, 'error'); + // 3秒后重置UI,让用户能够重新开始 + setTimeout(() => { + this.resetIflowOAuthUI(); + }, 3000); + } else if (status === 'wait') { + // 继续等待 + if (statusElement) { + statusElement.textContent = i18n.t('auth_login.iflow_oauth_status_waiting'); + statusElement.style.color = 'var(--warning-text)'; + } + } + } catch (error) { + clearInterval(pollInterval); + const statusElement = document.getElementById('iflow-oauth-status'); + if (statusElement) { + statusElement.textContent = `${i18n.t('auth_login.iflow_oauth_polling_error')} ${error.message}`; + statusElement.style.color = 'var(--error-text)'; + } + this.showNotification(`${i18n.t('auth_login.iflow_oauth_polling_error')} ${error.message}`, 'error'); + // 3秒后重置UI,让用户能够重新开始 + setTimeout(() => { + this.resetIflowOAuthUI(); + }, 3000); + } + }, 2000); // 每2秒轮询一次 + + // 设置超时,5分钟后停止轮询 + setTimeout(() => { + clearInterval(pollInterval); + }, 5 * 60 * 1000); + } + + // 重置 iFlow OAuth UI 到初始状态 + resetIflowOAuthUI() { + const urlInput = document.getElementById('iflow-oauth-url'); + const content = document.getElementById('iflow-oauth-content'); + const status = document.getElementById('iflow-oauth-status'); + + // 清空并隐藏授权链接输入框 + if (urlInput) { + urlInput.value = ''; + } + + // 隐藏整个授权链接内容区域 + if (content) { + content.style.display = 'none'; + } + + // 清空状态显示 + if (status) { + status.textContent = ''; + status.style.color = ''; + status.className = ''; + } + } + // ===== 使用统计相关方法 ===== // 初始化图表变量 diff --git a/i18n.js b/i18n.js index 1a6cddb..c6e68b4 100644 --- a/i18n.js +++ b/i18n.js @@ -239,6 +239,61 @@ const i18n = { 'auth_login.codex_oauth_start_error': '启动 Codex OAuth 失败:', 'auth_login.codex_oauth_polling_error': '检查认证状态失败:', + // Anthropic OAuth + 'auth_login.anthropic_oauth_title': 'Anthropic OAuth', + 'auth_login.anthropic_oauth_button': '开始 Anthropic 登录', + 'auth_login.anthropic_oauth_hint': '通过 OAuth 流程登录 Anthropic (Claude) 服务,自动获取并保存认证文件。', + 'auth_login.anthropic_oauth_url_label': '授权链接:', + 'auth_login.anthropic_open_link': '打开链接', + 'auth_login.anthropic_copy_link': '复制链接', + 'auth_login.anthropic_oauth_status_waiting': '等待认证中...', + 'auth_login.anthropic_oauth_status_success': '认证成功!', + 'auth_login.anthropic_oauth_status_error': '认证失败:', + 'auth_login.anthropic_oauth_start_error': '启动 Anthropic OAuth 失败:', + 'auth_login.anthropic_oauth_polling_error': '检查认证状态失败:', + + // Gemini CLI OAuth + 'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth', + 'auth_login.gemini_cli_oauth_button': '开始 Gemini CLI 登录', + 'auth_login.gemini_cli_oauth_hint': '通过 OAuth 流程登录 Google Gemini CLI 服务,自动获取并保存认证文件。', + 'auth_login.gemini_cli_project_id_label': 'Google Cloud 项目 ID (可选):', + 'auth_login.gemini_cli_project_id_placeholder': '输入 Google Cloud 项目 ID (可选)', + 'auth_login.gemini_cli_project_id_hint': '如果指定了项目 ID,将使用该项目的认证信息。', + 'auth_login.gemini_cli_oauth_url_label': '授权链接:', + 'auth_login.gemini_cli_open_link': '打开链接', + 'auth_login.gemini_cli_copy_link': '复制链接', + 'auth_login.gemini_cli_oauth_status_waiting': '等待认证中...', + 'auth_login.gemini_cli_oauth_status_success': '认证成功!', + 'auth_login.gemini_cli_oauth_status_error': '认证失败:', + 'auth_login.gemini_cli_oauth_start_error': '启动 Gemini CLI OAuth 失败:', + 'auth_login.gemini_cli_oauth_polling_error': '检查认证状态失败:', + + // Qwen OAuth + 'auth_login.qwen_oauth_title': 'Qwen OAuth', + 'auth_login.qwen_oauth_button': '开始 Qwen 登录', + 'auth_login.qwen_oauth_hint': '通过设备授权流程登录 Qwen 服务,自动获取并保存认证文件。', + 'auth_login.qwen_oauth_url_label': '授权链接:', + 'auth_login.qwen_open_link': '打开链接', + 'auth_login.qwen_copy_link': '复制链接', + 'auth_login.qwen_oauth_status_waiting': '等待认证中...', + 'auth_login.qwen_oauth_status_success': '认证成功!', + 'auth_login.qwen_oauth_status_error': '认证失败:', + 'auth_login.qwen_oauth_start_error': '启动 Qwen OAuth 失败:', + 'auth_login.qwen_oauth_polling_error': '检查认证状态失败:', + + // iFlow OAuth + 'auth_login.iflow_oauth_title': 'iFlow OAuth', + 'auth_login.iflow_oauth_button': '开始 iFlow 登录', + 'auth_login.iflow_oauth_hint': '通过 OAuth 流程登录 iFlow 服务,自动获取并保存认证文件。', + 'auth_login.iflow_oauth_url_label': '授权链接:', + 'auth_login.iflow_open_link': '打开链接', + 'auth_login.iflow_copy_link': '复制链接', + 'auth_login.iflow_oauth_status_waiting': '等待认证中...', + 'auth_login.iflow_oauth_status_success': '认证成功!', + 'auth_login.iflow_oauth_status_error': '认证失败:', + 'auth_login.iflow_oauth_start_error': '启动 iFlow OAuth 失败:', + 'auth_login.iflow_oauth_polling_error': '检查认证状态失败:', + // 使用统计 'usage_stats.title': '使用统计', 'usage_stats.total_requests': '总请求数', @@ -546,6 +601,61 @@ const i18n = { 'auth_login.codex_oauth_start_error': 'Failed to start Codex OAuth:', 'auth_login.codex_oauth_polling_error': 'Failed to check authentication status:', + // Anthropic OAuth + 'auth_login.anthropic_oauth_title': 'Anthropic OAuth', + 'auth_login.anthropic_oauth_button': 'Start Anthropic Login', + 'auth_login.anthropic_oauth_hint': 'Login to Anthropic (Claude) service through OAuth flow, automatically obtain and save authentication files.', + 'auth_login.anthropic_oauth_url_label': 'Authorization URL:', + 'auth_login.anthropic_open_link': 'Open Link', + 'auth_login.anthropic_copy_link': 'Copy Link', + 'auth_login.anthropic_oauth_status_waiting': 'Waiting for authentication...', + 'auth_login.anthropic_oauth_status_success': 'Authentication successful!', + 'auth_login.anthropic_oauth_status_error': 'Authentication failed:', + 'auth_login.anthropic_oauth_start_error': 'Failed to start Anthropic OAuth:', + 'auth_login.anthropic_oauth_polling_error': 'Failed to check authentication status:', + + // Gemini CLI OAuth + 'auth_login.gemini_cli_oauth_title': 'Gemini CLI OAuth', + 'auth_login.gemini_cli_oauth_button': 'Start Gemini CLI Login', + 'auth_login.gemini_cli_oauth_hint': 'Login to Google Gemini CLI service through OAuth flow, automatically obtain and save authentication files.', + 'auth_login.gemini_cli_project_id_label': 'Google Cloud Project ID (Optional):', + 'auth_login.gemini_cli_project_id_placeholder': 'Enter Google Cloud Project ID (optional)', + 'auth_login.gemini_cli_project_id_hint': 'If a project ID is specified, authentication information for that project will be used.', + 'auth_login.gemini_cli_oauth_url_label': 'Authorization URL:', + 'auth_login.gemini_cli_open_link': 'Open Link', + 'auth_login.gemini_cli_copy_link': 'Copy Link', + 'auth_login.gemini_cli_oauth_status_waiting': 'Waiting for authentication...', + 'auth_login.gemini_cli_oauth_status_success': 'Authentication successful!', + 'auth_login.gemini_cli_oauth_status_error': 'Authentication failed:', + 'auth_login.gemini_cli_oauth_start_error': 'Failed to start Gemini CLI OAuth:', + 'auth_login.gemini_cli_oauth_polling_error': 'Failed to check authentication status:', + + // Qwen OAuth + 'auth_login.qwen_oauth_title': 'Qwen OAuth', + 'auth_login.qwen_oauth_button': 'Start Qwen Login', + 'auth_login.qwen_oauth_hint': 'Login to Qwen service through device authorization flow, automatically obtain and save authentication files.', + 'auth_login.qwen_oauth_url_label': 'Authorization URL:', + 'auth_login.qwen_open_link': 'Open Link', + 'auth_login.qwen_copy_link': 'Copy Link', + 'auth_login.qwen_oauth_status_waiting': 'Waiting for authentication...', + 'auth_login.qwen_oauth_status_success': 'Authentication successful!', + 'auth_login.qwen_oauth_status_error': 'Authentication failed:', + 'auth_login.qwen_oauth_start_error': 'Failed to start Qwen OAuth:', + 'auth_login.qwen_oauth_polling_error': 'Failed to check authentication status:', + + // iFlow OAuth + 'auth_login.iflow_oauth_title': 'iFlow OAuth', + 'auth_login.iflow_oauth_button': 'Start iFlow Login', + 'auth_login.iflow_oauth_hint': 'Login to iFlow service through OAuth flow, automatically obtain and save authentication files.', + 'auth_login.iflow_oauth_url_label': 'Authorization URL:', + 'auth_login.iflow_open_link': 'Open Link', + 'auth_login.iflow_copy_link': 'Copy Link', + 'auth_login.iflow_oauth_status_waiting': 'Waiting for authentication...', + 'auth_login.iflow_oauth_status_success': 'Authentication successful!', + 'auth_login.iflow_oauth_status_error': 'Authentication failed:', + 'auth_login.iflow_oauth_start_error': 'Failed to start iFlow OAuth:', + 'auth_login.iflow_oauth_polling_error': 'Failed to check authentication status:', + // Usage Statistics 'usage_stats.title': 'Usage Statistics', 'usage_stats.total_requests': 'Total Requests', diff --git a/index.html b/index.html index 056d680..312a8ab 100644 --- a/index.html +++ b/index.html @@ -467,6 +467,159 @@ + + +
+
+

Anthropic OAuth

+ +
+
+

+ 通过 OAuth 流程登录 Anthropic (Claude) 服务,自动获取并保存认证文件。 +

+ +
+
+ + +
+
+

Gemini CLI OAuth

+ +
+
+

+ 通过 OAuth 流程登录 Google Gemini CLI 服务,自动获取并保存认证文件。 +

+
+ + +
+ 如果指定了项目 ID,将使用该项目的认证信息。 +
+
+ +
+
+ + +
+
+

Qwen + OAuth

+ +
+
+

+ 通过设备授权流程登录 Qwen 服务,自动获取并保存认证文件。 +

+ +
+
+ + +
+
+

iFlow OAuth

+ +
+
+

+ 通过 OAuth 流程登录 iFlow 服务,自动获取并保存认证文件。 +

+ +
+
diff --git a/styles.css b/styles.css index 83361db..69c98b7 100644 --- a/styles.css +++ b/styles.css @@ -2316,4 +2316,390 @@ input:checked+.slider:before { #codex-oauth-url { font-size: 12px; } +} + +/* Anthropic OAuth 样式 */ +#anthropic-oauth-content { + transition: all 0.3s ease; +} + +#anthropic-oauth-url { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 13px; + background: var(--bg-tertiary); + border: 1px solid var(--border-primary); + color: var(--text-secondary); +} + +#anthropic-oauth-url:focus { + border-color: var(--border-focus); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +#anthropic-oauth-status { + font-weight: 500; + padding: 8px 12px; + border-radius: 6px; + background: var(--bg-tertiary); + border: 1px solid var(--border-primary); + transition: all 0.3s ease; +} + +#anthropic-oauth-status.success { + background: var(--success-bg); + border-color: var(--success-border); + color: var(--success-text); +} + +#anthropic-oauth-status.error { + background: var(--error-bg); + border-color: var(--error-border); + color: var(--error-text); +} + +#anthropic-oauth-status.warning { + background: var(--warning-bg); + border-color: var(--warning-border); + color: var(--warning-text); +} + +/* Anthropic OAuth 按钮样式 */ +#anthropic-open-link, +#anthropic-copy-link { + min-width: 100px; + white-space: nowrap; +} + +#anthropic-open-link { + background: var(--primary-color); + border-color: var(--primary-color); +} + +#anthropic-open-link:hover { + background: var(--primary-hover); + border-color: var(--primary-hover); +} + +#anthropic-copy-link { + background: var(--bg-secondary); + border-color: var(--border-primary); + color: var(--text-secondary); +} + +#anthropic-copy-link:hover { + background: var(--bg-tertiary); + border-color: var(--border-secondary); + color: var(--text-primary); +} + +/* 响应式设计 - Anthropic OAuth */ +@media (max-width: 768px) { + #anthropic-oauth-content .input-group { + flex-direction: column; + align-items: stretch; + } + + #anthropic-open-link, + #anthropic-copy-link { + width: 100%; + margin-top: 8px; + } + + #anthropic-oauth-url { + font-size: 12px; + } +} + +/* Gemini CLI OAuth 样式 */ +#gemini-cli-oauth-content { + transition: all 0.3s ease; +} + +#gemini-cli-oauth-url { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 13px; + background: var(--bg-tertiary); + border: 1px solid var(--border-primary); + color: var(--text-secondary); +} + +#gemini-cli-oauth-url:focus { + border-color: var(--border-focus); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +#gemini-cli-oauth-status { + font-weight: 500; + padding: 8px 12px; + border-radius: 6px; + background: var(--bg-tertiary); + border: 1px solid var(--border-primary); + transition: all 0.3s ease; +} + +#gemini-cli-oauth-status.success { + background: var(--success-bg); + border-color: var(--success-border); + color: var(--success-text); +} + +#gemini-cli-oauth-status.error { + background: var(--error-bg); + border-color: var(--error-border); + color: var(--error-text); +} + +#gemini-cli-oauth-status.warning { + background: var(--warning-bg); + border-color: var(--warning-border); + color: var(--warning-text); +} + +/* Gemini CLI OAuth 按钮样式 */ +#gemini-cli-open-link, +#gemini-cli-copy-link { + min-width: 100px; + white-space: nowrap; +} + +#gemini-cli-open-link { + background: var(--primary-color); + border-color: var(--primary-color); +} + +#gemini-cli-open-link:hover { + background: var(--primary-hover); + border-color: var(--primary-hover); +} + +#gemini-cli-copy-link { + background: var(--bg-secondary); + border-color: var(--border-primary); + color: var(--text-secondary); +} + +#gemini-cli-copy-link:hover { + background: var(--bg-tertiary); + border-color: var(--border-secondary); + color: var(--text-primary); +} + +/* Gemini CLI 项目 ID 输入框样式 */ +#gemini-cli-project-id { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 13px; + background: var(--bg-tertiary); + border: 1px solid var(--border-primary); + color: var(--text-secondary); +} + +#gemini-cli-project-id:focus { + border-color: var(--border-focus); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +/* 响应式设计 - Gemini CLI OAuth */ +@media (max-width: 768px) { + #gemini-cli-oauth-content .input-group { + flex-direction: column; + align-items: stretch; + } + + #gemini-cli-open-link, + #gemini-cli-copy-link { + width: 100%; + margin-top: 8px; + } + + #gemini-cli-oauth-url { + font-size: 12px; + } + + #gemini-cli-project-id { + font-size: 12px; + } +} + +/* Qwen OAuth 样式 */ +#qwen-oauth-content { + transition: all 0.3s ease; +} + +#qwen-oauth-url { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 13px; + background: var(--bg-tertiary); + border: 1px solid var(--border-primary); + color: var(--text-secondary); +} + +#qwen-oauth-url:focus { + border-color: var(--border-focus); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +#qwen-oauth-status { + font-weight: 500; + padding: 8px 12px; + border-radius: 6px; + background: var(--bg-tertiary); + border: 1px solid var(--border-primary); + transition: all 0.3s ease; +} + +#qwen-oauth-status.success { + background: var(--success-bg); + border-color: var(--success-border); + color: var(--success-text); +} + +#qwen-oauth-status.error { + background: var(--error-bg); + border-color: var(--error-border); + color: var(--error-text); +} + +#qwen-oauth-status.warning { + background: var(--warning-bg); + border-color: var(--warning-border); + color: var(--warning-text); +} + +/* Qwen OAuth 按钮样式 */ +#qwen-open-link, +#qwen-copy-link { + min-width: 100px; + white-space: nowrap; +} + +#qwen-open-link { + background: var(--primary-color); + border-color: var(--primary-color); +} + +#qwen-open-link:hover { + background: var(--primary-hover); + border-color: var(--primary-hover); +} + +#qwen-copy-link { + background: var(--bg-secondary); + border-color: var(--border-primary); + color: var(--text-secondary); +} + +#qwen-copy-link:hover { + background: var(--bg-tertiary); + border-color: var(--border-secondary); + color: var(--text-primary); +} + +/* 响应式设计 - Qwen OAuth */ +@media (max-width: 768px) { + #qwen-oauth-content .input-group { + flex-direction: column; + align-items: stretch; + } + + #qwen-open-link, + #qwen-copy-link { + width: 100%; + margin-top: 8px; + } + + #qwen-oauth-url { + font-size: 12px; + } +} + +/* iFlow OAuth 样式 */ +#iflow-oauth-content { + transition: all 0.3s ease; +} + +#iflow-oauth-url { + font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; + font-size: 13px; + background: var(--bg-tertiary); + border: 1px solid var(--border-primary); + color: var(--text-secondary); +} + +#iflow-oauth-url:focus { + border-color: var(--border-focus); + box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); +} + +#iflow-oauth-status { + font-weight: 500; + padding: 8px 12px; + border-radius: 6px; + background: var(--bg-tertiary); + border: 1px solid var(--border-primary); + transition: all 0.3s ease; +} + +#iflow-oauth-status.success { + background: var(--success-bg); + border-color: var(--success-border); + color: var(--success-text); +} + +#iflow-oauth-status.error { + background: var(--error-bg); + border-color: var(--error-border); + color: var(--error-text); +} + +#iflow-oauth-status.warning { + background: var(--warning-bg); + border-color: var(--warning-border); + color: var(--warning-text); +} + +/* iFlow OAuth 按钮样式 */ +#iflow-open-link, +#iflow-copy-link { + min-width: 100px; + white-space: nowrap; +} + +#iflow-open-link { + background: var(--primary-color); + border-color: var(--primary-color); +} + +#iflow-open-link:hover { + background: var(--primary-hover); + border-color: var(--primary-hover); +} + +#iflow-copy-link { + background: var(--bg-secondary); + border-color: var(--border-primary); + color: var(--text-secondary); +} + +#iflow-copy-link:hover { + background: var(--bg-tertiary); + border-color: var(--border-secondary); + color: var(--text-primary); +} + +/* 响应式设计 - iFlow OAuth */ +@media (max-width: 768px) { + #iflow-oauth-content .input-group { + flex-direction: column; + align-items: stretch; + } + + #iflow-open-link, + #iflow-copy-link { + width: 100%; + margin-top: 8px; + } + + #iflow-oauth-url { + font-size: 12px; + } } \ No newline at end of file