修复初始化错误提示被邮箱同步清除及表单错位
This commit is contained in:
parent
e206d7e92a
commit
4993199fb1
@ -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>
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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());
|
||||
|
||||
Loading…
Reference in New Issue
Block a user