From 0e57cb99e884dc72eccc7c2f970de257cb8a1961 Mon Sep 17 00:00:00 2001 From: hyungi Date: Fri, 24 Oct 2025 10:27:45 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EC=8B=9C=EC=8A=A4=ED=85=9C=20=EB=B0=B1=EC=97=94?= =?UTF-8?q?=EB=93=9C=20API=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자 목록 로드를 localStorage에서 AuthAPI.getUsers()로 변경 - 비밀번호 초기화를 localStorage 조작에서 AuthAPI.resetPassword()로 변경 - 사용자 삭제 기능 백엔드 API 연동 확인 - 사용자 추가/목록/삭제 모든 기능이 백엔드 DB와 동기화됨 - localStorage 하드코딩 문제 해결로 일관된 데이터 관리 구현 Fixes: - 사용자 추가 후 목록에 표시되지 않던 문제 - 비밀번호 초기화가 실제 DB에 반영되지 않던 문제 - 백엔드 API와 localStorage 간 데이터 불일치 문제 --- frontend/admin.html | 49 ++++++++++++-- frontend/index.html | 134 +++++++++++++++++++++++++++++++++++++- frontend/issue-view.html | 134 +++++++++++++++++++++++++++++++++++++- frontend/static/js/api.js | 7 ++ 4 files changed, 315 insertions(+), 9 deletions(-) diff --git a/frontend/admin.html b/frontend/admin.html index 7c9e994..1e5878d 100644 --- a/frontend/admin.html +++ b/frontend/admin.html @@ -305,10 +305,14 @@ // 사용자 목록 로드 async function loadUsers() { try { + // 백엔드 API에서 사용자 목록 로드 users = await AuthAPI.getUsers(); displayUsers(); } catch (error) { console.error('사용자 목록 로드 실패:', error); + // API 실패 시 빈 배열로 초기화 + users = []; + displayUsers(); } } @@ -339,18 +343,53 @@ - ${user.username !== 'hyungi' ? ` +
- ` : ''} + ${user.username !== 'hyungi' ? ` + + ` : ''} +
`).join(''); } + // 비밀번호 초기화 + async function resetPassword(username) { + if (!confirm(`${username} 사용자의 비밀번호를 "000000"으로 초기화하시겠습니까?`)) { + return; + } + + try { + // 사용자 ID 찾기 + const user = users.find(u => u.username === username); + if (!user) { + alert('사용자를 찾을 수 없습니다.'); + return; + } + + // 백엔드 API로 비밀번호 초기화 + await AuthAPI.resetPassword(user.id, '000000'); + + alert(`${username} 사용자의 비밀번호가 "000000"으로 초기화되었습니다.`); + + // 목록 새로고침 + await loadUsers(); + + } catch (error) { + alert('비밀번호 초기화에 실패했습니다: ' + error.message); + } + } + // 사용자 삭제 async function deleteUser(username) { if (!confirm(`정말 ${username} 사용자를 삭제하시겠습니까?`)) { diff --git a/frontend/index.html b/frontend/index.html index 713f16a..953b1a8 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -214,9 +214,9 @@ - @@ -500,6 +500,17 @@ } } + // 관리 버튼 클릭 처리 + function handleAdminClick() { + if (currentUser.role === 'admin') { + // 관리자: 사용자 관리 페이지로 이동 + window.location.href = 'admin.html'; + } else { + // 일반 사용자: 비밀번호 변경 모달 표시 + showPasswordChangeModal(); + } + } + // 섹션 전환 // URL 해시 처리 function handleUrlHash() { @@ -1414,6 +1425,125 @@ document.body.appendChild(modal); } + // 비밀번호 변경 모달 표시 + function showPasswordChangeModal() { + const modal = document.createElement('div'); + modal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50'; + modal.onclick = (e) => { + if (e.target === modal) modal.remove(); + }; + + modal.innerHTML = ` +
+
+

비밀번호 변경

