mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-02-03 11:20:50 +08:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
27948b3d5c | ||
|
|
dff28db227 | ||
|
|
34b16ca886 | ||
|
|
fa86f76289 | ||
|
|
41ca99978f | ||
|
|
6ef674487f | ||
|
|
2be7ced21a | ||
|
|
b61155d215 | ||
|
|
5488d6153d | ||
|
|
30f5300bb4 | ||
|
|
52169200f1 | ||
|
|
80b2597611 | ||
|
|
04f21eea98 | ||
|
|
f6a4bae8c6 |
61
.github/workflows/release.yml
vendored
Normal file
61
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
name: Build and Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '18'
|
||||||
|
cache: 'npm'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Build all-in-one HTML
|
||||||
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Prepare release assets
|
||||||
|
run: |
|
||||||
|
cd dist
|
||||||
|
mv index.html management.html
|
||||||
|
ls -lh management.html
|
||||||
|
|
||||||
|
- name: Create Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
files: dist/management.html
|
||||||
|
body: |
|
||||||
|
## CLI Proxy API Management Center - ${{ github.ref_name }}
|
||||||
|
|
||||||
|
### Download and Usage
|
||||||
|
1. Download the `management.html` file
|
||||||
|
2. Open it directly in your browser
|
||||||
|
3. All assets (CSS, JavaScript, images) are bundled into this single file
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Single file, no external dependencies required
|
||||||
|
- Complete management interface for CLI Proxy API
|
||||||
|
- Support for local and remote connections
|
||||||
|
- Multi-language support (Chinese/English)
|
||||||
|
- Dark/Light theme support
|
||||||
|
|
||||||
|
---
|
||||||
|
🤖 Generated with GitHub Actions
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
22
.gitignore
vendored
Normal file
22
.gitignore
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Node modules
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Build output
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Temporary build files
|
||||||
|
index.build.html
|
||||||
|
|
||||||
|
# npm lock files
|
||||||
|
package-lock.json
|
||||||
|
|
||||||
|
# IDE and editor files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
69
BUILD_RELEASE.md
Normal file
69
BUILD_RELEASE.md
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
# Build and Release Instructions
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This project uses webpack to bundle all HTML, CSS, JavaScript, and images into a single all-in-one HTML file. The GitHub workflow automatically builds and releases this file when you create a new tag.
|
||||||
|
|
||||||
|
## How to Create a Release
|
||||||
|
|
||||||
|
1. Make sure all your changes are committed
|
||||||
|
2. Create and push a new tag:
|
||||||
|
```bash
|
||||||
|
git tag v1.0.0
|
||||||
|
git push origin v1.0.0
|
||||||
|
```
|
||||||
|
3. The GitHub workflow will automatically:
|
||||||
|
- Install dependencies
|
||||||
|
- Build the all-in-one HTML file using webpack
|
||||||
|
- Create a new release with the tag
|
||||||
|
- Upload the bundled HTML file to the release
|
||||||
|
|
||||||
|
## Manual Build
|
||||||
|
|
||||||
|
To build locally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install dependencies
|
||||||
|
npm install
|
||||||
|
|
||||||
|
# Build the all-in-one HTML file
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
The output will be in the `dist/` directory as `index.html`.
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
1. **build-scripts/prepare-html.js**: Pre-build script
|
||||||
|
- Reads the original `index.html`
|
||||||
|
- Removes local CSS and JavaScript references
|
||||||
|
- Generates temporary `index.build.html` for webpack
|
||||||
|
|
||||||
|
2. **webpack.config.js**: Configures webpack to bundle all assets
|
||||||
|
- Uses `style-loader` to inline CSS
|
||||||
|
- Uses `asset/inline` to embed images as base64
|
||||||
|
- Uses `html-inline-script-webpack-plugin` to inline JavaScript
|
||||||
|
- Uses `index.build.html` as template (generated dynamically)
|
||||||
|
|
||||||
|
3. **bundle-entry.js**: Entry point that imports all resources
|
||||||
|
- Imports CSS files
|
||||||
|
- Imports JavaScript modules
|
||||||
|
- Imports and sets logo image
|
||||||
|
|
||||||
|
4. **package.json scripts**:
|
||||||
|
- `prebuild`: Automatically runs before build to generate `index.build.html`
|
||||||
|
- `build`: Runs webpack to bundle everything
|
||||||
|
- `postbuild`: Cleans up temporary `index.build.html` file
|
||||||
|
|
||||||
|
5. **.github/workflows/release.yml**: GitHub workflow
|
||||||
|
- Triggers on tag push
|
||||||
|
- Builds the project (prebuild → build → postbuild)
|
||||||
|
- Creates a release with the bundled HTML file
|
||||||
|
|
||||||
|
## External Dependencies
|
||||||
|
|
||||||
|
The bundled HTML file still relies on these CDN resources:
|
||||||
|
- Font Awesome (icons)
|
||||||
|
- Chart.js (charts and graphs)
|
||||||
|
|
||||||
|
These are loaded from CDN to keep the file size reasonable and leverage browser caching.
|
||||||
101
README.md
101
README.md
@@ -9,8 +9,10 @@ https://github.com/router-for-me/CLIProxyAPI
|
|||||||
Example URL:
|
Example URL:
|
||||||
https://remote.router-for.me/
|
https://remote.router-for.me/
|
||||||
|
|
||||||
Minimum required version: ≥ 5.0.0
|
Minimum required version: ≥ 6.0.0
|
||||||
Recommended version: ≥ 5.2.6
|
Recommended version: ≥ 6.0.19
|
||||||
|
|
||||||
|
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
|
## Features
|
||||||
|
|
||||||
@@ -18,13 +20,16 @@ Recommended version: ≥ 5.2.6
|
|||||||
- Supports management key authentication
|
- Supports management key authentication
|
||||||
- Configurable API base address
|
- Configurable API base address
|
||||||
- Real-time connection status detection
|
- Real-time connection status detection
|
||||||
|
- Auto-login with saved credentials
|
||||||
|
- Language and theme switching
|
||||||
|
|
||||||
### Basic Settings
|
### Basic Settings
|
||||||
- **Debug Mode**: Enable/disable debugging
|
- **Debug Mode**: Enable/disable debugging
|
||||||
- **Proxy Settings**: Configure proxy server URL
|
- **Proxy Settings**: Configure proxy server URL
|
||||||
- **Request Retries**: Set the number of request retries
|
- **Request Retries**: Set the number of request retries
|
||||||
- **Quota Management**: Configure behavior when the quota is exceeded
|
- **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
|
### API Key Management
|
||||||
- **Proxy Service Authentication Key**: Manage API keys for the proxy service
|
- **Proxy Service Authentication Key**: Manage API keys for the proxy service
|
||||||
@@ -38,14 +43,33 @@ Recommended version: ≥ 5.2.6
|
|||||||
- Download existing authentication files
|
- Download existing authentication files
|
||||||
- Delete single or all authentication files
|
- Delete single or all authentication files
|
||||||
- Display file details
|
- Display file details
|
||||||
|
- **Gemini Web Token**: Direct authentication using browser cookies
|
||||||
|
|
||||||
|
### 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
|
## 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.
|
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
|
```bash
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
npm install
|
npm install
|
||||||
@@ -54,10 +78,19 @@ npm install
|
|||||||
npm start
|
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.
|
1. Open the management interface.
|
||||||
2. On the login screen, enter:
|
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
|
- **Management Key**: Your management key
|
||||||
3. Click the "Connect" button.
|
3. Click the "Connect" button.
|
||||||
4. Once connected successfully, all features will be available.
|
4. Once connected successfully, all features will be available.
|
||||||
@@ -69,8 +102,16 @@ npm start
|
|||||||
- **API Keys**: Management of keys for various API services.
|
- **API Keys**: Management of keys for various API services.
|
||||||
- **AI Providers**: Configuration for AI service providers.
|
- **AI Providers**: Configuration for AI service providers.
|
||||||
- **Auth Files**: Upload and download management for authentication files.
|
- **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.
|
- **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
|
## Feature Highlights
|
||||||
|
|
||||||
### Modern UI
|
### Modern UI
|
||||||
@@ -78,27 +119,45 @@ npm start
|
|||||||
- Beautiful gradient colors and shadow effects
|
- Beautiful gradient colors and shadow effects
|
||||||
- Smooth animations and transition effects
|
- Smooth animations and transition effects
|
||||||
- Intuitive icons and status indicators
|
- Intuitive icons and status indicators
|
||||||
|
- Dark/Light theme support with system preference detection
|
||||||
|
- Mobile-friendly sidebar with overlay
|
||||||
|
|
||||||
### Real-time Updates
|
### Real-time Updates
|
||||||
- Configuration changes take effect immediately
|
- Configuration changes take effect immediately
|
||||||
- Real-time status feedback
|
- Real-time status feedback
|
||||||
- Automatic data refresh
|
- Automatic data refresh
|
||||||
|
- Live usage statistics with interactive charts
|
||||||
|
- Real-time connection status monitoring
|
||||||
|
|
||||||
### Security Features
|
### Security Features
|
||||||
- Masked display for keys
|
- Masked display for keys
|
||||||
|
- Secure credential storage
|
||||||
|
- Auto-login with encrypted local storage
|
||||||
|
|
||||||
### Responsive Design
|
### Responsive Design
|
||||||
- Perfectly adapts to desktop and mobile devices
|
- Perfectly adapts to desktop and mobile devices
|
||||||
- Adaptive layout
|
- Adaptive layout with collapsible sidebar
|
||||||
- Touch-friendly interactions
|
- 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
|
## Tech Stack
|
||||||
|
|
||||||
- **Frontend**: Plain HTML, CSS, JavaScript
|
- **Frontend**: Plain HTML, CSS, JavaScript (ES6+)
|
||||||
- **Styling**: CSS3 + Flexbox/Grid
|
- **Styling**: CSS3 + Flexbox/Grid with CSS Variables
|
||||||
- **Icons**: Font Awesome 6.4.0
|
- **Icons**: Font Awesome 6.4.0
|
||||||
|
- **Charts**: Chart.js for interactive data visualization
|
||||||
- **Fonts**: Segoe UI system font
|
- **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
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -118,12 +177,20 @@ npm start
|
|||||||
### File Structure
|
### File Structure
|
||||||
```
|
```
|
||||||
webui/
|
webui/
|
||||||
├── index.html # Main page
|
├── index.html # Main page with responsive layout
|
||||||
├── styles.css # Stylesheet
|
├── styles.css # Stylesheet with theme support
|
||||||
├── app.js # Application logic
|
├── app.js # Application logic and API management
|
||||||
├── package.json # Project configuration
|
├── i18n.js # Internationalization support (EN/CN)
|
||||||
├── i18n.js # Internationalization support
|
├── package.json # Project configuration
|
||||||
└── 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
|
### API Calls
|
||||||
|
|||||||
101
README_CN.md
101
README_CN.md
@@ -1,13 +1,15 @@
|
|||||||
# Cli-Proxy-API-Management-Center
|
# Cli-Proxy-API-Management-Center
|
||||||
这是一个用于管理 CLI Proxy API 的现代化 Web 界面。
|
这是一个用于管理 CLI Proxy API 的现代化 Web 界面。
|
||||||
|
|
||||||
主项目
|
主项目
|
||||||
https://github.com/router-for-me/CLIProxyAPI
|
https://github.com/router-for-me/CLIProxyAPI
|
||||||
|
|
||||||
示例网站:
|
示例网站:
|
||||||
https://remote.router-for.me/
|
https://remote.router-for.me/
|
||||||
|
|
||||||
最低可用版本 ≥ 5.0.0
|
最低可用版本 ≥ 6.0.0
|
||||||
推荐版本 ≥ 5.2.6
|
推荐版本 ≥ 6.0.19
|
||||||
|
自6.0.19起WebUI已经集成在主程序中 可以通过主项目开启的外部端口的`/management.html`访问
|
||||||
|
|
||||||
## 功能特点
|
## 功能特点
|
||||||
|
|
||||||
@@ -15,13 +17,16 @@ https://remote.router-for.me/
|
|||||||
- 支持管理密钥认证
|
- 支持管理密钥认证
|
||||||
- 可配置 API 基础地址
|
- 可配置 API 基础地址
|
||||||
- 实时连接状态检测
|
- 实时连接状态检测
|
||||||
|
- 自动登录保存的凭据
|
||||||
|
- 语言和主题切换
|
||||||
|
|
||||||
### 基础设置
|
### 基础设置
|
||||||
- **调试模式**: 开启/关闭调试功能
|
- **调试模式**: 开启/关闭调试功能
|
||||||
- **代理设置**: 配置代理服务器 URL
|
- **代理设置**: 配置代理服务器 URL
|
||||||
- **请求重试**: 设置请求重试次数
|
- **请求重试**: 设置请求重试次数
|
||||||
- **配额管理**: 配置超出配额时的行为
|
- **配额管理**: 配置超出配额时的行为
|
||||||
- **本地访问**: 管理本地未认证访问
|
- 超出配额时自动切换项目
|
||||||
|
- 超出配额时切换到预览模型
|
||||||
|
|
||||||
### API 密钥管理
|
### API 密钥管理
|
||||||
- **代理服务认证密钥**: 管理用于代理服务的 API 密钥
|
- **代理服务认证密钥**: 管理用于代理服务的 API 密钥
|
||||||
@@ -35,14 +40,33 @@ https://remote.router-for.me/
|
|||||||
- 下载现有认证文件
|
- 下载现有认证文件
|
||||||
- 删除单个或所有认证文件
|
- 删除单个或所有认证文件
|
||||||
- 显示文件详细信息
|
- 显示文件详细信息
|
||||||
|
- **Gemini Web Token**: 使用浏览器 Cookie 直接认证
|
||||||
|
|
||||||
|
### 使用统计
|
||||||
|
- **实时分析**: 通过交互式图表跟踪 API 使用情况
|
||||||
|
- **请求趋势**: 按小时/天可视化请求模式
|
||||||
|
- **Token 使用**: 监控 Token 消耗随时间变化
|
||||||
|
- **API 详情**: 每个 API 端点的详细统计
|
||||||
|
- **成功率/失败率**: 跟踪 API 可靠性指标
|
||||||
|
|
||||||
|
### 系统信息
|
||||||
|
- **连接状态**: 实时连接监控
|
||||||
|
- **配置状态**: 跟踪配置加载状态
|
||||||
|
- **服务器信息**: 显示服务器地址和管理密钥
|
||||||
|
- **最后更新**: 显示数据最后刷新时间
|
||||||
|
|
||||||
|
|
||||||
## 使用方法
|
## 使用方法
|
||||||
|
|
||||||
### 1. 直接使用(推荐)
|
### 1. 在CLI Proxy API程序启动后使用 (推荐)
|
||||||
|
在启动了CLI Proxy API程序后 访问`http://您的服务器IP:8317/management.html`使用
|
||||||
|
|
||||||
|
### 2. 直接使用
|
||||||
直接用浏览器打开 `index.html` 文件即可使用。
|
直接用浏览器打开 `index.html` 文件即可使用。
|
||||||
|
|
||||||
### 2. 使用本地服务器
|
### 3. 使用本地服务器
|
||||||
|
|
||||||
|
#### 方法A:使用 Node.js (npm)
|
||||||
```bash
|
```bash
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
npm install
|
npm install
|
||||||
@@ -51,10 +75,19 @@ npm install
|
|||||||
npm start
|
npm start
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. 配置 API 连接
|
#### 方法B:使用 Python
|
||||||
|
```bash
|
||||||
|
# Python 3.x
|
||||||
|
python -m http.server 8000
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
然后在浏览器中打开 `http://localhost:8000`。
|
||||||
|
|
||||||
|
### 3. 配置连接
|
||||||
1. 打开管理界面
|
1. 打开管理界面
|
||||||
2. 在登录界面上输入:
|
2. 在登录界面上输入:
|
||||||
- **远程地址**: `http://localhost:8317`/v0/management将会自动为您补全
|
- **远程地址**: 现版本远程地址将会自动从您的访问地址中获取 当然您也可以自定义
|
||||||
- **管理密钥**: 您的管理密钥
|
- **管理密钥**: 您的管理密钥
|
||||||
3. 点击"连接"按钮
|
3. 点击"连接"按钮
|
||||||
4. 连接成功后即可使用所有功能
|
4. 连接成功后即可使用所有功能
|
||||||
@@ -66,8 +99,16 @@ npm start
|
|||||||
- **API 密钥**: 各种 API 服务的密钥管理
|
- **API 密钥**: 各种 API 服务的密钥管理
|
||||||
- **AI 提供商**: AI 服务提供商配置
|
- **AI 提供商**: AI 服务提供商配置
|
||||||
- **认证文件**: 认证文件的上传下载管理
|
- **认证文件**: 认证文件的上传下载管理
|
||||||
|
- **使用统计**: 实时分析和使用统计,包含交互式图表
|
||||||
- **系统信息**: 连接状态和系统信息
|
- **系统信息**: 连接状态和系统信息
|
||||||
|
|
||||||
|
### 登录界面
|
||||||
|
- **自动连接**: 使用保存的凭据自动尝试连接
|
||||||
|
- **自定义连接**: 手动配置 API 基础地址
|
||||||
|
- **当前地址检测**: 自动检测并使用当前访问地址
|
||||||
|
- **语言切换**: 支持多种语言(英文/中文)
|
||||||
|
- **主题切换**: 支持明暗主题
|
||||||
|
|
||||||
## 特性亮点
|
## 特性亮点
|
||||||
|
|
||||||
### 现代化 UI
|
### 现代化 UI
|
||||||
@@ -75,27 +116,45 @@ npm start
|
|||||||
- 美观的渐变色彩和阴影效果
|
- 美观的渐变色彩和阴影效果
|
||||||
- 流畅的动画和过渡效果
|
- 流畅的动画和过渡效果
|
||||||
- 直观的图标和状态指示
|
- 直观的图标和状态指示
|
||||||
|
- 明暗主题支持,自动检测系统偏好
|
||||||
|
- 移动端友好的侧边栏和遮罩
|
||||||
|
|
||||||
### 实时更新
|
### 实时更新
|
||||||
- 配置更改立即生效
|
- 配置更改立即生效
|
||||||
- 实时状态反馈
|
- 实时状态反馈
|
||||||
- 自动数据刷新
|
- 自动数据刷新
|
||||||
|
- 实时使用统计和交互式图表
|
||||||
|
- 实时连接状态监控
|
||||||
|
|
||||||
### 安全特性
|
### 安全特性
|
||||||
- 密钥遮蔽显示
|
- 密钥遮蔽显示
|
||||||
|
- 安全凭据存储
|
||||||
|
- 加密本地存储自动登录
|
||||||
|
|
||||||
### 响应式设计
|
### 响应式设计
|
||||||
- 完美适配桌面和移动设备
|
- 完美适配桌面和移动设备
|
||||||
- 自适应布局
|
- 自适应布局,可折叠侧边栏
|
||||||
- 触摸友好的交互
|
- 触摸友好的交互
|
||||||
|
- 移动端菜单和遮罩
|
||||||
|
|
||||||
|
### 分析与监控
|
||||||
|
- Chart.js 驱动的交互式图表
|
||||||
|
- 实时使用统计
|
||||||
|
- 请求趋势可视化
|
||||||
|
- Token 消耗跟踪
|
||||||
|
- API 性能指标
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
|
|
||||||
- **前端**: 纯 HTML、CSS、JavaScript
|
- **前端**: 纯 HTML、CSS、JavaScript (ES6+)
|
||||||
- **样式**: CSS3 + Flexbox/Grid
|
- **样式**: CSS3 + Flexbox/Grid,支持 CSS 变量
|
||||||
- **图标**: Font Awesome 6.4.0
|
- **图标**: Font Awesome 6.4.0
|
||||||
|
- **图表**: Chart.js 交互式数据可视化
|
||||||
- **字体**: Segoe UI 系统字体
|
- **字体**: Segoe UI 系统字体
|
||||||
- **API**: RESTful API 调用
|
- **API**: RESTful API 调用,自动认证
|
||||||
|
- **国际化**: 自定义 i18n 系统,支持中英文
|
||||||
|
- **主题系统**: CSS 自定义属性动态主题
|
||||||
|
- **存储**: LocalStorage 用户偏好和凭据存储
|
||||||
|
|
||||||
## 故障排除
|
## 故障排除
|
||||||
|
|
||||||
@@ -115,12 +174,20 @@ npm start
|
|||||||
### 文件结构
|
### 文件结构
|
||||||
```
|
```
|
||||||
webui/
|
webui/
|
||||||
├── index.html # 主页面
|
├── index.html # 主页面,响应式布局
|
||||||
├── styles.css # 样式文件
|
├── styles.css # 样式文件,支持主题
|
||||||
├── app.js # 应用逻辑
|
├── app.js # 应用逻辑和 API 管理
|
||||||
├── package.json # 项目配置
|
├── i18n.js # 国际化支持(中英文)
|
||||||
├── i18n.js # 国际化支持
|
├── package.json # 项目配置
|
||||||
└── 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 调用
|
### API 调用
|
||||||
|
|||||||
30
build-scripts/prepare-html.js
Normal file
30
build-scripts/prepare-html.js
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
// Read the original index.html
|
||||||
|
const indexPath = path.resolve(__dirname, '../index.html');
|
||||||
|
const outputPath = path.resolve(__dirname, '../index.build.html');
|
||||||
|
|
||||||
|
let htmlContent = fs.readFileSync(indexPath, 'utf8');
|
||||||
|
|
||||||
|
// Remove local CSS reference
|
||||||
|
htmlContent = htmlContent.replace(
|
||||||
|
/<link rel="stylesheet" href="styles\.css">\n?/g,
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
// Remove local JavaScript references
|
||||||
|
htmlContent = htmlContent.replace(
|
||||||
|
/<script src="i18n\.js"><\/script>\n?/g,
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
htmlContent = htmlContent.replace(
|
||||||
|
/<script src="app\.js"><\/script>\n?/g,
|
||||||
|
''
|
||||||
|
);
|
||||||
|
|
||||||
|
// Write the modified HTML to a temporary build file
|
||||||
|
fs.writeFileSync(outputPath, htmlContent, 'utf8');
|
||||||
|
|
||||||
|
console.log('✓ Generated index.build.html for webpack processing');
|
||||||
132
build.js
Normal file
132
build.js
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const projectRoot = __dirname;
|
||||||
|
const distDir = path.join(projectRoot, 'dist');
|
||||||
|
|
||||||
|
const sourceFiles = {
|
||||||
|
html: path.join(projectRoot, 'index.html'),
|
||||||
|
css: path.join(projectRoot, 'styles.css'),
|
||||||
|
i18n: path.join(projectRoot, 'i18n.js'),
|
||||||
|
app: path.join(projectRoot, 'app.js')
|
||||||
|
};
|
||||||
|
|
||||||
|
const logoCandidates = ['logo.png', 'logo.jpg', 'logo.jpeg', 'logo.svg', 'logo.webp', 'logo.gif'];
|
||||||
|
const logoMimeMap = {
|
||||||
|
'.png': 'image/png',
|
||||||
|
'.jpg': 'image/jpeg',
|
||||||
|
'.jpeg': 'image/jpeg',
|
||||||
|
'.svg': 'image/svg+xml',
|
||||||
|
'.webp': 'image/webp',
|
||||||
|
'.gif': 'image/gif'
|
||||||
|
};
|
||||||
|
|
||||||
|
function readFile(filePath) {
|
||||||
|
try {
|
||||||
|
return fs.readFileSync(filePath, 'utf8');
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`读取文件失败: ${filePath}`);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readBinary(filePath) {
|
||||||
|
try {
|
||||||
|
return fs.readFileSync(filePath);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`读取文件失败: ${filePath}`);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeForScript(content) {
|
||||||
|
return content.replace(/<\/(script)/gi, '<\\/$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeForStyle(content) {
|
||||||
|
return content.replace(/<\/(style)/gi, '<\\/$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureDistDir() {
|
||||||
|
if (fs.existsSync(distDir)) {
|
||||||
|
fs.rmSync(distDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
fs.mkdirSync(distDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadLogoDataUrl() {
|
||||||
|
for (const candidate of logoCandidates) {
|
||||||
|
const filePath = path.join(projectRoot, candidate);
|
||||||
|
if (!fs.existsSync(filePath)) continue;
|
||||||
|
|
||||||
|
const ext = path.extname(candidate).toLowerCase();
|
||||||
|
const mime = logoMimeMap[ext];
|
||||||
|
if (!mime) {
|
||||||
|
console.warn(`未知 Logo 文件类型,跳过内联: ${candidate}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = readBinary(filePath);
|
||||||
|
const base64 = buffer.toString('base64');
|
||||||
|
return `data:${mime};base64,${base64}`;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function build() {
|
||||||
|
ensureDistDir();
|
||||||
|
|
||||||
|
let html = readFile(sourceFiles.html);
|
||||||
|
const css = escapeForStyle(readFile(sourceFiles.css));
|
||||||
|
const i18n = escapeForScript(readFile(sourceFiles.i18n));
|
||||||
|
const app = escapeForScript(readFile(sourceFiles.app));
|
||||||
|
|
||||||
|
html = html.replace(
|
||||||
|
'<link rel="stylesheet" href="styles.css">',
|
||||||
|
`<style>
|
||||||
|
${css}
|
||||||
|
</style>`
|
||||||
|
);
|
||||||
|
|
||||||
|
html = html.replace(
|
||||||
|
'<script src="i18n.js"></script>',
|
||||||
|
`<script>
|
||||||
|
${i18n}
|
||||||
|
</script>`
|
||||||
|
);
|
||||||
|
|
||||||
|
html = html.replace(
|
||||||
|
'<script src="app.js"></script>',
|
||||||
|
`<script>
|
||||||
|
${app}
|
||||||
|
</script>`
|
||||||
|
);
|
||||||
|
|
||||||
|
const logoDataUrl = loadLogoDataUrl();
|
||||||
|
if (logoDataUrl) {
|
||||||
|
const logoScript = `<script>window.__INLINE_LOGO__ = "${logoDataUrl}";</script>`;
|
||||||
|
if (html.includes('</body>')) {
|
||||||
|
html = html.replace('</body>', `${logoScript}\n</body>`);
|
||||||
|
} else {
|
||||||
|
html += `\n${logoScript}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('未找到可内联的 Logo 文件,将保持运行时加载。');
|
||||||
|
}
|
||||||
|
|
||||||
|
const outputPath = path.join(distDir, 'index.html');
|
||||||
|
fs.writeFileSync(outputPath, html, 'utf8');
|
||||||
|
|
||||||
|
console.log('构建完成: dist/index.html');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
build();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('构建失败:', error);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
25
bundle-entry.js
Normal file
25
bundle-entry.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Import CSS
|
||||||
|
import './styles.css';
|
||||||
|
|
||||||
|
// Import JavaScript modules
|
||||||
|
import './i18n.js';
|
||||||
|
import './app.js';
|
||||||
|
|
||||||
|
// Import logo image
|
||||||
|
import logoImg from './logo.jpg';
|
||||||
|
|
||||||
|
// Set logo after DOM is loaded
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
const loginLogo = document.getElementById('login-logo');
|
||||||
|
const siteLogo = document.getElementById('site-logo');
|
||||||
|
|
||||||
|
if (loginLogo) {
|
||||||
|
loginLogo.src = logoImg;
|
||||||
|
loginLogo.style.display = 'block';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (siteLogo) {
|
||||||
|
siteLogo.src = logoImg;
|
||||||
|
siteLogo.style.display = 'block';
|
||||||
|
}
|
||||||
|
});
|
||||||
297
index.html
297
index.html
@@ -49,67 +49,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 选项卡导航 -->
|
<div class="login-body">
|
||||||
<div class="connection-tabs">
|
<div class="login-connection-info">
|
||||||
<button class="tab-button active" data-tab="local">
|
<div class="connection-summary">
|
||||||
<i class="fas fa-home"></i>
|
<i class="fas fa-link"></i>
|
||||||
<div class="tab-content">
|
<div>
|
||||||
<span class="tab-title" data-i18n="login.tab_local_title">Local</span>
|
<h3 data-i18n="login.connection_title">连接地址</h3>
|
||||||
<span class="tab-subtitle" data-i18n="login.tab_local_subtitle">Run CLI Web server on your local machine</span>
|
<p class="connection-url">
|
||||||
|
<span data-i18n="login.connection_current">当前地址</span>
|
||||||
|
<span class="connection-url-separator">:</span>
|
||||||
|
<span id="login-connection-url">-</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
<p class="form-hint" data-i18n="login.connection_auto_hint">系统将自动使用当前访问地址进行连接</p>
|
||||||
<button class="tab-button" data-tab="remote">
|
</div>
|
||||||
<i class="fas fa-cloud"></i>
|
|
||||||
<div class="tab-content">
|
|
||||||
<span class="tab-title" data-i18n="login.tab_remote_title">Remote</span>
|
|
||||||
<span class="tab-subtitle" data-i18n="login.tab_remote_subtitle">Remote connection for a remote CLI Web server</span>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 代理服务器设置(可选) -->
|
|
||||||
<div class="proxy-settings">
|
|
||||||
<label data-i18n="login.proxy_label">Proxy Server (Optional):</label>
|
|
||||||
<input type="text" id="login-proxy-url" data-i18n="login.proxy_placeholder" placeholder="http://ip:port or https://ip:port or socks5://user:pass@ip:port">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 本地连接表单 -->
|
|
||||||
<div id="local-form" class="connection-form active">
|
|
||||||
<form class="login-form">
|
<form class="login-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="local-port" data-i18n="login.local_port_label">端口号:</label>
|
<label for="login-api-base" data-i18n="login.custom_connection_label">自定义连接地址:</label>
|
||||||
<div class="local-url-group">
|
|
||||||
<span class="url-prefix">http://localhost:</span>
|
|
||||||
<input type="number" id="local-port" value="8317" min="1" max="65535" data-i18n="login.local_port_placeholder" placeholder="8317" required>
|
|
||||||
</div>
|
|
||||||
<div class="form-hint" data-i18n="login.local_url_hint">将连接到 http://localhost:端口/v0/management</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="local-management-key" data-i18n="login.management_key_label">管理密钥:</label>
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="password" id="local-management-key" data-i18n="login.management_key_placeholder" placeholder="请输入管理密钥" required>
|
<input type="text" id="login-api-base" data-i18n="login.custom_connection_placeholder" placeholder="例如: https://example.com:8317">
|
||||||
<button type="button" class="btn btn-secondary toggle-key-visibility">
|
<button type="button" id="login-reset-api-base" class="btn btn-secondary connection-reset-btn">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-location-arrow"></i>
|
||||||
|
<span data-i18n="login.use_current_address">使用当前地址</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="form-hint" data-i18n="login.custom_connection_hint">默认使用当前访问地址,若需要可手动输入其他地址。</p>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 远程连接表单 -->
|
|
||||||
<div id="remote-form" class="connection-form">
|
|
||||||
<form class="login-form">
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="remote-api-url" data-i18n="login.api_url_label">API 基础地址:</label>
|
<label for="login-management-key" data-i18n="login.management_key_label">管理密钥:</label>
|
||||||
<input type="text" id="remote-api-url" data-i18n="login.remote_api_url_placeholder" placeholder="例如: https://example.com:8317" required>
|
|
||||||
<div class="form-hint" data-i18n="login.api_url_hint">将自动补全 /v0/management</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="remote-management-key" data-i18n="login.management_key_label">管理密钥:</label>
|
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input type="password" id="remote-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">
|
<button type="button" class="btn btn-secondary toggle-key-visibility">
|
||||||
<i class="fas fa-eye"></i>
|
<i class="fas fa-eye"></i>
|
||||||
</button>
|
</button>
|
||||||
@@ -133,106 +105,81 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 主页面 -->
|
<!-- 主页面 -->
|
||||||
<div id="main-page" class="container" style="display: none;">
|
<div id="main-page" style="display: none;">
|
||||||
<!-- 头部导航 -->
|
<!-- 顶部导航栏 -->
|
||||||
<header class="header">
|
<div class="top-navbar">
|
||||||
<div class="header-content">
|
<div class="top-navbar-left">
|
||||||
<h1 class="brand">
|
<button class="mobile-menu-btn" id="mobile-menu-btn">
|
||||||
<img id="site-logo" alt="Logo" style="display:none" />
|
<i class="fas fa-bars"></i>
|
||||||
<span class="brand-title" data-i18n="title.main">CLI Proxy API Management Center</span>
|
</button>
|
||||||
</h1>
|
<button class="sidebar-toggle-btn-desktop" id="sidebar-toggle-btn-desktop" title="收起/展开侧边栏">
|
||||||
<div class="header-actions">
|
<i class="fas fa-bars"></i>
|
||||||
<div class="header-controls">
|
</button>
|
||||||
<div class="language-switcher">
|
<div class="top-navbar-brand">
|
||||||
<button id="language-toggle-main" class="btn btn-secondary language-btn">
|
<img id="site-logo" class="top-navbar-brand-logo" alt="Logo" style="display:none" />
|
||||||
<i class="fas fa-globe"></i>
|
<span class="top-navbar-brand-text" data-i18n="title.main">CLI Proxy API Management Center</span>
|
||||||
<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>
|
|
||||||
<button id="connection-status" class="btn btn-secondary">
|
|
||||||
<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>
|
|
||||||
</button>
|
|
||||||
<button id="logout-btn" class="btn btn-danger">
|
|
||||||
<i class="fas fa-sign-out-alt"></i> <span data-i18n="header.logout">登出</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
<div class="top-navbar-actions">
|
||||||
|
<div class="header-controls">
|
||||||
<!-- 连接信息 -->
|
<div class="language-switcher">
|
||||||
<section class="auth-section">
|
<button id="language-toggle-main" class="btn btn-secondary language-btn">
|
||||||
<div class="card">
|
<i class="fas fa-globe"></i>
|
||||||
<div class="card-header">
|
</button>
|
||||||
<h2><i class="fas fa-server"></i> <span data-i18n="connection.title">连接信息</span></h2>
|
</div>
|
||||||
</div>
|
<div class="theme-switcher">
|
||||||
<div class="card-content">
|
<button id="theme-toggle-main" class="btn btn-secondary theme-btn">
|
||||||
<div class="connection-info">
|
<i class="fas fa-moon"></i>
|
||||||
<div class="info-item">
|
</button>
|
||||||
<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>
|
</div>
|
||||||
|
<button id="connection-status" class="btn btn-secondary">
|
||||||
|
<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>
|
||||||
|
</button>
|
||||||
|
<button id="logout-btn" class="btn btn-danger">
|
||||||
|
<i class="fas fa-sign-out-alt"></i>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</div>
|
||||||
|
|
||||||
<!-- 主要内容区域 -->
|
<div class="layout" id="layout-container">
|
||||||
<main class="main-content">
|
<!-- 侧边栏 -->
|
||||||
<!-- 侧边栏导航 -->
|
<nav class="sidebar" id="sidebar">
|
||||||
<nav class="sidebar">
|
<!-- 导航菜单 -->
|
||||||
<ul class="nav-menu">
|
<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>
|
<i class="fas fa-sliders-h"></i> <span data-i18n="nav.basic_settings">基础设置</span>
|
||||||
</a></li>
|
</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>
|
<i class="fas fa-key"></i> <span data-i18n="nav.api_keys">API 密钥</span>
|
||||||
</a></li>
|
</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>
|
<i class="fas fa-robot"></i> <span data-i18n="nav.ai_providers">AI 提供商</span>
|
||||||
</a></li>
|
</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>
|
<i class="fas fa-file-alt"></i> <span data-i18n="nav.auth_files">认证文件</span>
|
||||||
</a></li>
|
</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>
|
<i class="fas fa-chart-line"></i> <span data-i18n="nav.usage_stats">使用统计</span>
|
||||||
</a></li>
|
</a></li>
|
||||||
<li><a href="#system-info" class="nav-item" data-section="system-info">
|
<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>
|
<i class="fas fa-info-circle"></i> <span data-i18n="nav.system_info">系统信息</span>
|
||||||
</a></li>
|
</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- 内容区域 -->
|
<!-- 侧边栏遮罩(移动端) -->
|
||||||
<div class="content-area">
|
<div class="sidebar-overlay" id="sidebar-overlay"></div>
|
||||||
|
|
||||||
|
<!-- 主内容包装器 -->
|
||||||
|
<div class="main-wrapper" id="main-wrapper">
|
||||||
|
<!-- 主内容区域 -->
|
||||||
|
<div class="main-content">
|
||||||
|
<!-- 内容区域 -->
|
||||||
|
<div class="content-area">
|
||||||
<!-- 基础设置 -->
|
<!-- 基础设置 -->
|
||||||
<section id="basic-settings" class="content-section active">
|
<section id="basic-settings" class="content-section active">
|
||||||
<h2 data-i18n="basic_settings.title">基础设置</h2>
|
<h2 data-i18n="basic_settings.title">基础设置</h2>
|
||||||
@@ -383,8 +330,20 @@
|
|||||||
<div id="openai-providers-list" class="provider-list"></div>
|
<div id="openai-providers-list" class="provider-list"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- 认证文件管理 -->
|
||||||
|
<section id="auth-files" class="content-section">
|
||||||
|
<h2 data-i18n="auth_files.title">认证文件管理</h2>
|
||||||
|
|
||||||
|
<div class="card" style="margin-bottom: 20px;">
|
||||||
|
<div class="card-content">
|
||||||
|
<p class="form-hint" data-i18n="auth_files.description">
|
||||||
|
这里管理 Qwen 和 Gemini 的认证配置文件。上传 JSON 格式的认证文件以启用相应的 AI 服务。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Gemini Web Token -->
|
<!-- Gemini Web Token -->
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@@ -405,19 +364,10 @@
|
|||||||
<label for="secure-1psidts-input" data-i18n="auth_login.secure_1psidts_label">__Secure-1PSIDTS Cookie:</label>
|
<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 值">
|
<input type="text" id="secure-1psidts-input" data-i18n="auth_login.secure_1psidts_placeholder" placeholder="输入 __Secure-1PSIDTS cookie 值">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="form-group">
|
||||||
</div>
|
<label for="gemini-web-label-input" data-i18n="auth_login.gemini_web_label_label">Label (Optional):</label>
|
||||||
</section>
|
<input type="text" id="gemini-web-label-input" data-i18n="auth_login.gemini_web_label_placeholder" placeholder="输入标签名称 (可选)">
|
||||||
|
</div>
|
||||||
<!-- 认证文件管理 -->
|
|
||||||
<section id="auth-files" class="content-section">
|
|
||||||
<h2 data-i18n="auth_files.title">认证文件管理</h2>
|
|
||||||
|
|
||||||
<div class="card" style="margin-bottom: 20px;">
|
|
||||||
<div class="card-content">
|
|
||||||
<p class="form-hint" data-i18n="auth_files.description">
|
|
||||||
这里管理 Qwen 和 Gemini 的认证配置文件。上传 JSON 格式的认证文件以启用相应的 AI 服务。
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -551,6 +501,40 @@
|
|||||||
<section id="system-info" class="content-section">
|
<section id="system-info" class="content-section">
|
||||||
<h2 data-i18n="system_info.title">系统信息</h2>
|
<h2 data-i18n="system_info.title">系统信息</h2>
|
||||||
|
|
||||||
|
<!-- 连接信息卡片 -->
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<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-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>
|
||||||
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-header">
|
<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-info-circle"></i> <span data-i18n="system_info.connection_status_title">连接状态</span></h3>
|
||||||
@@ -573,18 +557,23 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
</div>
|
||||||
|
<!-- /内容区域 -->
|
||||||
|
|
||||||
|
<!-- 版本信息 -->
|
||||||
|
<footer class="version-footer">
|
||||||
|
<div class="version-info">
|
||||||
|
<span data-i18n="footer.version">版本</span>: v0.1.0
|
||||||
|
<span class="separator">•</span>
|
||||||
|
<span data-i18n="footer.author">作者</span>: Supra4E8C
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
<!-- /主内容区域 -->
|
||||||
|
</div>
|
||||||
<!-- 版本信息 -->
|
<!-- /主内容包装器 -->
|
||||||
<footer class="version-footer">
|
|
||||||
<div class="version-info">
|
|
||||||
<span data-i18n="footer.version">版本</span>: v0.0.3
|
|
||||||
<span class="separator">•</span>
|
|
||||||
<span data-i18n="footer.author">作者</span>: Supra4E8C
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
|
<!-- /主页面 -->
|
||||||
|
|
||||||
<!-- 模态框 -->
|
<!-- 模态框 -->
|
||||||
<div id="modal" class="modal">
|
<div id="modal" class="modal">
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "npx serve .",
|
"start": "npx serve .",
|
||||||
"dev": "npx serve . --port 3000",
|
"dev": "npx serve . --port 3000",
|
||||||
"build": "echo '无需构建,直接使用静态文件'",
|
"build": "node build.js",
|
||||||
"lint": "echo '使用浏览器开发者工具检查代码'"
|
"lint": "echo '使用浏览器开发者工具检查代码'"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
|
|||||||
1352
styles.css
1352
styles.css
File diff suppressed because it is too large
Load Diff
64
webpack.config.js
Normal file
64
webpack.config.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const HtmlInlineScriptPlugin = require('html-inline-script-webpack-plugin');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: 'production',
|
||||||
|
entry: {
|
||||||
|
main: './bundle-entry.js'
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
filename: '[name].bundle.js',
|
||||||
|
clean: true
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.css$/i,
|
||||||
|
use: ['style-loader', 'css-loader']
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpg|jpeg|gif|svg)$/i,
|
||||||
|
type: 'asset/inline'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.html$/i,
|
||||||
|
loader: 'html-loader',
|
||||||
|
options: {
|
||||||
|
sources: {
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
tag: 'img',
|
||||||
|
attribute: 'src',
|
||||||
|
type: 'src'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: './index.build.html',
|
||||||
|
filename: 'index.html',
|
||||||
|
inject: 'body',
|
||||||
|
minify: {
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeComments: true,
|
||||||
|
removeRedundantAttributes: true,
|
||||||
|
removeScriptTypeAttributes: true,
|
||||||
|
removeStyleLinkTypeAttributes: true,
|
||||||
|
useShortDoctype: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new HtmlInlineScriptPlugin({
|
||||||
|
htmlMatchPattern: [/index.html$/],
|
||||||
|
scriptMatchPattern: [/.js$/]
|
||||||
|
})
|
||||||
|
],
|
||||||
|
optimization: {
|
||||||
|
minimize: true
|
||||||
|
}
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user