feat: 현황판을 관리함 스타일로 완전 변경 (날짜 그룹화 + 편집 가능)
🔄 Complete Layout Change: - ❌ 단순 카드 그리드 → ✅ 관리함 스타일 날짜별 그룹화 - 날짜별 접기/펼치기 기능 추가 - 업로드일 기준으로 그룹화 및 최신순 정렬 📋 Card Layout (Management Style): - 헤더: No., 긴급 표시 + 저장/완료처리 버튼 - 업로드 사진: 맨 위로 이동 (2개 슬롯, 없으면 '사진 없음') - 부적합 내용: 읽기 전용 텍스트 - 원인 분류: 노란색 배지로 표시 - 관리 정보: 편집 가능한 입력 필드들 🎯 Interactive Features: - 해결방안: textarea (편집 가능) - 담당부서: select dropdown (편집 가능) - 담당자: text input (편집 가능) - 조치 예상일: date input (편집 가능) - 원인부서: 읽기 전용 📅 Date Grouping: - 업로드일(report_date) 기준 그룹화 - 날짜 헤더: 클릭으로 접기/펼치기 - 각 그룹별 건수 표시 - '업로드일' 배지로 기준 명시 🎨 Visual Improvements: - 이모지 아이콘으로 필드 구분 (💡🏢👤📅) - 진행 중 상태 애니메이션 유지 - 부드러운 hover 효과 - 일관된 색상 체계 🔧 Functionality: - toggleDateGroup() 함수로 그룹 접기/펼치기 - 사진 모달 확대 기능 유지 - 긴급 표시 (3일 이내 마감) - 저장/완료처리 버튼 (UI만, 기능은 추후) Expected Result: ✅ 관리함과 완전히 동일한 UI/UX ✅ 날짜별 체계적 정리 ✅ 편집 가능한 관리 인터페이스 ✅ 직관적인 정보 표시
This commit is contained in:
@@ -68,6 +68,24 @@
|
||||
.animate-pulse {
|
||||
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
||||
}
|
||||
|
||||
/* 날짜 그룹 스타일 */
|
||||
.date-group {
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
.date-header {
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.date-header:hover {
|
||||
background-color: #f3f4f6 !important;
|
||||
}
|
||||
|
||||
.collapse-content {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background: linear-gradient(90deg, #10b981 0%, #059669 100%);
|
||||
@@ -381,7 +399,7 @@
|
||||
document.getElementById('activeProjects').textContent = activeProjectIds.size;
|
||||
}
|
||||
|
||||
// 이슈 카드 업데이트 (관리함 진행 중 카드 스타일)
|
||||
// 이슈 카드 업데이트 (관리함 스타일 - 날짜별 그룹화)
|
||||
function updateProjectCards() {
|
||||
const container = document.getElementById('projectDashboard');
|
||||
const emptyState = document.getElementById('emptyState');
|
||||
@@ -394,14 +412,47 @@
|
||||
|
||||
emptyState.classList.add('hidden');
|
||||
|
||||
// 카드 그리드 생성
|
||||
const cardsHTML = `
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
${filteredIssues.map(issue => createIssueCard(issue)).join('')}
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.innerHTML = cardsHTML;
|
||||
// 날짜별로 그룹화
|
||||
const groupedByDate = {};
|
||||
filteredIssues.forEach(issue => {
|
||||
const dateKey = new Date(issue.report_date).toLocaleDateString('ko-KR');
|
||||
if (!groupedByDate[dateKey]) {
|
||||
groupedByDate[dateKey] = [];
|
||||
}
|
||||
groupedByDate[dateKey].push(issue);
|
||||
});
|
||||
|
||||
// 날짜별 그룹 생성
|
||||
const dateGroups = Object.keys(groupedByDate)
|
||||
.sort((a, b) => new Date(b) - new Date(a)) // 최신순
|
||||
.map(dateKey => {
|
||||
const issues = groupedByDate[dateKey];
|
||||
const formattedDate = new Date(dateKey).toLocaleDateString('ko-KR', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit'
|
||||
}).replace(/\./g, '. ').trim();
|
||||
|
||||
return `
|
||||
<div class="date-group mb-6">
|
||||
<div class="date-header flex items-center justify-between p-4 bg-gray-50 rounded-lg cursor-pointer hover:bg-gray-100 transition-colors" onclick="toggleDateGroup('${dateKey}')">
|
||||
<div class="flex items-center space-x-3">
|
||||
<i class="fas fa-chevron-down transition-transform duration-200" id="chevron-${dateKey}"></i>
|
||||
<span class="font-semibold text-gray-800">${formattedDate}</span>
|
||||
<span class="text-sm text-gray-500">(${issues.length}건)</span>
|
||||
<span class="bg-blue-100 text-blue-800 text-xs px-2 py-1 rounded">업로드일</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse-content mt-4" id="content-${dateKey}">
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
${issues.map(issue => createIssueCard(issue)).join('')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
container.innerHTML = dateGroups;
|
||||
}
|
||||
|
||||
// 이슈 카드 생성 (관리함 진행 중 스타일, 읽기 전용)
|
||||
@@ -456,83 +507,111 @@
|
||||
};
|
||||
|
||||
return `
|
||||
<div class="issue-card bg-white rounded-lg border border-gray-200 p-6 hover:shadow-lg transition-all duration-200">
|
||||
<div class="issue-card bg-white rounded-lg border border-gray-200 p-6 hover:shadow-md transition-all duration-200">
|
||||
<!-- 헤더 -->
|
||||
<div class="flex justify-between items-start mb-4">
|
||||
<div class="flex items-center space-x-2">
|
||||
<span class="text-lg font-bold text-blue-600">No.${issue.project_sequence_no || '-'}</span>
|
||||
${isUrgent() ? '<span class="bg-red-100 text-red-800 text-xs font-medium px-2 py-1 rounded">긴급</span>' : ''}
|
||||
</div>
|
||||
<span class="text-sm text-gray-500">${formatKSTDate(issue.report_date)}</span>
|
||||
<div class="flex items-center space-x-2">
|
||||
<button class="bg-blue-500 text-white px-3 py-1 rounded text-sm hover:bg-blue-600 transition-colors">
|
||||
<i class="fas fa-edit mr-1"></i>저장
|
||||
</button>
|
||||
<button class="bg-green-500 text-white px-3 py-1 rounded text-sm hover:bg-green-600 transition-colors">
|
||||
<i class="fas fa-check mr-1"></i>완료처리
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 기본 정보 -->
|
||||
<div class="space-y-3 mb-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">프로젝트</label>
|
||||
<div class="text-sm text-gray-900 bg-gray-50 px-3 py-2 rounded">${projectName}</div>
|
||||
<!-- 업로드 사진 (맨 위로) -->
|
||||
${issue.photo_path || issue.photo_path2 ? `
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">업로드 사진</label>
|
||||
<div class="flex space-x-2">
|
||||
${issue.photo_path ? `
|
||||
<div class="w-20 h-20 bg-gray-100 rounded border flex items-center justify-center cursor-pointer hover:bg-gray-200 transition-colors" onclick="openPhotoModal('${issue.photo_path}')">
|
||||
<i class="fas fa-image text-gray-400"></i>
|
||||
</div>
|
||||
` : `
|
||||
<div class="w-20 h-20 bg-gray-100 rounded border flex items-center justify-center">
|
||||
<span class="text-xs text-gray-400">사진 없음</span>
|
||||
</div>
|
||||
`}
|
||||
${issue.photo_path2 ? `
|
||||
<div class="w-20 h-20 bg-gray-100 rounded border flex items-center justify-center cursor-pointer hover:bg-gray-200 transition-colors" onclick="openPhotoModal('${issue.photo_path2}')">
|
||||
<i class="fas fa-image text-gray-400"></i>
|
||||
</div>
|
||||
` : `
|
||||
<div class="w-20 h-20 bg-gray-100 rounded border flex items-center justify-center">
|
||||
<span class="text-xs text-gray-400">사진 없음</span>
|
||||
</div>
|
||||
`}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">부적합 내용</label>
|
||||
<div class="text-sm text-gray-900 bg-gray-50 px-3 py-2 rounded min-h-[60px]">${issue.final_description || issue.description || '-'}</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">원인 분류</label>
|
||||
<div class="text-sm text-gray-900 bg-gray-50 px-3 py-2 rounded">${getCategoryText(issue.final_category || issue.category)}</div>
|
||||
` : `
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">업로드 사진</label>
|
||||
<div class="flex space-x-2">
|
||||
<div class="w-20 h-20 bg-gray-100 rounded border flex items-center justify-center">
|
||||
<span class="text-xs text-gray-400">사진 없음</span>
|
||||
</div>
|
||||
<div class="w-20 h-20 bg-gray-100 rounded border flex items-center justify-center">
|
||||
<span class="text-xs text-gray-400">사진 없음</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`}
|
||||
|
||||
<!-- 부적합 내용 -->
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">부적합 내용</label>
|
||||
<div class="text-sm text-gray-900">${issue.final_description || issue.description || '중복작업 신고용'}</div>
|
||||
</div>
|
||||
|
||||
<!-- 원인 분류 -->
|
||||
<div class="mb-4">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">원인 분류</label>
|
||||
<span class="inline-block bg-yellow-100 text-yellow-800 px-2 py-1 rounded text-sm">${getCategoryText(issue.final_category || issue.category)}</span>
|
||||
</div>
|
||||
|
||||
<!-- 관리 정보 -->
|
||||
<div class="space-y-3 border-t pt-4">
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">해결방안</label>
|
||||
<div class="text-sm text-gray-900 bg-gray-50 px-3 py-2 rounded min-h-[40px]">${issue.solution || '-'}</div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">💡 해결방안</label>
|
||||
<textarea class="w-full text-sm border border-gray-300 rounded px-3 py-2 resize-none" rows="2" placeholder="해결 방안을 입력하세요...">${issue.solution || ''}</textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">담당부서</label>
|
||||
<div class="text-sm text-gray-900 bg-gray-50 px-3 py-2 rounded">${getDepartmentText(issue.responsible_department)}</div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">🏢 담당부서</label>
|
||||
<select class="w-full text-sm border border-gray-300 rounded px-3 py-2">
|
||||
<option value="">선택하세요</option>
|
||||
<option value="production" ${issue.responsible_department === 'production' ? 'selected' : ''}>생산</option>
|
||||
<option value="quality" ${issue.responsible_department === 'quality' ? 'selected' : ''}>품질</option>
|
||||
<option value="purchasing" ${issue.responsible_department === 'purchasing' ? 'selected' : ''}>구매</option>
|
||||
<option value="design" ${issue.responsible_department === 'design' ? 'selected' : ''}>설계</option>
|
||||
<option value="sales" ${issue.responsible_department === 'sales' ? 'selected' : ''}>영업</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">담당자</label>
|
||||
<div class="text-sm text-gray-900 bg-gray-50 px-3 py-2 rounded">${issue.responsible_person || '-'}</div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">👤 담당자</label>
|
||||
<input type="text" class="w-full text-sm border border-gray-300 rounded px-3 py-2" placeholder="담당자 이름" value="${issue.responsible_person || ''}">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">조치 예상일</label>
|
||||
<div class="text-sm text-gray-900 bg-gray-50 px-3 py-2 rounded ${isUrgent() ? 'text-red-600 font-medium' : ''}">${formatKSTDate(issue.expected_completion_date)}</div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">📅 조치 예상일</label>
|
||||
<input type="date" class="w-full text-sm border border-gray-300 rounded px-3 py-2" value="${issue.expected_completion_date ? issue.expected_completion_date.split('T')[0] : '2025-10-26'}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">원인부서</label>
|
||||
<div class="text-sm text-gray-900 bg-gray-50 px-3 py-2 rounded">${getDepartmentText(issue.cause_department)}</div>
|
||||
<div class="text-sm text-gray-900">${getDepartmentText(issue.cause_department)}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 업로드 사진 -->
|
||||
${issue.photo_path || issue.photo_path2 ? `
|
||||
<div class="border-t pt-4 mt-4">
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">업로드 사진</label>
|
||||
<div class="flex space-x-2">
|
||||
${issue.photo_path ? `
|
||||
<div class="w-16 h-16 bg-gray-100 rounded border flex items-center justify-center cursor-pointer hover:bg-gray-200 transition-colors" onclick="openPhotoModal('${issue.photo_path}')">
|
||||
<i class="fas fa-image text-gray-400"></i>
|
||||
</div>
|
||||
` : ''}
|
||||
${issue.photo_path2 ? `
|
||||
<div class="w-16 h-16 bg-gray-100 rounded border flex items-center justify-center cursor-pointer hover:bg-gray-200 transition-colors" onclick="openPhotoModal('${issue.photo_path2}')">
|
||||
<i class="fas fa-image text-gray-400"></i>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<!-- 진행 중 표시 -->
|
||||
<div class="border-t pt-4 mt-4 flex items-center justify-between">
|
||||
<div class="flex items-center space-x-2">
|
||||
@@ -584,6 +663,22 @@
|
||||
}
|
||||
});
|
||||
|
||||
// 날짜 그룹 토글 기능
|
||||
function toggleDateGroup(dateKey) {
|
||||
const content = document.getElementById(`content-${dateKey}`);
|
||||
const chevron = document.getElementById(`chevron-${dateKey}`);
|
||||
|
||||
if (content.style.display === 'none') {
|
||||
content.style.display = 'block';
|
||||
chevron.classList.remove('fa-chevron-right');
|
||||
chevron.classList.add('fa-chevron-down');
|
||||
} else {
|
||||
content.style.display = 'none';
|
||||
chevron.classList.remove('fa-chevron-down');
|
||||
chevron.classList.add('fa-chevron-right');
|
||||
}
|
||||
}
|
||||
|
||||
// 필터 및 정렬 함수들
|
||||
function filterByProject() {
|
||||
const projectId = document.getElementById('projectFilter').value;
|
||||
|
||||
Reference in New Issue
Block a user