diff --git a/backend/src/modules/task/task.service.ts b/backend/src/modules/task/task.service.ts index 06101be..43f6919 100644 --- a/backend/src/modules/task/task.service.ts +++ b/backend/src/modules/task/task.service.ts @@ -1383,7 +1383,12 @@ export class TaskService { c.workStatus = ws; changed.push(c); } - return { itemId: c.id, text: c.text, category: c.category, workStatus: ws }; + return { + itemId: c.id, + text: c.text, + category: c.category, + workStatus: ws, + }; }); if (changed.length) { await this.checklistRepo.save(changed); @@ -1429,8 +1434,19 @@ export class TaskService { const existingTimes = existing.map((c) => c.checkAt.getTime()); const wantedTimes = [...new Set(dates.map((d) => new Date(d).getTime()))]; + // 보고가 있는 점검일은 삭제하지 않는다 — 보고 이력(스냅샷) 보존 + // (점검일 삭제 시 checkpoint_reports 가 CASCADE 로 함께 사라지므로 명시적으로 보호) + const reports = await this.reportRepo.find({ + where: { task: { id: task.id } }, + relations: ['checkpoint'], + }); + const reportedIds = new Set( + reports.map((r) => r.checkpoint?.id).filter((id): id is string => !!id), + ); + const toRemove = existing.filter( - (c) => !wantedTimes.includes(c.checkAt.getTime()), + (c) => + !wantedTimes.includes(c.checkAt.getTime()) && !reportedIds.has(c.id), ); if (toRemove.length) { await this.checkpointRepo.remove(toRemove); diff --git a/frontend/src/pages/relay/TaskCreatePage.vue b/frontend/src/pages/relay/TaskCreatePage.vue index 8f73345..af20acf 100644 --- a/frontend/src/pages/relay/TaskCreatePage.vue +++ b/frontend/src/pages/relay/TaskCreatePage.vue @@ -100,6 +100,13 @@ async function loadTaskForEdit() { })) existingFiles.value = t.files checkpoints.value = t.checkpoints.map((c) => toDateInput(c.checkAt)).sort() + // 보고가 접수된 점검일은 잠금(삭제 불가) — 보고 이력 보존 + const reportedCpIds = new Set(t.checkpointReports.map((r) => r.checkpointId)) + reportedCheckpointDates.value = new Set( + t.checkpoints + .filter((c) => reportedCpIds.has(c.id)) + .map((c) => toDateInput(c.checkAt)), + ) } catch { // 404 등은 인터셉터가 알림 처리 } @@ -163,6 +170,8 @@ const dueDate = ref('') // yyyy-MM-dd (input[type=date]) // --- 중간 점검일(여러 개) — 작업자가 진행 상태를 보고하는 기준일 --- const checkpoints = ref([]) // yyyy-MM-dd 목록 const newCheckpoint = ref('') +// 이미 보고가 접수된 점검일(yyyy-MM-dd) — 삭제 불가(보고 이력 보존) +const reportedCheckpointDates = ref>(new Set()) function addCheckpoint() { const d = newCheckpoint.value if (!d) return @@ -173,6 +182,8 @@ function addCheckpoint() { newCheckpoint.value = '' } function removeCheckpoint(d: string) { + // 보고가 접수된 날짜는 삭제하지 않는다(서버도 거부/보존) + if (reportedCheckpointDates.value.has(d)) return checkpoints.value = checkpoints.value.filter((x) => x !== d) } @@ -1081,7 +1092,13 @@ function goBack() { class="cp-item" > {{ d }} + 보고됨