2025-12-23 21:13:07 +09:00
|
|
|
'use client';
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 작업일지 모달
|
|
|
|
|
*
|
2026-01-22 15:07:17 +09:00
|
|
|
* document-system 통합 버전 (2026-01-22)
|
2026-01-29 22:56:01 +09:00
|
|
|
* 공정별 작업일지 지원 (2026-01-29)
|
2026-01-22 15:07:17 +09:00
|
|
|
* - DocumentViewer 사용
|
2026-01-29 22:56:01 +09:00
|
|
|
* - 공정 타입에 따라 스크린/슬랫/절곡 작업일지 분기
|
|
|
|
|
* - processType 미지정 시 기존 WorkLogContent (범용) 사용
|
2025-12-23 21:13:07 +09:00
|
|
|
*/
|
|
|
|
|
|
2026-01-14 15:39:07 +09:00
|
|
|
import { useState, useEffect } from 'react';
|
2026-01-22 15:07:17 +09:00
|
|
|
import { Loader2 } from 'lucide-react';
|
|
|
|
|
import { DocumentViewer } from '@/components/document-system';
|
2026-01-14 15:39:07 +09:00
|
|
|
import { getWorkOrderById } from '../WorkOrders/actions';
|
2026-01-29 22:56:01 +09:00
|
|
|
import type { WorkOrder, ProcessType } from '../WorkOrders/types';
|
2026-01-22 15:07:17 +09:00
|
|
|
import { WorkLogContent } from './WorkLogContent';
|
2026-01-29 22:56:01 +09:00
|
|
|
import {
|
|
|
|
|
ScreenWorkLogContent,
|
|
|
|
|
SlatWorkLogContent,
|
|
|
|
|
BendingWorkLogContent,
|
|
|
|
|
} from '../WorkOrders/documents';
|
2025-12-23 21:13:07 +09:00
|
|
|
|
|
|
|
|
interface WorkLogModalProps {
|
|
|
|
|
open: boolean;
|
|
|
|
|
onOpenChange: (open: boolean) => void;
|
2026-01-14 15:39:07 +09:00
|
|
|
workOrderId: string | null;
|
2026-01-29 22:56:01 +09:00
|
|
|
processType?: ProcessType;
|
2025-12-23 21:13:07 +09:00
|
|
|
}
|
|
|
|
|
|
2026-01-29 22:56:01 +09:00
|
|
|
export function WorkLogModal({ open, onOpenChange, workOrderId, processType }: WorkLogModalProps) {
|
2026-01-14 15:39:07 +09:00
|
|
|
const [order, setOrder] = useState<WorkOrder | null>(null);
|
|
|
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
|
|
2026-01-29 22:56:01 +09:00
|
|
|
// 목업 WorkOrder 생성
|
|
|
|
|
const createMockOrder = (id: string, pType?: ProcessType): WorkOrder => ({
|
|
|
|
|
id,
|
|
|
|
|
workOrderNo: 'KD-WO-260129-01',
|
|
|
|
|
lotNo: 'KD-SA-260129-01',
|
|
|
|
|
processId: 1,
|
|
|
|
|
processName: pType === 'slat' ? '슬랫' : pType === 'bending' ? '절곡' : '스크린',
|
|
|
|
|
processCode: pType || 'screen',
|
|
|
|
|
processType: pType || 'screen',
|
|
|
|
|
status: 'in_progress',
|
|
|
|
|
client: '(주)경동',
|
|
|
|
|
projectName: '서울 강남 현장',
|
|
|
|
|
dueDate: '2026-02-05',
|
|
|
|
|
assignee: '홍길동',
|
|
|
|
|
assignees: [{ id: '1', name: '홍길동', isPrimary: true }],
|
|
|
|
|
orderDate: '2026-01-20',
|
|
|
|
|
scheduledDate: '2026-01-29',
|
|
|
|
|
shipmentDate: '2026-02-05',
|
|
|
|
|
salesOrderDate: '2026-01-15',
|
|
|
|
|
isAssigned: true,
|
|
|
|
|
isStarted: true,
|
|
|
|
|
priority: 3,
|
|
|
|
|
priorityLabel: '긴급',
|
|
|
|
|
shutterCount: 12,
|
|
|
|
|
department: '생산부',
|
|
|
|
|
items: [
|
|
|
|
|
{ id: '1', no: 1, status: 'in_progress', productName: '와이어 스크린', floorCode: '1층/FSS-01', specification: '8,260 X 8,350', quantity: 2, unit: 'EA' },
|
|
|
|
|
{ id: '2', no: 2, status: 'waiting', productName: '메쉬 스크린', floorCode: '2층/FSS-03', specification: '6,400 X 5,200', quantity: 4, unit: 'EA' },
|
|
|
|
|
{ id: '3', no: 3, status: 'completed', productName: '광폭 와이어', floorCode: '3층/FSS-05', specification: '12,000 X 4,500', quantity: 1, unit: 'EA' },
|
|
|
|
|
],
|
|
|
|
|
currentStep: { key: 'cutting', label: '절단', order: 2 },
|
|
|
|
|
completedSteps: ['material_input'],
|
|
|
|
|
totalProgress: 25,
|
|
|
|
|
issues: [],
|
|
|
|
|
memo: '',
|
|
|
|
|
createdAt: '2026-01-20T09:00:00',
|
|
|
|
|
updatedAt: '2026-01-29T14:00:00',
|
|
|
|
|
});
|
|
|
|
|
|
2026-01-14 15:39:07 +09:00
|
|
|
// 모달 열릴 때 데이터 fetch
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (open && workOrderId) {
|
2026-01-29 22:56:01 +09:00
|
|
|
// 목업 ID인 경우 API 호출 생략
|
|
|
|
|
if (workOrderId.startsWith('mock-')) {
|
|
|
|
|
setOrder(createMockOrder(workOrderId, processType));
|
|
|
|
|
setError(null);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-14 15:39:07 +09:00
|
|
|
setIsLoading(true);
|
|
|
|
|
setError(null);
|
|
|
|
|
|
|
|
|
|
getWorkOrderById(workOrderId)
|
|
|
|
|
.then((result) => {
|
|
|
|
|
if (result.success && result.data) {
|
|
|
|
|
setOrder(result.data);
|
|
|
|
|
} else {
|
|
|
|
|
setError(result.error || '데이터를 불러올 수 없습니다.');
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch(() => {
|
|
|
|
|
setError('서버 오류가 발생했습니다.');
|
|
|
|
|
})
|
|
|
|
|
.finally(() => {
|
|
|
|
|
setIsLoading(false);
|
|
|
|
|
});
|
|
|
|
|
} else if (!open) {
|
|
|
|
|
// 모달 닫힐 때 상태 초기화
|
|
|
|
|
setOrder(null);
|
|
|
|
|
setError(null);
|
|
|
|
|
}
|
2026-01-29 22:56:01 +09:00
|
|
|
}, [open, workOrderId, processType]);
|
2026-01-14 15:39:07 +09:00
|
|
|
|
|
|
|
|
if (!workOrderId) return null;
|
|
|
|
|
|
2026-01-22 15:07:17 +09:00
|
|
|
// 로딩/에러 상태는 DocumentViewer 내부에서 처리
|
|
|
|
|
const subtitle = order ? `${order.processName} 생산부서` : undefined;
|
2025-12-23 21:13:07 +09:00
|
|
|
|
2026-01-29 22:56:01 +09:00
|
|
|
// 공정 타입에 따라 콘텐츠 분기
|
|
|
|
|
const renderContent = () => {
|
|
|
|
|
if (!order) return null;
|
|
|
|
|
|
|
|
|
|
// processType prop 또는 order의 processType 사용
|
|
|
|
|
const type = processType || order.processType;
|
|
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 'screen':
|
|
|
|
|
return <ScreenWorkLogContent data={order} />;
|
|
|
|
|
case 'slat':
|
|
|
|
|
return <SlatWorkLogContent data={order} />;
|
|
|
|
|
case 'bending':
|
|
|
|
|
return <BendingWorkLogContent data={order} />;
|
|
|
|
|
default:
|
|
|
|
|
return <WorkLogContent data={order} />;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-12-23 21:13:07 +09:00
|
|
|
return (
|
2026-01-22 15:07:17 +09:00
|
|
|
<DocumentViewer
|
|
|
|
|
title="작업일지"
|
|
|
|
|
subtitle={subtitle}
|
|
|
|
|
preset="inspection"
|
|
|
|
|
open={open}
|
|
|
|
|
onOpenChange={onOpenChange}
|
|
|
|
|
>
|
|
|
|
|
{isLoading ? (
|
|
|
|
|
<div className="flex items-center justify-center h-64 bg-white">
|
|
|
|
|
<Loader2 className="w-8 h-8 animate-spin text-muted-foreground" />
|
2025-12-23 21:13:07 +09:00
|
|
|
</div>
|
2026-01-22 15:07:17 +09:00
|
|
|
) : error || !order ? (
|
|
|
|
|
<div className="flex flex-col items-center justify-center h-64 gap-4 bg-white">
|
|
|
|
|
<p className="text-muted-foreground">{error || '데이터를 불러올 수 없습니다.'}</p>
|
2025-12-23 21:13:07 +09:00
|
|
|
</div>
|
2026-01-22 15:07:17 +09:00
|
|
|
) : (
|
2026-01-29 22:56:01 +09:00
|
|
|
renderContent()
|
2026-01-22 15:07:17 +09:00
|
|
|
)}
|
|
|
|
|
</DocumentViewer>
|
2025-12-23 21:13:07 +09:00
|
|
|
);
|
2026-01-22 15:07:17 +09:00
|
|
|
}
|