feat: 사용자 관리에 부서 정보 추가 및 편집 기능 구현
🏢 Department Management System: - 5개 부서 지원: 생산, 품질, 구매, 설계, 영업 - 사용자 생성/수정 시 부서 선택 가능 - 부서별 사용자 분류 및 표시 📊 Database Schema Updates: - department_type ENUM 추가 (production, quality, purchasing, design, sales) - users 테이블에 department 컬럼 추가 - idx_users_department 인덱스 생성 (성능 최적화) - 014_add_user_department.sql 마이그레이션 실행 🔧 Backend Enhancements: - DepartmentType ENUM 클래스 추가 (models.py, schemas.py) - User 모델에 department 필드 추가 - UserBase, UserUpdate 스키마에 department 필드 포함 - 기존 API 엔드포인트 자동 호환 🎨 Frontend UI Improvements: - 사용자 추가 폼에 부서 선택 드롭다운 추가 - 사용자 목록에 부서 정보 배지 표시 (녹색 배경) - 사용자 편집 모달 새로 구현 - 부서명 한글 변환 함수 (AuthAPI.getDepartmentLabel) ✨ User Management Features: - 편집 버튼으로 사용자 정보 수정 가능 - 부서, 이름, 권한 실시간 변경 - 사용자 ID는 수정 불가 (읽기 전용) - 모달 기반 직관적 UI 🔍 Visual Enhancements: - 부서 정보 아이콘 (fas fa-building) - 색상 코딩: 부서(녹색), 권한(빨강/파랑) - 반응형 레이아웃 (flex-1, gap-3) - 호버 효과 및 트랜지션 🚀 API Integration: - AuthAPI.getDepartments() - 부서 목록 반환 - AuthAPI.getDepartmentLabel() - 부서명 변환 - AuthAPI.updateUser() - 부서 정보 포함 업데이트 - 기존 createUser API 확장 지원 Expected Result: ✅ 사용자 생성 시 부서 선택 가능 ✅ 사용자 목록에 부서 정보 표시 ✅ 편집 버튼으로 부서 변경 가능 ✅ 5개 부서 분류 시스템 완성 ✅ 직관적인 사용자 관리 UI
This commit is contained in:
@@ -141,6 +141,18 @@
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">부서</label>
|
||||
<select id="newDepartment" class="input-field w-full px-3 py-2 rounded-lg">
|
||||
<option value="">부서 선택 (선택사항)</option>
|
||||
<option value="production">생산</option>
|
||||
<option value="quality">품질</option>
|
||||
<option value="purchasing">구매</option>
|
||||
<option value="design">설계</option>
|
||||
<option value="sales">영업</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">권한</label>
|
||||
<select id="newRole" class="input-field w-full px-3 py-2 rounded-lg">
|
||||
@@ -256,6 +268,80 @@
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- 사용자 편집 모달 -->
|
||||
<div id="editUserModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50">
|
||||
<div class="flex items-center justify-center min-h-screen p-4">
|
||||
<div class="bg-white rounded-xl max-w-md w-full p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold text-gray-900">사용자 정보 수정</h3>
|
||||
<button onclick="closeEditModal()" class="text-gray-400 hover:text-gray-600">
|
||||
<i class="fas fa-times text-xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form id="editUserForm" class="space-y-4">
|
||||
<input type="hidden" id="editUserId">
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">사용자 ID</label>
|
||||
<input
|
||||
type="text"
|
||||
id="editUsername"
|
||||
class="input-field w-full px-3 py-2 rounded-lg bg-gray-100"
|
||||
readonly
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">이름</label>
|
||||
<input
|
||||
type="text"
|
||||
id="editFullName"
|
||||
class="input-field w-full px-3 py-2 rounded-lg"
|
||||
placeholder="실명 입력"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">부서</label>
|
||||
<select id="editDepartment" class="input-field w-full px-3 py-2 rounded-lg">
|
||||
<option value="">부서 선택 (선택사항)</option>
|
||||
<option value="production">생산</option>
|
||||
<option value="quality">품질</option>
|
||||
<option value="purchasing">구매</option>
|
||||
<option value="design">설계</option>
|
||||
<option value="sales">영업</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">권한</label>
|
||||
<select id="editRole" class="input-field w-full px-3 py-2 rounded-lg">
|
||||
<option value="user">일반 사용자</option>
|
||||
<option value="admin">관리자</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-3 pt-4">
|
||||
<button
|
||||
type="button"
|
||||
onclick="closeEditModal()"
|
||||
class="flex-1 px-4 py-2 bg-gray-300 text-gray-700 rounded-lg hover:bg-gray-400 transition-colors"
|
||||
>
|
||||
취소
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="flex-1 px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
|
||||
>
|
||||
<i class="fas fa-save mr-2"></i>저장
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="/static/js/date-utils.js?v=20250917"></script>
|
||||
<script src="/static/js/core/permissions.js?v=20251025"></script>
|
||||
@@ -361,6 +447,7 @@
|
||||
username: document.getElementById('newUsername').value.trim(),
|
||||
full_name: document.getElementById('newFullName').value.trim(),
|
||||
password: document.getElementById('newPassword').value,
|
||||
department: document.getElementById('newDepartment').value || null,
|
||||
role: document.getElementById('newRole').value
|
||||
};
|
||||
|
||||
@@ -430,14 +517,19 @@
|
||||
|
||||
container.innerHTML = users.map(user => `
|
||||
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
|
||||
<div>
|
||||
<div class="flex-1">
|
||||
<div class="font-medium text-gray-800">
|
||||
<i class="fas fa-user mr-2 text-gray-500"></i>
|
||||
${user.full_name || user.username}
|
||||
</div>
|
||||
<div class="text-sm text-gray-600">
|
||||
ID: ${user.username}
|
||||
<span class="ml-2 px-2 py-0.5 rounded text-xs ${
|
||||
<div class="text-sm text-gray-600 flex items-center gap-3">
|
||||
<span>ID: ${user.username}</span>
|
||||
${user.department ? `
|
||||
<span class="px-2 py-0.5 rounded text-xs bg-green-100 text-green-700">
|
||||
<i class="fas fa-building mr-1"></i>${AuthAPI.getDepartmentLabel(user.department)}
|
||||
</span>
|
||||
` : ''}
|
||||
<span class="px-2 py-0.5 rounded text-xs ${
|
||||
user.role === 'admin'
|
||||
? 'bg-red-100 text-red-700'
|
||||
: 'bg-blue-100 text-blue-700'
|
||||
@@ -447,6 +539,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
onclick="editUser(${user.id})"
|
||||
class="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 transition-colors text-sm"
|
||||
>
|
||||
<i class="fas fa-edit mr-1"></i>편집
|
||||
</button>
|
||||
<button
|
||||
onclick="resetPassword('${user.username}')"
|
||||
class="px-3 py-1 bg-yellow-500 text-white rounded hover:bg-yellow-600 transition-colors text-sm"
|
||||
@@ -507,6 +605,53 @@
|
||||
alert(error.message || '삭제에 실패했습니다.');
|
||||
}
|
||||
}
|
||||
|
||||
// 사용자 편집 모달 열기
|
||||
function editUser(userId) {
|
||||
const user = users.find(u => u.id === userId);
|
||||
if (!user) {
|
||||
alert('사용자를 찾을 수 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 모달 필드에 현재 값 설정
|
||||
document.getElementById('editUserId').value = user.id;
|
||||
document.getElementById('editUsername').value = user.username;
|
||||
document.getElementById('editFullName').value = user.full_name || '';
|
||||
document.getElementById('editDepartment').value = user.department || '';
|
||||
document.getElementById('editRole').value = user.role;
|
||||
|
||||
// 모달 표시
|
||||
document.getElementById('editUserModal').classList.remove('hidden');
|
||||
}
|
||||
|
||||
// 사용자 편집 모달 닫기
|
||||
function closeEditModal() {
|
||||
document.getElementById('editUserModal').classList.add('hidden');
|
||||
}
|
||||
|
||||
// 사용자 편집 폼 제출
|
||||
document.getElementById('editUserForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const userId = document.getElementById('editUserId').value;
|
||||
const userData = {
|
||||
full_name: document.getElementById('editFullName').value.trim() || null,
|
||||
department: document.getElementById('editDepartment').value || null,
|
||||
role: document.getElementById('editRole').value
|
||||
};
|
||||
|
||||
try {
|
||||
await AuthAPI.updateUser(userId, userData);
|
||||
|
||||
alert('사용자 정보가 수정되었습니다.');
|
||||
closeEditModal();
|
||||
await loadUsers(); // 목록 새로고침
|
||||
|
||||
} catch (error) {
|
||||
alert(error.message || '사용자 정보 수정에 실패했습니다.');
|
||||
}
|
||||
});
|
||||
|
||||
// 페이지 권한 관리 기능
|
||||
let selectedUserId = null;
|
||||
|
||||
Reference in New Issue
Block a user