Compare commits

...

23 Commits

Author SHA1 Message Date
hkfires
a208a484ff feat(config-ui): add YAML config editor with save/reload support 2025-10-19 22:40:08 +08:00
Supra4E8C
369cf52346 0.1.7 2025-10-18 17:04:29 +08:00
hkfires
dcfffc716b feat(ui): add in-app log viewer and file logging controls
- Add Logs section with refresh, download, and clear actions
- Implement auto-refresh toggle and incremental loading via timestamp
- Add “logging to file” setting; integrate with config and /logging-to-file API
- Auto-load logs when opening Logs; hide nav when logging disabled
- Escape HTML when rendering logs for safety
- Update i18n with strings for logs and settings
- Ignore CLAUDE.md and AGENTS.md in .gitignore

Why: Enable users to monitor and manage logs within the app, reduce overhead with incremental updates, and avoid committing local agent docs.
2025-10-16 12:03:15 +08:00
hkfires
7de5280824 feat(build): auto-inject release version into HTML output 2025-10-15 16:49:53 +08:00
hkfires
86d60aad77 增加使用统计开关 2025-10-13 15:56:26 +08:00
Supra4E8C
020fccc032 1 2025-10-11 15:51:51 +08:00
Supra4E8C
c162ab3a54 删除gemini web tokens 2025-10-11 15:02:57 +08:00
Supra4E8C
85d12e15d8 Merge pull request #4 from tombii/main
Add missing English translations.
2025-10-11 14:51:40 +08:00
tombii
ebffb49f52 Add missing English translations. 2025-10-08 22:08:36 +02:00
Supra4E8C
316c1ffc0d Update README_CN.md 2025-10-06 16:02:15 +08:00
Supra4E8C
b3e54e7f14 Update README.md 2025-10-06 16:01:56 +08:00
Luis Pater
fe11bfb48f Added hostname checking function. If it is not localhost or 127.0.0.1, the OAuth login box will be hidden to improve user experience; Added unique IDs to each OAuth card for easier operation. 2025-10-06 01:51:56 +08:00
Luis Pater
ee0d8f82d7 Implement multiple OAuth functions, including Anthropic, Gemini CLI, Qwen and iFlow, add relevant UI components and styles, optimize user experience, and enhance the usability and feedback mechanism of the authentication process. 2025-10-06 01:48:17 +08:00
Luis Pater
0bbb397df5 Implement the Codex OAuth function, add relevant UI components and styles, optimize the login experience, and fix several UI issues. 2025-10-06 01:12:34 +08:00
Supra4E8C
27948b3d5c 实现请求和Token使用趋势图表,更新API详细统计表格,优化侧边栏样式,增强移动端体验,修复若干UI问题。 2025-10-03 18:05:33 +08:00
Supra4E8C
dff28db227 增补README 2025-10-03 15:48:21 +08:00
Supra4E8C
34b16ca886 Merge branch 'main' of https://github.com/router-for-me/Cli-Proxy-API-Management-Center 2025-10-03 15:42:22 +08:00
Supra4E8C
fa86f76289 增补README 2025-10-03 15:42:10 +08:00
Supra4E8C
41ca99978f Update README_CN.md 2025-10-03 15:35:39 +08:00
Supra4E8C
6ef674487f 更新README以适配新版本 2025-10-03 15:34:14 +08:00
Supra4E8C
2be7ced21a 实现移动端侧边栏功能,添加移动菜单按钮及遮罩,优化导航项点击事件,更新样式以提升用户体验。 2025-10-03 15:09:41 +08:00
Supra4E8C
b61155d215 v0.0.6
添加代理 URL 支持,更新 API 配置模态框,增强 XSS 防护,优化界面样式,修复若干 UI 问题,版本更新至 0.0.6
2025-10-02 17:34:26 +08:00
Supra4E8C
5488d6153d Update README.md 2025-10-01 16:36:06 +08:00
9 changed files with 5186 additions and 1308 deletions

View File

@@ -27,6 +27,8 @@ jobs:
- name: Build all-in-one HTML
run: npm run build
env:
VERSION: ${{ github.ref_name }}
- name: Prepare release assets
run: |

4
.gitignore vendored
View File

@@ -20,3 +20,7 @@ package-lock.json
# OS files
.DS_Store
Thumbs.db
CLAUDE.md
AGENTS.md
.serena

View File

@@ -10,8 +10,9 @@ Example URL:
https://remote.router-for.me/
Minimum required version: ≥ 6.0.0
Recommended version: ≥ 6.0.19
Starting from version 6.0.19, the WebUI has been integrated into the main program and is accessible via `/management.html`.
Recommended version: ≥ 6.1.3
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
@@ -19,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
@@ -40,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
@@ -55,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.
@@ -70,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
@@ -79,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
@@ -119,12 +176,20 @@ npm start
### File Structure
```
webui/
├── index.html # Main page
├── styles.css # Stylesheet
├── app.js # Application logic
├── 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
├── i18n.js # Internationalization support
── README.md # README document
├── 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

View File

@@ -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 # 应用逻辑
├── index.html # 主页面,响应式布局
├── styles.css # 样式文件,支持主题
├── app.js # 应用逻辑和 API 管理
├── i18n.js # 国际化支持(中英文)
├── package.json # 项目配置
├── i18n.js # 国际化支持
── README.md # 说明文档
├── build.js # 生产环境构建脚本
── bundle-entry.js # 打包入口文件
├── build-scripts/ # 构建工具
│ └── prepare-html.js # HTML 准备脚本
├── logo.jpg # 应用图标
├── LICENSE # MIT 许可证
├── README.md # 英文文档
├── README_CN.md # 中文文档
└── BUILD_RELEASE.md # 构建和发布说明
```
### API 调用

2174
app.js

File diff suppressed because it is too large Load Diff

View File

