mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-18 08:21:34 +08:00
Compare commits
2 Commits
c3aba3fc79
...
7a06a5a069
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a06a5a069 | ||
|
|
99bbd7ee5a |
@ -7,13 +7,17 @@ import {
|
|||||||
} from '@mui/icons-material'
|
} from '@mui/icons-material'
|
||||||
import { Typography, Stack, Divider, Chip, IconButton } from '@mui/material'
|
import { Typography, Stack, Divider, Chip, IconButton } from '@mui/material'
|
||||||
import { useLockFn } from 'ahooks'
|
import { useLockFn } from 'ahooks'
|
||||||
import { useCallback, useEffect, useMemo, useReducer } from 'react'
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router'
|
||||||
|
|
||||||
import { useServiceInstaller } from '@/hooks/use-service-installer'
|
import { useServiceInstaller } from '@/hooks/use-service-installer'
|
||||||
import { useSystemState } from '@/hooks/use-system-state'
|
import { useSystemState } from '@/hooks/use-system-state'
|
||||||
import { useUpdate } from '@/hooks/use-update'
|
import {
|
||||||
|
useUpdate,
|
||||||
|
updateLastCheckTime,
|
||||||
|
readLastCheckTime,
|
||||||
|
} from '@/hooks/use-update'
|
||||||
import { useVerge } from '@/hooks/use-verge'
|
import { useVerge } from '@/hooks/use-verge'
|
||||||
import { getSystemInfo } from '@/services/cmds'
|
import { getSystemInfo } from '@/services/cmds'
|
||||||
import { showNotice } from '@/services/notice-service'
|
import { showNotice } from '@/services/notice-service'
|
||||||
@ -21,29 +25,6 @@ import { version as appVersion } from '@root/package.json'
|
|||||||
|
|
||||||
import { EnhancedCard } from './enhanced-card'
|
import { EnhancedCard } from './enhanced-card'
|
||||||
|
|
||||||
interface SystemState {
|
|
||||||
osInfo: string
|
|
||||||
lastCheckUpdate: string
|
|
||||||
}
|
|
||||||
|
|
||||||
type SystemStateAction =
|
|
||||||
| { type: 'set-os-info'; payload: string }
|
|
||||||
| { type: 'set-last-check-update'; payload: string }
|
|
||||||
|
|
||||||
const systemStateReducer = (
|
|
||||||
state: SystemState,
|
|
||||||
action: SystemStateAction,
|
|
||||||
): SystemState => {
|
|
||||||
switch (action.type) {
|
|
||||||
case 'set-os-info':
|
|
||||||
return { ...state, osInfo: action.payload }
|
|
||||||
case 'set-last-check-update':
|
|
||||||
return { ...state, lastCheckUpdate: action.payload }
|
|
||||||
default:
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const SystemInfoCard = () => {
|
export const SystemInfoCard = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { verge, patchVerge } = useVerge()
|
const { verge, patchVerge } = useVerge()
|
||||||
@ -51,28 +32,18 @@ export const SystemInfoCard = () => {
|
|||||||
const { isAdminMode, isSidecarMode } = useSystemState()
|
const { isAdminMode, isSidecarMode } = useSystemState()
|
||||||
const { installServiceAndRestartCore } = useServiceInstaller()
|
const { installServiceAndRestartCore } = useServiceInstaller()
|
||||||
|
|
||||||
// 自动检查更新逻辑
|
// 自动检查更新逻辑(lastCheckUpdate 由 useUpdate 统一管理)
|
||||||
const { checkUpdate: triggerCheckUpdate } = useUpdate(true, {
|
const { checkUpdate: triggerCheckUpdate, lastCheckUpdate } = useUpdate(true)
|
||||||
onSuccess: () => {
|
|
||||||
const now = Date.now()
|
|
||||||
localStorage.setItem('last_check_update', now.toString())
|
|
||||||
dispatchSystemState({
|
|
||||||
type: 'set-last-check-update',
|
|
||||||
payload: new Date(now).toLocaleString(),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// 系统信息状态
|
const [osInfo, setOsInfo] = useState('')
|
||||||
const [systemState, dispatchSystemState] = useReducer(systemStateReducer, {
|
|
||||||
osInfo: '',
|
const lastCheckUpdateText = useMemo(
|
||||||
lastCheckUpdate: '-',
|
() => (lastCheckUpdate ? new Date(lastCheckUpdate).toLocaleString() : '-'),
|
||||||
})
|
[lastCheckUpdate],
|
||||||
|
)
|
||||||
|
|
||||||
// 初始化系统信息
|
// 初始化系统信息
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let timeoutId: number | undefined
|
|
||||||
|
|
||||||
getSystemInfo()
|
getSystemInfo()
|
||||||
.then((info) => {
|
.then((info) => {
|
||||||
const lines = info.split('\n')
|
const lines = info.split('\n')
|
||||||
@ -87,49 +58,23 @@ export const SystemInfoCard = () => {
|
|||||||
sysVersion = sysVersion.substring(sysName.length).trim()
|
sysVersion = sysVersion.substring(sysName.length).trim()
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchSystemState({
|
setOsInfo(`${sysName} ${sysVersion}`)
|
||||||
type: 'set-os-info',
|
|
||||||
payload: `${sysName} ${sysVersion}`,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(console.error)
|
.catch(console.error)
|
||||||
|
}, [])
|
||||||
|
|
||||||
// 获取最后检查更新时间
|
// 如果启用了自动检查更新但没有记录,设置当前时间并延迟检查
|
||||||
const lastCheck = localStorage.getItem('last_check_update')
|
useEffect(() => {
|
||||||
if (lastCheck) {
|
if (!verge?.auto_check_update) return
|
||||||
try {
|
if (readLastCheckTime() !== null) return
|
||||||
const timestamp = parseInt(lastCheck, 10)
|
|
||||||
if (!isNaN(timestamp)) {
|
|
||||||
dispatchSystemState({
|
|
||||||
type: 'set-last-check-update',
|
|
||||||
payload: new Date(timestamp).toLocaleString(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Error parsing last check update time', e)
|
|
||||||
}
|
|
||||||
} else if (verge?.auto_check_update) {
|
|
||||||
// 如果启用了自动检查更新但没有记录,设置当前时间并延迟检查
|
|
||||||
const now = Date.now()
|
|
||||||
localStorage.setItem('last_check_update', now.toString())
|
|
||||||
dispatchSystemState({
|
|
||||||
type: 'set-last-check-update',
|
|
||||||
payload: new Date(now).toLocaleString(),
|
|
||||||
})
|
|
||||||
|
|
||||||
timeoutId = window.setTimeout(() => {
|
updateLastCheckTime()
|
||||||
if (verge?.auto_check_update) {
|
const timeoutId = window.setTimeout(() => {
|
||||||
triggerCheckUpdate().catch(console.error)
|
triggerCheckUpdate().catch(console.error)
|
||||||
}
|
}, 5000)
|
||||||
}, 5000)
|
return () => window.clearTimeout(timeoutId)
|
||||||
}
|
}, [verge?.auto_check_update, triggerCheckUpdate])
|
||||||
return () => {
|
|
||||||
if (timeoutId !== undefined) {
|
|
||||||
window.clearTimeout(timeoutId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [verge?.auto_check_update, dispatchSystemState, triggerCheckUpdate])
|
|
||||||
|
|
||||||
// 导航到设置页面
|
// 导航到设置页面
|
||||||
const goToSettings = useCallback(() => {
|
const goToSettings = useCallback(() => {
|
||||||
@ -157,12 +102,6 @@ export const SystemInfoCard = () => {
|
|||||||
const onCheckUpdate = useLockFn(async () => {
|
const onCheckUpdate = useLockFn(async () => {
|
||||||
try {
|
try {
|
||||||
const info = await triggerCheckUpdate()
|
const info = await triggerCheckUpdate()
|
||||||
const now = Date.now()
|
|
||||||
localStorage.setItem('last_check_update', now.toString())
|
|
||||||
dispatchSystemState({
|
|
||||||
type: 'set-last-check-update',
|
|
||||||
payload: new Date(now).toLocaleString(),
|
|
||||||
})
|
|
||||||
if (!info?.available) {
|
if (!info?.available) {
|
||||||
showNotice.success(
|
showNotice.success(
|
||||||
'settings.components.verge.advanced.notifications.latestVersion',
|
'settings.components.verge.advanced.notifications.latestVersion',
|
||||||
@ -280,7 +219,7 @@ export const SystemInfoCard = () => {
|
|||||||
{t('home.components.systemInfo.fields.osInfo')}
|
{t('home.components.systemInfo.fields.osInfo')}
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography variant="body2" fontWeight="medium">
|
<Typography variant="body2" fontWeight="medium">
|
||||||
{systemState.osInfo}
|
{osInfo}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Divider />
|
<Divider />
|
||||||
@ -341,7 +280,7 @@ export const SystemInfoCard = () => {
|
|||||||
'&:hover': { opacity: 0.7 },
|
'&:hover': { opacity: 0.7 },
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{systemState.lastCheckUpdate}
|
{lastCheckUpdateText}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Stack>
|
</Stack>
|
||||||
<Divider />
|
<Divider />
|
||||||
|
|||||||
@ -78,7 +78,6 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
const handleDnsToggle = useLockFn(async (enable: boolean) => {
|
const handleDnsToggle = useLockFn(async (enable: boolean) => {
|
||||||
try {
|
try {
|
||||||
setDnsSettingsEnabled(enable)
|
setDnsSettingsEnabled(enable)
|
||||||
localStorage.setItem('dns_settings_enabled', String(enable))
|
|
||||||
await patchVerge({ enable_dns_settings: enable })
|
await patchVerge({ enable_dns_settings: enable })
|
||||||
await invoke('apply_dns_config', { apply: enable })
|
await invoke('apply_dns_config', { apply: enable })
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -86,7 +85,6 @@ const SettingClash = ({ onError }: Props) => {
|
|||||||
}, 500)
|
}, 500)
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
setDnsSettingsEnabled(!enable)
|
setDnsSettingsEnabled(!enable)
|
||||||
localStorage.setItem('dns_settings_enabled', String(!enable))
|
|
||||||
showNotice.error(err)
|
showNotice.error(err)
|
||||||
await patchVerge({ enable_dns_settings: !enable }).catch(() => {})
|
await patchVerge({ enable_dns_settings: !enable }).catch(() => {})
|
||||||
throw err
|
throw err
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { useCallback, useRef } from 'react'
|
|||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
import { DialogRef, TooltipIcon } from '@/components/base'
|
import { DialogRef, TooltipIcon } from '@/components/base'
|
||||||
|
import { updateLastCheckTime } from '@/hooks/use-update'
|
||||||
import {
|
import {
|
||||||
exitApp,
|
exitApp,
|
||||||
exportDiagnosticInfo,
|
exportDiagnosticInfo,
|
||||||
@ -45,6 +46,7 @@ const SettingVergeAdvanced = ({ onError: _ }: Props) => {
|
|||||||
const onCheckUpdate = async () => {
|
const onCheckUpdate = async () => {
|
||||||
try {
|
try {
|
||||||
const info = await checkUpdate()
|
const info = await checkUpdate()
|
||||||
|
updateLastCheckTime()
|
||||||
if (!info?.available) {
|
if (!info?.available) {
|
||||||
showNotice.success(
|
showNotice.success(
|
||||||
'settings.components.verge.advanced.notifications.latestVersion',
|
'settings.components.verge.advanced.notifications.latestVersion',
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import useSWR, { SWRConfiguration } from 'swr'
|
import useSWR, { mutate as globalMutate, SWRConfiguration } from 'swr'
|
||||||
|
|
||||||
import { checkUpdateSafe } from '@/services/update'
|
import { checkUpdateSafe } from '@/services/update'
|
||||||
|
|
||||||
@ -12,6 +12,26 @@ export interface UpdateInfo {
|
|||||||
downloadAndInstall: (onEvent?: any) => Promise<void>
|
downloadAndInstall: (onEvent?: any) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Last check timestamp (shared via SWR + localStorage) ---
|
||||||
|
|
||||||
|
const LAST_CHECK_KEY = 'last_check_update'
|
||||||
|
|
||||||
|
export const readLastCheckTime = (): number | null => {
|
||||||
|
const stored = localStorage.getItem(LAST_CHECK_KEY)
|
||||||
|
if (!stored) return null
|
||||||
|
const ts = parseInt(stored, 10)
|
||||||
|
return isNaN(ts) ? null : ts
|
||||||
|
}
|
||||||
|
|
||||||
|
export const updateLastCheckTime = (timestamp?: number): number => {
|
||||||
|
const now = timestamp ?? Date.now()
|
||||||
|
localStorage.setItem(LAST_CHECK_KEY, now.toString())
|
||||||
|
globalMutate(LAST_CHECK_KEY, now, false)
|
||||||
|
return now
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- useUpdate hook ---
|
||||||
|
|
||||||
export const useUpdate = (
|
export const useUpdate = (
|
||||||
enabled: boolean = true,
|
enabled: boolean = true,
|
||||||
options?: SWRConfiguration,
|
options?: SWRConfiguration,
|
||||||
@ -36,11 +56,22 @@ export const useUpdate = (
|
|||||||
refreshInterval: 24 * 60 * 60 * 1000, // 24 hours
|
refreshInterval: 24 * 60 * 60 * 1000, // 24 hours
|
||||||
dedupingInterval: 60 * 60 * 1000, // 1 hour
|
dedupingInterval: 60 * 60 * 1000, // 1 hour
|
||||||
...options,
|
...options,
|
||||||
|
onSuccess: (...args) => {
|
||||||
|
updateLastCheckTime()
|
||||||
|
options?.onSuccess?.(...args)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Shared last check timestamp
|
||||||
|
const { data: lastCheckUpdate } = useSWR(LAST_CHECK_KEY, readLastCheckTime, {
|
||||||
|
revalidateOnFocus: false,
|
||||||
|
revalidateOnReconnect: false,
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
updateInfo,
|
updateInfo,
|
||||||
checkUpdate,
|
checkUpdate,
|
||||||
loading: isValidating,
|
loading: isValidating,
|
||||||
|
lastCheckUpdate: lastCheckUpdate ?? null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user