summaryrefslogtreecommitdiff
path: root/lib/rfq-last/table/rfq-items-dialog.tsx
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-10-30 10:35:26 +0900
committerjoonhoekim <26rote@gmail.com>2025-10-30 10:35:26 +0900
commit284f9f40d9494168f3e68eedd9af067c38362eea (patch)
treeac26b3e9fab46b996c16bfa7a7add8f26ddb5042 /lib/rfq-last/table/rfq-items-dialog.tsx
parent88f13ab89d2250e52c3375b077328a933a5762ec (diff)
(김준회) refactor: POS: 온디맨드로 다운로드받도록 변경, 매핑로직에선 pos 관련 로직 제거
Diffstat (limited to 'lib/rfq-last/table/rfq-items-dialog.tsx')
-rw-r--r--lib/rfq-last/table/rfq-items-dialog.tsx158
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>
)