Files
ev-charger-as/frontend/static/pages/admin/accounts.html
2026-04-18 06:18:58 +09:00

123 lines
7.0 KiB
HTML

<!DOCTYPE html><html lang="ko"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>계정 관리</title><link rel="stylesheet" href="/css/style.css"></head>
<body>
<nav class="nav"><span class="nav-brand">⚡ EV AS 관리 — 관리자</span><div id="navUser"></div></nav>
<div class="layout">
<div class="sidebar">
<div class="sidebar-section">AS 관리</div>
<a href="/pages/admin/dashboard.html">📊 대시보드</a>
<a href="/pages/admin/reports.html">📋 신고 목록</a>
<a href="/pages/admin/costs.html">💰 출장비 관리</a>
<div class="sidebar-section">시스템</div>
<a href="/pages/admin/improvements.html">🔧 개선항목</a>
<a href="/pages/admin/chargers.html">⚡ 충전기 관리</a>
<a href="/pages/admin/charger-types.html">🏷 충전기 종류</a>
<a href="/pages/admin/qr.html">📷 QR 생성</a>
<a href="/pages/admin/accounts.html" class="active">👥 계정 관리</a>
<a href="/pages/admin/settings.html">⚙️ 설정</a>
</div>
<div class="main">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:18px;">
<h2 style="font-size:18px;font-weight:700;color:var(--navy)">계정 관리</h2>
<button class="btn btn-primary" onclick="openModal()">+ 계정 생성</button>
</div>
<div class="card">
<div style="display:flex;gap:10px;margin-bottom:14px;">
<select id="fRole" onchange="load()" style="width:auto">
<option value="">전체</option><option value="mechanic">정비사</option>
<option value="manufacturer">제조사</option><option value="admin">관리자</option>
</select>
</div>
<div class="tbl-wrap"><table>
<thead><tr><th>ID</th><th>아이디</th><th>역할</th><th>이름</th><th>회사/제조사</th><th>전화번호</th><th>상태</th><th>수정</th></tr></thead>
<tbody id="tbody"></tbody>
</table></div>
</div>
</div>
</div>
<div class="modal-bg hidden" id="modal">
<div class="modal" style="max-width:480px">
<div class="modal-title" id="modalTitle">계정 생성</div>
<input type="hidden" id="eId">
<div class="form-row">
<div class="form-group"><label>역할 <span class="req">*</span></label>
<select id="eRole" onchange="toggleFields()">
<option value="mechanic">정비사</option>
<option value="manufacturer">제조사</option>
<option value="admin">관리자</option>
</select>
</div>
<div class="form-group"><label>로그인 ID <span class="req">*</span></label><input type="text" id="eUsername"></div>
</div>
<div class="form-group"><label>비밀번호 <span class="req" id="pwReq">*</span></label><input type="password" id="ePassword" placeholder="수정 시 변경할 경우에만 입력"></div>
<div class="form-row">
<div class="form-group"><label>이름 <span class="req">*</span></label><input type="text" id="eName"></div>
<div class="form-group" id="companyField"><label>회사명</label><input type="text" id="eCompany"></div>
</div>
<div class="form-row">
<div class="form-group"><label>전화번호</label><input type="tel" id="ePhone"></div>
<div class="form-group" id="emailField"><label>이메일</label><input type="email" id="eEmail"></div>
</div>
<div class="form-group"><label>계정 활성화</label>
<select id="eActive"><option value="true">활성</option><option value="false">비활성</option></select>
</div>
<div id="modalErr" class="alert alert-danger" style="display:none"></div>
<div class="modal-actions">
<button class="btn btn-outline" onclick="closeModal()">취소</button>
<button class="btn btn-primary" onclick="save()">저장</button>
</div>
</div>
</div>
<script src="/js/api.js"></script><script src="/js/auth.js"></script>
<script>
Auth.require(['admin']); Auth.renderNav(document.getElementById('navUser'));
const ROLE_LABEL = {admin:'관리자',mechanic:'정비사',manufacturer:'제조사'};
async function load() {
const role = document.getElementById('fRole').value;
const users = await API.get('/accounts'+(role?'?role='+role:''));
document.getElementById('tbody').innerHTML = users.map(u=>`
<tr><td>${u.id}</td><td>${u.username}</td><td>${ROLE_LABEL[u.role]||u.role}</td>
<td>${u.name}</td><td>${u.company||'-'}</td><td>${u.phone||'-'}</td>
<td><span class="badge ${u.is_active?'s-done':'s-waiting'}">${u.is_active?'활성':'비활성'}</span></td>
<td><button class="btn btn-outline btn-sm" onclick="editUser(${u.id})">수정</button>
<button class="btn btn-danger btn-sm" onclick="delUser(${u.id})">삭제</button></td></tr>`).join('');
}
function openModal() { document.getElementById('modal').classList.remove('hidden'); document.getElementById('eId').value=''; document.getElementById('eUsername').disabled=false; document.getElementById('pwReq').style.display='inline'; }
function closeModal() { document.getElementById('modal').classList.add('hidden'); document.getElementById('modalErr').style.display='none'; ['eUsername','ePassword','eName','eCompany','ePhone','eEmail'].forEach(id=>document.getElementById(id).value=''); }
function toggleFields() {}
async function editUser(id) {
const users = await API.get('/accounts');
const u = users.find(x=>x.id===id);
openModal();
document.getElementById('eId').value=id;
document.getElementById('eRole').value=u.role;
document.getElementById('eUsername').value=u.username; document.getElementById('eUsername').disabled=true;
document.getElementById('eName').value=u.name;
document.getElementById('eCompany').value=u.company||'';
document.getElementById('ePhone').value=u.phone||'';
document.getElementById('eEmail').value=u.email||'';
document.getElementById('eActive').value=String(u.is_active);
document.getElementById('pwReq').style.display='none';
document.getElementById('modalTitle').textContent='계정 수정';
}
async function save() {
const id = document.getElementById('eId').value;
const fd = new FormData();
if (!id) { fd.append('username',document.getElementById('eUsername').value.trim()); fd.append('role',document.getElementById('eRole').value); }
const pw = document.getElementById('ePassword').value;
if (pw) fd.append('password', pw);
else if (!id) { alert('비밀번호를 입력하세요.'); return; }
fd.append('name',document.getElementById('eName').value.trim());
fd.append('company',document.getElementById('eCompany').value);
fd.append('phone',document.getElementById('ePhone').value);
fd.append('email',document.getElementById('eEmail').value);
fd.append('is_active',document.getElementById('eActive').value);
try {
if (id) await API.put('/accounts/'+id, fd);
else await API.post('/accounts', fd);
closeModal(); load();
} catch(e) { const el=document.getElementById('modalErr'); el.textContent=e.message; el.style.display='block'; }
}
async function delUser(id) { if(!confirm('비활성 처리하시겠습니까?')) return; await API.delete('/accounts/'+id); load(); }
load();
</script></body></html>