mirror of
https://gh.catmak.name/https://github.com/mihomo-party-org/mihomo-party
synced 2025-12-26 20:50:30 +08:00
Compare commits
3 Commits
848f6277cb
...
99a5505d16
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
99a5505d16 | ||
|
|
76a849e376 | ||
|
|
74b65430be |
@ -183,6 +183,11 @@ export const mihomoUpgrade = async (): Promise<void> => {
|
||||
return await instance.post('/upgrade')
|
||||
}
|
||||
|
||||
export const mihomoUpgradeUI = async (): Promise<void> => {
|
||||
const instance = await getAxios()
|
||||
return await instance.post('/upgrade/ui')
|
||||
}
|
||||
|
||||
// Smart 内核 API
|
||||
export const mihomoSmartGroupWeights = async (
|
||||
groupName: string
|
||||
|
||||
@ -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)
|
||||
)
|
||||
|
||||
@ -138,3 +138,9 @@
|
||||
background: #c0c1c58f;
|
||||
}
|
||||
}
|
||||
|
||||
.sider-card-title {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
@ -218,7 +218,7 @@ const ConnCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold sider-card-title ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.connections')}
|
||||
</h3>
|
||||
|
||||
@ -102,7 +102,7 @@ const DNSCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold sider-card-title ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.dns')}
|
||||
</h3>
|
||||
|
||||
@ -84,7 +84,7 @@ const LogCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold text-ellipsis whitespace-nowrap overflow-hidden ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.logs')}
|
||||
</h3>
|
||||
|
||||
@ -158,7 +158,7 @@ const MihomoCoreCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold text-ellipsis whitespace-nowrap overflow-hidden ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.core')}
|
||||
</h3>
|
||||
|
||||
@ -83,7 +83,7 @@ const OverrideCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold text-ellipsis whitespace-nowrap overflow-hidden ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.override')}
|
||||
</h3>
|
||||
|
||||
@ -238,7 +238,7 @@ const ProfileCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold sider-card-title ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.profiles')}
|
||||
</h3>
|
||||
|
||||
@ -103,7 +103,7 @@ const ProxyCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold sider-card-title ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('proxies.card.title')}
|
||||
</h3>
|
||||
|
||||
@ -84,7 +84,7 @@ const ResourceCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold text-ellipsis whitespace-nowrap overflow-hidden ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.resources')}
|
||||
</h3>
|
||||
|
||||
@ -104,7 +104,7 @@ const RuleCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold text-ellipsis whitespace-nowrap overflow-hidden ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.rules')}
|
||||
</h3>
|
||||
|
||||
@ -102,7 +102,7 @@ const SniffCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold text-ellipsis whitespace-nowrap overflow-hidden ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.sniff')}
|
||||
</h3>
|
||||
|
||||
@ -84,7 +84,7 @@ const SubStoreCard: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold text-ellipsis whitespace-nowrap overflow-hidden ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.substore')}
|
||||
</h3>
|
||||
|
||||
@ -116,7 +116,7 @@ const SysproxySwitcher: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold sider-card-title ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.systemProxy')}
|
||||
</h3>
|
||||
|
||||
@ -150,7 +150,7 @@ const TunSwitcher: React.FC<Props> = (props) => {
|
||||
</CardBody>
|
||||
<CardFooter className="pt-1">
|
||||
<h3
|
||||
className={`text-md font-bold ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
className={`text-md font-bold sider-card-title ${match ? 'text-primary-foreground' : 'text-foreground'}`}
|
||||
>
|
||||
{t('sider.cards.tun')}
|
||||
</h3>
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -25,9 +25,9 @@
|
||||
"common.notification.systemProxyDisabled": "Системный прокси отключен",
|
||||
"common.notification.tunEnabled": "TUN включен",
|
||||
"common.notification.tunDisabled": "TUN отключен",
|
||||
"common.notification.ruleMode": "Режим правил",
|
||||
"common.notification.globalMode": "Глобальный режим",
|
||||
"common.notification.directMode": "Прямой режим",
|
||||
"common.notification.ruleMode": "Правило",
|
||||
"common.notification.globalMode": "Глобальный",
|
||||
"common.notification.directMode": "Прямой",
|
||||
"common.error.appCrash": "Приложение завершилось аварийно :( Пожалуйста, отправьте следующую информацию разработчику для устранения проблемы",
|
||||
"common.error.copyErrorMessage": "Копировать сообщение об ошибке",
|
||||
"common.error.invalidCron": "Неверное выражение Cron",
|
||||
@ -249,7 +249,7 @@
|
||||
"sider.cards.trafficUsage": "Использование трафика",
|
||||
"sider.cards.neverExpire": "Бессрочно",
|
||||
"sider.cards.outbound.title": "Режим исходящего трафика",
|
||||
"sider.cards.outbound.rule": "По правилам",
|
||||
"sider.cards.outbound.rule": "Правило",
|
||||
"sider.cards.outbound.global": "Глобальный",
|
||||
"sider.cards.outbound.direct": "Прямой",
|
||||
"sider.size.large": "Большой",
|
||||
@ -508,9 +508,9 @@
|
||||
"tray.showWindow": "Показать окно",
|
||||
"tray.showFloatingWindow": "Показать плавающее окно",
|
||||
"tray.hideFloatingWindow": "Скрыть плавающее окно",
|
||||
"tray.ruleMode": "Режим правил",
|
||||
"tray.globalMode": "Глобальный режим",
|
||||
"tray.directMode": "Прямой режим",
|
||||
"tray.ruleMode": "Правило",
|
||||
"tray.globalMode": "Глобальный",
|
||||
"tray.directMode": "Прямой",
|
||||
"tray.systemProxy": "Системный прокси",
|
||||
"tray.tun": "TUN",
|
||||
"tray.profiles": "Профили",
|
||||
|
||||
@ -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": "订阅地址",
|
||||
|
||||
@ -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 (
|
||||
<BasePage
|
||||
ref={pageRef}
|
||||
@ -378,6 +406,53 @@ const Profiles: React.FC = () => {
|
||||
</div>
|
||||
<Divider />
|
||||
</div>
|
||||
{/* WebUI Card with Multiple Options */}
|
||||
<div className="m-2">
|
||||
<Card>
|
||||
<CardHeader className="flex gap-3">
|
||||
<div className="flex flex-col">
|
||||
<p className="text-md">{t('profiles.openWebUI.title')}</p>
|
||||
<p className="text-small text-default-500">{t('profiles.openWebUI.description')}</p>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardBody>
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
<Button
|
||||
onPress={() => window.open('https://metacubexd.pages.dev/', '_blank')}
|
||||
>
|
||||
MetaCubeXD
|
||||
</Button>
|
||||
<Button
|
||||
onPress={() => window.open('https://zashboard.pages.dev/', '_blank')}
|
||||
>
|
||||
Zashboard
|
||||
</Button>
|
||||
{isLocalWebUIAvailable() && (
|
||||
<>
|
||||
<Button
|
||||
onPress={() => window.open(getLocalWebUIUrl(), '_blank')}
|
||||
>
|
||||
{t('profiles.openWebUI.local')}
|
||||
</Button>
|
||||
<Button
|
||||
color="success"
|
||||
onPress={async () => {
|
||||
try {
|
||||
await mihomoUpgradeUI()
|
||||
new Notification(t('profiles.updateWebUI.success'))
|
||||
} catch (e) {
|
||||
new Notification(t('profiles.updateWebUI.failed', { error: String(e) }))
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t('profiles.updateWebUI.button')}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={onDragEnd}>
|
||||
<div
|
||||
className={`${fileOver ? 'blur-sm' : ''} grid sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-2 m-2`}
|
||||
|
||||
@ -84,6 +84,10 @@ export async function mihomoUpgrade(): Promise<void> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoUpgrade'))
|
||||
}
|
||||
|
||||
export async function mihomoUpgradeUI(): Promise<void> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoUpgradeUI'))
|
||||
}
|
||||
|
||||
export async function mihomoProxyDelay(proxy: string, url?: string): Promise<IMihomoDelay> {
|
||||
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('mihomoProxyDelay', proxy, url))
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user