fix(btpanel): 连接配置页始终显示全局设置
未选服务器时不再隐藏整页内容,避免白屏。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,24 @@
|
|||||||
|
# Changelog — 宝塔连接配置页空白修复(2026-06-21)
|
||||||
|
|
||||||
|
**日期**:2026-06-21
|
||||||
|
|
||||||
|
## 摘要
|
||||||
|
|
||||||
|
修复「连接配置」在未选服务器时整页几乎空白:全局设置(中心 IP、自动获取、批量初始化)现始终可见。
|
||||||
|
|
||||||
|
## 动机
|
||||||
|
|
||||||
|
`BtPanelPageShell` 原先要求先选服务器才渲染插槽,全局配置被挡在门外,用户看到白屏或仅一条提示。
|
||||||
|
|
||||||
|
## 涉及文件
|
||||||
|
|
||||||
|
- `frontend/src/components/btpanel/BtPanelPageShell.vue` — 新增 `requireServer`(默认 true)
|
||||||
|
- `frontend/src/pages/btpanel/BtPanelSettingsPage.vue` — `require-server=false`,单机块按选中状态展示
|
||||||
|
|
||||||
|
## 迁移 / 重启
|
||||||
|
|
||||||
|
- 仅前端
|
||||||
|
|
||||||
|
## 验证
|
||||||
|
|
||||||
|
打开 `#/btpanel/settings`:应立刻看到「全局」卡片;选服务器后显示「当前服务器」表单。
|
||||||
@@ -16,9 +16,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<v-alert v-if="!serverId" type="info" variant="tonal" class="mb-4" text="请选择服务器" />
|
<v-alert v-if="props.requireServer && !serverId" type="info" variant="tonal" class="mb-4" text="请选择服务器" />
|
||||||
|
|
||||||
<slot v-else :server-id="serverId" :server="selected()" />
|
<slot :server-id="serverId" :server="selected()" />
|
||||||
</v-container>
|
</v-container>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -28,10 +28,14 @@ import BtPanelServerPicker from '@/components/btpanel/BtPanelServerPicker.vue'
|
|||||||
import { btPanelContextKey } from '@/composables/btpanel/btPanelContext'
|
import { btPanelContextKey } from '@/composables/btpanel/btPanelContext'
|
||||||
import { useBtPanelServer } from '@/composables/btpanel/useBtPanelServer'
|
import { useBtPanelServer } from '@/composables/btpanel/useBtPanelServer'
|
||||||
|
|
||||||
defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
title: string
|
title: string
|
||||||
subtitle?: string
|
subtitle?: string
|
||||||
}>()
|
/** 为 false 时未选服务器也渲染默认插槽(如连接配置页的全局块) */
|
||||||
|
requireServer?: boolean
|
||||||
|
}>(), {
|
||||||
|
requireServer: true,
|
||||||
|
})
|
||||||
|
|
||||||
const ctx = useBtPanelServer()
|
const ctx = useBtPanelServer()
|
||||||
const { servers, serverId, loading, loadServers, setServerId, selected } = ctx
|
const { servers, serverId, loading, loadServers, setServerId, selected } = ctx
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<BtPanelPageShell title="宝塔 · 连接配置" subtitle="SSH 自动获取 API 或手动填写面板地址与密钥">
|
<BtPanelPageShell
|
||||||
|
title="宝塔 · 连接配置"
|
||||||
|
subtitle="SSH 自动获取 API 或手动填写面板地址与密钥"
|
||||||
|
:require-server="false"
|
||||||
|
>
|
||||||
<template #default="{ serverId }">
|
<template #default="{ serverId }">
|
||||||
<v-card max-width="720" variant="outlined" rounded="lg" class="mb-4">
|
<v-card max-width="720" variant="outlined" rounded="lg" class="mb-4">
|
||||||
<v-card-title class="text-subtitle-1">全局</v-card-title>
|
<v-card-title class="text-subtitle-1">全局</v-card-title>
|
||||||
@@ -33,17 +37,34 @@
|
|||||||
>
|
>
|
||||||
批量初始化未配置({{ unconfiguredIds.length }})
|
批量初始化未配置({{ unconfiguredIds.length }})
|
||||||
</v-btn>
|
</v-btn>
|
||||||
|
<v-alert
|
||||||
|
v-if="globalLoaded && !serverList.length"
|
||||||
|
type="warning"
|
||||||
|
variant="tonal"
|
||||||
|
class="mt-4"
|
||||||
|
title="暂无服务器"
|
||||||
|
text="请先在「服务器」页添加子机,再回到此处配置宝塔连接。"
|
||||||
|
/>
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<v-card max-width="720" variant="outlined" rounded="lg" :loading="loading">
|
<v-alert
|
||||||
|
v-if="!serverId"
|
||||||
|
type="info"
|
||||||
|
variant="tonal"
|
||||||
|
class="mb-4"
|
||||||
|
title="单机配置"
|
||||||
|
text="请在右上角选择服务器,或从「服务器列表」点击「连接配置」进入。"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<v-card v-else max-width="720" variant="outlined" rounded="lg" :loading="loading">
|
||||||
|
<v-card-title class="text-subtitle-1">当前服务器</v-card-title>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<div class="d-flex flex-wrap align-center ga-2 mb-3">
|
<div class="d-flex flex-wrap align-center ga-2 mb-3">
|
||||||
<v-chip :color="btInstalledChipColor" size="small" variant="tonal">
|
<v-chip :color="btInstalledChipColor" size="small" variant="tonal">
|
||||||
SSH 检测:{{ btInstalledLabel }}
|
SSH 检测:{{ btInstalledLabel }}
|
||||||
</v-chip>
|
</v-chip>
|
||||||
<v-btn
|
<v-btn
|
||||||
v-if="serverId"
|
|
||||||
icon="mdi-refresh"
|
icon="mdi-refresh"
|
||||||
size="x-small"
|
size="x-small"
|
||||||
variant="text"
|
variant="text"
|
||||||
@@ -66,11 +87,11 @@
|
|||||||
variant="tonal"
|
variant="tonal"
|
||||||
class="mb-4"
|
class="mb-4"
|
||||||
:loading="bootstrapping"
|
:loading="bootstrapping"
|
||||||
@click="runBootstrap(serverId!)"
|
@click="runBootstrap(serverId)"
|
||||||
>
|
>
|
||||||
立即 SSH 获取
|
立即 SSH 获取
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-form @submit.prevent="save(serverId!)">
|
<v-form @submit.prevent="save(serverId)">
|
||||||
<v-switch
|
<v-switch
|
||||||
v-model="form.auto_bootstrap"
|
v-model="form.auto_bootstrap"
|
||||||
label="自动获取(每 5 分钟重试,直至成功)"
|
label="自动获取(每 5 分钟重试,直至成功)"
|
||||||
@@ -145,6 +166,7 @@ const globalSettings = ref<BtPanelGlobalSettings | null>(null)
|
|||||||
const serverList = ref<Awaited<ReturnType<typeof listBtServers>>>([])
|
const serverList = ref<Awaited<ReturnType<typeof listBtServers>>>([])
|
||||||
const form = reactive({ base_url: '', api_key: '', verify_ssl: false, auto_bootstrap: true })
|
const form = reactive({ base_url: '', api_key: '', verify_ssl: false, auto_bootstrap: true })
|
||||||
const globalForm = reactive({ bt_panel_source_ip: '', bt_panel_auto_bootstrap_enabled: true })
|
const globalForm = reactive({ bt_panel_source_ip: '', bt_panel_auto_bootstrap_enabled: true })
|
||||||
|
const globalLoaded = ref(false)
|
||||||
|
|
||||||
const bootstrapStateLabels: Record<string, string> = {
|
const bootstrapStateLabels: Record<string, string> = {
|
||||||
pending: '等待获取',
|
pending: '等待获取',
|
||||||
@@ -201,7 +223,7 @@ async function loadConfig(id: number, refreshBtInstalled = false) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { serverId } = useBtPanelPageLoad(async (id) => {
|
useBtPanelPageLoad(async (id) => {
|
||||||
await loadConfig(id)
|
await loadConfig(id)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -224,6 +246,8 @@ async function loadGlobal() {
|
|||||||
serverList.value = await listBtServers()
|
serverList.value = await listBtServers()
|
||||||
} catch (e: unknown) {
|
} catch (e: unknown) {
|
||||||
window.$snackbar?.(e instanceof Error ? e.message : '加载全局设置失败', 'error')
|
window.$snackbar?.(e instanceof Error ? e.message : '加载全局设置失败', 'error')
|
||||||
|
} finally {
|
||||||
|
globalLoaded.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user