From 0bee64ce8607831d025df8ea1ef52e39b57d026f Mon Sep 17 00:00:00 2001 From: xuans Date: Thu, 17 Sep 2026 12:16:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=95=B0=E6=8D=AE=E5=BA=93?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E6=88=90=E5=8A=9F=E5=90=8E=E4=BB=8D=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E8=BF=87=E6=97=B6=E6=AD=A5=E9=AA=A4=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/SetupWizard/SetupWizard.js | 11 ++++-- .../SetupWizard/SetupWizardBootstrap.test.js | 36 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/SetupWizard/SetupWizard.js b/frontend/src/views/SetupWizard/SetupWizard.js index 3178a14..e775622 100644 --- a/frontend/src/views/SetupWizard/SetupWizard.js +++ b/frontend/src/views/SetupWizard/SetupWizard.js @@ -4,6 +4,8 @@ import { bootstrapPayload } from "./BootstrapPayload.js"; const defaultDNSVerificationTimeoutSeconds = 60; const aliyunDNSVerificationTimeoutSeconds = 6; +const databaseRequiredMessage = "请先验证所选数据库的连接和写权限。"; +const databaseExpiredMessage = "数据库验证结果无效或已过期,请重新验证。"; function dnsVerificationTimeoutFor(providerID) { return String(providerID || "").trim().toLowerCase() === "aliyun" @@ -49,6 +51,11 @@ export function useSetupWizard(props, emit) { const dnsVerification = ref(null); const verificationClock = ref(Date.now()); const database = useDatabaseSetup(verificationClock); + watch(database.databaseVerified, (verified) => { + if (verified && [databaseRequiredMessage, databaseExpiredMessage].includes(error.value)) { + error.value = ""; + } + }, { flush: "sync" }); const completed = ref(false); const currentStep = ref(1); const notificationAdvancedVisible = ref(false); @@ -545,7 +552,7 @@ export function useSetupWizard(props, emit) { return false; } if (isBootstrap && !database.databaseVerified.value) { - error.value = "请先验证所选数据库的连接和写权限。"; + error.value = databaseRequiredMessage; return false; } } @@ -719,7 +726,7 @@ export function useSetupWizard(props, emit) { error.value = ""; resultMessage.value = ""; if (isBootstrap && !database.databaseVerified.value) { - error.value = "数据库验证结果无效或已过期,请重新验证。"; + error.value = databaseExpiredMessage; return; } if (!dnsVerificationValid.value) { diff --git a/frontend/src/views/SetupWizard/SetupWizardBootstrap.test.js b/frontend/src/views/SetupWizard/SetupWizardBootstrap.test.js index 74b008c..b750863 100644 --- a/frontend/src/views/SetupWizard/SetupWizardBootstrap.test.js +++ b/frontend/src/views/SetupWizard/SetupWizardBootstrap.test.js @@ -44,6 +44,42 @@ async function setup(t, complete = completion, driver = "sqlite") { return { ...mounted, submitted, emitted }; } +test("数据库验证成功清除过时的数据库步骤提示", async (t) => { + const { state } = await setup(t); + for (const message of [ + "请先验证所选数据库的连接和写权限。", + "数据库验证结果无效或已过期,请重新验证。", + ]) { + state.invalidateDatabase(); + state.error.value = message; + await state.testDatabase(); + assert.equal(state.databaseVerified.value, true); + assert.equal(state.error.value, ""); + } +}); + +test("数据库验证成功不清除其他字段错误", async (t) => { + const { state } = await setup(t); + state.invalidateDatabase(); + state.error.value = "两次输入的超级管理员密码不一致。"; + await state.testDatabase(); + assert.equal(state.databaseVerified.value, true); + assert.equal(state.error.value, "两次输入的超级管理员密码不一致。"); +}); + +test("数据库验证失败不清除步骤提示", async (t) => { + const { state } = await mountComposable(t, + () => useSetupWizard({ status: { mode: "bootstrap" } }, () => {}), + async (path) => path.endsWith("/providers") + ? Response.json({ items: [aliyunProvider] }) + : Response.json({ error: "数据库连接失败。" }, { status: 400 })); + state.error.value = "请先验证所选数据库的连接和写权限。"; + await state.testDatabase(); + assert.equal(state.databaseVerified.value, false); + assert.equal(state.error.value, "请先验证所选数据库的连接和写权限。"); + assert.equal(state.databaseError.value, "数据库连接失败。"); +}); + for (const driver of ["sqlite", "mysql", "postgres"]) { test(`首次向导 ${driver} 完整流程只提交验证令牌并保留通知配置`, async (t) => { const { state, submitted, emitted } = await setup(t, completion, driver);