Files
ev-charger-as/frontend/static/pages/mechanic/scan.html
byun 9f0f4326fe 기능 개선 — 사진 업로드, HEIC 지원, 재조치 흐름, 신고 순번, 모바일 UI
- 이미지 압축: 삼성/네이버 브라우저 호환, URL.createObjectURL 방식으로 메모리 절감,
  대용량 PNG/HEIC 처리, blob 유효성 검증, 순차 압축으로 모바일 OOM 방지
- HEIC/HEIF 지원: pillow-heif 서버사이드 변환, Pillow 12.2.0 업그레이드
- 조치 페이지: '조치 완료 저장' 단일 버튼으로 단순화
- 재조치 흐름: 관리자 재조치 요청 시 이전 조치 이력을 번호 카드로 순차 표시
- 신고 순번: 전체 기준 ROW_NUMBER(oldest=1) 순번 표시, 삭제 gap 제거
- 모바일 탭바: position:fixed 적용으로 nav 하단 흰 여백 제거

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 05:38:33 +09:00

82 lines
3.1 KiB
HTML

<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>QR 스캔</title>
<link rel="stylesheet" href="/css/style.css">
<style>
#reader{width:100%;max-width:400px;margin:0 auto;border-radius:10px;overflow:hidden;}
</style>
</head>
<body>
<nav class="nav">
<span class="nav-brand">⚡ EV AS 관리</span>
<div id="navUser"></div>
</nav>
<div class="mech-tab-bar">
<a href="/pages/mechanic/dashboard.html">📋<span>AS 목록</span></a>
<a href="/pages/mechanic/scan.html" class="active">📷<span>QR 스캔</span></a>
<a href="/pages/mechanic/history.html">🗂<span>처리 이력</span></a>
</div>
<div class="layout">
<div class="sidebar">
<div class="sidebar-section">메뉴</div>
<a href="/pages/mechanic/dashboard.html">📋 AS 목록</a>
<a href="/pages/mechanic/scan.html" class="active">📷 QR 스캔</a>
<a href="/pages/mechanic/history.html">🗂 처리 이력</a>
</div>
<div class="main">
<div style="max-width:480px;margin:0 auto;">
<h2 style="font-size:18px;font-weight:700;color:var(--navy);margin-bottom:16px">📷 QR 스캔</h2>
<div class="alert alert-info" style="margin-bottom:16px;">충전기의 QR 코드를 카메라로 인식해 주세요.</div>
<div id="reader"></div>
<div id="result" class="alert alert-success" style="display:none;margin-top:14px;"></div>
<div style="margin-top:16px;">
<div class="form-group">
<label>충전기 ID 직접 입력</label>
<div style="display:flex;gap:8px;">
<input type="text" id="manualId" placeholder="예: CG-003">
<button class="btn btn-primary" onclick="goManual()">이동</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://unpkg.com/html5-qrcode/minified/html5-qrcode.min.js"></script>
<script src="/js/api.js?v=20260603"></script><script src="/js/auth.js?v=20260603"></script>
<script>
Auth.require(['mechanic','admin']);
Auth.renderNav(document.getElementById('navUser'));
const scanner = new Html5Qrcode("reader");
scanner.start({ facingMode: "environment" },
{ fps: 10, qrbox: { width: 250, height: 250 } },
qrText => {
scanner.stop();
document.getElementById('result').style.display = 'block';
document.getElementById('result').textContent = '인식됨: ' + qrText + ' — 이동 중...';
// URL에서 charger_id 추출
try {
const url = new URL(qrText);
const parts = url.pathname.split('/');
const chargerId = parts[parts.length - 1];
setTimeout(() => location.href = `/pages/mechanic/repair.html?charger_id=${chargerId}`, 800);
} catch {
setTimeout(() => location.href = `/pages/mechanic/repair.html?charger_id=${qrText}`, 800);
}
},
() => {}
).catch(() => {
document.getElementById('reader').innerHTML = '<div class="alert alert-warn">카메라 접근이 거부되었습니다. 직접 입력을 이용해 주세요.</div>';
});
function goManual() {
const id = document.getElementById('manualId').value.trim();
if (!id) return;
location.href = `/pages/mechanic/repair.html?charger_id=${id}`;
}
</script>
</body>
</html>