feat: v2.2.0 - 중복 카드 문제 해결 및 삭제 기능 개선

### 주요 변경사항

1. 작업 현황 모달 중복 카드 문제 근본 해결
   - monthlyStatusModel.getDailyWorkerStatus() 리팩토링
   - 집계 테이블 대신 daily_work_reports에서 직접 조회
   - GROUP BY로 작업자별 1개 카드 보장

2. 삭제 권한 강화
   - 작업보고서 삭제는 그룹장/시스템/관리자만 가능
   - 권한 없는 사용자는 403 에러 반환

3. 작업 입력 UI 개선
   - 작업 항목 삭제 버튼 스타일 개선 (이모지 + 빨간색)
   - 삭제 버튼 호버 효과 추가

4. 작업 현황 모달에 삭제 기능 추가
   - 관리자/그룹장만 삭제 버튼 표시
   - 작업자의 해당 날짜 전체 작업 삭제 가능

5. 시놀로지 배포 스크립트 추가
   - update.sh: DB 보존하면서 코드만 업데이트
   - 안전한 배포 절차 자동화
This commit is contained in:
Hyungi Ahn
2025-12-02 13:33:24 +09:00
parent a9bce9d20b
commit a2669e08c4
16 changed files with 420 additions and 64 deletions

View File

@@ -591,6 +591,17 @@ async function renderModalDataFromSummary(workers, summary) {
// 작업자 이름의 첫 글자 추출
const initial = worker.workerName ? worker.workerName.charAt(0) : '?';
// 관리자/그룹장 권한 확인
const currentUser = JSON.parse(localStorage.getItem('user') || '{}');
const isAdmin = ['admin', 'system', 'group_leader'].includes(currentUser.access_level || currentUser.role);
// 삭제 버튼 (관리자/그룹장만 표시, 작업이 있는 경우에만)
const deleteBtn = isAdmin && worker.totalWorkCount > 0 ? `
<button class="btn-delete-worker-work" onclick="event.stopPropagation(); deleteWorkerDayWork(${worker.workerId}, '${currentModalDate}', '${worker.workerName}')" title="이 작업자의 해당 날짜 작업 전체 삭제">
🗑️
</button>
` : '';
return `
<div class="worker-card ${statusClass}" onclick="openWorkerModal(${worker.workerId}, '${currentModalDate}')">
<div class="worker-avatar">
@@ -618,6 +629,7 @@ async function renderModalDataFromSummary(workers, summary) {
</div>
</div>
<div class="worker-actions">
${deleteBtn}
<button class="btn-work-entry" onclick="event.stopPropagation(); openWorkerModal(${worker.workerId}, '${currentModalDate}')" title="작업입력">
작업입력
</button>
@@ -813,6 +825,40 @@ function showToast(message, type = 'info') {
}, 3000);
}
// 작업자의 해당 날짜 작업 전체 삭제 (관리자/그룹장용)
async function deleteWorkerDayWork(workerId, date, workerName) {
// 확인 대화상자
const confirmed = confirm(
`⚠️ 정말로 삭제하시겠습니까?\n\n` +
`작업자: ${workerName}\n` +
`날짜: ${date}\n\n` +
`이 작업자의 해당 날짜 모든 작업이 삭제됩니다.\n` +
`삭제된 작업은 복구할 수 없습니다.`
);
if (!confirmed) return;
try {
showToast('작업을 삭제하는 중...', 'info');
// 날짜+작업자별 전체 삭제 API 호출
const result = await window.apiCall(`/daily-work-reports/date/${date}/worker/${workerId}`, 'DELETE');
console.log('✅ 작업 삭제 성공:', result);
showToast(`${workerName}${date} 작업이 삭제되었습니다.`, 'success');
// 모달 데이터 새로고침
await openDailyWorkModal(currentModalDate);
// 캘린더도 새로고침
await loadCalendarData();
} catch (error) {
console.error('❌ 작업 삭제 실패:', error);
showToast(`작업 삭제 실패: ${error.message}`, 'error');
}
}
// 작업자 개별 작업 모달 열기
async function openWorkerModal(workerId, date) {
try {