diff options
Diffstat (limited to 'lib/rfq-last')
| -rw-r--r-- | lib/rfq-last/table/rfq-items-dialog.tsx | 158 |
1 files changed, 98 insertions, 60 deletions
diff --git a/lib/rfq-last/table/rfq-items-dialog.tsx b/lib/rfq-last/table/rfq-items-dialog.tsx index c640f3bd..5f8e4382 100644 --- a/lib/rfq-last/table/rfq-items-dialog.tsx +++ b/lib/rfq-last/table/rfq-items-dialog.tsx @@ -26,8 +26,8 @@ import { Separator } from "@/components/ui/separator" import { toast } from "sonner" import { RfqsLastView } from "@/db/schema" import { getRfqItemsAction } from "../service" -import { getDesignDocumentsForRfqItemsAction } from "@/lib/pos" -import { downloadFile } from "@/lib/file-download" +import { getDownloadUrlByMaterialCode, checkPosFileExists } from "@/lib/pos" +import { PosFileSelectionDialog } from "@/lib/pos/components/pos-file-selection-dialog" // 품목 타입 interface RfqItem { @@ -84,27 +84,29 @@ export function RfqItemsDialog({ isOpen, onClose, rfqData }: RfqItemsDialogProps const [items, setItems] = React.useState<RfqItem[]>([]) const [statistics, setStatistics] = React.useState<ItemStatistics | null>(null) const [isLoading, setIsLoading] = React.useState(false) - // 자재코드별 설계 문서 매핑 - const [designDocuments, setDesignDocuments] = React.useState<Record<string, { - id: number; - fileName: string; - filePath: string; - fileSize: number | null; - fileType: string | null; - description: string | null; - }>>({}) - const [isLoadingDocs, setIsLoadingDocs] = React.useState(false) + // POS 파일 선택 다이얼로그 상태 + const [posDialogOpen, setPosDialogOpen] = React.useState(false) + const [selectedMaterialCode, setSelectedMaterialCode] = React.useState<string>("") + const [posFiles, setPosFiles] = React.useState<Array<{ + fileName: string + dcmtmId: string + projNo: string + posNo: string + posRevNo: string + fileSer: string + }>>([]) + const [loadingPosFiles, setLoadingPosFiles] = React.useState(false) + const [downloadingFileIndex, setDownloadingFileIndex] = React.useState<number | null>(null) - // 품목 목록 및 설계 문서 로드 + // 품목 목록 로드 React.useEffect(() => { if (!isOpen || !rfqData.id) return const loadData = async () => { setIsLoading(true) - setIsLoadingDocs(true) try { - // 1. 품목 목록 로드 + // 품목 목록 로드 const itemsResult = await getRfqItemsAction(rfqData.id) if (itemsResult.success) { @@ -115,26 +117,14 @@ export function RfqItemsDialog({ isOpen, onClose, rfqData }: RfqItemsDialogProps setItems([]) setStatistics(null) } - - // 2. 설계 문서 매핑 로드 - const docsResult = await getDesignDocumentsForRfqItemsAction(rfqData.id) - - if (docsResult.success && docsResult.documents) { - setDesignDocuments(docsResult.documents) - } else { - console.warn("설계 문서 매핑 로드 실패:", docsResult.error) - setDesignDocuments({}) - } } catch (error) { console.error("데이터 로드 오류:", error) toast.error("데이터를 불러오는데 실패했습니다") setItems([]) setStatistics(null) - setDesignDocuments({}) } finally { setIsLoading(false) - setIsLoadingDocs(false) } } @@ -146,26 +136,74 @@ export function RfqItemsDialog({ isOpen, onClose, rfqData }: RfqItemsDialogProps window.open(specUrl, '_blank', 'noopener,noreferrer') } - // 설계 문서 다운로드 - const handleDownloadDesignDoc = async (materialCode: string, fileName: string, filePath: string) => { + // POS 파일 목록 조회 및 다이얼로그 열기 + const handleOpenPosDialog = async (materialCode: string) => { + if (!materialCode) { + toast.error("자재코드가 없습니다") + return + } + + setLoadingPosFiles(true) + setSelectedMaterialCode(materialCode) + + try { + toast.loading(`POS 파일 목록 조회 중... (${materialCode})`, { id: `pos-check-${materialCode}` }) + + const result = await checkPosFileExists(materialCode) + + if (result.exists && result.files && result.files.length > 0) { + // 파일 정보를 상세하게 가져오기 위해 getDownloadUrlByMaterialCode 사용 + const detailResult = await getDownloadUrlByMaterialCode(materialCode) + + if (detailResult.success && detailResult.availableFiles) { + setPosFiles(detailResult.availableFiles) + setPosDialogOpen(true) + toast.success(`${result.fileCount}개의 POS 파일을 찾았습니다`, { id: `pos-check-${materialCode}` }) + } else { + toast.error('POS 파일 정보를 가져올 수 없습니다', { id: `pos-check-${materialCode}` }) + } + } else { + toast.error(result.error || 'POS 파일을 찾을 수 없습니다', { id: `pos-check-${materialCode}` }) + } + } catch (error) { + console.error("POS 파일 조회 오류:", error) + toast.error("POS 파일 조회에 실패했습니다", { id: `pos-check-${materialCode}` }) + } finally { + setLoadingPosFiles(false) + } + } + + // POS 파일 다운로드 실행 + const handleDownloadPosFile = async (fileIndex: number, fileName: string) => { + if (!selectedMaterialCode) return + + setDownloadingFileIndex(fileIndex) + try { - await downloadFile(filePath, fileName, { - action: 'download', - showToast: true - }) + toast.loading(`POS 파일 다운로드 준비 중...`, { id: `download-${fileIndex}` }) + + const downloadUrl = `/api/pos/download-on-demand?materialCode=${encodeURIComponent(selectedMaterialCode)}&fileIndex=${fileIndex}` + + toast.success(`POS 파일 다운로드 시작: ${fileName}`, { id: `download-${fileIndex}` }) + window.open(downloadUrl, '_blank', 'noopener,noreferrer') + + // 다운로드 시작 후 잠시 대기 후 상태 초기화 + setTimeout(() => { + setDownloadingFileIndex(null) + }, 1000) } catch (error) { - console.error("설계 문서 다운로드 오류:", error) - toast.error("설계 문서 다운로드에 실패했습니다") + console.error("POS 파일 다운로드 오류:", error) + toast.error("POS 파일 다운로드에 실패했습니다", { id: `download-${fileIndex}` }) + setDownloadingFileIndex(null) } } - // 파일 크기 포맷팅 - const formatFileSize = (bytes: number | null) => { - if (!bytes) return "" - const sizes = ['B', 'KB', 'MB', 'GB'] - if (bytes === 0) return '0 B' - const i = Math.floor(Math.log(bytes) / Math.log(1024)) - return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i] + // POS 다이얼로그 닫기 + const handleClosePosDialog = () => { + setPosDialogOpen(false) + setSelectedMaterialCode("") + setPosFiles([]) + setDownloadingFileIndex(null) } @@ -361,23 +399,20 @@ export function RfqItemsDialog({ isOpen, onClose, rfqData }: RfqItemsDialogProps )} </div> - {/* 설계 문서 다운로드 */} - {item.materialCode && designDocuments[item.materialCode] && ( + {/* POS 파일 다운로드 */} + {item.materialCode && ( <div className="flex items-center gap-1"> - <FileText className="h-3 w-3 text-blue-500" /> + <FileText className="h-3 w-3 text-green-500" /> <Button variant="ghost" size="sm" - className="h-5 p-1 text-xs text-blue-600 hover:text-blue-800" - onClick={() => handleDownloadDesignDoc( - item.materialCode!, - designDocuments[item.materialCode!].fileName, - designDocuments[item.materialCode!].filePath - )} - title={`설계문서: ${designDocuments[item.materialCode!].fileName} (${formatFileSize(designDocuments[item.materialCode!].fileSize)})`} + className="h-5 p-1 text-xs text-green-600 hover:text-green-800" + onClick={() => handleOpenPosDialog(item.materialCode!)} + disabled={loadingPosFiles && selectedMaterialCode === item.materialCode} + title={`POS 파일 다운로드 (자재코드: ${item.materialCode})`} > <Download className="h-3 w-3 mr-1" /> - 설계문서 + {loadingPosFiles && selectedMaterialCode === item.materialCode ? '조회중...' : 'POS 다운로드'} </Button> </div> )} @@ -388,13 +423,6 @@ export function RfqItemsDialog({ isOpen, onClose, rfqData }: RfqItemsDialogProps TRK: {item.trackingNo} </div> )} - - {/* 설계 문서 로딩 상태 */} - {isLoadingDocs && item.materialCode && ( - <div className="text-xs text-muted-foreground"> - 설계문서 확인 중... - </div> - )} </div> </TableCell> <TableCell> @@ -435,6 +463,16 @@ export function RfqItemsDialog({ isOpen, onClose, rfqData }: RfqItemsDialogProps </div> </div> )} + + {/* POS 파일 선택 다이얼로그 */} + <PosFileSelectionDialog + isOpen={posDialogOpen} + onClose={handleClosePosDialog} + materialCode={selectedMaterialCode} + files={posFiles} + onDownload={handleDownloadPosFile} + downloadingIndex={downloadingFileIndex} + /> </DialogContent> </Dialog> ) |
