mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
feat(keys): 新增 Provider Keys 批量删除 API
- 后端新增 POST /keys/batch-delete 接口,支持一次删除最多 100 个 Key - 按 provider_id 聚合执行副作用,避免逐个删除导致的重复 Redis 操作 - 前端批量操作对话框中删除操作改用批量 API,按 100 个一批分批调用
This commit is contained in:
@@ -83,6 +83,20 @@ export async function deleteEndpointKey(keyId: string): Promise<{ message: strin
|
||||
return response.data
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除 Keys
|
||||
*/
|
||||
export interface BatchDeleteKeysResult {
|
||||
success_count: number
|
||||
failed_count: number
|
||||
failed: Array<{ id: string; error: string }>
|
||||
}
|
||||
|
||||
export async function batchDeleteEndpointKeys(ids: string[]): Promise<BatchDeleteKeysResult> {
|
||||
const response = await client.post('/api/admin/endpoints/keys/batch-delete', { ids })
|
||||
return response.data
|
||||
}
|
||||
|
||||
|
||||
// ========== Provider 级别的 Keys API ==========
|
||||
|
||||
|
||||
@@ -267,7 +267,7 @@ import { useToast } from '@/composables/useToast'
|
||||
import { useConfirm } from '@/composables/useConfirm'
|
||||
import { parseApiError } from '@/utils/errorParser'
|
||||
import { listPoolKeys, type PoolKeyDetail } from '@/api/endpoints/pool'
|
||||
import { deleteEndpointKey, refreshProviderQuota, updateProviderKey } from '@/api/endpoints/keys'
|
||||
import { batchDeleteEndpointKeys, refreshProviderQuota, updateProviderKey } from '@/api/endpoints/keys'
|
||||
import { refreshProviderOAuth } from '@/api/endpoints/provider_oauth'
|
||||
import { useProxyNodesStore } from '@/stores/proxy-nodes'
|
||||
import { hasNoFiveHourLimit as hasNoFiveHourLimitByQuota, hasNoWeeklyLimit as hasNoWeeklyLimitByQuota } from '@/features/pool/utils/quota-selectors'
|
||||
@@ -617,14 +617,34 @@ async function executeAction(): Promise<void> {
|
||||
failedCount += batch.length
|
||||
}
|
||||
|
||||
progressDone.value = Math.min(i + BATCH_SIZE, targetIds.length)
|
||||
}
|
||||
} else if (selectedAction.value === 'delete') {
|
||||
// 使用批量删除 API,按 100 个一批分批调用(后端限制 max_length=100)
|
||||
const targetIds = selectedKeys.map((key) => key.key_id)
|
||||
const BATCH_SIZE = 100
|
||||
const totalBatches = Math.ceil(targetIds.length / BATCH_SIZE)
|
||||
|
||||
for (let i = 0; i < targetIds.length; i += BATCH_SIZE) {
|
||||
const batchIndex = Math.floor(i / BATCH_SIZE) + 1
|
||||
const batch = targetIds.slice(i, i + BATCH_SIZE)
|
||||
if (totalBatches > 1) {
|
||||
progressLabel.value = `正在${actionLabel}...(第 ${batchIndex}/${totalBatches} 批)`
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await batchDeleteEndpointKeys(batch)
|
||||
successCount += result.success_count
|
||||
failedCount += result.failed_count
|
||||
} catch {
|
||||
failedCount += batch.length
|
||||
}
|
||||
|
||||
progressDone.value = Math.min(i + BATCH_SIZE, targetIds.length)
|
||||
}
|
||||
} else {
|
||||
const CONCURRENCY = props.batchConcurrency || 8
|
||||
const taskForKey = (key: PoolKeyDetail): (() => Promise<'success' | 'skip'>) | null => {
|
||||
if (selectedAction.value === 'delete') {
|
||||
return () => deleteEndpointKey(key.key_id).then(() => 'success' as const)
|
||||
}
|
||||
if (selectedAction.value === 'refresh_oauth') {
|
||||
if (normalizeText(key.auth_type) !== 'oauth') return null
|
||||
return () => refreshProviderOAuth(key.key_id).then(() => 'success' as const)
|
||||
|
||||
Reference in New Issue
Block a user