完善仪表盘DNS在线测试界面
This commit is contained in:
parent
f1c7fc34bd
commit
21dad55b45
@ -1020,4 +1020,155 @@ code {
|
||||
.version-row {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.settings-modal {
|
||||
width: min(100%, 1080px);
|
||||
max-height: calc(100vh - 24px);
|
||||
padding: 30px 34px;
|
||||
}
|
||||
|
||||
.settings-section-note {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
margin: -2px 0 16px;
|
||||
padding: 11px 13px;
|
||||
border: 1px solid #d8e6f3;
|
||||
border-radius: 10px;
|
||||
color: #637895;
|
||||
background: #f7fbff;
|
||||
font-size: 12px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.dns-provider-description {
|
||||
margin: -3px 0 15px;
|
||||
padding: 0 2px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.dns-credentials-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: 0 14px;
|
||||
}
|
||||
|
||||
.dns-test-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
margin: 2px 0 15px;
|
||||
padding: 12px 13px;
|
||||
border: 1px solid #d8e6f3;
|
||||
border-radius: 11px;
|
||||
background: #fbfdff;
|
||||
}
|
||||
|
||||
.dns-test-actions .text-button {
|
||||
padding: 5px 2px;
|
||||
}
|
||||
|
||||
.dns-verification-status {
|
||||
margin-left: auto;
|
||||
padding: 5px 10px;
|
||||
border-radius: 999px;
|
||||
color: #8b681e;
|
||||
background: #fff4d9;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.dns-verification-status.verified {
|
||||
color: #24734b;
|
||||
background: #e7f8ee;
|
||||
}
|
||||
|
||||
.dns-test-report {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
margin: 8px 0 16px;
|
||||
padding: 13px 14px;
|
||||
border: 1px solid #d9e6f3;
|
||||
border-radius: 11px;
|
||||
background: #f8fbff;
|
||||
}
|
||||
|
||||
.dns-test-report-heading {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
|
||||
.dns-test-report-heading strong {
|
||||
color: #32405a;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.dns-test-report-heading span,
|
||||
.dns-test-stage span {
|
||||
color: #6d7b91;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.dns-test-stage {
|
||||
display: grid;
|
||||
grid-template-columns: 8px minmax(0, 1fr);
|
||||
align-items: start;
|
||||
gap: 9px;
|
||||
padding: 8px 0;
|
||||
border-top: 1px solid #e6eef6;
|
||||
}
|
||||
|
||||
.dns-test-stage > div {
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.dns-test-stage strong {
|
||||
color: #32405a;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.dns-stage-indicator {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
margin-top: 4px;
|
||||
border-radius: 50%;
|
||||
background: #f0b44c;
|
||||
}
|
||||
|
||||
.dns-stage-indicator.success {
|
||||
background: #45ad72;
|
||||
}
|
||||
|
||||
.dns-stage-indicator.failed,
|
||||
.dns-stage-indicator.error {
|
||||
background: #c55c5c;
|
||||
}
|
||||
|
||||
@media (min-width: 1100px) {
|
||||
.settings-modal {
|
||||
width: min(100%, 1080px);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.settings-modal {
|
||||
max-height: calc(100vh - 16px);
|
||||
padding: 24px 20px;
|
||||
}
|
||||
|
||||
.dns-credentials-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.dns-verification-status {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1029,6 +1029,7 @@ export function useDashboard() {
|
||||
taskResponse,
|
||||
auditResponse,
|
||||
settingsResponse,
|
||||
dnsProviderResponse,
|
||||
] = await Promise.all([
|
||||
fetchAdmin("/api/v1/status"),
|
||||
fetchAdmin("/api/v1/domains"),
|
||||
@ -1038,6 +1039,7 @@ export function useDashboard() {
|
||||
fetchAdmin("/api/v1/tasks?limit=20"),
|
||||
fetchAdmin("/api/v1/audit-logs?limit=20"),
|
||||
fetchAdmin("/api/v1/settings"),
|
||||
fetchAdmin("/api/v1/dns/providers"),
|
||||
]);
|
||||
const failedResponse = [
|
||||
statusResponse,
|
||||
@ -1048,6 +1050,7 @@ export function useDashboard() {
|
||||
taskResponse,
|
||||
auditResponse,
|
||||
settingsResponse,
|
||||
dnsProviderResponse,
|
||||
].find((response) => !response.ok);
|
||||
if (failedResponse) {
|
||||
throw new Error(await responseError(failedResponse, "读取管理数据失败"));
|
||||
@ -1060,6 +1063,12 @@ export function useDashboard() {
|
||||
tasks.value = (await taskResponse.json()).items || [];
|
||||
auditLogs.value = (await auditResponse.json()).items || [];
|
||||
settings.value = await settingsResponse.json();
|
||||
const providerResult = await dnsProviderResponse.json();
|
||||
dnsProviderCatalog.value = (providerResult.items || []).map((item) => ({
|
||||
...item,
|
||||
value: item.id,
|
||||
label: item.name,
|
||||
}));
|
||||
settingsForm.value = normalizeSettings(settings.value);
|
||||
const associations = await Promise.all(
|
||||
domains.value.map(async (item) => {
|
||||
@ -1096,6 +1105,14 @@ export function useDashboard() {
|
||||
auditLogs,
|
||||
settings,
|
||||
settingsForm,
|
||||
dnsProviderCatalog,
|
||||
selectedDNSProvider,
|
||||
dnsTesting,
|
||||
dnsTestError,
|
||||
dnsReadyToSave,
|
||||
handleDNSProviderChange,
|
||||
clearDNSCredentials,
|
||||
testDNS,
|
||||
domainServers,
|
||||
loading,
|
||||
saving,
|
||||
|
||||
@ -55,6 +55,14 @@ const {
|
||||
showSettings,
|
||||
settingsSaving,
|
||||
settingsError,
|
||||
dnsProviderCatalog,
|
||||
selectedDNSProvider,
|
||||
dnsTesting,
|
||||
dnsTestError,
|
||||
dnsReadyToSave,
|
||||
handleDNSProviderChange,
|
||||
clearDNSCredentials,
|
||||
testDNS,
|
||||
sshKeyCommands,
|
||||
sshPublicKeyCommands,
|
||||
defaultCertificatePath,
|
||||
@ -464,6 +472,120 @@ const {
|
||||
<label class="field"><span>DNS 传播等待(秒)</span><input v-model.number="settingsForm.acme.propagation_timeout_secs" type="number" min="1" /></label>
|
||||
<label class="field"><span>DNS 检测间隔(秒)</span><input v-model.number="settingsForm.acme.propagation_polling_interval_secs" type="number" min="1" /></label>
|
||||
</div>
|
||||
<h3>DNS API 验证</h3>
|
||||
<div class="settings-section-note">
|
||||
<span>证书申请前会使用 DNS API 创建临时验证记录。</span>
|
||||
<span>凭据只会在本次在线测试请求中提交,系统仅保存加密引用。</span>
|
||||
</div>
|
||||
<div class="form-grid">
|
||||
<label class="field" for="settings-dns-provider">
|
||||
<span>DNS 服务商</span>
|
||||
<select
|
||||
id="settings-dns-provider"
|
||||
v-model="settingsForm.dns.provider"
|
||||
@change="handleDNSProviderChange"
|
||||
>
|
||||
<option value="">暂不配置</option>
|
||||
<option
|
||||
v-for="provider in dnsProviderCatalog"
|
||||
:key="provider.id"
|
||||
:value="provider.id"
|
||||
:disabled="!provider.available"
|
||||
>
|
||||
{{ provider.name }}{{ provider.available ? "" : "(暂不可用)" }}
|
||||
</option>
|
||||
</select>
|
||||
</label>
|
||||
<label class="field" for="settings-dns-test-domain">
|
||||
<span>在线测试域名</span>
|
||||
<input
|
||||
id="settings-dns-test-domain"
|
||||
v-model="settingsForm.dns.test_domain"
|
||||
placeholder="例如 example.com"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<p v-if="selectedDNSProvider" class="field-hint dns-provider-description">
|
||||
{{ selectedDNSProvider.description }}
|
||||
</p>
|
||||
<p
|
||||
v-if="selectedDNSProvider && !selectedDNSProvider.available"
|
||||
class="form-error"
|
||||
>
|
||||
当前服务商适配器暂未开放,无法进行在线测试。
|
||||
</p>
|
||||
<div v-if="selectedDNSProvider" class="dns-credentials-grid">
|
||||
<label
|
||||
v-for="field in selectedDNSProvider.credential_fields"
|
||||
:key="field.name"
|
||||
class="field"
|
||||
:for="`settings-dns-${field.name}`"
|
||||
>
|
||||
<span>
|
||||
{{ field.label }}
|
||||
<small v-if="field.required">必填</small>
|
||||
</span>
|
||||
<input
|
||||
:id="`settings-dns-${field.name}`"
|
||||
v-model="settingsForm.dns.credentials[field.name]"
|
||||
:type="field.secret ? 'password' : 'text'"
|
||||
:placeholder="field.placeholder"
|
||||
:required="field.required"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div v-if="selectedDNSProvider" class="dns-test-actions">
|
||||
<button
|
||||
class="secondary-button"
|
||||
type="button"
|
||||
:disabled="dnsTesting || settingsSaving || !selectedDNSProvider.available"
|
||||
@click="testDNS"
|
||||
>
|
||||
{{ dnsTesting ? "测试中……" : "在线测试 DNS API" }}
|
||||
</button>
|
||||
<button
|
||||
class="text-button"
|
||||
type="button"
|
||||
:disabled="dnsTesting || settingsSaving"
|
||||
@click="clearDNSCredentials"
|
||||
>
|
||||
清空凭据
|
||||
</button>
|
||||
<span
|
||||
class="dns-verification-status"
|
||||
:class="settingsForm.dns.verification_state"
|
||||
>
|
||||
{{ settingsForm.dns.verification_state === "verified" ? "已验证" : "待验证" }}
|
||||
</span>
|
||||
</div>
|
||||
<p v-if="dnsTestError" class="form-error">{{ dnsTestError }}</p>
|
||||
<div
|
||||
v-if="settingsForm.dns.test_report?.stages?.length"
|
||||
class="dns-test-report"
|
||||
>
|
||||
<div class="dns-test-report-heading">
|
||||
<strong>在线测试结果</strong>
|
||||
<span v-if="settingsForm.dns.test_report.record_name">
|
||||
临时记录:{{ settingsForm.dns.test_report.record_name }}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="stage in settingsForm.dns.test_report.stages"
|
||||
:key="stage.name"
|
||||
class="dns-test-stage"
|
||||
>
|
||||
<span class="dns-stage-indicator" :class="stage.status"></span>
|
||||
<div>
|
||||
<strong>{{ stage.name }}</strong>
|
||||
<span>{{ stage.message }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p v-if="!dnsReadyToSave" class="security-hint">
|
||||
DNS 服务商发生变化或尚未配置时,必须先完成 DNS API 在线测试。
|
||||
</p>
|
||||
<h3>HTTP 通知</h3>
|
||||
<div class="form-grid">
|
||||
<label class="switch-field">
|
||||
@ -503,7 +625,13 @@ const {
|
||||
<p v-if="settingsError" class="form-error">{{ settingsError }}</p>
|
||||
<div class="modal-actions">
|
||||
<button class="secondary-button" type="button" :disabled="settingsSaving" @click="closeSettings">取消</button>
|
||||
<button class="primary-button" type="submit" :disabled="settingsSaving">{{ settingsSaving ? "保存中……" : "保存设置" }}</button>
|
||||
<button
|
||||
class="primary-button"
|
||||
type="submit"
|
||||
:disabled="settingsSaving || !dnsReadyToSave"
|
||||
>
|
||||
{{ settingsSaving ? "保存中……" : "保存设置" }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user