mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-24 12:44:18 +08:00
refactor(health-check): remove per-provider test config
This commit is contained in:
@@ -20,7 +20,7 @@ export function FirstRunNoticeDialog() {
|
||||
const { data: settings } = useSettingsQuery();
|
||||
|
||||
// 后端启动时已经决定好要不要弹:条件不满足的话字段会立即被写成 true,
|
||||
// 所以前端这里只需要判空即可——完全对齐 streamCheckConfirmed 等既有 flag 的模式。
|
||||
// 所以前端这里只需要判空即可——与其他既有确认标记的模式一致。
|
||||
const isOpen = settings != null && settings.firstRunNoticeConfirmed !== true;
|
||||
|
||||
const handleAcknowledge = async () => {
|
||||
|
||||
@@ -174,7 +174,7 @@ export function EditProviderDialog({
|
||||
}, [
|
||||
open, // 修复:编辑保存后再次打开显示旧数据,依赖 open 确保每次打开时重新读取最新 provider 数据
|
||||
provider?.id, // 只依赖 ID,provider 对象更新不会触发重新计算
|
||||
provider?.meta, // 需要依赖 meta 以便正确初始化 testConfig
|
||||
provider?.meta, // 供应商元数据变化时重新初始化表单
|
||||
initialSettingsConfig,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { HealthStatus } from "@/lib/api/model-test";
|
||||
import type { HealthStatus } from "@/lib/api/connectivity-check";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
interface HealthStatusIndicatorProps {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useState, useEffect } from "react";
|
||||
import { ChevronDown, ChevronRight, FlaskConical, Coins } from "lucide-react";
|
||||
import { ChevronDown, ChevronRight, Coins } from "lucide-react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
@@ -12,8 +12,6 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { cn } from "@/lib/utils";
|
||||
import type { ProviderTestConfig } from "@/types";
|
||||
|
||||
export type PricingModelSourceOption = "inherit" | "request" | "response";
|
||||
|
||||
interface ProviderPricingConfig {
|
||||
@@ -23,170 +21,25 @@ interface ProviderPricingConfig {
|
||||
}
|
||||
|
||||
interface ProviderAdvancedConfigProps {
|
||||
testConfig: ProviderTestConfig;
|
||||
pricingConfig: ProviderPricingConfig;
|
||||
onTestConfigChange: (config: ProviderTestConfig) => void;
|
||||
onPricingConfigChange: (config: ProviderPricingConfig) => void;
|
||||
}
|
||||
|
||||
export function ProviderAdvancedConfig({
|
||||
testConfig,
|
||||
pricingConfig,
|
||||
onTestConfigChange,
|
||||
onPricingConfigChange,
|
||||
}: ProviderAdvancedConfigProps) {
|
||||
const { t } = useTranslation();
|
||||
const [isTestConfigOpen, setIsTestConfigOpen] = useState(testConfig.enabled);
|
||||
const [isPricingConfigOpen, setIsPricingConfigOpen] = useState(
|
||||
pricingConfig.enabled,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
setIsTestConfigOpen(testConfig.enabled);
|
||||
}, [testConfig.enabled]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsPricingConfigOpen(pricingConfig.enabled);
|
||||
}, [pricingConfig.enabled]);
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="rounded-lg border border-border/50 bg-muted/20">
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full items-center justify-between p-4 hover:bg-muted/30 transition-colors"
|
||||
onClick={() => setIsTestConfigOpen(!isTestConfigOpen)}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<FlaskConical className="h-4 w-4 text-muted-foreground" />
|
||||
<span className="font-medium">
|
||||
{t("providerAdvanced.testConfig", {
|
||||
defaultValue: "连通检测配置",
|
||||
})}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div
|
||||
className="flex items-center gap-2"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Label
|
||||
htmlFor="test-config-enabled"
|
||||
className="text-sm text-muted-foreground"
|
||||
>
|
||||
{t("providerAdvanced.useCustomConfig", {
|
||||
defaultValue: "使用单独配置",
|
||||
})}
|
||||
</Label>
|
||||
<Switch
|
||||
id="test-config-enabled"
|
||||
checked={testConfig.enabled}
|
||||
onCheckedChange={(checked) => {
|
||||
onTestConfigChange({ ...testConfig, enabled: checked });
|
||||
if (checked) setIsTestConfigOpen(true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{isTestConfigOpen ? (
|
||||
<ChevronDown className="h-4 w-4 text-muted-foreground" />
|
||||
) : (
|
||||
<ChevronRight className="h-4 w-4 text-muted-foreground" />
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
<div
|
||||
className={cn(
|
||||
"overflow-hidden transition-all duration-200",
|
||||
isTestConfigOpen
|
||||
? "max-h-[500px] opacity-100"
|
||||
: "max-h-0 opacity-0",
|
||||
)}
|
||||
>
|
||||
<div className="border-t border-border/50 p-4 space-y-4">
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{t("providerAdvanced.testConfigDesc", {
|
||||
defaultValue:
|
||||
"为此供应商配置单独的连通检测参数(超时/阈值/重试),不启用时使用全局配置。",
|
||||
})}
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="test-timeout">
|
||||
{t("providerAdvanced.timeoutSecs", {
|
||||
defaultValue: "超时时间(秒)",
|
||||
})}
|
||||
</Label>
|
||||
<Input
|
||||
id="test-timeout"
|
||||
type="number"
|
||||
min={1}
|
||||
max={60}
|
||||
value={testConfig.timeoutSecs || ""}
|
||||
onChange={(e) =>
|
||||
onTestConfigChange({
|
||||
...testConfig,
|
||||
timeoutSecs: e.target.value
|
||||
? parseInt(e.target.value, 10)
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
placeholder="8"
|
||||
disabled={!testConfig.enabled}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="degraded-threshold">
|
||||
{t("providerAdvanced.degradedThreshold", {
|
||||
defaultValue: "降级阈值(毫秒)",
|
||||
})}
|
||||
</Label>
|
||||
<Input
|
||||
id="degraded-threshold"
|
||||
type="number"
|
||||
min={100}
|
||||
max={60000}
|
||||
value={testConfig.degradedThresholdMs || ""}
|
||||
onChange={(e) =>
|
||||
onTestConfigChange({
|
||||
...testConfig,
|
||||
degradedThresholdMs: e.target.value
|
||||
? parseInt(e.target.value, 10)
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
placeholder="6000"
|
||||
disabled={!testConfig.enabled}
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="max-retries">
|
||||
{t("providerAdvanced.maxRetries", {
|
||||
defaultValue: "最大重试次数",
|
||||
})}
|
||||
</Label>
|
||||
<Input
|
||||
id="max-retries"
|
||||
type="number"
|
||||
min={0}
|
||||
max={5}
|
||||
value={testConfig.maxRetries ?? ""}
|
||||
onChange={(e) =>
|
||||
onTestConfigChange({
|
||||
...testConfig,
|
||||
maxRetries: e.target.value
|
||||
? parseInt(e.target.value, 10)
|
||||
: undefined,
|
||||
})
|
||||
}
|
||||
placeholder="1"
|
||||
disabled={!testConfig.enabled}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 计费配置 */}
|
||||
<div className="rounded-lg border border-border/50 bg-muted/20">
|
||||
<button
|
||||
|
||||
@@ -17,7 +17,6 @@ import { useDarkMode } from "@/hooks/useDarkMode";
|
||||
import type {
|
||||
ProviderCategory,
|
||||
ProviderMeta,
|
||||
ProviderTestConfig,
|
||||
ClaudeApiFormat,
|
||||
CodexApiFormat,
|
||||
CodexCatalogModel,
|
||||
@@ -313,9 +312,6 @@ function ProviderFormFull({
|
||||
return initialData?.meta?.isFullUrl ?? false;
|
||||
});
|
||||
|
||||
const [testConfig, setTestConfig] = useState<ProviderTestConfig>(
|
||||
() => initialData?.meta?.testConfig ?? { enabled: false },
|
||||
);
|
||||
const [pricingConfig, setPricingConfig] = useState<{
|
||||
enabled: boolean;
|
||||
costMultiplier?: string;
|
||||
@@ -351,7 +347,6 @@ function ProviderFormFull({
|
||||
setLocalIsFullUrl(
|
||||
supportsFullUrl ? (initialData?.meta?.isFullUrl ?? false) : false,
|
||||
);
|
||||
setTestConfig(initialData?.meta?.testConfig ?? { enabled: false });
|
||||
setPricingConfig({
|
||||
enabled:
|
||||
initialData?.meta?.costMultiplier !== undefined ||
|
||||
@@ -1497,7 +1492,6 @@ function ProviderFormFull({
|
||||
localProxyRequestOverrides: shouldApplyLocalProxyRequestOverrides
|
||||
? overridesResult.overrides
|
||||
: undefined,
|
||||
testConfig: testConfig.enabled ? testConfig : undefined,
|
||||
costMultiplier: pricingConfig.enabled
|
||||
? pricingConfig.costMultiplier
|
||||
: undefined,
|
||||
@@ -2469,9 +2463,7 @@ function ProviderFormFull({
|
||||
appId !== "openclaw" &&
|
||||
appId !== "hermes" && (
|
||||
<ProviderAdvancedConfig
|
||||
testConfig={testConfig}
|
||||
pricingConfig={pricingConfig}
|
||||
onTestConfigChange={setTestConfig}
|
||||
onPricingConfigChange={setPricingConfig}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -47,7 +47,7 @@ import { BackupListSection } from "@/components/settings/BackupListSection";
|
||||
import { WebdavSyncSection } from "@/components/settings/WebdavSyncSection";
|
||||
import { AboutSection } from "@/components/settings/AboutSection";
|
||||
import { ProxyTabContent } from "@/components/settings/ProxyTabContent";
|
||||
import { ModelTestConfigPanel } from "@/components/usage/ModelTestConfigPanel";
|
||||
import { ConnectivityCheckConfigPanel } from "@/components/usage/ConnectivityCheckConfigPanel";
|
||||
import { UsageDashboard } from "@/components/usage/UsageDashboard";
|
||||
import { LogConfigPanel } from "@/components/settings/LogConfigPanel";
|
||||
import { AuthCenterPanel } from "@/components/settings/AuthCenterPanel";
|
||||
@@ -455,7 +455,7 @@ export function SettingsPage({
|
||||
</AccordionItem>
|
||||
|
||||
<AccordionItem
|
||||
value="test"
|
||||
value="connectivityCheck"
|
||||
className="rounded-xl glass-card overflow-hidden"
|
||||
>
|
||||
<AccordionTrigger className="px-6 py-4 hover:no-underline hover:bg-muted/50 data-[state=open]:bg-muted/50">
|
||||
@@ -463,16 +463,18 @@ export function SettingsPage({
|
||||
<FlaskConical className="h-5 w-5 text-emerald-500" />
|
||||
<div className="text-left">
|
||||
<h3 className="text-base font-semibold">
|
||||
{t("settings.advanced.modelTest.title")}
|
||||
{t("settings.advanced.connectivityCheck.title")}
|
||||
</h3>
|
||||
<p className="text-sm text-muted-foreground font-normal">
|
||||
{t("settings.advanced.modelTest.description")}
|
||||
{t(
|
||||
"settings.advanced.connectivityCheck.description",
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="px-6 pb-6 pt-4 border-t border-border/50">
|
||||
<ModelTestConfigPanel />
|
||||
<ConnectivityCheckConfigPanel />
|
||||
</AccordionContent>
|
||||
</AccordionItem>
|
||||
|
||||
|
||||
+2
-2
@@ -10,9 +10,9 @@ import {
|
||||
getStreamCheckConfig,
|
||||
saveStreamCheckConfig,
|
||||
type StreamCheckConfig,
|
||||
} from "@/lib/api/model-test";
|
||||
} from "@/lib/api/connectivity-check";
|
||||
|
||||
export function ModelTestConfigPanel() {
|
||||
export function ConnectivityCheckConfigPanel() {
|
||||
const { t } = useTranslation();
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
Reference in New Issue
Block a user