import { BaseDialog, DialogRef, Switch } from "@/components/base"; import { useClashInfo } from "@/hooks/use-clash"; import { useVerge } from "@/hooks/use-verge"; import { showNotice } from "@/services/noticeService"; import { ContentCopy } from "@mui/icons-material"; import { Alert, Box, CircularProgress, IconButton, List, ListItem, ListItemText, Snackbar, TextField, Tooltip, } from "@mui/material"; import { useLockFn } from "ahooks"; import { forwardRef, useImperativeHandle, useState } from "react"; import { useTranslation } from "react-i18next"; export const ControllerViewer = forwardRef((props, ref) => { const { t } = useTranslation(); const [open, setOpen] = useState(false); const [copySuccess, setCopySuccess] = useState(null); const [isSaving, setIsSaving] = useState(false); const { clashInfo, patchInfo } = useClashInfo(); const { verge, patchVerge } = useVerge(); const [controller, setController] = useState(clashInfo?.server || ""); const [secret, setSecret] = useState(clashInfo?.secret || ""); const [enableController, setEnableController] = useState( verge?.enable_external_controller ?? false, ); // 对话框打开时初始化配置 useImperativeHandle(ref, () => ({ open: async () => { setOpen(true); setController(clashInfo?.server || ""); setSecret(clashInfo?.secret || ""); setEnableController(verge?.enable_external_controller ?? false); }, close: () => setOpen(false), })); // 保存配置 const onSave = useLockFn(async () => { try { setIsSaving(true); // 先保存 enable_external_controller 设置 await patchVerge({ enable_external_controller: enableController }); // 如果启用了外部控制器,则保存控制器地址和密钥 if (enableController) { if (!controller.trim()) { showNotice("error", t("Controller address cannot be empty")); return; } if (!secret.trim()) { showNotice("error", t("Secret cannot be empty")); return; } await patchInfo({ "external-controller": controller, secret }); } else { // 如果禁用了外部控制器,则清空控制器地址 await patchInfo({ "external-controller": "" }); } showNotice("success", t("Configuration saved successfully")); setOpen(false); } catch (err: any) { showNotice( "error", err.message || t("Failed to save configuration"), 4000, ); } finally { setIsSaving(false); } }); // 复制到剪贴板 const handleCopyToClipboard = useLockFn( async (text: string, type: string) => { try { await navigator.clipboard.writeText(text); setCopySuccess(type); setTimeout(() => setCopySuccess(null)); } catch (err) { console.warn("[ControllerViewer] copy to clipboard failed:", err); showNotice("error", t("Failed to copy")); } }, ); return ( {t("Saving...")} ) : ( t("Save") ) } cancelBtn={t("Cancel")} onClose={() => setOpen(false)} onCancel={() => setOpen(false)} onOk={onSave} > setEnableController(e.target.checked)} disabled={isSaving} /> setController(e.target.value)} disabled={isSaving || !enableController} /> handleCopyToClipboard(controller, "controller")} color="primary" disabled={isSaving || !enableController} > setSecret(e.target.value)} disabled={isSaving || !enableController} /> handleCopyToClipboard(secret, "secret")} color="primary" disabled={isSaving || !enableController} > {copySuccess === "controller" ? t("Controller address copied to clipboard") : t("Secret copied to clipboard")} ); });