XNSim/XNSimHtml/components/user-info.js

381 lines
14 KiB
JavaScript
Raw Normal View History

2025-04-28 12:25:20 +08:00
class UserInfo extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
this.addEventListeners();
this.checkLoginStatus();
}
render() {
this.shadowRoot.innerHTML = `
<style>
.user-dropdown {
height: 100%;
position: relative;
border-left: 1px solid #e0e0e0;
}
.user-dropdown-toggle {
height: 100%;
display: flex;
align-items: center;
padding: 0 20px;
cursor: pointer;
transition: background-color 0.3s;
gap: 10px;
position: relative;
}
.user-dropdown-toggle:hover {
background-color: #f5f5f5;
}
.user-dropdown-toggle img.icon-small {
width: 12px;
height: 12px;
opacity: 0.5;
}
.user-dropdown-toggle img:not(.icon-small) {
width: 32px;
height: 32px;
border-radius: 50%;
}
.user-dropdown-toggle span {
font-size: 17px;
color: #333;
font-weight: 500;
}
.user-level-icon {
width: 24px;
height: 24px;
margin-right: 0;
vertical-align: middle;
cursor: help;
}
.user-level-icon-wrapper {
position: relative;
display: inline-block;
z-index: 1002;
}
.icon-small {
width: 12px;
height: 12px;
opacity: 0.7;
}
.user-dropdown-menu {
position: absolute;
top: 100%;
right: 0;
background: white;
border: 1px solid #e0e0e0;
border-radius: 4px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
display: none;
z-index: 1000;
min-width: 150px;
max-width: 250px;
white-space: nowrap;
overflow: hidden;
2025-04-28 12:25:20 +08:00
}
.user-dropdown.active .user-dropdown-menu {
display: block;
}
.dropdown-item {
display: flex;
align-items: center;
padding: 8px 16px;
cursor: pointer;
transition: background-color 0.3s;
gap: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
2025-04-28 12:25:20 +08:00
}
.dropdown-item:hover {
background-color: #f5f5f5;
}
.dropdown-item .icon-small {
width: 16px;
height: 16px;
opacity: 0.7;
}
.dropdown-divider {
height: 1px;
background-color: #e0e0e0;
margin: 4px 0;
}
.tooltip {
position: absolute;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 12px 15px;
border-radius: 4px;
font-size: 14px;
white-space: pre-line;
visibility: hidden;
opacity: 0;
transition: opacity 0.3s;
top: 100%;
left: 50%;
transform: translateX(-50%);
margin-top: 10px;
z-index: 1001;
min-width: 200px;
text-align: left;
line-height: 1.5;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
.tooltip .info-row {
margin: 4px 0;
}
.tooltip .label {
color: #a8c8ff;
margin-right: 8px;
}
.user-level-icon-wrapper:hover .tooltip {
visibility: visible;
opacity: 1;
}
.tooltip::before {
content: '';
position: absolute;
bottom: 100%;
left: 50%;
transform: translateX(-50%);
border-width: 0 5px 5px 5px;
border-style: solid;
border-color: transparent transparent rgba(0, 0, 0, 0.8) transparent;
}
.dropdown-item span {
overflow: hidden;
text-overflow: ellipsis;
}
2025-04-28 12:25:20 +08:00
</style>
<div class="user-dropdown">
<div class="user-dropdown-toggle">
<div class="user-level-icon-wrapper">
<img id="userLevelIcon" src="assets/icons/png/user.png" alt="用户等级" class="user-level-icon">
<div class="tooltip" id="userTooltip">用户信息加载中...</div>
</div>
<span id="userName">用户名</span>
<img src="assets/icons/png/chevron-down_b.png" alt="展开" class="icon-small">
</div>
<div class="user-dropdown-menu">
<div class="dropdown-item" data-action="profile">
<img src="assets/icons/png/user_b.png" alt="个人中心" class="icon-small">
个人中心
</div>
<div class="dropdown-item admin-only" data-action="users">
<img src="assets/icons/png/users_b.png" alt="用户管理" class="icon-small">
用户管理
</div>
<div class="dropdown-divider"></div>
<div class="dropdown-item" data-action="logout">
<img src="assets/icons/png/logout_b.png" alt="退出登录" class="icon-small">
退出登录
</div>
</div>
</div>
`;
}
addEventListeners() {
const userDropdown = this.shadowRoot.querySelector('.user-dropdown');
const userDropdownToggle = this.shadowRoot.querySelector('.user-dropdown-toggle');
// 点击切换下拉菜单
userDropdownToggle.addEventListener('click', (e) => {
e.stopPropagation();
userDropdown.classList.toggle('active');
});
// 点击其他地方关闭下拉菜单
document.addEventListener('click', () => {
userDropdown.classList.remove('active');
});
// 处理下拉菜单项点击
const dropdownItems = this.shadowRoot.querySelectorAll('.dropdown-item');
dropdownItems.forEach(item => {
item.addEventListener('click', (e) => {
e.stopPropagation();
const action = item.getAttribute('data-action');
this.handleDropdownAction(action);
userDropdown.classList.remove('active');
});
});
}
handleDropdownAction(action) {
switch(action) {
case 'profile':
this.dispatchEvent(new CustomEvent('menu-action', {
detail: { action: 'profile' },
bubbles: true,
composed: true
}));
break;
case 'users':
this.dispatchEvent(new CustomEvent('menu-action', {
detail: { action: 'users' },
bubbles: true,
composed: true
}));
break;
case 'logout':
this.logout();
break;
}
}
async checkLoginStatus() {
2025-04-28 12:25:20 +08:00
try {
const response = await fetch('/api/check-auth', {
credentials: 'include'
});
const result = await response.json();
if (result.success) {
// 只存储非敏感的用户信息
localStorage.setItem('userInfo', JSON.stringify({
username: result.user.username,
access_level: result.user.access_level,
full_name: result.user.full_name,
phone: result.user.phone,
email: result.user.email,
department: result.user.department,
position: result.user.position
}));
this.updateUserInfo(result.user);
} else {
document.getElementById('authContainer').style.display = 'block';
document.getElementById('mainContainer').style.display = 'none';
2025-04-28 12:25:20 +08:00
}
} catch (error) {
console.error('获取用户信息失败:', error);
document.getElementById('authContainer').style.display = 'block';
document.getElementById('mainContainer').style.display = 'none';
2025-04-28 12:25:20 +08:00
}
}
updateUserInfo(userInfo) {
// 设置用户名
this.shadowRoot.getElementById('userName').textContent = userInfo.username;
// 设置用户等级图标和tooltip信息
const userLevelIcon = this.shadowRoot.getElementById('userLevelIcon');
const userTooltip = this.shadowRoot.getElementById('userTooltip');
const accessLevel = parseInt(userInfo.access_level);
let levelName = '';
switch(accessLevel) {
case 1:
userLevelIcon.src = 'assets/icons/png/user.png';
userLevelIcon.alt = '普通用户';
levelName = '普通用户';
break;
case 2:
userLevelIcon.src = 'assets/icons/png/dvlp.png';
userLevelIcon.alt = '开发者';
levelName = '开发者';
break;
case 3:
userLevelIcon.src = 'assets/icons/png/master.png';
userLevelIcon.alt = '组长';
levelName = '组长';
break;
case 4:
userLevelIcon.src = 'assets/icons/png/admin.png';
userLevelIcon.alt = '管理员';
levelName = '管理员';
break;
default:
userLevelIcon.src = 'assets/icons/png/guest.png';
userLevelIcon.alt = '访客';
levelName = '访客';
}
// 构建HTML内容
const tooltipContent = `
<div class="info-row"><span class="label">用户名</span>${userInfo.username}</div>
<div class="info-row"><span class="label">真实姓名</span>${userInfo.full_name || ''}</div>
2025-04-28 12:25:20 +08:00
<div class="info-row"><span class="label">权限级别</span>${levelName}</div>
<div class="info-row"><span class="label">所属部门</span>${userInfo.department || ''}</div>
<div class="info-row"><span class="label">职位</span>${userInfo.position || ''}</div>
<div class="info-row"><span class="label">电子邮箱</span>${userInfo.email || ''}</div>
<div class="info-row"><span class="label">联系电话</span>${userInfo.phone || ''}</div>
`;
userTooltip.innerHTML = tooltipContent;
// 控制用户管理选项的显示
const userManagementItem = this.shadowRoot.querySelector('.admin-only');
if (userManagementItem) {
userManagementItem.style.display = accessLevel >= 3 ? 'flex' : 'none';
}
}
async logout() {
try {
const response = await fetch('/api/logout', {
method: 'POST',
credentials: 'include'
});
if (response.ok) {
// 清除本地存储的用户信息
localStorage.removeItem('userInfo');
// 获取认证容器和主容器
const authContainer = document.getElementById('authContainer');
const mainContainer = document.getElementById('mainContainer');
// 先隐藏主容器
mainContainer.classList.remove('visible');
// 等待过渡效果完成
setTimeout(() => {
mainContainer.style.display = 'none';
// 显示认证容器
authContainer.style.display = 'block';
// 等待一帧以确保display:block生效
requestAnimationFrame(() => {
authContainer.classList.add('visible');
// 重置认证组件
const authComponent = document.querySelector('auth-component');
if (authComponent) {
authComponent.reset();
}
});
}, 300);
} else {
console.error('登出失败');
}
} catch (error) {
console.error('登出错误:', error);
}
2025-04-28 12:25:20 +08:00
}
}
customElements.define('user-info', UserInfo);