feat: 목록 관리 및 보고서 페이지 개선
- 목록 관리 페이지에 고급 필터링 시스템 추가 - 프로젝트별, 검토상태별, 날짜별 필터링 - 검토 완료/필요 항목 시각적 구분 및 정렬 - 해결 시간 입력 + 확인 버튼으로 검토 완료 처리 - 부적합 조회 페이지에 동일한 필터링 기능 적용 - 검토 상태에 따른 카드 스타일링 (음영 처리) - JavaScript 템플릿 리터럴 오류 수정 - 보고서 페이지 프로젝트별 분석 기능 추가 - 프로젝트 선택 드롭다운 추가 - 총 작업 공수를 프로젝트별 일일공수 데이터로 계산 - 부적합 처리 시간, 카테고리 분석, 상세 목록 모두 프로젝트별 필터링 - localStorage 키 이름 통일 (daily-work-data)
This commit is contained in:
@@ -98,11 +98,14 @@
|
||||
<div class="container mx-auto px-4 py-3">
|
||||
<div class="flex justify-between items-center">
|
||||
<h1 class="text-xl font-bold text-gray-800">
|
||||
<i class="fas fa-clipboard-list mr-2"></i>작업보고서 시스템
|
||||
<i class="fas fa-clipboard-check text-blue-500 mr-2"></i>작업보고서
|
||||
</h1>
|
||||
<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>로그아웃
|
||||
</button>
|
||||
<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>
|
||||
@@ -126,6 +129,9 @@
|
||||
<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>
|
||||
@@ -152,65 +158,34 @@
|
||||
id="workDate"
|
||||
class="input-field w-full px-4 py-3 rounded-lg text-lg"
|
||||
required
|
||||
onchange="loadExistingData()"
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- 인원 입력 -->
|
||||
<!-- 프로젝트별 시간 입력 섹션 -->
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-2">
|
||||
<i class="fas fa-users mr-1"></i>작업 인원
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="workerCount"
|
||||
min="1"
|
||||
class="input-field w-full px-4 py-3 rounded-lg text-lg"
|
||||
placeholder="예: 5"
|
||||
required
|
||||
>
|
||||
<p class="text-sm text-gray-500 mt-1">기본 근무시간: 8시간/인</p>
|
||||
</div>
|
||||
|
||||
<!-- 잔업 섹션 -->
|
||||
<div class="border-t pt-4">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<label class="text-sm font-medium text-gray-700">
|
||||
<i class="fas fa-clock mr-1"></i>잔업 여부
|
||||
<i class="fas fa-folder-open mr-1"></i>프로젝트별 작업 시간
|
||||
</label>
|
||||
<button
|
||||
type="button"
|
||||
id="overtimeToggle"
|
||||
class="px-4 py-2 rounded-lg border border-gray-300 hover:bg-gray-50 transition-colors"
|
||||
onclick="toggleOvertime()"
|
||||
id="addProjectBtn"
|
||||
class="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors"
|
||||
onclick="addProjectEntry()"
|
||||
>
|
||||
<i class="fas fa-plus mr-2"></i>잔업 추가
|
||||
<i class="fas fa-plus mr-2"></i>프로젝트 추가
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 잔업 입력 영역 -->
|
||||
<div id="overtimeSection" class="hidden space-y-3 bg-gray-50 p-4 rounded-lg">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">잔업 인원</label>
|
||||
<input
|
||||
type="number"
|
||||
id="overtimeWorkers"
|
||||
min="0"
|
||||
class="input-field w-full px-3 py-2 rounded"
|
||||
placeholder="명"
|
||||
>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">잔업 시간</label>
|
||||
<input
|
||||
type="number"
|
||||
id="overtimeHours"
|
||||
min="0"
|
||||
step="0.5"
|
||||
class="input-field w-full px-3 py-2 rounded"
|
||||
placeholder="시간"
|
||||
>
|
||||
</div>
|
||||
<div id="projectEntries" class="space-y-3">
|
||||
<!-- 프로젝트 입력 항목들이 여기에 추가됩니다 -->
|
||||
</div>
|
||||
|
||||
<div class="mt-4 p-4 bg-blue-50 rounded-lg">
|
||||
<div class="flex justify-between items-center">
|
||||
<span class="text-sm font-medium text-blue-900">총 작업 시간:</span>
|
||||
<span id="totalHours" class="text-lg font-bold text-blue-600">0시간</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -246,7 +221,9 @@
|
||||
<script src="/static/js/date-utils.js?v=20250917"></script>
|
||||
<script>
|
||||
let currentUser = null;
|
||||
let dailyWorks = [];
|
||||
let projects = [];
|
||||
let dailyWorkData = [];
|
||||
let projectEntryCounter = 0;
|
||||
|
||||
// 페이지 로드 시 인증 체크
|
||||
window.addEventListener('DOMContentLoaded', async () => {
|
||||
@@ -257,12 +234,22 @@
|
||||
}
|
||||
currentUser = user;
|
||||
|
||||
// 사용자 표시
|
||||
document.getElementById('userDisplay').textContent = user.full_name || user.username;
|
||||
|
||||
// 네비게이션 권한 체크
|
||||
updateNavigation();
|
||||
|
||||
// 프로젝트 및 일일 공수 데이터 로드
|
||||
loadProjects();
|
||||
loadDailyWorkData();
|
||||
|
||||
// 오늘 날짜로 초기화
|
||||
document.getElementById('workDate').valueAsDate = new Date();
|
||||
|
||||
// 첫 번째 프로젝트 입력 항목 추가
|
||||
addProjectEntry();
|
||||
|
||||
// 최근 내역 로드
|
||||
await loadRecentEntries();
|
||||
});
|
||||
@@ -272,95 +259,207 @@
|
||||
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-2"></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-2"></i>비밀번호 변경';
|
||||
}
|
||||
}
|
||||
|
||||
// 잔업 토글
|
||||
function toggleOvertime() {
|
||||
const section = document.getElementById('overtimeSection');
|
||||
const button = document.getElementById('overtimeToggle');
|
||||
// 프로젝트 데이터 로드
|
||||
function loadProjects() {
|
||||
const saved = localStorage.getItem('work-report-projects');
|
||||
if (saved) {
|
||||
projects = JSON.parse(saved);
|
||||
}
|
||||
}
|
||||
|
||||
// 일일 공수 데이터 로드
|
||||
function loadDailyWorkData() {
|
||||
const saved = localStorage.getItem('daily-work-data');
|
||||
if (saved) {
|
||||
dailyWorkData = JSON.parse(saved);
|
||||
}
|
||||
}
|
||||
|
||||
// 일일 공수 데이터 저장
|
||||
function saveDailyWorkData() {
|
||||
localStorage.setItem('daily-work-data', JSON.stringify(dailyWorkData));
|
||||
}
|
||||
|
||||
// 활성 프로젝트만 필터링
|
||||
function getActiveProjects() {
|
||||
return projects.filter(p => p.isActive);
|
||||
}
|
||||
|
||||
// 프로젝트 입력 항목 추가
|
||||
function addProjectEntry() {
|
||||
const activeProjects = getActiveProjects();
|
||||
if (activeProjects.length === 0) {
|
||||
alert('활성 프로젝트가 없습니다. 먼저 프로젝트를 생성해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (section.classList.contains('hidden')) {
|
||||
section.classList.remove('hidden');
|
||||
button.innerHTML = '<i class="fas fa-minus mr-2"></i>잔업 취소';
|
||||
button.classList.add('bg-gray-100');
|
||||
projectEntryCounter++;
|
||||
const entryId = `project-entry-${projectEntryCounter}`;
|
||||
|
||||
const entryHtml = `
|
||||
<div id="${entryId}" class="flex gap-3 items-center p-4 bg-gray-50 rounded-lg">
|
||||
<div class="flex-1">
|
||||
<select class="input-field w-full px-3 py-2 rounded-lg" onchange="updateTotalHours()">
|
||||
<option value="">프로젝트 선택</option>
|
||||
${activeProjects.map(p => `<option value="${p.id}">${p.jobNo} - ${p.projectName}</option>`).join('')}
|
||||
</select>
|
||||
</div>
|
||||
<div class="w-32">
|
||||
<input
|
||||
type="number"
|
||||
placeholder="시간"
|
||||
min="0"
|
||||
step="0.5"
|
||||
class="input-field w-full px-3 py-2 rounded-lg text-center"
|
||||
onchange="updateTotalHours()"
|
||||
>
|
||||
</div>
|
||||
<div class="w-16 text-center text-gray-600">시간</div>
|
||||
<button
|
||||
type="button"
|
||||
onclick="removeProjectEntry('${entryId}')"
|
||||
class="text-red-500 hover:text-red-700 p-2"
|
||||
title="제거"
|
||||
>
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.getElementById('projectEntries').insertAdjacentHTML('beforeend', entryHtml);
|
||||
updateTotalHours();
|
||||
}
|
||||
|
||||
// 프로젝트 입력 항목 제거
|
||||
function removeProjectEntry(entryId) {
|
||||
const entry = document.getElementById(entryId);
|
||||
if (entry) {
|
||||
entry.remove();
|
||||
updateTotalHours();
|
||||
}
|
||||
}
|
||||
|
||||
// 총 시간 계산 및 업데이트
|
||||
function updateTotalHours() {
|
||||
const entries = document.querySelectorAll('#projectEntries > div');
|
||||
let totalHours = 0;
|
||||
|
||||
entries.forEach(entry => {
|
||||
const hoursInput = entry.querySelector('input[type="number"]');
|
||||
const hours = parseFloat(hoursInput.value) || 0;
|
||||
totalHours += hours;
|
||||
});
|
||||
|
||||
document.getElementById('totalHours').textContent = `${totalHours}시간`;
|
||||
}
|
||||
|
||||
// 기존 데이터 로드 (날짜 선택 시)
|
||||
function loadExistingData() {
|
||||
const selectedDate = document.getElementById('workDate').value;
|
||||
if (!selectedDate) return;
|
||||
|
||||
const existingData = dailyWorkData.find(d => d.date === selectedDate);
|
||||
if (existingData) {
|
||||
// 기존 프로젝트 입력 항목들 제거
|
||||
document.getElementById('projectEntries').innerHTML = '';
|
||||
projectEntryCounter = 0;
|
||||
|
||||
// 기존 데이터로 프로젝트 입력 항목들 생성
|
||||
existingData.projects.forEach(projectData => {
|
||||
addProjectEntry();
|
||||
const lastEntry = document.querySelector('#projectEntries > div:last-child');
|
||||
const select = lastEntry.querySelector('select');
|
||||
const input = lastEntry.querySelector('input[type="number"]');
|
||||
|
||||
select.value = projectData.projectId;
|
||||
input.value = projectData.hours;
|
||||
});
|
||||
|
||||
updateTotalHours();
|
||||
} else {
|
||||
section.classList.add('hidden');
|
||||
button.innerHTML = '<i class="fas fa-plus mr-2"></i>잔업 추가';
|
||||
button.classList.remove('bg-gray-100');
|
||||
// 잔업 입력값 초기화
|
||||
document.getElementById('overtimeWorkers').value = '';
|
||||
document.getElementById('overtimeHours').value = '';
|
||||
// 새로운 날짜인 경우 초기화
|
||||
document.getElementById('projectEntries').innerHTML = '';
|
||||
projectEntryCounter = 0;
|
||||
addProjectEntry();
|
||||
}
|
||||
calculateTotal();
|
||||
}
|
||||
|
||||
// 총 공수 계산
|
||||
function calculateTotal() {
|
||||
const workerCount = parseInt(document.getElementById('workerCount').value) || 0;
|
||||
const regularHours = workerCount * 8; // 기본 8시간
|
||||
|
||||
let overtimeTotal = 0;
|
||||
if (!document.getElementById('overtimeSection').classList.contains('hidden')) {
|
||||
const overtimeWorkers = parseInt(document.getElementById('overtimeWorkers').value) || 0;
|
||||
const overtimeHours = parseFloat(document.getElementById('overtimeHours').value) || 0;
|
||||
overtimeTotal = overtimeWorkers * overtimeHours;
|
||||
}
|
||||
|
||||
const total = regularHours + overtimeTotal;
|
||||
document.getElementById('totalHours').textContent = `${total}시간`;
|
||||
}
|
||||
|
||||
// 입력값 변경 시 총 공수 재계산
|
||||
document.getElementById('workerCount').addEventListener('input', calculateTotal);
|
||||
document.getElementById('overtimeWorkers').addEventListener('input', calculateTotal);
|
||||
document.getElementById('overtimeHours').addEventListener('input', calculateTotal);
|
||||
|
||||
// 폼 제출
|
||||
document.getElementById('dailyWorkForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const workDate = document.getElementById('workDate').value;
|
||||
const workerCount = parseInt(document.getElementById('workerCount').value);
|
||||
const selectedDate = document.getElementById('workDate').value;
|
||||
const entries = document.querySelectorAll('#projectEntries > div');
|
||||
|
||||
let overtimeWorkers = 0;
|
||||
let overtimeHours = 0;
|
||||
const projectData = [];
|
||||
let hasValidEntry = false;
|
||||
|
||||
if (!document.getElementById('overtimeSection').classList.contains('hidden')) {
|
||||
overtimeWorkers = parseInt(document.getElementById('overtimeWorkers').value) || 0;
|
||||
overtimeHours = parseFloat(document.getElementById('overtimeHours').value) || 0;
|
||||
entries.forEach(entry => {
|
||||
const select = entry.querySelector('select');
|
||||
const input = entry.querySelector('input[type="number"]');
|
||||
const projectId = select.value;
|
||||
const hours = parseFloat(input.value) || 0;
|
||||
|
||||
if (projectId && hours > 0) {
|
||||
const project = projects.find(p => p.id == projectId);
|
||||
projectData.push({
|
||||
projectId: projectId,
|
||||
projectName: project ? `${project.jobNo} - ${project.projectName}` : '알 수 없음',
|
||||
hours: hours
|
||||
});
|
||||
hasValidEntry = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (!hasValidEntry) {
|
||||
alert('최소 하나의 프로젝트에 시간을 입력해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// API 호출
|
||||
await DailyWorkAPI.create({
|
||||
date: new Date(workDate).toISOString(),
|
||||
worker_count: workerCount,
|
||||
overtime_workers: overtimeWorkers,
|
||||
overtime_hours: overtimeHours
|
||||
});
|
||||
// 기존 데이터 업데이트 또는 새로 추가
|
||||
const existingIndex = dailyWorkData.findIndex(d => d.date === selectedDate);
|
||||
const newData = {
|
||||
date: selectedDate,
|
||||
projects: projectData,
|
||||
totalHours: projectData.reduce((sum, p) => sum + p.hours, 0),
|
||||
createdAt: new Date().toISOString(),
|
||||
createdBy: currentUser.username || currentUser
|
||||
};
|
||||
|
||||
if (existingIndex >= 0) {
|
||||
dailyWorkData[existingIndex] = newData;
|
||||
} else {
|
||||
dailyWorkData.push(newData);
|
||||
}
|
||||
|
||||
saveDailyWorkData();
|
||||
|
||||
// 성공 메시지
|
||||
showSuccessMessage();
|
||||
|
||||
// 폼 초기화
|
||||
resetForm();
|
||||
|
||||
// 최근 내역 갱신
|
||||
await loadRecentEntries();
|
||||
|
||||
} catch (error) {
|
||||
alert(error.message || '저장에 실패했습니다.');
|
||||
}
|
||||
@@ -369,22 +468,16 @@
|
||||
// 최근 데이터 로드
|
||||
async function loadRecentEntries() {
|
||||
try {
|
||||
// 최근 7일간 데이터 가져오기
|
||||
const endDate = new Date();
|
||||
const startDate = new Date();
|
||||
startDate.setDate(startDate.getDate() - 7);
|
||||
// 최근 7일 데이터 표시
|
||||
const recentData = dailyWorkData
|
||||
.sort((a, b) => new Date(b.date) - new Date(a.date))
|
||||
.slice(0, 7);
|
||||
|
||||
dailyWorks = await DailyWorkAPI.getAll({
|
||||
start_date: startDate.toISOString().split('T')[0],
|
||||
end_date: endDate.toISOString().split('T')[0],
|
||||
limit: 7
|
||||
});
|
||||
|
||||
displayRecentEntries();
|
||||
displayRecentEntries(recentData);
|
||||
} catch (error) {
|
||||
console.error('데이터 로드 실패:', error);
|
||||
dailyWorks = [];
|
||||
displayRecentEntries();
|
||||
document.getElementById('recentEntries').innerHTML =
|
||||
'<p class="text-gray-500 text-center py-4">데이터를 불러올 수 없습니다.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,52 +496,42 @@
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
// 폼 초기화
|
||||
function resetForm() {
|
||||
document.getElementById('workerCount').value = '';
|
||||
document.getElementById('overtimeWorkers').value = '';
|
||||
document.getElementById('overtimeHours').value = '';
|
||||
document.getElementById('overtimeSection').classList.add('hidden');
|
||||
document.getElementById('overtimeToggle').innerHTML = '<i class="fas fa-plus mr-2"></i>잔업 추가';
|
||||
document.getElementById('overtimeToggle').classList.remove('bg-gray-100');
|
||||
document.getElementById('totalHours').textContent = '0시간';
|
||||
|
||||
// 날짜는 오늘로 유지
|
||||
document.getElementById('workDate').valueAsDate = new Date();
|
||||
}
|
||||
|
||||
// 최근 입력 내역 표시
|
||||
function displayRecentEntries() {
|
||||
function displayRecentEntries(entries) {
|
||||
const container = document.getElementById('recentEntries');
|
||||
|
||||
if (dailyWorks.length === 0) {
|
||||
container.innerHTML = '<p class="text-gray-500 text-center py-4">입력된 내역이 없습니다.</p>';
|
||||
if (!entries || entries.length === 0) {
|
||||
container.innerHTML = '<p class="text-gray-500 text-center py-4">최근 입력 내역이 없습니다.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = dailyWorks.map(item => {
|
||||
const dateStr = DateUtils.formatKST(item.date);
|
||||
const relativeTime = DateUtils.getRelativeTime(item.created_at || item.date);
|
||||
container.innerHTML = entries.map(item => {
|
||||
const date = new Date(item.date);
|
||||
const dateStr = `${date.getMonth() + 1}/${date.getDate()} (${['일','월','화','수','목','금','토'][date.getDay()]})`;
|
||||
|
||||
return `
|
||||
<div class="flex justify-between items-center p-3 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors">
|
||||
<div>
|
||||
<div class="p-4 bg-gray-50 rounded-lg hover:bg-gray-100 transition-colors">
|
||||
<div class="flex justify-between items-start mb-2">
|
||||
<p class="font-medium text-gray-800">${dateStr}</p>
|
||||
<p class="text-sm text-gray-600">
|
||||
인원: ${item.worker_count}명
|
||||
${item.overtime_total > 0 ? `• 잔업: ${item.overtime_workers}명 × ${item.overtime_hours}시간` : ''}
|
||||
</p>
|
||||
<div class="text-right">
|
||||
<p class="text-lg font-bold text-blue-600">${item.totalHours}시간</p>
|
||||
${currentUser && (currentUser.role === 'admin' || currentUser.username === 'hyungi') ? `
|
||||
<button
|
||||
onclick="deleteDailyWork('${item.date}')"
|
||||
class="mt-1 px-2 py-1 bg-red-500 text-white rounded hover:bg-red-600 transition-colors text-xs"
|
||||
>
|
||||
<i class="fas fa-trash mr-1"></i>삭제
|
||||
</button>
|
||||
` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<p class="text-lg font-bold text-blue-600">${item.total_hours}시간</p>
|
||||
${currentUser && currentUser.role === 'admin' ? `
|
||||
<button
|
||||
onclick="deleteDailyWork(${item.id})"
|
||||
class="mt-1 px-2 py-1 bg-red-500 text-white rounded hover:bg-red-600 transition-colors text-xs"
|
||||
>
|
||||
<i class="fas fa-trash mr-1"></i>삭제
|
||||
</button>
|
||||
` : ''}
|
||||
<div class="space-y-1">
|
||||
${item.projects.map(p => `
|
||||
<div class="flex justify-between text-sm text-gray-600">
|
||||
<span>${p.projectName}</span>
|
||||
<span>${p.hours}시간</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -456,8 +539,8 @@
|
||||
}
|
||||
|
||||
// 일일 공수 삭제 (관리자만)
|
||||
async function deleteDailyWork(workId) {
|
||||
if (!currentUser || currentUser.role !== 'admin') {
|
||||
async function deleteDailyWork(date) {
|
||||
if (!currentUser || (currentUser.role !== 'admin' && currentUser.username !== 'hyungi')) {
|
||||
alert('관리자만 삭제할 수 있습니다.');
|
||||
return;
|
||||
}
|
||||
@@ -467,16 +550,23 @@
|
||||
}
|
||||
|
||||
try {
|
||||
await DailyWorkAPI.delete(workId);
|
||||
|
||||
// 성공 시 목록 다시 로드
|
||||
await loadRecentEntries();
|
||||
|
||||
alert('삭제되었습니다.');
|
||||
const index = dailyWorkData.findIndex(d => d.date === date);
|
||||
if (index >= 0) {
|
||||
dailyWorkData.splice(index, 1);
|
||||
saveDailyWorkData();
|
||||
await loadRecentEntries();
|
||||
alert('삭제되었습니다.');
|
||||
}
|
||||
} catch (error) {
|
||||
alert(error.message || '삭제에 실패했습니다.');
|
||||
alert('삭제에 실패했습니다.');
|
||||
}
|
||||
}
|
||||
|
||||
// 로그아웃
|
||||
function logout() {
|
||||
TokenManager.clearToken();
|
||||
window.location.href = '/index.html';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user