'use client'; /** * 스크린 중간검사 성적서 문서 콘텐츠 * * 검사 항목: 가공상태, 재봉상태, 조립상태, 길이, 나비, 간격(OK/NG) */ import { useState, useCallback, useMemo, forwardRef, useImperativeHandle, useEffect } from 'react'; import type { WorkOrder } from '../types'; import type { InspectionData } from '@/components/production/WorkerScreen/InspectionInputModal'; import type { WorkItemData } from '@/components/production/WorkerScreen/types'; import type { InspectionDataMap } from './InspectionReportModal'; import type { InspectionSetting } from '@/types/process'; import { type CheckStatus, type GapResult, type InspectionContentRef, convertToCheckStatus, convertToGapResult, getFullDate, getToday, getOrderInfo, INPUT_CLASS, DEFAULT_ROW_COUNT, InspectionCheckbox, CheckStatusCell, InspectionLayout, InspectionFooter, InspectionStandardSection, JudgmentCell, calculateOverallResult, } from './inspection-shared'; import { formatNumber } from '@/lib/utils/amount'; export type { InspectionContentRef }; export interface ScreenInspectionContentProps { data: WorkOrder; readOnly?: boolean; inspectionData?: InspectionData; workItems?: WorkItemData[]; inspectionDataMap?: InspectionDataMap; inspectionSetting?: InspectionSetting; } interface InspectionRow { id: number; itemId?: string; itemName?: string; processStatus: CheckStatus; sewingStatus: CheckStatus; assemblyStatus: CheckStatus; lengthDesign: string; lengthMeasured: string; widthDesign: string; widthMeasured: string; gapStandard: string; gapResult: GapResult; } function buildRow(i: number, workItems?: WorkItemData[], inspectionDataMap?: InspectionDataMap): InspectionRow { const item = workItems?.[i]; const itemData = item && inspectionDataMap?.get(item.id); return { id: i + 1, itemId: item?.id, itemName: item?.itemName || '', processStatus: itemData ? convertToCheckStatus(itemData.processingStatus) : null, sewingStatus: itemData ? convertToCheckStatus(itemData.sewingStatus) : null, assemblyStatus: itemData ? convertToCheckStatus(itemData.assemblyStatus) : null, lengthDesign: '7,400', lengthMeasured: itemData?.length?.toString() || '', widthDesign: '2,950', widthMeasured: itemData?.width?.toString() || '', gapStandard: '400 이하', gapResult: itemData ? convertToGapResult(itemData.gapStatus) : null, }; } export const ScreenInspectionContent = forwardRef(function ScreenInspectionContent({ data: order, readOnly = false, workItems, inspectionDataMap, inspectionSetting, }, ref) { const schematicImage = inspectionSetting?.schematicImage; const fullDate = getFullDate(); const today = getToday(); const { documentNo, primaryAssignee } = getOrderInfo(order); const rowCount = workItems?.length || DEFAULT_ROW_COUNT; const [rows, setRows] = useState(() => Array.from({ length: rowCount }, (_, i) => buildRow(i, workItems, inspectionDataMap)) ); const [inadequateContent, setInadequateContent] = useState(''); useEffect(() => { const newRowCount = workItems?.length || DEFAULT_ROW_COUNT; setRows(Array.from({ length: newRowCount }, (_, i) => buildRow(i, workItems, inspectionDataMap))); }, [workItems, inspectionDataMap]); const handleStatusChange = useCallback((rowId: number, field: 'processStatus' | 'sewingStatus' | 'assemblyStatus', value: CheckStatus) => { if (readOnly) return; setRows(prev => prev.map(row => row.id === rowId ? { ...row, [field]: value } : row)); }, [readOnly]); const formatNumberWithComma = (value: string): string => { const num = value.replace(/[^\d]/g, ''); if (!num) return ''; return formatNumber(Number(num)); }; const handleInputChange = useCallback((rowId: number, field: 'lengthMeasured' | 'widthMeasured', value: string) => { if (readOnly) return; const numOnly = value.replace(/[^\d]/g, ''); setRows(prev => prev.map(row => row.id === rowId ? { ...row, [field]: numOnly } : row)); }, [readOnly]); const handleGapChange = useCallback((rowId: number, value: GapResult) => { if (readOnly) return; setRows(prev => prev.map(row => row.id === rowId ? { ...row, gapResult: value } : row)); }, [readOnly]); const getRowJudgment = useCallback((row: InspectionRow): '적' | '부' | null => { const { processStatus, sewingStatus, assemblyStatus, gapResult } = row; if (processStatus === '불량' || sewingStatus === '불량' || assemblyStatus === '불량' || gapResult === 'NG') return '부'; if (processStatus === '양호' && sewingStatus === '양호' && assemblyStatus === '양호' && gapResult === 'OK') return '적'; return null; }, []); const overallResult = useMemo(() => calculateOverallResult(rows.map(getRowJudgment)), [rows, getRowJudgment]); useImperativeHandle(ref, () => ({ getInspectionData: () => ({ rows: rows.map(row => ({ id: row.id, processStatus: row.processStatus, sewingStatus: row.sewingStatus, assemblyStatus: row.assemblyStatus, lengthMeasured: row.lengthMeasured, widthMeasured: row.widthMeasured, gapResult: row.gapResult, })), inadequateContent, overallResult, }), }), [rows, inadequateContent, overallResult]); return ( {/* 기본 정보 */}
제품명 스크린 제품 LOT NO {order.lotNo || '-'}
규격 와이어 글라스 코팅직물 로트크기 {order.items?.length || 0} 개소
수주처 {order.client || '-'} 검사일자 {today}
현장명 {order.projectName || '-'} 검사자 {primaryAssignee}
{/* 중간검사 기준서 */}
{schematicImage ? ( 기준서 도해 ) : (
도해 이미지 영역
)}
검사항목 검사기준 검사방법 검사주기 관련규정
가공상태 사용상 해로운 결함이 없을것 육안검사 KS F 4510 5.1항
재봉상태 내화실험 되어 견고하게
조립상태 엔도확인 견고하게 조립되어야 함 KS F 4510
n = 1, c = 0
치수
(mm)
길이 도면치수 ± 4
높이 도면치수 + 제한없음 − 40
간격 400 이하 GONO 게이지 자체규정
{/* 중간검사 DATA */}
■ 중간검사 DATA
{rows.map((row) => { const judgment = getRowJudgment(row); return ( handleStatusChange(row.id, 'processStatus', v)} readOnly={readOnly} /> handleStatusChange(row.id, 'sewingStatus', v)} readOnly={readOnly} /> handleStatusChange(row.id, 'assemblyStatus', v)} readOnly={readOnly} /> ); })}
No. 가공상태
결모양
재봉상태
결모양
조립상태 길이 (mm) 나비 (mm) 간격 (mm) 판정
(적/부)
도면치수 측정값 도면치수 측정값 기준치 측정값
{row.id} {row.lengthDesign} handleInputChange(row.id, 'lengthMeasured', e.target.value)} disabled={readOnly} className={INPUT_CLASS} placeholder="-" /> {row.widthDesign} handleInputChange(row.id, 'widthMeasured', e.target.value)} disabled={readOnly} className={INPUT_CLASS} placeholder="-" /> {row.gapStandard}
); });