优化登录验证布局并补充动态码禁用提示
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-09-18 21:27:48 +08:00
parent 8abc09a43b
commit 2604b6f2bc
2 changed files with 155 additions and 57 deletions

View File

@ -14,7 +14,7 @@
}
.verification-heading {
margin-bottom: 32px;
margin-bottom: 24px;
}
.verification-eyebrow {
@ -45,24 +45,113 @@
}
.verification-methods {
display: flex;
flex-wrap: wrap;
gap: 12px;
margin-bottom: 16px;
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
margin-bottom: 24px;
}
.verification-method {
display: block;
min-width: 0;
border-radius: 10px;
}
.verification-method:has(.is-disabled) {
cursor: not-allowed;
}
.verification-method:focus-visible {
outline: 2px solid var(--pm-primary-color);
outline-offset: 3px;
}
.verification-methods .el-button {
flex: 1;
width: 100%;
min-height: 48px;
margin: 0;
padding: 10px 8px;
border-radius: 10px;
}
.verification-hint,
.verification-delivery {
.verification-methods .el-button.is-disabled {
pointer-events: none;
}
:global(.verification-method-tooltip) {
max-width: 280px;
line-height: 1.7;
}
.verification-hint {
color: var(--pm-text-secondary);
font-size: 14px;
line-height: 1.7;
margin: 0 0 20px;
}
.verification-placeholder {
text-align: center;
}
.verification-delivery {
padding: 16px;
margin-bottom: 20px;
border: 1px solid var(--pm-border-color);
border-radius: 12px;
}
.verification-delivery-row {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 12px;
}
.verification-email {
flex: 1 1 180px;
min-width: 0;
display: flex;
flex-direction: column;
gap: 6px;
}
.verification-email span {
color: var(--pm-text-secondary);
font-size: 13px;
}
.verification-email strong {
color: var(--pm-text-primary);
font-size: 14px;
font-weight: 500;
overflow-wrap: anywhere;
}
.verification-send {
min-height: 36px;
margin: 0;
border-radius: 8px;
}
.verification-delivery-status {
margin: 12px 0 0;
color: var(--pm-text-secondary);
font-size: 13px;
line-height: 1.6;
}
.verification-form :deep(.el-form-item) {
margin-bottom: 18px;
}
.verification-form :deep(.el-form-item__label) {
margin-bottom: 8px;
line-height: 1.5;
}
.verification-form :deep(.el-alert) {
margin-bottom: 16px;
}
.verification-input :deep(.el-input__wrapper) {
@ -78,18 +167,13 @@
text-align: center;
}
.verification-submit,
.webauthn-login-button {
.verification-submit {
width: 100%;
min-height: 48px;
border-radius: 12px;
font-weight: 600;
}
.verification-submit {
margin-top: 24px;
}
.verification-actions {
display: flex;
justify-content: center;
@ -97,14 +181,6 @@
margin-top: 14px;
}
.webauthn-unavailable {
margin: 0;
color: var(--pm-text-secondary);
font-size: 13px;
line-height: 1.6;
text-align: center;
}
@media (max-width: 760px) {
.verification-content {
min-height: 0;

View File

@ -13,38 +13,62 @@
</div>
<div class="verification-methods">
<el-button
:type="method === 'email' ? 'primary' : 'default'"
:disabled="!methods.includes('email') || loading"
@click="chooseMethod('email')"
>邮箱验证码</el-button>
<el-button
:type="method === 'totp' ? 'primary' : 'default'"
:disabled="!methods.includes('totp') || loading"
@click="chooseMethod('totp')"
>手机动态码(TOTP)</el-button>
<el-tooltip
:disabled="methods.includes('email') && !loading"
:content="loading ? '正在验证,请稍候。' : '尚未绑定可用的安全邮箱,请使用已启用的手机动态码登录。'"
placement="top"
:show-after="150"
>
<span class="verification-method" :tabindex="!methods.includes('email') || loading ? 0 : undefined">
<el-button
:type="method === 'email' ? 'primary' : 'default'"
:disabled="!methods.includes('email') || loading"
:aria-pressed="method === 'email'"
@click="chooseMethod('email')"
>邮箱验证码</el-button>
</span>
</el-tooltip>
<el-tooltip
:disabled="methods.includes('totp') && !loading"
:content="loading ? '正在验证,请稍候。' : '尚未启用手机动态码。请先使用邮箱验证码登录,再前往「安全中心 → 手机动态码」开启。'"
placement="top"
:show-after="150"
popper-class="verification-method-tooltip"
>
<span class="verification-method" :tabindex="!methods.includes('totp') || loading ? 0 : undefined">
<el-button
:type="method === 'totp' ? 'primary' : 'default'"
:disabled="!methods.includes('totp') || loading"
:aria-pressed="method === 'totp'"
@click="chooseMethod('totp')"
>手机动态码(TOTP)</el-button>
</span>
</el-tooltip>
</div>
<p v-if="!methods.includes('totp')" class="verification-hint">
尚未启用手机动态码,可在登录后的安全中心自行开启。
</p>
<p v-if="!methods.includes('email')" class="verification-hint">
尚未绑定可用的安全邮箱,请使用手机动态码。
<p v-if="!method" class="verification-hint verification-placeholder">
请选择一种验证方式,完成验证后即可登录。
</p>
<div v-if="method === 'email'" class="verification-delivery" aria-live="polite">
<p>绑定邮箱:<strong>{{ pending?.email }}</strong></p>
<p>{{ deliveryMessage }}</p>
<el-button
:loading="resending"
:disabled="sending || retrySeconds > 0 || remainingSeconds <= 0"
@click="resendCode"
>{{ sending ? '正在发送' : retrySeconds > 0 ? `${retrySeconds} 秒后可重发` : '发送邮箱验证码' }}</el-button>
</div>
<p v-if="method === 'totp'" class="verification-hint">
打开已绑定的手机验证器,输入当前六位动态码。已使用的动态码请等待更新。
</p>
<el-form v-if="method" class="verification-form" label-position="top" @submit.prevent="verifyCode">
<div v-if="method === 'email'" class="verification-delivery">
<div class="verification-delivery-row">
<div class="verification-email">
<span>绑定邮箱</span>
<strong>{{ pending?.email }}</strong>
</div>
<el-button
class="verification-send"
:loading="resending"
:disabled="loading || sending || retrySeconds > 0 || remainingSeconds <= 0"
@click="resendCode"
>{{ sending ? '正在发送' : retrySeconds > 0 ? `${retrySeconds} 秒后可重发` : '发送验证码' }}</el-button>
</div>
<p class="verification-delivery-status" aria-live="polite">{{ deliveryMessage }}</p>
</div>
<p v-else class="verification-hint">
打开已绑定的手机验证器,输入当前六位动态码。已使用的动态码请等待更新。
</p>
<el-form v-if="method" class="verification-form" @submit.prevent="verifyCode">
<el-form-item :label="method === 'totp' ? '六位手机动态码' : '八位邮箱验证码'">
<el-input
v-model="code"
@ -65,12 +89,6 @@
show-icon
/>
<p class="verification-expiry">
{{ remainingSeconds > 0
? `请在 ${remainingSeconds} 秒内完成登录验证`
: "登录验证已过期,请重新登录" }}
</p>
<el-button
type="primary"
size="large"
@ -81,7 +99,11 @@
>
验证并登录
</el-button>
<p class="verification-expiry">
{{ remainingSeconds > 0
? `请在 ${remainingSeconds} 秒内完成登录验证`
: "登录验证已过期,请重新登录" }}
</p>
</el-form>
<div class="verification-actions">
<el-button link :disabled="loading" @click="goBackToLogin">返回登录</el-button>