feat: 관리함 개선 - 데이터 필터링 및 탭 구조 개선

📊 Data Filtering Improvements:
- 관리함에서 수신함에서 처리된 항목만 표시 (in_progress, completed)
- 수신함의 pending_review, disposed 상태 제외
- 올바른 워크플로우 데이터만 관리함에서 처리

🎨 UI Simplification:
- 복잡한 필터 제거 (상태, 우선순위, 담당자, 검색)
- 프로젝트 필터만 유지하여 핵심 기능에 집중
- 더 깔끔하고 직관적인 인터페이스

📋 Status Tabs Implementation:
- 프로젝트 선택 아래에 진행 중/완료됨 탭 추가
- 탭 클릭으로 상태별 이슈 분리 표시
- 진행 중(파란색), 완료됨(초록색) 시각적 구분
- 부드러운 전환 애니메이션 적용

🔧 JavaScript Logic Updates:
- currentTab 변수로 현재 선택된 탭 상태 관리
- switchTab() 함수로 탭 전환 및 스타일 업데이트
- filterIssues() 함수에서 review_status 기반 필터링
- 불필요한 필터링 로직 제거로 성능 개선

🚀 User Experience:
- 프로젝트 선택 → 상태 탭 선택으로 단순한 워크플로우
- 진행 중과 완료됨 항목을 명확히 분리
- 관리함 본연의 목적에 맞는 기능 집중

Expected Result:
 수신함에서 처리된 항목만 관리함에 표시
 프로젝트별 진행 중/완료됨 탭으로 분리
 불필요한 필터 제거로 단순화된 UI
 직관적인 탭 기반 상태 관리
This commit is contained in:
Hyungi Ahn
2025-10-25 14:37:10 +09:00
parent f7bdbf522f
commit d450ff3cbc

View File

@@ -145,55 +145,29 @@
</div>
</div>
<!-- 필터 및 검색 -->
<!-- 프로젝트 필터 및 상태 탭 -->
<div class="bg-white rounded-xl shadow-sm p-6 mb-6">
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
<!-- 프로젝트 필터 -->
<div>
<div class="space-y-4">
<!-- 프로젝트 선택 -->
<div class="max-w-md">
<label class="block text-sm font-medium text-gray-700 mb-2">📁 프로젝트</label>
<select id="projectFilter" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500" onchange="filterIssues()">
<option value="">전체 프로젝트</option>
</select>
</div>
<!-- 상태 필터 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">📋 상태</label>
<select id="statusFilter" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500" onchange="filterIssues()">
<option value="">전체 상태</option>
<option value="new">새 부적합</option>
<option value="processing">처리 중</option>
<option value="pending">대기 중</option>
<option value="completed">완료</option>
</select>
</div>
<!-- 우선순위 필터 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">⚡ 우선순위</label>
<select id="priorityFilter" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500" onchange="filterIssues()">
<option value="">전체</option>
<option value="high">높음</option>
<option value="medium">보통</option>
<option value="low">낮음</option>
</select>
</div>
<!-- 담당자 필터 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">👤 담당자</label>
<select id="assigneeFilter" class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500" onchange="filterIssues()">
<option value="">전체 담당자</option>
<option value="unassigned">미배정</option>
</select>
</div>
<!-- 검색 -->
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">🔍 검색</label>
<input type="text" id="searchInput" placeholder="설명 또는 등록자 검색..."
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-green-500"
onkeyup="filterIssues()">
<!-- 상태 -->
<div class="flex space-x-1 bg-gray-100 p-1 rounded-lg max-w-md">
<button id="inProgressTab"
class="flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 bg-blue-500 text-white"
onclick="switchTab('in_progress')">
<i class="fas fa-cog mr-2"></i>진행 중
</button>
<button id="completedTab"
class="flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 text-gray-600 hover:text-gray-900"
onclick="switchTab('completed')">
<i class="fas fa-check-circle mr-2"></i>완료됨
</button>
</div>
</div>
</div>
@@ -283,6 +257,7 @@
let filteredIssues = [];
let selectedIssues = new Set();
let currentIssueId = null;
let currentTab = 'in_progress'; // 기본값: 진행 중
// API 로드 후 초기화 함수
async function initializeManagement() {
@@ -343,12 +318,7 @@
// 부적합 목록 로드 (관리자는 모든 부적합 조회)
async function loadIssues() {
try {
let endpoint = '/api/issues/';
// 관리자인 경우 전체 부적합 조회 API 사용
if (currentUser.role === 'admin') {
endpoint = '/api/issues/admin/all';
}
let endpoint = '/api/issues/admin/all';
const response = await fetch(endpoint, {
headers: {
@@ -358,7 +328,11 @@
});
if (response.ok) {
issues = await response.json();
const allIssues = await response.json();
// 관리함에서는 진행 중(in_progress)과 완료됨(completed) 상태만 표시
issues = allIssues.filter(issue =>
issue.review_status === 'in_progress' || issue.review_status === 'completed'
);
filterIssues();
updateStatistics();
} else {
@@ -370,25 +344,35 @@
}
}
// 탭 전환 함수
function switchTab(tab) {
currentTab = tab;
// 탭 버튼 스타일 업데이트
const inProgressTab = document.getElementById('inProgressTab');
const completedTab = document.getElementById('completedTab');
if (tab === 'in_progress') {
inProgressTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 bg-blue-500 text-white';
completedTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 text-gray-600 hover:text-gray-900';
} else {
inProgressTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 text-gray-600 hover:text-gray-900';
completedTab.className = 'flex-1 px-4 py-2 text-sm font-medium rounded-md transition-colors duration-200 bg-green-500 text-white';
}
filterIssues();
}
// 필터링 및 표시 함수들
function filterIssues() {
const projectFilter = document.getElementById('projectFilter').value;
const statusFilter = document.getElementById('statusFilter').value;
const priorityFilter = document.getElementById('priorityFilter').value;
const assigneeFilter = document.getElementById('assigneeFilter').value;
const searchInput = document.getElementById('searchInput').value.toLowerCase();
filteredIssues = issues.filter(issue => {
if (projectFilter && issue.project_id != projectFilter) return false;
if (statusFilter && issue.status !== statusFilter) return false;
if (priorityFilter && issue.priority !== priorityFilter) return false;
if (assigneeFilter === 'unassigned' && issue.assignee_id) return false;
if (assigneeFilter && assigneeFilter !== 'unassigned' && issue.assignee_id != assigneeFilter) return false;
// 현재 탭에 따른 상태 필터링
if (issue.review_status !== currentTab) return false;
if (searchInput) {
const searchText = `${issue.description} ${issue.reporter?.username || ''}`.toLowerCase();
if (!searchText.includes(searchInput)) return false;
}
// 프로젝트 필터링
if (projectFilter && issue.project_id != projectFilter) return false;
return true;
});