界面文案改成中性措辞;延迟测试报出真实原因

原来那句「X 测不通」把两种要查不同地方的情况混在了一起。内核的语义是精确的
(hub/route/proxies.go:122-145):504 表示在给定超时内没有完成,503 表示连接建立失败
或测得延迟为 0。现在分开报,超时会写明是几秒,503 且内核没给具体错误时说明可能是
线路失效或本机到该服务器网络不通。

其余文案统一过一遍:「本机之外也能连」「这个名字已经被占用了」「还没做」这类口语改成
「允许来自其它主机的连接」「名称已存在」「尚未实现」。
This commit is contained in:
im0o
2026-08-10 13:38:02 +08:00
parent e8b8181ef6
commit 71adcd60ef
7 changed files with 59 additions and 34 deletions
+37 -12
View File
@@ -115,7 +115,7 @@ async function pickOutbound(mode: OutboundMode) {
else entry.proxy = proxy
try {
await commit(next, `${target.name} 的出站改成了 ${outboundLabel(mode).text}`)
await commit(next, `${target.name} 的出站已设为 ${outboundLabel(mode).text}`)
} finally {
pendingOutbound.value = null
}
@@ -143,7 +143,7 @@ async function submitForm(entry: ConfigObject) {
next.listeners = listeners
formOpen.value = false
await commit(next, editingIndex === null ? `新增了 ${String(entry.name)}` : '改动已保存')
await commit(next, editingIndex === null ? `已新增 ${String(entry.name)}` : '已保存')
if (editingIndex === null) selectedId.value = `listener:${String(listeners.length - 1)}`
}
@@ -159,22 +159,47 @@ async function selectMember(group: string, member: string) {
emit('changed')
} catch (error) {
const message = error instanceof ApiError ? String(error.payload.error ?? error.message) : String(error)
failure.value = { message, hint: '这一步只改内核的运行状态,配置文件没有被动过。' }
failure.value = { message, hint: '该操作仅修改内核运行状态,配置文件未被修改。' }
}
}
/** 测一条线路的延迟。纯读操作,不影响任何配置,所以谁都不用禁用。 */
/** 延迟测试用的超时,毫秒。也用在失败提示里,让「超时」这个词有具体含义。 */
const TEST_TIMEOUT_MS = 5000
/**
* 把内核的延迟测试结果翻译成一句说明原因的话。
*
* 内核的语义是精确的(hub/route/proxies.go:122-145):
* 504 在给定超时内没有完成
* 503 连接建立失败,或者测得的延迟为 0
* 笼统说一句「测不通」会把这两种情况混在一起,而它们要查的地方不一样。
*/
function describeTestFailure(name: string, error: unknown): string {
if (!(error instanceof ApiError)) return `${name} 延迟测试失败:${String(error)}`
const seconds = String(TEST_TIMEOUT_MS / 1000)
if (error.status === 504) return `${name} 延迟测试超时,${seconds} 秒内没有取到测试地址`
const detail = String(error.payload.message ?? '')
const generic = detail === '' || detail === 'An error occurred in the delay test'
if (error.status === 503) {
return generic
? `${name} 无法建立连接,线路可能已失效,或本机到该服务器的网络不通`
: `${name} 无法建立连接:${detail}`
}
return `${name} 延迟测试失败(HTTP ${String(error.status)})${generic ? '' : `:${detail}`}`
}
/** 测一条线路的延迟。纯读操作,不影响任何配置,所以不禁用任何东西。 */
async function testLine(name: string) {
if (testing.value.includes(name)) return
testing.value = [...testing.value, name]
try {
await api.testLine(name)
await api.testLine(name, undefined, TEST_TIMEOUT_MS)
emit('changed')
} catch (error) {
// 测不通是关于线路的结论,不是 Patchbay 出了问题,不弹错误框
const raw =
error instanceof ApiError ? String(error.payload.message ?? error.message) : String(error)
done.value = raw.includes('timeout') ? `${name} 超时` : `${name} 测不通`
// 测不通是关于线路的结论,不是 Patchbay 出了故障,所以不用错误框
done.value = describeTestFailure(name, error)
} finally {
testing.value = testing.value.filter((n) => n !== name)
}
@@ -183,7 +208,7 @@ async function testLine(name: string) {
async function removeSelected() {
const target = selected.value
if (!target || target.listenerIndex === null || saving.value) return
if (!confirm(`删除入站「${target.name}」?端口 ${target.port} 会立刻停止监听。`)) return
if (!confirm(`删除入站「${target.name}」?端口 ${target.port} 将停止监听。`)) return
const next = clone()
const listeners = (next.listeners as ConfigObject[]).filter((_, i) => i !== target.listenerIndex)
@@ -192,7 +217,7 @@ async function removeSelected() {
else next.listeners = listeners
selectedId.value = null
await commit(next, `删除了 ${target.name}`)
await commit(next, `已删除 ${target.name}`)
}
</script>
@@ -266,7 +291,7 @@ async function removeSelected() {
/>
</div>
<p v-if="inbounds.length === 0" class="empty">没有入站。mihomo 不会监听任何端口。</p>
<p v-if="inbounds.length === 0" class="empty">没有入站,内核不会监听任何端口。</p>
<InboundForm
:open="formOpen"