feat: 사진 업로드 기능 개선 및 카테고리 업데이트

- 사진 2장까지 업로드 지원
- 카메라 촬영 + 갤러리 선택 분리
- 이미지 압축 및 최적화 (ImageUtils)
- iPhone .mpo 파일 JPEG 변환 지원
- 카테고리 변경: 치수불량 → 설계미스, 검사미스 추가
- KST 시간대 설정
- URL 해시 처리로 목록관리 페이지 이동 개선
- 로그인 OAuth2 form-data 형식 수정
- 업로드 속도 개선 및 프로그레스바 추가
This commit is contained in:
hyungi
2025-09-18 07:00:28 +09:00
parent f6bdb68d19
commit 44e2fb2e44
32 changed files with 988 additions and 177 deletions

View File

@@ -121,7 +121,8 @@
</main>
<!-- Scripts -->
<script src="/static/js/api.js"></script>
<script src="/static/js/api.js?v=20250917"></script>
<script src="/static/js/date-utils.js?v=20250917"></script>
<script>
let currentUser = null;
let issues = [];
@@ -143,6 +144,30 @@
setDateRange('week');
});
// 이미지 모달 표시
function showImageModal(imagePath) {
if (!imagePath) return;
// 모달 HTML 생성
const modal = document.createElement('div');
modal.className = 'fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50';
modal.onclick = () => modal.remove();
modal.innerHTML = `
<div class="relative max-w-4xl max-h-[90vh]">
<img src="${imagePath}" class="max-w-full max-h-[90vh] object-contain rounded-lg">
<button
onclick="this.parentElement.parentElement.remove()"
class="absolute top-2 right-2 p-2 bg-red-500 text-white rounded-full hover:bg-red-600"
>
<i class="fas fa-times"></i>
</button>
</div>
`;
document.body.appendChild(modal);
}
// 네비게이션 권한 업데이트
function updateNavigation() {
const listBtn = document.getElementById('listBtn');
@@ -261,38 +286,39 @@
const categoryNames = {
material_missing: '자재누락',
dimension_defect: '치수불량',
incoming_defect: '입고자재 불량'
design_error: '설계미스',
incoming_defect: '입고자재 불량',
inspection_miss: '검사미스'
};
const categoryColors = {
material_missing: 'bg-yellow-100 text-yellow-700 border-yellow-300',
dimension_defect: 'bg-orange-100 text-orange-700 border-orange-300',
incoming_defect: 'bg-red-100 text-red-700 border-red-300'
design_error: 'bg-blue-100 text-blue-700 border-blue-300',
incoming_defect: 'bg-red-100 text-red-700 border-red-300',
inspection_miss: 'bg-purple-100 text-purple-700 border-purple-300'
};
// 시간순으로 나열
container.innerHTML = issues.map(issue => {
const date = new Date(issue.report_date);
const dateStr = date.toLocaleDateString('ko-KR', {
month: 'short',
day: 'numeric',
weekday: 'short'
});
const timeStr = date.toLocaleTimeString('ko-KR', {
hour: '2-digit',
minute: '2-digit'
});
const dateStr = DateUtils.formatKST(issue.report_date, true);
const relativeTime = DateUtils.getRelativeTime(issue.report_date);
return `
<div class="flex gap-3 p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors border-l-4 ${categoryColors[issue.category].split(' ')[2] || 'border-gray-300'}">
<!-- 사진 -->
${issue.photo_path ?
`<img src="${issue.photo_path}" class="w-20 h-20 object-cover rounded shadow-sm flex-shrink-0">` :
`<div class="w-20 h-20 bg-gray-200 rounded flex items-center justify-center flex-shrink-0">
<i class="fas fa-image text-gray-400"></i>
</div>`
}
<!-- 사진 -->
<div class="flex gap-1 flex-shrink-0">
${issue.photo_path ?
`<img src="${issue.photo_path}" class="w-20 h-20 object-cover rounded shadow-sm cursor-pointer" onclick="showImageModal('${issue.photo_path}')">` : ''
}
${issue.photo_path2 ?
`<img src="${issue.photo_path2}" class="w-20 h-20 object-cover rounded shadow-sm cursor-pointer" onclick="showImageModal('${issue.photo_path2}')">` : ''
}
${!issue.photo_path && !issue.photo_path2 ?
`<div class="w-20 h-20 bg-gray-200 rounded flex items-center justify-center">
<i class="fas fa-image text-gray-400"></i>
</div>` : ''
}
</div>
<!-- 내용 -->
<div class="flex-1 min-w-0">
@@ -308,7 +334,7 @@
` : ''}
</div>
<div class="text-xs text-gray-500">
${dateStr} ${timeStr}
${dateStr} (${relativeTime})
</div>
</div>
@@ -329,8 +355,9 @@
<span class="font-medium text-blue-900">총 ${issues.length}건</span>
<span class="text-blue-700 ml-3">
자재누락: ${issues.filter(i => i.category === 'material_missing').length}건 |
치수불량: ${issues.filter(i => i.category === 'dimension_defect').length}건 |
입고자재 불량: ${issues.filter(i => i.category === 'incoming_defect').length}
설계미스: ${issues.filter(i => i.category === 'design_error').length}건 |
입고자재 불량: ${issues.filter(i => i.category === 'incoming_defect').length} |
검사미스: ${issues.filter(i => i.category === 'inspection_miss').length}
</span>
</div>
`;