From 03feef2300119ef28806383d66b394a743c7b9d5 Mon Sep 17 00:00:00 2001 From: jinchao <383321154@qq.com> Date: Wed, 18 Jun 2025 12:11:04 +0800 Subject: [PATCH] =?UTF-8?q?V0.27.1.250618=5Falpha:=E4=B8=AA=E4=BA=BA?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E9=A1=B5=E9=9D=A2=E6=B7=BB=E5=8A=A0=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=AF=86=E7=A0=81=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Login/.vscode/settings.json | 62 +++++ Login/login.cpp | 16 +- Release/database/UserInfo.db | Bin 32768 -> 32768 bytes Release/database/XNSim.db | Bin 1224704 -> 1224704 bytes XNSimHtml/assets/icons/png/password.png | Bin 0 -> 5358 bytes XNSimHtml/components/profile-center.js | 302 +++++++++++++++++++++++- XNSimHtml/routes/auth.js | 10 + 7 files changed, 373 insertions(+), 17 deletions(-) create mode 100644 Login/.vscode/settings.json create mode 100644 XNSimHtml/assets/icons/png/password.png diff --git a/Login/.vscode/settings.json b/Login/.vscode/settings.json new file mode 100644 index 0000000..8821a20 --- /dev/null +++ b/Login/.vscode/settings.json @@ -0,0 +1,62 @@ +{ + "files.associations": { + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "array": "cpp", + "atomic": "cpp", + "bit": "cpp", + "*.tcc": "cpp", + "chrono": "cpp", + "codecvt": "cpp", + "compare": "cpp", + "concepts": "cpp", + "cstdint": "cpp", + "deque": "cpp", + "forward_list": "cpp", + "map": "cpp", + "unordered_map": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "optional": "cpp", + "random": "cpp", + "ratio": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "ranges": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "thread": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp", + "valarray": "cpp" + } +} \ No newline at end of file diff --git a/Login/login.cpp b/Login/login.cpp index 0a7e92a..cf84912 100644 --- a/Login/login.cpp +++ b/Login/login.cpp @@ -510,9 +510,13 @@ extern "C" LOGIN_EXPORT int changePassword(int user_id, const char *old_password return -1; } + if (old_password_str == new_password_str) { + return -2; + } + const char *xnCorePath = std::getenv("XNCore"); if (!xnCorePath) { - return -1; + return -3; } fs::path dbPath = fs::path(xnCorePath) / "database" / "UserInfo.db"; @@ -520,7 +524,7 @@ extern "C" LOGIN_EXPORT int changePassword(int user_id, const char *old_password { sqlite3 *db; if (sqlite3_open(dbPath.string().c_str(), &db) != SQLITE_OK) { - return -1; + return -3; } // 首先验证旧密码 @@ -543,7 +547,7 @@ extern "C" LOGIN_EXPORT int changePassword(int user_id, const char *old_password if (encryptedOldPassword != storedPassword) { sqlite3_finalize(stmt); sqlite3_close(db); - return -3; // 旧密码错误 + return -4; // 旧密码错误 } // 生成新的加密密码 @@ -570,16 +574,16 @@ extern "C" LOGIN_EXPORT int changePassword(int user_id, const char *old_password // 用户不存在 sqlite3_finalize(stmt); sqlite3_close(db); - return -2; // 用户不存在 + return -5; // 用户不存在 } } sqlite3_close(db); } - return -1; // Default error return + return -6; // Default error return } catch (const std::exception &) { - return -1; + return -3; } } diff --git a/Release/database/UserInfo.db b/Release/database/UserInfo.db index 2b0b402b232b4d6dbc6176d9dd5262696f2b2d63..64d94801da3ef2b281b5abe57a0c722e85c35b3f 100644 GIT binary patch delta 19 acmZo@U}|V!njp<6HBrWyQEFqtf_eZs?FI$_ delta 19 acmZo@U}|V!njp<6F;T{uQDS4lf_eZs&jtbj diff --git a/Release/database/XNSim.db b/Release/database/XNSim.db index 5fae359876abb9c603932b6490faa8ec473969c9..b7f0965568d2669e9306a5695d2f01320b9d784f 100644 GIT binary patch delta 270 zcmZp8;MMTJYl1Z6*@-gFjAt7YS`!$zCNM2|&+N)8Je~amQ$7=~@by48$xz%nHP8K+F!r9NXpoay}Dc7Gl~zon3%SnTcutW=4U@O!alH9FmIS zvWbb}26{&3dWJ>@My9$3X1azJi8%!siH1g2h6YxKmQQx9da`TRll=>yHLicTaO=yt zi=J)Y{j_Vrll|+SP1*T$ecST|jZeGgzi8eI5r4K|=d<2*Py6OWq>z<8pVb0UnV6EB j$(Yw}FU$qR+(66&#JoVv2gLk9EC9rU+wFyg4$c7p>Be?9 delta 129 zcmZp8;MMTJYl1Z6nTayajAt4XS`!$zCNM2|&+Ni0H=X?hQ~vgf4@|RpCI;}f%l%~n zVrC#_0b*7lW&>h&Am-RE_m}gT5VIh&{d9H#F6GUP0;0_A_QG61%nigmK+Frod_c?( P!~#GpxZPe@=-?axLbWSD diff --git a/XNSimHtml/assets/icons/png/password.png b/XNSimHtml/assets/icons/png/password.png new file mode 100644 index 0000000000000000000000000000000000000000..aca08b448f32a7e9ec324ff86873014fa72c95a4 GIT binary patch literal 5358 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 QF$qinr)!KUyX<)XKl=>O*#H0l literal 0 HcmV?d00001 diff --git a/XNSimHtml/components/profile-center.js b/XNSimHtml/components/profile-center.js index 56e57f5..c0c374a 100644 --- a/XNSimHtml/components/profile-center.js +++ b/XNSimHtml/components/profile-center.js @@ -65,6 +65,11 @@ class ProfileCenter extends HTMLElement { display: inline-block; } + .avatar-wrapper { + position: relative; + display: inline-block; + } + .avatar { width: 100px; height: 100px; @@ -78,12 +83,12 @@ class ProfileCenter extends HTMLElement { .avatar-edit-btn { position: absolute; - bottom: 15px; - right: 0; - width: 32px; - height: 32px; + bottom: 5px; + right: 5px; + width: 28px; + height: 28px; border-radius: 50%; - background: rgba(255,255,255,0.9); + background: rgba(255,255,255,0.95); border: 2px solid #667eea; cursor: pointer; display: flex; @@ -91,6 +96,7 @@ class ProfileCenter extends HTMLElement { justify-content: center; transition: all 0.3s ease; box-shadow: 0 2px 8px rgba(0,0,0,0.2); + z-index: 5; } .avatar-edit-btn:hover { @@ -100,9 +106,9 @@ class ProfileCenter extends HTMLElement { } .avatar-edit-btn img { - width: 16px; - height: 16px; - opacity: 0.7; + width: 14px; + height: 14px; + opacity: 0.8; } .avatar-edit-btn:hover img { @@ -319,6 +325,131 @@ class ProfileCenter extends HTMLElement { color: #6c757d; } + .modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + opacity: 0; + visibility: hidden; + transition: all 0.3s ease; + } + + .modal-overlay.active { + opacity: 1; + visibility: visible; + } + + .modal { + background: white; + border-radius: 12px; + padding: 24px; + width: 90%; + max-width: 400px; + box-shadow: 0 10px 30px rgba(0,0,0,0.2); + transform: scale(0.9); + transition: transform 0.3s ease; + } + + .modal-overlay.active .modal { + transform: scale(1); + } + + .modal-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + } + + .modal-title { + font-size: 18px; + font-weight: 600; + color: #333; + } + + .modal-close { + background: none; + border: none; + font-size: 20px; + cursor: pointer; + color: #6c757d; + padding: 0; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + } + + .modal-close:hover { + color: #333; + } + + .form-group { + margin-bottom: 16px; + } + + .form-label { + display: block; + margin-bottom: 6px; + font-weight: 500; + color: #333; + } + + .form-input { + width: 100%; + padding: 10px 12px; + border: 1px solid #ced4da; + border-radius: 6px; + font-size: 14px; + box-sizing: border-box; + } + + .form-input:focus { + outline: none; + border-color: #667eea; + box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1); + } + + .modal-actions { + display: flex; + gap: 12px; + justify-content: flex-end; + margin-top: 24px; + } + + .btn-small { + padding: 8px 16px; + font-size: 14px; + } + + .modal-message { + margin-bottom: 16px; + padding: 12px; + border-radius: 6px; + font-size: 14px; + text-align: center; + } + + .modal-message.error { + background: #f8d7da; + color: #721c24; + border: 1px solid #f5c6cb; + } + + .modal-message.success { + background: #d4edda; + color: #155724; + border: 1px solid #c3e6cb; + } + @media (max-width: 768px) { :host { padding: 10px; @@ -340,9 +471,11 @@ class ProfileCenter extends HTMLElement {
- 用户头像 -
- 编辑头像 +
+ 用户头像 +
+ 编辑头像 +
@@ -414,6 +547,10 @@ class ProfileCenter extends HTMLElement { 编辑 编辑信息 +
+ + + `; } @@ -515,12 +681,14 @@ class ProfileCenter extends HTMLElement { 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', () => { @@ -750,6 +918,118 @@ class ProfileCenter extends HTMLElement { 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); \ No newline at end of file diff --git a/XNSimHtml/routes/auth.js b/XNSimHtml/routes/auth.js index 057a0a4..d40f7dd 100644 --- a/XNSimHtml/routes/auth.js +++ b/XNSimHtml/routes/auth.js @@ -230,6 +230,16 @@ router.post('/change-password', (req, res) => { if (result === 0) { res.json({ success: true, message: '密码修改成功' }); + } else if(result === -1){ + res.status(400).json({ success: false, message: '新密码或旧密码为空' }); + } else if(result === -2){ + res.status(400).json({ success: false, message: '新密码与旧密码相同' }); + } else if(result === -3){ + res.status(400).json({ success: false, message: '内部错误' }); + } else if(result === -4){ + res.status(400).json({ success: false, message: '旧密码错误' }); + } else if(result === -5){ + res.status(400).json({ success: false, message: '用户不存在' }); } else { res.status(400).json({ success: false, message: '密码修改失败', error: `错误码:${result}` }); }