修复初始化错误提示被邮箱同步清除及表单错位

This commit is contained in:
xuans 2026-09-17 11:48:00 +08:00
parent e206d7e92a
commit 4993199fb1
4 changed files with 102 additions and 10 deletions

View File

@ -17,7 +17,12 @@ const emit = defineEmits(["test"]);
<div class="setup-grid two-columns">
<label>
<span>数据库类型</span>
<select v-model="form.driver" :disabled="testing">
<select
id="database-driver"
name="database_driver"
v-model="form.driver"
:disabled="testing"
>
<option value="sqlite">SQLite(本机文件,无需额外服务)</option>
<option value="mysql">MySQL</option>
<option value="postgres">PostgreSQL</option>
@ -26,27 +31,61 @@ const emit = defineEmits(["test"]);
<template v-if="form.driver !== 'sqlite'">
<label>
<span>数据库主机</span>
<input v-model.trim="form.host" autocomplete="off" placeholder="db.example.com" />
<input
id="database-host"
name="database_host"
v-model.trim="form.host"
autocomplete="off"
placeholder="db.example.com"
/>
</label>
<label>
<span>数据库端口</span>
<input v-model.number="form.port" type="number" min="1" max="65535" />
<input
id="database-port"
name="database_port"
v-model.number="form.port"
type="number"
min="1"
max="65535"
/>
</label>
<label>
<span>数据库名称</span>
<input v-model.trim="form.database" autocomplete="off" />
<input
id="database-name"
name="database_name"
v-model.trim="form.database"
autocomplete="off"
/>
</label>
<label>
<span>数据库用户名</span>
<input v-model.trim="form.username" autocomplete="off" />
<input
id="database-username"
name="database_username"
v-model.trim="form.username"
autocomplete="off"
/>
</label>
<label>
<span>数据库密码</span>
<input v-model="form.password" type="password" autocomplete="new-password" />
<input
id="database-password"
name="database_password"
v-model="form.password"
type="password"
autocomplete="new-password"
/>
</label>
<label v-if="form.driver === 'postgres'">
<span>根证书路径(服务器绝对路径,可选)</span>
<input v-model.trim="form.root_certificate" placeholder="使用系统信任库时留空" />
<input
id="database-root-certificate"
name="database_root_certificate"
v-model.trim="form.root_certificate"
placeholder="使用系统信任库时留空"
/>
</label>
</template>
</div>

View File

@ -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;

View File

@ -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;
}

View File

@ -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());