diff --git a/frontend/src/features/providers/components/ProviderDetailDrawer.vue b/frontend/src/features/providers/components/ProviderDetailDrawer.vue
index a652f19..edd1a0d 100644
--- a/frontend/src/features/providers/components/ProviderDetailDrawer.vue
+++ b/frontend/src/features/providers/components/ProviderDetailDrawer.vue
@@ -325,10 +325,31 @@
class="text-muted-foreground/40"
>/
- {{ API_FORMAT_SHORT[format] || format }} {{ getKeyRateMultiplier(key, format) }}x{{ getFormatProbeCountdown(key, format) }}
+ {{ API_FORMAT_SHORT[format] || format }}
+ {{ getKeyRateMultiplier(key, format) }}x
+ handleMultiplierKeydown(e, key, format)"
+ @blur="handleMultiplierBlur(key, format)"
+ >
+ {{ getFormatProbeCountdown(key, format) }}
- | {{ key.rate_limit }}rpm
@@ -765,6 +786,13 @@ const editingPriorityValue = ref(0)
const priorityInputRef = ref(null)
const prioritySaving = ref(false)
+// 点击编辑倍率相关状态
+const editingMultiplierKey = ref(null)
+const editingMultiplierFormat = ref(null)
+const editingMultiplierValue = ref(1.0)
+const multiplierInputRef = ref(null)
+const multiplierSaving = ref(false)
+
// 任意模态窗口打开时,阻止抽屉被误关闭
const hasBlockingDialogOpen = computed(() =>
endpointDialogOpen.value ||
@@ -1338,6 +1366,96 @@ async function savePriority(key: EndpointAPIKey) {
}
}
+// ===== 点击编辑倍率 =====
+function startEditMultiplier(key: EndpointAPIKey, format: string) {
+ editingMultiplierKey.value = key.id
+ editingMultiplierFormat.value = format
+ editingMultiplierValue.value = getKeyRateMultiplier(key, format)
+ multiplierSaving.value = false
+ nextTick(() => {
+ const input = Array.isArray(multiplierInputRef.value) ? multiplierInputRef.value[0] : multiplierInputRef.value
+ input?.focus()
+ input?.select()
+ })
+}
+
+function cancelEditMultiplier() {
+ editingMultiplierKey.value = null
+ editingMultiplierFormat.value = null
+ multiplierSaving.value = false
+}
+
+function handleMultiplierKeydown(e: KeyboardEvent, key: EndpointAPIKey, format: string) {
+ if (e.key === 'Enter') {
+ e.preventDefault()
+ e.stopPropagation()
+ if (!multiplierSaving.value) {
+ multiplierSaving.value = true
+ saveMultiplier(key, format)
+ }
+ } else if (e.key === 'Escape') {
+ e.preventDefault()
+ cancelEditMultiplier()
+ }
+}
+
+function handleMultiplierBlur(key: EndpointAPIKey, format: string) {
+ if (multiplierSaving.value) return
+ saveMultiplier(key, format)
+}
+
+async function saveMultiplier(key: EndpointAPIKey, format: string) {
+ // 防止重复调用
+ if (multiplierSaving.value) return
+ multiplierSaving.value = true
+
+ const keyId = editingMultiplierKey.value
+ const newMultiplier = parseFloat(String(editingMultiplierValue.value))
+
+ // 验证输入有效性
+ if (!keyId || isNaN(newMultiplier)) {
+ showError('请输入有效的倍率值')
+ cancelEditMultiplier()
+ return
+ }
+
+ // 验证合理范围
+ if (newMultiplier <= 0 || newMultiplier > 100) {
+ showError('倍率必须在 0.01 到 100 之间')
+ cancelEditMultiplier()
+ return
+ }
+
+ // 如果倍率没有变化,直接取消编辑(使用精度容差比较浮点数)
+ const currentMultiplier = getKeyRateMultiplier(key, format)
+ if (Math.abs(currentMultiplier - newMultiplier) < 0.0001) {
+ cancelEditMultiplier()
+ return
+ }
+
+ cancelEditMultiplier()
+
+ try {
+ // 构建 rate_multipliers 对象
+ const rateMultipliers = { ...(key.rate_multipliers || {}) }
+ rateMultipliers[format] = newMultiplier
+
+ await updateProviderKey(keyId, { rate_multipliers: rateMultipliers })
+ showSuccess('倍率已更新')
+
+ // 更新本地数据
+ const keyToUpdate = providerKeys.value.find(k => k.id === keyId)
+ if (keyToUpdate) {
+ keyToUpdate.rate_multipliers = rateMultipliers
+ }
+ emit('refresh')
+ } catch (err: any) {
+ showError(err.response?.data?.detail || '更新倍率失败', '错误')
+ } finally {
+ multiplierSaving.value = false
+ }
+}
+
// ===== 密钥列表拖拽排序 =====
function handleKeyDragStart(event: DragEvent, index: number) {
keyDragState.value.isDragging = true