mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-09 10:57:03 +08:00
feat: 手动代理节点支持、系统默认代理与跨格式流式 usage 提取
代理节点: - 支持手动添加代理节点(HTTP/HTTPS/SOCKS5),含地址、认证信息和区域标签 - 新增手动节点的 CRUD API 和前端管理界面 - 提供商代理配置从 URL 字符串迁移至代理节点选择器(proxy_node_id) - 新增系统默认代理节点设置,未单独配置代理的提供商自动回退使用 - 删除节点时自动清除系统默认代理引用并失效缓存 - 健康检查跳过手动节点(无心跳,始终在线) 流式处理: - CLI handler 跨格式转换时委托基类解析 Provider 原始事件的 usage - StreamProcessor 新增 _extract_usage_from_converted_event 从转换后事件补充提取 usage - 支持 Claude/OpenAI/OpenAI Responses/Gemini 多种 usage 格式
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div class="space-y-1.5">
|
||||
<Select
|
||||
:model-value="modelValue"
|
||||
:disabled="proxyNodesStore.loading || nodeOptions.length === 0"
|
||||
@update:model-value="(v: string) => $emit('update:modelValue', v)"
|
||||
>
|
||||
<SelectTrigger :class="triggerClass">
|
||||
<SelectValue
|
||||
:placeholder="proxyNodesStore.loading
|
||||
? '加载节点列表中...'
|
||||
: nodeOptions.length === 0
|
||||
? '暂无可用节点'
|
||||
: '选择代理节点...'"
|
||||
/>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem
|
||||
v-for="node in nodeOptions"
|
||||
:key="node.id"
|
||||
:value="node.id"
|
||||
>
|
||||
{{ node.name }}{{ node.region ? ` · ${node.region}` : '' }} ({{ node.ip }}:{{ node.port }})
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<p
|
||||
v-if="!proxyNodesStore.loading && nodeOptions.length === 0"
|
||||
class="text-xs text-muted-foreground"
|
||||
>
|
||||
暂无在线代理节点,请在「代理节点」页面添加
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import {
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
} from '@/components/ui'
|
||||
import { useProxyNodesStore } from '@/stores/proxy-nodes'
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: string
|
||||
triggerClass?: string
|
||||
}>()
|
||||
|
||||
defineEmits<{
|
||||
'update:modelValue': [value: string]
|
||||
}>()
|
||||
|
||||
const proxyNodesStore = useProxyNodesStore()
|
||||
|
||||
/** 在线节点 + 保留当前已选节点(可能已离线) */
|
||||
const nodeOptions = computed(() => {
|
||||
const online = proxyNodesStore.onlineNodes
|
||||
if (props.modelValue) {
|
||||
const found = online.find(n => n.id === props.modelValue)
|
||||
if (!found) {
|
||||
const allNode = proxyNodesStore.nodes.find(n => n.id === props.modelValue)
|
||||
if (allNode) return [allNode, ...online]
|
||||
}
|
||||
}
|
||||
return online
|
||||
})
|
||||
|
||||
/** 供父组件调用:启用代理时懒加载节点列表 */
|
||||
function ensureLoaded() {
|
||||
proxyNodesStore.ensureLoaded()
|
||||
}
|
||||
|
||||
defineExpose({ ensureLoaded })
|
||||
</script>
|
||||
Reference in New Issue
Block a user