mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
refactor: 完善拖拽排序逻辑并新增格式转换开关
- 修复 PriorityManagementDialog 中 provider 和 key 的拖拽排序逻辑 - 修复 ProviderDetailDrawer 中 key 的拖拽排序逻辑 - 被拖动项单独成组,其他同组项保持在一起 - 在系统设置中新增"启用格式自动转换"配置项
This commit is contained in:
@@ -728,7 +728,8 @@ function handleProviderDrop(dropIndex: number) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const providers = sortedProviders.value
|
const providers = sortedProviders.value
|
||||||
const draggedItem = providers[draggedProvider.value]
|
const dragIndex = draggedProvider.value
|
||||||
|
const draggedItem = providers[dragIndex]
|
||||||
const targetItem = providers[dropIndex]
|
const targetItem = providers[dropIndex]
|
||||||
const draggedPriority = draggedItem.provider_priority
|
const draggedPriority = draggedItem.provider_priority
|
||||||
const targetPriority = targetItem.provider_priority
|
const targetPriority = targetItem.provider_priority
|
||||||
@@ -740,33 +741,43 @@ function handleProviderDrop(dropIndex: number) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 收集所有唯一的优先级并排序
|
// 记录每个 provider 的原始优先级
|
||||||
const uniquePriorities = [...new Set(providers.map(p => p.provider_priority))].sort((a, b) => a - b)
|
const originalPriorityMap = new Map<string, number>()
|
||||||
|
providers.forEach(p => {
|
||||||
// 找到被拖动组和目标组的索引
|
originalPriorityMap.set(p.id, p.provider_priority)
|
||||||
const draggedGroupIndex = uniquePriorities.indexOf(draggedPriority)
|
|
||||||
const targetGroupIndex = uniquePriorities.indexOf(targetPriority)
|
|
||||||
|
|
||||||
// 移动优先级组
|
|
||||||
uniquePriorities.splice(draggedGroupIndex, 1)
|
|
||||||
uniquePriorities.splice(targetGroupIndex, 0, draggedPriority)
|
|
||||||
|
|
||||||
// 创建旧优先级到新优先级的映射(按顺序重新分配 1, 2, 3...)
|
|
||||||
const priorityMap = new Map<number, number>()
|
|
||||||
uniquePriorities.forEach((oldPriority, index) => {
|
|
||||||
priorityMap.set(oldPriority, index + 1)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更新所有 provider 的优先级
|
// 重排数组:将被拖动项移到目标位置
|
||||||
providers.forEach(provider => {
|
const items = [...providers]
|
||||||
const newPriority = priorityMap.get(provider.provider_priority)
|
items.splice(dragIndex, 1)
|
||||||
if (newPriority !== undefined) {
|
items.splice(dropIndex, 0, draggedItem)
|
||||||
provider.provider_priority = newPriority
|
|
||||||
|
// 按新顺序分配优先级:被拖动项单独成组,其他同组项保持在一起
|
||||||
|
const groupNewPriority = new Map<number, number>()
|
||||||
|
let currentPriority = 1
|
||||||
|
|
||||||
|
items.forEach(provider => {
|
||||||
|
const originalPriority = originalPriorityMap.get(provider.id)!
|
||||||
|
|
||||||
|
if (provider === draggedItem) {
|
||||||
|
// 被拖动的项单独成组
|
||||||
|
provider.provider_priority = currentPriority
|
||||||
|
currentPriority++
|
||||||
|
} else {
|
||||||
|
if (groupNewPriority.has(originalPriority)) {
|
||||||
|
// 同组的其他项使用相同的新优先级
|
||||||
|
provider.provider_priority = groupNewPriority.get(originalPriority)!
|
||||||
|
} else {
|
||||||
|
// 新组,分配新优先级
|
||||||
|
groupNewPriority.set(originalPriority, currentPriority)
|
||||||
|
provider.provider_priority = currentPriority
|
||||||
|
currentPriority++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 重新排序
|
// 重新排序
|
||||||
sortedProviders.value = [...providers].sort((a, b) => a.provider_priority - b.provider_priority)
|
sortedProviders.value = [...items].sort((a, b) => a.provider_priority - b.provider_priority)
|
||||||
draggedProvider.value = null
|
draggedProvider.value = null
|
||||||
dragOverProvider.value = null
|
dragOverProvider.value = null
|
||||||
}
|
}
|
||||||
@@ -814,33 +825,43 @@ function handleKeyDrop(format: string, dropIndex: number) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 收集所有唯一的优先级并排序
|
// 记录每个 key 的原始优先级
|
||||||
const uniquePriorities = [...new Set(keys.map(k => k.priority))].sort((a, b) => a - b)
|
const originalPriorityMap = new Map<string, number>()
|
||||||
|
keys.forEach(k => {
|
||||||
// 找到被拖动组和目标组的索引
|
originalPriorityMap.set(k.id, k.priority)
|
||||||
const draggedGroupIndex = uniquePriorities.indexOf(draggedPriority)
|
|
||||||
const targetGroupIndex = uniquePriorities.indexOf(targetPriority)
|
|
||||||
|
|
||||||
// 移动优先级组
|
|
||||||
uniquePriorities.splice(draggedGroupIndex, 1)
|
|
||||||
uniquePriorities.splice(targetGroupIndex, 0, draggedPriority)
|
|
||||||
|
|
||||||
// 创建旧优先级到新优先级的映射(按顺序重新分配 1, 2, 3...)
|
|
||||||
const priorityMap = new Map<number, number>()
|
|
||||||
uniquePriorities.forEach((oldPriority, index) => {
|
|
||||||
priorityMap.set(oldPriority, index + 1)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更新所有 key 的优先级
|
// 重排数组:将被拖动项移到目标位置
|
||||||
keys.forEach(key => {
|
const items = [...keys]
|
||||||
const newPriority = priorityMap.get(key.priority)
|
items.splice(dragIndex, 1)
|
||||||
if (newPriority !== undefined) {
|
items.splice(dropIndex, 0, draggedItem)
|
||||||
key.priority = newPriority
|
|
||||||
|
// 按新顺序分配优先级:被拖动项单独成组,其他同组项保持在一起
|
||||||
|
const groupNewPriority = new Map<number, number>()
|
||||||
|
let currentPriority = 1
|
||||||
|
|
||||||
|
items.forEach(key => {
|
||||||
|
const originalPriority = originalPriorityMap.get(key.id)!
|
||||||
|
|
||||||
|
if (key === draggedItem) {
|
||||||
|
// 被拖动的项单独成组
|
||||||
|
key.priority = currentPriority
|
||||||
|
currentPriority++
|
||||||
|
} else {
|
||||||
|
if (groupNewPriority.has(originalPriority)) {
|
||||||
|
// 同组的其他项使用相同的新优先级
|
||||||
|
key.priority = groupNewPriority.get(originalPriority)!
|
||||||
|
} else {
|
||||||
|
// 新组,分配新优先级
|
||||||
|
groupNewPriority.set(originalPriority, currentPriority)
|
||||||
|
key.priority = currentPriority
|
||||||
|
currentPriority++
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 按优先级重新排序
|
// 按优先级重新排序
|
||||||
keysByFormat.value[format] = [...keys].sort((a, b) => a.priority - b.priority)
|
keysByFormat.value[format] = [...items].sort((a, b) => a.priority - b.priority)
|
||||||
draggedKey.value[format] = null
|
draggedKey.value[format] = null
|
||||||
dragOverKey.value[format] = null
|
dragOverKey.value[format] = null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1118,27 +1118,46 @@ async function handleKeyDrop(event: DragEvent, targetIndex: number) {
|
|||||||
handleKeyDragEnd()
|
handleKeyDragEnd()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// 收集所有唯一的优先级并排序
|
// 记录每个 key 的原始优先级
|
||||||
const uniquePriorities = [...new Set(keys.map(k => k.internal_priority ?? 0))].sort((a, b) => a - b)
|
const originalPriorityMap = new Map<string, number>()
|
||||||
|
keys.forEach(k => {
|
||||||
// 找到被拖动组和目标组的索引
|
originalPriorityMap.set(k.id, k.internal_priority ?? 0)
|
||||||
const draggedGroupIndex = uniquePriorities.indexOf(draggedPriority)
|
|
||||||
const targetGroupIndex = uniquePriorities.indexOf(targetPriority)
|
|
||||||
|
|
||||||
// 移动优先级组
|
|
||||||
uniquePriorities.splice(draggedGroupIndex, 1)
|
|
||||||
uniquePriorities.splice(targetGroupIndex, 0, draggedPriority)
|
|
||||||
|
|
||||||
// 创建旧优先级到新优先级的映射(按顺序重新分配 1, 2, 3...)
|
|
||||||
const priorityMap = new Map<number, number>()
|
|
||||||
uniquePriorities.forEach((oldPriority, index) => {
|
|
||||||
priorityMap.set(oldPriority, index + 1)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 更新所有 key 的优先级
|
// 重排数组:将被拖动项移到目标位置
|
||||||
|
const items = [...keys]
|
||||||
|
items.splice(draggedIndex, 1)
|
||||||
|
items.splice(targetIndex, 0, draggedKey)
|
||||||
|
|
||||||
|
// 按新顺序分配优先级:被拖动项单独成组,其他同组项保持在一起
|
||||||
|
const groupNewPriority = new Map<number, number>()
|
||||||
|
let currentPriority = 1
|
||||||
|
const newPriorityMap = new Map<string, number>()
|
||||||
|
|
||||||
|
items.forEach(key => {
|
||||||
|
const originalPriority = originalPriorityMap.get(key.id)!
|
||||||
|
|
||||||
|
if (key === draggedKey) {
|
||||||
|
// 被拖动的项单独成组
|
||||||
|
newPriorityMap.set(key.id, currentPriority)
|
||||||
|
currentPriority++
|
||||||
|
} else {
|
||||||
|
if (groupNewPriority.has(originalPriority)) {
|
||||||
|
// 同组的其他项使用相同的新优先级
|
||||||
|
newPriorityMap.set(key.id, groupNewPriority.get(originalPriority)!)
|
||||||
|
} else {
|
||||||
|
// 新组,分配新优先级
|
||||||
|
groupNewPriority.set(originalPriority, currentPriority)
|
||||||
|
newPriorityMap.set(key.id, currentPriority)
|
||||||
|
currentPriority++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 更新所有优先级发生变化的 key
|
||||||
const updatePromises = keys.map(key => {
|
const updatePromises = keys.map(key => {
|
||||||
const oldPriority = key.internal_priority ?? 0
|
const oldPriority = key.internal_priority ?? 0
|
||||||
const newPriority = priorityMap.get(oldPriority)
|
const newPriority = newPriorityMap.get(key.id)
|
||||||
if (newPriority !== undefined && oldPriority !== newPriority) {
|
if (newPriority !== undefined && oldPriority !== newPriority) {
|
||||||
return updateProviderKey(key.id, { internal_priority: newPriority })
|
return updateProviderKey(key.id, { internal_priority: newPriority })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -187,6 +187,26 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center h-full">
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<Checkbox
|
||||||
|
id="format-conversion-enabled"
|
||||||
|
v-model:checked="systemConfig.format_conversion_enabled"
|
||||||
|
/>
|
||||||
|
<div>
|
||||||
|
<Label
|
||||||
|
for="format-conversion-enabled"
|
||||||
|
class="cursor-pointer"
|
||||||
|
>
|
||||||
|
启用格式自动转换
|
||||||
|
</Label>
|
||||||
|
<p class="text-xs text-muted-foreground">
|
||||||
|
允许网关在 OpenAI/Claude/Gemini 格式间自动转换
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</CardSection>
|
</CardSection>
|
||||||
|
|
||||||
@@ -834,6 +854,8 @@ interface SystemConfig {
|
|||||||
enable_registration: boolean
|
enable_registration: boolean
|
||||||
// 独立余额 Key 过期管理
|
// 独立余额 Key 过期管理
|
||||||
auto_delete_expired_keys: boolean
|
auto_delete_expired_keys: boolean
|
||||||
|
// 格式转换
|
||||||
|
format_conversion_enabled: boolean
|
||||||
// 日志记录
|
// 日志记录
|
||||||
request_log_level: string
|
request_log_level: string
|
||||||
max_request_body_size: number
|
max_request_body_size: number
|
||||||
@@ -886,6 +908,8 @@ const systemConfig = ref<SystemConfig>({
|
|||||||
enable_registration: false,
|
enable_registration: false,
|
||||||
// 独立余额 Key 过期管理
|
// 独立余额 Key 过期管理
|
||||||
auto_delete_expired_keys: false,
|
auto_delete_expired_keys: false,
|
||||||
|
// 格式转换
|
||||||
|
format_conversion_enabled: false,
|
||||||
// 日志记录
|
// 日志记录
|
||||||
request_log_level: 'basic',
|
request_log_level: 'basic',
|
||||||
max_request_body_size: 1048576,
|
max_request_body_size: 1048576,
|
||||||
@@ -911,7 +935,8 @@ const hasBasicConfigChanges = computed(() => {
|
|||||||
systemConfig.value.default_user_quota_usd !== originalConfig.value.default_user_quota_usd ||
|
systemConfig.value.default_user_quota_usd !== originalConfig.value.default_user_quota_usd ||
|
||||||
systemConfig.value.rate_limit_per_minute !== originalConfig.value.rate_limit_per_minute ||
|
systemConfig.value.rate_limit_per_minute !== originalConfig.value.rate_limit_per_minute ||
|
||||||
systemConfig.value.enable_registration !== originalConfig.value.enable_registration ||
|
systemConfig.value.enable_registration !== originalConfig.value.enable_registration ||
|
||||||
systemConfig.value.auto_delete_expired_keys !== originalConfig.value.auto_delete_expired_keys
|
systemConfig.value.auto_delete_expired_keys !== originalConfig.value.auto_delete_expired_keys ||
|
||||||
|
systemConfig.value.format_conversion_enabled !== originalConfig.value.format_conversion_enabled
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -988,6 +1013,8 @@ async function loadSystemConfig() {
|
|||||||
'enable_registration',
|
'enable_registration',
|
||||||
// 独立余额 Key 过期管理
|
// 独立余额 Key 过期管理
|
||||||
'auto_delete_expired_keys',
|
'auto_delete_expired_keys',
|
||||||
|
// 格式转换
|
||||||
|
'format_conversion_enabled',
|
||||||
// 日志记录
|
// 日志记录
|
||||||
'request_log_level',
|
'request_log_level',
|
||||||
'max_request_body_size',
|
'max_request_body_size',
|
||||||
@@ -1045,6 +1072,11 @@ async function saveBasicConfig() {
|
|||||||
value: systemConfig.value.auto_delete_expired_keys,
|
value: systemConfig.value.auto_delete_expired_keys,
|
||||||
description: '是否自动删除过期的API Key'
|
description: '是否自动删除过期的API Key'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'format_conversion_enabled',
|
||||||
|
value: systemConfig.value.format_conversion_enabled,
|
||||||
|
description: '是否启用全局格式自动转换'
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@@ -1058,6 +1090,7 @@ async function saveBasicConfig() {
|
|||||||
originalConfig.value.rate_limit_per_minute = systemConfig.value.rate_limit_per_minute
|
originalConfig.value.rate_limit_per_minute = systemConfig.value.rate_limit_per_minute
|
||||||
originalConfig.value.enable_registration = systemConfig.value.enable_registration
|
originalConfig.value.enable_registration = systemConfig.value.enable_registration
|
||||||
originalConfig.value.auto_delete_expired_keys = systemConfig.value.auto_delete_expired_keys
|
originalConfig.value.auto_delete_expired_keys = systemConfig.value.auto_delete_expired_keys
|
||||||
|
originalConfig.value.format_conversion_enabled = systemConfig.value.format_conversion_enabled
|
||||||
}
|
}
|
||||||
success('基础配置已保存')
|
success('基础配置已保存')
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
Reference in New Issue
Block a user