feat: 목록 관리 및 보고서 페이지 개선
- 목록 관리 페이지에 고급 필터링 시스템 추가 - 프로젝트별, 검토상태별, 날짜별 필터링 - 검토 완료/필요 항목 시각적 구분 및 정렬 - 해결 시간 입력 + 확인 버튼으로 검토 완료 처리 - 부적합 조회 페이지에 동일한 필터링 기능 적용 - 검토 상태에 따른 카드 스타일링 (음영 처리) - JavaScript 템플릿 리터럴 오류 수정 - 보고서 페이지 프로젝트별 분석 기능 추가 - 프로젝트 선택 드롭다운 추가 - 총 작업 공수를 프로젝트별 일일공수 데이터로 계산 - 부적합 처리 시간, 카테고리 분석, 상세 목록 모두 프로젝트별 필터링 - localStorage 키 이름 통일 (daily-work-data)
This commit is contained in:
@@ -45,41 +45,72 @@
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: #6b7280;
|
||||
padding: 0.5rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.2s;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
background-color: #f3f4f6;
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
.nav-link.active {
|
||||
background-color: #3b82f6;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Navigation -->
|
||||
<nav class="glass-effect border-b border-gray-200 sticky top-0 z-50">
|
||||
<!-- 헤더 -->
|
||||
<header class="bg-white shadow-sm sticky top-0 z-50">
|
||||
<div class="container mx-auto px-4 py-3">
|
||||
<div class="flex items-center justify-between">
|
||||
<h1 class="text-xl font-semibold text-gray-800">
|
||||
<i class="fas fa-clipboard-list mr-2"></i>작업보고서 시스템
|
||||
<div class="flex justify-between items-center">
|
||||
<h1 class="text-xl font-bold text-gray-800">
|
||||
<i class="fas fa-clipboard-check text-blue-500 mr-2"></i>작업보고서
|
||||
</h1>
|
||||
<div id="navContainer" class="flex items-center gap-4">
|
||||
<a href="/daily-work.html" class="text-gray-600 hover:text-gray-800 transition-colors">
|
||||
<i class="fas fa-calendar-day mr-1"></i>일일 공수
|
||||
</a>
|
||||
<a href="/index.html" class="text-gray-600 hover:text-gray-800 transition-colors">
|
||||
<i class="fas fa-exclamation-triangle mr-1"></i>부적합 등록
|
||||
</a>
|
||||
<a href="/issue-view.html" class="text-blue-600 font-medium">
|
||||
<i class="fas fa-search mr-1"></i>부적합 조회
|
||||
</a>
|
||||
<a href="/index.html#list" class="text-gray-600 hover:text-gray-800 transition-colors" style="display:none;" id="listBtn">
|
||||
<i class="fas fa-list mr-1"></i>목록 관리
|
||||
</a>
|
||||
<a href="/index.html#summary" class="text-gray-600 hover:text-gray-800 transition-colors" style="display:none;" id="summaryBtn">
|
||||
<i class="fas fa-chart-bar mr-1"></i>보고서
|
||||
</a>
|
||||
<a href="/admin.html" class="text-gray-600 hover:text-gray-800 transition-colors" style="display:none;" id="adminBtn">
|
||||
<i class="fas fa-users-cog mr-1"></i>관리
|
||||
</a>
|
||||
<button onclick="AuthAPI.logout()" class="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600 transition-colors text-sm">
|
||||
<i class="fas fa-sign-out-alt mr-1"></i>로그아웃
|
||||
<div class="flex items-center gap-4">
|
||||
<span class="text-sm text-gray-600" id="userDisplay"></span>
|
||||
<button onclick="logout()" class="text-gray-500 hover:text-gray-700">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
<!-- 네비게이션 -->
|
||||
<nav class="bg-white border-b">
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="flex gap-2 py-2 overflow-x-auto">
|
||||
<a href="daily-work.html" class="nav-link">
|
||||
<i class="fas fa-calendar-check mr-2"></i>일일 공수
|
||||
</a>
|
||||
<a href="index.html" class="nav-link">
|
||||
<i class="fas fa-camera-retro mr-2"></i>부적합 등록
|
||||
</a>
|
||||
<a href="issue-view.html" class="nav-link active">
|
||||
<i class="fas fa-search mr-2"></i>부적합 조회
|
||||
</a>
|
||||
<a href="index.html#list" class="nav-link" style="display:none;" id="listBtn">
|
||||
<i class="fas fa-list mr-2"></i>목록 관리
|
||||
</a>
|
||||
<a href="index.html#summary" class="nav-link" style="display:none;" id="summaryBtn">
|
||||
<i class="fas fa-chart-bar mr-2"></i>보고서
|
||||
</a>
|
||||
<a href="project-management.html" class="nav-link" style="display:none;" id="projectBtn">
|
||||
<i class="fas fa-folder-open mr-2"></i>프로젝트 관리
|
||||
</a>
|
||||
<a href="admin.html" class="nav-link" style="display:none;" id="adminBtn">
|
||||
<i class="fas fa-users-cog mr-2"></i>사용자 관리
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
@@ -91,6 +122,41 @@
|
||||
<i class="fas fa-list-alt text-blue-500 mr-2"></i>부적합 사항 목록
|
||||
</h2>
|
||||
|
||||
<!-- 필터 섹션 -->
|
||||
<div class="bg-gray-50 p-4 rounded-lg mb-4">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<!-- 프로젝트 필터 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">프로젝트</label>
|
||||
<select id="projectFilter" class="w-full px-3 py-2 border border-gray-300 rounded text-sm" onchange="filterIssues()">
|
||||
<option value="">전체 프로젝트</option>
|
||||
<!-- 프로젝트 옵션들이 여기에 로드됩니다 -->
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 검토 상태 필터 -->
|
||||
<div>
|
||||
<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="filterIssues()">
|
||||
<option value="">전체</option>
|
||||
<option value="pending">검토 필요</option>
|
||||
<option value="completed">검토 완료</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- 날짜 필터 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">날짜</label>
|
||||
<select id="dateFilter" class="w-full px-3 py-2 border border-gray-300 rounded text-sm" onchange="filterIssues()">
|
||||
<option value="">전체</option>
|
||||
<option value="today">오늘</option>
|
||||
<option value="week">이번 주</option>
|
||||
<option value="month">이번 달</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1"></div>
|
||||
|
||||
<button onclick="setDateRange('today')" class="px-3 py-1.5 bg-gray-100 text-gray-700 rounded hover:bg-gray-200 transition-colors text-sm">
|
||||
@@ -140,6 +206,9 @@
|
||||
// 네비게이션 권한 체크
|
||||
updateNavigation();
|
||||
|
||||
// 프로젝트 로드
|
||||
loadProjects();
|
||||
|
||||
// 기본값: 이번 주 데이터 로드
|
||||
setDateRange('week');
|
||||
});
|
||||
@@ -173,22 +242,138 @@
|
||||
const listBtn = document.getElementById('listBtn');
|
||||
const summaryBtn = document.getElementById('summaryBtn');
|
||||
const adminBtn = document.getElementById('adminBtn');
|
||||
const projectBtn = document.getElementById('projectBtn');
|
||||
|
||||
if (currentUser.role === 'admin') {
|
||||
// 관리자는 모든 메뉴 표시
|
||||
listBtn.style.display = '';
|
||||
summaryBtn.style.display = '';
|
||||
projectBtn.style.display = '';
|
||||
adminBtn.style.display = '';
|
||||
adminBtn.innerHTML = '<i class="fas fa-users-cog mr-1"></i>사용자 관리';
|
||||
} else {
|
||||
// 일반 사용자는 제한된 메뉴만 표시
|
||||
listBtn.style.display = 'none';
|
||||
summaryBtn.style.display = 'none';
|
||||
projectBtn.style.display = 'none';
|
||||
adminBtn.style.display = '';
|
||||
adminBtn.innerHTML = '<i class="fas fa-key mr-1"></i>비밀번호 변경';
|
||||
}
|
||||
}
|
||||
|
||||
// 프로젝트 로드
|
||||
function loadProjects() {
|
||||
const saved = localStorage.getItem('work-report-projects');
|
||||
if (saved) {
|
||||
const projects = JSON.parse(saved);
|
||||
const projectFilter = document.getElementById('projectFilter');
|
||||
|
||||
// 기존 옵션 제거 (전체 프로젝트 옵션 제외)
|
||||
projectFilter.innerHTML = '<option value="">전체 프로젝트</option>';
|
||||
|
||||
// 모든 프로젝트 추가 (활성/비활성 모두 - 기존 데이터 조회를 위해)
|
||||
projects.forEach(project => {
|
||||
const option = document.createElement('option');
|
||||
option.value = project.id;
|
||||
option.textContent = `${project.jobNo} - ${project.projectName}${!project.isActive ? ' (비활성)' : ''}`;
|
||||
projectFilter.appendChild(option);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 이슈 필터링
|
||||
// 검토 상태 확인 함수
|
||||
function isReviewCompleted(issue) {
|
||||
return issue.status === 'complete' && issue.work_hours && issue.work_hours > 0;
|
||||
}
|
||||
|
||||
// 날짜 필터링 함수
|
||||
function filterByDate(issues, dateFilter) {
|
||||
const now = new Date();
|
||||
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
|
||||
|
||||
switch (dateFilter) {
|
||||
case 'today':
|
||||
return issues.filter(issue => {
|
||||
const issueDate = new Date(issue.report_date);
|
||||
return issueDate >= today;
|
||||
});
|
||||
case 'week':
|
||||
const weekStart = new Date(today);
|
||||
weekStart.setDate(today.getDate() - today.getDay());
|
||||
return issues.filter(issue => {
|
||||
const issueDate = new Date(issue.report_date);
|
||||
return issueDate >= weekStart;
|
||||
});
|
||||
case 'month':
|
||||
const monthStart = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
return issues.filter(issue => {
|
||||
const issueDate = new Date(issue.report_date);
|
||||
return issueDate >= monthStart;
|
||||
});
|
||||
default:
|
||||
return issues;
|
||||
}
|
||||
}
|
||||
|
||||
function filterIssues() {
|
||||
console.log('필터링 시작 - 전체 이슈:', issues.length);
|
||||
|
||||
// 필터 값 가져오기
|
||||
const selectedProjectId = document.getElementById('projectFilter').value;
|
||||
const reviewStatusFilter = document.getElementById('reviewStatusFilter').value;
|
||||
const dateFilter = document.getElementById('dateFilter').value;
|
||||
|
||||
let filteredIssues = [...issues];
|
||||
|
||||
// 프로젝트 필터 적용
|
||||
if (selectedProjectId) {
|
||||
filteredIssues = filteredIssues.filter(issue => {
|
||||
const issueProjectId = issue.project_id || issue.projectId;
|
||||
return issueProjectId && (issueProjectId == selectedProjectId || issueProjectId.toString() === selectedProjectId.toString());
|
||||
});
|
||||
console.log('프로젝트 필터 후:', filteredIssues.length);
|
||||
}
|
||||
|
||||
// 검토 상태 필터 적용
|
||||
if (reviewStatusFilter) {
|
||||
filteredIssues = filteredIssues.filter(issue => {
|
||||
const isCompleted = isReviewCompleted(issue);
|
||||
return reviewStatusFilter === 'completed' ? isCompleted : !isCompleted;
|
||||
});
|
||||
console.log('검토 상태 필터 후:', filteredIssues.length);
|
||||
}
|
||||
|
||||
// 날짜 필터 적용
|
||||
if (dateFilter) {
|
||||
filteredIssues = filterByDate(filteredIssues, dateFilter);
|
||||
console.log('날짜 필터 후:', filteredIssues.length);
|
||||
}
|
||||
|
||||
// 전역 변수에 필터링된 결과 저장
|
||||
window.filteredIssues = filteredIssues;
|
||||
|
||||
displayResults();
|
||||
}
|
||||
|
||||
// 프로젝트 정보 표시용 함수
|
||||
function getProjectInfo(projectId) {
|
||||
if (!projectId) {
|
||||
return '<span class="text-gray-500">프로젝트 미지정</span>';
|
||||
}
|
||||
|
||||
const saved = localStorage.getItem('work-report-projects');
|
||||
if (saved) {
|
||||
const projects = JSON.parse(saved);
|
||||
const project = projects.find(p => p.id == projectId);
|
||||
if (project) {
|
||||
return `${project.jobNo} - ${project.projectName}`;
|
||||
}
|
||||
}
|
||||
|
||||
return `<span class="text-red-500">프로젝트 ID: ${projectId} (정보 없음)</span>`;
|
||||
}
|
||||
|
||||
// 날짜 범위 설정 및 자동 조회
|
||||
async function setDateRange(range) {
|
||||
currentRange = range;
|
||||
@@ -274,16 +459,60 @@
|
||||
function displayResults() {
|
||||
const container = document.getElementById('issueResults');
|
||||
|
||||
if (issues.length === 0) {
|
||||
// 필터링된 결과 사용 (filterIssues에서 설정됨)
|
||||
const filteredIssues = window.filteredIssues || issues;
|
||||
|
||||
if (filteredIssues.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="text-gray-500 text-center py-8">
|
||||
<i class="fas fa-inbox text-4xl mb-3"></i>
|
||||
<p>등록된 부적합 사항이 없습니다.</p>
|
||||
<p>조건에 맞는 부적합 사항이 없습니다.</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 검토 상태별로 분류 및 정렬
|
||||
const pendingIssues = filteredIssues.filter(issue => !isReviewCompleted(issue));
|
||||
const completedIssues = filteredIssues.filter(issue => isReviewCompleted(issue));
|
||||
|
||||
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));
|
||||
});
|
||||
}
|
||||
|
||||
// 검토 완료 항목을 아래에 표시
|
||||
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));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 부적합 사항 카드 생성 함수 (조회용)
|
||||
function createIssueCard(issue, isCompleted) {
|
||||
const categoryNames = {
|
||||
material_missing: '자재누락',
|
||||
design_error: '설계미스',
|
||||
@@ -298,72 +527,114 @@
|
||||
inspection_miss: 'bg-purple-100 text-purple-700 border-purple-300'
|
||||
};
|
||||
|
||||
// 시간순으로 나열
|
||||
container.innerHTML = issues.map(issue => {
|
||||
const dateStr = DateUtils.formatKST(issue.report_date, true);
|
||||
const relativeTime = DateUtils.getRelativeTime(issue.report_date);
|
||||
const div = document.createElement('div');
|
||||
// 검토 완료 상태에 따른 스타일링
|
||||
const baseClasses = 'rounded-lg transition-colors border-l-4 mb-4';
|
||||
const statusClasses = isCompleted
|
||||
? 'bg-gray-100 opacity-75'
|
||||
: 'bg-gray-50 hover:bg-gray-100';
|
||||
const borderColor = categoryColors[issue.category]?.split(' ')[2] || 'border-gray-300';
|
||||
div.className = `${baseClasses} ${statusClasses} ${borderColor}`;
|
||||
|
||||
const dateStr = DateUtils.formatKST(issue.report_date, true);
|
||||
const relativeTime = DateUtils.getRelativeTime(issue.report_date);
|
||||
const projectInfo = getProjectInfo(issue.project_id || issue.projectId);
|
||||
|
||||
div.innerHTML = `
|
||||
<!-- 프로젝트 정보 및 상태 (오른쪽 상단) -->
|
||||
<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>'
|
||||
}
|
||||
</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}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
return `
|
||||
<div class="flex gap-3 p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors border-l-4 ${categoryColors[issue.category].split(' ')[2] || 'border-gray-300'}">
|
||||
<!-- 사진들 -->
|
||||
<div class="flex gap-1 flex-shrink-0">
|
||||
${issue.photo_path ?
|
||||
`<img src="${issue.photo_path}" class="w-20 h-20 object-cover rounded shadow-sm cursor-pointer" onclick="showImageModal('${issue.photo_path}')">` : ''
|
||||
}
|
||||
${issue.photo_path2 ?
|
||||
`<img src="${issue.photo_path2}" class="w-20 h-20 object-cover rounded shadow-sm cursor-pointer" onclick="showImageModal('${issue.photo_path2}')">` : ''
|
||||
}
|
||||
${!issue.photo_path && !issue.photo_path2 ?
|
||||
`<div class="w-20 h-20 bg-gray-200 rounded flex items-center justify-center">
|
||||
<i class="fas fa-image text-gray-400"></i>
|
||||
</div>` : ''
|
||||
<!-- 기존 내용 -->
|
||||
<div class="flex gap-3 p-3 pt-1">
|
||||
<!-- 사진들 -->
|
||||
<div class="flex gap-1 flex-shrink-0">
|
||||
${issue.photo_path ?
|
||||
`<img src="${issue.photo_path}" class="w-20 h-20 object-cover rounded shadow-sm cursor-pointer" onclick="showImageModal('${issue.photo_path}')">` : ''
|
||||
}
|
||||
${issue.photo_path2 ?
|
||||
`<img src="${issue.photo_path2}" class="w-20 h-20 object-cover rounded shadow-sm cursor-pointer" onclick="showImageModal('${issue.photo_path2}')">` : ''
|
||||
}
|
||||
${!issue.photo_path && !issue.photo_path2 ?
|
||||
`<div class="w-20 h-20 bg-gray-200 rounded flex items-center justify-center">
|
||||
<i class="fas fa-image text-gray-400"></i>
|
||||
</div>` : ''
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- 내용 -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-start justify-between mb-2">
|
||||
<span class="px-2 py-1 rounded-full text-xs font-medium ${categoryColors[issue.category] || 'bg-gray-100 text-gray-700'}">
|
||||
${categoryNames[issue.category] || issue.category}
|
||||
</span>
|
||||
${issue.work_hours ?
|
||||
`<span class="text-sm text-green-600 font-medium">
|
||||
<i class="fas fa-clock mr-1"></i>${issue.work_hours}시간
|
||||
</span>` :
|
||||
'<span class="text-sm text-gray-400">시간 미입력</span>'
|
||||
}
|
||||
</div>
|
||||
|
||||
<!-- 내용 -->
|
||||
<div class="flex-1 min-w-0">
|
||||
<div class="flex items-start justify-between mb-1">
|
||||
<div class="flex items-center gap-2">
|
||||
<span class="px-2 py-0.5 rounded text-xs font-medium ${categoryColors[issue.category].split(' ').slice(0, 2).join(' ')}">
|
||||
${categoryNames[issue.category]}
|
||||
</span>
|
||||
${issue.work_hours ? `
|
||||
<span class="text-xs text-green-600 font-medium">
|
||||
✓ ${issue.work_hours}시간
|
||||
</span>
|
||||
` : ''}
|
||||
</div>
|
||||
<div class="text-xs text-gray-500">
|
||||
${dateStr} (${relativeTime})
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="text-sm text-gray-800 line-clamp-2">${issue.description}</p>
|
||||
|
||||
<div class="mt-1 text-xs text-gray-500">
|
||||
<i class="fas fa-user mr-1"></i>
|
||||
${issue.reporter.full_name || issue.reporter.username}
|
||||
</div>
|
||||
<p class="text-gray-800 mb-2 line-clamp-2">${issue.description}</p>
|
||||
|
||||
<div class="flex items-center gap-4 text-sm text-gray-500">
|
||||
<span><i class="fas fa-user mr-1"></i>${issue.reporter?.full_name || issue.reporter?.username || '알 수 없음'}</span>
|
||||
<span><i class="fas fa-calendar mr-1"></i>${dateStr}</span>
|
||||
<span class="text-xs text-gray-400">${relativeTime}</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
|
||||
// 상단에 요약 추가
|
||||
const summary = `
|
||||
<div class="mb-4 p-3 bg-blue-50 rounded-lg text-sm">
|
||||
<span class="font-medium text-blue-900">총 ${issues.length}건</span>
|
||||
<span class="text-blue-700 ml-3">
|
||||
자재누락: ${issues.filter(i => i.category === 'material_missing').length}건 |
|
||||
설계미스: ${issues.filter(i => i.category === 'design_error').length}건 |
|
||||
입고자재 불량: ${issues.filter(i => i.category === 'incoming_defect').length}건 |
|
||||
검사미스: ${issues.filter(i => i.category === 'inspection_miss').length}건
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.innerHTML = summary + container.innerHTML;
|
||||
return div;
|
||||
}
|
||||
|
||||
// 로그아웃 함수
|
||||
function logout() {
|
||||
localStorage.removeItem('currentUser');
|
||||
window.location.href = 'index.html';
|
||||
}
|
||||
|
||||
// 페이지 로드 시 사용자 정보 확인 및 관리자 배너 표시
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const currentUserData = localStorage.getItem('currentUser');
|
||||
if (!currentUserData) {
|
||||
window.location.href = 'index.html';
|
||||
return;
|
||||
}
|
||||
|
||||
let currentUser;
|
||||
try {
|
||||
// JSON 파싱 시도
|
||||
currentUser = JSON.parse(currentUserData);
|
||||
} catch (e) {
|
||||
// JSON이 아니면 문자열로 처리 (기존 방식 호환)
|
||||
currentUser = { username: currentUserData };
|
||||
}
|
||||
|
||||
// 사용자 표시
|
||||
const username = currentUser.username || currentUser;
|
||||
const displayName = currentUser.full_name || (username === 'hyungi' ? '관리자' : username);
|
||||
document.getElementById('userDisplay').textContent = `${displayName} (${username})`;
|
||||
|
||||
// 관리자인 경우 메뉴 표시
|
||||
if (username === 'hyungi' || currentUser.role === 'admin') {
|
||||
document.getElementById('listBtn').style.display = '';
|
||||
document.getElementById('summaryBtn').style.display = '';
|
||||
document.getElementById('projectBtn').style.display = '';
|
||||
document.getElementById('adminBtn').style.display = '';
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user