diff options
Diffstat (limited to 'lib/rfq-last/vendor')
| -rw-r--r-- | lib/rfq-last/vendor/rfq-vendor-table.tsx | 223 |
1 files changed, 162 insertions, 61 deletions
diff --git a/lib/rfq-last/vendor/rfq-vendor-table.tsx b/lib/rfq-last/vendor/rfq-vendor-table.tsx index 830fd448..d451b2ba 100644 --- a/lib/rfq-last/vendor/rfq-vendor-table.tsx +++ b/lib/rfq-last/vendor/rfq-vendor-table.tsx @@ -27,7 +27,9 @@ import { Info, Loader2, Router, - Shield + Shield, + CheckSquare, + GitCompare } from "lucide-react"; import { format } from "date-fns"; import { ko } from "date-fns/locale"; @@ -59,6 +61,7 @@ import { getRfqSendData, getSelectedVendorsWithEmails, sendRfqToVendors, + updateShortList, type RfqSendData, type VendorEmailInfo } from "../service" @@ -278,7 +281,7 @@ export function RfqVendorTable({ }); const [editContractVendor, setEditContractVendor] = React.useState<any | null>(null); - + const [isUpdatingShortList, setIsUpdatingShortList] = React.useState(false); const router = useRouter() @@ -290,6 +293,51 @@ export function RfqVendorTable({ console.log(mergedData, "mergedData") + // Short List 확정 핸들러 + const handleShortListConfirm = React.useCallback(async () => { + + try { + setIsUpdatingShortList(true); + + const vendorIds = selectedRows + .map(vendor => vendor.vendorId) + .filter(id => id != null); + + const result = await updateShortList(rfqId, vendorIds, true); + + if (result.success) { + toast.success(`${result.updatedCount}개 벤더를 Short List로 확정했습니다.`); + setSelectedRows([]); + router.refresh(); + } + } catch (error) { + console.error("Short List 확정 실패:", error); + toast.error("Short List 확정에 실패했습니다."); + } finally { + setIsUpdatingShortList(false); + } + }, [selectedRows, rfqId, router]); + + // 견적 비교 핸들러 + const handleQuotationCompare = React.useCallback(() => { + const vendorsWithQuotation = selectedRows.filter(row => + row.response?.submission?.submittedAt + ); + + if (vendorsWithQuotation.length < 2) { + toast.warning("비교를 위해 최소 2개 이상의 견적서가 필요합니다."); + return; + } + + // 견적 비교 페이지로 이동 또는 모달 열기 + const vendorIds = vendorsWithQuotation + .map(v => v.vendorId) + .filter(id => id != null) + .join(','); + + router.push(`/evcp/rfq-last/${rfqId}/compare?vendors=${vendorIds}`); + }, [selectedRows, rfqId, router]); + // 일괄 발송 핸들러 const handleBulkSend = React.useCallback(async () => { if (selectedRows.length === 0) { @@ -302,6 +350,7 @@ export function RfqVendorTable({ // 선택된 벤더 ID들 추출 const selectedVendorIds = selectedRows + .filter(v=>v.shortList) .map(row => row.vendorId) .filter(id => id != null); @@ -1142,65 +1191,117 @@ export function RfqVendorTable({ }, [selectedRows]); // 추가 액션 버튼들 - const additionalActions = React.useMemo(() => ( - <div className="flex items-center gap-2"> - <Button - variant="outline" - size="sm" - onClick={() => setIsAddDialogOpen(true)} - disabled={isLoadingSendData} - > - <Plus className="h-4 w-4 mr-2" /> - 벤더 추가 - </Button> - {selectedRows.length > 0 && ( - <> - <Button - variant="outline" - size="sm" - onClick={() => setIsBatchUpdateOpen(true)} - disabled={isLoadingSendData} - > - <Settings2 className="h-4 w-4 mr-2" /> - 정보 일괄 입력 ({selectedRows.length}) - </Button> - <Button - variant="outline" - size="sm" - onClick={handleBulkSend} - disabled={isLoadingSendData || selectedRows.length === 0} - > - {isLoadingSendData ? ( - <> - <Loader2 className="mr-2 h-4 w-4 animate-spin" /> - 데이터 준비중... - </> - ) : ( - <> - <Send className="h-4 w-4 mr-2" /> - RFQ 발송 ({selectedRows.length}) - </> - )} - </Button> - </> - )} - <Button - variant="outline" - size="sm" - onClick={() => { - setIsRefreshing(true); - setTimeout(() => { - setIsRefreshing(false); - toast.success("데이터를 새로고침했습니다."); - }, 1000); - }} - disabled={isRefreshing || isLoadingSendData} - > - <RefreshCw className={cn("h-4 w-4 mr-2", isRefreshing && "animate-spin")} /> - 새로고침 - </Button> - </div> - ), [selectedRows, isRefreshing, isLoadingSendData, handleBulkSend]); + const additionalActions = React.useMemo(() => { + + // 참여 의사가 있는 선택된 벤더 수 계산 + const participatingCount = selectedRows.length; + const shortListCount = selectedRows.filter(v=>v.shortList).length; + + // 견적서가 있는 선택된 벤더 수 계산 + const quotationCount = selectedRows.filter(row => + row.response?.submission?.submittedAt + ).length; + + return ( + <div className="flex items-center gap-2"> + <Button + variant="outline" + size="sm" + onClick={() => setIsAddDialogOpen(true)} + disabled={isLoadingSendData} + > + <Plus className="h-4 w-4 mr-2" /> + 벤더 추가 + </Button> + + {selectedRows.length > 0 && ( + <> + {/* Short List 확정 버튼 */} + <Button + variant="outline" + size="sm" + onClick={handleShortListConfirm} + disabled={isUpdatingShortList } + // className={ "border-green-500 text-green-600 hover:bg-green-50" } + > + {isUpdatingShortList ? ( + <> + <Loader2 className="mr-2 h-4 w-4 animate-spin" /> + 처리중... + </> + ) : ( + <> + <CheckSquare className="h-4 w-4 mr-2" /> + Short List 확정 + {participatingCount > 0 && ` (${participatingCount})`} + </> + )} + </Button> + + {/* 견적 비교 버튼 */} + <Button + variant="outline" + size="sm" + onClick={handleQuotationCompare} + disabled={quotationCount < 1} + className={quotationCount >= 2 ? "border-blue-500 text-blue-600 hover:bg-blue-50" : ""} + > + <GitCompare className="h-4 w-4 mr-2" /> + 견적 비교 + {quotationCount > 0 && ` (${quotationCount})`} + </Button> + + {/* 정보 일괄 입력 버튼 */} + <Button + variant="outline" + size="sm" + onClick={() => setIsBatchUpdateOpen(true)} + disabled={isLoadingSendData} + > + <Settings2 className="h-4 w-4 mr-2" /> + 정보 일괄 입력 ({selectedRows.length}) + </Button> + + {/* RFQ 발송 버튼 */} + <Button + variant="outline" + size="sm" + onClick={handleBulkSend} + disabled={isLoadingSendData || selectedRows.length === 0} + > + {isLoadingSendData ? ( + <> + <Loader2 className="mr-2 h-4 w-4 animate-spin" /> + 데이터 준비중... + </> + ) : ( + <> + <Send className="h-4 w-4 mr-2" /> + RFQ 발송 ({shortListCount}) + </> + )} + </Button> + </> + )} + + <Button + variant="outline" + size="sm" + onClick={() => { + setIsRefreshing(true); + setTimeout(() => { + setIsRefreshing(false); + toast.success("데이터를 새로고침했습니다."); + }, 1000); + }} + disabled={isRefreshing || isLoadingSendData} + > + <RefreshCw className={cn("h-4 w-4 mr-2", isRefreshing && "animate-spin")} /> + 새로고침 + </Button> + </div> + ); + }, [selectedRows, isRefreshing, isLoadingSendData, handleBulkSend, handleShortListConfirm, handleQuotationCompare, isUpdatingShortList]); return ( <> |
