feat: 부적합 조회 페이지를 새로운 워크플로우 시스템에 맞게 업데이트

🔄 Workflow Status System Integration:
- 기존 '검토 상태' → '워크플로우 상태'로 변경
- 4단계 워크플로우 지원: 수신함, 관리함(진행중), 관리함(완료), 폐기함
- 기존 데이터와의 호환성 유지 (폴백 로직)

📋 Filter Updates:
- issue-view.html: 워크플로우 상태 필터 추가
- index.html: 목록 섹션 워크플로우 상태 필터 추가
- 4개 상태별 필터링: pending_review, in_progress, completed, disposed

🎨 Visual Enhancements:
- 워크플로우 상태별 배지 시스템 구현
- 아이콘 및 색상 코딩: 수신함(주황), 진행중(파랑), 완료(녹색), 폐기(회색)
- 상태별 그룹화 표시 개선

🔧 Technical Implementation:
- getWorkflowStatusBadge() 함수 추가
- review_status 필드 기반 필터링
- 기존 isReviewCompleted() 함수와 호환성 유지
- 상태별 분류 로직 개선

📊 Status Configuration:
- pending_review: 수신함 (검토 대기) - fas fa-inbox
- in_progress: 관리함 (진행 중) - fas fa-cog
- completed: 관리함 (완료됨) - fas fa-check-circle
- disposed: 폐기함 (폐기됨) - fas fa-trash

🔄 Backward Compatibility:
- 기존 데이터 자동 매핑
- 점진적 마이그레이션 지원
- 오류 없는 상태 전환

Expected Result:
 부적합 조회에서 4단계 워크플로우 상태 확인 가능
 수신함/관리함/폐기함별 필터링 지원
 시각적으로 구분되는 상태 배지 표시
 기존 데이터와 새 시스템 모두 호환
This commit is contained in:
Hyungi Ahn
2025-10-25 13:36:56 +09:00
parent 236e1ca493
commit 11692b4a91
2 changed files with 104 additions and 55 deletions

View File

