'use client'; import { useState, useCallback, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { X, Save, Plus, Wrench, Trash2, Loader2, Pencil } 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, getDepartmentOptions, type DepartmentOption } from './actions'; // 작업일지 양식 옵션 (추후 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 [departmentOptions, setDepartmentOptions] = useState([]); const [isDepartmentsLoading, setIsDepartmentsLoading] = useState(true); // 규칙 모달 상태 const [ruleModalOpen, setRuleModalOpen] = useState(false); const [editingRule, setEditingRule] = useState(undefined); // 부서 목록 로드 useEffect(() => { const loadDepartments = async () => { setIsDepartmentsLoading(true); const result = await getDepartmentOptions(); if (result.success && result.data) { setDepartmentOptions(result.data); } setIsDepartmentsLoading(false); }; loadDepartments(); }, []); // 규칙 추가/수정 const handleSaveRule = useCallback( (ruleData: Omit) => { if (editingRule) { // 수정 모드 setClassificationRules((prev) => prev.map((r) => r.id === editingRule.id ? { ...r, ...ruleData } : r ) ); } else { // 추가 모드 const newRule: ClassificationRule = { ...ruleData, id: `rule-${Date.now()}`, createdAt: new Date().toISOString(), }; setClassificationRules((prev) => [...prev, newRule]); } setEditingRule(undefined); }, [editingRule] ); // 규칙 수정 모달 열기 const handleEditRule = useCallback((rule: ClassificationRule) => { setEditingRule(rule); setRuleModalOpen(true); }, []); // 규칙 삭제 const handleDeleteRule = useCallback((ruleId: string) => { setClassificationRules((prev) => prev.filter((r) => r.id !== ruleId)); }, []); // 모달 닫기 const handleModalClose = useCallback((open: boolean) => { setRuleModalOpen(open); if (!open) { setEditingRule(undefined); } }, []); // 제출 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, index) => { // 개별 품목인 경우 품목 개수 계산 const isIndividual = rule.registrationType === 'individual'; const itemCount = isIndividual ? rule.conditionValue.split(',').filter(Boolean).length : 0; return (
{/* 번호 */} {index + 1}.
{/* 제목 */}
{isIndividual ? ( <>개별 품목 지정 - {itemCount}개 품목 ) : ( <> {rule.ruleType}{' '} { MATCHING_TYPE_OPTIONS.find( (o) => o.value === rule.matchingType )?.label }{' '} "{rule.conditionValue}" )}
{/* 뱃지 + 우선순위 */}
{isIndividual ? `${itemCount}개 품목 배정됨` : rule.isActive ? '활성' : '비활성'} 우선순위: {rule.priority}
{/* 설명 */}
{isIndividual ? `직접 선택한 품목 ${itemCount}개` : rule.description || ''}
{/* 수정/삭제 버튼 */}
); })}
)}
{/* 작업 정보 */} 작업 정보
setRequiredWorkers(Number(e.target.value))} min={1} className="w-32" />
setEquipmentInfo(e.target.value)} placeholder="예: 미싱기 3대, 절단기 1대" />
setWorkSteps(e.target.value)} placeholder="예: 원단절단, 미싱, 핸드작업, 중간검사, 포장" />
{/* 설명 */} 설명