diff --git a/src/components/process-management/actions.ts b/src/components/process-management/actions.ts index 5dbf2971..2f780b83 100644 --- a/src/components/process-management/actions.ts +++ b/src/components/process-management/actions.ts @@ -13,6 +13,9 @@ import type { Process, ProcessFormData, ClassificationRule, IndividualItem, Proc interface ApiProcess { id: number; tenant_id: number; + parent_id: number | null; + parent?: { id: number; process_code: string; process_name: string } | null; + children?: ApiProcess[]; process_code: string; process_name: string; description: string | null; @@ -103,7 +106,10 @@ function transformApiToFrontend(apiData: ApiProcess): Process { workLogTemplateName: apiData.work_log_template_relation?.name ?? undefined, needsInspection: apiData.options?.needs_inspection ?? false, needsWorkLog: apiData.options?.needs_work_log ?? false, - processGroup: apiData.options?.process_group ?? undefined, + parentId: apiData.parent_id ? String(apiData.parent_id) : undefined, + parentProcessCode: apiData.parent?.process_code ?? undefined, + parentProcessName: apiData.parent?.process_name ?? undefined, + children: (apiData.children ?? []).map(transformProcessApiToFrontend), classificationRules: [...patternRules, ...individualRules], requiredWorkers: apiData.required_workers, equipmentInfo: apiData.equipment_info ?? undefined, diff --git a/src/components/production/WorkerScreen/index.tsx b/src/components/production/WorkerScreen/index.tsx index f1e311e5..89d69681 100644 --- a/src/components/production/WorkerScreen/index.tsx +++ b/src/components/production/WorkerScreen/index.tsx @@ -289,18 +289,26 @@ export default function WorkerScreen() { return processListCache.filter((p) => p.status === '사용중'); }, [processListCache]); - // 그룹별 탭 구성 (process_group 기준, 없으면 공정명 사용) + // 그룹별 탭 구성 (parent_id 기반 트리 구조) const groupedTabs = useMemo(() => { const groupMap = new Map(); + + // 루트 공정 기준 그룹 구성 activeProcesses.forEach((p) => { - const group = p.processGroup || p.processName; + if (p.parentId) return; // 자식은 건너뜀 + + const group = p.processName; if (!groupMap.has(group)) groupMap.set(group, []); groupMap.get(group)!.push(p); + + // 자식 공정 추가 + const children = activeProcesses.filter((c) => c.parentId === p.id); + children.forEach((c) => groupMap.get(group)!.push(c)); }); + return Array.from(groupMap.entries()).map(([group, processes]) => ({ group, processes, - // 그룹 내 첫 번째 공정 ID를 탭 value로 사용 defaultProcessId: processes[0].id, })); }, [activeProcesses]); @@ -315,8 +323,9 @@ export default function WorkerScreen() { const activeGroup = useMemo(() => { const process = processListCache.find((p) => p.id === activeTab); if (!process) return null; - const group = process.processGroup || process.processName; - return groupedTabs.find((g) => g.group === group) || null; + // 자식이면 부모 공정명, 루트면 자기 공정명 + const groupName = process.parentProcessName || process.processName; + return groupedTabs.find((g) => g.group === groupName) || null; }, [activeTab, processListCache, groupedTabs]); // 공정 목록 로드 후 첫 번째 그룹을 기본 선택 diff --git a/src/types/process.ts b/src/types/process.ts index 1cd825e8..16b90b0b 100644 --- a/src/types/process.ts +++ b/src/types/process.ts @@ -92,8 +92,11 @@ export interface Process { // 단계 목록 steps?: ProcessStep[]; - // 공정 그룹 (같은 그룹은 하나의 탭으로 표시) - processGroup?: string; + // 부모-자식 트리 구조 + parentId?: string; + parentProcessCode?: string; + parentProcessName?: string; + children?: Process[]; // 상태 status: ProcessStatus; @@ -105,6 +108,7 @@ export interface Process { // 공정 등록/수정 폼 데이터 export interface ProcessFormData { + parentId?: number; processName: string; processType: ProcessType; department: string;