Add files via upload

This commit is contained in:
公明
2025-12-18 23:07:48 +08:00
committed by GitHub
parent c439113331
commit 1734092f9a
3 changed files with 141 additions and 0 deletions

View File

@@ -548,6 +548,74 @@ header {
background: var(--bg-primary);
}
/* 用户菜单样式 */
.user-menu-container {
position: relative;
}
.user-avatar-btn {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 50%;
border: 1px solid var(--border-color);
background: var(--bg-primary);
color: var(--text-secondary);
cursor: pointer;
transition: all 0.2s ease;
padding: 0;
}
.user-avatar-btn:hover {
background: var(--bg-tertiary);
border-color: var(--accent-color);
color: var(--accent-color);
}
.user-avatar-btn svg {
stroke: currentColor;
}
.user-menu-dropdown {
position: absolute;
top: calc(100% + 8px);
right: 0;
min-width: 160px;
background: var(--bg-primary);
border: 1px solid var(--border-color);
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
z-index: 1000;
overflow: hidden;
}
.user-menu-item {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
cursor: pointer;
color: var(--text-primary);
font-size: 0.875rem;
transition: all 0.2s ease;
border: none;
background: none;
width: 100%;
text-align: left;
}
.user-menu-item:hover {
background: var(--bg-tertiary);
color: var(--accent-color);
}
.user-menu-item svg {
stroke: currentColor;
flex-shrink: 0;
}
.attack-chain-btn:not(:disabled):hover {
background: var(--bg-tertiary);
border-color: var(--accent-color);

View File

@@ -328,4 +328,59 @@ async function initializeApp() {
showLoginOverlay();
}
// 用户菜单控制
function toggleUserMenu() {
const dropdown = document.getElementById('user-menu-dropdown');
if (!dropdown) return;
const isVisible = dropdown.style.display !== 'none';
dropdown.style.display = isVisible ? 'none' : 'block';
}
// 点击页面其他地方时关闭下拉菜单
document.addEventListener('click', function(event) {
const dropdown = document.getElementById('user-menu-dropdown');
const avatarBtn = document.querySelector('.user-avatar-btn');
if (dropdown && avatarBtn &&
!dropdown.contains(event.target) &&
!avatarBtn.contains(event.target)) {
dropdown.style.display = 'none';
}
});
// 退出登录
async function logout() {
// 关闭下拉菜单
const dropdown = document.getElementById('user-menu-dropdown');
if (dropdown) {
dropdown.style.display = 'none';
}
try {
// 先尝试调用退出API如果token有效
if (authToken) {
const headers = new Headers();
headers.set('Authorization', `Bearer ${authToken}`);
await fetch('/api/auth/logout', {
method: 'POST',
headers: headers,
}).catch(() => {
// 忽略错误,继续清除本地认证信息
});
}
} catch (error) {
console.error('退出登录API调用失败:', error);
} finally {
// 无论如何都清除本地认证信息
clearAuthStorage();
hideLoginOverlay();
showLoginOverlay('已退出登录');
}
}
// 导出函数供HTML使用
window.toggleUserMenu = toggleUserMenu;
window.logout = logout;
document.addEventListener('DOMContentLoaded', initializeApp);

View File

@@ -42,6 +42,24 @@
</svg>
<span>攻击链</span>
</button>
<div class="user-menu-container">
<button class="user-avatar-btn" onclick="toggleUserMenu()" title="用户菜单">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="12" cy="7" r="4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div id="user-menu-dropdown" class="user-menu-dropdown" style="display: none;">
<div class="user-menu-item" onclick="logout()">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<polyline points="16 17 21 12 16 7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="21" y1="12" x2="9" y2="12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span>退出登录</span>
</div>
</div>
</div>
</div>
</div>
</div>