fix(tkqc): 관리함 데스크톱 인라인 카드에도 사진 보충 UI 추가
첫 커밋(178155d)에서는 createModalContent(완료된 이슈 상세 모달)에만
사진 보충 input을 추가했는데, 데스크톱 관리함은 상세 모달이 아니라
createInProgressRow 로 렌더링되는 인라인 카드(저장/삭제/완료처리 버튼이
카드에 직접 있는 형태) 이었음. 사용자 스크린샷으로 확인.
- createInProgressRow: "업로드 사진" 섹션 아래 file input 추가
- saveIssueChanges: 저장 시 빈 슬롯에만 photo/photo2~5 base64 업로드
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -427,25 +427,37 @@ function createInProgressRow(issue, project) {
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">업로드 사진</label>
|
||||
${(() => {
|
||||
const photos = [
|
||||
const photoSlots = [
|
||||
issue.photo_path,
|
||||
issue.photo_path2,
|
||||
issue.photo_path3,
|
||||
issue.photo_path4,
|
||||
issue.photo_path5
|
||||
].filter(p => p);
|
||||
];
|
||||
const filled = photoSlots.filter(p => p);
|
||||
const emptyCount = 5 - filled.length;
|
||||
|
||||
if (photos.length === 0) {
|
||||
return '<div class="w-20 h-20 bg-gray-100 rounded-lg flex items-center justify-center text-gray-400 text-xs border-2 border-dashed border-gray-300">사진 없음</div>';
|
||||
}
|
||||
const existing = filled.length === 0
|
||||
? '<div class="w-20 h-20 bg-gray-100 rounded-lg flex items-center justify-center text-gray-400 text-xs border-2 border-dashed border-gray-300">사진 없음</div>'
|
||||
: `<div class="flex flex-wrap gap-2">
|
||||
${filled.map((path, idx) => `
|
||||
<img src="${path}" class="w-20 h-20 object-cover rounded-lg cursor-pointer border-2 border-gray-200 hover:border-blue-400 transition-colors" onclick="openPhotoModal('${path}')" alt="업로드 사진 ${idx + 1}">
|
||||
`).join('')}
|
||||
</div>`;
|
||||
|
||||
return `
|
||||
<div class="flex flex-wrap gap-2">
|
||||
${photos.map((path, idx) => `
|
||||
<img src="${path}" class="w-20 h-20 object-cover rounded-lg cursor-pointer border-2 border-gray-200 hover:border-blue-400 transition-colors" onclick="openPhotoModal('${path}')" alt="업로드 사진 ${idx + 1}">
|
||||
`).join('')}
|
||||
// 사진 보충 UI (빈 슬롯에만 채움, 저장 버튼 클릭 시 업로드)
|
||||
const uploadUi = isPendingCompletion ? '' : (emptyCount > 0 ? `
|
||||
<div class="mt-3 pt-3 border-t border-gray-200">
|
||||
<label class="block text-xs font-medium text-gray-600 mb-1">
|
||||
<i class="fas fa-plus-circle text-blue-500 mr-1"></i>사진 보충 (남은 슬롯: ${emptyCount}장)
|
||||
</label>
|
||||
<input type="file" id="original_photo_${issue.id}" accept="image/*" multiple
|
||||
class="block w-full text-xs text-gray-500 file:mr-3 file:py-1.5 file:px-3 file:rounded-md file:border-0 file:text-xs file:font-semibold file:bg-blue-50 file:text-blue-700 hover:file:bg-blue-100">
|
||||
<p class="text-xs text-gray-400 mt-1">※ 비어있는 슬롯에만 자동으로 채워집니다 (기존 사진은 유지). 저장 버튼 클릭 시 업로드.</p>
|
||||
</div>
|
||||
`;
|
||||
` : '<p class="text-xs text-gray-400 mt-2"><i class="fas fa-info-circle mr-1"></i>5장 모두 찬 상태입니다</p>');
|
||||
|
||||
return existing + uploadUi;
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
@@ -909,6 +921,36 @@ async function saveIssueChanges(issueId) {
|
||||
}
|
||||
}
|
||||
|
||||
// 원본 사진 보충 — 빈 슬롯에만 자동 채움 (기존 사진 유지)
|
||||
const originalPhotoInput = document.getElementById(`original_photo_${issueId}`);
|
||||
if (originalPhotoInput && originalPhotoInput.files && originalPhotoInput.files.length > 0) {
|
||||
const currentIssue = issues.find(i => i.id === issueId);
|
||||
if (currentIssue) {
|
||||
const slotKeys = ['photo_path', 'photo_path2', 'photo_path3', 'photo_path4', 'photo_path5'];
|
||||
const emptySlots = [];
|
||||
slotKeys.forEach((key, idx) => {
|
||||
if (!currentIssue[key]) emptySlots.push(idx + 1);
|
||||
});
|
||||
|
||||
if (emptySlots.length === 0) {
|
||||
alert('원본 사진 슬롯이 가득 찼습니다. 보충할 수 없습니다.');
|
||||
return;
|
||||
}
|
||||
|
||||
const files = Array.from(originalPhotoInput.files).slice(0, emptySlots.length);
|
||||
if (originalPhotoInput.files.length > emptySlots.length) {
|
||||
alert(`빈 슬롯은 ${emptySlots.length}개인데 ${originalPhotoInput.files.length}개를 선택하셨습니다. 처음 ${emptySlots.length}장만 업로드됩니다.`);
|
||||
}
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const slotNum = emptySlots[i];
|
||||
const base64 = await fileToBase64(files[i]);
|
||||
const fieldName = slotNum === 1 ? 'photo' : `photo${slotNum}`;
|
||||
updates[fieldName] = base64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// API 호출
|
||||
const response = await fetch(`/api/issues/${issueId}/management`, {
|
||||
method: 'PUT',
|
||||
|
||||
Reference in New Issue
Block a user