|
|
|
|
@@ -395,8 +395,43 @@ async function load() {
|
|
|
|
|
<pre style="margin-top:6px;background:var(--gray1);border:1px solid var(--gray3);border-radius:6px;padding:10px;font-size:11px;overflow-x:auto;white-space:pre-wrap;word-break:break-all;max-height:200px;overflow-y:auto;">${escHtmlDetail(r.ocpp_log)}</pre>
|
|
|
|
|
</div>` : ''}
|
|
|
|
|
${r.status === 'pending_approval' ? `
|
|
|
|
|
<button class="btn btn-success btn-sm" style="margin-top:12px"
|
|
|
|
|
onclick="approveReport(${r.id})">✅ 신고 승인 (정비사 공개)</button>` : ''}
|
|
|
|
|
<div style="display:flex;gap:8px;margin-top:12px;flex-wrap:wrap">
|
|
|
|
|
<button class="btn btn-success btn-sm"
|
|
|
|
|
onclick="approveReport(${r.id})">✅ 신고 승인 (정비사 공개)</button>
|
|
|
|
|
<button class="btn btn-sm" style="background:#64748B;color:white;border:none"
|
|
|
|
|
onclick="toggleClosePanel()">🔚 상황종료</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div id="closurePanel" style="display:none;margin-top:12px;background:#F8FAFC;border:1px solid var(--gray3);border-radius:8px;padding:14px">
|
|
|
|
|
<div style="font-size:13px;font-weight:700;color:var(--navy);margin-bottom:10px">🔚 상황종료 사유 선택</div>
|
|
|
|
|
<div style="display:flex;flex-direction:column;gap:7px;margin-bottom:10px">
|
|
|
|
|
${[
|
|
|
|
|
['natural','증상자연소거'],
|
|
|
|
|
['remote_reset','원격리셋후증상소거'],
|
|
|
|
|
['false_alarm','인지오류'],
|
|
|
|
|
['other','기타']
|
|
|
|
|
].map(([v,l]) => `
|
|
|
|
|
<label style="display:flex;align-items:center;gap:8px;font-size:13px;cursor:pointer">
|
|
|
|
|
<input type="radio" name="closureType" value="${v}" style="width:auto;accent-color:var(--accent)"
|
|
|
|
|
onchange="document.getElementById('closureNoteWrap').style.display=this.value==='other'?'block':'none'">
|
|
|
|
|
${l}
|
|
|
|
|
</label>`).join('')}
|
|
|
|
|
</div>
|
|
|
|
|
<div id="closureNoteWrap" style="display:none;margin-bottom:10px">
|
|
|
|
|
<input type="text" id="closureNote" placeholder="기타 사유를 입력하세요"
|
|
|
|
|
style="width:100%;padding:8px 10px;border:1px solid var(--gray3);border-radius:6px;font-size:13px">
|
|
|
|
|
</div>
|
|
|
|
|
<div style="display:flex;gap:8px">
|
|
|
|
|
<button class="btn btn-sm" style="background:#64748B;color:white;border:none"
|
|
|
|
|
onclick="submitClose(${r.id})">확인</button>
|
|
|
|
|
<button class="btn btn-outline btn-sm" onclick="toggleClosePanel()">취소</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>` : ''}
|
|
|
|
|
${r.status === 'closed' ? `
|
|
|
|
|
<div style="margin-top:12px;padding:10px 14px;background:#F1F5F9;border-radius:8px;border-left:4px solid #64748B">
|
|
|
|
|
<div style="font-size:12px;font-weight:700;color:#475569;margin-bottom:4px">🔚 상황종료 처리됨</div>
|
|
|
|
|
<div style="font-size:13px;color:var(--text)">사유: <strong>${{'natural':'증상자연소거','remote_reset':'원격리셋후증상소거','false_alarm':'인지오류','other':'기타'}[r.closure_type]||r.closure_type||'-'}</strong>${r.closure_note ? ' — ' + escHtmlDetail(r.closure_note) : ''}</div>
|
|
|
|
|
<div style="font-size:11px;color:var(--gray4);margin-top:3px">${r.closed_by_name||''} · ${r.closed_at ? new Date(r.closed_at).toLocaleString('ko-KR') : ''}</div>
|
|
|
|
|
</div>` : ''}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- 편집 모드 -->
|
|
|
|
|
@@ -886,6 +921,27 @@ async function approveReport(id) {
|
|
|
|
|
load();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toggleClosePanel() {
|
|
|
|
|
const panel = document.getElementById('closurePanel');
|
|
|
|
|
if (!panel) return;
|
|
|
|
|
panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function submitClose(id) {
|
|
|
|
|
const selected = document.querySelector('input[name="closureType"]:checked');
|
|
|
|
|
if (!selected) { alert('상황종료 사유를 선택해 주세요.'); return; }
|
|
|
|
|
const note = document.getElementById('closureNote')?.value || '';
|
|
|
|
|
if (selected.value === 'other' && !note.trim()) { alert('기타 사유를 입력해 주세요.'); return; }
|
|
|
|
|
if (!confirm('상황종료 처리하시겠습니까?\n정비사 조치 없이 신고를 종결합니다.')) return;
|
|
|
|
|
try {
|
|
|
|
|
const fd = new FormData();
|
|
|
|
|
fd.append('closure_type', selected.value);
|
|
|
|
|
fd.append('closure_note', note);
|
|
|
|
|
await API.patch(`/reports/${id}/close`, fd);
|
|
|
|
|
load();
|
|
|
|
|
} catch(e) { alert('오류: ' + e.message); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function saveCost(repairId) {
|
|
|
|
|
const partyType = document.getElementById('partyType').value;
|
|
|
|
|
if (!partyType) { showCostErr('출장비 부담 주체를 선택해 주세요.'); return; }
|
|
|
|
|
|