diff options
Diffstat (limited to 'lib/rfq-last/vendor')
| -rw-r--r-- | lib/rfq-last/vendor/batch-update-conditions-dialog.tsx | 59 | ||||
| -rw-r--r-- | lib/rfq-last/vendor/rfq-vendor-table.tsx | 118 | ||||
| -rw-r--r-- | lib/rfq-last/vendor/send-rfq-dialog.tsx | 9 | ||||
| -rw-r--r-- | lib/rfq-last/vendor/vendor-detail-dialog.tsx | 4 |
4 files changed, 137 insertions, 53 deletions
diff --git a/lib/rfq-last/vendor/batch-update-conditions-dialog.tsx b/lib/rfq-last/vendor/batch-update-conditions-dialog.tsx index af38ff45..893fd9a3 100644 --- a/lib/rfq-last/vendor/batch-update-conditions-dialog.tsx +++ b/lib/rfq-last/vendor/batch-update-conditions-dialog.tsx @@ -128,6 +128,7 @@ export function BatchUpdateConditionsDialog({ const [shippingOpen, setShippingOpen] = React.useState(false); const [destinationOpen, setDestinationOpen] = React.useState(false); const [calendarOpen, setCalendarOpen] = React.useState(false); + const [currencyOpen, setCurrencyOpen] = React.useState(false); // 체크박스로 각 필드 업데이트 여부 관리 const [fieldsToUpdate, setFieldsToUpdate] = React.useState({ @@ -381,7 +382,28 @@ export function BatchUpdateConditionsDialog({ {/* 기본 조건 설정 */} <Card> <CardHeader> - <CardTitle className="text-lg">기본 조건</CardTitle> + <div className="flex items-center justify-between"> + <CardTitle className="text-lg">기본 조건</CardTitle> + <Button + type="button" + variant="outline" + size="sm" + onClick={() => { + // 기본조건만 전체 선택/해제 + const basicFields = ['currency', 'paymentTermsCode', 'incoterms', 'deliveryDate', 'contractDuration', 'taxCode', 'shipping']; + const allBasicSelected = basicFields.every(field => fieldsToUpdate[field as keyof typeof fieldsToUpdate]); + const newState = { ...fieldsToUpdate }; + + basicFields.forEach(field => { + newState[field as keyof typeof newState] = !allBasicSelected; + }); + + setFieldsToUpdate(newState); + }} + > + {['currency', 'paymentTermsCode', 'incoterms', 'deliveryDate', 'contractDuration', 'taxCode', 'shipping'].every(field => fieldsToUpdate[field as keyof typeof fieldsToUpdate]) ? '전체 해제' : '전체 선택'} + </Button> + </div> </CardHeader> <CardContent className="space-y-4"> {/* 통화 */} @@ -405,11 +427,12 @@ export function BatchUpdateConditionsDialog({ </FormLabel> <div className="col-span-2"> <FormControl> - <Popover> + <Popover open={currencyOpen} onOpenChange={setCurrencyOpen}> <PopoverTrigger asChild> <Button variant="outline" role="combobox" + aria-expanded={currencyOpen} className="w-full justify-between" disabled={!fieldsToUpdate.currency} > @@ -433,7 +456,10 @@ export function BatchUpdateConditionsDialog({ <CommandItem key={currency} value={currency} - onSelect={() => field.onChange(currency)} + onSelect={() => { + field.onChange(currency); + setCurrencyOpen(false); + }} > {currency} <Check @@ -1017,9 +1043,12 @@ export function BatchUpdateConditionsDialog({ <div className="flex items-center gap-4"> <Checkbox checked={fieldsToUpdate.materialPrice} - onCheckedChange={(checked) => - setFieldsToUpdate({ ...fieldsToUpdate, materialPrice: !!checked }) - } + onCheckedChange={(checked) => { + setFieldsToUpdate({ ...fieldsToUpdate, materialPrice: !!checked }); + if (checked) { + form.setValue("materialPriceRelatedYn", true); + } + }} /> <FormField control={form.control} @@ -1053,9 +1082,12 @@ export function BatchUpdateConditionsDialog({ <div className="flex items-center gap-4"> <Checkbox checked={fieldsToUpdate.sparepart} - onCheckedChange={(checked) => - setFieldsToUpdate({ ...fieldsToUpdate, sparepart: !!checked }) - } + onCheckedChange={(checked) => { + setFieldsToUpdate({ ...fieldsToUpdate, sparepart: !!checked }); + if (checked) { + form.setValue("sparepartYn", true); + } + }} /> <FormField control={form.control} @@ -1108,9 +1140,12 @@ export function BatchUpdateConditionsDialog({ <div className="flex items-center gap-4"> <Checkbox checked={fieldsToUpdate.first} - onCheckedChange={(checked) => - setFieldsToUpdate({ ...fieldsToUpdate, first: !!checked }) - } + onCheckedChange={(checked) => { + setFieldsToUpdate({ ...fieldsToUpdate, first: !!checked }); + if (checked) { + form.setValue("firstYn", true); + } + }} /> <FormField control={form.control} diff --git a/lib/rfq-last/vendor/rfq-vendor-table.tsx b/lib/rfq-last/vendor/rfq-vendor-table.tsx index ad89d1dc..98d53f5d 100644 --- a/lib/rfq-last/vendor/rfq-vendor-table.tsx +++ b/lib/rfq-last/vendor/rfq-vendor-table.tsx @@ -488,6 +488,37 @@ export function RfqVendorTable({ } }, [rfqId, rfqCode, router]); + // vendor status에 따른 category 분류 함수 + const getVendorCategoryFromStatus = React.useCallback((status: string | null): string => { + if (!status) return "미분류"; + + const categoryMap: Record<string, string> = { + "PENDING_REVIEW": "발굴업체", // 가입 신청 중 + "IN_REVIEW": "잠재업체", // 심사 중 + "REJECTED": "발굴업체", // 심사 거부됨 + "IN_PQ": "잠재업체", // PQ 진행 중 + "PQ_SUBMITTED": "잠재업체", // PQ 제출 + "PQ_FAILED": "잠재업체", // PQ 실패 + "PQ_APPROVED": "잠재업체", // PQ 통과 + "APPROVED": "잠재업체", // 승인됨 + "READY_TO_SEND": "잠재업체", // 정규등록검토 + "ACTIVE": "정규업체", // 활성 상태 (실제 거래 중) + "INACTIVE": "중지업체", // 비활성 상태 + "BLACKLISTED": "중지업체", // 거래 금지 + }; + + return categoryMap[status] || "미분류"; + }, []); + + // vendorCountry를 보기 좋은 형태로 변환 + const formatVendorCountry = React.useCallback((country: string | null): string => { + if (!country) return "미지정"; + + // KR 또는 한국이면 내자, 그 외는 전부 외자 + const isLocal = country === "KR" || country === "한국"; + return isLocal ? `내자(${country})` : `외자(${country})`; + }, []); + // 액션 처리 const handleAction = React.useCallback(async (action: string, vendor: any) => { switch (action) { @@ -636,7 +667,15 @@ export function RfqVendorTable({ header: ({ column }) => <ClientDataTableColumnHeaderSimple column={column} title="업체분류" />, filterFn: createFilterFn("text"), - cell: ({ row }) => row.original.vendorCategory || "-", + cell: ({ row }) => { + const status = row.original.status; + const category = getVendorCategoryFromStatus(status); + return ( + <Badge variant="outline" className="text-xs"> + {category} + </Badge> + ); + }, size: 100, }, { @@ -646,10 +685,11 @@ export function RfqVendorTable({ cell: ({ row }) => { const country = row.original.vendorCountry; + const formattedCountry = formatVendorCountry(country); const isLocal = country === "KR" || country === "한국"; return ( <Badge variant={isLocal ? "default" : "secondary"}> - {country || "-"} + {formattedCountry} </Badge> ); }, @@ -1503,6 +1543,37 @@ export function RfqVendorTable({ {selectedRows.length > 0 && ( <> + {/* 정보 일괄 입력 버튼 */} + <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> + {/* Short List 확정 버튼 */} {rfqCode?.startsWith("I") && <Button @@ -1539,37 +1610,6 @@ export function RfqVendorTable({ 견적 비교 {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> </> )} @@ -1679,6 +1719,18 @@ export function RfqVendorTable({ }} /> )} + + {/* AVL 벤더 연동 다이얼로그 */} + <AvlVendorDialog + open={isAvlDialogOpen} + onOpenChange={setIsAvlDialogOpen} + rfqId={rfqId} + rfqCode={rfqCode} + onSuccess={() => { + setIsAvlDialogOpen(false); + router.refresh(); + }} + /> </> ); }
\ No newline at end of file diff --git a/lib/rfq-last/vendor/send-rfq-dialog.tsx b/lib/rfq-last/vendor/send-rfq-dialog.tsx index 34777864..ed43d87f 100644 --- a/lib/rfq-last/vendor/send-rfq-dialog.tsx +++ b/lib/rfq-last/vendor/send-rfq-dialog.tsx @@ -653,10 +653,7 @@ export function SendRfqDialog({ return; } - if (selectedAttachments.length === 0) { - toast.warning("최소 하나 이상의 첨부파일을 선택해주세요."); - return; - } + // 첨부파일은 선택사항 - 없어도 발송 가능 // 재발송 업체 확인 const resendVendors = vendorsWithRecipients.filter(v => v.sendVersion && v.sendVersion > 0); @@ -1350,12 +1347,12 @@ export function SendRfqDialog({ </Button> <Button onClick={handleSend} - disabled={isSending || isGeneratingPdfs || selectedAttachments.length === 0} + disabled={isSending || isGeneratingPdfs} > {isGeneratingPdfs ? ( <> <RefreshCw className="h-4 w-4 mr-2 animate-spin" /> - 계약서 생성중... ({Math.round(pdfGenerationProgress)}%) + RFQ 송부중... ({Math.round(pdfGenerationProgress)}%) </> ) : isSending ? ( <> diff --git a/lib/rfq-last/vendor/vendor-detail-dialog.tsx b/lib/rfq-last/vendor/vendor-detail-dialog.tsx index e4c78656..54aada1d 100644 --- a/lib/rfq-last/vendor/vendor-detail-dialog.tsx +++ b/lib/rfq-last/vendor/vendor-detail-dialog.tsx @@ -253,8 +253,8 @@ export function VendorResponseDetailDialog({ <div className="flex items-center gap-2"> <Globe className="h-4 w-4 text-muted-foreground" /> <span className="text-sm text-muted-foreground">국가</span> - <Badge variant={data.vendorCountry === "KR" ? "default" : "secondary"} className="ml-auto"> - {data.vendorCountry} + <Badge variant={data.vendorCountry === "KR" || data.vendorCountry === "한국" ? "default" : "secondary"} className="ml-auto"> + {data.vendorCountry === "KR" || data.vendorCountry === "한국" ? `내자(${data.vendorCountry})` : `외자(${data.vendorCountry})`} </Badge> </div> </div> |
