fix(port): edit the saved mixed port, not the session fallback

Closes #8149
This commit is contained in:
wonfen
2026-10-05 22:00:54 +08:00
parent c7cee50fc1
commit 7cc6c1ed95
17 changed files with 72 additions and 17 deletions
+1
View File
@@ -3,6 +3,7 @@
<details>
<summary><strong> 🐞 修复问题 </strong></summary>
- 修复端口设置混淆保存值与运行值、输入无效时缺少提示的问题
- 修复从开始菜单再次打开应用后,窗口反复弹出并提示启动失败的问题
- 修复多个代理集合包含同名节点时,代理组中的节点变灰并显示 ambiguous、无法选择的问题
@@ -13,6 +13,7 @@ import { forwardRef, useImperativeHandle, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { BaseDialog, Switch } from '@/components/base'
import { useClashInfo } from '@/hooks/use-clash'
import { useDisplayedMixedPort } from '@/hooks/use-displayed-mixed-port'
import { useVerge } from '@/hooks/use-verge'
import { saveProxyPorts } from '@/services/cmds'
@@ -32,11 +33,14 @@ const generateRandomPort = () =>
export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
const { t } = useTranslation()
const { verge } = useVerge()
const { clashInfo } = useClashInfo()
const configuredMixedPort =
verge?.verge_mixed_port ?? clashInfo?.mixed_port ?? 7897
const displayedMixedPort = useDisplayedMixedPort()
const [open, setOpen] = useState(false)
// Mixed Port
const [mixedPort, setMixedPort] = useState(displayedMixedPort)
const [mixedPort, setMixedPort] = useState(configuredMixedPort)
// 其他端口状态
const [socksPort, setSocksPort] = useState(verge?.verge_socks_port ?? 7898)
@@ -76,7 +80,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
useImperativeHandle(ref, () => ({
open: () => {
setMixedPort(displayedMixedPort)
setMixedPort(configuredMixedPort)
setSocksPort(verge?.verge_socks_port ?? 7898)
setSocksEnabled(verge?.verge_socks_enabled ?? false)
setHttpPort(verge?.verge_port ?? 7899)
@@ -92,6 +96,14 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
// TODO 减少代码复杂度,性能开支
const onSave = useLockFn(async () => {
// The backend also rejects out-of-range ports on disabled listeners.
const isValidPort = (port: number) => port >= 1 && port <= 65535
const allPorts = [mixedPort, socksPort, httpPort, redirPort, tproxyPort]
if (!allPorts.every(isValidPort)) {
showNotice.error('settings.modals.clashPort.messages.invalidPort')
return
}
// 端口冲突检测
const portList = [
mixedPort,
@@ -102,20 +114,7 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
].filter((p) => p !== -1)
if (new Set(portList).size !== portList.length) {
return
}
// 验证端口范围
const isValidPort = (port: number) => port >= 1 && port <= 65535
const allPortsValid = [
mixedPort,
socksEnabled ? socksPort : 0,
httpEnabled ? httpPort : 0,
redirEnabled ? redirPort : 0,
tproxyEnabled ? tproxyPort : 0,
].every((port) => port === 0 || isValidPort(port))
if (!allPortsValid) {
showNotice.error('settings.modals.clashPort.messages.duplicatePort')
return
}
@@ -154,7 +153,17 @@ export const ClashPortViewer = forwardRef<ClashPortViewerRef>((_, ref) => {
<ListItem sx={{ padding: '4px 0', minHeight: 36 }}>
<ListItemText
primary={t('settings.modals.clashPort.fields.mixed')}
slotProps={{ primary: { sx: { fontSize: 12 } } }}
secondary={
displayedMixedPort !== configuredMixedPort
? t('settings.modals.clashPort.messages.runningPort', {
port: displayedMixedPort,
})
: undefined
}
slotProps={{
primary: { sx: { fontSize: 12 } },
secondary: { sx: { fontSize: 12 } },
}}
/>
<div style={{ display: 'flex', alignItems: 'center' }}>
<TextField
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "المنفذ المستخدم حاليًا: {{port}}",
"duplicatePort": "يجب أن تستخدم المستمعات المفعّلة منافذ مختلفة",
"invalidPort": "أدخل منفذًا بين 1 و65535",
"saved": "Port settings saved",
"saveFailed": "Failed to save port settings",
"automaticFallback": "المنفذ {{oldPort}} مستخدم، لذا تعمل هذه الجلسة على {{newPort}}. لم يتغيّر إعدادك وسيُعاد تجربة {{oldPort}} عند التشغيل التالي.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "Aktuell verwendeter Port: {{port}}",
"duplicatePort": "Aktivierte Listener müssen unterschiedliche Ports verwenden",
"invalidPort": "Geben Sie einen Port zwischen 1 und 65535 ein",
"saved": "Port settings saved",
"saveFailed": "Failed to save port settings",
"automaticFallback": "Port {{oldPort}} ist belegt, daher läuft diese Sitzung auf {{newPort}}. Die Einstellung bleibt unverändert und {{oldPort}} wird beim nächsten Start erneut versucht.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "Currently using port {{port}}",
"duplicatePort": "Enabled listeners must use different ports",
"invalidPort": "Enter a port between 1 and 65535",
"saved": "Port settings saved",
"saveFailed": "Failed to save port settings",
"automaticFallback": "Port {{oldPort}} was in use, so this session runs on {{newPort}}. Your setting is unchanged and {{oldPort}} is retried on the next start.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "Puerto actual: {{port}}",
"duplicatePort": "Los servicios de escucha habilitados deben usar puertos diferentes",
"invalidPort": "Introduce un puerto entre 1 y 65535",
"saved": "Port settings saved",
"saveFailed": "Failed to save port settings",
"automaticFallback": "El puerto {{oldPort}} está en uso, por lo que esta sesión usa {{newPort}}. Tu configuración no ha cambiado y se volverá a intentar {{oldPort}} en el próximo inicio.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "درگاه فعلی: {{port}}",
"duplicatePort": "شنونده‌های فعال باید از درگاه‌های متفاوت استفاده کنند",
"invalidPort": "شمارهٔ درگاهی بین 1 و 65535 وارد کنید",
"saved": "Port settings saved",
"saveFailed": "Failed to save port settings",
"automaticFallback": "پورت {{oldPort}} در حال استفاده بود، بنابراین این اجرا از {{newPort}} استفاده می‌کند. تنظیم شما تغییر نکرده و در اجرای بعدی {{oldPort}} دوباره امتحان می‌شود.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "Port yang sedang digunakan: {{port}}",
"duplicatePort": "Listener yang diaktifkan harus menggunakan port yang berbeda",
"invalidPort": "Masukkan port antara 1 dan 65535",
"saved": "Port settings saved",
"saveFailed": "Failed to save port settings",
"automaticFallback": "Port {{oldPort}} sedang digunakan, jadi sesi ini menggunakan {{newPort}}. Pengaturan Anda tidak berubah dan {{oldPort}} akan dicoba lagi saat mulai berikutnya.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "現在使用中のポート:{{port}}",
"duplicatePort": "有効なリスナーには異なるポートを指定してください",
"invalidPort": "1〜65535のポート番号を入力してください",
"saved": "Port settings saved",
"saveFailed": "Failed to save port settings",
"automaticFallback": "ポート {{oldPort}} が使用中のため、今回は {{newPort}} で動作します。設定は変更されておらず、次回起動時に {{oldPort}} を再試行します。",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "현재 사용 중인 포트: {{port}}",
"duplicatePort": "활성화된 리스너는 서로 다른 포트를 사용해야 합니다",
"invalidPort": "1에서 65535 사이의 포트 번호를 입력하세요",
"saved": "포트 설정이 저장되었습니다",
"saveFailed": "포트 설정 저장에 실패했습니다",
"automaticFallback": "포트 {{oldPort}}이(가) 사용 중이어서 이번 실행은 {{newPort}}을(를) 사용합니다. 설정은 변경되지 않았으며 다음 시작 시 {{oldPort}}을(를) 다시 시도합니다.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Порт {{port}} уже используется",
"runningPort": "Сейчас используется порт {{port}}",
"duplicatePort": "Включённые слушатели должны использовать разные порты",
"invalidPort": "Введите порт от 1 до 65535",
"saved": "Настройки портов сохранены",
"saveFailed": "Не удалось сохранить настройки портов",
"automaticFallback": "Порт {{oldPort}} занят, поэтому этот запуск использует {{newPort}}. Настройка не изменена, при следующем запуске {{oldPort}} будет опробован снова.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "{{port}} portu zaten kullanımda",
"runningPort": "Şu anda kullanılan port: {{port}}",
"duplicatePort": "Etkin dinleyiciler farklı portlar kullanmalıdır",
"invalidPort": "1 ile 65535 arasında bir port girin",
"saved": "Port ayarları kaydedildi",
"saveFailed": "Port ayarları kaydedilemedi",
"automaticFallback": "{{oldPort}} portu kullanımda olduğu için bu oturum {{newPort}} portunu kullanıyor. Ayarınız değişmedi ve sonraki başlatmada {{oldPort}} yeniden denenecek.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "Хәзер {{port}} порты кулланыла",
"duplicatePort": "Кабызылган тыңлаучылар төрле портлар кулланырга тиеш",
"invalidPort": "1 белән 65535 арасындагы порт номерын кертегез",
"saved": "Port settings saved",
"saveFailed": "Failed to save port settings",
"automaticFallback": "Port {{oldPort}} was in use, so this session runs on {{newPort}}. Your setting is unchanged and {{oldPort}} is retried on the next start.",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "端口 {{port}} 已被占用",
"runningPort": "当前运行端口:{{port}}",
"duplicatePort": "已启用的监听端口不能重复",
"invalidPort": "请输入 1 至 65535 之间的端口号",
"saved": "端口设置已保存",
"saveFailed": "端口设置保存失败",
"automaticFallback": "端口 {{oldPort}} 已被占用,本次运行改用 {{newPort}}。设置未更改,下次启动会重新尝试 {{oldPort}}。",
+3
View File
@@ -290,6 +290,9 @@
},
"messages": {
"portInUse": "Port {{port}} is already in use",
"runningPort": "目前執行中的連接埠:{{port}}",
"duplicatePort": "已啟用的監聽連接埠不能重複",
"invalidPort": "請輸入 1 至 65535 之間的連接埠號碼",
"saved": "連結埠設定已儲存",
"saveFailed": "連結埠設定儲存失敗",
"automaticFallback": "連結埠 {{oldPort}} 已被佔用,本次執行改用 {{newPort}}。設定未變更,下次啟動會重新嘗試 {{oldPort}}。",
+3
View File
@@ -571,6 +571,9 @@ export const translationKeys = [
'settings.modals.clashPort.fields.tproxy',
'settings.modals.clashPort.actions.random',
'settings.modals.clashPort.messages.portInUse',
'settings.modals.clashPort.messages.runningPort',
'settings.modals.clashPort.messages.duplicatePort',
'settings.modals.clashPort.messages.invalidPort',
'settings.modals.clashPort.messages.saved',
'settings.modals.clashPort.messages.saveFailed',
'settings.modals.clashPort.messages.automaticFallback',
+3
View File
@@ -962,9 +962,12 @@ export interface TranslationResources {
messages: {
automaticFallback: string
automaticFallbackFailed: string
duplicatePort: string
invalidPort: string
portInUse: string
portTooHigh: string
portTooLow: string
runningPort: string
saved: string
saveFailed: string
}