feat:명함 등록 페이지에 카메라 촬영 기능 추가

- 모바일에서 직접 카메라로 명함 촬영 가능
- capture="environment" 속성으로 후면 카메라 기본 사용
- 기존 파일 업로드와 카메라 촬영 버튼 병행 지원

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
pro
2026-01-28 16:17:54 +09:00
parent 8d73cc3f79
commit 273e2768da

View File

@@ -99,11 +99,23 @@
<div class="ocr-drop-zone" id="ocr-drop-zone">
<input type="file" id="ocr-file-input" accept="image/*" class="hidden">
<input type="file" id="ocr-camera-input" accept="image/*" capture="environment" class="hidden">
<svg class="ocr-drop-zone-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<p class="text-gray-600 font-medium text-sm">명함 이미지를 드래그하거나 클릭하여 업로드</p>
<p class="text-gray-400 text-xs mt-1">AI가 자동으로 정보를 추출합니다 (JPG, PNG)</p>
<!-- 모바일 카메라 촬영 버튼 -->
<div class="mt-4 pt-4 border-t border-gray-200">
<button type="button" id="ocr-camera-btn" class="inline-flex items-center gap-2 px-4 py-2 bg-blue-500 hover:bg-blue-600 text-white text-sm font-medium rounded-lg transition">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 13a3 3 0 11-6 0 3 3 0 016 0z" />
</svg>
카메라로 촬영
</button>
</div>
</div>
<img id="ocr-preview-image" alt="Preview">
</div>
@@ -201,13 +213,31 @@ class="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition"
<script>
document.addEventListener('DOMContentLoaded', function() {
const fileInput = document.getElementById('ocr-file-input');
const cameraInput = document.getElementById('ocr-camera-input');
const cameraBtn = document.getElementById('ocr-camera-btn');
const dropZone = document.getElementById('ocr-drop-zone');
const previewImage = document.getElementById('ocr-preview-image');
const statusEl = document.getElementById('ocr-status');
const csrfToken = '{{ csrf_token() }}';
// 드래그 앤 드롭
dropZone.addEventListener('click', () => fileInput.click());
// 카메라 버튼 클릭 시 카메라 입력 트리거
cameraBtn.addEventListener('click', (e) => {
e.stopPropagation(); // dropZone 클릭 이벤트 전파 방지
cameraInput.click();
});
// 카메라 입력 처리
cameraInput.addEventListener('change', (e) => {
if (e.target.files.length) handleFile(e.target.files[0]);
});
// 드래그 앤 드롭 (드롭존 클릭 시 파일 선택)
dropZone.addEventListener('click', (e) => {
// 카메라 버튼 클릭이 아닌 경우에만 파일 선택
if (e.target !== cameraBtn && !cameraBtn.contains(e.target)) {
fileInput.click();
}
});
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
dropZone.classList.add('dragover');