统一生成十二个安全码并采用三行四列规整布局
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-09-27 18:10:55 +08:00
parent 2adc521ee6
commit de83f4ef81
8 changed files with 104 additions and 17 deletions

View File

@ -31,7 +31,7 @@ var (
)
const (
defaultCodeCount = 10
defaultCodeCount = 12
minCodeCount = 5
maxCodeCount = 20
)

View File

@ -35,22 +35,34 @@
.recovery-code-list {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px;
padding: 14px;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px;
padding: 8px;
border: 1px solid var(--pm-border-color);
border-radius: var(--pm-radius-md);
background: var(--pm-bg-secondary);
}
.recovery-code-list code {
padding: 8px 10px;
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
min-height: 44px;
box-sizing: border-box;
padding: 10px 4px;
border-radius: 8px;
color: var(--pm-text-primary);
background: var(--pm-bg-primary);
font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
font-size: 12px;
font-weight: 600;
font-variant-numeric: tabular-nums;
line-height: 1.5;
text-align: center;
letter-spacing: 0.08em;
letter-spacing: 0;
white-space: nowrap;
user-select: all;
}
.recovery-prompt-actions {
@ -59,7 +71,13 @@
gap: 10px;
}
@media (max-width: 520px) {
@media (max-width: 760px) {
.recovery-code-list {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 420px) {
.recovery-code-list {
grid-template-columns: 1fr;
}

View File

@ -2,7 +2,7 @@
<el-dialog
v-model="visible"
title="完善账户安全"
width="min(520px, calc(100vw - 32px))"
width="min(800px, calc(100vw - 32px))"
:close-on-click-modal="false"
class="recovery-setup-dialog"
@close="dismiss"
@ -11,7 +11,7 @@
<div class="recovery-prompt-icon">盾</div>
<h3>建议立即配置离线恢复码</h3>
<p>
离线恢复码可以在外部邮箱不可用时帮助您完成账户恢复。恢复码只会显示一次,生成后请保存到安全位置。
离线恢复码可以在外部邮箱不可用时帮助您完成账户恢复。请妥善保存,后续可在安全设置中验证本人密码后再次查看有效恢复码。
</p>
<el-alert
v-if="generatedCodes.length === 0"
@ -22,7 +22,7 @@
/>
<div v-else class="recovery-code-result">
<el-alert
title="恢复码已生成,请立即复制并妥善保存。离开此提示后将无法再次读取。"
title="恢复码已生成,请妥善保存;验证本人密码后可再次查看有效恢复码。"
type="success"
:closable="false"
show-icon
@ -85,7 +85,7 @@ const generateRecoveryCodes = async () => {
}
loading.value = true
try {
const response = await http.post("/api/v1/security/credentials/recovery-codes/generate", { count: 10 })
const response = await http.post("/api/v1/security/credentials/recovery-codes/generate", { count: 12 })
if (response.errorNo !== 0 || !Array.isArray(response.data?.codes)) {
throw new Error(response.errorMsg || "离线恢复码生成失败")
}

View File

@ -70,3 +70,53 @@
.password-verification-row strong {
overflow-wrap: anywhere;
}
.recovery-code-panel {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px;
margin-top: 16px;
}
.recovery-code-panel .one-time-tip {
grid-column: 1 / -1;
margin-bottom: 4px;
color: var(--pm-text-secondary);
font-size: 13px;
line-height: 1.6;
}
.recovery-code {
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
min-height: 44px;
box-sizing: border-box;
padding: 10px 4px;
border: 1px solid var(--pm-border-color);
border-radius: var(--pm-radius-sm);
background: var(--pm-bg-secondary);
color: var(--pm-text-primary);
font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
font-size: 12px;
font-weight: 600;
font-variant-numeric: tabular-nums;
line-height: 1.5;
letter-spacing: 0;
text-align: center;
white-space: nowrap;
user-select: all;
}
@container settings-content (max-width: 860px) {
.recovery-code-panel {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@container settings-content (max-width: 360px) {
.recovery-code-panel {
grid-template-columns: 1fr;
}
}

View File

@ -251,7 +251,7 @@ export function usePage() {
try {
await ElMessageBox.confirm('生成新恢复码会撤销当前仍有效的恢复码,请确认已准备好安全保存。', '生成离线恢复码', { type: 'warning' })
if (!isRecoveryViewCurrent(version)) return
const res = await requestRecoveryAction('generate', { count: 10 }, version)
const res = await requestRecoveryAction('generate', { count: 12 }, version)
if (!isRecoveryViewCurrent(version)) return
if (res.errorNo !== 0 || !Array.isArray(res.data?.codes)) throw new Error(res.errorMsg || '离线恢复码生成失败')
generatedCodes.value = res.data.codes

View File

@ -45,17 +45,30 @@
.recovery-code-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 8px;
}
.recovery-code-grid code {
padding: 9px 10px;
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
min-height: 44px;
box-sizing: border-box;
padding: 10px 4px;
border: 1px solid var(--pm-border-color);
border-radius: var(--pm-radius-sm);
background: var(--pm-bg-secondary);
color: var(--pm-text-primary);
font-family: ui-monospace, SFMono-Regular, Consolas, monospace;
font-size: 12px;
font-weight: 600;
font-variant-numeric: tabular-nums;
line-height: 1.5;
letter-spacing: 0;
text-align: center;
white-space: nowrap;
user-select: all;
}
@ -83,7 +96,13 @@
margin-left: 0;
}
@media (max-width: 520px) {
@media (max-width: 760px) {
.recovery-code-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 420px) {
.recovery-code-grid {
grid-template-columns: 1fr;
}

View File

@ -105,7 +105,7 @@ export function useRecoveryCodeDialog(props, emit) {
if (!isCurrentView(version, userID)) return null
const result = await http.post('/api/v1/user/security/recovery-codes/generate', {
user_id: userID,
count: 10,
count: 12,
})
return assertSuccess(result, '安全码生成失败')
})

View File

@ -2,7 +2,7 @@
<el-dialog
:model-value="visible"
title="管理安全码"
width="min(560px, calc(100vw - 32px))"
width="min(800px, calc(100vw - 32px))"
:close-on-click-modal="false"
:close-on-press-escape="!busy"
:show-close="!busy"