From 99a5505d163fb8e577aed624176501c1d1b1758b Mon Sep 17 00:00:00 2001 From: Memory <134070804+Memory2314@users.noreply.github.com> Date: Sat, 27 Sep 2025 10:00:21 +0800 Subject: [PATCH] feat: launch WebUI directly from subscription manager --- src/main/core/mihomoApi.ts | 5 ++ src/main/utils/ipc.ts | 2 + src/renderer/src/locales/en-US.json | 6 +++ src/renderer/src/locales/zh-CN.json | 6 +++ src/renderer/src/pages/profiles.tsx | 77 ++++++++++++++++++++++++++++- src/renderer/src/utils/ipc.ts | 4 ++ 6 files changed, 99 insertions(+), 1 deletion(-) diff --git a/src/main/core/mihomoApi.ts b/src/main/core/mihomoApi.ts index 235003f..936e6a2 100644 --- a/src/main/core/mihomoApi.ts +++ b/src/main/core/mihomoApi.ts @@ -183,6 +183,11 @@ export const mihomoUpgrade = async (): Promise => { return await instance.post('/upgrade') } +export const mihomoUpgradeUI = async (): Promise => { + const instance = await getAxios() + return await instance.post('/upgrade/ui') +} + // Smart 内核 API export const mihomoSmartGroupWeights = async ( groupName: string diff --git a/src/main/utils/ipc.ts b/src/main/utils/ipc.ts index 900d80e..20e3752 100644 --- a/src/main/utils/ipc.ts +++ b/src/main/utils/ipc.ts @@ -15,6 +15,7 @@ import { mihomoUpdateRuleProviders, mihomoUpgrade, mihomoUpgradeGeo, + mihomoUpgradeUI, mihomoVersion, patchMihomoConfig, mihomoSmartGroupWeights, @@ -167,6 +168,7 @@ export function registerIpcMainHandlers(): void { ipcMain.handle('mihomoUnfixedProxy', (_e, group) => ipcErrorWrapper(mihomoUnfixedProxy)(group)) ipcMain.handle('mihomoUpgradeGeo', ipcErrorWrapper(mihomoUpgradeGeo)) ipcMain.handle('mihomoUpgrade', ipcErrorWrapper(mihomoUpgrade)) + ipcMain.handle('mihomoUpgradeUI', ipcErrorWrapper(mihomoUpgradeUI)) ipcMain.handle('mihomoProxyDelay', (_e, proxy, url) => ipcErrorWrapper(mihomoProxyDelay)(proxy, url) ) diff --git a/src/renderer/src/locales/en-US.json b/src/renderer/src/locales/en-US.json index 892b539..1863565 100644 --- a/src/renderer/src/locales/en-US.json +++ b/src/renderer/src/locales/en-US.json @@ -400,6 +400,12 @@ "profiles.remote": "Remote", "profiles.local": "Local", "profiles.trafficUsage": "Traffic Usage Progress", + "profiles.openWebUI.title": "WebUI Management Panel", + "profiles.openWebUI.description": "Select a WebUI panel to open", + "profiles.openWebUI.local": "Local WebUI", + "profiles.updateWebUI.button": "Update Panel", + "profiles.updateWebUI.success": "WebUI panel updated successfully", + "profiles.updateWebUI.failed": "WebUI panel update failed: {{error}}", "profiles.editInfo.title": "Edit Information", "profiles.editInfo.name": "Name", "profiles.editInfo.url": "Subscription URL", diff --git a/src/renderer/src/locales/zh-CN.json b/src/renderer/src/locales/zh-CN.json index 204d10a..13ca959 100644 --- a/src/renderer/src/locales/zh-CN.json +++ b/src/renderer/src/locales/zh-CN.json @@ -405,6 +405,12 @@ "profiles.traffic.expired": "已过期", "profiles.traffic.remainingDays": "剩余 {{days}} 天", "profiles.traffic.lastUpdate": "最后更新:{{time}}", + "profiles.openWebUI.title": "WebUI 管理面板", + "profiles.openWebUI.description": "选择一个 WebUI 面板打开", + "profiles.openWebUI.local": "本地 WebUI", + "profiles.updateWebUI.button": "更新面板", + "profiles.updateWebUI.success": "WebUI 面板更新成功", + "profiles.updateWebUI.failed": "WebUI 面板更新失败: {{error}}", "profiles.editInfo.title": "编辑信息", "profiles.editInfo.name": "名称", "profiles.editInfo.url": "订阅地址", diff --git a/src/renderer/src/pages/profiles.tsx b/src/renderer/src/pages/profiles.tsx index 228bdd0..64b4a93 100644 --- a/src/renderer/src/pages/profiles.tsx +++ b/src/renderer/src/pages/profiles.tsx @@ -7,12 +7,16 @@ import { DropdownItem, DropdownMenu, DropdownTrigger, - Input + Input, + Card, + CardBody, + CardHeader } from '@heroui/react' import BasePage from '@renderer/components/base/base-page' import ProfileItem from '@renderer/components/profiles/profile-item' import { useProfileConfig } from '@renderer/hooks/use-profile-config' import { useAppConfig } from '@renderer/hooks/use-app-config' +import { useControledMihomoConfig } from '@renderer/hooks/use-controled-mihomo-config' import { getFilePath, readTextFile, subStoreCollections, subStoreSubs } from '@renderer/utils/ipc' import type { KeyboardEvent } from 'react' import { ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react' @@ -32,6 +36,7 @@ import SubStoreIcon from '@renderer/components/base/substore-icon' import useSWR from 'swr' import { useNavigate } from 'react-router-dom' import { useTranslation } from 'react-i18next' +import { mihomoUpgradeUI } from '@renderer/utils/ipc' const Profiles: React.FC = () => { const { t } = useTranslation() @@ -45,6 +50,9 @@ const Profiles: React.FC = () => { mutateProfileConfig } = useProfileConfig() const { appConfig } = useAppConfig() + const { controledMihomoConfig } = useControledMihomoConfig() + const externalController = controledMihomoConfig?.['external-controller'] || '' + const externalUI = (controledMihomoConfig as any)?.['external-ui'] const { useSubStore = true, useCustomSubStore = false, customSubStoreUrl = '' } = appConfig || {} const { current, items = [] } = profileConfig || {} const navigate = useNavigate() @@ -195,6 +203,26 @@ const Profiles: React.FC = () => { setSortedItems(items) }, [items]) + // 获取本地WebUI的URL + const getLocalWebUIUrl = (): string => { + if (externalController) { + // 将地址转换为WebUI URL + // 例如: 127.0.0.1:9090 -> http://127.0.0.1:9090/ui + const controller = externalController.replace('0.0.0.0', '127.0.0.1') + // 如果配置了external-ui,使用/ui路径,否则可能需要使用不同的路径 + const uiPath = externalUI ? '/ui' : '/ui' // 默认使用/ui路径 + return `http://${controller}${uiPath}` + } + // 默认URL + return 'http://127.0.0.1:9090/ui' + } + + // 检查本地WebUI是否可用 + const isLocalWebUIAvailable = (): boolean => { + // 如果有配置的external-controller,则认为本地WebUI可用 + return !!externalController + } + return ( { + {/* WebUI Card with Multiple Options */} +
+ + +
+

{t('profiles.openWebUI.title')}

+

{t('profiles.openWebUI.description')}

+
+
+ +
+ + + {isLocalWebUIAvailable() && ( + <> + + + + )} +
+
+
+
{ return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoUpgrade')) } +export async function mihomoUpgradeUI(): Promise { + return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoUpgradeUI')) +} + export async function mihomoProxyDelay(proxy: string, url?: string): Promise { return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoProxyDelay', proxy, url)) }