품질검사관리: - InspectionCreate 생성 폼 대폭 개선 (+269줄) - InspectionDetail 상세 페이지 확장 (+424줄) - InspectionReportModal 검사성적서 모달 기능 강화 - InspectionReportDocument 문서 구조 개선 - ProductInspectionInputModal 제품검사 입력 모달 신규 추가 - types, mockData, actions 확장 자재입고: - ReceivingDetail 수입검사 연동 기능 추가 - ImportInspectionInputModal 수입검사 입력 모달 신규 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
170 lines
4.9 KiB
TypeScript
170 lines
4.9 KiB
TypeScript
'use client';
|
|
|
|
/**
|
|
* 제품검사성적서 모달 (읽기전용)
|
|
* DocumentViewer를 사용하여 문서 표시 + 인쇄/PDF 기능 제공
|
|
* 검사 입력은 별도 ProductInspectionInputModal에서 진행
|
|
*
|
|
* 페이지네이션: 층(orderItem)별로 검사성적서 표시
|
|
*/
|
|
|
|
import { useState, useCallback, useMemo, useEffect } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
|
import { DocumentViewer } from '@/components/document-system';
|
|
import { InspectionReportDocument } from './InspectionReportDocument';
|
|
import type {
|
|
InspectionReportDocument as InspectionReportDocumentType,
|
|
OrderSettingItem,
|
|
ProductInspection
|
|
} from '../types';
|
|
import { buildReportDocumentDataForItem } from '../mockData';
|
|
|
|
interface InspectionReportModalProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
data: InspectionReportDocumentType | null;
|
|
/** 페이지네이션용: 원본 inspection 데이터 */
|
|
inspection?: ProductInspection | null;
|
|
/** 페이지네이션용: orderItems (수정 모드에서는 formData.orderItems) */
|
|
orderItems?: OrderSettingItem[];
|
|
}
|
|
|
|
export function InspectionReportModal({
|
|
open,
|
|
onOpenChange,
|
|
data,
|
|
inspection,
|
|
orderItems,
|
|
}: InspectionReportModalProps) {
|
|
const [currentPage, setCurrentPage] = useState(1);
|
|
const [inputPage, setInputPage] = useState('1');
|
|
|
|
// 총 페이지 수 (orderItems가 있으면 그 길이, 아니면 1)
|
|
const totalPages = useMemo(() => {
|
|
if (orderItems && orderItems.length > 0) {
|
|
return orderItems.length;
|
|
}
|
|
return 1;
|
|
}, [orderItems]);
|
|
|
|
// 모달 열릴 때 페이지 초기화
|
|
useEffect(() => {
|
|
if (open) {
|
|
setCurrentPage(1);
|
|
setInputPage('1');
|
|
}
|
|
}, [open]);
|
|
|
|
// 현재 페이지에 해당하는 문서 데이터
|
|
const currentData = useMemo(() => {
|
|
// 페이지네이션이 가능한 경우 (inspection과 orderItems 모두 있음)
|
|
if (inspection && orderItems && orderItems.length > 0) {
|
|
const currentItem = orderItems[currentPage - 1];
|
|
if (currentItem) {
|
|
return buildReportDocumentDataForItem(inspection, currentItem);
|
|
}
|
|
}
|
|
// 기본: data prop 사용
|
|
return data;
|
|
}, [inspection, orderItems, currentPage, data]);
|
|
|
|
// 이전 페이지
|
|
const handlePrevPage = useCallback(() => {
|
|
if (currentPage > 1) {
|
|
const newPage = currentPage - 1;
|
|
setCurrentPage(newPage);
|
|
setInputPage(String(newPage));
|
|
}
|
|
}, [currentPage]);
|
|
|
|
// 다음 페이지
|
|
const handleNextPage = useCallback(() => {
|
|
if (currentPage < totalPages) {
|
|
const newPage = currentPage + 1;
|
|
setCurrentPage(newPage);
|
|
setInputPage(String(newPage));
|
|
}
|
|
}, [currentPage, totalPages]);
|
|
|
|
// 페이지 입력 후 이동
|
|
const handleGoToPage = useCallback(() => {
|
|
const pageNum = parseInt(inputPage, 10);
|
|
if (!isNaN(pageNum) && pageNum >= 1 && pageNum <= totalPages) {
|
|
setCurrentPage(pageNum);
|
|
} else {
|
|
// 잘못된 입력 → 현재 페이지로 복원
|
|
setInputPage(String(currentPage));
|
|
}
|
|
}, [inputPage, totalPages, currentPage]);
|
|
|
|
// 엔터키로 이동
|
|
const handleKeyDown = useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
|
|
if (e.key === 'Enter') {
|
|
handleGoToPage();
|
|
}
|
|
}, [handleGoToPage]);
|
|
|
|
if (!currentData) return null;
|
|
|
|
// 페이지네이션 UI 컴포넌트
|
|
const paginationUI = totalPages > 1 ? (
|
|
<div className="flex items-center justify-center gap-2 py-3 border-t bg-gray-100 print:hidden">
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={handlePrevPage}
|
|
disabled={currentPage <= 1}
|
|
className="h-8"
|
|
>
|
|
<ChevronLeft className="w-4 h-4 mr-1" />
|
|
이전
|
|
</Button>
|
|
<div className="flex items-center gap-2">
|
|
<Input
|
|
value={inputPage}
|
|
onChange={(e) => setInputPage(e.target.value)}
|
|
onKeyDown={handleKeyDown}
|
|
className="w-14 h-8 text-center"
|
|
/>
|
|
<span className="text-sm text-muted-foreground">/ {totalPages}</span>
|
|
</div>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={handleGoToPage}
|
|
className="h-8"
|
|
>
|
|
이동
|
|
</Button>
|
|
<Button
|
|
variant="outline"
|
|
size="sm"
|
|
onClick={handleNextPage}
|
|
disabled={currentPage >= totalPages}
|
|
className="h-8"
|
|
>
|
|
다음
|
|
<ChevronRight className="w-4 h-4 ml-1" />
|
|
</Button>
|
|
</div>
|
|
) : null;
|
|
|
|
return (
|
|
<DocumentViewer
|
|
title="제품검사성적서"
|
|
preset="readonly"
|
|
open={open}
|
|
onOpenChange={onOpenChange}
|
|
pdfMeta={{
|
|
documentNumber: currentData.documentNumber,
|
|
createdDate: currentData.createdDate,
|
|
}}
|
|
toolbarExtra={paginationUI}
|
|
>
|
|
<InspectionReportDocument data={currentData} />
|
|
</DocumentViewer>
|
|
);
|
|
}
|