feat(admin): 渠道管理 - 模型供应商支持渠道级 SOCKS5/HTTP 代理

- ModelChannel 新增 proxy_url 字段,v48 迁移自动加列
- outbound 新增 OutboundHTTPClientWithProxy,socks5/socks5h/http/https 均支持;
  目标主机名不做本地解析,直接交给代理服务器远端解析,本地开启 TUN/VPN 时仍可用
- 系统代理、Provider 出站、管理员模型测试路径均使用渠道级代理
- 渠道管理表单新增"代理地址"输入框,留空回退全局代理
This commit is contained in:
dxiaom
2026-10-10 00:59:37 +08:00
parent 85c2aa178b
commit 9df34abd6b
13 changed files with 119 additions and 8 deletions

View File

@@ -25,6 +25,7 @@ type ChannelFormValues = {
useGlobalConcurrency?: boolean;
concurrencyLimit?: number;
enabled?: boolean;
proxyUrl?: string;
};
export function adminChannelSavePayload(values: ChannelFormValues) {
@@ -37,6 +38,7 @@ export function adminChannelSavePayload(values: ChannelFormValues) {
useGlobalConcurrency: values.useGlobalConcurrency !== false,
concurrencyLimit: values.useGlobalConcurrency === false ? values.concurrencyLimit : undefined,
enabled: values.enabled !== false,
proxyUrl: values.proxyUrl?.trim() || "",
};
}
@@ -129,8 +131,9 @@ export default function ChannelsPage() {
useGlobalConcurrency: !channel.concurrencyLimit,
concurrencyLimit: channel.concurrencyLimit || undefined,
enabled: channel.enabled !== false,
proxyUrl: channel.proxyUrl || "",
}
: { name: "", baseUrl: "", apiKey: "", secretKey: "", headers: [], useGlobalConcurrency: true, concurrencyLimit: undefined, enabled: true },
: { name: "", baseUrl: "", apiKey: "", secretKey: "", headers: [], useGlobalConcurrency: true, concurrencyLimit: undefined, enabled: true, proxyUrl: "" },
);
setDrawerOpen(true);
};
@@ -393,6 +396,13 @@ export default function ChannelsPage() {
<ChannelHeadersEditor />
</Form.Item>
</div>
<Form.Item
name="proxyUrl"
label="代理地址"
extra="为该渠道单独配置出站代理,支持 socks5://、http://、https://。留空则使用全局环境变量代理。"
>
<Input placeholder="例如:socks5://127.0.0.1:1080 或 http://127.0.0.1:7890" />
</Form.Item>
<Form.Item name="useGlobalConcurrency" label="跟随系统并发配置" valuePropName="checked">
<Switch />
</Form.Item>

View File

@@ -88,6 +88,7 @@ export type ModelChannel = {
hasApiKey?: boolean;
hasSecretKey?: boolean;
concurrencyLimit?: number;
proxyUrl?: string;
modelCosts?: Array<{
model: string;
displayName?: string;