feat(tests): add comprehensive tests for TokenRouter and related components

- Implement tests for TokenRouter downstream policy, covering allowedRouteIds and site weight multipliers.
- Add tests for TokenRouter patterns and model mapping, including regex pattern matching and model mapping precedence.
- Create tests for BrandIcon component to verify brand detection logic.
- Develop tests for Accounts page, focusing on rebind panel behavior and refresh action on error.
- Introduce fuzzy search utility tests to validate substring and subsequence matching.
- Implement navigation focus helpers tests for building and parsing focus paths.
- Add progressive render tests to ensure correct initial and next visible counts.
- Create route model candidates index tests to validate route candidate indexing and matching logic.
This commit is contained in:
cita
2026-03-02 13:33:35 +08:00
parent 99c9e145c3
commit f6389a999a
98 changed files with 11286 additions and 801 deletions
+2
View File
@@ -0,0 +1,2 @@
dist/
cache/
+64
View File
@@ -0,0 +1,64 @@
import { defineConfig } from 'vitepress';
import { withMermaid } from 'vitepress-plugin-mermaid';
export default withMermaid(
defineConfig({
lang: 'zh-CN',
title: 'Metapi 文档',
description: 'Metapi 使用文档、FAQ 与教程沉淀',
cleanUrls: true,
lastUpdated: true,
ignoreDeadLinks: true,
themeConfig: {
siteTitle: 'Metapi Docs',
logo: '/logos/logo-icon-512.png',
nav: [
{ text: '首页', link: '/' },
{ text: '快速上手', link: '/getting-started' },
{ text: 'FAQ', link: '/faq' },
{ text: '社区贡献', link: '/community/faq-tutorial-guidelines' },
{ text: '项目主页', link: 'https://github.com/cita-777/metapi' },
],
sidebar: [
{
text: '开始',
items: [
{ text: '文档首页', link: '/' },
{ text: '文档总览', link: '/README' },
{ text: '快速上手', link: '/getting-started' },
{ text: '部署指南', link: '/deployment' },
],
},
{
text: '使用与配置',
items: [
{ text: '配置说明', link: '/configuration' },
{ text: '客户端接入', link: '/client-integration' },
{ text: '运维手册', link: '/operations' },
],
},
{
text: '知识库',
items: [
{ text: '常见问题 FAQ', link: '/faq' },
{ text: '目录规范', link: '/project-structure' },
{ text: 'FAQ/教程贡献规范', link: '/community/faq-tutorial-guidelines' },
],
},
],
socialLinks: [
{ icon: 'github', link: 'https://github.com/cita-777/metapi' },
],
outline: {
level: [2, 3],
},
footer: {
message: 'MIT Licensed',
copyright: 'Copyright (c) 2026 Metapi Contributors',
},
search: {
provider: 'local',
},
},
}),
);
+23 -26
View File
@@ -10,6 +10,18 @@
---
## 文档站运行
```bash
npm run docs:dev
```
构建静态站点:
```bash
npm run docs:build
```
## 快速导航
| 文档 | 适合谁 | 解决的问题 |
@@ -20,36 +32,21 @@
| 🔌 [客户端接入](./client-integration.md) | 下游应用接入者 | Open WebUI、Cherry Studio、Cursor 等接入 |
| 🔧 [运维手册](./operations.md) | 运维人员 | 备份恢复、日志排查、健康检查 |
| ❓ [常见问题](./faq.md) | 所有用户 | 常见报错与修复路径 |
| 🧩 [FAQ/教程贡献规范](./community/faq-tutorial-guidelines.md) | 社区贡献者 | 统一沉淀 FAQ、教程与排障经验 |
| 📁 [目录规范](./project-structure.md) | 开发者 | 项目目录组织与约定 |
## 架构概览
```text
┌──────────────────────────────────────────────────┐
│ 下游客户端 │
│ Open WebUI / Cherry Studio / Cursor / Claude │
│ Code / Roo Code / Kilo Code / ... │
└───────────────────┬──────────────────────────────┘
│ Authorization: Bearer <PROXY_TOKEN>
▼
┌──────────────────────────────────────────────────┐
│ Metapi 网关 │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 统一代理 │ │ 智能路由 │ │ 格式转换 │ │
│ │ /v1/* │ │ 成本+余额 │ │ OpenAI⇄ │ │
│ │ │ │ +使用率 │ │ Claude │ │
│ └────────────┘ └────────────┘ └────────────┘ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ 自动签到 │ │ 余额管理 │ │ 多渠道告警 │ │
│ └────────────┘ └────────────┘ └────────────┘ │
└───────────────────┬──────────────────────────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ New API │ │ One API │ │ Veloera │ ...
└─────────┘ └─────────┘ └─────────┘
```
**下游客户端**(Cursor · Claude Code · Codex · Open WebUI · Cherry Studio 等)
&emsp;↓ &ensp;`Authorization: Bearer <PROXY_TOKEN>`
**Metapi 网关**
&emsp;• 统一代理 `/v1/*` — 兼容 OpenAI / Claude 全接口
&emsp;• 智能路由引擎 — 按成本、余额、可用率加权选路,失败自动冷却与重试
&emsp;• 模型发现 — 自动聚合上游全部模型,零配置
&emsp;• 格式转换 — OpenAI ⇄ Claude 双向透明转换
&emsp;• 自动签到 · 余额管理 · 告警通知 · 数据看板
&emsp;↓
**上游平台**(New API · One API · OneHub · DoneHub · Veloera · AnyRouter · Sub2API …)
## 核心概念
+55 -11
View File
@@ -13,7 +13,7 @@ Metapi 暴露标准 OpenAI / Claude 兼容接口,下游客户端只需配置
| 配置项 | 值 |
|--------|-----|
| **Base URL** | `https://your-domain.com`(不要拼接 `/v1`,客户端会自动加) |
| **API Key** | 你设置的 `PROXY_TOKEN` 值 |
| **API Key** | 你设置的 `PROXY_TOKEN` 值,或创建的下游 API Key |
模型列表自动从 `GET /v1/models` 获取,无需手动配置。
@@ -61,19 +61,46 @@ Metapi 暴露标准 OpenAI / Claude 兼容接口,下游客户端只需配置
### Claude Code
```bash
export ANTHROPIC_BASE_URL=https://your-domain.com
export ANTHROPIC_API_KEY=your-proxy-sk-token
export CLAUDE_CODE_ATTRIBUTION_HEADER=0
export CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1
# 可选:进一步关闭非必要模型调用
export DISABLE_NON_ESSENTIAL_MODEL_CALLS=1
在 `~/.claude/settings.json` 中配置:
```json
{
“env”: {
“ANTHROPIC_BASE_URL”: “https://your-domain.com”,
“ANTHROPIC_API_KEY”: “your-proxy-sk-token”,
“ANTHROPIC_AUTH_TOKEN”: “your-proxy-sk-token”,
“CLAUDE_CODE_ATTRIBUTION_HEADER”: “0”,
“CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC”: “1”
}
}
```
或在配置文件中设置相应的环境变量(例如 `~/.claude/settings.json`)。
> 说明:不同版本客户端可能读取 `ANTHROPIC_API_KEY` 或 `ANTHROPIC_AUTH_TOKEN`,建议同时设置。
> 上述变量由 Claude Code 客户端读取,属于客户端行为开关;
> `metapi` 服务端无法替代客户端”设置这些变量”,只能处理已经发来的请求。
> 说明:上述变量由 Claude Code 客户端读取,属于客户端行为开关;
> `metapi` 服务端无法替代客户端“设置这些变量”,只能处理已经发来的请求。
### Codex CLI
`~/.codex/config.toml`
```toml
model = “gpt-5”
model_provider = “metapi”
[model_providers.metapi]
name = “metapi”
base_url = “https://your-domain.com/v1”
```
`~/.codex/auth.json`
```json
{
“OPENAI_API_KEY”: “your-proxy-sk-token”
}
```
> 提示:`model` 需要是你在 Metapi `GET /v1/models` 可见的模型名。
### Roo Code / Kilo Code
@@ -83,6 +110,23 @@ export DISABLE_NON_ESSENTIAL_MODEL_CALLS=1
所有支持 OpenAI API 格式的客户端均可接入,只需找到 Base URL 和 API Key 的配置位置即可。
## 下游 API Key 策略
除了全局 `PROXY_TOKEN`,你还可以在 **系统设置 → 下游 API Key 策略** 中创建多个项目级下游 Key,每个 Key 可独立配置:
| 配置项 | 说明 |
|--------|------|
| **过期时间**(ExpiresAt) | Key 到期后自动失效 |
| **费用上限**(MaxCost) | 累计消费超限后拒绝请求 |
| **请求上限**(MaxRequests) | 累计请求数超限后拒绝请求 |
| **模型白名单**(SupportedModels) | 限制可用模型,支持 exact / glob / `re:regex` |
| **路由白名单**(AllowedRouteIds) | 限制可走的路由规则 |
| **站点倍率**(SiteWeightMultipliers) | 按站点调整路由权重,控制上游偏好 |
适用于多团队/多项目共用一个 Metapi 实例但需要独立计量和权限控制的场景。
---
## 快速自检
部署完成后,用以下命令验证链路:
+81
View File
@@ -0,0 +1,81 @@
# FAQ / 教程贡献规范
> 目标:让任何人都可以提交可复用、可检索、可维护的经验内容,避免口口相传丢失。
## 适用范围
- FAQ(常见问题与报错处理)
- 使用教程(从 0 到 1、进阶技巧、集成示例)
- 运维经验(排障、监控、升级、回滚)
## FAQ 模板
复制以下结构提交:
```md
## 问题标题(简短、可搜索)
### 现象
- 具体报错信息:
- 出现场景:
### 根因
- 触发原因 1
- 触发原因 2
### 解决步骤
1. 步骤一
2. 步骤二
3. 验证结果
### 预防建议
- 建议一
- 建议二
```
## 教程模板
复制以下结构提交:
```md
# 教程标题
## 适用人群
- 新手 / 运维 / 集成开发者
## 前置条件
- 条件一
- 条件二
## 操作步骤
1. ...
2. ...
3. ...
## 验证方式
- 成功标准 1
- 成功标准 2
## 常见坑位
- 坑位 1 与规避方式
- 坑位 2 与规避方式
```
## 命名与归档建议
- FAQ 统一追加到 [`/docs/faq.md`](../faq.md)
- 教程建议新增 `docs/community/tutorial-<topic>.md`
- 文件名使用小写英文与 `-`,例如:`tutorial-openwebui.md`
## 提交要求
- 标题可检索:包含关键词(平台名、报错码、功能名)
- 步骤可复现:避免“试一下”“差不多”描述
- 版本要明确:注明适用版本、部署方式
- 结果可验证:给出成功判定标准
## 维护原则
- 过时内容要标记“已失效”并给替代方案
- 同类问题合并,避免 FAQ 膨胀重复
- 优先给“最短修复路径”,再补原理解释
+22
View File
@@ -78,6 +78,28 @@ Metapi 的路由引擎按多因子加权选择最优通道。
示例:`ADMIN_IP_ALLOWLIST=192.168.1.0/24,10.0.0.1`
## 下游 API Key 策略
除了全局 `PROXY_TOKEN`,Metapi 支持在管理后台「设置 → 下游 API Key」中创建多个项目级下游 Key。
每个 Key 可独立配置以下约束:
| 字段 | 说明 | 示例 |
|------|------|------|
| `name` | Key 名称(仅供标识) | `team-backend` |
| `expiresAt` | 过期时间 | `2026-12-31T23:59:59Z` |
| `maxCost` | 累计费用上限 | `100`(超限后拒绝请求) |
| `maxRequests` | 累计请求数上限 | `10000` |
| `supportedModels` | 模型白名单(JSON 数组) | `["gpt-4o", "claude-*", "re:deepseek.*"]` |
| `allowedRouteIds` | 可走的路由 ID 白名单 | `[1, 3, 5]` |
| `siteWeightMultipliers` | 站点权重倍率 | `{"1": 2.0, "3": 0.5}` |
模型白名单支持三种匹配模式:
- **精确匹配**:`gpt-4o`
- **通配符**:`claude-*`(glob 风格)
- **正则表达式**:`re:deepseek.*`(`re:` 前缀)
## 通知渠道
### Webhook
+81
View File
@@ -55,6 +55,57 @@ docker run -d --name metapi \
> - `./data:/app/data` — 相对路径,数据存到当前目录下的 `data` 文件夹
> - 也可以使用绝对路径:`/your/custom/path:/app/data`
## Release 包部署(免 Docker)
适用于没有 Docker 环境的服务器,或 Windows / macOS 桌面使用场景。
### 前置条件
- Node.js 20+(推荐 22 LTS)
### 步骤
1. 从 [Releases](https://github.com/cita-777/metapi/releases) 下载与你系统匹配的压缩包(Linux / Windows / macOS)
2. 解压后进入目录
Linux / macOS:
```bash
export AUTH_TOKEN=your-admin-token
export PROXY_TOKEN=your-proxy-sk-token
export PORT=4000
export DATA_DIR=./data
./start.sh
```
Windows(PowerShell):
```powershell
$env:AUTH_TOKEN="your-admin-token"
$env:PROXY_TOKEN="your-proxy-sk-token"
$env:PORT="4000"
$env:DATA_DIR="./data"
.\start.bat
```
`start.sh` / `start.bat` 的作用是:
- 先检查 `better-sqlite3` 与当前 Node.js ABI 是否兼容
- 若检测到 ABI 不匹配,会自动尝试 `npm rebuild better-sqlite3`
- 若重建失败,会回退到 `npm ci --omit=dev` 重新安装运行时依赖
- 最后执行数据库迁移并启动服务
> [!NOTE]
> 如果本机 Node 主版本与打包时不同(例如包内依赖基于 Node 22,而本机是 Node 24),首次启动可能触发自动重建,需联网。
### Release 包升级
1. 下载新版本的 Release 包
2. 解压覆盖旧文件(`data/` 目录不受影响)
3. 重新启动即可
---
## 反向代理
### Nginx
@@ -151,6 +202,36 @@ Metapi 的所有运行数据存储在 SQLite 数据库中,位于 `DATA_DIR`(
- 保留最近 7~30 天的备份
- 重要操作前手动快照
## 文档站部署
Metapi 使用 [VitePress](https://vitepress.dev) 构建文档站,支持本地预览和 GitHub Pages 自动部署。
### 本地预览
```bash
npm run docs:dev
```
访问 `http://localhost:4173` 查看文档站。
### 构建静态站点
```bash
npm run docs:build
```
构建产物位于 `docs/.vitepress/dist/`,可部署到任意静态站点托管服务。
### GitHub Pages 自动部署
推送到 `main` 分支后,`.github/workflows/docs-pages.yml` 会自动构建并部署到 GitHub Pages。
首次使用需在仓库设置中开启:
`Settings → Pages → Build and deployment → Source: GitHub Actions`
---
## 下一步
- [配置说明](./configuration.md) — 详细环境变量
+31 -1
View File
@@ -36,6 +36,15 @@ docker compose up -d
或使用 `.env` 文件。
### Q: Release 包启动失败
**A:** 排查步骤:
1. 确认 Node.js 已安装且版本 ≥ 20:`node --version`
2. 首次启动时如果报 `better-sqlite3` 相关错误,启动脚本会尝试自动重建,需要网络连接
3. 如果本机 Node 主版本与打包时不同(例如包内依赖基于 Node 22,而本机是 Node 24),首次启动需联网执行 `npm rebuild`
4. Windows 用户确认使用 PowerShell 而非 CMD 运行 `start.bat`
---
## 代理相关
@@ -86,6 +95,23 @@ docker compose up -d
---
## 下游 API Key 相关
### Q: 如何限制不同项目/团队的用量
**A:** 在管理后台 **设置 → 下游 API Key** 中为每个项目创建独立的 Key,可单独配置:
- 费用上限(MaxCost)和请求上限(MaxRequests)
- 模型白名单(限制可用模型,支持通配符和正则)
- 路由白名单(限制可走的路由规则)
- 站点倍率(控制不同项目的上游偏好)
### Q: 下游 Key 和 PROXY_TOKEN 有什么区别
**A:** `PROXY_TOKEN` 是全局代理令牌,拥有完整权限。下游 Key 是项目级的细粒度控制,可设置过期时间、用量上限和模型限制,适合多团队共用的场景。
---
## 签到相关
### Q: 签到一直失败
@@ -128,5 +154,9 @@ docker compose up -d
## 更多帮助
- [提交 Issue](https://github.com/cita-777/metapi/issues) — 报告 Bug 或提出建议
如果以上内容未能解决你的问题:
- [搜索已有 Issue](https://github.com/cita-777/metapi/issues?q=is%3Aissue) — 看看是否有人遇到过相同问题
- [提交新 Issue](https://github.com/cita-777/metapi/issues/new) — 报告 Bug 或提出功能建议
- [参与讨论](https://github.com/cita-777/metapi/discussions) — 使用疑问、经验分享
- [文档中心](./README.md) — 查看所有文档
+32 -2
View File
@@ -9,6 +9,7 @@
## 前置条件
- Docker 与 Docker Compose(推荐)
- 或下载 [Release 包](https://github.com/cita-777/metapi/releases) + Node.js 20+(免 Docker 运行)
- 或 Node.js 20+ 与 npm(本地开发)
## 方式一:Docker Compose 部署(推荐)
@@ -59,7 +60,36 @@ docker compose up -d
> 如果未显式设置(非 Compose 场景),默认值为 `change-me-admin-token`(仅建议本地调试)。
> 若你在后台「设置」里修改过管理员令牌,后续登录请使用新令牌。
## 方式二:本地开发启动
## 方式二:Release 包启动(Linux / macOS / Windows)
如果不想用 Docker,可以直接下载预打包的 Release 产物运行:
1. 打开 [Releases](https://github.com/cita-777/metapi/releases) 下载与你系统匹配的压缩包
2. 解压后进入目录
3. 设置环境变量并启动
Linux / macOS:
```bash
export AUTH_TOKEN=your-admin-token
export PROXY_TOKEN=your-proxy-sk-token
./start.sh
```
Windows(PowerShell):
```powershell
$env:AUTH_TOKEN="your-admin-token"
$env:PROXY_TOKEN="your-proxy-sk-token"
.\start.bat
```
`start.sh` / `start.bat` 会自动检查 `better-sqlite3` ABI 兼容性、执行数据库迁移并启动服务。
> [!NOTE]
> Release 包依赖本机安装 Node.js(支持 20+,推荐 22 LTS)。
## 方式三:本地开发启动
```bash
git clone https://github.com/cita-777/metapi.git
@@ -81,7 +111,7 @@ npm run dev
进入 **站点管理**,添加你使用的上游中转站:
- 填写站点名称和 URL
- 选择平台类型(New API / One API / OneHub 等)
- 选择平台类型(New API / One API / OneHub / DoneHub / Veloera / AnyRouter / Sub2API)
- 填写站点的管理员 API Key(可选,部分功能需要)
### 步骤 2:添加账号
+51
View File
@@ -0,0 +1,51 @@
---
layout: home
hero:
name: "Metapi 文档中心"
text: "中转站的中转站"
tagline: "将分散的 AI 中转站聚合为一个统一网关"
image:
src: /logos/logo-full.png
alt: Metapi
actions:
- theme: brand
text: 10 分钟快速上手
link: /getting-started
- theme: alt
text: 常见问题 FAQ
link: /faq
- theme: alt
text: 贡献教程/FAQ
link: /community/faq-tutorial-guidelines
features:
- title: 快速上手
details: 从部署到第一条请求,按步骤完成最小可用环境搭建。
link: /getting-started
- title: 问题排查
details: 汇总高频报错、根因定位和标准修复路径,降低重复沟通成本。
link: /faq
- title: 运维与配置
details: 覆盖部署、配置、监控、备份、升级回滚等生产场景。
link: /operations
---
## 文档定位
- 面向新用户:快速搭建和接入
- 面向维护者:稳定运行、排障和升级
- 面向贡献者:持续沉淀教程、FAQ 与最佳实践
## 推荐阅读路径
1. [快速上手](/getting-started)
2. [部署指南](/deployment)
3. [配置说明](/configuration)
4. [客户端接入](/client-integration)
5. [常见问题 FAQ](/faq)
## 协作维护
如需新增文档内容,请优先使用统一模板与提交流程:
[FAQ/教程贡献规范](/community/faq-tutorial-guidelines)
+36 -9
View File
@@ -10,23 +10,35 @@ metapi/
├── dist/ # 构建产物(前后端)
├── docker/ # 容器相关文件
│ ├── Dockerfile # 多阶段构建(Alpine)
│ └── docker-compose.yml # Docker Compose 编排
│ ├── docker-compose.yml # Docker Compose 编排
│ └── docker-compose.override.yml # 开发覆盖配置
├── docs/ # 文档与资源
│ ├── .vitepress/ # VitePress 文档站配置
│ ├── community/ # 社区贡献规范
│ ├── logos/ # Logo 素材
│ │ └── drafts/ # Logo 草稿
│ └── project-structure.md
│ ├── screenshots/ # 界面截图
│ └── *.md # 各文档页面
├── drizzle/ # Drizzle ORM 迁移 SQL 与元数据
├── scripts/ # 项目脚本(按场景分组)
│ └── dev/
│ └── restart.bat # Windows 开发环境快捷重启
│ ├── dev/
│ │ └── restart.bat # Windows 开发环境快捷重启
│ └── release/
│ ├── start.sh # Release 包启动脚本(Linux/macOS)
│ └── start.bat # Release 包启动脚本(Windows)
├── src/
│ ├── server/ # Fastify 后端服务
│ └── web/ # React 前端应用
├── .github/workflows/ # CI/CD 工作流
│ ├── ci.yml # 测试与构建检查
│ ├── release.yml # 多平台 Release 包发布
│ └── docs-pages.yml # 文档站 GitHub Pages 部署
├── tmp/ # 临时调试文件(已 gitignore)
├── package.json
├── tsconfig.json
├── tsconfig.server.json
├── vite.config.ts
├── drizzle.config.ts
└── README.md
```
@@ -48,8 +60,8 @@ src/server/
│ │ ├── sites.ts # 站点 CRUD
│ │ ├── accounts.ts # 账号管理
│ │ ├── accountTokens.ts # Token 同步与管理
│ │ ├── tokens.ts # Token 批量操作
│ │ ├── tokenRoutes.ts # 路由规则管理
│ │ ├── tokens.ts # Token 批量操作与路由规则管理
│ │ ├── downstreamApiKeys.ts # 下游 API Key 管理
│ │ ├── checkin.ts # 签到触发与日志
│ │ ├── stats.ts # 仪表盘统计
│ │ ├── search.ts # 全局搜索
@@ -61,11 +73,14 @@ src/server/
│ └── proxy/ # 代理路由
│ ├── router.ts # 代理路由注册
│ ├── chat.ts # Chat Completions & Claude Messages
│ ├── responses.ts # OpenAI Responses 端点
│ ├── completions.ts # Legacy Completions
│ ├── embeddings.ts # 向量嵌入
│ ├── images.ts # 图像生成
│ ├── models.ts # 模型列表
│ └── chatFormats.ts # OpenAI <-> Claude 格式转换
│ ├── chatFormats.ts # OpenAI <-> Claude 格式转换
│ ├── upstreamEndpoint.ts # 上游端点处理与透传
│ └── downstreamPolicy.ts # 下游 API Key 策略校验
└── services/
├── platforms/ # 平台适配器
│ ├── base.ts # 适配器接口定义
@@ -94,6 +109,9 @@ src/server/
├── accountCredentialService.ts # 凭证加密
├── accountHealthService.ts # 健康状态管理
├── accountExtraConfig.ts # 平台专属配置
├── accountTokenService.ts # Token 管理服务
├── downstreamApiKeyService.ts # 下游 API Key 服务
├── downstreamPolicyTypes.ts # 下游策略类型定义
├── proxyRetryPolicy.ts # 重试策略
├── proxyUsageParser.ts # Token 用量解析
├── proxyUsageFallbackService.ts # 余额兜底估算
@@ -116,14 +134,18 @@ src/web/
├── api.ts # 统一 API 请求客户端
├── authSession.ts # 认证会话管理
├── i18n.tsx # 国际化
├── i18n.supplement.ts # 国际化补充翻译
├── components/ # 通用 UI 组件
│ ├── BrandIcon.tsx # 模型品牌图标
│ ├── ChangeKeyModal.tsx # 修改管理令牌弹窗
│ ├── ModelAnalysisPanel.tsx # 消费分析图表
│ ├── ModernSelect.tsx # 自定义下拉选择组件
│ ├── SearchModal.tsx # 全局搜索弹窗
│ ├── NotificationPanel.tsx # 实时事件面板
│ ├── Toast.tsx # 通知提示
│ ├── SiteDistributionChart.tsx # 余额分布饼图
│ └── SiteTrendChart.tsx # 消费趋势图
│ └── charts/ # 图表组件
│ ├── SiteDistributionChart.tsx # 余额分布饼图
│ └── SiteTrendChart.tsx # 消费趋势图
├── pages/ # 页面组件(路由页)
│ ├── Dashboard.tsx # 仪表盘
│ ├── Sites.tsx # 站点管理
@@ -131,9 +153,14 @@ src/web/
│ ├── Tokens.tsx # Token 管理
│ ├── TokenRoutes.tsx # 路由规则
│ ├── Models.tsx # 模型广场
│ ├── ModelTester.tsx # 模型操练场
│ ├── Monitors.tsx # 可用性监控
│ ├── CheckinLog.tsx # 签到日志
│ ├── ProxyLogs.tsx # 代理日志
│ ├── ProgramLogs.tsx # 系统事件日志
│ ├── ImportExport.tsx # 数据导入导出
│ ├── Settings.tsx # 系统设置
│ ├── NotificationSettings.tsx # 通知设置
│ ├── About.tsx # 关于页面
│ └── helpers/ # 页面级纯逻辑 / 工具函数(含测试)
└── public/ # 静态资源