diff --git a/src/components/shared/proxy-control-switches.tsx b/src/components/shared/proxy-control-switches.tsx
index 837312e8b..9210c8703 100644
--- a/src/components/shared/proxy-control-switches.tsx
+++ b/src/components/shared/proxy-control-switches.tsx
@@ -8,11 +8,10 @@ import {
} from '@mui/icons-material'
import { Box, Typography, alpha, useTheme } from '@mui/material'
import { useLockFn } from 'ahooks'
-import React, { useCallback, useRef } from 'react'
+import React, { useCallback, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { DialogRef, Switch, TooltipIcon } from '@/components/base'
-import { GuardState } from '@/components/setting/mods/guard-state'
import { SysproxyViewer } from '@/components/setting/mods/sysproxy-viewer'
import { TunViewer } from '@/components/setting/mods/tun-viewer'
import { useServiceInstaller } from '@/hooks/use-service-installer'
@@ -42,6 +41,7 @@ interface SwitchRowProps {
/**
* 抽取的子组件:统一的开关 UI
+ * active = 真实状态OS/配置 乐观更新
*/
const SwitchRow = ({
label,
@@ -55,6 +55,24 @@ const SwitchRow = ({
highlight,
}: SwitchRowProps) => {
const theme = useTheme()
+ const [checked, setChecked] = useState(active)
+ const pendingRef = useRef(false)
+
+ if (pendingRef.current) {
+ if (active === checked) pendingRef.current = false
+ } else if (checked !== active) {
+ setChecked(active)
+ }
+
+ const handleChange = (_: React.ChangeEvent, value: boolean) => {
+ pendingRef.current = true
+ setChecked(value)
+ onToggle(value).catch((err: any) => {
+ pendingRef.current = false
+ onError?.(err)
+ })
+ }
+
return (
- v}
- onGuard={onToggle}
- >
-
-
+
)
}
diff --git a/src/hooks/use-system-proxy-state.ts b/src/hooks/use-system-proxy-state.ts
index e2d2be991..7b96182f8 100644
--- a/src/hooks/use-system-proxy-state.ts
+++ b/src/hooks/use-system-proxy-state.ts
@@ -1,4 +1,4 @@
-import { useLockFn } from 'ahooks'
+import { useRef } from 'react'
import useSWR, { mutate } from 'swr'
import { closeAllConnections } from 'tauri-plugin-mihomo-api'
@@ -36,28 +36,31 @@ export const useSystemProxyState = () => {
}
})()
- const toggleSystemProxy = useLockFn(async (enabled: boolean) => {
- mutateVerge({ ...verge, enable_system_proxy: enabled }, false)
+ // "最后一次生效"模式:快速连续点击时,只执行最终状态
+ const pendingRef = useRef(null)
+ const busyRef = useRef(false)
- const updateProxyStatus = async () => {
- await new Promise((resolve) => setTimeout(resolve, enabled ? 20 : 10))
- await mutate('getSystemProxy')
- await mutate('getAutotemProxy')
- }
+ const toggleSystemProxy = async (enabled: boolean) => {
+ mutateVerge({ ...verge, enable_system_proxy: enabled }, false)
+ pendingRef.current = enabled
+
+ if (busyRef.current) return
+ busyRef.current = true
try {
- if (!enabled && verge?.auto_close_connection) {
- await closeAllConnections()
+ while (pendingRef.current !== null) {
+ const target = pendingRef.current
+ pendingRef.current = null
+ if (!target && verge?.auto_close_connection) {
+ await closeAllConnections().catch(() => {})
+ }
+ await patchVerge({ enable_system_proxy: target })
}
- await patchVerge({ enable_system_proxy: enabled })
- await updateProxyStatus()
- } catch (error) {
- console.warn('[useSystemProxyState] toggleSystemProxy failed:', error)
- mutateVerge({ ...verge, enable_system_proxy: !enabled }, false)
- await updateProxyStatus()
- throw error
+ } finally {
+ busyRef.current = false
+ await Promise.all([mutate('getSystemProxy'), mutate('getAutotemProxy')])
}
- })
+ }
return {
indicator,