import { useEffect, useState } from "react"; import { Box, Button, Card, Divider, Typography, Chip, Tooltip, CircularProgress, alpha, useTheme, } from "@mui/material"; import Grid from "@mui/material/Grid2"; import { useTranslation } from "react-i18next"; import { invoke } from "@tauri-apps/api/core"; import { BasePage, BaseEmpty } from "@/components/base"; import { useLockFn } from "ahooks"; import { CheckCircleOutlined, CancelOutlined, HelpOutline, PendingOutlined, RefreshRounded, AccessTimeOutlined, } from "@mui/icons-material"; // 定义流媒体检测项类型 interface UnlockItem { name: string; status: string; region?: string | null; check_time?: string | null; } // 用于存储测试结果的本地存储键名 const UNLOCK_RESULTS_STORAGE_KEY = "clash_verge_unlock_results"; const UNLOCK_RESULTS_TIME_KEY = "clash_verge_unlock_time"; const UnlockPage = () => { const { t } = useTranslation(); const theme = useTheme(); // 保存所有流媒体检测项的状态 const [unlockItems, setUnlockItems] = useState([]); // 是否正在执行全部检测 const [isCheckingAll, setIsCheckingAll] = useState(false); // 记录正在检测中的项目 const [loadingItems, setLoadingItems] = useState([]); // 最后检测时间 const [lastCheckTime, setLastCheckTime] = useState(null); // 按首字母排序项目 const sortItemsByName = (items: UnlockItem[]) => { return [...items].sort((a, b) => a.name.localeCompare(b.name)); }; // 保存测试结果到本地存储 const saveResultsToStorage = (items: UnlockItem[], time: string | null) => { try { localStorage.setItem(UNLOCK_RESULTS_STORAGE_KEY, JSON.stringify(items)); if (time) { localStorage.setItem(UNLOCK_RESULTS_TIME_KEY, time); } } catch (err) { console.error("Failed to save results to storage:", err); } }; // 从本地存储加载测试结果 const loadResultsFromStorage = (): { items: UnlockItem[] | null; time: string | null; } => { try { const itemsJson = localStorage.getItem(UNLOCK_RESULTS_STORAGE_KEY); const time = localStorage.getItem(UNLOCK_RESULTS_TIME_KEY); if (itemsJson) { return { items: JSON.parse(itemsJson) as UnlockItem[], time, }; } } catch (err) { console.error("Failed to load results from storage:", err); } return { items: null, time: null }; }; // 页面加载时获取初始检测项列表 useEffect(() => { // 尝试从本地存储加载上次测试结果 const { items: storedItems, time } = loadResultsFromStorage(); if (storedItems && storedItems.length > 0) { // 如果有存储的结果,优先使用 setUnlockItems(storedItems); setLastCheckTime(time); // 后台同时获取最新的初始状态(但不更新UI) getUnlockItems(false); } else { // 没有存储的结果,获取初始状态 getUnlockItems(true); } }, []); // 获取所有解锁检测项列表 const getUnlockItems = async (updateUI: boolean = true) => { try { const items = await invoke("get_unlock_items"); const sortedItems = sortItemsByName(items); if (updateUI) { setUnlockItems(sortedItems); } } catch (err: any) { console.error("Failed to get unlock items:", err); } }; // 执行全部项目检测 const checkAllMedia = useLockFn(async () => { try { setIsCheckingAll(true); const result = await invoke("check_media_unlock"); const sortedItems = sortItemsByName(result); // 更新UI setUnlockItems(sortedItems); const currentTime = new Date().toLocaleString(); setLastCheckTime(currentTime); // 保存结果到本地存储 saveResultsToStorage(sortedItems, currentTime); setIsCheckingAll(false); } catch (err: any) { setIsCheckingAll(false); console.error("Failed to check media unlock:", err); } }); // 根据项目名称检测单个流媒体服务 const checkSingleMedia = useLockFn(async (name: string) => { try { // 将该项目添加到加载状态 setLoadingItems((prev) => [...prev, name]); // 执行检测 const result = await invoke("check_media_unlock"); // 找到对应的检测结果 const targetItem = result.find((item: UnlockItem) => item.name === name); if (targetItem) { // 更新单个检测项结果并按名称排序 const updatedItems = sortItemsByName( unlockItems.map((item: UnlockItem) => item.name === name ? targetItem : item, ), ); // 更新UI setUnlockItems(updatedItems); const currentTime = new Date().toLocaleString(); setLastCheckTime(currentTime); // 保存结果到本地存储 saveResultsToStorage(updatedItems, currentTime); } // 移除加载状态 setLoadingItems((prev) => prev.filter((item) => item !== name)); } catch (err: any) { setLoadingItems((prev) => prev.filter((item) => item !== name)); console.error(`Failed to check ${name}:`, err); } }); // 获取状态对应的颜色 const getStatusColor = (status: string) => { if (status === "Pending") return "default"; if (status === "Yes") return "success"; if (status === "No") return "error"; if (status === "Soon") return "warning"; if (status.includes("Failed")) return "error"; if (status === "Completed") return "info"; if ( status === "Disallowed ISP" || status === "Blocked" || status === "Unsupported Country" ) { return "error"; } return "default"; }; // 获取状态对应的图标 const getStatusIcon = (status: string) => { if (status === "Pending") return ; if (status === "Yes") return ; if (status === "No") return ; if (status === "Soon") return ; if (status.includes("Failed")) return ; return ; }; // 获取状态对应的背景色 const getStatusBgColor = (status: string) => { if (status === "Yes") return alpha(theme.palette.success.main, 0.05); if (status === "No") return alpha(theme.palette.error.main, 0.05); if (status === "Soon") return alpha(theme.palette.warning.main, 0.05); if (status.includes("Failed")) return alpha(theme.palette.error.main, 0.03); if (status === "Completed") return alpha(theme.palette.info.main, 0.05); return "transparent"; }; // 获取状态对应的边框色 const getStatusBorderColor = (status: string) => { if (status === "Yes") return theme.palette.success.main; if (status === "No") return theme.palette.error.main; if (status === "Soon") return theme.palette.warning.main; if (status.includes("Failed")) return theme.palette.error.main; if (status === "Completed") return theme.palette.info.main; return theme.palette.divider; }; const isDark = theme.palette.mode === "dark"; return ( } > {unlockItems.length === 0 ? ( ) : ( {unlockItems.map((item) => ( {item.name} {item.region && ( )} {item.check_time || "-- --"} ))} )} ); }; export default UnlockPage;