기능 추가 — 재조치 요청 (조치 기록 유지 재출동)
정비사 조치 완료 후 동일 문제 재발 시 관리자가 기존 기록을 보존한 채
재조치를 요청할 수 있는 기능 추가.
- DB: repairs.re_dispatch_requested/at, reports.re_dispatch_count 컬럼 추가
- 재조치 요청 엔드포인트 (POST /repairs/{id}/re-dispatch): 기존 repair에 플래그,
연결 신고를 pending으로 복원, re_dispatch_count 증가
- pending 상태 신고는 새 조치 생성으로 분기 (in_progress만 기존 수정 모드)
- report-detail: 조치승인·취소 사이에 "🔁 재조치 요청" 버튼, 이전 조치 이력 카드
- 정비사 대시보드: 재조치 건에 🔁 뱃지 및 강조 버튼색 표시
- 엑셀 export: 재조치횟수 컬럼 추가
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -206,6 +206,7 @@ async function load() {
|
||||
]);
|
||||
const repair = r.repair;
|
||||
const cost = repair?.cost;
|
||||
const prevRepairs = r.prev_repairs || [];
|
||||
|
||||
document.getElementById('pageTitle').textContent = `신고 #${r.id} 상세`;
|
||||
|
||||
@@ -529,8 +530,13 @@ async function load() {
|
||||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
||||
${repair.approved_at
|
||||
? `<span style="font-size:12px;background:#D1FAE5;color:#065F46;padding:3px 12px;border-radius:10px;font-weight:700;">✅ 승인완료 · ${repair.approved_by_name||''}</span>`
|
||||
: `<button onclick="toggleApprovePanel()" id="approvePanelBtn" style="padding:5px 14px;border:none;border-radius:7px;background:var(--green);color:white;font-size:12px;font-weight:700;cursor:pointer;">✅ 조치 승인</button>`
|
||||
: repair.re_dispatch_requested
|
||||
? `<span style="font-size:12px;background:#FEF3C7;color:#92400E;padding:3px 12px;border-radius:10px;font-weight:700;">🔁 재조치 요청됨 · ${Auth.fmtDt(repair.re_dispatch_requested_at)}</span>`
|
||||
: `<button onclick="toggleApprovePanel()" id="approvePanelBtn" style="padding:5px 14px;border:none;border-radius:7px;background:var(--green);color:white;font-size:12px;font-weight:700;cursor:pointer;">✅ 조치 승인</button>`
|
||||
}
|
||||
${!repair.approved_at && !repair.re_dispatch_requested
|
||||
? `<button onclick="requestRedispatch(${repair.id})" style="padding:5px 14px;border:none;border-radius:7px;background:#F59E0B;color:white;font-size:12px;font-weight:700;cursor:pointer;">🔁 재조치 요청</button>`
|
||||
: ''}
|
||||
<button onclick="cancelRepair(${repair.id}, ${!!repair.approved_at})" style="padding:5px 14px;border:none;border-radius:7px;background:#FEE2E2;color:#991B1B;font-size:12px;font-weight:700;cursor:pointer;">🔄 조치취소</button>
|
||||
</div>` : ''}
|
||||
</div>
|
||||
@@ -543,6 +549,8 @@ async function load() {
|
||||
<tr><td style="color:var(--gray4)">시작시각</td><td>${Auth.fmtDt(repair.started_at)}</td></tr>
|
||||
<tr><td style="color:var(--gray4)">완료시각</td><td>${Auth.fmtDt(repair.completed_at)}</td></tr>
|
||||
<tr><td style="color:var(--gray4)">처리결과</td><td>${Auth.statusBadge(repair.result_status)}</td></tr>
|
||||
${repair.re_dispatch_requested ? `
|
||||
<tr><td style="color:var(--gray4)">재조치요청</td><td style="color:#92400E;font-weight:700;">🔁 재조치 요청됨 (${Auth.fmtDt(repair.re_dispatch_requested_at)})</td></tr>` : ''}
|
||||
</table>
|
||||
<div style="margin-top:12px">
|
||||
<label style="font-size:12px;font-weight:700;color:var(--navy2)">조치 전 사진</label>
|
||||
@@ -661,6 +669,35 @@ async function load() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${prevRepairs.length ? `
|
||||
<div class="card">
|
||||
<div class="card-title">📋 이전 조치 이력 (재조치 전 기록 ${prevRepairs.length}건)</div>
|
||||
${prevRepairs.map((pr, idx) => `
|
||||
<details style="margin-bottom:10px;border:1px solid var(--gray2);border-radius:8px;overflow:hidden;">
|
||||
<summary style="padding:10px 14px;cursor:pointer;font-size:13px;font-weight:700;color:var(--navy2);background:var(--gray1);list-style:none;display:flex;justify-content:space-between;align-items:center;">
|
||||
<span>#${pr.id} · ${pr.mechanic_name||'?'} · ${Auth.fmtDt(pr.completed_at)}</span>
|
||||
<span style="font-size:11px;background:#FEF3C7;color:#92400E;padding:2px 8px;border-radius:8px;">🔁 재조치 요청됨</span>
|
||||
</summary>
|
||||
<div style="padding:12px 14px;font-size:13px;">
|
||||
<table class="no-hover" style="font-size:13px;">
|
||||
<tr><td style="color:var(--gray4);width:100px">정비사</td><td>${pr.mechanic_name||'-'} (${pr.mechanic_company||'-'})</td></tr>
|
||||
<tr><td style="color:var(--gray4)">조치유형</td><td>${(pr.repair_types||[]).join(', ')||'-'}</td></tr>
|
||||
<tr><td style="color:var(--gray4)">조치내용</td><td>${pr.description||'-'}</td></tr>
|
||||
<tr><td style="color:var(--gray4)">완료시각</td><td>${Auth.fmtDt(pr.completed_at)}</td></tr>
|
||||
<tr><td style="color:var(--gray4)">처리결과</td><td>${Auth.statusBadge(pr.result_status)}</td></tr>
|
||||
<tr><td style="color:var(--gray4)">재조치요청</td><td style="color:#92400E;font-weight:700;">${Auth.fmtDt(pr.re_dispatch_requested_at)}</td></tr>
|
||||
</table>
|
||||
${(pr.photos_before||[]).length || (pr.photos_after||[]).length ? `
|
||||
<div style="margin-top:10px;">
|
||||
${(pr.photos_before||[]).length ? `<div style="font-size:11px;font-weight:700;color:var(--gray4);margin-bottom:4px;">조치 전</div>
|
||||
<div class="photo-preview">${(pr.photos_before||[]).map(p=>`<img src="${p}" onclick="window.open('${p}')" style="cursor:zoom-in">`).join('')}</div>` : ''}
|
||||
${(pr.photos_after||[]).length ? `<div style="font-size:11px;font-weight:700;color:var(--gray4);margin:6px 0 4px;">조치 후</div>
|
||||
<div class="photo-preview">${(pr.photos_after||[]).map(p=>`<img src="${p}" onclick="window.open('${p}')" style="cursor:zoom-in">`).join('')}</div>` : ''}
|
||||
</div>` : ''}
|
||||
</div>
|
||||
</details>`).join('')}
|
||||
</div>` : ''}
|
||||
|
||||
${costHtml}
|
||||
`;
|
||||
|
||||
@@ -914,6 +951,14 @@ async function cancelRepair(repairId, isApproved) {
|
||||
} catch(e) { alert('조치취소 오류: ' + e.message); }
|
||||
}
|
||||
|
||||
async function requestRedispatch(repairId) {
|
||||
if (!confirm('재조치를 요청합니다.\n\n기존 조치 기록은 유지되며,\n연결된 신고가 정비사 목록에 다시 표시됩니다.\n\n계속하시겠습니까?')) return;
|
||||
try {
|
||||
await API.post('/repairs/' + repairId + '/re-dispatch', new FormData());
|
||||
load();
|
||||
} catch(e) { alert('재조치 요청 오류: ' + e.message); }
|
||||
}
|
||||
|
||||
async function approveReport(id) {
|
||||
if (!confirm('신고를 승인하여 정비사에게 공개하시겠습니까?')) return;
|
||||
await API.patch(`/reports/${id}/approve`);
|
||||
|
||||
@@ -157,14 +157,14 @@ function renderList() {
|
||||
: `/pages/mechanic/repair.html?charger_id=${r.charger_id}&report_id=${r.id}`;
|
||||
return `
|
||||
<tr onclick="location.href='${href}'">
|
||||
<td>#${r.id}</td>
|
||||
<td>#${r.id}${r.re_dispatch_count > 0 ? ' <span style="font-size:10px;background:#FEF3C7;color:#92400E;padding:1px 6px;border-radius:8px;font-weight:700;vertical-align:middle;">🔁재조치</span>' : ''}</td>
|
||||
<td><strong>${r.charger_id}</strong><br><small>${r.charger_name||''}</small></td>
|
||||
<td>${r.station_name||'-'}</td>
|
||||
<td>${r.charger_type||'-'}</td>
|
||||
<td>${(r.issue_types||[]).join(', ')}</td>
|
||||
<td>${Auth.fmtDt(r.reported_at)}</td>
|
||||
<td>${Auth.statusBadge(r.status)}</td>
|
||||
<td><a class="btn btn-primary btn-sm" href="${href}" onclick="event.stopPropagation()">조치</a></td>
|
||||
<td><a class="btn ${r.re_dispatch_count > 0 ? 'btn-accent' : 'btn-primary'} btn-sm" href="${href}" onclick="event.stopPropagation()">조치</a></td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user