mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-04-03 14:36:44 +08:00
fix(provider): persist endpoint auto-select state (#611)
- Add endpointAutoSelect field to ProviderMeta for persistence - Lift autoSelect state from EndpointSpeedTest to ProviderForm - Save auto-select preference when provider is saved - Restore preference when editing existing provider Fixes https://github.com/farion1231/cc-switch/issues/589
This commit is contained in:
@@ -147,6 +147,9 @@ pub struct ProviderMeta {
|
||||
/// 用量查询脚本配置
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub usage_script: Option<UsageScript>,
|
||||
/// 请求地址管理:测速后自动选择最佳端点
|
||||
#[serde(rename = "endpointAutoSelect", skip_serializing_if = "Option::is_none")]
|
||||
pub endpoint_auto_select: Option<bool>,
|
||||
/// 合作伙伴标记(前端使用 isPartner,保持字段名一致)
|
||||
#[serde(rename = "isPartner", skip_serializing_if = "Option::is_none")]
|
||||
pub is_partner: Option<bool>,
|
||||
|
||||
@@ -36,6 +36,8 @@ interface ClaudeFormFieldsProps {
|
||||
isEndpointModalOpen: boolean;
|
||||
onEndpointModalToggle: (open: boolean) => void;
|
||||
onCustomEndpointsChange?: (endpoints: string[]) => void;
|
||||
autoSelect: boolean;
|
||||
onAutoSelectChange: (checked: boolean) => void;
|
||||
|
||||
// Model Selector
|
||||
shouldShowModelSelector: boolean;
|
||||
@@ -83,6 +85,8 @@ export function ClaudeFormFields({
|
||||
isEndpointModalOpen,
|
||||
onEndpointModalToggle,
|
||||
onCustomEndpointsChange,
|
||||
autoSelect,
|
||||
onAutoSelectChange,
|
||||
shouldShowModelSelector,
|
||||
claudeModel,
|
||||
reasoningModel,
|
||||
@@ -170,6 +174,8 @@ export function ClaudeFormFields({
|
||||
initialEndpoints={speedTestEndpoints}
|
||||
visible={isEndpointModalOpen}
|
||||
onClose={() => onEndpointModalToggle(false)}
|
||||
autoSelect={autoSelect}
|
||||
onAutoSelectChange={onAutoSelectChange}
|
||||
onCustomEndpointsChange={onCustomEndpointsChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -25,6 +25,8 @@ interface CodexFormFieldsProps {
|
||||
isEndpointModalOpen: boolean;
|
||||
onEndpointModalToggle: (open: boolean) => void;
|
||||
onCustomEndpointsChange?: (endpoints: string[]) => void;
|
||||
autoSelect: boolean;
|
||||
onAutoSelectChange: (checked: boolean) => void;
|
||||
|
||||
// Model Name
|
||||
shouldShowModelField?: boolean;
|
||||
@@ -50,6 +52,8 @@ export function CodexFormFields({
|
||||
isEndpointModalOpen,
|
||||
onEndpointModalToggle,
|
||||
onCustomEndpointsChange,
|
||||
autoSelect,
|
||||
onAutoSelectChange,
|
||||
shouldShowModelField = true,
|
||||
modelName = "",
|
||||
onModelNameChange,
|
||||
@@ -130,6 +134,8 @@ export function CodexFormFields({
|
||||
initialEndpoints={speedTestEndpoints}
|
||||
visible={isEndpointModalOpen}
|
||||
onClose={() => onEndpointModalToggle(false)}
|
||||
autoSelect={autoSelect}
|
||||
onAutoSelectChange={onAutoSelectChange}
|
||||
onCustomEndpointsChange={onCustomEndpointsChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -30,6 +30,8 @@ interface EndpointSpeedTestProps {
|
||||
initialEndpoints: EndpointCandidate[];
|
||||
visible?: boolean;
|
||||
onClose: () => void;
|
||||
autoSelect: boolean;
|
||||
onAutoSelectChange: (checked: boolean) => void;
|
||||
// 新建模式:当自定义端点列表变化时回传(仅包含 isCustom 的条目)
|
||||
// 编辑模式:不使用此回调,端点直接保存到后端
|
||||
onCustomEndpointsChange?: (urls: string[]) => void;
|
||||
@@ -85,6 +87,8 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
|
||||
initialEndpoints,
|
||||
visible = true,
|
||||
onClose,
|
||||
autoSelect,
|
||||
onAutoSelectChange,
|
||||
onCustomEndpointsChange,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -93,7 +97,6 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
|
||||
);
|
||||
const [customUrl, setCustomUrl] = useState("");
|
||||
const [addError, setAddError] = useState<string | null>(null);
|
||||
const [autoSelect, setAutoSelect] = useState(true);
|
||||
const [isTesting, setIsTesting] = useState(false);
|
||||
const [lastError, setLastError] = useState<string | null>(null);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
@@ -488,7 +491,9 @@ const EndpointSpeedTest: React.FC<EndpointSpeedTestProps> = ({
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={autoSelect}
|
||||
onChange={(event) => setAutoSelect(event.target.checked)}
|
||||
onChange={(event) => {
|
||||
onAutoSelectChange(event.target.checked);
|
||||
}}
|
||||
className="h-3.5 w-3.5 rounded border-border-default bg-background text-primary focus:ring-2 focus:ring-primary/20"
|
||||
/>
|
||||
{t("endpointTest.autoSelect")}
|
||||
|
||||
@@ -29,6 +29,8 @@ interface GeminiFormFieldsProps {
|
||||
isEndpointModalOpen: boolean;
|
||||
onEndpointModalToggle: (open: boolean) => void;
|
||||
onCustomEndpointsChange: (endpoints: string[]) => void;
|
||||
autoSelect: boolean;
|
||||
onAutoSelectChange: (checked: boolean) => void;
|
||||
|
||||
// Model
|
||||
shouldShowModelField: boolean;
|
||||
@@ -55,6 +57,8 @@ export function GeminiFormFields({
|
||||
isEndpointModalOpen,
|
||||
onEndpointModalToggle,
|
||||
onCustomEndpointsChange,
|
||||
autoSelect,
|
||||
onAutoSelectChange,
|
||||
shouldShowModelField,
|
||||
model,
|
||||
onModelChange,
|
||||
@@ -142,6 +146,8 @@ export function GeminiFormFields({
|
||||
initialEndpoints={speedTestEndpoints}
|
||||
visible={isEndpointModalOpen}
|
||||
onClose={() => onEndpointModalToggle(false)}
|
||||
autoSelect={autoSelect}
|
||||
onAutoSelectChange={onAutoSelectChange}
|
||||
onCustomEndpointsChange={onCustomEndpointsChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -124,6 +124,9 @@ export function ProviderForm({
|
||||
return [];
|
||||
},
|
||||
);
|
||||
const [endpointAutoSelect, setEndpointAutoSelect] = useState<boolean>(
|
||||
() => initialData?.meta?.endpointAutoSelect ?? true,
|
||||
);
|
||||
|
||||
// 使用 category hook
|
||||
const { category } = useProviderCategory({
|
||||
@@ -141,6 +144,7 @@ export function ProviderForm({
|
||||
if (!initialData) {
|
||||
setDraftCustomEndpoints([]);
|
||||
}
|
||||
setEndpointAutoSelect(initialData?.meta?.endpointAutoSelect ?? true);
|
||||
}, [appId, initialData]);
|
||||
|
||||
const defaultValues: ProviderFormData = useMemo(
|
||||
@@ -647,6 +651,13 @@ export function ProviderForm({
|
||||
}
|
||||
}
|
||||
|
||||
const baseMeta: ProviderMeta | undefined =
|
||||
payload.meta ?? (initialData?.meta ? { ...initialData.meta } : undefined);
|
||||
payload.meta = {
|
||||
...(baseMeta ?? {}),
|
||||
endpointAutoSelect,
|
||||
};
|
||||
|
||||
onSubmit(payload);
|
||||
};
|
||||
|
||||
@@ -856,6 +867,8 @@ export function ProviderForm({
|
||||
onCustomEndpointsChange={
|
||||
isEditMode ? undefined : setDraftCustomEndpoints
|
||||
}
|
||||
autoSelect={endpointAutoSelect}
|
||||
onAutoSelectChange={setEndpointAutoSelect}
|
||||
shouldShowModelSelector={category !== "official"}
|
||||
claudeModel={claudeModel}
|
||||
reasoningModel={reasoningModel}
|
||||
@@ -889,6 +902,8 @@ export function ProviderForm({
|
||||
onCustomEndpointsChange={
|
||||
isEditMode ? undefined : setDraftCustomEndpoints
|
||||
}
|
||||
autoSelect={endpointAutoSelect}
|
||||
onAutoSelectChange={setEndpointAutoSelect}
|
||||
shouldShowModelField={category !== "official"}
|
||||
modelName={codexModelName}
|
||||
onModelNameChange={handleCodexModelNameChange}
|
||||
@@ -917,6 +932,8 @@ export function ProviderForm({
|
||||
isEndpointModalOpen={isEndpointModalOpen}
|
||||
onEndpointModalToggle={setIsEndpointModalOpen}
|
||||
onCustomEndpointsChange={setDraftCustomEndpoints}
|
||||
autoSelect={endpointAutoSelect}
|
||||
onAutoSelectChange={setEndpointAutoSelect}
|
||||
shouldShowModelField={true}
|
||||
model={geminiModel}
|
||||
onModelChange={handleGeminiModelChange}
|
||||
|
||||
@@ -92,6 +92,8 @@ export interface ProviderMeta {
|
||||
custom_endpoints?: Record<string, CustomEndpoint>;
|
||||
// 用量查询脚本配置
|
||||
usage_script?: UsageScript;
|
||||
// 请求地址管理:测速后自动选择最佳端点
|
||||
endpointAutoSelect?: boolean;
|
||||
// 是否为官方合作伙伴
|
||||
isPartner?: boolean;
|
||||
// 合作伙伴促销 key(用于后端识别 PackyCode 等)
|
||||
|
||||
Reference in New Issue
Block a user