'use client'; import { useState, useCallback } from 'react'; import { useRouter } from 'next/navigation'; import { X, Save, Plus, Wrench, Trash2, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Textarea } from '@/components/ui/textarea'; import { Checkbox } from '@/components/ui/checkbox'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { PageLayout } from '@/components/organisms/PageLayout'; import { RuleModal } from './RuleModal'; import { toast } from 'sonner'; import type { Process, ClassificationRule, ProcessType } from '@/types/process'; import { PROCESS_TYPE_OPTIONS, MATCHING_TYPE_OPTIONS } from '@/types/process'; import { createProcess, updateProcess } from './actions'; // 담당부서 옵션 (추후 API 연동 가능) const DEPARTMENT_OPTIONS = [ { value: '스크린생산부서', label: '스크린생산부서' }, { value: '절곡생산부서', label: '절곡생산부서' }, { value: '슬랫생산부서', label: '슬랫생산부서' }, { value: '품질관리부서', label: '품질관리부서' }, { value: '포장/출하부서', label: '포장/출하부서' }, ]; // 작업일지 양식 옵션 (추후 API 연동 가능) const WORK_LOG_OPTIONS = [ { value: '스크린 작업일지', label: '스크린 작업일지' }, { value: '절곡 작업일지', label: '절곡 작업일지' }, { value: '슬랫 작업일지', label: '슬랫 작업일지' }, { value: '재고생산 작업일지', label: '재고생산 작업일지' }, { value: '포장 작업일지', label: '포장 작업일지' }, ]; interface ProcessFormProps { mode: 'create' | 'edit'; initialData?: Process; } export function ProcessForm({ mode, initialData }: ProcessFormProps) { const router = useRouter(); const isEdit = mode === 'edit'; // 폼 상태 const [processName, setProcessName] = useState(initialData?.processName || ''); const [processType, setProcessType] = useState( initialData?.processType || '생산' ); const [department, setDepartment] = useState(initialData?.department || ''); const [workLogTemplate, setWorkLogTemplate] = useState( initialData?.workLogTemplate || '' ); const [classificationRules, setClassificationRules] = useState( initialData?.classificationRules || [] ); const [requiredWorkers, setRequiredWorkers] = useState( initialData?.requiredWorkers || 1 ); const [equipmentInfo, setEquipmentInfo] = useState(initialData?.equipmentInfo || ''); const [workSteps, setWorkSteps] = useState(initialData?.workSteps?.join(', ') || ''); const [note, setNote] = useState(initialData?.note || ''); const [isActive, setIsActive] = useState(initialData ? initialData.status === '사용중' : true); const [isLoading, setIsLoading] = useState(false); // 규칙 모달 상태 const [ruleModalOpen, setRuleModalOpen] = useState(false); // 규칙 추가 const handleAddRule = useCallback( (ruleData: Omit) => { const newRule: ClassificationRule = { ...ruleData, id: `rule-${Date.now()}`, createdAt: new Date().toISOString(), }; setClassificationRules((prev) => [...prev, newRule]); }, [] ); // 규칙 삭제 const handleDeleteRule = useCallback((ruleId: string) => { setClassificationRules((prev) => prev.filter((r) => r.id !== ruleId)); }, []); // 제출 const handleSubmit = async () => { if (!processName.trim()) { toast.error('공정명을 입력해주세요.'); return; } if (!department) { toast.error('담당부서를 선택해주세요.'); return; } const formData = { processName: processName.trim(), processType, department, workLogTemplate: workLogTemplate || undefined, classificationRules: classificationRules.map((rule) => ({ registrationType: rule.registrationType, ruleType: rule.ruleType, matchingType: rule.matchingType, conditionValue: rule.conditionValue, priority: rule.priority, description: rule.description, isActive: rule.isActive, })), requiredWorkers, equipmentInfo: equipmentInfo.trim() || undefined, workSteps: workSteps, note: note.trim() || undefined, isActive, }; setIsLoading(true); try { if (isEdit && initialData?.id) { const result = await updateProcess(initialData.id, formData); if (result.success) { toast.success('공정이 수정되었습니다.'); router.push('/ko/master-data/process-management'); } else { toast.error(result.error || '수정에 실패했습니다.'); } } else { const result = await createProcess(formData); if (result.success) { toast.success('공정이 등록되었습니다.'); router.push('/ko/master-data/process-management'); } else { toast.error(result.error || '등록에 실패했습니다.'); } } } catch { toast.error('처리 중 오류가 발생했습니다.'); } finally { setIsLoading(false); } }; // 취소 const handleCancel = () => { router.back(); }; return ( {/* 헤더 */}

공정 {isEdit ? '수정' : '등록'}

{/* 기본 정보 */} 기본 정보
setProcessName(e.target.value)} placeholder="예: 스크린" />
{/* 자동 분류 규칙 */}
자동 분류 규칙

품목이 이 공정에 이동으로 분류되는 규칙을 생성합니다.

{classificationRules.length === 0 ? (

품목별 규칙이 없습니다

규칙을 추가하면 해당 패턴의 품목이 이 공정으로 분류됩니다

) : (
{classificationRules.map((rule) => (
{rule.isActive ? '활성' : '비활성'}
{rule.ruleType}{' '} { MATCHING_TYPE_OPTIONS.find( (o) => o.value === rule.matchingType )?.label }{' '} "{rule.conditionValue}"
{rule.description && (
{rule.description}
)}
우선순위: {rule.priority}
))}
)}
{/* 작업 정보 */} 작업 정보
setRequiredWorkers(Number(e.target.value))} min={1} className="w-32" />
setEquipmentInfo(e.target.value)} placeholder="예: 미싱기 3대, 절단기 1대" />
setWorkSteps(e.target.value)} placeholder="예: 원단절단, 미싱, 핸드작업, 중간검사, 포장" />
{/* 설명 */} 설명