This commit is contained in:
parent
8abc09a43b
commit
2604b6f2bc
@ -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;
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user