Files
2026-04-18 06:18:58 +09:00

132 lines
6.5 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" class="active">⚡ 충전기 관리</a>
<a href="/pages/admin/charger-types.html">🏷 충전기 종류</a>
<a href="/pages/admin/qr.html">📷 QR 생성</a>
<a href="/pages/admin/accounts.html">👥 계정 관리</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 class="tbl-wrap">
<table>
<thead><tr><th>ID</th><th>종류</th><th>충전기명</th><th>충전소</th><th>CPO</th><th>설치일</th><th>미처리</th><th>QR</th><th>수정</th></tr></thead>
<tbody id="tbody"></tbody>
</table>
</div>
</div>
</div>
</div>
<div class="modal-bg hidden" id="modal">
<div class="modal">
<div class="modal-title" id="modalTitle">충전기 등록</div>
<input type="hidden" id="editId">
<div class="form-row">
<div class="form-group"><label>충전기 종류 <span class="req">*</span></label><select id="fTypeId"></select></div>
<div class="form-group"><label>충전기 ID <span class="req">*</span></label><input type="text" id="fId" placeholder="예: CG-003"></div>
</div>
<div class="form-row">
<div class="form-group"><label>충전기명 <span class="req">*</span></label><input type="text" id="fName" placeholder="예: 1호기"></div>
<div class="form-group"><label>충전소명 <span class="req">*</span></label><input type="text" id="fStation"></div>
</div>
<div class="form-row">
<div class="form-group"><label>CPO명</label><input type="text" id="fCpo"></div>
<div class="form-group"><label>설치일</label><input type="date" id="fInstalled"></div>
</div>
<div class="form-group"><label>위치 상세</label><input type="text" id="fLocation"></div>
<div class="form-row">
<div class="form-group"><label>위도</label><input type="number" id="fLat" step="0.000001"></div>
<div class="form-group"><label>경도</label><input type="number" id="fLng" step="0.000001"></div>
</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'));
let types = [], isEdit = false;
async function load() {
[types] = await Promise.all([API.get('/chargers/types')]);
const chargers = await API.get('/chargers');
document.getElementById('fTypeId').innerHTML = types.map(t=>`<option value="${t.id}">${t.name}</option>`).join('');
document.getElementById('tbody').innerHTML = chargers.map(c => `
<tr>
<td><strong>${c.id}</strong></td>
<td>${c.charger_type||'-'}</td>
<td>${c.name}</td>
<td>${c.station_name}</td>
<td>${c.cpo_name||'-'}</td>
<td>${c.installed_at||'-'}</td>
<td><span class="badge ${c.pending_reports>0?'s-pending':'s-done'}">${c.pending_reports}건</span></td>
<td><a class="btn btn-outline btn-sm" href="/pages/admin/qr.html?id=${c.id}">QR</a></td>
<td><button class="btn btn-outline btn-sm" onclick="editCharger('${c.id}')">수정</button></td>
</tr>`).join('');
}
function openModal(id=null) { isEdit=!!id; document.getElementById('modal').classList.remove('hidden'); document.getElementById('modalTitle').textContent = id?'충전기 수정':'충전기 등록'; }
function closeModal() { document.getElementById('modal').classList.add('hidden'); clearForm(); }
function clearForm() { ['fId','fName','fStation','fCpo','fInstalled','fLocation','fLat','fLng','editId'].forEach(id=>document.getElementById(id).value=''); document.getElementById('modalErr').style.display='none'; }
async function editCharger(id) {
const c = await API.get('/chargers/'+id);
openModal(id);
document.getElementById('editId').value = id;
document.getElementById('fTypeId').value = c.charger_type_id;
document.getElementById('fId').value = c.id; document.getElementById('fId').disabled = true;
document.getElementById('fName').value = c.name;
document.getElementById('fStation').value = c.station_name;
document.getElementById('fCpo').value = c.cpo_name||'';
document.getElementById('fInstalled').value = c.installed_at||'';
document.getElementById('fLocation').value = c.location_detail||'';
document.getElementById('fLat').value = c.gps_lat||'';
document.getElementById('fLng').value = c.gps_lng||'';
}
async function save() {
const fd = new FormData();
const id = document.getElementById('editId').value;
fd.append('charger_type_id', document.getElementById('fTypeId').value);
fd.append('name', document.getElementById('fName').value.trim());
fd.append('station_name', document.getElementById('fStation').value.trim());
fd.append('cpo_name', document.getElementById('fCpo').value);
fd.append('installed_at', document.getElementById('fInstalled').value);
fd.append('location_detail', document.getElementById('fLocation').value);
fd.append('gps_lat', document.getElementById('fLat').value||'');
fd.append('gps_lng', document.getElementById('fLng').value||'');
if (!id) fd.append('id', document.getElementById('fId').value.trim());
try {
if (id) await API.put('/chargers/'+id, fd);
else await API.post('/chargers', fd);
closeModal(); load();
} catch(e) { const el=document.getElementById('modalErr'); el.textContent=e.message; el.style.display='block'; }
}
load();
</script>
</body>
</html>