完成SSL DNS验证流程优化

This commit is contained in:
smail 2026-09-02 01:22:02 +08:00
parent ecb8277496
commit 593a633689
3 changed files with 192 additions and 19 deletions

View File

@ -1786,4 +1786,72 @@
min-width: 40px;
width: 40px;
}
}
/* SSL页面专属布局规则:提示与标题同排,验证帮助与选择框同排。 */
.ssl-page .ssl-title-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 18px;
width: 100%;
}
.ssl-page .ssl-title-row h2 {
flex: none;
}
.ssl-page .ssl-title-description {
margin-top: 10px;
}
.ssl-page .ssl-challenge-select-row {
display: flex;
align-items: center;
gap: 10px;
width: 100%;
}
.ssl-page .ssl-challenge-select-row .ssl-type-select {
flex: 1 1 auto;
min-width: 0;
}
.ssl-page .ssl-challenge-help {
flex: none;
}
.ssl-page .ssl-help-mark {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
color: var(--pm-brand);
border: 1px solid rgba(0, 113, 227, 0.28);
border-radius: 50%;
font-size: 15px;
font-weight: 700;
line-height: 1;
cursor: help;
}
.ssl-page .ssl-port-warning {
flex: 1 1 auto;
min-width: 0;
}
.ssl-page .ssl-dns-refresh-notice {
width: 100%;
}
@media (max-width: 760px) {
.ssl-page .ssl-title-row {
align-items: stretch;
flex-direction: column;
gap: 10px;
}
.ssl-page .ssl-port-warning {
width: 100%;
}
}

View File

