将服务访问与数据库类型调整为桌面四列同排

This commit is contained in:
xuans 2026-09-20 23:00:22 +08:00
parent b0e5be077b
commit 8ddb217833
5 changed files with 167 additions and 105 deletions

View File

@ -86,3 +86,9 @@ p {
grid-template-columns: minmax(0, 1fr);
}
}
.database-type-field {
display: grid;
gap: 10px;
min-width: 0;
}

View File

@ -10,11 +10,7 @@ const emit = defineEmits(["test"]);
<template>
<section class="database-setup" aria-label="数据库存储配置">
<div class="setup-section-heading">
<strong>数据库存储</strong>
<span>选择一种存储方式,验证连接和写权限后继续。不会清空已有数据。</span>
</div>
<div class="setup-grid two-columns">
<div class="database-type-field">
<label>
<span>数据库类型</span>
<select
@ -28,74 +24,78 @@ const emit = defineEmits(["test"]);
<option value="postgres">PostgreSQL</option>
</select>
</label>
<template v-if="form.driver !== 'sqlite'">
<label>
<span>数据库主机</span>
<input
id="database-host"
name="database_host"
v-model.trim="form.host"
autocomplete="off"
placeholder="db.example.com"
/>
</label>
<label>
<span>数据库端口</span>
<input
id="database-port"
name="database_port"
v-model.number="form.port"
type="number"
min="1"
max="65535"
/>
</label>
<label>
<span>数据库名称</span>
<input
id="database-name"
name="database_name"
v-model.trim="form.database"
autocomplete="off"
/>
</label>
<label>
<span>数据库用户名</span>
<input
id="database-username"
name="database_username"
v-model.trim="form.username"
autocomplete="off"
/>
</label>
<label>
<span>数据库密码</span>
<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
id="database-root-certificate"
name="database_root_certificate"
v-model.trim="form.root_certificate"
placeholder="使用系统信任库时留空"
/>
</label>
</template>
<div class="dns-test-actions">
<button type="button" class="dns-test-button" :disabled="testing" @click="emit('test')">
{{ testing ? "正在验证数据库,请等待(最长约 20 秒)……" : "验证数据库" }}
</button>
<span v-if="verified" role="status">数据库连接及写权限已验证。</span>
</div>
</div>
<div class="setup-section-heading">
<strong>数据库存储</strong>
<span>选择一种存储方式,验证连接和写权限后继续。不会清空已有数据。</span>
</div>
<div v-if="form.driver !== 'sqlite'" class="setup-grid two-columns database-connection-grid">
<label>
<span>数据库主机</span>
<input
id="database-host"
name="database_host"
v-model.trim="form.host"
autocomplete="off"
placeholder="db.example.com"
/>
</label>
<label>
<span>数据库端口</span>
<input
id="database-port"
name="database_port"
v-model.number="form.port"
type="number"
min="1"
max="65535"
/>
</label>
<label>
<span>数据库名称</span>
<input
id="database-name"
name="database_name"
v-model.trim="form.database"
autocomplete="off"
/>
</label>
<label>
<span>数据库用户名</span>
<input
id="database-username"
name="database_username"
v-model.trim="form.username"
autocomplete="off"
/>
</label>
<label>
<span>数据库密码</span>
<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
id="database-root-certificate"
name="database_root_certificate"
v-model.trim="form.root_certificate"
placeholder="使用系统信任库时留空"
/>
</label>
</div>
<p v-if="form.driver !== 'sqlite'">外部数据库必须启用 TLS 并校验证书和主机名,不支持跳过验证。请使用专属数据库与最小权限账号。</p>
<div class="dns-test-actions">
<button type="button" class="dns-test-button" :disabled="testing" @click="emit('test')">
{{ testing ? "正在验证数据库,请等待(最长约 20 秒)……" : "验证数据库" }}
</button>
<span v-if="verified" role="status">数据库连接及写权限已验证。</span>
</div>
<p v-if="error" class="inline-error" role="alert">{{ error }}</p>
</section>
</template>

View File

