diff --git a/fe/src/views/Setup/Setup.css b/fe/src/views/Setup/Setup.css index 6f96595..5b8599b 100644 --- a/fe/src/views/Setup/Setup.css +++ b/fe/src/views/Setup/Setup.css @@ -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%; + } } \ No newline at end of file diff --git a/fe/src/views/Setup/Setup.js b/fe/src/views/Setup/Setup.js index 0cb19d0..2891f62 100644 --- a/fe/src/views/Setup/Setup.js +++ b/fe/src/views/Setup/Setup.js @@ -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 } diff --git a/fe/src/views/Setup/Setup.vue b/fe/src/views/Setup/Setup.vue index b2597b0..072fb35 100644 --- a/fe/src/views/Setup/Setup.vue +++ b/fe/src/views/Setup/Setup.vue @@ -274,16 +274,17 @@ - -
-

{{ lang.setSSL }}

-
{{ lang.setSSL }}
+
+

{{ lang.setSSL }}

+ +
+
{{ lang.setSSL }}
@@ -295,16 +296,18 @@ - - - - +
+ + + + - - ? - + + ? + +
@@ -346,6 +349,14 @@ {{ sslSettings.paramsList.length }} 条记录
+ @@ -393,10 +404,12 @@ const { sslSettings, port, dnsChecking, + dnsChallengeNotice, waitDesc, next, previous, handleDbTypeChange, + handleSSLChallengeChange, clearDatabaseError, formatDNSRecordTTL, copyDNSValue,