"use client"; import React, { useState, useEffect, useCallback } from "react"; import { apiClient } from "@/lib/api/client"; /* ------------------------------------------------------------------ */ /* Types */ /* ------------------------------------------------------------------ */ export interface InspectionItem { id: string; inspection_item_name: string; inspection_standard: string; inspection_method: string; pass_criteria: string; is_required: string; /** User-entered measured value */ measured_value: string; /** "pass" | "fail" | null */ result: "pass" | "fail" | null; } export interface InspectionResult { items: InspectionItem[]; goodQty: number; badQty: number; remark: string; completed: boolean; } interface InspectionModalProps { open: boolean; onClose: () => void; onComplete: (result: InspectionResult) => void; itemCode: string; itemName: string; totalQty: number; initialResult?: InspectionResult | null; } /* ------------------------------------------------------------------ */ /* Dummy inspection items (fallback) */ /* ------------------------------------------------------------------ */ const DUMMY_INSPECTION_ITEMS: InspectionItem[] = [ { id: "dummy-1", inspection_item_name: "외관 검사", inspection_standard: "스크래치, 변색, 찍힘 없음", inspection_method: "육안 검사", pass_criteria: "이상 없음", is_required: "Y", measured_value: "", result: null, }, { id: "dummy-2", inspection_item_name: "치수 검사", inspection_standard: "규격 +-0.5mm", inspection_method: "캘리퍼스 측정", pass_criteria: "허용 오차 이내", is_required: "Y", measured_value: "", result: null, }, { id: "dummy-3", inspection_item_name: "수량 검사", inspection_standard: "발주 수량과 일치", inspection_method: "전수 검사", pass_criteria: "수량 일치", is_required: "Y", measured_value: "", result: null, }, { id: "dummy-4", inspection_item_name: "포장 상태", inspection_standard: "포장 손상 없음", inspection_method: "육안 검사", pass_criteria: "이상 없음", is_required: "", measured_value: "", result: null, }, ]; /* ------------------------------------------------------------------ */ /* Component */ /* ------------------------------------------------------------------ */ export function InspectionModal({ open, onClose, onComplete, itemCode, itemName, totalQty, initialResult, }: InspectionModalProps) { const [inspItems, setInspItems] = useState([]); const [loading, setLoading] = useState(false); const [goodQty, setGoodQty] = useState(0); const [badQty, setBadQty] = useState(0); const [remark, setRemark] = useState(""); /* Fetch inspection items from DB */ const fetchInspectionItems = useCallback(async () => { setLoading(true); try { const res = await apiClient.get("/pop/execute-action", { params: { taskType: "data-list", targetTable: "item_inspection_info", filters: JSON.stringify({ item_code: itemCode }), pageSize: "50", }, }); const data = res.data?.data; if (Array.isArray(data) && data.length > 0) { setInspItems( data.map((r: Record) => ({ id: String(r.id ?? ""), inspection_item_name: String(r.inspection_item_name ?? ""), inspection_standard: String(r.inspection_standard ?? ""), inspection_method: String(r.inspection_method ?? ""), pass_criteria: String(r.pass_criteria ?? ""), is_required: String(r.is_required ?? ""), measured_value: "", result: null, })) ); } else { setInspItems(DUMMY_INSPECTION_ITEMS.map((i) => ({ ...i }))); } } catch { setInspItems(DUMMY_INSPECTION_ITEMS.map((i) => ({ ...i }))); } finally { setLoading(false); } }, [itemCode]); /* Init on open */ useEffect(() => { if (!open) return; if (initialResult) { setInspItems(initialResult.items.map((i) => ({ ...i }))); setGoodQty(initialResult.goodQty); setBadQty(initialResult.badQty); setRemark(initialResult.remark); } else { fetchInspectionItems(); setGoodQty(totalQty); setBadQty(0); setRemark(""); } }, [open, initialResult, fetchInspectionItems, totalQty]); /* Update item */ const updateItem = (id: string, field: "measured_value" | "result", value: string) => { setInspItems((prev) => prev.map((item) => item.id === id ? { ...item, [field]: field === "result" ? (item.result === value ? null : value) : value } : item ) ); }; /* Handle good/bad qty sync */ const handleGoodQtyChange = (val: number) => { const v = Math.max(0, Math.min(val, totalQty)); setGoodQty(v); setBadQty(totalQty - v); }; const handleBadQtyChange = (val: number) => { const v = Math.max(0, Math.min(val, totalQty)); setBadQty(v); setGoodQty(totalQty - v); }; /* Complete */ const handleComplete = () => { onComplete({ items: inspItems, goodQty, badQty, remark, completed: true, }); onClose(); }; if (!open) return null; return (
{/* Full-screen slide panel */}
{/* Header */}

자주검사

{/* Scrollable body */}
{/* Item summary */}
{itemCode} {itemName} {totalQty.toLocaleString()} EA
{/* Inspection items section */}

검사 항목

{inspItems.length}개
{loading ? (
불러오는 중...
) : inspItems.length === 0 ? (
등록된 검사 항목이 없습니다
) : (
{inspItems.map((item) => (
{/* Item header */}
{item.inspection_item_name} {item.is_required === "Y" && ( 필수 )}
{/* Info grid */}
{item.inspection_standard && ( <> 기준 {item.inspection_standard} )} {item.inspection_method && ( <> 방법 {item.inspection_method} )} {item.pass_criteria && ( <> 판정 {item.pass_criteria} )}
{/* Input + result buttons */}
updateItem(item.id, "measured_value", e.target.value)} placeholder="측정값 입력" className="flex-1 h-9 px-2.5 text-[13px] border border-gray-200 rounded-md outline-none focus:border-blue-400 focus:ring-1 focus:ring-blue-100" />
{/* Camera placeholder */}
))}
)}
{/* Final judgment section */}

종합 판정

{/* Good / Bad qty */}
handleGoodQtyChange(parseInt(e.target.value, 10) || 0)} className="flex-1 min-w-0 h-10 px-2 text-center text-sm font-semibold border-2 border-green-400 rounded-lg bg-green-50 text-green-700 outline-none focus:ring-2 focus:ring-green-200" /> EA
handleBadQtyChange(parseInt(e.target.value, 10) || 0)} className="flex-1 min-w-0 h-10 px-2 text-center text-sm font-semibold border-2 border-red-400 rounded-lg bg-red-50 text-red-700 outline-none focus:ring-2 focus:ring-red-200" /> EA
{/* Total summary */}
전체 수량 {totalQty.toLocaleString()} EA
{/* Remark */}

비고