주요 변경사항: - 비활성화된 프로젝트 관리 기능 추가 * 프로젝트 관리 페이지에 접을 수 있는 비활성 프로젝트 섹션 추가 * 비활성화된 프로젝트 복구 기능 제공 * 업로드 시에는 활성 프로젝트만 표시되도록 API 호출 분리 - 헤더 비밀번호 변경 기능 완전 구현 * CommonHeader.js에 완전한 비밀번호 변경 모달 구현 * ESC 키 지원, 실시간 유효성 검사, 토스트 메시지 추가 * 중복 코드 제거 및 통일된 함수 호출 구조 - 수신함 수정 내용 표시 문제 해결 * description 우선 표시로 최신 수정 내용 반영 * 관리함에서 final_description/final_category 업데이트 로직 추가 - 현황판 날짜 그룹화 개선 * 업로드일 기준에서 관리함 진입일(reviewed_at) 기준으로 변경 * Invalid Date 오류 해결 - 프로젝트 관리 페이지 JavaScript 오류 수정 * 중복 변수 선언 및 함수 참조 오류 해결 * 페이지 초기화 로직 개선 기술적 개선: - API 호출 최적화 (active_only 매개변수 명시적 전달) - 프론트엔드 표시 우선순위 통일 (description || final_description) - 백엔드 final_* 필드 업데이트 로직 추가
593 lines
26 KiB
HTML
593 lines
26 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>프로젝트 관리 - 작업보고서 시스템</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<style>
|
|
:root {
|
|
--primary: #3b82f6;
|
|
--primary-dark: #2563eb;
|
|
--success: #10b981;
|
|
--warning: #f59e0b;
|
|
--danger: #ef4444;
|
|
--gray-50: #f9fafb;
|
|
--gray-100: #f3f4f6;
|
|
--gray-200: #e5e7eb;
|
|
--gray-300: #d1d5db;
|
|
}
|
|
|
|
body {
|
|
background-color: var(--gray-50);
|
|
}
|
|
|
|
.btn-primary {
|
|
background-color: var(--primary);
|
|
color: white;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.btn-primary:hover {
|
|
background-color: var(--primary-dark);
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
|
|
}
|
|
|
|
.input-field {
|
|
border: 1px solid var(--gray-300);
|
|
background: white;
|
|
transition: all 0.2s;
|
|
}
|
|
|
|
.input-field:focus {
|
|
border-color: var(--primary);
|
|
outline: none;
|
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
}
|
|
|
|
/* 부드러운 페이드인 애니메이션 */
|
|
.fade-in {
|
|
opacity: 0;
|
|
transform: translateY(20px);
|
|
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
|
|
}
|
|
|
|
.fade-in.visible {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* 헤더 전용 빠른 페이드인 */
|
|
.header-fade-in {
|
|
opacity: 0;
|
|
transform: translateY(-10px);
|
|
transition: opacity 0.4s ease-out, transform 0.4s ease-out;
|
|
}
|
|
|
|
.header-fade-in.visible {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* 본문 컨텐츠 지연 페이드인 */
|
|
.content-fade-in {
|
|
opacity: 0;
|
|
transform: translateY(30px);
|
|
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
|
transition-delay: 0.2s;
|
|
}
|
|
|
|
.content-fade-in.visible {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- 공통 헤더가 여기에 자동으로 삽입됩니다 -->
|
|
|
|
<!-- 메인 컨텐츠 -->
|
|
<main class="container mx-auto px-4 py-8 max-w-4xl content-fade-in" style="padding-top: 80px;">
|
|
<!-- 프로젝트 생성 섹션 -->
|
|
<div class="bg-white rounded-xl shadow-sm p-6 mb-8">
|
|
<h2 class="text-lg font-semibold text-gray-800 mb-4">
|
|
<i class="fas fa-plus text-green-500 mr-2"></i>새 프로젝트 생성
|
|
</h2>
|
|
|
|
<form id="projectForm" class="grid md:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">Job No.</label>
|
|
<input
|
|
type="text"
|
|
id="jobNo"
|
|
class="input-field w-full px-4 py-2 rounded-lg"
|
|
placeholder="예: JOB-2024-001"
|
|
required
|
|
maxlength="50"
|
|
>
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-2">프로젝트 이름</label>
|
|
<input
|
|
type="text"
|
|
id="projectName"
|
|
class="input-field w-full px-4 py-2 rounded-lg"
|
|
placeholder="프로젝트 이름을 입력하세요"
|
|
required
|
|
maxlength="200"
|
|
>
|
|
</div>
|
|
|
|
<div class="md:col-span-2">
|
|
<button type="submit" class="btn-primary px-6 py-2 rounded-lg font-medium">
|
|
<i class="fas fa-plus mr-2"></i>프로젝트 생성
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- 프로젝트 목록 섹션 -->
|
|
<div class="bg-white rounded-xl shadow-sm p-6">
|
|
<div class="flex justify-between items-center mb-4">
|
|
<h2 class="text-lg font-semibold text-gray-800">프로젝트 목록</h2>
|
|
<button onclick="loadProjects()" class="text-blue-600 hover:text-blue-800">
|
|
<i class="fas fa-refresh mr-1"></i>새로고침
|
|
</button>
|
|
</div>
|
|
|
|
<div id="projectsList" class="space-y-3">
|
|
<!-- 프로젝트 목록이 여기에 표시됩니다 -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 비활성화된 프로젝트 섹션 -->
|
|
<div class="bg-white rounded-xl shadow-sm p-6 mt-6">
|
|
<div class="flex justify-between items-center mb-4 cursor-pointer" onclick="toggleInactiveProjects()">
|
|
<div class="flex items-center space-x-2">
|
|
<i id="inactiveToggleIcon" class="fas fa-chevron-down transition-transform duration-200"></i>
|
|
<h2 class="text-lg font-semibold text-gray-600">비활성화된 프로젝트</h2>
|
|
<span id="inactiveProjectCount" class="bg-gray-100 text-gray-600 px-2 py-1 rounded-full text-sm font-medium">0</span>
|
|
</div>
|
|
<div class="text-sm text-gray-500">
|
|
<i class="fas fa-info-circle mr-1"></i>클릭하여 펼치기/접기
|
|
</div>
|
|
</div>
|
|
|
|
<div id="inactiveProjectsList" class="space-y-3">
|
|
<!-- 비활성화된 프로젝트 목록이 여기에 표시됩니다 -->
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<!-- API 스크립트 먼저 로드 (최강 캐시 무력화) -->
|
|
<script>
|
|
// 브라우저 캐시 완전 무력화
|
|
const timestamp = new Date().getTime();
|
|
const random1 = Math.random() * 1000000;
|
|
const random2 = Math.floor(Math.random() * 1000000);
|
|
const cacheBuster = `${timestamp}-${random1}-${random2}`;
|
|
|
|
const script = document.createElement('script');
|
|
script.src = `/static/js/api.js?force-reload=${cacheBuster}&no-cache=${timestamp}&bust=${random2}`;
|
|
script.onload = function() {
|
|
console.log('✅ API 스크립트 로드 완료');
|
|
console.log('🔍 API_BASE_URL:', typeof API_BASE_URL !== 'undefined' ? API_BASE_URL : 'undefined');
|
|
console.log('🌐 현재 hostname:', window.location.hostname);
|
|
console.log('🔗 현재 protocol:', window.location.protocol);
|
|
// API 로드 후 인증 체크 시작
|
|
setTimeout(checkAdminAccess, 100);
|
|
};
|
|
script.setAttribute('cache-control', 'no-cache, no-store, must-revalidate');
|
|
script.setAttribute('pragma', 'no-cache');
|
|
script.setAttribute('expires', '0');
|
|
document.head.appendChild(script);
|
|
|
|
console.log('🚀 캐시 버스터:', cacheBuster);
|
|
</script>
|
|
|
|
<!-- 메인 스크립트 -->
|
|
<script>
|
|
// 관리자 권한 확인 함수
|
|
async function checkAdminAccess() {
|
|
try {
|
|
const currentUser = await AuthAPI.getCurrentUser();
|
|
if (!currentUser || currentUser.role !== 'admin') {
|
|
alert('관리자만 접근할 수 있습니다.');
|
|
window.location.href = '/index.html';
|
|
return;
|
|
}
|
|
// 권한 확인 후 페이지 초기화
|
|
initializeProjectManagement();
|
|
} catch (error) {
|
|
console.error('권한 확인 실패:', error);
|
|
alert('로그인이 필요합니다.');
|
|
window.location.href = '/index.html';
|
|
}
|
|
}
|
|
|
|
// 프로젝트 관리 페이지 초기화 함수
|
|
async function initializeProjectManagement() {
|
|
try {
|
|
console.log('🚀 프로젝트 관리 페이지 초기화 시작');
|
|
|
|
// 헤더 애니메이션 시작
|
|
animateHeaderAppearance();
|
|
|
|
// 프로젝트 목록 로드
|
|
await loadProjects();
|
|
|
|
console.log('✅ 프로젝트 관리 페이지 초기화 완료');
|
|
} catch (error) {
|
|
console.error('❌ 프로젝트 관리 페이지 초기화 실패:', error);
|
|
alert('페이지 로드 중 오류가 발생했습니다.');
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<script src="/static/js/core/permissions.js?v=20251025"></script>
|
|
<script src="/static/js/components/common-header.js?v=20251025"></script>
|
|
<script src="/static/js/core/page-manager.js?v=20251025"></script>
|
|
<script>
|
|
// 전역 변수
|
|
let currentUser = null;
|
|
|
|
// 애니메이션 함수들
|
|
function animateHeaderAppearance() {
|
|
console.log('🎨 헤더 애니메이션 시작');
|
|
|
|
// 헤더 요소 찾기 (공통 헤더가 생성한 요소)
|
|
const headerElement = document.querySelector('header') || document.querySelector('[class*="header"]') || document.querySelector('nav');
|
|
|
|
if (headerElement) {
|
|
headerElement.classList.add('header-fade-in');
|
|
setTimeout(() => {
|
|
headerElement.classList.add('visible');
|
|
console.log('✨ 헤더 페이드인 완료');
|
|
|
|
// 헤더 애니메이션 완료 후 본문 애니메이션
|
|
setTimeout(() => {
|
|
animateContentAppearance();
|
|
}, 200);
|
|
}, 50);
|
|
} else {
|
|
// 헤더를 찾지 못했으면 바로 본문 애니메이션
|
|
console.log('⚠️ 헤더 요소를 찾지 못함 - 본문 애니메이션 시작');
|
|
animateContentAppearance();
|
|
}
|
|
}
|
|
|
|
// 본문 컨텐츠 애니메이션
|
|
function animateContentAppearance() {
|
|
console.log('🎨 본문 컨텐츠 애니메이션 시작');
|
|
|
|
// 모든 content-fade-in 요소들을 순차적으로 애니메이션
|
|
const contentElements = document.querySelectorAll('.content-fade-in');
|
|
|
|
contentElements.forEach((element, index) => {
|
|
setTimeout(() => {
|
|
element.classList.add('visible');
|
|
console.log(`✨ 컨텐츠 ${index + 1} 페이드인 완료`);
|
|
}, index * 100); // 100ms씩 지연
|
|
});
|
|
}
|
|
|
|
async function initAuth() {
|
|
console.log('인증 초기화 시작');
|
|
const token = localStorage.getItem('access_token');
|
|
console.log('토큰 존재:', !!token);
|
|
|
|
if (!token) {
|
|
console.log('토큰 없음 - 로그인 페이지로 이동');
|
|
alert('로그인이 필요합니다.');
|
|
window.location.href = 'index.html';
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
console.log('API로 사용자 정보 가져오는 중...');
|
|
const user = await AuthAPI.getCurrentUser();
|
|
console.log('사용자 정보:', user);
|
|
currentUser = user;
|
|
localStorage.setItem('currentUser', JSON.stringify(user));
|
|
return true;
|
|
} catch (error) {
|
|
console.error('인증 실패:', error);
|
|
localStorage.removeItem('access_token');
|
|
localStorage.removeItem('currentUser');
|
|
alert('로그인이 필요합니다.');
|
|
window.location.href = 'index.html';
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function checkAdminAccess() {
|
|
const authSuccess = await initAuth();
|
|
if (!authSuccess) return;
|
|
|
|
// 공통 헤더 초기화
|
|
await window.commonHeader.init(currentUser, 'projects_manage');
|
|
|
|
// 헤더 초기화 후 부드러운 애니메이션 시작
|
|
setTimeout(() => {
|
|
animateHeaderAppearance();
|
|
}, 100);
|
|
|
|
// 페이지 접근 권한 체크 (프로젝트 관리 페이지)
|
|
setTimeout(() => {
|
|
if (!canAccessPage('projects_manage')) {
|
|
alert('프로젝트 관리 페이지에 접근할 권한이 없습니다.');
|
|
window.location.href = 'index.html';
|
|
return;
|
|
}
|
|
}, 500);
|
|
|
|
// 사용자 정보는 공통 헤더에서 표시됨
|
|
|
|
// 프로젝트 로드
|
|
loadProjects();
|
|
}
|
|
|
|
let projects = [];
|
|
|
|
// 프로젝트 데이터 로드 (API 기반)
|
|
async function loadProjects() {
|
|
console.log('프로젝트 로드 시작 (API)');
|
|
|
|
try {
|
|
// API에서 모든 프로젝트 로드 (활성/비활성 모두)
|
|
const apiProjects = await ProjectsAPI.getAll(false);
|
|
|
|
// API 데이터를 그대로 사용 (필드명 통일)
|
|
projects = apiProjects;
|
|
|
|
console.log('API에서 프로젝트 로드:', projects.length, '개');
|
|
|
|
} catch (error) {
|
|
console.error('API 로드 실패:', error);
|
|
projects = [];
|
|
}
|
|
|
|
displayProjectList();
|
|
}
|
|
|
|
// 프로젝트 데이터 저장 (더 이상 사용하지 않음 - API 기반)
|
|
// function saveProjects() {
|
|
// localStorage.setItem('work-report-projects', JSON.stringify(projects));
|
|
// }
|
|
|
|
// 프로젝트 생성 폼 처리
|
|
document.getElementById('projectForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const jobNo = document.getElementById('jobNo').value.trim();
|
|
const projectName = document.getElementById('projectName').value.trim();
|
|
|
|
// 중복 Job No. 확인
|
|
if (projects.some(p => p.job_no === jobNo)) {
|
|
alert('이미 존재하는 Job No.입니다.');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// API를 통한 프로젝트 생성
|
|
const newProject = await ProjectsAPI.create({
|
|
job_no: jobNo,
|
|
project_name: projectName
|
|
});
|
|
|
|
// 성공 메시지
|
|
alert('프로젝트가 생성되었습니다.');
|
|
|
|
// 폼 초기화
|
|
document.getElementById('projectForm').reset();
|
|
|
|
// 목록 새로고침
|
|
await loadProjects();
|
|
displayProjectList();
|
|
|
|
} catch (error) {
|
|
console.error('프로젝트 생성 실패:', error);
|
|
alert('프로젝트 생성에 실패했습니다: ' + error.message);
|
|
}
|
|
});
|
|
|
|
// 프로젝트 목록 표시
|
|
function displayProjectList() {
|
|
const activeContainer = document.getElementById('projectsList');
|
|
const inactiveContainer = document.getElementById('inactiveProjectsList');
|
|
const inactiveCount = document.getElementById('inactiveProjectCount');
|
|
|
|
activeContainer.innerHTML = '';
|
|
inactiveContainer.innerHTML = '';
|
|
|
|
if (projects.length === 0) {
|
|
activeContainer.innerHTML = '<p class="text-gray-500 text-center py-8">등록된 프로젝트가 없습니다.</p>';
|
|
inactiveCount.textContent = '0';
|
|
return;
|
|
}
|
|
|
|
// 활성 프로젝트와 비활성 프로젝트 분리
|
|
const activeProjects = projects.filter(p => p.is_active);
|
|
const inactiveProjects = projects.filter(p => !p.is_active);
|
|
|
|
console.log('전체 프로젝트:', projects.length, '개');
|
|
console.log('활성 프로젝트:', activeProjects.length, '개');
|
|
console.log('비활성 프로젝트:', inactiveProjects.length, '개');
|
|
|
|
// 비활성 프로젝트 개수 업데이트
|
|
inactiveCount.textContent = inactiveProjects.length;
|
|
|
|
// 활성 프로젝트 표시
|
|
if (activeProjects.length > 0) {
|
|
activeProjects.forEach(project => {
|
|
const div = document.createElement('div');
|
|
div.className = 'border border-green-200 rounded-lg p-4 hover:shadow-md transition-shadow mb-3 bg-green-50';
|
|
div.innerHTML = `
|
|
<div class="flex justify-between items-start">
|
|
<div class="flex-1">
|
|
<div class="flex items-center gap-3 mb-2">
|
|
<h3 class="font-semibold text-gray-800">${project.job_no}</h3>
|
|
<span class="px-2 py-1 bg-green-100 text-green-800 text-xs rounded-full">활성</span>
|
|
</div>
|
|
<p class="text-gray-600 mb-2">${project.project_name}</p>
|
|
<div class="flex items-center gap-4 text-sm text-gray-500">
|
|
<span><i class="fas fa-user mr-1"></i>${project.created_by?.full_name || '관리자'}</span>
|
|
<span><i class="fas fa-calendar mr-1"></i>${new Date(project.created_at).toLocaleDateString()}</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<button onclick="editProject(${project.id})" class="text-blue-600 hover:text-blue-800 p-2" title="수정">
|
|
<i class="fas fa-edit"></i>
|
|
</button>
|
|
<button onclick="toggleProjectStatus(${project.id})" class="text-orange-600 hover:text-orange-800 p-2" title="비활성화">
|
|
<i class="fas fa-pause"></i>
|
|
</button>
|
|
<button onclick="deleteProject(${project.id})" class="text-red-600 hover:text-red-800 p-2" title="삭제">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
activeContainer.appendChild(div);
|
|
});
|
|
} else {
|
|
activeContainer.innerHTML = '<p class="text-gray-500 text-center py-8">활성 프로젝트가 없습니다.</p>';
|
|
}
|
|
|
|
// 비활성 프로젝트 표시
|
|
if (inactiveProjects.length > 0) {
|
|
inactiveProjects.forEach(project => {
|
|
const div = document.createElement('div');
|
|
div.className = 'border border-gray-200 rounded-lg p-4 hover:shadow-md transition-shadow mb-3 bg-gray-50';
|
|
div.innerHTML = `
|
|
<div class="flex justify-between items-start">
|
|
<div class="flex-1">
|
|
<div class="flex items-center gap-3 mb-2">
|
|
<h3 class="font-semibold text-gray-600">${project.job_no}</h3>
|
|
<span class="px-2 py-1 bg-gray-100 text-gray-600 text-xs rounded-full">비활성</span>
|
|
</div>
|
|
<p class="text-gray-500 mb-2">${project.project_name}</p>
|
|
<div class="flex items-center gap-4 text-sm text-gray-400">
|
|
<span><i class="fas fa-user mr-1"></i>${project.created_by?.full_name || '관리자'}</span>
|
|
<span><i class="fas fa-calendar mr-1"></i>${new Date(project.created_at).toLocaleDateString()}</span>
|
|
</div>
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<button onclick="toggleProjectStatus(${project.id})" class="text-green-600 hover:text-green-800 p-2" title="활성화">
|
|
<i class="fas fa-play"></i>
|
|
</button>
|
|
<button onclick="deleteProject(${project.id})" class="text-red-600 hover:text-red-800 p-2" title="완전 삭제">
|
|
<i class="fas fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
inactiveContainer.appendChild(div);
|
|
});
|
|
} else {
|
|
inactiveContainer.innerHTML = '<p class="text-gray-500 text-center py-8">비활성화된 프로젝트가 없습니다.</p>';
|
|
}
|
|
}
|
|
|
|
// 비활성 프로젝트 섹션 토글
|
|
function toggleInactiveProjects() {
|
|
const inactiveList = document.getElementById('inactiveProjectsList');
|
|
const toggleIcon = document.getElementById('inactiveToggleIcon');
|
|
|
|
if (inactiveList.style.display === 'none') {
|
|
// 펼치기
|
|
inactiveList.style.display = 'block';
|
|
toggleIcon.classList.remove('fa-chevron-right');
|
|
toggleIcon.classList.add('fa-chevron-down');
|
|
} else {
|
|
// 접기
|
|
inactiveList.style.display = 'none';
|
|
toggleIcon.classList.remove('fa-chevron-down');
|
|
toggleIcon.classList.add('fa-chevron-right');
|
|
}
|
|
}
|
|
|
|
// 프로젝트 편집
|
|
async function editProject(projectId) {
|
|
const project = projects.find(p => p.id === projectId);
|
|
if (!project) return;
|
|
|
|
const newName = prompt('프로젝트 이름을 수정하세요:', project.project_name);
|
|
if (newName && newName.trim() && newName.trim() !== project.project_name) {
|
|
try {
|
|
// API를 통한 프로젝트 업데이트
|
|
await ProjectsAPI.update(projectId, {
|
|
project_name: newName.trim()
|
|
});
|
|
|
|
// 목록 새로고침
|
|
await loadProjects();
|
|
displayProjectList();
|
|
alert('프로젝트가 수정되었습니다.');
|
|
|
|
} catch (error) {
|
|
console.error('프로젝트 수정 실패:', error);
|
|
alert('프로젝트 수정에 실패했습니다: ' + error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 프로젝트 활성/비활성 토글
|
|
async function toggleProjectStatus(projectId) {
|
|
const project = projects.find(p => p.id === projectId);
|
|
if (!project) return;
|
|
|
|
const action = project.is_active ? '비활성화' : '활성화';
|
|
if (confirm(`"${project.job_no}" 프로젝트를 ${action}하시겠습니까?`)) {
|
|
try {
|
|
// API를 통한 프로젝트 상태 업데이트
|
|
await ProjectsAPI.update(projectId, {
|
|
is_active: !project.is_active
|
|
});
|
|
|
|
// 목록 새로고침
|
|
await loadProjects();
|
|
displayProjectList();
|
|
alert(`프로젝트가 ${action}되었습니다.`);
|
|
|
|
} catch (error) {
|
|
console.error('프로젝트 상태 변경 실패:', error);
|
|
alert('프로젝트 상태 변경에 실패했습니다: ' + error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 프로젝트 삭제 (완전 삭제)
|
|
async function deleteProject(projectId) {
|
|
const project = projects.find(p => p.id === projectId);
|
|
if (!project) return;
|
|
|
|
const confirmMessage = project.is_active
|
|
? `"${project.job_no}" 프로젝트를 완전히 삭제하시겠습니까?\n\n※ 활성 프로젝트입니다. 먼저 비활성화를 권장합니다.`
|
|
: `"${project.job_no}" 프로젝트를 완전히 삭제하시겠습니까?\n\n※ 이 작업은 되돌릴 수 없습니다.`;
|
|
|
|
if (confirm(confirmMessage)) {
|
|
try {
|
|
// API를 통한 프로젝트 삭제
|
|
await ProjectsAPI.delete(projectId);
|
|
|
|
// 목록 새로고침
|
|
await loadProjects();
|
|
displayProjectList();
|
|
alert('프로젝트가 완전히 삭제되었습니다.');
|
|
|
|
} catch (error) {
|
|
console.error('프로젝트 삭제 실패:', error);
|
|
alert('프로젝트 삭제에 실패했습니다: ' + error.message);
|
|
}
|
|
}
|
|
}
|
|
|
|
// DOMContentLoaded 이벤트 제거 - API 스크립트 로드 후 checkAdminAccess() 호출됨
|
|
</script>
|
|
</body>
|
|
</html>
|