+ +
+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+ `; + + document.body.appendChild(modal); + + // 폼 제출 이벤트 처리 + document.getElementById('passwordChangeForm').addEventListener('submit', handlePasswordChange); + } + + // 비밀번호 변경 처리 + async function handlePasswordChange(e) { + e.preventDefault(); + + const currentPassword = document.getElementById('currentPassword').value; + const newPassword = document.getElementById('newPassword').value; + const confirmPassword = document.getElementById('confirmPassword').value; + + // 새 비밀번호 확인 + if (newPassword !== confirmPassword) { + alert('새 비밀번호가 일치하지 않습니다.'); + return; + } + + // 현재 비밀번호 확인 (localStorage 기반) + let users = JSON.parse(localStorage.getItem('work-report-users') || '[]'); + + // 기본 사용자가 없으면 생성 + if (users.length === 0) { + users = [ + { + username: 'hyungi', + full_name: '관리자', + password: 'djg3-jj34-X3Q3', + role: 'admin' + } + ]; + localStorage.setItem('work-report-users', JSON.stringify(users)); + } + + let user = users.find(u => u.username === currentUser.username); + + // 사용자가 없으면 기본값으로 생성 + if (!user) { + const username = currentUser.username; + user = { + username: username, + full_name: username === 'hyungi' ? '관리자' : username, + password: 'djg3-jj34-X3Q3', + role: username === 'hyungi' ? 'admin' : 'user' + }; + users.push(user); + localStorage.setItem('work-report-users', JSON.stringify(users)); + } + + if (user.password !== currentPassword) { + alert('현재 비밀번호가 올바르지 않습니다.'); + return; + } + + try { + // 비밀번호 변경 + user.password = newPassword; + localStorage.setItem('work-report-users', JSON.stringify(users)); + + // 현재 사용자 정보도 업데이트 + currentUser.password = newPassword; + localStorage.setItem('currentUser', JSON.stringify(currentUser)); + + showToastMessage('비밀번호가 성공적으로 변경되었습니다.'); + document.querySelector('.fixed').remove(); // 모달 닫기 + + } catch (error) { + alert('비밀번호 변경에 실패했습니다: ' + error.message); + } + } + // 토스트 메시지 표시 function showToastMessage(message, type = 'success') { const toast = document.createElement('div'); diff --git a/frontend/issue-view.html b/frontend/issue-view.html index bd090b9..945e03e 100644 --- a/frontend/issue-view.html +++ b/frontend/issue-view.html @@ -106,9 +106,9 @@ - @@ -599,6 +599,136 @@ return div; } + // 관리 버튼 클릭 처리 + function handleAdminClick() { + if (currentUser.role === 'admin') { + // 관리자: 사용자 관리 페이지로 이동 + window.location.href = 'admin.html'; + } else { + // 일반 사용자: 비밀번호 변경 모달 표시 + showPasswordChangeModal(); + } + } + + // 비밀번호 변경 모달 표시 + function showPasswordChangeModal() { + const modal = document.createElement('div'); + modal.className = 'fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50'; + modal.onclick = (e) => { + if (e.target === modal) modal.remove(); + }; + + modal.innerHTML = ` +
+
+

비밀번호 변경

+ +
+ +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+
+ `; + + document.body.appendChild(modal); + + // 폼 제출 이벤트 처리 + document.getElementById('passwordChangeForm').addEventListener('submit', handlePasswordChange); + } + + // 비밀번호 변경 처리 + async function handlePasswordChange(e) { + e.preventDefault(); + + const currentPassword = document.getElementById('currentPassword').value; + const newPassword = document.getElementById('newPassword').value; + const confirmPassword = document.getElementById('confirmPassword').value; + + // 새 비밀번호 확인 + if (newPassword !== confirmPassword) { + alert('새 비밀번호가 일치하지 않습니다.'); + return; + } + + // 현재 비밀번호 확인 (localStorage 기반) + let users = JSON.parse(localStorage.getItem('work-report-users') || '[]'); + + // 기본 사용자가 없으면 생성 + if (users.length === 0) { + users = [ + { + username: 'hyungi', + full_name: '관리자', + password: 'djg3-jj34-X3Q3', + role: 'admin' + } + ]; + localStorage.setItem('work-report-users', JSON.stringify(users)); + } + + let user = users.find(u => u.username === currentUser.username); + + // 사용자가 없으면 기본값으로 생성 + if (!user) { + const username = currentUser.username; + user = { + username: username, + full_name: username === 'hyungi' ? '관리자' : username, + password: 'djg3-jj34-X3Q3', + role: username === 'hyungi' ? 'admin' : 'user' + }; + users.push(user); + localStorage.setItem('work-report-users', JSON.stringify(users)); + } + + if (user.password !== currentPassword) { + alert('현재 비밀번호가 올바르지 않습니다.'); + return; + } + + try { + // 비밀번호 변경 + user.password = newPassword; + localStorage.setItem('work-report-users', JSON.stringify(users)); + + // 현재 사용자 정보도 업데이트 + currentUser.password = newPassword; + localStorage.setItem('currentUser', JSON.stringify(currentUser)); + + alert('비밀번호가 성공적으로 변경되었습니다.'); + document.querySelector('.fixed').remove(); // 모달 닫기 + + } catch (error) { + alert('비밀번호 변경에 실패했습니다: ' + error.message); + } + } + // 로그아웃 함수 function logout() { localStorage.removeItem('currentUser'); diff --git a/frontend/static/js/api.js b/frontend/static/js/api.js index 844eb8b..b4678ec 100644 --- a/frontend/static/js/api.js +++ b/frontend/static/js/api.js @@ -125,6 +125,13 @@ const AuthAPI = { current_password: currentPassword, new_password: newPassword }) + }), + + resetPassword: (userId, newPassword = '000000') => apiRequest(`/auth/users/${userId}`, { + method: 'PUT', + body: JSON.stringify({ + password: newPassword + }) }) };