feat: 添加API Key时间窗口限流功能并移除累计总量限制

- 新增时间窗口限流功能,支持按分钟设置时间窗口
- 支持在时间窗口内限制请求次数和Token使用量
- 移除原有的累计总量限制,只保留时间窗口限制
- Token统计包含所有4种类型:输入、输出、缓存创建、缓存读取
- 前端UI优化,明确显示限流参数的作用范围
- 限流触发时提供友好的错误提示和重置时间

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-20 15:58:00 +08:00
parent 0aa986a0d8
commit 088ce266ba
7 changed files with 224 additions and 16 deletions

View File

@@ -117,6 +117,8 @@ const app = createApp({
tokenLimit: '',
description: '',
concurrencyLimit: '',
rateLimitWindow: '',
rateLimitRequests: '',
claudeAccountId: '',
enableModelRestriction: false,
restrictedModels: [],
@@ -158,6 +160,8 @@ const app = createApp({
name: '',
tokenLimit: '',
concurrencyLimit: '',
rateLimitWindow: '',
rateLimitRequests: '',
claudeAccountId: '',
enableModelRestriction: false,
restrictedModels: [],
@@ -1211,6 +1215,8 @@ const app = createApp({
tokenLimit: this.apiKeyForm.tokenLimit && this.apiKeyForm.tokenLimit.trim() ? parseInt(this.apiKeyForm.tokenLimit) : null,
description: this.apiKeyForm.description || '',
concurrencyLimit: this.apiKeyForm.concurrencyLimit && this.apiKeyForm.concurrencyLimit.trim() ? parseInt(this.apiKeyForm.concurrencyLimit) : 0,
rateLimitWindow: this.apiKeyForm.rateLimitWindow && this.apiKeyForm.rateLimitWindow.trim() ? parseInt(this.apiKeyForm.rateLimitWindow) : null,
rateLimitRequests: this.apiKeyForm.rateLimitRequests && this.apiKeyForm.rateLimitRequests.trim() ? parseInt(this.apiKeyForm.rateLimitRequests) : null,
claudeAccountId: this.apiKeyForm.claudeAccountId || null,
enableModelRestriction: this.apiKeyForm.enableModelRestriction,
restrictedModels: this.apiKeyForm.restrictedModels
@@ -1231,7 +1237,7 @@ const app = createApp({
// 关闭创建弹窗并清理表单
this.showCreateApiKeyModal = false;
this.apiKeyForm = { name: '', tokenLimit: '', description: '', concurrencyLimit: '', claudeAccountId: '', enableModelRestriction: false, restrictedModels: [], modelInput: '' };
this.apiKeyForm = { name: '', tokenLimit: '', description: '', concurrencyLimit: '', rateLimitWindow: '', rateLimitRequests: '', claudeAccountId: '', enableModelRestriction: false, restrictedModels: [], modelInput: '' };
// 重新加载API Keys列表
await this.loadApiKeys();
@@ -1275,6 +1281,8 @@ const app = createApp({
name: key.name,
tokenLimit: key.tokenLimit || '',
concurrencyLimit: key.concurrencyLimit || '',
rateLimitWindow: key.rateLimitWindow || '',
rateLimitRequests: key.rateLimitRequests || '',
claudeAccountId: key.claudeAccountId || '',
enableModelRestriction: key.enableModelRestriction || false,
restrictedModels: key.restrictedModels ? [...key.restrictedModels] : [],
@@ -1290,6 +1298,8 @@ const app = createApp({
name: '',
tokenLimit: '',
concurrencyLimit: '',
rateLimitWindow: '',
rateLimitRequests: '',
claudeAccountId: '',
enableModelRestriction: false,
restrictedModels: [],
@@ -1309,6 +1319,8 @@ const app = createApp({
body: JSON.stringify({
tokenLimit: this.editApiKeyForm.tokenLimit && this.editApiKeyForm.tokenLimit.toString().trim() !== '' ? parseInt(this.editApiKeyForm.tokenLimit) : 0,
concurrencyLimit: this.editApiKeyForm.concurrencyLimit && this.editApiKeyForm.concurrencyLimit.toString().trim() !== '' ? parseInt(this.editApiKeyForm.concurrencyLimit) : 0,
rateLimitWindow: this.editApiKeyForm.rateLimitWindow && this.editApiKeyForm.rateLimitWindow.toString().trim() !== '' ? parseInt(this.editApiKeyForm.rateLimitWindow) : 0,
rateLimitRequests: this.editApiKeyForm.rateLimitRequests && this.editApiKeyForm.rateLimitRequests.toString().trim() !== '' ? parseInt(this.editApiKeyForm.rateLimitRequests) : 0,
claudeAccountId: this.editApiKeyForm.claudeAccountId || null,
enableModelRestriction: this.editApiKeyForm.enableModelRestriction,
restrictedModels: this.editApiKeyForm.restrictedModels