Download front/control_panel_mobile.html from zym1/gcli2api: direct link, hf CLI and curl.
- Browser
- Download file 98.8 kB
-
https://huggingface.co/spaces/zym1/gcli2api/resolve/main/front/control_panel_mobile.html
- Command line
-
hf download hf://spaces/zym1/gcli2api/front/control_panel_mobile.html
-
curl -L -o control_panel_mobile.html https://huggingface.co/spaces/zym1/gcli2api/resolve/main/front/control_panel_mobile.html
98.8 kB
| <html lang="zh-CN"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> | |
| <title>GCLI2API 移动端控制面板</title> | |
| <style> | |
| * { | |
| box-sizing: border-box; | |
| -webkit-tap-highlight-color: transparent; | |
| } | |
| body { | |
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif; | |
| margin: 0; | |
| padding: 0; | |
| background-color: #f5f5f5; | |
| font-size: 16px; | |
| line-height: 1.5; | |
| } | |
| .container { | |
| max-width: 100%; | |
| margin: 0; | |
| padding: 10px; | |
| background-color: white; | |
| min-height: 100vh; | |
| } | |
| h1 { | |
| color: #333; | |
| text-align: center; | |
| margin: 10px 0 20px 0; | |
| font-size: 20px; | |
| } | |
| .form-group { | |
| margin-bottom: 16px; | |
| } | |
| label { | |
| display: block; | |
| margin-bottom: 6px; | |
| font-weight: bold; | |
| color: #555; | |
| font-size: 14px; | |
| } | |
| input[type="text"], | |
| input[type="password"], | |
| input[type="number"], | |
| select, | |
| textarea { | |
| width: 100%; | |
| padding: 12px; | |
| border: 2px solid #ddd; | |
| border-radius: 8px; | |
| font-size: 16px; | |
| background-color: white; | |
| } | |
| input:focus, | |
| select:focus, | |
| textarea:focus { | |
| border-color: #4285f4; | |
| outline: none; | |
| } | |
| .btn { | |
| background-color: #28a745; | |
| color: white; | |
| padding: 14px 20px; | |
| border: none; | |
| border-radius: 8px; | |
| font-size: 16px; | |
| cursor: pointer; | |
| width: 100%; | |
| margin-bottom: 10px; | |
| touch-action: manipulation; | |
| } | |
| .btn:hover { | |
| background-color: #218838; | |
| } | |
| .btn:disabled { | |
| background-color: #ccc; | |
| cursor: not-allowed; | |
| } | |
| .btn-small { | |
| padding: 8px 12px; | |
| font-size: 14px; | |
| width: auto; | |
| display: inline-block; | |
| margin: 2px; | |
| } | |
| .btn-small.btn-danger { | |
| background-color: #dc3545; | |
| } | |
| .btn-small.btn-danger:hover { | |
| background-color: #c82333; | |
| } | |
| /* 移动端优化的标签页 */ | |
| .tabs { | |
| display: flex; | |
| background: linear-gradient(145deg, #f5f5f7, #e8e8ed); | |
| padding: 5px; | |
| border-radius: 12px; | |
| margin-bottom: 20px; | |
| overflow-x: auto; | |
| -webkit-overflow-scrolling: touch; | |
| gap: 3px; | |
| border-bottom: none; | |
| user-select: none; | |
| width: 100%; | |
| box-sizing: border-box; | |
| box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06), | |
| 0 1px 2px rgba(255, 255, 255, 0.9); | |
| position: relative; | |
| } | |
| /* 滑块指示器 */ | |
| .tab-slider { | |
| position: absolute; | |
| top: 5px; | |
| left: 0; | |
| right: 0; | |
| height: calc(100% - 10px); | |
| background: white; | |
| border-radius: 9px; | |
| box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1), | |
| 0 1px 3px rgba(0, 0, 0, 0.06); | |
| transition: left 0.3s cubic-bezier(0.4, 0, 0.2, 1), | |
| right 0.3s cubic-bezier(0.4, 0, 0.2, 1); | |
| z-index: 0; | |
| pointer-events: none; | |
| } | |
| /* 滑块微光效果 */ | |
| .tab-slider::after { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| height: 50%; | |
| background: linear-gradient(180deg, | |
| rgba(255, 255, 255, 0.8) 0%, | |
| rgba(255, 255, 255, 0) 100%); | |
| border-radius: 9px 9px 0 0; | |
| pointer-events: none; | |
| opacity: 0.5; | |
| } | |
| .tabs::-webkit-scrollbar { | |
| height: 3px; | |
| } | |
| .tabs::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| .tabs::-webkit-scrollbar-thumb { | |
| background: rgba(0, 0, 0, 0.15); | |
| border-radius: 2px; | |
| } | |
| .tab { | |
| padding: 10px 14px; | |
| cursor: pointer; | |
| border: none; | |
| background: transparent; | |
| border-radius: 9px; | |
| white-space: nowrap; | |
| min-width: 70px; | |
| flex-shrink: 0; | |
| font-size: 13px; | |
| font-weight: 450; | |
| color: #666; | |
| transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| /* 点击波纹效果 */ | |
| .tab::before { | |
| content: ''; | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| width: 0; | |
| height: 0; | |
| border-radius: 50%; | |
| background: rgba(66, 133, 244, 0.15); | |
| transform: translate(-50%, -50%); | |
| transition: width 0.4s ease, height 0.4s ease; | |
| z-index: -1; | |
| } | |
| .tab:active::before { | |
| width: 200%; | |
| height: 200%; | |
| } | |
| .tab.active { | |
| color: #1a1a1a; | |
| font-weight: 550; | |
| /* 背景和阴影由滑块提供 */ | |
| } | |
| .tab:hover:not(.active) { | |
| background: rgba(255, 255, 255, 0.5); | |
| color: #333; | |
| } | |
| /* 按压效果 */ | |
| .tab:active { | |
| transform: scale(0.96); | |
| transition: transform 0.1s ease; | |
| } | |
| .tab.active:active { | |
| transform: scale(0.98); | |
| box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); | |
| } | |
| .tab-content { | |
| display: none; | |
| padding: 10px 0; | |
| /* 动画由 JavaScript 控制,避免冲突 */ | |
| } | |
| .tab-content.active { | |
| display: block; | |
| } | |
| /* Toast 固定定位在右上角 */ | |
| #statusSection { | |
| position: fixed; | |
| top: 10px; | |
| right: 10px; | |
| left: auto; | |
| transform: none; | |
| z-index: 9999; | |
| width: auto; | |
| max-width: 90%; | |
| min-width: 200px; | |
| } | |
| /* Toast 专用样式 - 只在 #statusSection 内生效 */ | |
| #statusSection .status { | |
| padding: 10px 16px; | |
| border-radius: 8px; | |
| margin: 0; | |
| font-size: 13px; | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); | |
| opacity: 0; | |
| transform: translateX(100%); | |
| transition: opacity 0.3s ease, transform 0.3s ease; | |
| } | |
| #statusSection .status.show { | |
| opacity: 1; | |
| transform: translateX(0); | |
| } | |
| #statusSection .status.fade-out { | |
| opacity: 0; | |
| transform: translateX(100%); | |
| } | |
| #statusSection .status.success { | |
| background-color: #28a745; | |
| border: none; | |
| color: white; | |
| } | |
| #statusSection .status.error { | |
| background-color: #dc3545; | |
| border: none; | |
| color: white; | |
| } | |
| #statusSection .status.warning { | |
| background-color: #ffc107; | |
| border: none; | |
| color: #212529; | |
| } | |
| #statusSection .status.info { | |
| background-color: #17a2b8; | |
| border: none; | |
| color: white; | |
| } | |
| /* 页面内嵌的 status 样式 - 保持原有风格 */ | |
| .status { | |
| padding: 12px; | |
| border-radius: 8px; | |
| margin: 10px 0; | |
| font-size: 14px; | |
| } | |
| .status.success { | |
| background-color: #d4edda; | |
| border: 1px solid #c3e6cb; | |
| color: #155724; | |
| } | |
| .status.error { | |
| background-color: #f8d7da; | |
| border: 1px solid #f5c6cb; | |
| color: #721c24; | |
| } | |
| .status.info { | |
| background-color: #d1ecf1; | |
| border: 1px solid #bee5eb; | |
| color: #0c5460; | |
| } | |
| .hidden { | |
| display: none; | |
| } | |
| .loading { | |
| text-align: center; | |
| color: #666; | |
| padding: 20px; | |
| } | |
| .login-form { | |
| text-align: center; | |
| padding: 40px 20px; | |
| } | |
| /* 移动端优化的卡片样式 */ | |
| .card { | |
| background-color: white; | |
| border: 1px solid #e1e4e8; | |
| border-radius: 8px; | |
| padding: 15px; | |
| margin: 10px 0; | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | |
| } | |
| .card-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 10px; | |
| flex-wrap: wrap; | |
| } | |
| .card-title { | |
| font-weight: bold; | |
| color: #333; | |
| font-size: 14px; | |
| word-break: break-all; | |
| } | |
| .card-actions { | |
| display: flex; | |
| gap: 5px; | |
| flex-wrap: wrap; | |
| margin-top: 10px; | |
| } | |
| /* 移动端优化的统计样式 */ | |
| .stats-container { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); | |
| gap: 10px; | |
| margin-bottom: 15px; | |
| } | |
| .stat-item { | |
| background: white; | |
| border: 1px solid #dee2e6; | |
| border-radius: 8px; | |
| padding: 12px; | |
| text-align: center; | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | |
| } | |
| .stat-number { | |
| font-size: 20px; | |
| font-weight: bold; | |
| color: #333; | |
| display: block; | |
| } | |
| .stat-label { | |
| font-size: 12px; | |
| color: #666; | |
| margin-top: 4px; | |
| } | |
| /* 移动端优化的进度条 */ | |
| .progress-bar { | |
| width: 100%; | |
| height: 8px; | |
| background-color: #e9ecef; | |
| border-radius: 4px; | |
| overflow: hidden; | |
| margin: 8px 0; | |
| } | |
| .progress-fill { | |
| height: 100%; | |
| background-color: #28a745; | |
| transition: width 0.3s ease; | |
| } | |
| /* 移动端优化的模态框 */ | |
| .modal { | |
| display: none; | |
| position: fixed; | |
| z-index: 1000; | |
| left: 0; | |
| top: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: rgba(0, 0, 0, 0.5); | |
| } | |
| .modal-content { | |
| background-color: white; | |
| margin: 5% auto; | |
| padding: 20px; | |
| border-radius: 8px; | |
| width: 95%; | |
| max-width: 400px; | |
| max-height: 90vh; | |
| overflow-y: auto; | |
| } | |
| .modal-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| margin-bottom: 15px; | |
| padding-bottom: 10px; | |
| border-bottom: 1px solid #dee2e6; | |
| } | |
| .modal-close { | |
| background: none; | |
| border: none; | |
| font-size: 24px; | |
| cursor: pointer; | |
| color: #999; | |
| } | |
| /* 响应式优化 */ | |
| @media (max-width: 768px) { | |
| .container { | |
| padding: 5px; | |
| } | |
| h1 { | |
| font-size: 18px; | |
| } | |
| .tabs { | |
| font-size: 13px; | |
| } | |
| .tab { | |
| padding: 10px 12px; | |
| min-width: 70px; | |
| } | |
| .btn { | |
| padding: 12px 16px; | |
| font-size: 15px; | |
| } | |
| .modal-content { | |
| width: 98%; | |
| margin: 2% auto; | |
| } | |
| } | |
| @media (max-width: 480px) { | |
| .stats-container { | |
| grid-template-columns: repeat(2, 1fr); | |
| } | |
| .card-header { | |
| flex-direction: column; | |
| align-items: flex-start; | |
| gap: 8px; | |
| } | |
| .card-actions { | |
| width: 100%; | |
| justify-content: space-between; | |
| } | |
| .btn-small { | |
| flex: 1; | |
| margin: 1px; | |
| font-size: 12px; | |
| padding: 6px 8px; | |
| } | |
| } | |
| .log-entry { | |
| margin-bottom: 2px; | |
| padding: 2px 0; | |
| border-left: 3px solid transparent; | |
| padding-left: 8px; | |
| } | |
| .log-debug { | |
| color: #888; | |
| border-left-color: #888; | |
| } | |
| .log-info { | |
| color: #d4d4d4; | |
| border-left-color: #007acc; | |
| } | |
| .log-warning { | |
| color: #ffcc02; | |
| border-left-color: #ffcc02; | |
| } | |
| .log-error { | |
| color: #f48771; | |
| border-left-color: #f48771; | |
| } | |
| .log-critical { | |
| color: #ff6b6b; | |
| background-color: rgba(255, 107, 107, 0.1); | |
| border-left-color: #ff6b6b; | |
| } | |
| .log-timestamp { | |
| color: #569cd6; | |
| margin-right: 8px; | |
| } | |
| .log-level { | |
| font-weight: bold; | |
| margin-right: 8px; | |
| min-width: 60px; | |
| display: inline-block; | |
| } | |
| .log-message { | |
| word-break: break-all; | |
| } | |
| /* 文件管理卡片样式 */ | |
| .cred-card { | |
| background-color: #f8f9fa; | |
| border: 1px solid #e1e4e8; | |
| border-radius: 8px; | |
| padding: 15px; | |
| margin: 10px 0; | |
| position: relative; | |
| box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); | |
| } | |
| .cred-card.disabled { | |
| background-color: #f5f5f5; | |
| border-color: #ccc; | |
| opacity: 0.7; | |
| } | |
| .cred-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: flex-start; | |
| margin-bottom: 10px; | |
| gap: 10px; | |
| flex-wrap: wrap; | |
| } | |
| .cred-filename { | |
| font-family: monospace; | |
| font-weight: bold; | |
| color: #333; | |
| font-size: 13px; | |
| word-break: break-all; | |
| flex: 1; | |
| min-width: 0; | |
| } | |
| .cred-status { | |
| display: flex; | |
| gap: 5px; | |
| flex-wrap: wrap; | |
| } | |
| .status-badge { | |
| padding: 2px 8px; | |
| border-radius: 12px; | |
| font-size: 11px; | |
| color: white; | |
| white-space: nowrap; | |
| } | |
| .status-badge.enabled { | |
| background-color: #28a745; | |
| } | |
| .status-badge.disabled { | |
| background-color: #6c757d; | |
| } | |
| .error-codes { | |
| background-color: #f8d7da; | |
| color: #721c24; | |
| padding: 2px 8px; | |
| border-radius: 12px; | |
| font-size: 11px; | |
| } | |
| .cooldown-badge { | |
| background-color: #ffc107; | |
| color: #856404; | |
| padding: 2px 8px; | |
| border-radius: 12px; | |
| font-size: 11px; | |
| font-weight: bold; | |
| white-space: nowrap; | |
| } | |
| .cooldown-badge.ready { | |
| background-color: #28a745; | |
| color: white; | |
| } | |
| .model-cooldown-details { | |
| background-color: #e3f2fd; | |
| border: 1px solid #90caf9; | |
| border-radius: 4px; | |
| padding: 8px; | |
| margin-top: 8px; | |
| font-size: 11px; | |
| color: #1976d2; | |
| } | |
| .model-cooldown-item { | |
| display: inline-block; | |
| background-color: #64b5f6; | |
| color: white; | |
| padding: 2px 6px; | |
| border-radius: 10px; | |
| margin: 2px; | |
| font-size: 10px; | |
| } | |
| .cred-actions { | |
| display: flex; | |
| gap: 5px; | |
| flex-wrap: wrap; | |
| margin-top: 10px; | |
| } | |
| .cred-btn { | |
| padding: 6px 12px; | |
| border: none; | |
| border-radius: 4px; | |
| font-size: 12px; | |
| cursor: pointer; | |
| transition: background-color 0.2s; | |
| white-space: nowrap; | |
| background-color: #28a745; | |
| color: white; | |
| } | |
| .cred-btn:hover { | |
| background-color: #218838; | |
| } | |
| .cred-btn.enable { | |
| background-color: #28a745; | |
| color: white; | |
| } | |
| .cred-btn.disable { | |
| background-color: #28a745; | |
| color: white; | |
| } | |
| .cred-btn.delete { | |
| background-color: #dc3545; | |
| color: white; | |
| } | |
| .cred-btn.delete:hover { | |
| background-color: #c82333; | |
| } | |
| .cred-btn.download { | |
| background-color: #28a745; | |
| color: white; | |
| } | |
| .cred-btn.view { | |
| background-color: #28a745; | |
| color: white; | |
| } | |
| .cred-btn.email { | |
| background-color: #28a745; | |
| color: white; | |
| } | |
| .cred-details { | |
| margin-top: 10px; | |
| display: none; | |
| } | |
| .cred-details.show { | |
| display: block; | |
| } | |
| .cred-content { | |
| background-color: #f0f8ff; | |
| border: 1px solid #b0d4ff; | |
| border-radius: 4px; | |
| padding: 10px; | |
| font-family: monospace; | |
| font-size: 11px; | |
| white-space: pre-wrap; | |
| word-break: break-all; | |
| max-height: 200px; | |
| overflow-y: auto; | |
| } | |
| /* 额度信息显示样式 */ | |
| .cred-quota-details { | |
| margin-top: 10px; | |
| animation: slideDown 0.3s ease-out; | |
| } | |
| @keyframes slideDown { | |
| from { | |
| opacity: 0; | |
| transform: translateY(-10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .cred-quota-content { | |
| background: linear-gradient(to bottom, #ffffff, #f8f9fa); | |
| border: 2px solid #17a2b8; | |
| border-radius: 8px; | |
| padding: 10px; | |
| box-shadow: 0 2px 8px rgba(23, 162, 184, 0.15); | |
| } | |
| /* 批量操作按钮禁用状态 */ | |
| .btn-small:disabled { | |
| background-color: #e9ecef ; | |
| color: #6c757d ; | |
| cursor: not-allowed; | |
| opacity: 0.6; | |
| } | |
| /* 批量操作控件优化 */ | |
| .batch-controls-grid { | |
| display: grid; | |
| grid-template-columns: repeat(2, 1fr); | |
| gap: 8px; | |
| } | |
| @media (max-width: 400px) { | |
| .batch-controls-grid { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| /* 文件卡片复选框区域优化 */ | |
| .file-selection-area { | |
| display: flex; | |
| align-items: flex-start; | |
| gap: 10px; | |
| } | |
| @media (max-width: 400px) { | |
| .file-selection-area { | |
| gap: 8px; | |
| } | |
| .file-checkbox { | |
| transform: scale(1.1) ; | |
| } | |
| } | |
| /* 消息模态框样式 */ | |
| .message-modal-overlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| background-color: rgba(0, 0, 0, 0.5); | |
| display: flex; | |
| justify-content: center; | |
| align-items: center; | |
| z-index: 10000; | |
| animation: fadeIn 0.2s ease-in; | |
| } | |
| @keyframes fadeIn { | |
| from { | |
| opacity: 0; | |
| } | |
| to { | |
| opacity: 1; | |
| } | |
| } | |
| .message-modal { | |
| background: white; | |
| border-radius: 8px; | |
| box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); | |
| max-width: 600px; | |
| width: 90%; | |
| max-height: 80vh; | |
| display: flex; | |
| flex-direction: column; | |
| animation: slideIn 0.3s ease-out; | |
| } | |
| @keyframes slideIn { | |
| from { | |
| transform: translateY(-50px); | |
| opacity: 0; | |
| } | |
| to { | |
| transform: translateY(0); | |
| opacity: 1; | |
| } | |
| } | |
| .message-modal-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| padding: 20px 24px; | |
| border-bottom: 1px solid #e0e0e0; | |
| } | |
| .message-modal.success .message-modal-header { | |
| background: linear-gradient(135deg, #4caf50 0%, #45a049 100%); | |
| color: white; | |
| border-radius: 8px 8px 0 0; | |
| } | |
| .message-modal.error .message-modal-header { | |
| background: linear-gradient(135deg, #f44336 0%, #d32f2f 100%); | |
| color: white; | |
| border-radius: 8px 8px 0 0; | |
| } | |
| .message-modal.info .message-modal-header { | |
| background: linear-gradient(135deg, #2196f3 0%, #1976d2 100%); | |
| color: white; | |
| border-radius: 8px 8px 0 0; | |
| } | |
| .message-modal-header h3 { | |
| margin: 0; | |
| font-size: 20px; | |
| font-weight: 600; | |
| } | |
| .message-modal-close { | |
| background: none; | |
| border: none; | |
| font-size: 28px; | |
| cursor: pointer; | |
| color: inherit; | |
| opacity: 0.8; | |
| transition: opacity 0.2s; | |
| padding: 0; | |
| width: 32px; | |
| height: 32px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| } | |
| .message-modal-close:hover { | |
| opacity: 1; | |
| } | |
| .message-modal-body { | |
| padding: 24px; | |
| overflow-y: auto; | |
| line-height: 1.6; | |
| color: #333; | |
| font-size: 14px; | |
| white-space: pre-wrap; | |
| word-break: break-word; | |
| } | |
| .message-modal-footer { | |
| padding: 16px 24px; | |
| border-top: 1px solid #e0e0e0; | |
| display: flex; | |
| justify-content: flex-end; | |
| gap: 10px; | |
| } | |
| .message-modal-btn { | |
| padding: 10px 24px; | |
| border: none; | |
| border-radius: 4px; | |
| font-size: 14px; | |
| font-weight: 500; | |
| cursor: pointer; | |
| transition: all 0.2s; | |
| background-color: #4285f4; | |
| color: white; | |
| } | |
| .message-modal-btn:hover { | |
| background-color: #3367d6; | |
| transform: translateY(-1px); | |
| box-shadow: 0 2px 8px rgba(66, 133, 244, 0.3); | |
| } | |
| /* 消息中的链接样式 */ | |
| .message-link { | |
| color: #1976d2; | |
| text-decoration: none; | |
| font-weight: 500; | |
| padding: 2px 4px; | |
| border-radius: 3px; | |
| background-color: rgba(25, 118, 210, 0.1); | |
| transition: all 0.2s; | |
| display: inline-block; | |
| word-break: break-all; | |
| } | |
| .message-link:hover { | |
| background-color: rgba(25, 118, 210, 0.2); | |
| text-decoration: underline; | |
| transform: translateY(-1px); | |
| } | |
| .message-link:active { | |
| transform: translateY(0); | |
| } | |
| /* 移动端适配 */ | |
| @media (max-width: 768px) { | |
| .message-modal { | |
| max-width: 95%; | |
| max-height: 90vh; | |
| } | |
| .message-modal-header { | |
| padding: 16px 20px; | |
| } | |
| .message-modal-body { | |
| padding: 20px; | |
| font-size: 13px; | |
| } | |
| .message-modal-footer { | |
| padding: 12px 20px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <!-- 登录界面 --> | |
| <div id="loginSection" class="login-form"> | |
| <h1>GCLI2API 移动端控制面板</h1> | |
| <p>请输入访问密码:</p> | |
| <input type="password" id="loginPassword" placeholder="输入密码" onkeypress="handlePasswordEnter(event)" /> | |
| <br><br> | |
| <button class="btn" onclick="login()">登录</button> | |
| </div> | |
| <!-- 主界面 --> | |
| <div id="mainSection" class="hidden"> | |
| <div | |
| style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 15px; flex-wrap: wrap; gap: 10px;"> | |
| <div style="display: flex; flex-direction: column; gap: 6px; flex: 1;"> | |
| <h1 style="margin: 0; font-size: 20px;">GCLI2API 移动端控制面板</h1> | |
| <div style="display: flex; align-items: center; gap: 8px; flex-wrap: wrap;"> | |
| <span id="versionInfo" style="font-size: 11px; color: #666;"> | |
| <span id="versionText">加载中...</span> | |
| </span> | |
| <button onclick="checkForUpdates()" id="checkUpdateBtn" | |
| style="padding: 2px 8px; background-color: #17a2b8; color: white; border: none; border-radius: 3px; font-size: 10px; cursor: pointer; white-space: nowrap;"> | |
| 检查更新 | |
| </button> | |
| </div> | |
| </div> | |
| <button onclick="logout()" | |
| style="padding: 6px 15px; background-color: #dc3545; color: white; border: none; border-radius: 4px; font-size: 12px; cursor: pointer; white-space: nowrap;"> | |
| 退出登录 | |
| </button> | |
| </div> | |
| <!-- 移动端优化的标签页 --> | |
| <!-- 移动端优化的标签页 --> | |
| <div class="tabs"> | |
| <div class="tab-slider"></div> | |
| <button class="tab active" onclick="switchTab('oauth')">OAuth认证</button> | |
| <button class="tab" onclick="switchTab('antigravity')">Antigravity认证</button> | |
| <button class="tab" onclick="switchTab('upload')">批量上传</button> | |
| <button class="tab" onclick="switchTab('manage')">GCLI凭证</button> | |
| <button class="tab" onclick="switchTab('antigravity-manage')">AG凭证</button> | |
| <button class="tab" onclick="switchTab('config')">配置管理</button> | |
| <button class="tab" onclick="switchTab('logs')">实时日志</button> | |
| <button class="tab" onclick="switchTab('about')">项目信息</button> | |
| </div> | |
| <!-- OAuth认证标签页 --> | |
| <div id="oauthTab" class="tab-content active"> | |
| <!-- API 自动启用说明 --> | |
| <div class="status success" style="margin-bottom: 20px;"> | |
| <strong>✨ 自动化优化:</strong> 系统现在会在认证成功后自动为您的项目启用必需的API服务 | |
| <ul style="margin: 10px 0; padding-left: 20px; font-size: 13px;"> | |
| <li><strong>Gemini Cloud Assist API</strong></li> | |
| <li><strong>Gemini for Google Cloud API</strong></li> | |
| </ul> | |
| <p style="margin: 10px 0; color: #155724; font-size: 13px;"> | |
| <strong>说明:</strong>无需手动启用API,系统会自动处理这些配置步骤,让认证流程更加顺畅。 | |
| </p> | |
| </div> | |
| <!-- 折叠式 Project ID 输入框 --> | |
| <div class="form-group"> | |
| <div style="cursor: pointer; user-select: none; padding: 12px; border: 2px solid #ddd; border-radius: 8px; background: #f8f8f8; display: flex; justify-content: space-between; align-items: center;" | |
| onclick="toggleProjectIdSection()"> | |
| <span style="font-weight: bold; color: #555; font-size: 14px;">📁 高级选项:Google Cloud Project ID | |
| (不用管,直接点击获取链接即可)</span> | |
| <span id="projectIdToggleIcon" | |
| style="font-size: 14px; color: #666; transition: transform 0.3s ease;">▶</span> | |
| </div> | |
| <div id="projectIdSection" | |
| style="display: none; margin-top: 10px; padding: 12px; border: 2px solid #ddd; border-top: none; border-radius: 0 0 8px 8px; background: #ffffff;"> | |
| <label for="projectId">Google Cloud Project ID (可选):</label> | |
| <input type="text" id="projectId" placeholder="留空将尝试自动检测,或手动输入项目ID" /> | |
| <small style="color: #666; font-size: 12px; margin-top: 5px; display: block;"> | |
| 💡 提示:如果你不懂这是什么,可以留空此字段让系统自动检测项目ID | |
| </small> | |
| </div> | |
| </div> | |
| <button class="btn" id="getAuthBtn" onclick="startAuth()">获取认证链接</button> | |
| <div id="authUrlSection" class="hidden"> | |
| <h4>认证链接:</h4> | |
| <div | |
| style="background-color: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 12px; margin: 15px 0; word-break: break-all;"> | |
| <a id="authUrl" href="#" target="_blank" | |
| style="color: #4285f4; text-decoration: none;">点击此链接进行认证</a> | |
| </div> | |
| <div class="status info"> | |
| <strong>重要说明:</strong> | |
| <ol style="margin: 10px 0; padding-left: 20px; font-size: 13px;"> | |
| <li>点击上方认证链接,会在新窗口中打开Google OAuth页面</li> | |
| <li>完成Google账号登录和授权</li> | |
| <li>授权成功后会跳转到localhost:11451显示成功页面</li> | |
| <li>关闭OAuth窗口,返回本页面</li> | |
| <li>点击下方"获取认证文件"按钮完成流程</li> | |
| </ol> | |
| </div> | |
| <!-- 快捷回调URL输入选项 --> | |
| <div class="form-group" | |
| style="margin: 20px 0; padding: 15px; border: 2px solid #e8f4fd; border-radius: 8px; background: #f8fcff;"> | |
| <div style="cursor: pointer; user-select: none; display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;" | |
| onclick="toggleCallbackUrlSection()"> | |
| <span style="font-weight: bold; color: #0066cc;">🚀 无法回源?试试快捷方式</span> | |
| <span id="callbackUrlToggleIcon" | |
| style="font-size: 14px; color: #666; transition: transform 0.3s ease;">▼</span> | |
| </div> | |
| <div id="callbackUrlSection" style="display: none;"> | |
| <div | |
| style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; padding: 12px; margin-bottom: 12px;"> | |
| <div style="color: #856404; font-size: 14px; font-weight: bold; margin-bottom: 6px;">📚 | |
| 适用场景:</div> | |
| <ul | |
| style="color: #856404; font-size: 13px; margin: 0; padding-left: 18px; line-height: 1.5;"> | |
| <li>云服务器、VPS等非本地环境</li> | |
| <li>防火墙阻止了11451端口访问</li> | |
| <li>网络环境无法正常回源到localhost</li> | |
| <li>Docker容器内运行,端口映射问题</li> | |
| </ul> | |
| </div> | |
| <div style="color: #666; font-size: 13px; margin-bottom: 12px; line-height: 1.6;"> | |
| <strong style="color: #0066cc;">🔍 什么是回调URL?</strong><br> | |
| 完成Google OAuth授权后,浏览器地址栏显示的完整URL,通常看起来像这样:<br> | |
| <code | |
| style="background: #f1f3f4; padding: 2px 6px; border-radius: 3px; font-size: 12px; word-break: break-all;"> | |
| http://localhost:11451/?state=abc123...&code=4/0AVMBsJ...&scope=email%20profile... | |
| </code> | |
| </div> | |
| <div | |
| style="background: #e7f3ff; border: 1px solid #b3d9ff; border-radius: 6px; padding: 10px; margin-bottom: 12px;"> | |
| <div style="color: #0066cc; font-size: 13px; font-weight: bold; margin-bottom: 4px;">📋 | |
| 使用步骤:</div> | |
| <ol | |
| style="color: #0066cc; font-size: 12px; margin: 0; padding-left: 18px; line-height: 1.4;"> | |
| <li>点击上方认证链接,完成Google授权</li> | |
| <li>授权成功后,复制浏览器地址栏的<strong>完整URL</strong></li> | |
| <li>粘贴到下方输入框,点击获取凭证即可</li> | |
| </ol> | |
| </div> | |
| <div class="input-group"> | |
| <input type="url" id="callbackUrlInput" | |
| placeholder="粘贴完整的回调URL,例如:http://localhost:11451/?state=xxx&code=xxx&scope=xxx..." | |
| style="width: 100%; padding: 10px; border: 2px solid #ddd; border-radius: 4px; font-size: 13px;"> | |
| </div> | |
| <button class="btn" style="margin-top: 10px;" onclick="processCallbackUrl()"> | |
| 从回调URL获取凭证 | |
| </button> | |
| </div> | |
| </div> | |
| <button class="btn" id="getCredsBtn" onclick="getCredentials()">获取认证文件</button> | |
| </div> | |
| <div id="credentialsSection" class="hidden"> | |
| <h4>认证文件内容:</h4> | |
| <div style="background-color: #f0f8ff; border: 1px solid #b0d4ff; border-radius: 8px; padding: 12px; font-family: monospace; font-size: 11px; white-space: pre-wrap; word-break: break-all; max-height: 300px; overflow-y: auto;" | |
| id="credentialsContent"></div> | |
| </div> | |
| </div> | |
| <!-- Antigravity 认证标签页 --> | |
| <div id="antigravityTab" class="tab-content"> | |
| <div class="status info" style="margin-bottom: 20px;"> | |
| <strong>🚀 Antigravity 认证模式</strong> | |
| <p style="margin: 10px 0; font-size: 13px;"> | |
| 获取谷歌Antigravity 凭证 | |
| </p> | |
| </div> | |
| <button class="btn" id="getAntigravityAuthBtn">获取 Antigravity 认证链接</button> | |
| <div id="antigravityAuthUrlSection" class="hidden"> | |
| <h4>Antigravity 认证链接:</h4> | |
| <div | |
| style="background-color: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 12px; margin: 15px 0; word-break: break-all;"> | |
| <a id="antigravityAuthUrl" href="#" target="_blank" | |
| style="color: #4285f4; text-decoration: none;">点击此链接进行认证</a> | |
| </div> | |
| <div class="status info"> | |
| <strong>使用说明:</strong> | |
| <ol style="margin: 10px 0; padding-left: 20px; font-size: 13px;"> | |
| <li>点击上方认证链接,在新窗口中完成 Google 授权</li> | |
| <li>授权成功后会跳转到 localhost 显示成功页面</li> | |
| <li>关闭 OAuth 窗口,返回本页面</li> | |
| <li>点击下方"获取凭证"按钮完成流程</li> | |
| </ol> | |
| </div> | |
| <!-- 快捷回调URL输入选项 --> | |
| <div class="form-group" | |
| style="margin: 15px 0; padding: 12px; border: 2px solid #e8f4fd; border-radius: 8px; background: #f8fcff;"> | |
| <div style="cursor: pointer; user-select: none; display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;" | |
| onclick="toggleAntigravityCallbackUrlSection()"> | |
| <span style="font-weight: bold; color: #0066cc; font-size: 13px;">🚀 无法回源?试试快捷方式</span> | |
| <span id="antigravityCallbackUrlToggleIcon" | |
| style="font-size: 14px; color: #666; transition: transform 0.3s ease;">▼</span> | |
| </div> | |
| <div id="antigravityCallbackUrlSection" style="display: none;"> | |
| <div | |
| style="background: #fff3cd; border: 1px solid #ffeaa7; border-radius: 6px; padding: 10px; margin-bottom: 10px;"> | |
| <div style="color: #856404; font-size: 12px; font-weight: bold; margin-bottom: 4px;">📚 | |
| 适用场景:</div> | |
| <ul | |
| style="color: #856404; font-size: 11px; margin: 0; padding-left: 16px; line-height: 1.4;"> | |
| <li>云服务器、VPS等非本地环境</li> | |
| <li>防火墙阻止了11451端口访问</li> | |
| <li>网络环境无法正常回源到localhost</li> | |
| <li>Docker容器内运行,端口映射问题</li> | |
| </ul> | |
| </div> | |
| <div style="color: #666; font-size: 11px; margin-bottom: 10px; line-height: 1.5;"> | |
| <strong style="color: #0066cc;">🔍 什么是回调URL?</strong><br> | |
| 完成Google OAuth授权后,浏览器地址栏显示的完整URL,通常看起来像这样:<br> | |
| <code | |
| style="background: #f1f3f4; padding: 2px 4px; border-radius: 3px; font-size: 10px; word-break: break-all;"> | |
| http://localhost:11451/?state=abc123...&code=4/0AVMBsJ...&scope=email%20profile... | |
| </code> | |
| </div> | |
| <div | |
| style="background: #e7f3ff; border: 1px solid #b3d9ff; border-radius: 6px; padding: 8px; margin-bottom: 10px;"> | |
| <div style="color: #0066cc; font-size: 11px; font-weight: bold; margin-bottom: 3px;">📋 | |
| 使用步骤:</div> | |
| <ol | |
| style="color: #0066cc; font-size: 10px; margin: 0; padding-left: 16px; line-height: 1.3;"> | |
| <li>点击上方认证链接,完成Google授权</li> | |
| <li>授权成功后,复制浏览器地址栏的<strong>完整URL</strong></li> | |
| <li>粘贴到下方输入框,点击获取凭证即可</li> | |
| </ol> | |
| </div> | |
| <div class="input-group"> | |
| <input type="url" id="antigravityCallbackUrlInput" | |
| placeholder="粘贴完整的回调URL,例如:http://localhost:11451/?state=xxx&code=xxx&scope=xxx..." | |
| style="width: 100%; padding: 8px; border: 2px solid #ddd; border-radius: 4px; font-size: 12px;"> | |
| </div> | |
| <button class="btn" | |
| style="margin-top: 8px; background: #28a745; border-color: #28a745; font-size: 13px;" | |
| onclick="processAntigravityCallbackUrl()"> | |
| 从回调URL获取凭证 | |
| </button> | |
| </div> | |
| </div> | |
| <button class="btn" id="getAntigravityCredsBtn" onclick="getAntigravityCredentials()">获取 Antigravity | |
| 凭证</button> | |
| <div id="antigravityCredsSection" class="hidden"> | |
| <h4>Antigravity 凭证内容:</h4> | |
| <div | |
| style="background-color: #f0f8ff; border: 1px solid #b0d4ff; border-radius: 8px; padding: 12px; font-family: monospace; font-size: 11px; white-space: pre-wrap; word-break: break-all; max-height: 300px; overflow-y: auto;"> | |
| <pre id="antigravityCredsContent"></pre> | |
| </div> | |
| <button class="btn" onclick="downloadAntigravityCredentials()" | |
| style="margin-top: 10px;">下载凭证文件</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 批量上传标签页 --> | |
| <div id="uploadTab" class="tab-content"> | |
| <h3>批量上传认证文件</h3> | |
| <p>支持批量上传 GCLI 和 Antigravity 认证文件</p> | |
| <!-- GCLI凭证上传区域 --> | |
| <div | |
| style="margin-bottom: 25px; padding: 15px; border: 2px solid #007bff; border-radius: 8px; background: #f8f9fa;"> | |
| <h4 | |
| style="margin-top: 0; color: #007bff; border-bottom: 2px solid #007bff; padding-bottom: 8px; font-size: 16px;"> | |
| 📤 GCLI 凭证批量上传</h4> | |
| <div style="border: 2px dashed #007bff; border-radius: 8px; padding: 25px; text-align: center; background-color: #fafafa; margin: 15px 0; cursor: pointer; transition: border-color 0.3s;" | |
| id="uploadArea" onclick="document.getElementById('fileInput').click()"> | |
| <p style="margin: 10px 0; font-size: 16px;">📁 点击选择文件或拖拽文件到此区域</p> | |
| <p style="color: #666; font-size: 14px; margin: 5px 0;">支持 .json 和 .zip 格式文件</p> | |
| <p style="color: #888; font-size: 12px; margin: 5px 0;">ZIP文件会自动解压提取其中的JSON凭证</p> | |
| </div> | |
| <input type="file" id="fileInput" multiple accept=".json,.zip" style="display: none;" | |
| onchange="handleFileSelect(event)" /> | |
| <div id="fileListSection" class="hidden"> | |
| <h4>选择的文件:</h4> | |
| <div id="fileList"></div> | |
| <div style="display: flex; gap: 10px; margin-top: 15px;"> | |
| <button class="btn" onclick="uploadFiles()" style="flex: 1;">上传文件</button> | |
| <button class="btn" style="flex: 1;" onclick="clearFiles()">清空列表</button> | |
| </div> | |
| </div> | |
| <div id="uploadProgressSection" class="hidden"> | |
| <div | |
| style="background-color: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 15px; margin: 20px 0;"> | |
| <h4>上传进度:</h4> | |
| <div class="progress-bar" style="height: 20px;"> | |
| <div class="progress-fill" id="progressFill" style="width: 0%"></div> | |
| </div> | |
| <p id="progressText" style="text-align: center; margin: 10px 0;">0%</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Antigravity凭证上传区域 --> | |
| <div style="padding: 15px; border: 2px solid #28a745; border-radius: 8px; background: #f8f9fa;"> | |
| <h4 | |
| style="margin-top: 0; color: #28a745; border-bottom: 2px solid #28a745; padding-bottom: 8px; font-size: 16px;"> | |
| 📤 Antigravity 凭证批量上传</h4> | |
| <div style="border: 2px dashed #28a745; border-radius: 8px; padding: 25px; text-align: center; background-color: #fafafa; margin: 15px 0; cursor: pointer;" | |
| onclick="document.getElementById('antigravityFileInput').click()"> | |
| <p style="color: #28a745; font-size: 16px; font-weight: bold; margin: 8px 0;">📤 批量上传 | |
| Antigravity 凭证文件</p> | |
| <p style="color: #666; font-size: 14px; margin: 4px 0;">支持 .json 和 .zip 格式文件</p> | |
| <p style="color: #888; font-size: 12px; margin: 4px 0;">ZIP文件会自动解压提取其中的JSON凭证</p> | |
| </div> | |
| <input type="file" id="antigravityFileInput" multiple accept=".json,.zip" style="display: none;" | |
| onchange="handleAntigravityFileSelect(event)" /> | |
| <div id="antigravityFileListSection" class="hidden"> | |
| <h4>选择的文件:</h4> | |
| <div id="antigravityFileList"></div> | |
| <div style="display: flex; gap: 10px; margin-top: 15px;"> | |
| <button class="btn" style="flex: 1;" onclick="uploadAntigravityFiles()">上传文件</button> | |
| <button class="btn" style="flex: 1;" onclick="clearAntigravityFiles()">清空列表</button> | |
| </div> | |
| </div> | |
| <div id="antigravityUploadProgressSection" class="hidden"> | |
| <div | |
| style="background-color: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 15px; margin: 20px 0;"> | |
| <h4>上传进度:</h4> | |
| <div class="progress-bar" style="height: 20px;"> | |
| <div class="progress-fill" id="antigravityProgressFill" style="width: 0%"></div> | |
| </div> | |
| <p id="antigravityProgressText" style="text-align: center; margin: 10px 0;">0%</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="manageTab" class="tab-content"> | |
| <h3>凭证文件管理</h3> | |
| <p>管理所有认证文件,查看状态和执行操作</p> | |
| <div | |
| style="background:#f0f7ff;border:1px solid #b8d4f0;border-radius:6px;padding:10px 14px;margin:8px 0;font-size:13px;"> | |
| <strong>📡 API地址(点击复制):</strong> | |
| <table style="margin-top:6px;border-collapse:collapse;width:100%;"> | |
| <tr> | |
| <td style="color:#666;width:90px;">OpenAI格式</td> | |
| <td><code id="mGcliOpenaiUrl" onclick="cpUrl(this)" title="点击复制" | |
| style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> | |
| </td> | |
| </tr> | |
| <tr> | |
| <td style="color:#666;">Claude格式</td> | |
| <td><code id="mGcliClaudeUrl" onclick="cpUrl(this)" title="点击复制" | |
| style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> | |
| </td> | |
| </tr> | |
| <tr> | |
| <td style="color:#666;">Gemini格式</td> | |
| <td><code id="mGcliGeminiUrl" onclick="cpUrl(this)" title="点击复制" | |
| style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> | |
| </td> | |
| </tr> | |
| </table> | |
| <script> | |
| (function () { var mo = window.location.origin; document.getElementById('mGcliOpenaiUrl').textContent = mo + '/v1'; document.getElementById('mGcliClaudeUrl').textContent = mo + '/v1'; document.getElementById('mGcliGeminiUrl').textContent = mo; })(); | |
| function cpUrl(el) { navigator.clipboard.writeText(el.textContent).then(function () { var s = el.style.background; el.style.background = '#b7f0b7'; setTimeout(function () { el.style.background = s; }, 800); }); } | |
| </script> | |
| </div> | |
| <!-- 检验功能说明 --> | |
| <div class="status info" style="margin-bottom: 15px;"> | |
| <strong>💡 检验功能说明:</strong> | |
| <p style="margin: 8px 0; font-size: 14px;"> | |
| 点击每个凭证的"检验"按钮可以重新获取Project ID, 并查看账号的tier(free/pro/ultra)。<br> | |
| <strong style="color: #0c5460;">✅ 检验成功可以恢复403错误</strong>,让凭证重新正常工作。<br> | |
| 建议在遇到403错误时使用此功能。 | |
| </p> | |
| <strong>💡 设置预览功能说明:</strong> | |
| <p style="margin: 8px 0; font-size: 14px;"> | |
| 点击每个凭证的"设置预览"按钮可以配置Preview通道。<br> | |
| <strong style="color: #0c5460;">✅ 设置预览可以解决部分凭证调用preview模型时404的问题</strong>。<br> | |
| 建议在调用gemini-3-pro-preview等模型遇到404错误时使用此功能。 | |
| </p> | |
| </div> | |
| <!-- 状态统计 --> | |
| <div class="stats-container" id="statsContainer"> | |
| <div class="stat-item" style="border-left: 4px solid #007bff;"> | |
| <span class="stat-number" id="statTotal">0</span> | |
| <span class="stat-label">总计</span> | |
| </div> | |
| <div class="stat-item" style="border-left: 4px solid #28a745;"> | |
| <span class="stat-number" id="statNormal">0</span> | |
| <span class="stat-label">正常</span> | |
| </div> | |
| <div class="stat-item" style="border-left: 4px solid #6c757d;"> | |
| <span class="stat-number" id="statDisabled">0</span> | |
| <span class="stat-label">禁用</span> | |
| </div> | |
| </div> | |
| <div style="display: flex; gap: 8px; margin: 15px 0; flex-wrap: wrap;"> | |
| <button class="btn btn-small" onclick="refreshCredsStatus()">刷新状态</button> | |
| <button class="btn btn-small" onclick="downloadAllCreds()">打包下载</button> | |
| </div> | |
| <!-- 批量操作控件 --> | |
| <div class="card" style="margin: 15px 0;"> | |
| <h4 style="margin-top: 0; margin-bottom: 10px; font-size: 16px;">批量操作</h4> | |
| <div style="margin-bottom: 10px;"> | |
| <label style="display: flex; align-items: center; cursor: pointer; font-size: 14px;"> | |
| <input type="checkbox" id="selectAllCheckbox" onchange="toggleSelectAll()" | |
| style="margin-right: 8px; transform: scale(1.2);"> | |
| 全选 | |
| </label> | |
| <span id="selectedCount" style="font-weight: bold; color: #007bff; font-size: 12px;">已选择 0 | |
| 项</span> | |
| </div> | |
| <div class="batch-controls-grid"> | |
| <button class="btn btn-small" id="batchEnableBtn" onclick="batchAction('enable')" | |
| disabled>批量启用</button> | |
| <button class="btn btn-small" id="batchDisableBtn" onclick="batchAction('disable')" | |
| disabled>批量禁用</button> | |
| <button class="btn btn-small btn-danger" id="batchDeleteBtn" onclick="batchAction('delete')" | |
| disabled>批量删除</button> | |
| <button class="btn btn-small" id="batchVerifyBtn" onclick="batchVerifyProjectIds()" | |
| disabled>批量检验</button> | |
| <button class="btn btn-small" id="batchPreviewBtn" onclick="batchConfigurePreview()" | |
| disabled>批量设置预览</button> | |
| <button class="btn btn-small" onclick="refreshAllEmails()">刷新所有邮箱</button> | |
| <button class="btn btn-small" onclick="deduplicateByEmail()">凭证一键去重</button> | |
| </div> | |
| </div> | |
| <!-- 筛选控件 --> | |
| <div | |
| style="background-color: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 12px; margin: 15px 0;"> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="statusFilter">状态筛选:</label> | |
| <select id="statusFilter" onchange="applyStatusFilter()"> | |
| <option value="all">全部凭证</option> | |
| <option value="enabled">仅启用</option> | |
| <option value="disabled">仅禁用</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="errorCodeFilter">错误码筛选:</label> | |
| <select id="errorCodeFilter" onchange="applyStatusFilter()"> | |
| <option value="all">全部</option> | |
| <option value="400">400</option> | |
| <option value="403">403</option> | |
| <option value="429">429</option> | |
| <option value="500">500</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="cooldownFilter">冷却状态:</label> | |
| <select id="cooldownFilter" onchange="applyStatusFilter()"> | |
| <option value="all">全部</option> | |
| <option value="in_cooldown">CD中</option> | |
| <option value="no_cooldown">未CD</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="previewFilter">Preview:</label> | |
| <select id="previewFilter" onchange="applyStatusFilter()"> | |
| <option value="all">全部</option> | |
| <option value="preview">支持</option> | |
| <option value="no_preview">不支持</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="tierFilter">Tier:</label> | |
| <select id="tierFilter" onchange="applyStatusFilter()"> | |
| <option value="all">全部</option> | |
| <option value="free">Free</option> | |
| <option value="pro">Pro</option> | |
| <option value="ultra">Ultra</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 0;"> | |
| <label for="pageSizeSelect">每页显示:</label> | |
| <select id="pageSizeSelect" onchange="changePageSize()"> | |
| <option value="10">10</option> | |
| <option value="20" selected>20</option> | |
| <option value="50">50</option> | |
| <option value="100">100</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div id="credsListSection"> | |
| <div class="loading" id="credsLoading">正在加载凭证文件...</div> | |
| <div id="credsList"></div> | |
| <!-- 分页控件 --> | |
| <div id="paginationContainer" style="display: none; text-align: center; margin: 20px 0;"> | |
| <div | |
| style="display: flex; justify-content: center; align-items: center; gap: 10px; flex-wrap: wrap;"> | |
| <button class="btn btn-small" id="prevPageBtn" onclick="changePage(-1)" | |
| style="background-color: #6c757d;">上一页</button> | |
| <div id="paginationInfo" style="font-size: 14px; color: #666;">第 1 页,共 1 页</div> | |
| <button class="btn btn-small" id="nextPageBtn" onclick="changePage(1)" | |
| style="background-color: #6c757d;">下一页</button> | |
| </div> | |
| <div | |
| style="margin-top: 10px; display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px;"> | |
| <div> | |
| <label for="pageSizeSelect" style="font-size: 12px; margin-right: 5px;">每页显示:</label> | |
| <select id="pageSizeSelect" onchange="changePageSize()" | |
| style="padding: 4px; font-size: 12px;"> | |
| <option value="10">10</option> | |
| <option value="20" selected>20</option> | |
| <option value="50">50</option> | |
| <option value="100">100</option> | |
| </select> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Antigravity凭证管理标签页 --> | |
| <div id="antigravity-manageTab" class="tab-content"> | |
| <h3>Antigravity凭证文件管理</h3> | |
| <p>管理所有Antigravity认证文件,查看状态和执行操作</p> | |
| <div | |
| style="background:#f0f7ff;border:1px solid #b8d4f0;border-radius:6px;padding:10px 14px;margin:8px 0;font-size:13px;"> | |
| <strong>📡 API地址(点击复制):</strong> | |
| <table style="margin-top:6px;border-collapse:collapse;width:100%;"> | |
| <tr> | |
| <td style="color:#666;width:90px;">OpenAI格式</td> | |
| <td><code id="mAntOpenaiUrl" onclick="cpUrl(this)" title="点击复制" | |
| style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> | |
| </td> | |
| </tr> | |
| <tr> | |
| <td style="color:#666;">Claude格式</td> | |
| <td><code id="mAntClaudeUrl" onclick="cpUrl(this)" title="点击复制" | |
| style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> | |
| </td> | |
| </tr> | |
| <tr> | |
| <td style="color:#666;">Gemini格式</td> | |
| <td><code id="mAntGeminiUrl" onclick="cpUrl(this)" title="点击复制" | |
| style="background:#e8f0fe;padding:2px 6px;border-radius:3px;cursor:pointer;"></code> | |
| </td> | |
| </tr> | |
| </table> | |
| <script> | |
| (function () { var mo2 = window.location.origin; document.getElementById('mAntOpenaiUrl').textContent = mo2 + '/antigravity/v1'; document.getElementById('mAntClaudeUrl').textContent = mo2 + '/antigravity/v1'; document.getElementById('mAntGeminiUrl').textContent = mo2 + '/antigravity'; })(); | |
| </script> | |
| </div> | |
| <!-- 检验功能说明 --> | |
| <div class="status info" style="margin-bottom: 15px;"> | |
| <strong>💡 检验功能说明:</strong> | |
| <p style="margin: 8px 0; font-size: 14px;"> | |
| 点击每个凭证的"检验"按钮可以重新获取Project ID, 并查看账号的tier(free/pro/ultra)。<br> | |
| <strong style="color: #0c5460;">✅ 检验成功可以恢复403错误</strong>,让凭证重新正常工作。<br> | |
| 建议在遇到403错误时使用此功能。 | |
| </p> | |
| </div> | |
| <!-- 状态统计 --> | |
| <div class="stats-container" id="antigravityStatsContainer"> | |
| <div class="stat-item" style="border-left: 4px solid #007bff;"> | |
| <span class="stat-number" id="antigravityStatTotal">0</span> | |
| <span class="stat-label">总计</span> | |
| </div> | |
| <div class="stat-item" style="border-left: 4px solid #28a745;"> | |
| <span class="stat-number" id="antigravityStatNormal">0</span> | |
| <span class="stat-label">正常</span> | |
| </div> | |
| <div class="stat-item" style="border-left: 4px solid #6c757d;"> | |
| <span class="stat-number" id="antigravityStatDisabled">0</span> | |
| <span class="stat-label">禁用</span> | |
| </div> | |
| </div> | |
| <div style="display: flex; gap: 8px; margin: 15px 0; flex-wrap: wrap;"> | |
| <button class="btn btn-small" onclick="refreshAntigravityCredsList()" | |
| style="background-color: #17a2b8;">刷新状态</button> | |
| <button class="btn btn-small" onclick="downloadAllAntigravityCreds()" | |
| style="background-color: #28a745;">打包下载</button> | |
| </div> | |
| <!-- 批量操作控件 --> | |
| <div class="card" style="margin: 15px 0;"> | |
| <h4 style="margin-top: 0; margin-bottom: 10px; font-size: 16px;">批量操作</h4> | |
| <div style="margin-bottom: 10px;"> | |
| <label style="display: flex; align-items: center; cursor: pointer; font-size: 14px;"> | |
| <input type="checkbox" id="selectAllAntigravityCheckbox" | |
| onchange="toggleSelectAllAntigravity()" | |
| style="margin-right: 8px; transform: scale(1.2);"> | |
| 全选 | |
| </label> | |
| <span id="antigravitySelectedCount" | |
| style="font-weight: bold; color: #007bff; font-size: 12px;">已选择 0 | |
| 项</span> | |
| </div> | |
| <div class="batch-controls-grid"> | |
| <button class="btn btn-small" id="antigravityBatchEnableBtn" | |
| onclick="batchAntigravityAction('enable')" disabled>批量启用</button> | |
| <button class="btn btn-small" id="antigravityBatchDisableBtn" | |
| onclick="batchAntigravityAction('disable')" disabled>批量禁用</button> | |
| <button class="btn btn-small btn-danger" id="antigravityBatchDeleteBtn" | |
| onclick="batchAntigravityAction('delete')" disabled>批量删除</button> | |
| <button class="btn btn-small" id="antigravityBatchEnableCreditBtn" | |
| onclick="batchAntigravityAction('enable_credit')" disabled>批量开启积分</button> | |
| <button class="btn btn-small" id="antigravityBatchDisableCreditBtn" | |
| onclick="batchAntigravityAction('disable_credit')" disabled>批量关闭积分</button> | |
| <button class="btn btn-small" id="antigravityBatchVerifyBtn" | |
| onclick="batchVerifyAntigravityProjectIds()" disabled>批量检验</button> | |
| <button class="btn btn-small" onclick="refreshAllAntigravityEmails()">刷新所有邮箱</button> | |
| <button class="btn btn-small" onclick="deduplicateAntigravityByEmail()">凭证一键去重</button> | |
| </div> | |
| </div> | |
| <!-- 筛选控件 --> | |
| <div | |
| style="background-color: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 12px; margin: 15px 0;"> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="antigravityStatusFilter">状态筛选:</label> | |
| <select id="antigravityStatusFilter" onchange="applyAntigravityStatusFilter()"> | |
| <option value="all">全部凭证</option> | |
| <option value="enabled">仅启用</option> | |
| <option value="disabled">仅禁用</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="antigravityErrorCodeFilter">错误码筛选:</label> | |
| <select id="antigravityErrorCodeFilter" onchange="applyAntigravityStatusFilter()"> | |
| <option value="all">全部</option> | |
| <option value="400">400</option> | |
| <option value="403">403</option> | |
| <option value="429">429</option> | |
| <option value="500">500</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="antigravityCooldownFilter">冷却状态:</label> | |
| <select id="antigravityCooldownFilter" onchange="applyAntigravityStatusFilter()"> | |
| <option value="all">全部</option> | |
| <option value="in_cooldown">CD中</option> | |
| <option value="no_cooldown">未CD</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="antigravityTierFilter">Tier:</label> | |
| <select id="antigravityTierFilter" onchange="applyAntigravityStatusFilter()"> | |
| <option value="all">全部</option> | |
| <option value="free">Free</option> | |
| <option value="pro">Pro</option> | |
| <option value="ultra">Ultra</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 0;"> | |
| <label for="antigravityPageSizeSelect">每页显示:</label> | |
| <select id="antigravityPageSizeSelect" onchange="changeAntigravityPageSize()"> | |
| <option value="10">10</option> | |
| <option value="20" selected>20</option> | |
| <option value="50">50</option> | |
| <option value="100">100</option> | |
| </select> | |
| </div> | |
| </div> | |
| <div id="antigravityCredsListSection"> | |
| <div class="loading" id="antigravityCredsLoading">正在加载凭证文件...</div> | |
| <div id="antigravityCredsList"></div> | |
| <!-- 分页控件 --> | |
| <div id="antigravityPaginationContainer" style="display: none; text-align: center; margin: 20px 0;"> | |
| <div | |
| style="display: flex; justify-content: center; align-items: center; gap: 10px; flex-wrap: wrap;"> | |
| <button class="btn btn-small" id="antigravityPrevPageBtn" | |
| onclick="changeAntigravityPage(-1)" style="background-color: #6c757d;">上一页</button> | |
| <div id="antigravityPaginationInfo" style="font-size: 14px; color: #666;">第 1 页,共 1 页</div> | |
| <button class="btn btn-small" id="antigravityNextPageBtn" onclick="changeAntigravityPage(1)" | |
| style="background-color: #6c757d;">下一页</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="configTab" class="tab-content"> | |
| <h3>配置管理</h3> | |
| <p>管理系统配置参数,修改后立即生效</p> | |
| <div style="display: flex; gap: 8px; margin: 15px 0; flex-wrap: wrap;"> | |
| <button class="btn btn-small" onclick="loadConfig()" | |
| style="background-color: #17a2b8;">刷新配置</button> | |
| <button class="btn btn-small" onclick="saveConfig()">保存配置</button> | |
| </div> | |
| <div id="configSection"> | |
| <div class="loading" id="configLoading">正在加载配置...</div> | |
| <div id="configForm" class="hidden"> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; margin-bottom: 15px;">服务器配置</h4> | |
| <div class="form-group"> | |
| <label for="host">服务器主机地址:</label> | |
| <input type="text" id="host" placeholder="例如: 0.0.0.0, 127.0.0.1" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">服务器监听的主机地址,0.0.0.0表示监听所有接口</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="port">服务器端口:</label> | |
| <input type="number" id="port" min="1" max="65535" placeholder="7861" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">服务器监听的端口号,修改后需要重启服务器</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="configApiPassword">API访问密码:</label> | |
| <input type="text" id="configApiPassword" placeholder="pwd" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">聊天API访问密码,用于OpenAI和Gemini | |
| API端点的认证</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="configPanelPassword">控制面板密码:</label> | |
| <input type="text" id="configPanelPassword" placeholder="pwd" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">控制面板访问密码,用于web界面登录认证</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="configPassword">通用密码:</label> | |
| <input type="text" id="configPassword" placeholder="pwd" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">(兼容性保留)设置后将覆盖上述两个密码,留空则使用分开的密码设置</small> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; margin-bottom: 15px;">基础配置</h4> | |
| <div class="form-group"> | |
| <label for="credentialsDir">凭证目录路径:</label> | |
| <input type="text" id="credentialsDir" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">存储认证文件的目录路径</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="proxy">代理设置:</label> | |
| <input type="text" id="proxy" | |
| placeholder="例如: http://proxy:11451 或 socks5://proxy:1080" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">HTTP/HTTPS/SOCKS5Endpoint,留空表示不使用代理</small> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; margin-bottom: 15px;">端点配置</h4> | |
| <!-- 快速配置按钮 --> | |
| <div class="form-group"> | |
| <div style="display: flex; gap: 8px; margin-bottom: 15px; flex-wrap: wrap;"> | |
| <button type="button" class="btn" onclick="useMirrorUrls()" | |
| style="font-size: 13px; flex: 1; min-width: 120px;"> | |
| 🚀 镜像网址 | |
| </button> | |
| <button type="button" class="btn" onclick="restoreOfficialUrls()" | |
| style="font-size: 13px; flex: 1; min-width: 120px;"> | |
| 🔄 官方端点 | |
| </button> | |
| </div> | |
| <small | |
| style="display: block; color: #666; font-size: 11px; margin-bottom: 10px;">镜像网址主要解决墙内无法访问官方端点的问题,部分地区可能无法使用</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="codeAssistEndpoint">Code Assist Endpoint:</label> | |
| <input type="text" id="codeAssistEndpoint" /> | |
| <small style="display: block; color: #666; font-size: 12px; margin-top: 5px;">Google | |
| Cloud Code Assist API端点地址</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="oauthProxyUrl">OAuth Endpoint:</label> | |
| <input type="text" id="oauthProxyUrl" placeholder="https://oauth2.googleapis.com" /> | |
| <small style="display: block; color: #666; font-size: 12px; margin-top: 5px;">Google | |
| OAuth2 API端点地址,用于token获取和刷新</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="googleapisProxyUrl">Google APIs Endpoint:</label> | |
| <input type="text" id="googleapisProxyUrl" placeholder="https://www.googleapis.com" /> | |
| <small style="display: block; color: #666; font-size: 12px; margin-top: 5px;">Google | |
| APIs API端点地址,用于API服务调用</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="resourceManagerApiUrl">Resource Manager API Endpoint:</label> | |
| <input type="text" id="resourceManagerApiUrl" | |
| placeholder="https://cloudresourcemanager.googleapis.com" /> | |
| <small style="display: block; color: #666; font-size: 12px; margin-top: 5px;">Google | |
| Cloud Resource Manager API端点地址,用于项目管理</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="serviceUsageApiUrl">Service Usage API Endpoint:</label> | |
| <input type="text" id="serviceUsageApiUrl" | |
| placeholder="https://serviceusage.googleapis.com" /> | |
| <small style="display: block; color: #666; font-size: 12px; margin-top: 5px;">Google | |
| Cloud Service Usage API端点地址,用于服务启用管理</small> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; margin-bottom: 15px;">自动封禁配置</h4> | |
| <div class="form-group"> | |
| <label style="display: flex; align-items: center; cursor: pointer;"> | |
| <input type="checkbox" id="autoBanEnabled" style="margin-right: 8px;" /> | |
| 启用自动封禁 | |
| </label> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">遇到指定错误码时自动禁用凭证</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="autoBanErrorCodes">自动封禁错误码:</label> | |
| <input type="text" id="autoBanErrorCodes" placeholder="例如: 400,403" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">用逗号分隔的错误码列表</small> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; margin-bottom: 15px;">错误重试配置</h4> | |
| <div class="form-group"> | |
| <label style="display: flex; align-items: center; cursor: pointer;"> | |
| <input type="checkbox" id="retry429Enabled" style="margin-right: 8px;" /> | |
| 启用错误重试 | |
| </label> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">遇到错误时自动重试</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="retry429MaxRetries">错误重试次数:</label> | |
| <input type="number" id="retry429MaxRetries" min="1" max="50" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">遇到错误时的最大重试次数</small> | |
| </div> | |
| <div class="form-group"> | |
| <label for="retry429Interval">错误重试间隔(秒):</label> | |
| <input type="number" id="retry429Interval" min="0.01" max="10" step="0.01" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">遇到错误时每两次重试间的等待时间</small> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; margin-bottom: 15px;">兼容性配置</h4> | |
| <div class="form-group"> | |
| <label style="display: flex; align-items: center; gap: 8px;"> | |
| <input type="checkbox" id="compatibilityModeEnabled" | |
| style="width: auto; margin: 0;" /> | |
| 启用兼容性模式 | |
| </label> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">启用后所有system消息全部转换成user,停用system_instructions | |
| <span style="color: #28a745;">✓ 支持热更新</span></small> | |
| <div | |
| style="background-color: #fff3cd; border: 1px solid #ffc107; border-radius: 6px; padding: 12px; margin-top: 8px; font-size: 13px; color: #856404;"> | |
| <strong>⚠️ 注意:</strong>该选项可能会降低模型理解能力,但是能避免流式空回的情况。 | |
| <br><strong>适用场景:</strong>当遇到流式传输时模型不返回内容或返回空响应时启用此选项。 | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label style="display: flex; align-items: center; gap: 8px;"> | |
| <input type="checkbox" id="returnThoughtsToFrontend" | |
| style="width: auto; margin: 0;" /> | |
| 返回思维链到前端 | |
| </label> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">启用后,模型的思维链会在响应中返回;禁用后,思维链会被过滤掉 | |
| <span style="color: #28a745;">✓ 支持热更新</span></small> | |
| <div | |
| style="background-color: #e3f2fd; border: 1px solid #2196f3; border-radius: 6px; padding: 12px; margin-top: 8px; font-size: 13px; color: #0d47a1;"> | |
| <strong>💭 说明:</strong>某些模型(如Gemini 2.0 | |
| Pro)支持thinking模式,会在生成回答前先输出思考过程。启用后可以看到模型的思考过程;禁用后只显示最终回答,让输出更简洁。 | |
| </div> | |
| </div> | |
| <div class="form-group"> | |
| <label style="display: flex; align-items: center; gap: 8px;"> | |
| <input type="checkbox" id="antigravityStream2nostream" | |
| style="width: auto; margin: 0;" /> | |
| Antigravity流式转非流式 | |
| </label> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">启用后,非流式请求将使用流式API并收集为完整响应 | |
| <span style="color: #28a745;">✓ 支持热更新</span></small> | |
| <div | |
| style="background-color: #f3e5f5; border: 1px solid #9c27b0; border-radius: 6px; padding: 12px; margin-top: 8px; font-size: 13px; color: #4a148c;"> | |
| <strong>🔄 | |
| 说明:</strong>针对Antigravity模式的优化选项。启用后,即使客户端请求非流式响应,后端也会使用流式API获取数据并收集完整后再返回。 | |
| <br><strong>适用场景:</strong>某些情况下流式API比非流式API更稳定,启用此选项可以提高响应质量。 | |
| <br><strong>默认:</strong>已启用 | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; margin-bottom: 15px;">抗截断配置</h4> | |
| <div class="form-group"> | |
| <label for="antiTruncationMaxAttempts">抗截断最大重试次数:</label> | |
| <input type="number" id="antiTruncationMaxAttempts" min="1" max="10" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">当检测到输出截断时的最大续传尝试次数</small> | |
| </div> | |
| <div | |
| style="background-color: #e3f2fd; border: 1px solid #1976d2; border-radius: 6px; padding: 12px; margin-top: 8px; font-size: 13px; color: #1565c0;"> | |
| <strong>注意:</strong>抗截断功能现在通过模型名控制: | |
| <ul style="margin: 5px 0; padding-left: 20px; color: #424242;"> | |
| <li>选择带有 "-流式抗截断" 后缀的模型即可启用</li> | |
| <li>该功能仅在流式传输时生效</li> | |
| <li>例如: "gemini-2.5-pro-流式抗截断"</li> | |
| </ul> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; margin-bottom: 15px;">保活配置</h4> | |
| <div class="form-group"> | |
| <label for="keepaliveUrl">保活 URL:</label> | |
| <input type="text" id="keepaliveUrl" | |
| placeholder="留空则不启用,例如: https://your-app.example.com/keepalive" /> | |
| <small style="display: block; color: #666; font-size: 12px; margin-top: 5px;">配置后服务会定期向该 | |
| URL 发送 GET 请求以保持在线;留空则禁用保活 ✓ 支持热更新</small> | |
| <button type="button" onclick="autoSetKeepaliveUrl()" | |
| style="margin-top:6px; padding:4px 12px; font-size:13px; cursor:pointer;">一键设置保活</button> | |
| </div> | |
| <div class="form-group"> | |
| <label for="keepaliveInterval">保活间隔 (秒):</label> | |
| <input type="number" id="keepaliveInterval" min="5" max="86400" /> | |
| <small | |
| style="display: block; color: #666; font-size: 12px; margin-top: 5px;">两次保活请求之间的等待时间,范围 | |
| 5 - 86400 秒,默认 60 ✓ 支持热更新</small> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; margin-bottom: 15px;">配置热更新说明</h4> | |
| <div | |
| style="background-color: #d4edda; border: 1px solid #c3e6cb; border-radius: 6px; padding: 12px; font-size: 13px; color: #155724; margin-bottom: 10px;"> | |
| <strong>🔥 热更新配置(立即生效):</strong> | |
| <ul style="margin: 8px 0; padding-left: 20px; color: #212529;"> | |
| <li><strong>网络配置:</strong>代理、端点配置、超时、连接数</li> | |
| <li><strong>API配置:</strong>轮换次数、重试设置、自动封禁</li> | |
| <li><strong>密码配置:</strong>API密码、面板密码</li> | |
| <li><strong>功能配置:</strong>抗截断重试次数</li> | |
| </ul> | |
| </div> | |
| <div | |
| style="background-color: #fff3cd; border: 1px solid #ffc107; border-radius: 6px; padding: 12px; font-size: 13px; color: #856404; margin-bottom: 10px;"> | |
| <strong>🔄 需要重启的配置:</strong> | |
| <ul style="margin: 8px 0; padding-left: 20px; color: #212529;"> | |
| <li><strong>服务器配置:</strong>主机地址、端口号</li> | |
| <li><strong>文件路径:</strong>凭证目录</li> | |
| </ul> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="logsTab" class="tab-content"> | |
| <h3>实时日志</h3> | |
| <p>查看系统实时日志输出,支持日志筛选和自动滚动</p> | |
| <div style="display: flex; gap: 8px; margin: 15px 0; flex-wrap: wrap;"> | |
| <button class="btn btn-small" onclick="connectWebSocket()">连接日志流</button> | |
| <button class="btn btn-small" onclick="disconnectWebSocket()">断开连接</button> | |
| <button class="btn btn-small" onclick="downloadLogs()">下载日志</button> | |
| <button class="btn btn-small" onclick="clearLogs()">清空日志</button> | |
| </div> | |
| <div | |
| style="background-color: #f8f9fa; border: 1px solid #e1e4e8; border-radius: 8px; padding: 12px; margin: 15px 0;"> | |
| <div class="form-group" style="margin-bottom: 8px;"> | |
| <label for="logLevelFilter">日志级别筛选:</label> | |
| <select id="logLevelFilter" onchange="filterLogs()"> | |
| <option value="all">全部</option> | |
| <option value="ERROR">错误</option> | |
| <option value="WARNING">警告</option> | |
| <option value="INFO">信息</option> | |
| <option value="DEBUG">调试</option> | |
| </select> | |
| </div> | |
| <div class="form-group" style="margin-bottom: 0;"> | |
| <label style="display: flex; align-items: center; cursor: pointer;"> | |
| <input type="checkbox" id="autoScroll" checked style="margin-right: 8px;" /> | |
| 自动滚动到底部 | |
| </label> | |
| </div> | |
| </div> | |
| <div id="logConnectionStatus" class="status info"> | |
| <strong>连接状态:</strong> <span id="connectionStatusText">未连接</span> | |
| </div> | |
| <div id="logContainer" | |
| style="background-color: #1e1e1e; color: #ffffff; font-family: 'Courier New', monospace; font-size: 12px; height: 600px; overflow-y: auto; border: 1px solid #333; border-radius: 5px; padding: 15px; white-space: pre-wrap; word-break: break-all;"> | |
| <div id="logContent">等待连接日志流...</div> | |
| </div> | |
| </div> | |
| <!-- 项目信息标签页 --> | |
| <div id="aboutTab" class="tab-content"> | |
| <h3>项目信息</h3> | |
| <p>关于GCLI2API项目的详细信息</p> | |
| <!-- 项目介绍 --> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; color: #007bff;">📋 项目简介</h4> | |
| <p style="margin: 10px 0; line-height: 1.6; color: #495057; font-size: 14px;"> | |
| GCLI2API是一个将Google Gemini API转换为OpenAI 和GEMINI API格式的代理工具,支持多账户管理、自动轮换、实时日志监控等功能。 | |
| </p> | |
| <div style="margin: 15px 0; font-size: 14px;"> | |
| <p style="margin: 5px 0;"><strong>🔗 项目地址:</strong> <a | |
| href="https://github.com/su-kaka/gcli2api" target="_blank" | |
| style="color: #007bff; text-decoration: none;">GitHub - su-kaka/gcli2api</a></p> | |
| <p style="margin: 5px 0;"><strong>⚠️ 使用声明:</strong> <span | |
| style="color: #dc3545; font-weight: 500;">禁止商业用途和倒卖 - 仅供学习使用</span></p> | |
| </div> | |
| </div> | |
| <!-- 功能特性 --> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; color: #17a2b8;">✨ 主要功能</h4> | |
| <div style="font-size: 14px; line-height: 1.6;"> | |
| <p><strong>🔄 多账户管理:</strong> 支持批量上传和管理多个Google账户</p> | |
| <p><strong>⚡ 自动轮换:</strong> 智能轮换账户,避免单账户限额</p> | |
| <p><strong>📊 实时监控:</strong> 使用统计、错误监控、实时日志</p> | |
| <p><strong>🛡️ 安全可靠:</strong> OAuth2认证、自动封禁异常账户</p> | |
| <p><strong>🎛️ 配置灵活:</strong> 支持热更新配置、代理设置</p> | |
| <p><strong>📱 界面友好:</strong> 响应式设计、移动端适配</p> | |
| </div> | |
| </div> | |
| <!-- 交流群 --> | |
| <div class="card" style="border-left: 4px solid #4285f4; text-align: center;"> | |
| <h4 style="margin-top: 0; color: #1976d2;">💬 交流群</h4> | |
| <div style="color: #1565c0; line-height: 1.6; font-size: 14px;"> | |
| <p>欢迎加入 QQ 群交流讨论!</p> | |
| <p style="font-size: 16px; font-weight: bold; color: #4285f4;">QQ 群号:1083250744</p> | |
| </div> | |
| <div | |
| style="display: inline-block; background: white; padding: 12px; border-radius: 10px; box-shadow: 0 2px 15px rgba(0,0,0,0.1); margin-top: 10px;"> | |
| <img src="docs/qq群.jpg" alt="QQ群二维码" | |
| style="width: 180px; height: 180px; border-radius: 6px; display: block;"> | |
| <p | |
| style="color: #666; margin: 8px 0 0 0; font-size: 12px; font-weight: 600; text-align: center;"> | |
| 扫码加入QQ群</p> | |
| </div> | |
| </div> | |
| <!-- 联系和反馈 --> | |
| <div class="card"> | |
| <h4 style="margin-top: 0; color: #0c5460;">📞 联系我们</h4> | |
| <div style="color: #0c5460; line-height: 1.6; font-size: 14px;"> | |
| <p>• <strong>问题反馈:</strong> 通过GitHub Issues提交问题和建议</p> | |
| <p>• <strong>功能请求:</strong> 在GitHub Discussions中讨论新功能</p> | |
| <p>• <strong>代码贡献:</strong> 欢迎提交Pull Request改进项目</p> | |
| <p>• <strong>文档完善:</strong> 帮助改进项目文档和使用指南</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div id="statusSection"></div> | |
| <!-- 项目信息 --> | |
| <div | |
| style="background-color: #f8f9fa; border: 1px solid #dee2e6; border-radius: 6px; padding: 10px; margin-top: 20px; text-align: center; border-left: 4px solid #007bff;"> | |
| <p style="margin: 4px 0; font-size: 12px; color: #495057;">GitHub: <a | |
| href="https://github.com/su-kaka/gcli2api" target="_blank" | |
| style="color: #007bff; text-decoration: none;">github.com/su-kaka/gcli2api</a></p> | |
| <p style="margin: 4px 0; font-size: 12px; color: #dc3545; font-weight: 500;">⚠️ 禁止商业用途和倒卖 - 仅供学习使用 ⚠️ | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- 引入公共JavaScript模块 --> | |
| <script src="./front/common.js"></script> | |
| </body> | |
| </html> |