diff --git a/UPDATELOG.md b/UPDATELOG.md
index eccbcd4f..9ada17c8 100644
--- a/UPDATELOG.md
+++ b/UPDATELOG.md
@@ -19,6 +19,11 @@
- 修复通过托盘重启应用无法恢复
- 修复订阅在某些情况下无法导入
- 修复无法新建订阅时使用远程链接
+- 修复卸载服务后的 tun 开关状态问题
+
+### 👙 界面样式
+
+- 统一代理设置样式
### 🗑️ 移除内容
diff --git a/src/components/home/proxy-tun-card.tsx b/src/components/home/proxy-tun-card.tsx
index fe1dc04e..3a6795b9 100644
--- a/src/components/home/proxy-tun-card.tsx
+++ b/src/components/home/proxy-tun-card.tsx
@@ -232,6 +232,7 @@ export const ProxyTunCard: FC = () => {
diff --git a/src/components/setting/setting-system.tsx b/src/components/setting/setting-system.tsx
index 37012d49..c015b4ff 100644
--- a/src/components/setting/setting-system.tsx
+++ b/src/components/setting/setting-system.tsx
@@ -1,29 +1,19 @@
import { mutate } from "swr";
-import { useRef } from "react";
+import React, { useRef } from "react";
import { useTranslation } from "react-i18next";
-import {
- SettingsRounded,
- PlayArrowRounded,
- PauseRounded,
- WarningRounded,
- BuildRounded,
- DeleteForeverRounded,
-} from "@mui/icons-material";
+import { WarningRounded } from "@mui/icons-material";
import { useVerge } from "@/hooks/use-verge";
-import { useSystemProxyState } from "@/hooks/use-system-proxy-state";
import { DialogRef, Switch } from "@/components/base";
import { SettingList, SettingItem } from "./mods/setting-comp";
import { GuardState } from "./mods/guard-state";
import { SysproxyViewer } from "./mods/sysproxy-viewer";
import { TunViewer } from "./mods/tun-viewer";
import { TooltipIcon } from "@/components/base/base-tooltip-icon";
-import { uninstallService, restartCore, stopCore } from "@/services/cmds";
-import { useLockFn } from "ahooks";
-import { Button, Tooltip } from "@mui/material";
+import { Tooltip } from "@mui/material";
import { useSystemState } from "@/hooks/use-system-state";
+import ProxyControlSwitches from "@/components/shared/ProxyControlSwitches";
import { showNotice } from "@/services/noticeService";
-import { useServiceInstaller } from "@/hooks/useServiceInstaller";
interface Props {
onError?: (err: Error) => void;
@@ -33,167 +23,30 @@ const SettingSystem = ({ onError }: Props) => {
const { t } = useTranslation();
const { verge, mutateVerge, patchVerge } = useVerge();
- const { installServiceAndRestartCore } = useServiceInstaller();
- const { actualState: systemProxyActualState, toggleSystemProxy } =
- useSystemProxyState();
- const { isAdminMode, isServiceMode, mutateRunningMode } = useSystemState();
+ const { isAdminMode } = useSystemState();
- // +++ isTunAvailable 现在使用 SWR 的 isServiceMode
- const isTunAvailable = isServiceMode || isAdminMode;
+ const { enable_auto_launch, enable_silent_start } = verge ?? {};
const sysproxyRef = useRef(null);
const tunRef = useRef(null);
- const { enable_tun_mode, enable_auto_launch, enable_silent_start } =
- verge ?? {};
-
- const onSwitchFormat = (_e: any, value: boolean) => value;
+ const onSwitchFormat = (
+ _e: React.ChangeEvent,
+ value: boolean,
+ ) => value;
const onChangeData = (patch: Partial) => {
mutateVerge({ ...verge, ...patch }, false);
};
- // 抽象服务操作逻辑
- const handleServiceOperation = useLockFn(
- async ({
- beforeMsg,
- action,
- actionMsg,
- successMsg,
- }: {
- beforeMsg: string;
- action: () => Promise;
- actionMsg: string;
- successMsg: string;
- }) => {
- try {
- showNotice("info", beforeMsg);
- await stopCore();
- showNotice("info", actionMsg);
- await action();
- showNotice("success", successMsg);
- showNotice("info", t("Restarting Core..."));
- await restartCore();
- await mutateRunningMode();
- } catch (err: any) {
- showNotice("error", err.message || err.toString());
- try {
- showNotice("info", t("Try running core as Sidecar..."));
- await restartCore();
- await mutateRunningMode();
- } catch (e: any) {
- showNotice("error", e?.message || e?.toString());
- }
- }
- },
- );
-
- // 卸载系统服务
- const onUninstallService = () =>
- handleServiceOperation({
- beforeMsg: t("Stopping Core..."),
- action: uninstallService,
- actionMsg: t("Uninstalling Service..."),
- successMsg: t("Service Uninstalled Successfully"),
- });
-
return (
-
- tunRef.current?.open()}
- />
- {!isTunAvailable && (
-
-
-
- )}
- {!isServiceMode && !isAdminMode && (
-
-
-
- )}
- {isServiceMode && (
-
-
-
- )}
- >
- }
- >
- {
- if (!isTunAvailable) return;
- onChangeData({ enable_tun_mode: e });
- }}
- onGuard={(e) => {
- if (!isTunAvailable) {
- showNotice("error", t("TUN requires Service Mode or Admin Mode"));
- return Promise.reject(
- new Error(t("TUN requires Service Mode or Admin Mode")),
- );
- }
- return patchVerge({ enable_tun_mode: e });
- }}
- >
-
-
-
-
- sysproxyRef.current?.open()}
- />
- {systemProxyActualState ? (
-
- ) : (
-
- )}
- >
- }
- >
- toggleSystemProxy(e)}
- >
-
-
-
+
+
+
void;
+ noRightPadding?: boolean;
}
/**
* 可复用的代理控制开关组件
* 包含 Tun Mode 和 System Proxy 的开关功能
*/
-const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
+const ProxyControlSwitches = ({
+ label,
+ onError,
+ noRightPadding = false,
+}: ProxySwitchProps) => {
const { t } = useTranslation();
const { verge, mutateVerge, patchVerge } = useVerge();
const theme = useTheme();
@@ -42,7 +51,7 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
const { actualState: systemProxyActualState, toggleSystemProxy } =
useSystemProxyState();
- const { isAdminMode, isServiceMode } = useSystemState();
+ const { isAdminMode, isServiceMode, mutateRunningMode } = useSystemState();
const isTunAvailable = isServiceMode || isAdminMode;
@@ -55,7 +64,10 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
const isSystemProxyMode = label === t("System Proxy") || !label;
const isTunMode = label === t("Tun Mode");
- const onSwitchFormat = (_e: any, value: boolean) => value;
+ const onSwitchFormat = (
+ _e: React.ChangeEvent,
+ value: boolean,
+ ) => value;
const onChangeData = (patch: Partial) => {
mutateVerge({ ...verge, ...patch }, false);
};
@@ -63,8 +75,31 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
// 安装系统服务
const onInstallService = installServiceAndRestartCore;
+ // 卸载系统服务
+ const onUninstallService = useLockFn(async () => {
+ try {
+ showNotice("info", t("Stopping Core..."));
+ await stopCore();
+ showNotice("info", t("Uninstalling Service..."));
+ await uninstallService();
+ showNotice("success", t("Service Uninstalled Successfully"));
+ showNotice("info", t("Restarting Core..."));
+ await restartCore();
+ await mutateRunningMode();
+ } catch (err: unknown) {
+ showNotice("error", (err as Error).message || err?.toString());
+ try {
+ showNotice("info", t("Try running core as Sidecar..."));
+ await restartCore();
+ await mutateRunningMode();
+ } catch (e: unknown) {
+ showNotice("error", (e as Error)?.message || e?.toString());
+ }
+ }
+ });
+
return (
-
+
{label && (
{
alignItems: "center",
justifyContent: "space-between",
p: 1,
+ pr: noRightPadding ? 1 : 2,
borderRadius: 1.5,
bgcolor: enable_system_proxy
? alpha(theme.palette.success.main, 0.07)
@@ -111,12 +147,6 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
>
{t("System Proxy")}
- {/*
- {sysproxy?.enable
- ? t("Proxy is active")
- : t("Enable this for most users")
- }
- */}
@@ -155,6 +185,7 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
alignItems: "center",
justifyContent: "space-between",
p: 1,
+ pr: noRightPadding ? 1 : 2,
borderRadius: 1.5,
bgcolor: enable_tun_mode
? alpha(theme.palette.success.main, 0.07)
@@ -182,6 +213,15 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
{t("Tun Mode")}
+
+ {!isTunAvailable && (
+
+
+
+ )}
@@ -199,6 +239,19 @@ const ProxyControlSwitches = ({ label, onError }: ProxySwitchProps) => {
)}
+ {isServiceMode && (
+
+
+
+ )}
+
{
+ const { t } = useTranslation();
+ const { isAdminMode, isServiceMode } = useSystemState();
+
const { data: verge, mutate: mutateVerge } = useSWR(
"getVergeConfig",
async () => {
@@ -15,6 +22,29 @@ export const useVerge = () => {
mutateVerge();
};
+ const isTunAvailable = isServiceMode || isAdminMode;
+ const { enable_tun_mode } = verge ?? {};
+
+ // 当服务不可用且TUN模式开启时自动关闭TUN
+ useEffect(() => {
+ if (enable_tun_mode && !isTunAvailable) {
+ console.log("[useVerge] 检测到服务不可用,自动关闭TUN模式");
+
+ patchVergeConfig({ enable_tun_mode: false })
+ .then(() => {
+ mutateVerge();
+ showNotice(
+ "info",
+ t("TUN Mode automatically disabled due to service unavailable"),
+ );
+ })
+ .catch((err) => {
+ console.error("[useVerge] 自动关闭TUN模式失败:", err);
+ showNotice("error", t("Failed to disable TUN Mode automatically"));
+ });
+ }
+ }, [isTunAvailable, enable_tun_mode, mutateVerge, t]);
+
return {
verge,
mutateVerge,
diff --git a/src/locales/en.json b/src/locales/en.json
index 8650e095..b747d5a7 100644
--- a/src/locales/en.json
+++ b/src/locales/en.json
@@ -210,6 +210,8 @@
"Reset to Default": "Reset to Default",
"Tun Mode Info": "Tun (Virtual NIC) mode: Captures all system traffic, when enabled, there is no need to enable system proxy.",
"TUN requires Service Mode or Admin Mode": "TUN requires Service Mode or Admin Mode",
+ "TUN Mode automatically disabled due to service unavailable": "TUN Mode automatically disabled due to service unavailable",
+ "Failed to disable TUN Mode automatically": "Failed to disable TUN Mode automatically",
"System Proxy Enabled": "System proxy is enabled, your applications will access the network through the proxy",
"System Proxy Disabled": "System proxy is disabled, it is recommended for most users to turn on this option",
"TUN Mode Enabled": "TUN mode is enabled, applications will access the network through the virtual network card",
diff --git a/src/locales/zh.json b/src/locales/zh.json
index ac574727..c7a522e4 100644
--- a/src/locales/zh.json
+++ b/src/locales/zh.json
@@ -210,6 +210,8 @@
"Reset to Default": "重置为默认值",
"Tun Mode Info": "TUN(虚拟网卡)模式接管系统所有流量,启用时无须打开系统代理",
"TUN requires Service Mode or Admin Mode": "TUN 模式需要安装服务模式或管理员模式",
+ "TUN Mode automatically disabled due to service unavailable": "由于服务不可用,TUN 模式已自动关闭",
+ "Failed to disable TUN Mode automatically": "自动关闭 TUN 模式失败",
"System Proxy Enabled": "系统代理已启用,您的应用将通过代理访问网络",
"System Proxy Disabled": "系统代理已关闭,建议大多数用户打开此选项",
"TUN Mode Enabled": "TUN 模式已启用,应用将通过虚拟网卡访问网络",