@@ -403,15 +403,17 @@
</select>
</div>
<!-- 검토 상태 필터 -->
<!-- 워크플로우 상태 필터 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">검토 상태</label>
<label class="block text-sm font-medium text-gray-700 mb-1">워크플로우 상태</label>
<select id="reviewStatusFilter" class="w-full px-3 py-2 border border-gray-300 rounded text-sm" onchange="displayIssueList()">
<option value="">전체</option>
<option value="pending">검토 필요</option>
<option value="completed">검토 완료</option>
<option value="pending_review">수신함 (검토 대기)</option>
<option value="in_progress">관리함 (진행 중)</option>
<option value="completed">관리함 (완료됨)</option>
<option value="disposed">폐기함 (폐기됨)</option>
</select>
</div>
</div>
<!-- 날짜 필터 -->
<div>
@@ -1403,11 +1405,20 @@
});
}
// 검토 상태 필터 적용
// 워크플로우 상태 필터 적용
if (reviewStatusFilter) {
filteredIssues = filteredIssues.filter(issue => {
const isCompleted = isReviewCompleted(issue);
return reviewStatusFilter === 'completed' ? isCompleted : !isCompleted;
// 새로운 워크플로우 시스템 사용
if (issue.review_status) {
return issue.review_status === reviewStatusFilter;
}
// 기존 데이터 호환성을 위한 폴백
else {
const isCompleted = isReviewCompleted(issue);
if (reviewStatusFilter === 'pending_review') return !isCompleted;
if (reviewStatusFilter === 'completed') return isCompleted;
return false;
}
});
}
@@ -1421,9 +1432,20 @@
return;
}
// 검토 상태별로 분류 및 정렬
const pendingIssues = filteredIssues.filter(issue => !isReviewCompleted(issue));
const completedIssues = filteredIssues.filter(issue => isReviewCompleted(issue));
// 워크플로우 상태별로 분류 및 정렬
const groupedIssues = {
pending_review: filteredIssues.filter(issue =>
issue.review_status === 'pending_review' || (!issue.review_status && !isReviewCompleted(issue))
),
in_progress: filteredIssues.filter(issue => issue.review_status === 'in_progress'),
completed: filteredIssues.filter(issue =>
issue.review_status === 'completed' || (!issue.review_status && isReviewCompleted(issue))
),
disposed: filteredIssues.filter(issue => issue.review_status === 'disposed')
};
const pendingIssues = groupedIssues.pending_review;
const completedIssues = [...groupedIssues.in_progress, ...groupedIssues.completed, ...groupedIssues.disposed];
// 검토 필요 항목을 먼저 표시
if (pendingIssues.length > 0) {

View File

@@ -135,13 +135,15 @@
</select>
</div>
<!-- 검토 상태 필터 -->
<!-- 워크플로우 상태 필터 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">📋 검토 상태</label>
<label class="block text-sm font-medium text-gray-700 mb-2">📋 워크플로우 상태</label>
<select id="reviewStatusFilter" class="w-full px-3 py-2 border border-gray-300 rounded-lg text-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500" onchange="filterIssues()">
<option value="">전체</option>
<option value="pending">검토 필요</option>
<option value="completed">검토 완료</option>
<option value="pending_review">수신함 (검토 대기)</option>
<option value="in_progress">관리함 (진행 중)</option>
<option value="completed">관리함 (완료됨)</option>
<option value="disposed">폐기함 (폐기됨)</option>
</select>
</div>
</div>
@@ -513,11 +515,20 @@
});
}
// 검토 상태 필터 적용
// 워크플로우 상태 필터 적용
if (reviewStatusFilter) {
filteredIssues = filteredIssues.filter(issue => {
const isCompleted = isReviewCompleted(issue);
return reviewStatusFilter === 'completed' ? isCompleted : !isCompleted;
// 새로운 워크플로우 시스템 사용
if (issue.review_status) {
return issue.review_status === reviewStatusFilter;
}
// 기존 데이터 호환성을 위한 폴백
else {
const isCompleted = isReviewCompleted(issue);
if (reviewStatusFilter === 'pending_review') return !isCompleted;
if (reviewStatusFilter === 'completed') return isCompleted;
return false;
}
});
}
@@ -668,45 +679,64 @@
return;
}
// 검토 상태별로 분류 및 정렬
const pendingIssues = filteredIssues.filter(issue => !isReviewCompleted(issue));
const completedIssues = filteredIssues.filter(issue => isReviewCompleted(issue));
// 워크플로우 상태별로 분류 및 정렬
const groupedIssues = {
pending_review: filteredIssues.filter(issue =>
issue.review_status === 'pending_review' || (!issue.review_status && !isReviewCompleted(issue))
),
in_progress: filteredIssues.filter(issue => issue.review_status === 'in_progress'),
completed: filteredIssues.filter(issue =>
issue.review_status === 'completed' || (!issue.review_status && isReviewCompleted(issue))
),
disposed: filteredIssues.filter(issue => issue.review_status === 'disposed')
};
container.innerHTML = '';
// 검토 필요 항목을 먼저 표시
if (pendingIssues.length > 0) {
const pendingHeader = document.createElement('div');
pendingHeader.className = 'mb-4';
pendingHeader.innerHTML = `
<h3 class="text-md font-semibold text-orange-700 flex items-center">
<i class="fas fa-exclamation-triangle mr-2"></i>검토 필요 (${pendingIssues.length}건)
</h3>
`;
container.appendChild(pendingHeader);
pendingIssues.forEach(issue => {
container.appendChild(createIssueCard(issue, false));
});
}
// 각 상태별로 표시
const statusConfig = [
{ key: 'pending_review', title: '수신함 (검토 대기)', icon: 'fas fa-inbox', color: 'text-orange-700' },
{ key: 'in_progress', title: '관리함 (진행 중)', icon: 'fas fa-cog', color: 'text-blue-700' },
{ key: 'completed', title: '관리함 (완료됨)', icon: 'fas fa-check-circle', color: 'text-green-700' },
{ key: 'disposed', title: '폐기함 (폐기됨)', icon: 'fas fa-trash', color: 'text-gray-700' }
];
// 검토 완료 항목을 아래에 표시
if (completedIssues.length > 0) {
const completedHeader = document.createElement('div');
completedHeader.className = 'mb-4 mt-8';
completedHeader.innerHTML = `
<h3 class="text-md font-semibold text-green-700 flex items-center">
<i class="fas fa-check-circle mr-2"></i>검토 완료 (${completedIssues.length}건)
</h3>
`;
container.appendChild(completedHeader);
completedIssues.forEach(issue => {
container.appendChild(createIssueCard(issue, true));
});
}
statusConfig.forEach((config, index) => {
const issues = groupedIssues[config.key];
if (issues.length > 0) {
const header = document.createElement('div');
header.className = index > 0 ? 'mb-4 mt-8' : 'mb-4';
header.innerHTML = `
<h3 class="text-md font-semibold ${config.color} flex items-center">
<i class="${config.icon} mr-2"></i>${config.title} (${issues.length}건)
</h3>
`;
container.appendChild(header);
issues.forEach(issue => {
container.appendChild(createIssueCard(issue, config.key === 'completed'));
});
}
});
}
// 워크플로우 상태 표시 함수
function getWorkflowStatusBadge(issue) {
const status = issue.review_status || (isReviewCompleted(issue) ? 'completed' : 'pending_review');
const statusConfig = {
'pending_review': { text: '검토 대기', class: 'bg-orange-100 text-orange-700', icon: 'fas fa-inbox' },
'in_progress': { text: '진행 중', class: 'bg-blue-100 text-blue-700', icon: 'fas fa-cog' },
'completed': { text: '완료됨', class: 'bg-green-100 text-green-700', icon: 'fas fa-check-circle' },
'disposed': { text: '폐기됨', class: 'bg-gray-100 text-gray-700', icon: 'fas fa-trash' }
};
const config = statusConfig[status] || statusConfig['pending_review'];
return `<span class="px-2 py-1 rounded-full text-xs font-medium ${config.class}">
<i class="${config.icon} mr-1"></i>${config.text}
</span>`;
}
// 부적합 사항 카드 생성 함수 (조회용)
function createIssueCard(issue, isCompleted) {
const categoryNames = {
@@ -740,10 +770,7 @@
<!-- 프로젝트 정보 및 상태 (오른쪽 상단) -->
<div class="flex justify-between items-start p-2 pb-0">
<div class="flex items-center gap-2">
${isCompleted ?
'<div class="px-2 py-1 bg-green-100 text-green-800 rounded-full text-xs font-medium"><i class="fas fa-check-circle mr-1"></i>검토완료</div>' :
'<div class="px-2 py-1 bg-orange-100 text-orange-800 rounded-full text-xs font-medium"><i class="fas fa-exclamation-triangle mr-1"></i>검토필요</div>'
}
${getWorkflowStatusBadge(issue)}
</div>
<div class="px-2 py-1 bg-blue-100 text-blue-800 rounded-full text-xs font-medium">
<i class="fas fa-folder-open mr-1"></i>${projectInfo}