From 1fc9dff69f299ba7e635e53fb237baf63b1f8414 Mon Sep 17 00:00:00 2001 From: Hyungi Ahn Date: Mon, 26 Jan 2026 15:18:14 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=9E=91=EC=97=85=20=EA=B4=80=EB=A6=AC?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20=EA=B3=B5=EC=A0=95=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 추가 기능 - 공정 추가/수정/삭제 기능 구현 - 공정 관리 모달 UI 추가 - 공정 탭에 편집 버튼 추가 (✏️) ## UI 변경 - 상단에 "공정 추가" 버튼 추가 - 공정 모달: 공정명, 카테고리, 설명 입력 필드 - 각 공정 탭에 편집 아이콘 표시 ## JavaScript 함수 - openWorkTypeModal(): 공정 추가 모달 열기 - editWorkType(workTypeId): 공정 수정 모달 열기 - saveWorkType(): 공정 저장 (POST/PUT) - deleteWorkType(): 공정 삭제 (연결된 작업 확인) - closeWorkTypeModal(): 모달 닫기 ## 검증 로직 - 연결된 작업이 있는 공정은 삭제 불가 - 필수 필드(공정명) 검증 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- web-ui/js/task-management.js | 131 +++++++++++++++++++++++++++++++++- web-ui/pages/admin/tasks.html | 46 ++++++++++++ 2 files changed, 176 insertions(+), 1 deletion(-) diff --git a/web-ui/js/task-management.js b/web-ui/js/task-management.js index 88994ab..1aa1b36 100644 --- a/web-ui/js/task-management.js +++ b/web-ui/js/task-management.js @@ -103,9 +103,15 @@ function renderWorkTypeTabs() { tabsHtml += ` `; }); @@ -375,3 +381,126 @@ function showToast(message, type = 'info') { setTimeout(() => toast.remove(), 300); }, 3000); } + +// ==================== 공정 관리 ==================== + +let currentEditingWorkType = null; + +// 공정 모달 열기 (신규) +function openWorkTypeModal() { + currentEditingWorkType = null; + document.getElementById('workTypeModalTitle').textContent = '공정 추가'; + document.getElementById('workTypeId').value = ''; + document.getElementById('workTypeName').value = ''; + document.getElementById('workTypeCategory').value = ''; + document.getElementById('workTypeDescription').value = ''; + document.getElementById('deleteWorkTypeBtn').style.display = 'none'; + + document.getElementById('workTypeModal').style.display = 'flex'; + document.body.style.overflow = 'hidden'; +} +window.openWorkTypeModal = openWorkTypeModal; + +// 공정 수정 모달 열기 +async function editWorkType(workTypeId) { + try { + const workType = workTypes.find(wt => wt.id === workTypeId); + if (!workType) { + showToast('공정 정보를 찾을 수 없습니다.', 'error'); + return; + } + + currentEditingWorkType = workType; + document.getElementById('workTypeModalTitle').textContent = '공정 수정'; + document.getElementById('workTypeId').value = workType.id; + document.getElementById('workTypeName').value = workType.name || ''; + document.getElementById('workTypeCategory').value = workType.category || ''; + document.getElementById('workTypeDescription').value = workType.description || ''; + document.getElementById('deleteWorkTypeBtn').style.display = 'block'; + + document.getElementById('workTypeModal').style.display = 'flex'; + document.body.style.overflow = 'hidden'; + } catch (error) { + console.error('❌ 공정 조회 오류:', error); + showToast('공정 정보를 불러올 수 없습니다.', 'error'); + } +} +window.editWorkType = editWorkType; + +// 공정 모달 닫기 +function closeWorkTypeModal() { + document.getElementById('workTypeModal').style.display = 'none'; + document.body.style.overflow = 'auto'; + currentEditingWorkType = null; +} +window.closeWorkTypeModal = closeWorkTypeModal; + +// 공정 저장 +async function saveWorkType() { + const workTypeId = document.getElementById('workTypeId').value; + const workTypeData = { + name: document.getElementById('workTypeName').value.trim(), + category: document.getElementById('workTypeCategory').value.trim() || null, + description: document.getElementById('workTypeDescription').value.trim() || null + }; + + if (!workTypeData.name) { + showToast('공정명을 입력해주세요.', 'error'); + return; + } + + try { + let response; + if (workTypeId) { + // 수정 + response = await window.apiCall(`/daily-work-reports/work-types/${workTypeId}`, 'PUT', workTypeData); + } else { + // 신규 + response = await window.apiCall('/daily-work-reports/work-types', 'POST', workTypeData); + } + + if (response && response.success) { + showToast(workTypeId ? '공정이 수정되었습니다.' : '공정이 추가되었습니다.', 'success'); + closeWorkTypeModal(); + await loadAllData(); + } else { + throw new Error(response.message || '저장에 실패했습니다.'); + } + } catch (error) { + console.error('❌ 공정 저장 오류:', error); + showToast('공정 저장 중 오류가 발생했습니다.', 'error'); + } +} +window.saveWorkType = saveWorkType; + +// 공정 삭제 +async function deleteWorkType() { + if (!currentEditingWorkType) return; + + // 이 공정에 속한 작업이 있는지 확인 + const relatedTasks = tasks.filter(t => t.work_type_id === currentEditingWorkType.id); + if (relatedTasks.length > 0) { + showToast(`이 공정에 ${relatedTasks.length}개의 작업이 연결되어 있어 삭제할 수 없습니다.`, 'error'); + return; + } + + if (!confirm(`"${currentEditingWorkType.name}" 공정을 삭제하시겠습니까?`)) { + return; + } + + try { + const response = await window.apiCall(`/daily-work-reports/work-types/${currentEditingWorkType.id}`, 'DELETE'); + + if (response && response.success) { + showToast('공정이 삭제되었습니다.', 'success'); + closeWorkTypeModal(); + await loadAllData(); + } else { + throw new Error(response.message || '삭제에 실패했습니다.'); + } + } catch (error) { + console.error('❌ 공정 삭제 오류:', error); + showToast('공정 삭제 중 오류가 발생했습니다.', 'error'); + } +} +window.deleteWorkType = deleteWorkType; diff --git a/web-ui/pages/admin/tasks.html b/web-ui/pages/admin/tasks.html index 8bfe771..6a84889 100644 --- a/web-ui/pages/admin/tasks.html +++ b/web-ui/pages/admin/tasks.html @@ -77,6 +77,10 @@
+
+ + +