class ProfileCenter extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.userInfo = null; this.isEditing = false; } connectedCallback() { this.render(); this.loadUserInfo(); this.addEventListeners(); } async loadUserInfo() { try { const response = await fetch('/api/check-auth', { credentials: 'include' }); const result = await response.json(); if (result.success) { this.userInfo = result.user; this.updateDisplay(); } else { this.showError('获取用户信息失败'); } } catch (error) { console.error('获取用户信息失败:', error); this.showError('获取用户信息失败'); } } render() { this.shadowRoot.innerHTML = `
用户头像
编辑头像

加载中...

加载中...

基本信息 基本信息
用户名 -
真实姓名 -
权限级别 -
所属部门 -
职位 -
用户ID -
联系方式 联系方式
电子邮箱 -
联系电话 -
`; } updateDisplay() { if (!this.userInfo) return; // 更新头像 const avatar = this.shadowRoot.getElementById('userAvatar'); if (this.userInfo.icon && this.userInfo.icon.trim() !== '') { const base64Data = this.userInfo.icon.trim(); // 检查是否是有效的图片Base64数据 if (base64Data.length > 100 && /^[A-Za-z0-9+/]*={0,2}$/.test(base64Data)) { // 根据Base64数据开头判断图片格式 let mimeType = 'image/jpeg'; // 默认 if (base64Data.startsWith('iVBORw0KGgo')) { mimeType = 'image/png'; } else if (base64Data.startsWith('R0lGODlh')) { mimeType = 'image/gif'; } else if (base64Data.startsWith('UklGR')) { mimeType = 'image/webp'; } avatar.src = `data:${mimeType};base64,${base64Data}`; } else { avatar.src = 'assets/icons/png/user.png'; } } else { avatar.src = 'assets/icons/png/user.png'; } // 更新基本信息 this.shadowRoot.getElementById('userName').textContent = this.userInfo.username || '未设置'; this.shadowRoot.getElementById('userRole').textContent = this.getAccessLevelName(this.userInfo.access_level); // 更新详细信息 this.updateInfoField('username', this.userInfo.username); this.updateInfoField('fullName', this.userInfo.full_name); this.updateInfoField('accessLevel', this.getAccessLevelName(this.userInfo.access_level), true); this.updateInfoField('department', this.userInfo.department); this.updateInfoField('position', this.userInfo.position); this.updateInfoField('userId', this.userInfo.id); this.updateInfoField('email', this.userInfo.email); this.updateInfoField('phone', this.userInfo.phone); } updateInfoField(fieldId, value, isBadge = false) { const element = this.shadowRoot.getElementById(fieldId); if (element) { if (isBadge) { element.innerHTML = `${value}`; } else { if (value && value !== '') { element.textContent = value; element.classList.remove('empty'); } else { element.textContent = '未设置'; element.classList.add('empty'); } } } } getAccessLevelName(accessLevel) { const level = parseInt(accessLevel); switch(level) { case 1: return '普通用户'; case 2: return '开发者'; case 3: return '组长'; case 4: return '管理员'; default: return '访客'; } } getPermissionClass(accessLevel) { const level = parseInt(accessLevel); switch(level) { case 1: return 'user'; case 2: return 'developer'; case 3: return 'leader'; case 4: return 'admin'; default: return 'guest'; } } addEventListeners() { const editBtn = this.shadowRoot.getElementById('editBtn'); const saveBtn = this.shadowRoot.getElementById('saveBtn'); const cancelBtn = this.shadowRoot.getElementById('cancelBtn'); const changePasswordBtn = this.shadowRoot.getElementById('changePasswordBtn'); const avatarEditBtn = this.shadowRoot.getElementById('avatarEditBtn'); const avatarFileInput = this.shadowRoot.getElementById('avatarFileInput'); editBtn.addEventListener('click', () => this.startEditing()); saveBtn.addEventListener('click', () => this.saveChanges()); cancelBtn.addEventListener('click', () => this.cancelEditing()); changePasswordBtn.addEventListener('click', () => this.showChangePasswordModal()); // 头像编辑按钮点击事件 avatarEditBtn.addEventListener('click', () => { avatarFileInput.click(); }); // 文件选择事件 avatarFileInput.addEventListener('change', (e) => { const file = e.target.files[0]; if (file) { this.handleAvatarUpload(file); } }); } startEditing() { this.isEditing = true; this.shadowRoot.getElementById('editBtn').style.display = 'none'; this.shadowRoot.getElementById('saveBtn').style.display = 'flex'; this.shadowRoot.getElementById('cancelBtn').style.display = 'flex'; // 将可编辑字段转换为输入框 this.convertToInput('fullName', this.userInfo.full_name || ''); this.convertToInput('department', this.userInfo.department || ''); this.convertToInput('position', this.userInfo.position || ''); this.convertToInput('email', this.userInfo.email || ''); this.convertToInput('phone', this.userInfo.phone || ''); } convertToInput(fieldId, value) { const element = this.shadowRoot.getElementById(fieldId); if (element) { const input = document.createElement('input'); input.type = 'text'; input.className = 'edit-input'; input.value = value; input.id = `${fieldId}Input`; element.innerHTML = ''; element.appendChild(input); } } async saveChanges() { const updatedInfo = { full_name: this.shadowRoot.getElementById('fullNameInput')?.value || '', department: this.shadowRoot.getElementById('departmentInput')?.value || '', position: this.shadowRoot.getElementById('positionInput')?.value || '', email: this.shadowRoot.getElementById('emailInput')?.value || '', phone: this.shadowRoot.getElementById('phoneInput')?.value || '' }; try { const response = await fetch('/api/update-user-info', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId: this.userInfo.id, userInfo: updatedInfo }), credentials: 'include' }); const result = await response.json(); if (result.success) { // 更新本地用户信息 this.userInfo = { ...this.userInfo, ...updatedInfo }; this.showSuccess('用户信息更新成功'); this.cancelEditing(); this.updateDisplay(); } else { this.showError('更新失败: ' + result.message); } } catch (error) { console.error('更新用户信息失败:', error); this.showError('更新用户信息失败'); } } cancelEditing() { this.isEditing = false; this.shadowRoot.getElementById('editBtn').style.display = 'flex'; this.shadowRoot.getElementById('saveBtn').style.display = 'none'; this.shadowRoot.getElementById('cancelBtn').style.display = 'none'; // 恢复显示模式 this.updateDisplay(); } showError(message) { const errorElement = this.shadowRoot.getElementById('errorMessage'); errorElement.textContent = message; errorElement.style.display = 'block'; setTimeout(() => { errorElement.style.display = 'none'; }, 5000); } showSuccess(message) { const successElement = this.shadowRoot.getElementById('successMessage'); successElement.textContent = message; successElement.style.display = 'block'; setTimeout(() => { successElement.style.display = 'none'; }, 3000); } async handleAvatarUpload(file) { // 验证文件类型 if (!file.type.startsWith('image/')) { this.showError('请选择图片文件'); return; } // 验证文件大小(限制为500KB) if (file.size > 500 * 1024) { this.showError('图片大小不能超过500KB'); return; } try { // 显示上传中状态 const loadingElement = this.shadowRoot.getElementById('uploadLoading'); loadingElement.style.display = 'block'; // 压缩图片并转换为Base64 const base64Data = await this.compressAndConvertToBase64(file); // 提取纯Base64数据(去掉data URL前缀) const pureBase64 = base64Data.replace(/^data:image\/[a-z]+;base64,/, ''); // 调用后端API更新头像 const response = await fetch('/api/update-user-icon', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId: this.userInfo.id, iconBase64: pureBase64 }), credentials: 'include' }); const result = await response.json(); if (result.success) { // 更新本地头像显示 const avatar = this.shadowRoot.getElementById('userAvatar'); avatar.src = base64Data; // 更新用户信息中的头像 this.userInfo.icon = base64Data; this.showSuccess('头像更新成功'); } else { this.showError('头像更新失败: ' + (result.error || result.message)); } } catch (error) { console.error('头像上传失败:', error); this.showError('头像上传失败'); } finally { // 隐藏上传中状态 const loadingElement = this.shadowRoot.getElementById('uploadLoading'); loadingElement.style.display = 'none'; // 清空文件输入框 this.shadowRoot.getElementById('avatarFileInput').value = ''; } } compressAndConvertToBase64(file) { return new Promise((resolve, reject) => { const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); const img = new Image(); img.onload = () => { // 设置画布尺寸(限制最大尺寸为200x200) const maxSize = 200; let { width, height } = img; if (width > height) { if (width > maxSize) { height = (height * maxSize) / width; width = maxSize; } } else { if (height > maxSize) { width = (width * maxSize) / height; height = maxSize; } } canvas.width = width; canvas.height = height; // 清空画布并设置透明背景 ctx.clearRect(0, 0, width, height); // 绘制图片到画布 ctx.drawImage(img, 0, 0, width, height); // 根据原图片格式选择合适的输出格式 let mimeType = 'image/png'; // 默认使用PNG保持透明背景 let quality = 0.9; // 如果原图是JPEG格式,则输出JPEG if (file.type === 'image/jpeg' || file.type === 'image/jpg') { mimeType = 'image/jpeg'; quality = 0.8; } // 转换为Base64 const base64 = canvas.toDataURL(mimeType, quality); resolve(base64); }; img.onerror = () => { reject(new Error('图片加载失败')); }; // 从文件创建URL const url = URL.createObjectURL(file); img.src = url; }); } showChangePasswordModal() { const modal = this.shadowRoot.getElementById('changePasswordModal'); modal.classList.add('active'); // 添加模态框事件监听器 this.addPasswordModalListeners(); } addPasswordModalListeners() { const modal = this.shadowRoot.getElementById('changePasswordModal'); const closeBtn = this.shadowRoot.getElementById('closePasswordModal'); const cancelBtn = this.shadowRoot.getElementById('cancelPasswordChange'); const form = this.shadowRoot.getElementById('changePasswordForm'); // 关闭按钮事件 closeBtn.addEventListener('click', () => this.hideChangePasswordModal()); // 取消按钮事件 cancelBtn.addEventListener('click', () => this.hideChangePasswordModal()); // 点击模态框背景关闭 modal.addEventListener('click', (e) => { if (e.target === modal) { this.hideChangePasswordModal(); } }); // 表单提交事件 form.addEventListener('submit', (e) => { e.preventDefault(); this.handlePasswordChange(); }); } hideChangePasswordModal() { const modal = this.shadowRoot.getElementById('changePasswordModal'); modal.classList.remove('active'); // 清空表单 const form = this.shadowRoot.getElementById('changePasswordForm'); form.reset(); // 隐藏消息 const messageElement = this.shadowRoot.getElementById('passwordModalMessage'); messageElement.style.display = 'none'; } async handlePasswordChange() { const oldPassword = this.shadowRoot.getElementById('oldPassword').value; const newPassword = this.shadowRoot.getElementById('newPassword').value; const confirmPassword = this.shadowRoot.getElementById('confirmPassword').value; // 验证输入 if (!oldPassword || !newPassword || !confirmPassword) { this.showPasswordModalMessage('请填写所有密码字段', 'error'); return; } if (newPassword !== confirmPassword) { this.showPasswordModalMessage('新密码和确认密码不匹配', 'error'); return; } if (newPassword.length < 6) { this.showPasswordModalMessage('新密码长度至少6位', 'error'); return; } try { const response = await fetch('/api/change-password', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId: this.userInfo.id, oldPassword: oldPassword, newPassword: newPassword }), credentials: 'include' }); const result = await response.json(); if (result.success) { this.showPasswordModalMessage('密码修改成功', 'success'); setTimeout(() => { this.hideChangePasswordModal(); }, 1500); } else { this.showPasswordModalMessage('密码修改失败: ' + result.message, 'error'); } } catch (error) { console.error('修改密码失败:', error); this.showPasswordModalMessage('修改密码失败', 'error'); } } showPasswordModalMessage(message, type) { const messageElement = this.shadowRoot.getElementById('passwordModalMessage'); messageElement.textContent = message; messageElement.className = `modal-message ${type}`; messageElement.style.display = 'block'; // 如果是成功消息,3秒后自动隐藏 if (type === 'success') { setTimeout(() => { messageElement.style.display = 'none'; }, 3000); } } } customElements.define('profile-center', ProfileCenter);