diff --git a/frontend/src/views/SetupWizard/DatabaseSetup.vue b/frontend/src/views/SetupWizard/DatabaseSetup.vue
index 3d8bbf7..f4ec3dd 100644
--- a/frontend/src/views/SetupWizard/DatabaseSetup.vue
+++ b/frontend/src/views/SetupWizard/DatabaseSetup.vue
@@ -17,7 +17,12 @@ const emit = defineEmits(["test"]);
diff --git a/frontend/src/views/SetupWizard/SetupWizard.css b/frontend/src/views/SetupWizard/SetupWizard.css
index 8c73742..f758730 100644
--- a/frontend/src/views/SetupWizard/SetupWizard.css
+++ b/frontend/src/views/SetupWizard/SetupWizard.css
@@ -22,6 +22,22 @@
gap: 16px;
}
+.warning-card {
+ display: grid;
+ gap: 8px;
+ margin-top: 18px;
+ padding-top: 16px;
+ border-top: 1px solid rgba(255, 255, 255, 0.3);
+ font-size: 12px;
+ line-height: 1.7;
+ letter-spacing: 0;
+ overflow-wrap: anywhere;
+}
+
+.warning-card strong {
+ font-size: 13px;
+}
+
.setup-eyebrow {
margin: 0 0 6px;
color: #4d76b7;
@@ -188,6 +204,7 @@ legend span {
.setup-grid {
min-width: 0;
display: grid;
+ align-items: start;
gap: 9px 12px;
}
@@ -202,6 +219,7 @@ legend span {
label {
min-width: 0;
display: grid;
+ align-content: start;
gap: 5px;
margin-top: 8px;
color: #34445f;
diff --git a/frontend/src/views/SetupWizard/SetupWizard.js b/frontend/src/views/SetupWizard/SetupWizard.js
index bb75d9e..3178a14 100644
--- a/frontend/src/views/SetupWizard/SetupWizard.js
+++ b/frontend/src/views/SetupWizard/SetupWizard.js
@@ -247,9 +247,9 @@ export function useSetupWizard(props, emit) {
emailAutofillElement.value.value = String(value || "");
}
- function handleEmailInput(value) {
+ function handleEmailInput(value, clearError = true) {
emailVisibleEdited = true;
- error.value = "";
+ if (clearError) error.value = "";
const rawValue = String(value || "").trim();
if (!rawValue) {
@@ -314,7 +314,8 @@ export function useSetupWizard(props, emit) {
if (!rawValue) return;
if (rawValue.includes("@") || rawValue !== emailLocalPart.value) {
- handleEmailInput(rawValue);
+ // 自动同步不应清除数据库、密码等其他字段的校验结果。
+ handleEmailInput(rawValue, false);
return;
}
diff --git a/frontend/src/views/SetupWizard/SetupWizard.test.js b/frontend/src/views/SetupWizard/SetupWizard.test.js
index 33022bc..7648342 100644
--- a/frontend/src/views/SetupWizard/SetupWizard.test.js
+++ b/frontend/src/views/SetupWizard/SetupWizard.test.js
@@ -19,6 +19,40 @@ test("已有初始化服务商选择保持兼容", async (t) => {
assert.equal(state.form.value.dns_provider, "cloudflare");
});
+test("邮箱定时同步不能清除步骤校验错误,手动编辑仍可清除", async (t) => {
+ const { state, runIntervals } = await mountComposable(t,
+ () => useSetupWizard({ status: { mode: "bootstrap" } }, () => {}),
+ async () => Response.json({ items: [aliyunProvider] }));
+ Object.assign(state.form.value, {
+ admin_username: "test-admin",
+ admin_password: "TestPass123",
+ confirm_password: "TestPass123",
+ web_hostname: "scert.example.test",
+ });
+ state.emailInputElement.value = { value: "admin@example.test" };
+ state.emailAutofillElement.value = { value: "" };
+ state.handleEmailInput("admin@example.test");
+ state.handleSubmit();
+ assert.equal(state.error.value, "请先验证所选数据库的连接和写权限。");
+ for (let i = 0; i < 8; i += 1) runIntervals();
+ assert.equal(state.error.value, "请先验证所选数据库的连接和写权限。");
+ assert.equal(state.currentStep.value, 1);
+ state.handleEmailInput("changed@example.test");
+ assert.equal(state.error.value, "");
+});
+
+test("自动填充同步新邮箱时保留其他字段的错误", async (t) => {
+ const { state, runIntervals } = await mountComposable(t,
+ () => useSetupWizard({ status: {} }, () => {}),
+ async () => Response.json({ items: [aliyunProvider] }));
+ state.emailInputElement.value = { value: "" };
+ state.emailAutofillElement.value = { value: "autofill@example.test" };
+ state.error.value = "两次输入的超级管理员密码不一致。";
+ runIntervals();
+ assert.equal(state.form.value.admin_email, "autofill@example.test");
+ assert.equal(state.error.value, "两次输入的超级管理员密码不一致。");
+});
+
async function setup(t, request) {
const mounted = await mountComposable(t, () => useSetupWizard({ status: { dns_provider: "aliyun" } }, () => {}),
async (path) => path.endsWith("/providers") ? Response.json({ items: [aliyunProvider] }) : request());