feat: 프로젝트 관리 및 비밀번호 변경 기능 개선

주요 변경사항:
- 비활성화된 프로젝트 관리 기능 추가
  * 프로젝트 관리 페이지에 접을 수 있는 비활성 프로젝트 섹션 추가
  * 비활성화된 프로젝트 복구 기능 제공
  * 업로드 시에는 활성 프로젝트만 표시되도록 API 호출 분리

- 헤더 비밀번호 변경 기능 완전 구현
  * CommonHeader.js에 완전한 비밀번호 변경 모달 구현
  * ESC 키 지원, 실시간 유효성 검사, 토스트 메시지 추가
  * 중복 코드 제거 및 통일된 함수 호출 구조

- 수신함 수정 내용 표시 문제 해결
  * description 우선 표시로 최신 수정 내용 반영
  * 관리함에서 final_description/final_category 업데이트 로직 추가

- 현황판 날짜 그룹화 개선
  * 업로드일 기준에서 관리함 진입일(reviewed_at) 기준으로 변경
  * Invalid Date 오류 해결

- 프로젝트 관리 페이지 JavaScript 오류 수정
  * 중복 변수 선언 및 함수 참조 오류 해결
  * 페이지 초기화 로직 개선

기술적 개선:
- API 호출 최적화 (active_only 매개변수 명시적 전달)
- 프론트엔드 표시 우선순위 통일 (description || final_description)
- 백엔드 final_* 필드 업데이트 로직 추가
This commit is contained in:
hyungi
2025-10-26 15:28:23 +09:00
parent fd0579805c
commit c16fc53f3b
25 changed files with 295 additions and 169 deletions

View File

@@ -812,7 +812,7 @@
</div>
<!-- 제목 -->
<h3 class="text-lg font-semibold text-gray-900 mb-3 cursor-pointer hover:text-blue-600 transition-colors" onclick="viewIssueDetail(${issue.id})">${issue.description}</h3>
<h3 class="text-lg font-semibold text-gray-900 mb-3 cursor-pointer hover:text-blue-600 transition-colors" onclick="viewIssueDetail(${issue.id})">${issue.final_description || issue.description}</h3>
<!-- 상세 정보 그리드 -->
<div class="grid grid-cols-2 md:grid-cols-4 gap-3 mb-4 text-sm">
@@ -822,7 +822,7 @@
</div>
<div class="flex items-center text-gray-600">
<i class="fas fa-tag mr-2 text-green-500"></i>
<span>${getCategoryText(issue.category)}</span>
<span>${getCategoryText(issue.category || issue.final_category)}</span>
</div>
<div class="flex items-center text-gray-600">
<i class="fas fa-camera mr-2 text-purple-500"></i>
@@ -1075,10 +1075,10 @@
<div class="flex items-start justify-between">
<div class="flex-1">
<div class="text-sm font-medium text-gray-900 mb-1">
${issue.description}
${issue.description || issue.final_description}
</div>
<div class="flex items-center gap-2 text-xs text-gray-500">
<span class="px-2 py-1 bg-gray-100 rounded">${getCategoryText(issue.category)}</span>
<span class="px-2 py-1 bg-gray-100 rounded">${getCategoryText(issue.category || issue.final_category)}</span>
<span>신고자: ${issue.reporter_name}</span>
${issue.duplicate_count > 0 ? `<span class="text-orange-600">중복 ${issue.duplicate_count}건</span>` : ''}
</div>
@@ -1176,8 +1176,8 @@
originalInfo.innerHTML = `
<div class="space-y-2">
<div><strong>프로젝트:</strong> ${project ? project.project_name : '미지정'}</div>
<div><strong>카테고리:</strong> ${getCategoryText(issue.category)}</div>
<div><strong>설명:</strong> ${issue.description}</div>
<div><strong>카테고리:</strong> ${getCategoryText(issue.category || issue.final_category)}</div>
<div><strong>설명:</strong> ${issue.description || issue.final_description}</div>
<div><strong>등록자:</strong> ${issue.reporter?.username || '알 수 없음'}</div>
<div><strong>등록일:</strong> ${new Date(issue.report_date).toLocaleDateString('ko-KR')}</div>
</div>
@@ -1196,12 +1196,13 @@
reviewProjectSelect.appendChild(option);
});
// 현재 값들로 폼 초기화
document.getElementById('reviewCategory').value = issue.category;
// 기존 description을 title과 description으로 분리 (첫 번째 줄을 title로 사용)
const lines = issue.description.split('\n');
// 현재 값들로 폼 초기화 (최신 내용 우선 사용)
document.getElementById('reviewCategory').value = issue.category || issue.final_category;
// 최신 description을 title과 description으로 분리 (첫 번째 줄을 title로 사용)
const currentDescription = issue.description || issue.final_description;
const lines = currentDescription.split('\n');
document.getElementById('reviewTitle').value = lines[0] || '';
document.getElementById('reviewDescription').value = lines.slice(1).join('\n') || issue.description;
document.getElementById('reviewDescription').value = lines.slice(1).join('\n') || currentDescription;
document.getElementById('reviewModal').classList.remove('hidden');
}