mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-03 03:10:50 +08:00
Compare commits
16 Commits
v0.1.0
...
v0.1.4-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86d60aad77 | ||
|
|
020fccc032 | ||
|
|
c162ab3a54 | ||
|
|
85d12e15d8 | ||
|
|
ebffb49f52 | ||
|
|
316c1ffc0d | ||
|
|
b3e54e7f14 | ||
|
|
fe11bfb48f | ||
|
|
ee0d8f82d7 | ||
|
|
0bbb397df5 | ||
|
|
27948b3d5c | ||
|
|
dff28db227 | ||
|
|
34b16ca886 | ||
|
|
fa86f76289 | ||
|
|
41ca99978f | ||
|
|
6ef674487f |
98
README.md
98
README.md
@@ -10,9 +10,9 @@ Example URL:
|
||||
https://remote.router-for.me/
|
||||
|
||||
Minimum required version: ≥ 6.0.0
|
||||
Recommended version: ≥ 6.0.19
|
||||
Recommended version: ≥ 6.1.3
|
||||
|
||||
Starting from version 6.0.19, the WebUI has been integrated into the main program and is accessible via `/management.html`.
|
||||
Since version 6.0.19, the WebUI has been rolled into the main program. You can access it by going to `/management.html` on the external port after firing up the main project.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -20,13 +20,16 @@ Starting from version 6.0.19, the WebUI has been integrated into the main progra
|
||||
- Supports management key authentication
|
||||
- Configurable API base address
|
||||
- Real-time connection status detection
|
||||
- Auto-login with saved credentials
|
||||
- Language and theme switching
|
||||
|
||||
### Basic Settings
|
||||
- **Debug Mode**: Enable/disable debugging
|
||||
- **Proxy Settings**: Configure proxy server URL
|
||||
- **Request Retries**: Set the number of request retries
|
||||
- **Quota Management**: Configure behavior when the quota is exceeded
|
||||
- **Local Access**: Manage local unauthenticated access
|
||||
- Auto-switch project when quota exceeded
|
||||
- Switch to preview models when quota exceeded
|
||||
|
||||
### API Key Management
|
||||
- **Proxy Service Authentication Key**: Manage API keys for the proxy service
|
||||
@@ -41,13 +44,31 @@ Starting from version 6.0.19, the WebUI has been integrated into the main progra
|
||||
- Delete single or all authentication files
|
||||
- Display file details
|
||||
|
||||
### Usage Statistics
|
||||
- **Real-time Analytics**: Track API usage with interactive charts
|
||||
- **Request Trends**: Visualize request patterns by hour/day
|
||||
- **Token Usage**: Monitor token consumption over time
|
||||
- **API Details**: Detailed statistics for each API endpoint
|
||||
- **Success/Failure Rates**: Track API reliability metrics
|
||||
|
||||
### System Information
|
||||
- **Connection Status**: Real-time connection monitoring
|
||||
- **Configuration Status**: Track configuration loading state
|
||||
- **Server Information**: Display server address and management key
|
||||
- **Last Update**: Show when data was last refreshed
|
||||
|
||||
|
||||
## How to Use
|
||||
|
||||
### 1. Direct Use (Recommended)
|
||||
### 1. Using After CLI Proxy API Program Launch (Recommended)
|
||||
Once the CLI Proxy API program is up and running, you can access the WebUI at `http://your-server-IP:8317/management.html`.
|
||||
|
||||
### 2. Direct Use
|
||||
Simply open the `index.html` file directly in your browser to use it.
|
||||
|
||||
### 2. Use a Local Server
|
||||
### 3. Use a Local Server
|
||||
|
||||
#### Option A: Using Node.js (npm)
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
@@ -56,10 +77,19 @@ npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
### 3. Configure API Connection
|
||||
#### Option B: Using Python
|
||||
```bash
|
||||
# Python 3.x
|
||||
python -m http.server 8000
|
||||
|
||||
```
|
||||
|
||||
Then open `http://localhost:8000` in your browser.
|
||||
|
||||
### 3. Configure Connection
|
||||
1. Open the management interface.
|
||||
2. On the login screen, enter:
|
||||
- **Remote Address**: `http://localhost:8317` (`/v0/management` will be auto-completed for you)
|
||||
- **Remote Address**: The current version automatically picks up the remote address from where you're connecting. But you can also set your own address if you prefer.
|
||||
- **Management Key**: Your management key
|
||||
3. Click the "Connect" button.
|
||||
4. Once connected successfully, all features will be available.
|
||||
@@ -71,8 +101,16 @@ npm start
|
||||
- **API Keys**: Management of keys for various API services.
|
||||
- **AI Providers**: Configuration for AI service providers.
|
||||
- **Auth Files**: Upload and download management for authentication files.
|
||||
- **Usage Stats**: Real-time analytics and usage statistics with interactive charts.
|
||||
- **System Info**: Connection status and system information.
|
||||
|
||||
### Login Interface
|
||||
- **Auto-connection**: Automatically attempts to connect using saved credentials
|
||||
- **Custom Connection**: Manual configuration of API base address
|
||||
- **Current Address Detection**: Automatically detects and uses current access address
|
||||
- **Language Switching**: Support for multiple languages (English/Chinese)
|
||||
- **Theme Switching**: Light and dark theme support
|
||||
|
||||
## Feature Highlights
|
||||
|
||||
### Modern UI
|
||||
@@ -80,27 +118,45 @@ npm start
|
||||
- Beautiful gradient colors and shadow effects
|
||||
- Smooth animations and transition effects
|
||||
- Intuitive icons and status indicators
|
||||
- Dark/Light theme support with system preference detection
|
||||
- Mobile-friendly sidebar with overlay
|
||||
|
||||
### Real-time Updates
|
||||
- Configuration changes take effect immediately
|
||||
- Real-time status feedback
|
||||
- Automatic data refresh
|
||||
- Live usage statistics with interactive charts
|
||||
- Real-time connection status monitoring
|
||||
|
||||
### Security Features
|
||||
- Masked display for keys
|
||||
- Secure credential storage
|
||||
- Auto-login with encrypted local storage
|
||||
|
||||
### Responsive Design
|
||||
- Perfectly adapts to desktop and mobile devices
|
||||
- Adaptive layout
|
||||
- Adaptive layout with collapsible sidebar
|
||||
- Touch-friendly interactions
|
||||
- Mobile menu with overlay
|
||||
|
||||
### Analytics & Monitoring
|
||||
- Interactive charts powered by Chart.js
|
||||
- Real-time usage statistics
|
||||
- Request trend visualization
|
||||
- Token consumption tracking
|
||||
- API performance metrics
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Frontend**: Plain HTML, CSS, JavaScript
|
||||
- **Styling**: CSS3 + Flexbox/Grid
|
||||
- **Frontend**: Plain HTML, CSS, JavaScript (ES6+)
|
||||
- **Styling**: CSS3 + Flexbox/Grid with CSS Variables
|
||||
- **Icons**: Font Awesome 6.4.0
|
||||
- **Charts**: Chart.js for interactive data visualization
|
||||
- **Fonts**: Segoe UI system font
|
||||
- **API**: RESTful API calls
|
||||
- **API**: RESTful API calls with automatic authentication
|
||||
- **Internationalization**: Custom i18n system with English/Chinese support
|
||||
- **Theme System**: CSS custom properties for dynamic theming
|
||||
- **Storage**: LocalStorage for user preferences and credentials
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@@ -120,12 +176,20 @@ npm start
|
||||
### File Structure
|
||||
```
|
||||
webui/
|
||||
├── index.html # Main page
|
||||
├── styles.css # Stylesheet
|
||||
├── app.js # Application logic
|
||||
├── package.json # Project configuration
|
||||
├── i18n.js # Internationalization support
|
||||
└── README.md # README document
|
||||
├── index.html # Main page with responsive layout
|
||||
├── styles.css # Stylesheet with theme support
|
||||
├── app.js # Application logic and API management
|
||||
├── i18n.js # Internationalization support (EN/CN)
|
||||
├── package.json # Project configuration
|
||||
├── build.js # Build script for production
|
||||
├── bundle-entry.js # Entry point for bundling
|
||||
├── build-scripts/ # Build utilities
|
||||
│ └── prepare-html.js # HTML preparation script
|
||||
├── logo.jpg # Application logo
|
||||
├── LICENSE # MIT License
|
||||
├── README.md # English documentation
|
||||
├── README_CN.md # Chinese documentation
|
||||
└── BUILD_RELEASE.md # Build and release notes
|
||||
```
|
||||
|
||||
### API Calls
|
||||
|
||||
103
README_CN.md
103
README_CN.md
@@ -1,14 +1,17 @@
|
||||
# Cli-Proxy-API-Management-Center
|
||||
这是一个用于管理 CLI Proxy API 的现代化 Web 界面。
|
||||
|
||||
主项目
|
||||
https://github.com/router-for-me/CLIProxyAPI
|
||||
|
||||
示例网站:
|
||||
https://remote.router-for.me/
|
||||
|
||||
最低可用版本 ≥ 5.0.0
|
||||
推荐版本 ≥ 5.2.6
|
||||
自6.0.19起WebUI已经集成在主程序中 可以通过/management.html访问
|
||||
最低可用版本 ≥ 6.0.0
|
||||
|
||||
推荐版本 ≥ 6.1.3
|
||||
|
||||
自6.0.19起WebUI已经集成在主程序中 可以通过主项目开启的外部端口的`/management.html`访问
|
||||
|
||||
## 功能特点
|
||||
|
||||
@@ -16,13 +19,16 @@ https://remote.router-for.me/
|
||||
- 支持管理密钥认证
|
||||
- 可配置 API 基础地址
|
||||
- 实时连接状态检测
|
||||
- 自动登录保存的凭据
|
||||
- 语言和主题切换
|
||||
|
||||
### 基础设置
|
||||
- **调试模式**: 开启/关闭调试功能
|
||||
- **代理设置**: 配置代理服务器 URL
|
||||
- **请求重试**: 设置请求重试次数
|
||||
- **配额管理**: 配置超出配额时的行为
|
||||
- **本地访问**: 管理本地未认证访问
|
||||
- 超出配额时自动切换项目
|
||||
- 超出配额时切换到预览模型
|
||||
|
||||
### API 密钥管理
|
||||
- **代理服务认证密钥**: 管理用于代理服务的 API 密钥
|
||||
@@ -37,13 +43,31 @@ https://remote.router-for.me/
|
||||
- 删除单个或所有认证文件
|
||||
- 显示文件详细信息
|
||||
|
||||
### 使用统计
|
||||
- **实时分析**: 通过交互式图表跟踪 API 使用情况
|
||||
- **请求趋势**: 按小时/天可视化请求模式
|
||||
- **Token 使用**: 监控 Token 消耗随时间变化
|
||||
- **API 详情**: 每个 API 端点的详细统计
|
||||
- **成功率/失败率**: 跟踪 API 可靠性指标
|
||||
|
||||
### 系统信息
|
||||
- **连接状态**: 实时连接监控
|
||||
- **配置状态**: 跟踪配置加载状态
|
||||
- **服务器信息**: 显示服务器地址和管理密钥
|
||||
- **最后更新**: 显示数据最后刷新时间
|
||||
|
||||
|
||||
## 使用方法
|
||||
|
||||
### 1. 直接使用(推荐)
|
||||
### 1. 在CLI Proxy API程序启动后使用 (推荐)
|
||||
在启动了CLI Proxy API程序后 访问`http://您的服务器IP:8317/management.html`使用
|
||||
|
||||
### 2. 直接使用
|
||||
直接用浏览器打开 `index.html` 文件即可使用。
|
||||
|
||||
### 2. 使用本地服务器
|
||||
### 3. 使用本地服务器
|
||||
|
||||
#### 方法A:使用 Node.js (npm)
|
||||
```bash
|
||||
# 安装依赖
|
||||
npm install
|
||||
@@ -52,10 +76,19 @@ npm install
|
||||
npm start
|
||||
```
|
||||
|
||||
### 3. 配置 API 连接
|
||||
#### 方法B:使用 Python
|
||||
```bash
|
||||
# Python 3.x
|
||||
python -m http.server 8000
|
||||
|
||||
```
|
||||
|
||||
然后在浏览器中打开 `http://localhost:8000`。
|
||||
|
||||
### 3. 配置连接
|
||||
1. 打开管理界面
|
||||
2. 在登录界面上输入:
|
||||
- **远程地址**: `http://localhost:8317`/v0/management将会自动为您补全
|
||||
- **远程地址**: 现版本远程地址将会自动从您的访问地址中获取 当然您也可以自定义
|
||||
- **管理密钥**: 您的管理密钥
|
||||
3. 点击"连接"按钮
|
||||
4. 连接成功后即可使用所有功能
|
||||
@@ -67,8 +100,16 @@ npm start
|
||||
- **API 密钥**: 各种 API 服务的密钥管理
|
||||
- **AI 提供商**: AI 服务提供商配置
|
||||
- **认证文件**: 认证文件的上传下载管理
|
||||
- **使用统计**: 实时分析和使用统计,包含交互式图表
|
||||
- **系统信息**: 连接状态和系统信息
|
||||
|
||||
### 登录界面
|
||||
- **自动连接**: 使用保存的凭据自动尝试连接
|
||||
- **自定义连接**: 手动配置 API 基础地址
|
||||
- **当前地址检测**: 自动检测并使用当前访问地址
|
||||
- **语言切换**: 支持多种语言(英文/中文)
|
||||
- **主题切换**: 支持明暗主题
|
||||
|
||||
## 特性亮点
|
||||
|
||||
### 现代化 UI
|
||||
@@ -76,27 +117,45 @@ npm start
|
||||
- 美观的渐变色彩和阴影效果
|
||||
- 流畅的动画和过渡效果
|
||||
- 直观的图标和状态指示
|
||||
- 明暗主题支持,自动检测系统偏好
|
||||
- 移动端友好的侧边栏和遮罩
|
||||
|
||||
### 实时更新
|
||||
- 配置更改立即生效
|
||||
- 实时状态反馈
|
||||
- 自动数据刷新
|
||||
- 实时使用统计和交互式图表
|
||||
- 实时连接状态监控
|
||||
|
||||
### 安全特性
|
||||
- 密钥遮蔽显示
|
||||
- 安全凭据存储
|
||||
- 加密本地存储自动登录
|
||||
|
||||
### 响应式设计
|
||||
- 完美适配桌面和移动设备
|
||||
- 自适应布局
|
||||
- 自适应布局,可折叠侧边栏
|
||||
- 触摸友好的交互
|
||||
- 移动端菜单和遮罩
|
||||
|
||||
### 分析与监控
|
||||
- Chart.js 驱动的交互式图表
|
||||
- 实时使用统计
|
||||
- 请求趋势可视化
|
||||
- Token 消耗跟踪
|
||||
- API 性能指标
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **前端**: 纯 HTML、CSS、JavaScript
|
||||
- **样式**: CSS3 + Flexbox/Grid
|
||||
- **前端**: 纯 HTML、CSS、JavaScript (ES6+)
|
||||
- **样式**: CSS3 + Flexbox/Grid,支持 CSS 变量
|
||||
- **图标**: Font Awesome 6.4.0
|
||||
- **图表**: Chart.js 交互式数据可视化
|
||||
- **字体**: Segoe UI 系统字体
|
||||
- **API**: RESTful API 调用
|
||||
- **API**: RESTful API 调用,自动认证
|
||||
- **国际化**: 自定义 i18n 系统,支持中英文
|
||||
- **主题系统**: CSS 自定义属性动态主题
|
||||
- **存储**: LocalStorage 用户偏好和凭据存储
|
||||
|
||||
## 故障排除
|
||||
|
||||
@@ -116,12 +175,20 @@ npm start
|
||||
### 文件结构
|
||||
```
|
||||
webui/
|
||||
├── index.html # 主页面
|
||||
├── styles.css # 样式文件
|
||||
├── app.js # 应用逻辑
|
||||
├── package.json # 项目配置
|
||||
├── i18n.js # 国际化支持
|
||||
└── README.md # 说明文档
|
||||
├── index.html # 主页面,响应式布局
|
||||
├── styles.css # 样式文件,支持主题
|
||||
├── app.js # 应用逻辑和 API 管理
|
||||
├── i18n.js # 国际化支持(中英文)
|
||||
├── package.json # 项目配置
|
||||
├── build.js # 生产环境构建脚本
|
||||
├── bundle-entry.js # 打包入口文件
|
||||
├── build-scripts/ # 构建工具
|
||||
│ └── prepare-html.js # HTML 准备脚本
|
||||
├── logo.jpg # 应用图标
|
||||
├── LICENSE # MIT 许可证
|
||||
├── README.md # 英文文档
|
||||
├── README_CN.md # 中文文档
|
||||
└── BUILD_RELEASE.md # 构建和发布说明
|
||||
```
|
||||
|
||||
### API 调用
|
||||
|
||||
186
i18n.js
186
i18n.js
@@ -99,6 +99,8 @@ const i18n = {
|
||||
'basic_settings.quota_title': '配额超出行为',
|
||||
'basic_settings.quota_switch_project': '自动切换项目',
|
||||
'basic_settings.quota_switch_preview': '切换到预览模型',
|
||||
'basic_settings.usage_statistics_title': '使用统计',
|
||||
'basic_settings.usage_statistics_enable': '启用使用统计',
|
||||
|
||||
// API 密钥管理
|
||||
'api_keys.title': 'API 密钥管理',
|
||||
@@ -214,17 +216,74 @@ const i18n = {
|
||||
'auth_files.delete_all_success': '成功删除',
|
||||
'auth_files.files_count': '个文件',
|
||||
|
||||
// Gemini Web Token
|
||||
'auth_login.gemini_web_title': 'Gemini Web Token',
|
||||
'auth_login.gemini_web_button': '保存 Gemini Web Token',
|
||||
'auth_login.gemini_web_hint': '从浏览器开发者工具中获取 Gemini 网页版的 Cookie 值,用于直接认证访问 Gemini。',
|
||||
'auth_login.secure_1psid_label': '__Secure-1PSID Cookie:',
|
||||
'auth_login.secure_1psid_placeholder': '输入 __Secure-1PSID cookie 值',
|
||||
'auth_login.secure_1psidts_label': '__Secure-1PSIDTS Cookie:',
|
||||
'auth_login.secure_1psidts_placeholder': '输入 __Secure-1PSIDTS cookie 值',
|
||||
'auth_login.gemini_web_label_label': '标签 (可选):',
|
||||
'auth_login.gemini_web_label_placeholder': '输入标签名称 (可选)',
|
||||
'auth_login.gemini_web_saved': 'Gemini Web Token 保存成功',
|
||||
|
||||
// Codex OAuth
|
||||
'auth_login.codex_oauth_title': 'Codex OAuth',
|
||||
'auth_login.codex_oauth_button': '开始 Codex 登录',
|
||||
'auth_login.codex_oauth_hint': '通过 OAuth 流程登录 Codex 服务,自动获取并保存认证文件。',
|
||||
'auth_login.codex_oauth_url_label': '授权链接:',
|
||||
'auth_login.codex_open_link': '打开链接',
|
||||
'auth_login.codex_copy_link': '复制链接',
|
||||
'auth_login.codex_oauth_status_waiting': '等待认证中...',
|
||||
'auth_login.codex_oauth_status_success': '认证成功!',
|
||||
'auth_login.codex_oauth_status_error': '认证失败:',
|
||||
'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': '使用统计',
|
||||
@@ -264,6 +323,7 @@ const i18n = {
|
||||
'notification.retry_updated': '重试设置已更新',
|
||||
'notification.quota_switch_project_updated': '项目切换设置已更新',
|
||||
'notification.quota_switch_preview_updated': '预览模型切换设置已更新',
|
||||
'notification.usage_statistics_updated': '使用统计设置已更新',
|
||||
'notification.api_key_added': 'API密钥添加成功',
|
||||
'notification.api_key_updated': 'API密钥更新成功',
|
||||
'notification.api_key_deleted': 'API密钥删除成功',
|
||||
@@ -347,6 +407,8 @@ const i18n = {
|
||||
'common.required': 'Required',
|
||||
'common.api_key': 'Key',
|
||||
'common.base_url': 'Address',
|
||||
'common.proxy_url': 'Proxy',
|
||||
'common.alias': 'Alias',
|
||||
|
||||
// Page titles
|
||||
'title.main': 'CLI Proxy API Management Center',
|
||||
@@ -408,6 +470,8 @@ const i18n = {
|
||||
'basic_settings.quota_title': 'Quota Exceeded Behavior',
|
||||
'basic_settings.quota_switch_project': 'Auto Switch Project',
|
||||
'basic_settings.quota_switch_preview': 'Switch to Preview Model',
|
||||
'basic_settings.usage_statistics_title': 'Usage Statistics',
|
||||
'basic_settings.usage_statistics_enable': 'Enable usage statistics',
|
||||
|
||||
// API Keys management
|
||||
'api_keys.title': 'API Keys Management',
|
||||
@@ -447,9 +511,12 @@ const i18n = {
|
||||
'ai_providers.codex_add_modal_key_placeholder': 'Please enter Codex API key',
|
||||
'ai_providers.codex_add_modal_url_label': 'Base URL (Optional):',
|
||||
'ai_providers.codex_add_modal_url_placeholder': 'e.g.: https://api.example.com',
|
||||
'ai_providers.codex_add_modal_proxy_label': 'Proxy URL (Optional):',
|
||||
'ai_providers.codex_add_modal_proxy_placeholder': 'e.g.: socks5://proxy.example.com:1080',
|
||||
'ai_providers.codex_edit_modal_title': 'Edit Codex API Configuration',
|
||||
'ai_providers.codex_edit_modal_key_label': 'API Key:',
|
||||
'ai_providers.codex_edit_modal_url_label': 'Base URL (Optional):',
|
||||
'ai_providers.codex_edit_modal_proxy_label': 'Proxy URL (Optional):',
|
||||
'ai_providers.codex_delete_confirm': 'Are you sure you want to delete this Codex configuration?',
|
||||
|
||||
'ai_providers.claude_title': 'Claude API Configuration',
|
||||
@@ -462,9 +529,12 @@ const i18n = {
|
||||
'ai_providers.claude_add_modal_key_placeholder': 'Please enter Claude API key',
|
||||
'ai_providers.claude_add_modal_url_label': 'Base URL (Optional):',
|
||||
'ai_providers.claude_add_modal_url_placeholder': 'e.g.: https://api.anthropic.com',
|
||||
'ai_providers.claude_add_modal_proxy_label': 'Proxy URL (Optional):',
|
||||
'ai_providers.claude_add_modal_proxy_placeholder': 'e.g.: socks5://proxy.example.com:1080',
|
||||
'ai_providers.claude_edit_modal_title': 'Edit Claude API Configuration',
|
||||
'ai_providers.claude_edit_modal_key_label': 'API Key:',
|
||||
'ai_providers.claude_edit_modal_url_label': 'Base URL (Optional):',
|
||||
'ai_providers.claude_edit_modal_proxy_label': 'Proxy URL (Optional):',
|
||||
'ai_providers.claude_delete_confirm': 'Are you sure you want to delete this Claude configuration?',
|
||||
|
||||
'ai_providers.openai_title': 'OpenAI Compatible Providers',
|
||||
@@ -478,10 +548,19 @@ const i18n = {
|
||||
'ai_providers.openai_add_modal_url_placeholder': 'e.g.: https://openrouter.ai/api/v1',
|
||||
'ai_providers.openai_add_modal_keys_label': 'API Keys (one per line):',
|
||||
'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2',
|
||||
'ai_providers.openai_add_modal_keys_proxy_label': 'Proxy URL (one per line, optional):',
|
||||
'ai_providers.openai_add_modal_keys_proxy_placeholder': 'socks5://proxy.example.com:1080\n',
|
||||
'ai_providers.openai_add_modal_models_label': 'Model List (name[, alias] one per line):',
|
||||
'ai_providers.openai_models_hint': 'Example: gpt-4o-mini or moonshotai/kimi-k2:free, kimi-k2',
|
||||
'ai_providers.openai_model_name_placeholder': 'Model name, e.g. moonshotai/kimi-k2:free',
|
||||
'ai_providers.openai_model_alias_placeholder': 'Model alias (optional)',
|
||||
'ai_providers.openai_models_add_btn': 'Add Model',
|
||||
'ai_providers.openai_edit_modal_title': 'Edit OpenAI Compatible Provider',
|
||||
'ai_providers.openai_edit_modal_name_label': 'Provider Name:',
|
||||
'ai_providers.openai_edit_modal_url_label': 'Base URL:',
|
||||
'ai_providers.openai_edit_modal_keys_label': 'API Keys (one per line):',
|
||||
'ai_providers.openai_edit_modal_keys_proxy_label': 'Proxy URL (one per line, optional):',
|
||||
'ai_providers.openai_edit_modal_models_label': 'Model List (name[, alias] one per line):',
|
||||
'ai_providers.openai_delete_confirm': 'Are you sure you want to delete this OpenAI provider?',
|
||||
'ai_providers.openai_keys_count': 'Keys Count',
|
||||
'ai_providers.openai_models_count': 'Models Count',
|
||||
@@ -508,17 +587,73 @@ const i18n = {
|
||||
'auth_files.delete_all_success': 'Successfully deleted',
|
||||
'auth_files.files_count': 'files',
|
||||
|
||||
// Gemini Web Token
|
||||
'auth_login.gemini_web_title': 'Gemini Web Token',
|
||||
'auth_login.gemini_web_button': 'Save Gemini Web Token',
|
||||
'auth_login.gemini_web_hint': 'Obtain the Cookie value of the Gemini web version from the browser\'s developer tools, used for direct authentication to access Gemini.',
|
||||
'auth_login.secure_1psid_label': '__Secure-1PSID Cookie:',
|
||||
'auth_login.secure_1psid_placeholder': 'Enter __Secure-1PSID cookie value',
|
||||
'auth_login.secure_1psidts_label': '__Secure-1PSIDTS Cookie:',
|
||||
'auth_login.secure_1psidts_placeholder': 'Enter __Secure-1PSIDTS cookie value',
|
||||
'auth_login.gemini_web_label_label': 'Label (Optional):',
|
||||
'auth_login.gemini_web_label_placeholder': 'Enter label name (optional)',
|
||||
'auth_login.gemini_web_saved': 'Gemini Web Token saved successfully',
|
||||
// Codex OAuth
|
||||
'auth_login.codex_oauth_title': 'Codex OAuth',
|
||||
'auth_login.codex_oauth_button': 'Start Codex Login',
|
||||
'auth_login.codex_oauth_hint': 'Login to Codex service through OAuth flow, automatically obtain and save authentication files.',
|
||||
'auth_login.codex_oauth_url_label': 'Authorization URL:',
|
||||
'auth_login.codex_open_link': 'Open Link',
|
||||
'auth_login.codex_copy_link': 'Copy Link',
|
||||
'auth_login.codex_oauth_status_waiting': 'Waiting for authentication...',
|
||||
'auth_login.codex_oauth_status_success': 'Authentication successful!',
|
||||
'auth_login.codex_oauth_status_error': 'Authentication failed:',
|
||||
'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',
|
||||
@@ -558,6 +693,7 @@ const i18n = {
|
||||
'notification.retry_updated': 'Retry settings updated',
|
||||
'notification.quota_switch_project_updated': 'Project switch settings updated',
|
||||
'notification.quota_switch_preview_updated': 'Preview model switch settings updated',
|
||||
'notification.usage_statistics_updated': 'Usage statistics settings updated',
|
||||
'notification.api_key_added': 'API key added successfully',
|
||||
'notification.api_key_updated': 'API key updated successfully',
|
||||
'notification.api_key_deleted': 'API key deleted successfully',
|
||||
@@ -570,6 +706,8 @@ const i18n = {
|
||||
'notification.claude_config_added': 'Claude configuration added successfully',
|
||||
'notification.claude_config_updated': 'Claude configuration updated successfully',
|
||||
'notification.claude_config_deleted': 'Claude configuration deleted successfully',
|
||||
'notification.field_required': 'Required fields cannot be empty',
|
||||
'notification.openai_provider_required': 'Please fill in provider name and Base URL',
|
||||
'notification.openai_provider_added': 'OpenAI provider added successfully',
|
||||
'notification.openai_provider_updated': 'OpenAI provider updated successfully',
|
||||
'notification.openai_provider_deleted': 'OpenAI provider deleted successfully',
|
||||
@@ -613,8 +751,8 @@ const i18n = {
|
||||
// 获取翻译文本
|
||||
t(key, params = {}) {
|
||||
const translation = this.translations[this.currentLanguage]?.[key] ||
|
||||
this.translations[this.fallbackLanguage]?.[key] ||
|
||||
key;
|
||||
this.translations[this.fallbackLanguage]?.[key] ||
|
||||
key;
|
||||
|
||||
// 简单的参数替换
|
||||
return translation.replace(/\{(\w+)\}/g, (match, param) => {
|
||||
|
||||
1167
index.html
1167
index.html
File diff suppressed because it is too large
Load Diff
766
styles.css
766
styles.css
@@ -7,6 +7,9 @@
|
||||
|
||||
/* CSS变量主题系统 */
|
||||
:root {
|
||||
/* 布局尺寸 */
|
||||
--navbar-height: 69px;
|
||||
|
||||
/* 亮色主题(默认) */
|
||||
--bg-primary: #f5f7fa;
|
||||
--bg-secondary: #ffffff;
|
||||
@@ -146,8 +149,13 @@
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.auto-login-content h2 {
|
||||
@@ -195,7 +203,8 @@
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s ease;
|
||||
margin-top: 8px; /* 与标题拉开距离,避免遮挡 */
|
||||
margin-top: 8px;
|
||||
/* 与标题拉开距离,避免遮挡 */
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
@@ -546,12 +555,14 @@
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
margin-bottom: 10px; /* 在小屏幕上给控制按钮组添加下边距 */
|
||||
margin-bottom: 10px;
|
||||
/* 在小屏幕上给控制按钮组添加下边距 */
|
||||
}
|
||||
|
||||
/* 登录页面小屏幕优化 */
|
||||
.login-header-top .header-controls {
|
||||
margin: 8px auto 0 auto; /* 顶部留白,避免与标题拥挤 */
|
||||
margin: 8px auto 0 auto;
|
||||
/* 顶部留白,避免与标题拥挤 */
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
padding: 6px;
|
||||
border-radius: 10px;
|
||||
@@ -569,7 +580,8 @@
|
||||
.theme-btn {
|
||||
padding: 8px 16px;
|
||||
font-size: 13px;
|
||||
height: 36px; /* 在小屏幕上稍微减小高度 */
|
||||
height: 36px;
|
||||
/* 在小屏幕上稍微减小高度 */
|
||||
}
|
||||
|
||||
.login-title {
|
||||
@@ -605,30 +617,92 @@ body {
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
position: relative;
|
||||
/* 侧边栏样式 */
|
||||
.layout {
|
||||
display: grid;
|
||||
grid-template-columns: 240px 1fr;
|
||||
min-height: calc(100vh - var(--navbar-height, 69px));
|
||||
width: 100%;
|
||||
transition: grid-template-columns 0.3s ease;
|
||||
}
|
||||
|
||||
.layout.sidebar-collapsed {
|
||||
grid-template-columns: 64px 1fr;
|
||||
}
|
||||
|
||||
/* 侧边栏样式 */
|
||||
.sidebar {
|
||||
width: 240px;
|
||||
background: var(--sidebar-bg);
|
||||
border-right: 1px solid var(--sidebar-border);
|
||||
height: 100vh;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: calc(100vh - var(--navbar-height, 69px));
|
||||
position: sticky;
|
||||
top: var(--navbar-height, 69px);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 100;
|
||||
z-index: 5;
|
||||
box-shadow: var(--shadow-sm);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.sidebar.collapsed {
|
||||
width: 64px;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .nav-item span {
|
||||
opacity: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .nav-item {
|
||||
justify-content: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .nav-item i {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
/* 侧边栏切换按钮(桌面端-在顶栏) */
|
||||
.sidebar-toggle-btn-desktop {
|
||||
display: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
color: var(--text-primary);
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
transition: all 0.2s ease;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.sidebar-toggle-btn-desktop:hover {
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.sidebar-toggle-btn-desktop i {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.layout.sidebar-collapsed .sidebar-toggle-btn-desktop i {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* 在大屏幕上显示桌面端切换按钮 */
|
||||
@media (min-width: 1025px) {
|
||||
.sidebar-toggle-btn-desktop {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
/* 侧边栏品牌区域 */
|
||||
.sidebar-brand {
|
||||
padding: 24px 20px;
|
||||
@@ -662,6 +736,7 @@ body {
|
||||
|
||||
.sidebar .nav-menu li {
|
||||
margin-bottom: 4px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidebar .nav-item {
|
||||
@@ -675,6 +750,7 @@ body {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sidebar .nav-item:hover {
|
||||
@@ -692,16 +768,43 @@ body {
|
||||
width: 18px;
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
transition: margin 0.3s ease;
|
||||
}
|
||||
|
||||
/* 收起状态时的工具提示 */
|
||||
.sidebar.collapsed .nav-menu li:hover::after {
|
||||
content: attr(data-tooltip);
|
||||
position: absolute;
|
||||
left: 68px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: var(--bg-secondary);
|
||||
color: var(--text-primary);
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
box-shadow: var(--shadow-md);
|
||||
border: 1px solid var(--border-primary);
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
animation: tooltipFadeIn 0.2s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes tooltipFadeIn {
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 主内容区域包装器 */
|
||||
.main-wrapper {
|
||||
margin-left: 240px;
|
||||
min-height: 100vh;
|
||||
width: calc(100% - 240px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--bg-primary);
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
/* 顶部导航栏 */
|
||||
@@ -714,30 +817,50 @@ body {
|
||||
align-items: center;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 90;
|
||||
z-index: 200;
|
||||
box-shadow: var(--shadow-sm);
|
||||
height: var(--navbar-height, 69px);
|
||||
min-height: var(--navbar-height, 69px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.top-navbar-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.top-navbar-title {
|
||||
font-size: 20px;
|
||||
.top-navbar-brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
max-width: max-content;
|
||||
}
|
||||
|
||||
.top-navbar-brand-logo {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
object-fit: contain;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.top-navbar-brand-text {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.top-navbar-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.top-navbar-actions > * {
|
||||
.top-navbar-actions>* {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
@@ -778,7 +901,7 @@ body {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.top-navbar-actions > * {
|
||||
.top-navbar-actions>* {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
}
|
||||
@@ -935,6 +1058,7 @@ body {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
@@ -1179,11 +1303,11 @@ textarea::placeholder {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
input:checked+.slider {
|
||||
background: var(--primary-color);
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
input:checked+.slider:before {
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
@@ -1343,6 +1467,7 @@ input:checked + .slider:before {
|
||||
opacity: 0;
|
||||
transform: translateY(-30px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
@@ -1476,17 +1601,54 @@ input:checked + .slider:before {
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 1024px) {
|
||||
.layout {
|
||||
position: relative;
|
||||
grid-template-columns: 1fr;
|
||||
min-height: calc(100vh - var(--navbar-height, 69px));
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: var(--navbar-height, 69px);
|
||||
height: calc(100vh - var(--navbar-height, 69px));
|
||||
transform: translateX(-100%);
|
||||
z-index: 150;
|
||||
box-shadow: var(--shadow-sm);
|
||||
background: var(--sidebar-bg);
|
||||
width: 240px !important;
|
||||
}
|
||||
|
||||
.sidebar.mobile-open {
|
||||
transform: translateX(0);
|
||||
box-shadow: var(--shadow-secondary);
|
||||
}
|
||||
|
||||
/* 移动端强制恢复侧栏展开状态 */
|
||||
.sidebar.collapsed {
|
||||
width: 240px !important;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .nav-item span {
|
||||
opacity: 1 !important;
|
||||
width: auto !important;
|
||||
overflow: visible !important;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .nav-item {
|
||||
justify-content: flex-start !important;
|
||||
padding: 10px 14px !important;
|
||||
}
|
||||
|
||||
.sidebar.collapsed .nav-item i {
|
||||
margin-right: 12px !important;
|
||||
}
|
||||
|
||||
.main-wrapper {
|
||||
margin-left: 0;
|
||||
width: 100%;
|
||||
min-height: calc(100vh - var(--navbar-height, 69px));
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
@@ -1509,7 +1671,7 @@ input:checked + .slider:before {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.top-navbar-actions > * {
|
||||
.top-navbar-actions>* {
|
||||
height: 34px;
|
||||
min-height: 34px;
|
||||
}
|
||||
@@ -1605,29 +1767,38 @@ input:checked + .slider:before {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 99;
|
||||
z-index: 120;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.sidebar-overlay.active {
|
||||
display: block;
|
||||
}
|
||||
.sidebar-overlay.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 移动端菜单按钮 */
|
||||
.mobile-menu-btn {
|
||||
display: none;
|
||||
background: none;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
background: transparent;
|
||||
border: none;
|
||||
padding: 8px;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
color: var(--text-primary);
|
||||
font-size: 20px;
|
||||
border-radius: 8px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.mobile-menu-btn:hover {
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.mobile-menu-btn {
|
||||
display: block;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1643,7 +1814,9 @@ input:checked + .slider:before {
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
@@ -1739,53 +1912,17 @@ input:checked + .slider:before {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Gemini Web Token 模态框样式 */
|
||||
.gemini-web-form .form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.gemini-web-form .form-group label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: var(--text-secondary);
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.gemini-web-form .form-group input {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border: 2px solid var(--border-primary);
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
transition: all 0.3s ease;
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-primary);
|
||||
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
||||
}
|
||||
|
||||
.gemini-web-form .form-group input:focus {
|
||||
outline: none;
|
||||
border-color: var(--border-focus);
|
||||
box-shadow: 0 0 0 3px var(--border-primary);
|
||||
}
|
||||
|
||||
.gemini-web-form .form-hint {
|
||||
margin-top: 6px;
|
||||
color: var(--text-tertiary);
|
||||
font-size: 12px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 使用统计样式 */
|
||||
.stats-overview {
|
||||
display: grid;
|
||||
@@ -2051,3 +2188,480 @@ input:checked + .slider:before {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
/* Codex OAuth 样式 */
|
||||
#codex-oauth-content {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
#codex-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);
|
||||
}
|
||||
|
||||
#codex-oauth-url:focus {
|
||||
border-color: var(--border-focus);
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
#codex-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;
|
||||
}
|
||||
|
||||
#codex-oauth-status.success {
|
||||
background: var(--success-bg);
|
||||
border-color: var(--success-border);
|
||||
color: var(--success-text);
|
||||
}
|
||||
|
||||
#codex-oauth-status.error {
|
||||
background: var(--error-bg);
|
||||
border-color: var(--error-border);
|
||||
color: var(--error-text);
|
||||
}
|
||||
|
||||
#codex-oauth-status.warning {
|
||||
background: var(--warning-bg);
|
||||
border-color: var(--warning-border);
|
||||
color: var(--warning-text);
|
||||
}
|
||||
|
||||
/* Codex OAuth 按钮样式 */
|
||||
#codex-open-link,
|
||||
#codex-copy-link {
|
||||
min-width: 100px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#codex-open-link {
|
||||
background: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
#codex-open-link:hover {
|
||||
background: var(--primary-hover);
|
||||
border-color: var(--primary-hover);
|
||||
}
|
||||
|
||||
#codex-copy-link {
|
||||
background: var(--bg-secondary);
|
||||
border-color: var(--border-primary);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
#codex-copy-link:hover {
|
||||
background: var(--bg-tertiary);
|
||||
border-color: var(--border-secondary);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* 响应式设计 - Codex OAuth */
|
||||
@media (max-width: 768px) {
|
||||
#codex-oauth-content .input-group {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
#codex-open-link,
|
||||
#codex-copy-link {
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user