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:
@@ -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;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user