将注销入口移动到侧栏当前账号区域
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-09-18 16:56:27 +08:00
parent bd48352405
commit 5279e56018
6 changed files with 73 additions and 11 deletions

View File

@ -115,7 +115,7 @@
}
.account-caption {
grid-column: 1 / -1;
grid-column: 1;
color: var(--pm-text-secondary);
font-size: 11px;
line-height: 1.4;
@ -132,10 +132,42 @@
}
.account-role {
justify-self: end;
border-radius: 6px;
font-size: 11px;
}
.logout-btn {
display: inline-flex;
align-items: center;
justify-content: center;
justify-self: end;
width: 32px;
height: 32px;
padding: 0;
border: 0;
border-radius: 6px;
background: transparent;
color: var(--pm-text-secondary);
font-size: 18px;
cursor: pointer;
}
.logout-btn:hover:not(:disabled) {
background: var(--el-color-danger-light-9);
color: var(--el-color-danger);
}
.logout-btn:focus-visible {
outline: 2px solid var(--pm-primary-color);
outline-offset: 2px;
}
.logout-btn:disabled {
opacity: 0.5;
cursor: wait;
}
.settings-btn {
display: flex;
width: 100%;

View File

@ -8,7 +8,8 @@ import lang from "../../../i18n/i18n";
import { http } from "@/utils/axios";
import { Setting } from "@element-plus/icons-vue";
import { Setting, SwitchButton } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import { useGlobalStatusStore } from "../../../stores/useGlobalStatusStore";
@ -25,6 +26,22 @@ export function usePage() {
const currentAccount = computed(() => globalStatus.userInfos.account || '账号未加载');
const currentRole = computed(() => roleMeta(globalStatus.role));
const loggingOut = ref(false);
const logout = async () => {
if (loggingOut.value) return;
loggingOut.value = true;
try {
const result = await http.post('/api/v1/logout', {});
if (result.errorNo !== 0) {
throw new Error(result.errorMsg || '注销失败,请重试');
}
location.reload();
} catch (error) {
ElMessage.error(error.message || '注销失败,请重试');
loggingOut.value = false;
}
};
const router = useRouter();
@ -89,6 +106,8 @@ export function usePage() {
isLogin,
currentAccount,
currentRole,
loggingOut,
logout,
router,
data,
searchQuery,
@ -100,5 +119,6 @@ export function usePage() {
export {
BrandLogo,
Setting
Setting,
SwitchButton
}

View File

@ -32,6 +32,18 @@
<div class="sidebar-footer" v-if="isLogin">
<div class="account-identity" aria-label="当前登录账号" aria-live="polite">
<span class="account-caption">当前账号</span>
<el-tooltip :content="lang.logout" placement="top">
<button
type="button"
class="logout-btn"
:aria-label="lang.logout"
:aria-busy="loggingOut"
:disabled="loggingOut"
@click="logout"
>
<el-icon><SwitchButton /></el-icon>
</button>
</el-tooltip>
<strong class="account-name" :title="currentAccount">{{ currentAccount }}</strong>
<el-tag :type="currentRole.type" size="small" effect="light" class="account-role">
{{ currentRole.label }}
@ -46,7 +58,7 @@
</template>
<script setup>
import { usePage, BrandLogo, Setting } from './HomeAside.js'
import { usePage, BrandLogo, Setting, SwitchButton } from './HomeAside.js'
const {
searchQuery,
@ -57,6 +69,8 @@ const {
isLogin,
currentAccount,
currentRole,
loggingOut,
logout,
openSettings
} = usePage()
</script>

View File

@ -21,7 +21,7 @@
.premium-input :deep(.el-input__wrapper) { box-shadow: none; border-radius: var(--pm-radius-sm); border: 1px solid var(--pm-border-color); background-color: var(--pm-bg-secondary); transition: all 0.2s; }
.premium-input :deep(.el-input__wrapper:hover), .premium-input :deep(.el-input__wrapper.is-focus) { border-color: var(--pm-primary-color); background-color: var(--pm-bg-primary); }
.form-actions { margin-top: 24px; }
.submit-btn, .logout-btn { border-radius: var(--pm-radius-sm); font-weight: 500; }
.submit-btn { border-radius: var(--pm-radius-sm); font-weight: 500; }
.submit-btn { padding: 10px 24px; }
.settings-divider { margin: 32px 0; border-color: var(--pm-border-color); }
.security-key-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }

View File

@ -26,7 +26,6 @@ export function usePage() {
}
options.push({ value: 'external-email', label: '外部安全邮箱' })
options.push({ value: 'webauthn', label: '安全密钥' })
options.push({ value: 'logout', label: lang.logout })
return options
})
const selectedSection = computed({
@ -259,7 +258,6 @@ export function usePage() {
}
const formatTime = value => value ? new Date(value).toLocaleString('zh-CN', { hour12: false }) : '-'
const logout = () => http.post('/api/v1/logout', {}).then(() => location.reload())
const submit = async () => {
if (passwordSubmitting.value || passwordSending.value) return
@ -348,6 +346,6 @@ export function usePage() {
externalDialogVisible, ruleForm, rules, submit, registerCredential, renameCredential, revokeCredential,
saveSecurityQuestion, generateRecoveryCodes, revokeRecoveryCodes, openExternalEmailDialog,
handleExternalEmailBound,
disableExternalEmail, formatTime, logout,
disableExternalEmail, formatTime,
}
}

View File

@ -124,8 +124,6 @@
</section>
<el-alert v-if="selectedSection === 'webauthn' && !supported" title="当前浏览器不支持 WebAuthn,请使用 HTTPS 和受支持的浏览器。" type="warning" :closable="false" show-icon />
<el-divider v-if="selectedSection === 'logout'" class="settings-divider" />
<section v-if="selectedSection === 'logout'" class="security-section"><div class="settings-header"><h3 class="danger-text">{{ lang.logout }}</h3><p class="settings-desc">{{ lang.logout_desc }}</p></div><el-button type="danger" plain @click="logout" class="logout-btn">{{ lang.logout }}</el-button></section>
<ExternalEmailBindingDialog
v-model="externalDialogVisible"
@ -152,7 +150,7 @@ const {
externalDialogVisible, ruleForm, rules, submit, registerCredential, renameCredential, revokeCredential,
saveSecurityQuestion, generateRecoveryCodes, revokeRecoveryCodes, openExternalEmailDialog,
handleExternalEmailBound,
disableExternalEmail, formatTime, logout,
disableExternalEmail, formatTime,
} = usePage()
</script>