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;
|
2025-05-09 16:29:50 +08:00
|
|
|
|
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;
|
2025-05-09 16:29:50 +08:00
|
|
|
|
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;
|
|
|
|
|
}
|
2025-05-09 16:29:50 +08:00
|
|
|
|
|
|
|
|
|
.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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
checkLoginStatus() {
|
|
|
|
|
let userInfo;
|
|
|
|
|
try {
|
|
|
|
|
const userInfoStr = localStorage.getItem('userInfo');
|
|
|
|
|
if (!userInfoStr) {
|
2025-05-09 16:29:50 +08:00
|
|
|
|
document.getElementById('authContainer').style.display = 'block';
|
|
|
|
|
document.getElementById('mainContainer').style.display = 'none';
|
2025-04-28 12:25:20 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
userInfo = JSON.parse(userInfoStr);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.error('解析用户信息失败:', error);
|
2025-05-09 16:29:50 +08:00
|
|
|
|
document.getElementById('authContainer').style.display = 'block';
|
|
|
|
|
document.getElementById('mainContainer').style.display = 'none';
|
2025-04-28 12:25:20 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.updateUserInfo(userInfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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.real_name || '未设置'}</div>
|
|
|
|
|
<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';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
logout() {
|
|
|
|
|
localStorage.removeItem('userInfo');
|
2025-05-09 16:29:50 +08:00
|
|
|
|
document.getElementById('authContainer').style.display = 'block';
|
|
|
|
|
document.getElementById('mainContainer').style.display = 'none';
|
2025-04-28 12:25:20 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
customElements.define('user-info', UserInfo);
|