@@ -49,6 +49,35 @@ function escapeForStyle(content) {
return content.replace(/<\/(style)/gi, '<\\/$1');
}
function getVersion() {
// 1. 优先从环境变量获取GitHub Actions 会设置)
if (process.env.VERSION) {
return process.env.VERSION;
}
// 2. 尝试从 git tag 获取
try {
const { execSync } = require('child_process');
const gitTag = execSync('git describe --tags --exact-match 2>/dev/null || git describe --tags 2>/dev/null || echo ""', { encoding: 'utf8' }).trim();
if (gitTag) {
return gitTag;
}
} catch (err) {
console.warn('无法从 git 获取版本号');
}
// 3. 回退到 package.json
try {
const packageJson = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
return 'v' + packageJson.version;
} catch (err) {
console.warn('无法从 package.json 读取版本号');
}
// 4. 最后使用默认值
return 'v0.0.0-dev';
}
function ensureDistDir() {
if (fs.existsSync(distDir)) {
fs.rmSync(distDir, { recursive: true, force: true });
@@ -83,6 +112,11 @@ function build() {
const i18n = escapeForScript(readFile(sourceFiles.i18n));
const app = escapeForScript(readFile(sourceFiles.app));
// 获取版本号并替换
const version = getVersion();
console.log(`使用版本号: ${version}`);
html = html.replace(/__VERSION__/g, version);
html = html.replace(
'<link rel="stylesheet" href="styles.css">',
`<style>

291
i18n.js
View File

@@ -36,6 +36,8 @@ const i18n = {
'common.required': '必填',
'common.api_key': '密钥',
'common.base_url': '地址',
'common.proxy_url': '代理',
'common.alias': '别名',
// 页面标题
'title.main': 'CLI Proxy API Management Center',
@@ -80,6 +82,8 @@ const i18n = {
'nav.ai_providers': 'AI 提供商',
'nav.auth_files': '认证文件',
'nav.usage_stats': '使用统计',
'nav.config_management': '配置管理',
'nav.logs': '日志查看',
'nav.system_info': '系统信息',
// 基础设置
@@ -97,6 +101,10 @@ 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': '启用使用统计',
'basic_settings.logging_title': '日志记录',
'basic_settings.logging_to_file_enable': '启用日志记录到文件',
// API 密钥管理
'api_keys.title': 'API 密钥管理',
@@ -136,9 +144,12 @@ const i18n = {
'ai_providers.codex_add_modal_key_placeholder': '请输入Codex API密钥',
'ai_providers.codex_add_modal_url_label': 'Base URL (可选):',
'ai_providers.codex_add_modal_url_placeholder': '例如: https://api.example.com',
'ai_providers.codex_add_modal_proxy_label': '代理 URL (可选):',
'ai_providers.codex_add_modal_proxy_placeholder': '例如: socks5://proxy.example.com:1080',
'ai_providers.codex_edit_modal_title': '编辑Codex API配置',
'ai_providers.codex_edit_modal_key_label': 'API密钥:',
'ai_providers.codex_edit_modal_url_label': 'Base URL (可选):',
'ai_providers.codex_edit_modal_proxy_label': '代理 URL (可选):',
'ai_providers.codex_delete_confirm': '确定要删除这个Codex配置吗',
'ai_providers.claude_title': 'Claude API 配置',
@@ -151,9 +162,12 @@ const i18n = {
'ai_providers.claude_add_modal_key_placeholder': '请输入Claude API密钥',
'ai_providers.claude_add_modal_url_label': 'Base URL (可选):',
'ai_providers.claude_add_modal_url_placeholder': '例如: https://api.anthropic.com',
'ai_providers.claude_add_modal_proxy_label': '代理 URL (可选):',
'ai_providers.claude_add_modal_proxy_placeholder': '例如: socks5://proxy.example.com:1080',
'ai_providers.claude_edit_modal_title': '编辑Claude API配置',
'ai_providers.claude_edit_modal_key_label': 'API密钥:',
'ai_providers.claude_edit_modal_url_label': 'Base URL (可选):',
'ai_providers.claude_edit_modal_proxy_label': '代理 URL (可选):',
'ai_providers.claude_delete_confirm': '确定要删除这个Claude配置吗',
'ai_providers.openai_title': 'OpenAI 兼容提供商',
@@ -167,10 +181,19 @@ const i18n = {
'ai_providers.openai_add_modal_url_placeholder': '例如: https://openrouter.ai/api/v1',
'ai_providers.openai_add_modal_keys_label': 'API密钥 (每行一个):',
'ai_providers.openai_add_modal_keys_placeholder': 'sk-key1\nsk-key2',
'ai_providers.openai_add_modal_keys_proxy_label': '代理 URL (按行对应,可选):',
'ai_providers.openai_add_modal_keys_proxy_placeholder': 'socks5://proxy.example.com:1080\n',
'ai_providers.openai_add_modal_models_label': '模型列表 (name[, alias] 每行一个):',
'ai_providers.openai_models_hint': '示例gpt-4o-mini 或 moonshotai/kimi-k2:free, kimi-k2',
'ai_providers.openai_model_name_placeholder': '模型名称,如 moonshotai/kimi-k2:free',
'ai_providers.openai_model_alias_placeholder': '模型别名 (可选)',
'ai_providers.openai_models_add_btn': '添加模型',
'ai_providers.openai_edit_modal_title': '编辑OpenAI兼容提供商',
'ai_providers.openai_edit_modal_name_label': '提供商名称:',
'ai_providers.openai_edit_modal_url_label': 'Base URL:',
'ai_providers.openai_edit_modal_keys_label': 'API密钥 (每行一个):',
'ai_providers.openai_edit_modal_keys_proxy_label': '代理 URL (按行对应,可选):',
'ai_providers.openai_edit_modal_models_label': '模型列表 (name[, alias] 每行一个):',
'ai_providers.openai_delete_confirm': '确定要删除这个OpenAI提供商吗',
'ai_providers.openai_keys_count': '密钥数量',
'ai_providers.openai_models_count': '模型数量',
@@ -197,17 +220,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': '使用统计',
@@ -229,6 +309,45 @@ const i18n = {
'usage_stats.models': '模型统计',
'usage_stats.success_rate': '成功率',
// 日志查看
'logs.title': '日志查看',
'logs.refresh_button': '刷新日志',
'logs.clear_button': '清空日志',
'logs.download_button': '下载日志',
'logs.empty_title': '暂无日志记录',
'logs.empty_desc': '当启用"日志记录到文件"功能后,日志将显示在这里',
'logs.log_content': '日志内容',
'logs.loading': '正在加载日志...',
'logs.load_error': '加载日志失败',
'logs.clear_confirm': '确定要清空所有日志吗?此操作不可恢复!',
'logs.clear_success': '日志已清空',
'logs.download_success': '日志下载成功',
'logs.auto_refresh': '自动刷新',
'logs.auto_refresh_enabled': '自动刷新已开启',
'logs.auto_refresh_disabled': '自动刷新已关闭',
'logs.lines': '行',
'logs.removed': '已删除',
'logs.upgrade_required_title': '需要升级 CLI Proxy API',
'logs.upgrade_required_desc': '当前服务器版本不支持日志查看功能,请升级到最新版本的 CLI Proxy API 以使用此功能。',
// 配置管理
'config_management.title': '配置管理',
'config_management.editor_title': '配置文件',
'config_management.reload': '重新加载',
'config_management.save': '保存',
'config_management.description': '查看并编辑服务器上的 config.yaml 配置文件。保存前请确认语法正确。',
'config_management.status_idle': '等待操作',
'config_management.status_loading': '加载配置中...',
'config_management.status_loaded': '配置已加载',
'config_management.status_dirty': '有未保存的更改',
'config_management.status_disconnected': '请先连接服务器以加载配置',
'config_management.status_load_failed': '加载失败',
'config_management.status_saving': '正在保存配置...',
'config_management.status_saved': '配置保存完成',
'config_management.status_save_failed': '保存失败',
'config_management.save_success': '配置已保存',
'config_management.error_yaml_not_supported': '服务器未返回 YAML 格式,请确认 /config.yaml 接口可用',
// 系统信息
'system_info.title': '系统信息',
'system_info.connection_status_title': '连接状态',
@@ -247,6 +366,8 @@ const i18n = {
'notification.retry_updated': '重试设置已更新',
'notification.quota_switch_project_updated': '项目切换设置已更新',
'notification.quota_switch_preview_updated': '预览模型切换设置已更新',
'notification.usage_statistics_updated': '使用统计设置已更新',
'notification.logging_to_file_updated': '日志记录设置已更新',
'notification.api_key_added': 'API密钥添加成功',
'notification.api_key_updated': 'API密钥更新成功',
'notification.api_key_deleted': 'API密钥删除成功',
@@ -259,9 +380,12 @@ const i18n = {
'notification.claude_config_added': 'Claude配置添加成功',
'notification.claude_config_updated': 'Claude配置更新成功',
'notification.claude_config_deleted': 'Claude配置删除成功',
'notification.field_required': '必填字段不能为空',
'notification.openai_provider_required': '请填写提供商名称和Base URL',
'notification.openai_provider_added': 'OpenAI提供商添加成功',
'notification.openai_provider_updated': 'OpenAI提供商更新成功',
'notification.openai_provider_deleted': 'OpenAI提供商删除成功',
'notification.openai_model_name_required': '请填写模型名称',
'notification.data_refreshed': '数据刷新成功',
'notification.connection_required': '请先建立连接',
'notification.refresh_failed': '刷新失败',
@@ -327,6 +451,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',
@@ -371,6 +497,8 @@ const i18n = {
'nav.ai_providers': 'AI Providers',
'nav.auth_files': 'Auth Files',
'nav.usage_stats': 'Usage Statistics',
'nav.config_management': 'Config Management',
'nav.logs': 'Logs Viewer',
'nav.system_info': 'System Info',
// Basic settings
@@ -388,6 +516,10 @@ 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',
'basic_settings.logging_title': 'Logging',
'basic_settings.logging_to_file_enable': 'Enable logging to file',
// API Keys management
'api_keys.title': 'API Keys Management',
@@ -427,9 +559,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',
@@ -442,9 +577,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',
@@ -458,10 +596,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',
@@ -488,17 +635,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',
@@ -520,6 +723,45 @@ const i18n = {
'usage_stats.models': 'Model Statistics',
'usage_stats.success_rate': 'Success Rate',
// Logs viewer
'logs.title': 'Logs Viewer',
'logs.refresh_button': 'Refresh Logs',
'logs.clear_button': 'Clear Logs',
'logs.download_button': 'Download Logs',
'logs.empty_title': 'No Logs Available',
'logs.empty_desc': 'When "Enable logging to file" is enabled, logs will be displayed here',
'logs.log_content': 'Log Content',
'logs.loading': 'Loading logs...',
'logs.load_error': 'Failed to load logs',
'logs.clear_confirm': 'Are you sure you want to clear all logs? This action cannot be undone!',
'logs.clear_success': 'Logs cleared successfully',
'logs.download_success': 'Logs downloaded successfully',
'logs.auto_refresh': 'Auto Refresh',
'logs.auto_refresh_enabled': 'Auto refresh enabled',
'logs.auto_refresh_disabled': 'Auto refresh disabled',
'logs.lines': 'lines',
'logs.removed': 'Removed',
'logs.upgrade_required_title': 'Please Upgrade CLI Proxy API',
'logs.upgrade_required_desc': 'The current server version does not support the logs viewing feature. Please upgrade to the latest version of CLI Proxy API to use this feature.',
// Config management
'config_management.title': 'Config Management',
'config_management.editor_title': 'Configuration File',
'config_management.reload': 'Reload',
'config_management.save': 'Save',
'config_management.description': 'View and edit the server-side config.yaml file. Validate the syntax before saving.',
'config_management.status_idle': 'Waiting for action',
'config_management.status_loading': 'Loading configuration...',
'config_management.status_loaded': 'Configuration loaded',
'config_management.status_dirty': 'Unsaved changes',
'config_management.status_disconnected': 'Connect to the server to load the configuration',
'config_management.status_load_failed': 'Load failed',
'config_management.status_saving': 'Saving configuration...',
'config_management.status_saved': 'Configuration saved',
'config_management.status_save_failed': 'Save failed',
'config_management.save_success': 'Configuration saved successfully',
'config_management.error_yaml_not_supported': 'Server did not return YAML. Verify the /config.yaml endpoint is available.',
// System info
'system_info.title': 'System Information',
'system_info.connection_status_title': 'Connection Status',
@@ -538,6 +780,8 @@ 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.logging_to_file_updated': 'Logging 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',
@@ -550,9 +794,12 @@ 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',
'notification.openai_model_name_required': 'Model name is required',
'notification.data_refreshed': 'Data refreshed successfully',
'notification.connection_required': 'Please establish connection first',
'notification.refresh_failed': 'Refresh failed',

View File

@@ -1,14 +1,22 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title data-i18n="title.login">CLI Proxy API Management Center</title>
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/mode/yaml/yaml.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/edit/closebrackets.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.16/addon/comment/comment.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/js-yaml@4.1.0/dist/js-yaml.min.js"></script>
<script src="i18n.js"></script>
</head>
<body>
<!-- 自动登录加载页面 -->
<div id="auto-login-loading" class="login-container" style="display: none;">
@@ -69,8 +77,10 @@
<div class="form-group">
<label for="login-api-base" data-i18n="login.custom_connection_label">自定义连接地址:</label>
<div class="input-group">
<input type="text" id="login-api-base" data-i18n="login.custom_connection_placeholder" placeholder="例如: https://example.com:8317">
<button type="button" id="login-reset-api-base" class="btn btn-secondary connection-reset-btn">
<input type="text" id="login-api-base" data-i18n="login.custom_connection_placeholder"
placeholder="例如: https://example.com:8317">
<button type="button" id="login-reset-api-base"
class="btn btn-secondary connection-reset-btn">
<i class="fas fa-location-arrow"></i>
<span data-i18n="login.use_current_address">使用当前地址</span>
</button>
@@ -81,7 +91,8 @@
<div class="form-group">
<label for="login-management-key" data-i18n="login.management_key_label">管理密钥:</label>
<div class="input-group">
<input type="password" id="login-management-key" data-i18n="login.management_key_placeholder" placeholder="请输入管理密钥" required>
<input type="password" id="login-management-key"
data-i18n="login.management_key_placeholder" placeholder="请输入管理密钥" required>
<button type="button" class="btn btn-secondary toggle-key-visibility">
<i class="fas fa-eye"></i>
</button>
@@ -105,26 +116,31 @@
</div>
<!-- 主页面 -->
<div id="main-page" class="container" style="display: none;">
<!-- 部导航 -->
<header class="header">
<div class="header-content">
<h1 class="brand">
<img id="site-logo" alt="Logo" style="display:none" />
<span class="brand-title" data-i18n="title.main">CLI Proxy API Management Center</span>
</h1>
<div class="header-actions">
<div id="main-page" style="display: none;">
<!-- 部导航 -->
<div class="top-navbar">
<div class="top-navbar-left">
<button class="mobile-menu-btn" id="mobile-menu-btn">
<i class="fas fa-bars"></i>
</button>
<button class="sidebar-toggle-btn-desktop" id="sidebar-toggle-btn-desktop" title="收起/展开侧边栏">
<i class="fas fa-bars"></i>
</button>
<div class="top-navbar-brand">
<img id="site-logo" class="top-navbar-brand-logo" alt="Logo" style="display:none" />
<span class="top-navbar-brand-text" data-i18n="title.main">CLI Proxy API Management Center</span>
</div>
</div>
<div class="top-navbar-actions">
<div class="header-controls">
<div class="language-switcher">
<button id="language-toggle-main" class="btn btn-secondary language-btn">
<i class="fas fa-globe"></i>
<span data-i18n="language.switch">语言</span>
</button>
</div>
<div class="theme-switcher">
<button id="theme-toggle-main" class="btn btn-secondary theme-btn">
<i class="fas fa-moon"></i>
<span data-i18n="theme.switch">主题</span>
</button>
</div>
</div>
@@ -132,77 +148,54 @@
<i class="fas fa-circle"></i> <span data-i18n="header.check_connection">检查连接</span>
</button>
<button id="refresh-all" class="btn btn-primary">
<i class="fas fa-sync-alt"></i> <span data-i18n="header.refresh_all">刷新全部</span>
<i class="fas fa-sync-alt"></i>
</button>
<button id="logout-btn" class="btn btn-danger">
<i class="fas fa-sign-out-alt"></i> <span data-i18n="header.logout">登出</span>
<i class="fas fa-sign-out-alt"></i>
</button>
</div>
</div>
</header>
<!-- 连接信息 -->
<section class="auth-section">
<div class="card">
<div class="card-header">
<h2><i class="fas fa-server"></i> <span data-i18n="connection.title">连接信息</span></h2>
</div>
<div class="card-content">
<div class="connection-info">
<div class="info-item">
<div class="info-label">
<i class="fas fa-globe"></i>
<span data-i18n="connection.server_address">服务器地址:</span>
</div>
<div class="info-value" id="display-api-url">-</div>
</div>
<div class="info-item">
<div class="info-label">
<i class="fas fa-key"></i>
<span data-i18n="connection.management_key">管理密钥:</span>
</div>
<div class="info-value" id="display-management-key">-</div>
</div>
<div class="info-item">
<div class="info-label">
<i class="fas fa-circle"></i>
<span data-i18n="connection.status">连接状态:</span>
</div>
<div class="info-value" id="display-connection-status">
<span class="status-indicator disconnected" data-i18n="common.disconnected">未连接</span>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- 主要内容区域 -->
<main class="main-content">
<!-- 侧边栏导航 -->
<nav class="sidebar">
<div class="layout" id="layout-container">
<!-- 侧边栏 -->
<nav class="sidebar" id="sidebar">
<!-- 导航菜单 -->
<ul class="nav-menu">
<li><a href="#basic-settings" class="nav-item active" data-section="basic-settings">
<li data-tooltip="基础设置"><a href="#basic-settings" class="nav-item active"
data-section="basic-settings">
<i class="fas fa-sliders-h"></i> <span data-i18n="nav.basic_settings">基础设置</span>
</a></li>
<li><a href="#api-keys" class="nav-item" data-section="api-keys">
<li data-tooltip="API 密钥"><a href="#api-keys" class="nav-item" data-section="api-keys">
<i class="fas fa-key"></i> <span data-i18n="nav.api_keys">API 密钥</span>
</a></li>
<li><a href="#ai-providers" class="nav-item" data-section="ai-providers">
<li data-tooltip="AI 提供商"><a href="#ai-providers" class="nav-item" data-section="ai-providers">
<i class="fas fa-robot"></i> <span data-i18n="nav.ai_providers">AI 提供商</span>
</a></li>
<li><a href="#auth-files" class="nav-item" data-section="auth-files">
<li data-tooltip="认证文件"><a href="#auth-files" class="nav-item" data-section="auth-files">
<i class="fas fa-file-alt"></i> <span data-i18n="nav.auth_files">认证文件</span>
</a></li>
<li><a href="#usage-stats" class="nav-item" data-section="usage-stats">
<li data-tooltip="使用统计"><a href="#usage-stats" class="nav-item" data-section="usage-stats">
<i class="fas fa-chart-line"></i> <span data-i18n="nav.usage_stats">使用统计</span>
</a></li>
<li><a href="#system-info" class="nav-item" data-section="system-info">
<li data-tooltip="配置管理"><a href="#config-management" class="nav-item" data-section="config-management">
<i class="fas fa-cog"></i> <span data-i18n="nav.config_management">配置管理</span>
</a></li>
<li id="logs-nav-item" data-tooltip="日志查看" style="display: none;"><a href="#logs" class="nav-item" data-section="logs">
<i class="fas fa-scroll"></i> <span data-i18n="nav.logs">日志查看</span>
</a></li>
<li data-tooltip="系统信息"><a href="#system-info" class="nav-item" data-section="system-info">
<i class="fas fa-info-circle"></i> <span data-i18n="nav.system_info">系统信息</span>
</a></li>
</ul>
</nav>
<!-- 侧边栏遮罩(移动端) -->
<div class="sidebar-overlay" id="sidebar-overlay"></div>
<!-- 主内容包装器 -->
<div class="main-wrapper" id="main-wrapper">
<!-- 主内容区域 -->
<div class="main-content">
<!-- 内容区域 -->
<div class="content-area">
<!-- 基础设置 -->
@@ -212,7 +205,8 @@
<!-- Debug 设置 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-bug"></i> <span data-i18n="basic_settings.debug_title">调试模式</span></h3>
<h3><i class="fas fa-bug"></i> <span
data-i18n="basic_settings.debug_title">调试模式</span></h3>
</div>
<div class="card-content">
<div class="toggle-group">
@@ -228,15 +222,21 @@
<!-- 代理设置 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-network-wired"></i> <span data-i18n="basic_settings.proxy_title">代理设置</span></h3>
<h3><i class="fas fa-network-wired"></i> <span
data-i18n="basic_settings.proxy_title">代理设置</span></h3>
</div>
<div class="card-content">
<div class="form-group">
<label for="proxy-url" data-i18n="basic_settings.proxy_url_label">代理 URL:</label>
<label for="proxy-url" data-i18n="basic_settings.proxy_url_label">代理
URL:</label>
<div class="input-group">
<input type="text" id="proxy-url" data-i18n="basic_settings.proxy_url_placeholder" placeholder="例如: socks5://user:pass@127.0.0.1:1080/">
<button id="update-proxy" class="btn btn-primary" data-i18n="basic_settings.proxy_update">更新</button>
<button id="clear-proxy" class="btn btn-danger" data-i18n="basic_settings.proxy_clear">清空</button>
<input type="text" id="proxy-url"
data-i18n="basic_settings.proxy_url_placeholder"
placeholder="例如: socks5://user:pass@127.0.0.1:1080/">
<button id="update-proxy" class="btn btn-primary"
data-i18n="basic_settings.proxy_update">更新</button>
<button id="clear-proxy" class="btn btn-danger"
data-i18n="basic_settings.proxy_clear">清空</button>
</div>
</div>
</div>
@@ -245,14 +245,17 @@
<!-- 请求重试设置 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-redo"></i> <span data-i18n="basic_settings.retry_title">请求重试</span></h3>
<h3><i class="fas fa-redo"></i> <span
data-i18n="basic_settings.retry_title">请求重试</span></h3>
</div>
<div class="card-content">
<div class="form-group">
<label for="request-retry" data-i18n="basic_settings.retry_count_label">重试次数:</label>
<label for="request-retry"
data-i18n="basic_settings.retry_count_label">重试次数:</label>
<div class="input-group">
<input type="number" id="request-retry" min="0" max="10" value="3">
<button id="update-retry" class="btn btn-primary" data-i18n="basic_settings.retry_update">更新</button>
<button id="update-retry" class="btn btn-primary"
data-i18n="basic_settings.retry_update">更新</button>
</div>
</div>
</div>
@@ -261,7 +264,8 @@
<!-- 配额超出行为 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-exclamation-triangle"></i> <span data-i18n="basic_settings.quota_title">配额超出行为</span></h3>
<h3><i class="fas fa-exclamation-triangle"></i> <span
data-i18n="basic_settings.quota_title">配额超出行为</span></h3>
</div>
<div class="card-content">
<div class="toggle-group">
@@ -269,14 +273,52 @@
<input type="checkbox" id="switch-project-toggle">
<span class="slider"></span>
</label>
<span class="toggle-label" data-i18n="basic_settings.quota_switch_project">自动切换项目</span>
<span class="toggle-label"
data-i18n="basic_settings.quota_switch_project">自动切换项目</span>
</div>
<div class="toggle-group">
<label class="toggle-switch">
<input type="checkbox" id="switch-preview-model-toggle">
<span class="slider"></span>
</label>
<span class="toggle-label" data-i18n="basic_settings.quota_switch_preview">切换到预览模型</span>
<span class="toggle-label"
data-i18n="basic_settings.quota_switch_preview">切换到预览模型</span>
</div>
</div>
</div>
<!-- 使用统计设置 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-chart-bar"></i> <span
data-i18n="basic_settings.usage_statistics_title">使用统计</span></h3>
</div>
<div class="card-content">
<div class="toggle-group">
<label class="toggle-switch">
<input type="checkbox" id="usage-statistics-enabled-toggle">
<span class="slider"></span>
</label>
<span class="toggle-label"
data-i18n="basic_settings.usage_statistics_enable">启用使用统计</span>
</div>
</div>
</div>
<!-- 日志记录设置 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-file-alt"></i> <span
data-i18n="basic_settings.logging_title">日志记录</span></h3>
</div>
<div class="card-content">
<div class="toggle-group">
<label class="toggle-switch">
<input type="checkbox" id="logging-to-file-toggle">
<span class="slider"></span>
</label>
<span class="toggle-label"
data-i18n="basic_settings.logging_to_file_enable">启用日志记录到文件</span>
</div>
</div>
</div>
@@ -289,7 +331,8 @@
<div class="card">
<div class="card-header">
<h3><i class="fas fa-key"></i> <span data-i18n="api_keys.proxy_auth_title">代理服务认证密钥</span></h3>
<h3><i class="fas fa-key"></i> <span
data-i18n="api_keys.proxy_auth_title">代理服务认证密钥</span></h3>
<button id="add-api-key" class="btn btn-primary">
<i class="fas fa-plus"></i> <span data-i18n="api_keys.add_button">添加密钥</span>
</button>
@@ -307,9 +350,11 @@
<!-- Gemini API Keys -->
<div class="card">
<div class="card-header">
<h3><i class="fab fa-google"></i> <span data-i18n="ai_providers.gemini_title">Gemini API 密钥</span></h3>
<h3><i class="fab fa-google"></i> <span data-i18n="ai_providers.gemini_title">Gemini
API 密钥</span></h3>
<button id="add-gemini-key" class="btn btn-primary">
<i class="fas fa-plus"></i> <span data-i18n="ai_providers.gemini_add_button">添加密钥</span>
<i class="fas fa-plus"></i> <span
data-i18n="ai_providers.gemini_add_button">添加密钥</span>
</button>
</div>
<div class="card-content">
@@ -320,9 +365,11 @@
<!-- Codex API Keys -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-code"></i> <span data-i18n="ai_providers.codex_title">Codex API 配置</span></h3>
<h3><i class="fas fa-code"></i> <span data-i18n="ai_providers.codex_title">Codex API
配置</span></h3>
<button id="add-codex-key" class="btn btn-primary">
<i class="fas fa-plus"></i> <span data-i18n="ai_providers.codex_add_button">添加配置</span>
<i class="fas fa-plus"></i> <span
data-i18n="ai_providers.codex_add_button">添加配置</span>
</button>
</div>
<div class="card-content">
@@ -333,9 +380,11 @@
<!-- Claude API Keys -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-brain"></i> <span data-i18n="ai_providers.claude_title">Claude API 配置</span></h3>
<h3><i class="fas fa-brain"></i> <span data-i18n="ai_providers.claude_title">Claude
API 配置</span></h3>
<button id="add-claude-key" class="btn btn-primary">
<i class="fas fa-plus"></i> <span data-i18n="ai_providers.claude_add_button">添加配置</span>
<i class="fas fa-plus"></i> <span
data-i18n="ai_providers.claude_add_button">添加配置</span>
</button>
</div>
<div class="card-content">
@@ -346,9 +395,11 @@
<!-- OpenAI 兼容提供商 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-plug"></i> <span data-i18n="ai_providers.openai_title">OpenAI 兼容提供商</span></h3>
<h3><i class="fas fa-plug"></i> <span data-i18n="ai_providers.openai_title">OpenAI
兼容提供商</span></h3>
<button id="add-openai-provider" class="btn btn-primary">
<i class="fas fa-plus"></i> <span data-i18n="ai_providers.openai_add_button">添加提供商</span>
<i class="fas fa-plus"></i> <span
data-i18n="ai_providers.openai_add_button">添加提供商</span>
</button>
</div>
<div class="card-content">
@@ -369,43 +420,19 @@
</div>
</div>
<!-- Gemini Web Token -->
<div class="card">
<div class="card-header">
<h3><i class="fab fa-google"></i> <span data-i18n="auth_login.gemini_web_title">Gemini Web Token</span></h3>
<button id="gemini-web-token-btn" class="btn btn-primary">
<i class="fas fa-save"></i> <span data-i18n="auth_login.gemini_web_button">保存 Gemini Web Token</span>
</button>
</div>
<div class="card-content">
<p class="form-hint" style="margin-bottom: 20px;" data-i18n="auth_login.gemini_web_hint">
从浏览器开发者工具中获取 Gemini 网页版的 Cookie 值,用于直接认证访问 Gemini。
</p>
<div class="form-group">
<label for="secure-1psid-input" data-i18n="auth_login.secure_1psid_label">__Secure-1PSID Cookie:</label>
<input type="text" id="secure-1psid-input" data-i18n="auth_login.secure_1psid_placeholder" placeholder="输入 __Secure-1PSID cookie 值">
</div>
<div class="form-group">
<label for="secure-1psidts-input" data-i18n="auth_login.secure_1psidts_label">__Secure-1PSIDTS Cookie:</label>
<input type="text" id="secure-1psidts-input" data-i18n="auth_login.secure_1psidts_placeholder" placeholder="输入 __Secure-1PSIDTS cookie 值">
</div>
<div class="form-group">
<label for="gemini-web-label-input" data-i18n="auth_login.gemini_web_label_label">Label (Optional):</label>
<input type="text" id="gemini-web-label-input" data-i18n="auth_login.gemini_web_label_placeholder" placeholder="输入标签名称 (可选)">
</div>
</div>
</div>
<!-- 认证文件 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-file-alt"></i> <span data-i18n="auth_files.title_section">认证文件</span></h3>
<h3><i class="fas fa-file-alt"></i> <span
data-i18n="auth_files.title_section">认证文件</span></h3>
<div class="header-actions">
<button id="upload-auth-file" class="btn btn-primary">
<i class="fas fa-upload"></i> <span data-i18n="auth_files.upload_button">上传文件</span>
<i class="fas fa-upload"></i> <span
data-i18n="auth_files.upload_button">上传文件</span>
</button>
<button id="delete-all-auth-files" class="btn btn-danger">
<i class="fas fa-trash"></i> <span data-i18n="auth_files.delete_all_button">删除全部</span>
<i class="fas fa-trash"></i> <span
data-i18n="auth_files.delete_all_button">删除全部</span>
</button>
</div>
</div>
@@ -414,6 +441,228 @@
<input type="file" id="auth-file-input" accept=".json" style="display: none;">
</div>
</div>
<!-- Codex OAuth -->
<div class="card" id="codex-oauth-card">
<div class="card-header">
<h3><i class="fas fa-code"></i> <span data-i18n="auth_login.codex_oauth_title">Codex
OAuth</span></h3>
<button id="codex-oauth-btn" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> <span
data-i18n="auth_login.codex_oauth_button">开始 Codex 登录</span>
</button>
</div>
<div class="card-content">
<p class="form-hint" style="margin-bottom: 20px;"
data-i18n="auth_login.codex_oauth_hint">
通过 OAuth 流程登录 Codex 服务,自动获取并保存认证文件。
</p>
<div id="codex-oauth-content" style="display: none;">
<div class="form-group">
<label data-i18n="auth_login.codex_oauth_url_label">授权链接:</label>
<div class="input-group">
<input type="text" id="codex-oauth-url" readonly>
<button id="codex-open-link" class="btn btn-primary">
<i class="fas fa-external-link-alt"></i> <span
data-i18n="auth_login.codex_open_link">打开链接</span>
</button>
<button id="codex-copy-link" class="btn btn-secondary">
<i class="fas fa-copy"></i> <span
data-i18n="auth_login.codex_copy_link">复制链接</span>
</button>
</div>
</div>
<div id="codex-oauth-status" class="form-hint" style="margin-top: 10px;"></div>
</div>
</div>
</div>
<!-- Anthropic OAuth -->
<div class="card" id="anthropic-oauth-card">
<div class="card-header">
<h3><i class="fas fa-brain"></i> <span
data-i18n="auth_login.anthropic_oauth_title">Anthropic OAuth</span></h3>
<button id="anthropic-oauth-btn" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> <span
data-i18n="auth_login.anthropic_oauth_button">开始 Anthropic 登录</span>
</button>
</div>
<div class="card-content">
<p class="form-hint" style="margin-bottom: 20px;"
data-i18n="auth_login.anthropic_oauth_hint">
通过 OAuth 流程登录 Anthropic (Claude) 服务,自动获取并保存认证文件。
</p>
<div id="anthropic-oauth-content" style="display: none;">
<div class="form-group">
<label data-i18n="auth_login.anthropic_oauth_url_label">授权链接:</label>
<div class="input-group">
<input type="text" id="anthropic-oauth-url" readonly>
<button id="anthropic-open-link" class="btn btn-primary">
<i class="fas fa-external-link-alt"></i> <span
data-i18n="auth_login.anthropic_open_link">打开链接</span>
</button>
<button id="anthropic-copy-link" class="btn btn-secondary">
<i class="fas fa-copy"></i> <span
data-i18n="auth_login.anthropic_copy_link">复制链接</span>
</button>
</div>
</div>
<div id="anthropic-oauth-status" class="form-hint" style="margin-top: 10px;">
</div>
</div>
</div>
</div>
<!-- Gemini CLI OAuth -->
<div class="card" id="gemini-cli-oauth-card">
<div class="card-header">
<h3><i class="fab fa-google"></i> <span
data-i18n="auth_login.gemini_cli_oauth_title">Gemini CLI OAuth</span></h3>
<button id="gemini-cli-oauth-btn" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> <span
data-i18n="auth_login.gemini_cli_oauth_button">开始 Gemini CLI 登录</span>
</button>
</div>
<div class="card-content">
<p class="form-hint" style="margin-bottom: 20px;"
data-i18n="auth_login.gemini_cli_oauth_hint">
通过 OAuth 流程登录 Google Gemini CLI 服务,自动获取并保存认证文件。
</p>
<div class="form-group" style="margin-bottom: 20px;">
<label for="gemini-cli-project-id"
data-i18n="auth_login.gemini_cli_project_id_label">Google Cloud 项目 ID
(可选):</label>
<input type="text" id="gemini-cli-project-id"
data-i18n="auth_login.gemini_cli_project_id_placeholder"
placeholder="输入 Google Cloud 项目 ID (可选)">
<div class="form-hint" data-i18n="auth_login.gemini_cli_project_id_hint">
如果指定了项目 ID将使用该项目的认证信息。
</div>
</div>
<div id="gemini-cli-oauth-content" style="display: none;">
<div class="form-group">
<label data-i18n="auth_login.gemini_cli_oauth_url_label">授权链接:</label>
<div class="input-group">
<input type="text" id="gemini-cli-oauth-url" readonly>
<button id="gemini-cli-open-link" class="btn btn-primary">
<i class="fas fa-external-link-alt"></i> <span
data-i18n="auth_login.gemini_cli_open_link">打开链接</span>
</button>
<button id="gemini-cli-copy-link" class="btn btn-secondary">
<i class="fas fa-copy"></i> <span
data-i18n="auth_login.gemini_cli_copy_link">复制链接</span>
</button>
</div>
</div>
<div id="gemini-cli-oauth-status" class="form-hint" style="margin-top: 10px;">
</div>
</div>
</div>
</div>
<!-- Qwen OAuth -->
<div class="card" id="qwen-oauth-card">
<div class="card-header">
<h3><i class="fas fa-robot"></i> <span data-i18n="auth_login.qwen_oauth_title">Qwen
OAuth</span></h3>
<button id="qwen-oauth-btn" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> <span
data-i18n="auth_login.qwen_oauth_button">开始 Qwen 登录</span>
</button>
</div>
<div class="card-content">
<p class="form-hint" style="margin-bottom: 20px;"
data-i18n="auth_login.qwen_oauth_hint">
通过设备授权流程登录 Qwen 服务,自动获取并保存认证文件。
</p>
<div id="qwen-oauth-content" style="display: none;">
<div class="form-group">
<label data-i18n="auth_login.qwen_oauth_url_label">授权链接:</label>
<div class="input-group">
<input type="text" id="qwen-oauth-url" readonly>
<button id="qwen-open-link" class="btn btn-primary">
<i class="fas fa-external-link-alt"></i> <span
data-i18n="auth_login.qwen_open_link">打开链接</span>
</button>
<button id="qwen-copy-link" class="btn btn-secondary">
<i class="fas fa-copy"></i> <span
data-i18n="auth_login.qwen_copy_link">复制链接</span>
</button>
</div>
</div>
<div id="qwen-oauth-status" class="form-hint" style="margin-top: 10px;"></div>
</div>
</div>
</div>
<!-- iFlow OAuth -->
<div class="card" id="iflow-oauth-card">
<div class="card-header">
<h3><i class="fas fa-stream"></i> <span
data-i18n="auth_login.iflow_oauth_title">iFlow OAuth</span></h3>
<button id="iflow-oauth-btn" class="btn btn-primary">
<i class="fas fa-sign-in-alt"></i> <span
data-i18n="auth_login.iflow_oauth_button">开始 iFlow 登录</span>
</button>
</div>
<div class="card-content">
<p class="form-hint" style="margin-bottom: 20px;"
data-i18n="auth_login.iflow_oauth_hint">
通过 OAuth 流程登录 iFlow 服务,自动获取并保存认证文件。
</p>
<div id="iflow-oauth-content" style="display: none;">
<div class="form-group">
<label data-i18n="auth_login.iflow_oauth_url_label">授权链接:</label>
<div class="input-group">
<input type="text" id="iflow-oauth-url" readonly>
<button id="iflow-open-link" class="btn btn-primary">
<i class="fas fa-external-link-alt"></i> <span
data-i18n="auth_login.iflow_open_link">打开链接</span>
</button>
<button id="iflow-copy-link" class="btn btn-secondary">
<i class="fas fa-copy"></i> <span
data-i18n="auth_login.iflow_copy_link">复制链接</span>
</button>
</div>
</div>
<div id="iflow-oauth-status" class="form-hint" style="margin-top: 10px;"></div>
</div>
</div>
</div>
</section>
<!-- 日志查看 -->
<section id="logs" class="content-section">
<h2 data-i18n="logs.title">日志查看</h2>
<div class="card">
<div class="card-header">
<h3><i class="fas fa-scroll"></i> <span data-i18n="logs.log_content">日志内容</span></h3>
<div class="header-actions">
<div class="toggle-group" style="margin-right: 15px;">
<label class="toggle-switch" style="margin-right: 5px;">
<input type="checkbox" id="logs-auto-refresh-toggle">
<span class="slider"></span>
</label>
<span class="toggle-label" data-i18n="logs.auto_refresh" style="font-size: 0.9em;">自动刷新</span>
</div>
<button id="refresh-logs" class="btn btn-primary">
<i class="fas fa-sync-alt"></i> <span data-i18n="logs.refresh_button">刷新日志</span>
</button>
<button id="download-logs" class="btn btn-secondary">
<i class="fas fa-download"></i> <span data-i18n="logs.download_button">下载日志</span>
</button>
<button id="clear-logs" class="btn btn-danger">
<i class="fas fa-trash"></i> <span data-i18n="logs.clear_button">清空日志</span>
</button>
</div>
</div>
<div class="card-content">
<div id="logs-content" class="logs-container">
<div class="loading-placeholder" data-i18n="logs.loading">正在加载日志...</div>
</div>
</div>
</div>
</section>
<!-- 使用统计 -->
@@ -468,12 +717,14 @@
<!-- 请求趋势图 -->
<div class="card chart-card">
<div class="card-header">
<h3><i class="fas fa-chart-line"></i> <span data-i18n="usage_stats.requests_trend">请求趋势</span></h3>
<h3><i class="fas fa-chart-line"></i> <span
data-i18n="usage_stats.requests_trend">请求趋势</span></h3>
<div class="chart-controls">
<button class="btn btn-small" data-period="hour" id="requests-hour-btn">
<span data-i18n="usage_stats.by_hour">按小时</span>
</button>
<button class="btn btn-small active" data-period="day" id="requests-day-btn">
<button class="btn btn-small active" data-period="day"
id="requests-day-btn">
<span data-i18n="usage_stats.by_day">按天</span>
</button>
</div>
@@ -488,7 +739,8 @@
<!-- Token使用趋势图 -->
<div class="card chart-card">
<div class="card-header">
<h3><i class="fas fa-chart-area"></i> <span data-i18n="usage_stats.tokens_trend">Token 使用趋势</span></h3>
<h3><i class="fas fa-chart-area"></i> <span
data-i18n="usage_stats.tokens_trend">Token 使用趋势</span></h3>
<div class="chart-controls">
<button class="btn btn-small" data-period="hour" id="tokens-hour-btn">
<span data-i18n="usage_stats.by_hour">按小时</span>
@@ -509,7 +761,8 @@
<!-- API详细统计 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-list"></i> <span data-i18n="usage_stats.api_details">API 详细统计</span></h3>
<h3><i class="fas fa-list"></i> <span data-i18n="usage_stats.api_details">API
详细统计</span></h3>
<button id="refresh-usage-stats" class="btn btn-primary">
<i class="fas fa-sync-alt"></i> <span data-i18n="usage_stats.refresh">刷新</span>
</button>
@@ -522,26 +775,87 @@
</div>
</section>
<!-- 配置管理 -->
<section id="config-management" class="content-section">
<h2 data-i18n="config_management.title">配置管理</h2>
<div class="card">
<div class="card-header">
<h3><i class="fas fa-file-code"></i> <span data-i18n="config_management.editor_title">配置文件</span></h3>
<div class="editor-actions">
<button id="config-reload-btn" class="btn btn-secondary">
<i class="fas fa-sync-alt"></i> <span data-i18n="config_management.reload">重新加载</span>
</button>
<button id="config-save-btn" class="btn btn-primary">
<i class="fas fa-save"></i> <span data-i18n="config_management.save">保存</span>
</button>
</div>
</div>
<div class="card-content">
<p class="form-hint" data-i18n="config_management.description">查看并编辑服务器上的 config.yaml 配置文件。保存前请确认语法正确。</p>
<div class="yaml-editor-container">
<textarea id="config-editor" class="yaml-editor" spellcheck="false" placeholder="key: value"></textarea>
<div id="config-editor-status" class="editor-status" data-i18n="config_management.status_idle">等待操作</div>
</div>
</div>
</div>
</section>
<!-- 系统信息 -->
<section id="system-info" class="content-section">
<h2 data-i18n="system_info.title">系统信息</h2>
<!-- 连接信息卡片 -->
<div class="card">
<div class="card-header">
<h3><i class="fas fa-info-circle"></i> <span data-i18n="system_info.connection_status_title">连接状态</span></h3>
<h3><i class="fas fa-server"></i> <span data-i18n="connection.title">连接信息</span>
</h3>
</div>
<div class="card-content">
<div class="connection-info">
<div class="info-item">
<div class="info-label">
<i class="fas fa-globe"></i>
<span data-i18n="connection.server_address">服务器地址:</span>
</div>
<div class="info-value" id="display-api-url">-</div>
</div>
<div class="info-item">
<div class="info-label">
<i class="fas fa-circle"></i>
<span data-i18n="connection.status">连接状态:</span>
</div>
<div class="info-value" id="display-connection-status">
<span class="status-indicator disconnected"
data-i18n="common.disconnected">未连接</span>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h3><i class="fas fa-info-circle"></i> <span
data-i18n="system_info.connection_status_title">连接状态</span></h3>
</div>
<div class="card-content">
<div id="system-status" class="status-info">
<div class="status-item">
<span class="status-label" data-i18n="system_info.api_status_label">API 状态:</span>
<span id="api-status" class="status-value" data-i18n="common.disconnected">未连接</span>
<span class="status-label" data-i18n="system_info.api_status_label">API
状态:</span>
<span id="api-status" class="status-value"
data-i18n="common.disconnected">未连接</span>
</div>
<div class="status-item">
<span class="status-label" data-i18n="system_info.config_status_label">配置状态:</span>
<span id="config-status" class="status-value" data-i18n="system_info.not_loaded">未加载</span>
<span class="status-label"
data-i18n="system_info.config_status_label">配置状态:</span>
<span id="config-status" class="status-value"
data-i18n="system_info.not_loaded">未加载</span>
</div>
<div class="status-item">
<span class="status-label" data-i18n="system_info.last_update_label">最后更新:</span>
<span class="status-label"
data-i18n="system_info.last_update_label">最后更新:</span>
<span id="last-update" class="status-value">-</span>
</div>
</div>
@@ -549,17 +863,22 @@
</div>
</section>
</div>
</main>
<!-- /内容区域 -->
<!-- 版本信息 -->
<footer class="version-footer">
<div class="version-info">
<span data-i18n="footer.version">版本</span>: v0.0.5
<span data-i18n="footer.version">版本</span>: __VERSION__
<span class="separator"></span>
<span data-i18n="footer.author">作者</span>: Supra4E8C
<span data-i18n="footer.author">作者</span>: CLI Proxy API Team
</div>
</footer>
</div>
<!-- /主内容区域 -->
</div>
<!-- /主内容包装器 -->
</div>
<!-- /主页面 -->
<!-- 模态框 -->
<div id="modal" class="modal">
@@ -576,4 +895,5 @@
<script src="app.js"></script>
</body>
</html>

2029
styles.css

File diff suppressed because it is too large Load Diff