@ -115,6 +115,7 @@ export function usePage() {
}
const dnsChecking = ref(false)
const dnsChallengeNotice = ref("")
const dnsInfos = ref({})
@ -382,6 +383,7 @@ export function usePage() {
if (sslType === "2") {
fullscreenLoading.value = false
dnsChecking.value = true
dnsChallengeNotice.value = ""
return getSSLDNSParams()
}
if (sslType === "1") {
@ -404,6 +406,8 @@ export function usePage() {
let statusCheckRunning = false
let statusCheckStartedAt = 0
const statusCheckTimeout = 10 * 60 * 1000
const dnsVerificationTimeout = 30 * 60 * 1000
const dnsChallengeTimerDelay = 30 * 60 * 1000
const stopStatusCheck = () => {
if (statusTimer !== null) {
@ -421,14 +425,25 @@ export function usePage() {
}
}
let dnsChallengeTimer = null
const stopDNSChallengeTimer = () => {
if (dnsChallengeTimer !== null) {
window.clearTimeout(dnsChallengeTimer)
dnsChallengeTimer = null
}
}
onUnmounted(() => {
setupViewUnmounted = true
stopStatusCheck()
stopDNSParamsPolling()
stopDNSChallengeTimer()
})
const navigateToFormalService = (sslData) => {
stopStatusCheck()
stopDNSChallengeTimer()
fullscreenLoading.value = false
const target = buildFinalURL(sslData)
if (target && target !== window.location.href) {
@ -453,10 +468,17 @@ export function usePage() {
if (!statusCheckStartedAt) {
statusCheckStartedAt = Date.now()
}
if (Date.now() - statusCheckStartedAt > statusCheckTimeout) {
const currentStatusCheckTimeout = dnsChecking.value && sslSettings.challenge === "dns"
? dnsVerificationTimeout
: statusCheckTimeout
if (Date.now() - statusCheckStartedAt > currentStatusCheckTimeout) {
stopStatusCheck()
fullscreenLoading.value = false
ElMessage.error(lang.setup_failed)
if (dnsChecking.value && sslSettings.challenge === "dns") {
refreshDNSChallenge()
} else {
ElMessage.error(lang.setup_failed)
}
return
}
@ -516,6 +538,9 @@ export function usePage() {
}, 1000)
} else if (sslSettings.paramsList.length > 0 || !dnsChecking.value) {
stopDNSParamsPolling()
if (sslSettings.paramsList.length > 0 && dnsChecking.value) {
scheduleDNSChallengeRefresh()
}
}
return res
}).catch((error) => {
@ -525,6 +550,61 @@ export function usePage() {
})
}
const scheduleDNSChallengeRefresh = () => {
stopDNSChallengeTimer()
if (setupViewUnmounted || !dnsChecking.value) {
return
}
dnsChallengeTimer = window.setTimeout(() => {
dnsChallengeTimer = null
refreshDNSChallenge()
}, dnsChallengeTimerDelay)
}
const getDNSRefreshNotice = () => `${lang.ssl_dns_ready}(记录已刷新,请使用最新记录。)`
const refreshDNSChallenge = () => {
if (setupViewUnmounted || !dnsChecking.value || fullscreenLoading.value) {
return
}
stopStatusCheck()
stopDNSChallengeTimer()
stopDNSParamsPolling()
fullscreenLoading.value = true
return setupRequest({
"action": "set",
"step": "ssl",
"ssl_type": "2",
"key_path": sslSettings.key_path,
"crt_path": sslSettings.crt_path
}).then((res) => {
assertSetupSuccess(res)
sslSettings.paramsList = []
dnsChallengeNotice.value = getDNSRefreshNotice()
return getSSLDNSParams()
}).then((res) => {
ElMessage.warning(getDNSRefreshNotice())
return res
}).catch((error) => {
showSetupError(error)
return null
}).finally(() => {
fullscreenLoading.value = false
})
}
const handleSSLChallengeChange = (challenge) => {
if (challenge !== "dns" || dnsChecking.value || fullscreenLoading.value) {
return
}
dnsChallengeNotice.value = ""
return setSSLConfig()
}
const runStep = (action) => {
if (stepLoading.value) {
return
@ -568,6 +648,7 @@ export function usePage() {
break
case 5:
if (dnsChecking.value) {
stopDNSChallengeTimer()
fullscreenLoading.value = true
waitDesc.value = lang.dns_challenge_wait
checkStatus()
@ -579,6 +660,15 @@ export function usePage() {
}
const previous = () => {
if (active.value > 0) {
if (active.value === 5) {
stopStatusCheck()
stopDNSChallengeTimer()
stopDNSParamsPolling()
dnsChecking.value = false
dnsChallengeNotice.value = ""
sslSettings.paramsList = []
fullscreenLoading.value = false
}
active.value--
}
}
@ -602,6 +692,7 @@ export function usePage() {
active,
fullscreenLoading,
dnsChecking,
dnsChallengeNotice,
dnsInfos,
hasDNSIPv6,
port,
@ -621,6 +712,7 @@ export function usePage() {
checkStatus,
setDomainConfig,
getSSLDNSParams,
handleSSLChallengeChange,
next,
previous
}

View File

@ -274,16 +274,17 @@
<el-empty v-else :description="lang.dns_empty" />
</div>
<div v-if="active === 5 && sslSettings.type === '0' && sslSettings.challenge === 'http' && port !== 80"
class="ssl-port-warning" role="alert">
<strong>{{ lang.warning }}</strong>
<span>{{ lang.autoSSLWarn }}</span>
</div>
<div v-if="active === 5" class="ctn setup-form-panel">
<div class="desc">
<h2>{{ lang.setSSL }}</h2>
<div style="margin-top: 10px;">{{ lang.setSSL }}</div>
<div class="ssl-title-row">
<h2>{{ lang.setSSL }}</h2>
<div v-if="sslSettings.type === '0' && sslSettings.challenge === 'http' && port !== 80"
class="ssl-port-warning" role="alert">
<strong>{{ lang.warning }}</strong>
<span>{{ lang.autoSSLWarn }}</span>
</div>
</div>
<div class="ssl-title-description">{{ lang.setSSL }}</div>
</div>
<div class="form ssl-form">
<el-form label-position="top">
@ -295,16 +296,18 @@
</el-form-item>
<el-form-item :label="lang.ssl_challenge_type" v-if="sslSettings.type === '0'">
<el-select class="ssl-type-select" :placeholder="lang.ssl_auto_http" v-model="sslSettings.challenge"
:disabled="dnsChecking">
<el-option :label="lang.ssl_auto_http" value="http"/>
<el-option :label="lang.ssl_auto_dns" value="dns"/>
</el-select>
<div class="ssl-challenge-select-row">
<el-select class="ssl-type-select" :placeholder="lang.ssl_auto_http" v-model="sslSettings.challenge"
:disabled="dnsChecking || fullscreenLoading" @change="handleSSLChallengeChange">
<el-option :label="lang.ssl_auto_http" value="http"/>
<el-option :label="lang.ssl_auto_dns" value="dns"/>
</el-select>
<el-tooltip class="box-item" effect="dark" :content="lang.challenge_typ_desc"
placement="top-start">
<span style="margin-left: 6px; font-size:18px; font-weight: bolder;">?</span>
</el-tooltip>
<el-tooltip class="ssl-challenge-help" effect="dark" :content="lang.challenge_typ_desc"
placement="top-start">
<span class="ssl-help-mark">?</span>
</el-tooltip>
</div>
</el-form-item>
<div v-if="sslSettings.type === '0'" class="ssl-storage-card">
@ -346,6 +349,14 @@
{{ sslSettings.paramsList.length }} 条记录
</span>
</div>
<el-alert
v-if="dnsChallengeNotice"
:title="dnsChallengeNotice"
type="warning"
show-icon
:closable="false"
class="ssl-dns-refresh-notice"
/>
<el-table v-if="sslSettings.paramsList.length > 0" :data="sslSettings.paramsList" border>
<el-table-column prop="host" label="主机名" width="180px"/>
<el-table-column prop="type" label="类型" width="100px"/>
@ -393,10 +404,12 @@ const {
sslSettings,
port,
dnsChecking,
dnsChallengeNotice,
waitDesc,
next,
previous,
handleDbTypeChange,
handleSSLChallengeChange,
clearDatabaseError,
formatDNSRecordTTL,
copyDNSValue,