@ -221,7 +221,7 @@ const {
<strong>服务访问配置</strong>
<span>先确定 Scert 主服务和管理页面的访问方式,后续步骤会使用这里的配置。</span>
</div>
<div class="setup-grid two-columns">
<div class="setup-grid service-access-grid" :class="{ 'has-database': isBootstrap }">
<div class="access-target-field">
<span>管理页面访问方式</span>
<div class="target-switch" role="group" aria-label="管理页面访问方式">
@ -276,15 +276,15 @@ const {
/>
<small>管理页面和 API 对外提供服务使用的端口。</small>
</label>
<DatabaseSetup
v-if="isBootstrap"
:form="databaseForm"
:testing="databaseTesting"
:verified="databaseVerified"
:error="databaseError"
@test="testDatabase"
/>
</div>
<DatabaseSetup
v-if="isBootstrap"
:form="databaseForm"
:testing="databaseTesting"
:verified="databaseVerified"
:error="databaseError"
@test="testDatabase"
/>
<div class="provider-description reset-preview">
<strong>密码重置地址预览</strong>
<span>{{ resetURLPreview }}</span>

View File

@ -241,3 +241,20 @@ test("首次向导拒绝畸形成功响应而不是误报完成", async (t) => {
assert.equal(state.dnsVerification.value, null);
}
});
test("bootstrap service port defaults to 80 independently of listener port", async (t) => {
const { state, submitted } = await setup(t);
assert.equal(state.form.value.server_port, 80);
state.currentStep.value = 4;
await state.handleSubmit();
assert.equal(submitted[0].server_port, 80);
});
test("bootstrap service port accepts a custom port", async (t) => {
const { state, submitted } = await setup(t);
state.form.value.server_port = 8443;
state.currentStep.value = 4;
await state.handleSubmit();
assert.equal(submitted[0].server_port, 8443);
});

View File

@ -97,6 +97,13 @@
margin: 10px 0 4px;
}
.access-shell--setup .setup-step-card > .setup-section-heading {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 4px 10px;
}
.access-shell--setup .setup-section-heading strong,
.access-shell--setup .notification-section-heading strong,
.access-shell--setup .notification-advanced-toggle strong,
@ -109,47 +116,69 @@
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.access-shell--setup .setup-step-card > .setup-section-heading + .setup-grid {
grid-template-columns: minmax(0, 0.8fr) minmax(0, 1fr) minmax(0, 1.2fr);
}
.access-shell--setup .email-input-group {
grid-template-columns: minmax(0, 1fr) 96px;
}
.access-shell--setup .database-setup {
.access-shell--setup .service-access-grid {
grid-template-columns: repeat(3, minmax(0, 1fr));
align-items: start;
}
.access-shell--setup .service-access-grid.has-database {
grid-template-columns: minmax(168px, 0.85fr) minmax(160px, 1.1fr) minmax(140px, 0.8fr) minmax(310px, 1.8fr);
}
.access-shell--setup .service-access-grid > .database-setup {
display: contents;
}
.access-shell--setup .database-type-field {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: start;
gap: 8px;
margin-top: 12px;
padding-top: 10px;
min-width: 0;
}
.access-shell--setup .database-setup .setup-section-heading {
margin: 0;
.access-shell--setup .database-type-field .dns-test-actions {
display: contents;
}
.access-shell--setup .database-setup > .setup-grid {
grid-template-columns: repeat(4, minmax(0, 1fr));
.access-shell--setup .database-type-field .dns-test-button {
width: 92px;
height: auto;
min-height: 36px;
margin-top: calc(8px + 1.35 * 12px);
white-space: normal;
overflow-wrap: anywhere;
padding: 6px 10px;
font-size: 12px;
}
.access-shell--setup .database-setup:not(:has(#database-host)) {
grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) auto;
align-items: center;
}
.access-shell--setup .database-setup:not(:has(#database-host)) > .setup-grid {
grid-template-columns: minmax(0, 1fr);
}
.access-shell--setup .database-setup:not(:has(#database-host)) > .inline-error {
.access-shell--setup .database-type-field [role="status"] {
grid-column: 1 / -1;
}
.access-shell--setup .database-setup .dns-test-actions {
margin-top: 0;
.access-shell--setup .database-setup > .setup-section-heading,
.access-shell--setup .database-setup > .database-connection-grid,
.access-shell--setup .database-setup > p {
grid-column: 1 / -1;
margin: 0;
}
.access-shell--setup .database-setup:not(:has(#database-host)) .dns-test-actions {
max-width: 200px;
.access-shell--setup .database-setup > .setup-section-heading {
display: flex;
flex-wrap: wrap;
align-items: baseline;
gap: 4px 10px;
padding-top: 8px;
border-top: 1px solid #e4ebf5;
}
.access-shell--setup .database-connection-grid {
grid-template-columns: repeat(6, minmax(0, 1fr));
align-items: end;
}
.access-shell--setup .reset-preview,
@ -295,3 +324,13 @@
margin-bottom: 16px;
}
}
@media (min-width: 901px) and (max-width: 1279px) {
.access-shell--setup .service-access-grid.has-database {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.access-shell--setup .database-connection-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}