mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-08 18:37:46 +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:
@@ -53,7 +53,7 @@
|
||||
v-for="(group, groupIndex) in fieldGroups"
|
||||
:key="groupIndex"
|
||||
>
|
||||
<!-- 可折叠的分组(如代理配置) -->
|
||||
<!-- 可折叠的分组(代理配置 - 代理节点选择) -->
|
||||
<div
|
||||
v-if="group.collapsible && group.hasToggle && group.toggleKey"
|
||||
class="space-y-2"
|
||||
@@ -65,50 +65,22 @@
|
||||
<span class="text-xs text-muted-foreground">启用代理</span>
|
||||
<Switch
|
||||
:model-value="formData[group.toggleKey] || false"
|
||||
@update:model-value="formData[group.toggleKey] = $event"
|
||||
@update:model-value="handleProxyToggle(group.toggleKey, $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 展开内容(卡片) -->
|
||||
<!-- 展开内容(卡片)- 代理节点选择 -->
|
||||
<div
|
||||
v-if="formData[group.toggleKey]"
|
||||
class="rounded-lg border border-border bg-muted/30 px-4 py-3"
|
||||
>
|
||||
<!-- 横向排列的字段:代理地址占更多空间 -->
|
||||
<div class="flex gap-3">
|
||||
<div
|
||||
v-for="(field, fieldIndex) in group.fields"
|
||||
:key="field.key"
|
||||
class="space-y-1"
|
||||
:class="fieldIndex === 0 ? 'flex-[2]' : 'flex-1'"
|
||||
>
|
||||
<Label class="text-xs text-muted-foreground">
|
||||
{{ field.label }}
|
||||
</Label>
|
||||
|
||||
<!-- 文本输入 -->
|
||||
<Input
|
||||
v-if="field.type === 'text'"
|
||||
v-model="formData[field.key]"
|
||||
:placeholder="field.sensitive ? (sensitivePlaceholders[field.key] || field.placeholder) : field.placeholder"
|
||||
:masked="field.sensitive"
|
||||
disable-autofill
|
||||
class="h-8 text-sm"
|
||||
@update:model-value="handleFieldChange(field.key, $event)"
|
||||
/>
|
||||
|
||||
<!-- 密码/敏感输入 -->
|
||||
<Input
|
||||
v-else-if="field.type === 'password'"
|
||||
v-model="formData[field.key]"
|
||||
:placeholder="sensitivePlaceholders[field.key] || field.placeholder"
|
||||
masked
|
||||
class="h-8 text-sm"
|
||||
@update:model-value="handleFieldChange(field.key, $event)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<ProxyNodeSelect
|
||||
ref="proxyNodeSelectRef"
|
||||
:model-value="formData.proxy_node_id || ''"
|
||||
trigger-class="h-8"
|
||||
@update:model-value="(v: string) => { formData.proxy_node_id = v; handleFieldChange('proxy_node_id', v) }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -304,6 +276,8 @@ import {
|
||||
type AuthTemplate,
|
||||
type AuthTemplateFieldGroup,
|
||||
} from '../auth-templates'
|
||||
import ProxyNodeSelect from './ProxyNodeSelect.vue'
|
||||
import { useProxyNodesStore } from '@/stores/proxy-nodes'
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean
|
||||
@@ -322,6 +296,16 @@ const SENSITIVE_FIELDS = ['api_key', 'password', 'session_token', 'session_cooki
|
||||
|
||||
const { success: showSuccess, error: showError } = useToast()
|
||||
const { confirmDanger } = useConfirm()
|
||||
const proxyNodeSelectRef = ref<InstanceType<typeof ProxyNodeSelect> | null>(null)
|
||||
const proxyNodesStore = useProxyNodesStore()
|
||||
|
||||
/** 启用代理时加载节点列表(直接调用 store,避免 ref 未挂载时静默失败) */
|
||||
function handleProxyToggle(toggleKey: string, value: boolean) {
|
||||
formData.value[toggleKey] = value
|
||||
if (value) {
|
||||
proxyNodesStore.ensureLoaded()
|
||||
}
|
||||
}
|
||||
|
||||
// State
|
||||
const isSaving = ref(false)
|
||||
|
||||
Reference in New Issue
Block a user