diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-11-20 10:25:41 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-11-20 10:25:41 +0000 |
| commit | b75b1cd920efd61923f7b2dbc4c49987b7b0c4e1 (patch) | |
| tree | 9e4195e697df6df21b5896b0d33acc97d698b4a7 /components/bidding/manage/bidding-basic-info-editor.tsx | |
| parent | 4df8d72b79140919c14df103b45bbc8b1afa37c2 (diff) | |
(최겸) 구매 입찰 수정
Diffstat (limited to 'components/bidding/manage/bidding-basic-info-editor.tsx')
| -rw-r--r-- | components/bidding/manage/bidding-basic-info-editor.tsx | 250 |
1 files changed, 43 insertions, 207 deletions
diff --git a/components/bidding/manage/bidding-basic-info-editor.tsx b/components/bidding/manage/bidding-basic-info-editor.tsx index f0d56689..c2c668a4 100644 --- a/components/bidding/manage/bidding-basic-info-editor.tsx +++ b/components/bidding/manage/bidding-basic-info-editor.tsx @@ -51,6 +51,7 @@ import { DropzoneDescription, DropzoneInput, DropzoneTitle, + DropzoneTrigger, DropzoneUploadIcon, DropzoneZone, } from "@/components/ui/dropzone" @@ -113,8 +114,6 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB const [noticeTemplate, setNoticeTemplate] = React.useState('') // 첨부파일 관련 상태 - const [shiAttachmentFiles, setShiAttachmentFiles] = React.useState<File[]>([]) - const [vendorAttachmentFiles, setVendorAttachmentFiles] = React.useState<File[]>([]) const [existingDocuments, setExistingDocuments] = React.useState<UploadedDocument[]>([]) const [isLoadingDocuments, setIsLoadingDocuments] = React.useState(false) @@ -371,7 +370,7 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB const result = await uploadBiddingDocument( biddingId, file, - 'bid_attachment', + 'evaluation_doc', // SHI용 문서 타입 file.name, 'SHI용 첨부파일', '1' // TODO: 실제 사용자 ID 가져오기 @@ -381,17 +380,12 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB } } await loadExistingDocuments() - setShiAttachmentFiles([]) } catch (error) { console.error('Failed to upload SHI files:', error) toast.error('파일 업로드에 실패했습니다.') } } - const removeShiFile = (index: number) => { - setShiAttachmentFiles(prev => prev.filter((_, i) => i !== index)) - } - // 협력업체용 파일 첨부 핸들러 const handleVendorFileUpload = async (files: File[]) => { try { @@ -400,7 +394,7 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB const result = await uploadBiddingDocument( biddingId, file, - 'bid_attachment', + 'company_proposal', // 협력업체용 문서 타입 file.name, '협력업체용 첨부파일', '1' // TODO: 실제 사용자 ID 가져오기 @@ -410,17 +404,12 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB } } await loadExistingDocuments() - setVendorAttachmentFiles([]) } catch (error) { console.error('Failed to upload vendor files:', error) toast.error('파일 업로드에 실패했습니다.') } } - const removeVendorFile = (index: number) => { - setVendorAttachmentFiles(prev => prev.filter((_, i) => i !== index)) - } - // 파일 삭제 const handleDeleteDocument = async (documentId: number) => { if (!confirm('이 파일을 삭제하시겠습니까?')) { @@ -623,7 +612,7 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB </div> )} - {/* 2행: 예산, 실적가, 내정가, 낙찰수 */} + {/* 2행: 예산, 실적가, 내정가, 낙찰업체 수 */} <div className="grid grid-cols-4 gap-4"> <FormField control={form.control} name="budget" render={({ field }) => ( <FormItem> @@ -666,11 +655,11 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB <FormField control={form.control} name="awardCount" render={({ field }) => ( <FormItem> - <FormLabel>낙찰수</FormLabel> + <FormLabel>낙찰업체 수</FormLabel> <Select onValueChange={field.onChange} value={field.value}> <FormControl> <SelectTrigger> - <SelectValue placeholder="낙찰수 선택" /> + <SelectValue placeholder="낙찰업체 수 선택" /> </SelectTrigger> </FormControl> <SelectContent> @@ -741,9 +730,15 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB </SelectTrigger> </FormControl> <SelectContent> - <SelectItem value="조선">조선</SelectItem> - <SelectItem value="해양">해양</SelectItem> - <SelectItem value="기타">기타</SelectItem> + <SelectItem value="Shipbuild & Offshore">Shipbuild & Offshore</SelectItem> + <SelectItem value="Wind Energy">Wind Energy</SelectItem> + <SelectItem value="Power & Control Sys.">Power & Control Sys.</SelectItem> + <SelectItem value="SHI NINGBO Co., LTD">SHI NINGBO Co., LTD</SelectItem> + <SelectItem value="RONGCHENG Co.LTD">RONGCHENG Co.LTD</SelectItem> + <SelectItem value="RONGCHENGGAYA Co.LTD">RONGCHENGGAYA Co.LTD</SelectItem> + <SelectItem value="S&Sys">S&Sys</SelectItem> + <SelectItem value="Energy & Infra Solut">Energy & Infra Solut</SelectItem> + <SelectItem value="test pur.org222">test pur.org222</SelectItem> </SelectContent> </Select> <FormMessage /> @@ -825,69 +820,8 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB <FormMessage /> </FormItem> )} /> - - {/* <FormField control={form.control} name="submissionStartDate" render={({ field }) => ( - <FormItem> - <FormLabel>입찰서 제출 시작</FormLabel> - <FormControl> - <Input type="datetime-local" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} /> - - <FormField control={form.control} name="submissionEndDate" render={({ field }) => ( - <FormItem> - <FormLabel>입찰서 제출 마감</FormLabel> - <FormControl> - <Input type="datetime-local" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} /> */} </div> - {/* 5행: 개찰 일시, 사양설명회, PR문서 */} - {/* <div className="grid grid-cols-3 gap-4"> - <FormField control={form.control} name="evaluationDate" render={({ field }) => ( - <FormItem> - <FormLabel>개찰 일시</FormLabel> - <FormControl> - <Input type="datetime-local" {...field} /> - </FormControl> - <FormMessage /> - </FormItem> - )} /> */} - - {/* <FormField control={form.control} name="hasSpecificationMeeting" render={({ field }) => ( - <FormItem className="flex flex-row items-center justify-between rounded-lg border p-3"> - <div className="space-y-0.5"> - <FormLabel className="text-base">사양설명회</FormLabel> - <div className="text-sm text-muted-foreground"> - 사양설명회가 필요한 경우 체크 - </div> - </div> - <FormControl> - <Switch checked={field.value} onCheckedChange={field.onChange} /> - </FormControl> - </FormItem> - )} /> */} - - {/* <FormField control={form.control} name="hasPrDocument" render={({ field }) => ( - <FormItem className="flex flex-row items-center justify-between rounded-lg border p-3"> - <div className="space-y-0.5"> - <FormLabel className="text-base">PR 문서</FormLabel> - <div className="text-sm text-muted-foreground"> - PR 문서가 있는 경우 체크 - </div> - </div> - <FormControl> - <Switch checked={field.value} onCheckedChange={field.onChange} /> - </FormControl> - </FormItem> - )} /> */} - {/* </div> */} - {/* 입찰개요 */} <div className="pt-2"> <FormField control={form.control} name="description" render={({ field }) => ( @@ -902,7 +836,7 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB </div> {/* 비고 */} - <div className="pt-2"> + {/* <div className="pt-2"> <FormField control={form.control} name="remarks" render={({ field }) => ( <FormItem> <FormLabel>비고</FormLabel> @@ -912,7 +846,7 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB <FormMessage /> </FormItem> )} /> - </div> + </div> */} {/* 입찰 조건 */} <div className="pt-4 border-t"> @@ -1100,24 +1034,6 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB }} /> </div> - - {/* <div className="flex flex-row items-center justify-between rounded-lg border p-3"> - <div className="space-y-0.5"> - <FormLabel className="text-base">연동제 적용 가능</FormLabel> - <div className="text-sm text-muted-foreground"> - 연동제 적용 요건 여부 - </div> - </div> - <Switch - checked={biddingConditions.isPriceAdjustmentApplicable} - onCheckedChange={(checked) => { - setBiddingConditions(prev => ({ - ...prev, - isPriceAdjustmentApplicable: checked - })) - }} - /> - </div> */} </div> {/* 5행: 스페어파트 옵션 */} @@ -1159,12 +1075,12 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB </FormItem> )} /> - {isLoadingTemplate && ( + {/* {isLoadingTemplate && ( <div className="flex items-center justify-center p-4 text-sm text-muted-foreground"> <div className="animate-spin rounded-full h-4 w-4 border-b-2 border-gray-900 mr-2"></div> 입찰공고 템플릿을 불러오는 중... </div> - )} + )} */} </div> {/* 액션 버튼 */} @@ -1195,9 +1111,10 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB <CardContent className="space-y-4"> <Dropzone maxSize={6e8} // 600MB - onDropAccepted={(files) => { + onDropAccepted={async (files) => { const newFiles = Array.from(files) - setShiAttachmentFiles(prev => [...prev, ...newFiles]) + // 파일을 즉시 업로드 + await handleShiFileUpload(newFiles) }} onDropRejected={() => { toast({ @@ -1208,60 +1125,19 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB }} > {() => ( - <DropzoneZone className="flex justify-center h-32"> - <div className="flex items-center gap-6"> - <DropzoneUploadIcon /> - <div className="grid gap-0.5"> - <DropzoneTitle>파일을 드래그하여 업로드</DropzoneTitle> + <DropzoneTrigger asChild> + <DropzoneZone className="flex justify-center h-32"> + <div className="flex items-center gap-6"> + <DropzoneUploadIcon /> + <div className="grid gap-0.5"> + <DropzoneTitle>파일을 드래그하여 업로드</DropzoneTitle> + </div> </div> - </div> - </DropzoneZone> + </DropzoneZone> + </DropzoneTrigger> )} </Dropzone> - {shiAttachmentFiles.length > 0 && ( - <div className="space-y-2"> - <h4 className="text-sm font-medium">업로드 예정 파일</h4> - <div className="space-y-2"> - {shiAttachmentFiles.map((file, index) => ( - <div - key={index} - className="flex items-center justify-between p-3 bg-muted rounded-lg" - > - <div className="flex items-center gap-3"> - <FileText className="h-4 w-4 text-muted-foreground" /> - <div> - <p className="text-sm font-medium">{file.name}</p> - <p className="text-xs text-muted-foreground"> - {(file.size / 1024 / 1024).toFixed(2)} MB - </p> - </div> - </div> - <div className="flex gap-2"> - <Button - type="button" - variant="ghost" - size="sm" - onClick={() => { - handleShiFileUpload([file]) - }} - > - 업로드 - </Button> - <Button - type="button" - variant="ghost" - size="sm" - onClick={() => removeShiFile(index)} - > - 제거 - </Button> - </div> - </div> - ))} - </div> - </div> - )} {/* 기존 문서 목록 */} {isLoadingDocuments ? ( @@ -1329,9 +1205,10 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB <CardContent className="space-y-4"> <Dropzone maxSize={6e8} // 600MB - onDropAccepted={(files) => { + onDropAccepted={async (files) => { const newFiles = Array.from(files) - setVendorAttachmentFiles(prev => [...prev, ...newFiles]) + // 파일을 즉시 업로드 + await handleVendorFileUpload(newFiles) }} onDropRejected={() => { toast({ @@ -1342,60 +1219,19 @@ export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingB }} > {() => ( - <DropzoneZone className="flex justify-center h-32"> - <div className="flex items-center gap-6"> - <DropzoneUploadIcon /> - <div className="grid gap-0.5"> - <DropzoneTitle>파일을 드래그하여 업로드</DropzoneTitle> + <DropzoneTrigger asChild> + <DropzoneZone className="flex justify-center h-32"> + <div className="flex items-center gap-6"> + <DropzoneUploadIcon /> + <div className="grid gap-0.5"> + <DropzoneTitle>파일을 드래그하여 업로드</DropzoneTitle> + </div> </div> - </div> - </DropzoneZone> + </DropzoneZone> + </DropzoneTrigger> )} </Dropzone> - {vendorAttachmentFiles.length > 0 && ( - <div className="space-y-2"> - <h4 className="text-sm font-medium">업로드 예정 파일</h4> - <div className="space-y-2"> - {vendorAttachmentFiles.map((file, index) => ( - <div - key={index} - className="flex items-center justify-between p-3 bg-muted rounded-lg" - > - <div className="flex items-center gap-3"> - <FileText className="h-4 w-4 text-muted-foreground" /> - <div> - <p className="text-sm font-medium">{file.name}</p> - <p className="text-xs text-muted-foreground"> - {(file.size / 1024 / 1024).toFixed(2)} MB - </p> - </div> - </div> - <div className="flex gap-2"> - <Button - type="button" - variant="ghost" - size="sm" - onClick={() => { - handleVendorFileUpload([file]) - }} - > - 업로드 - </Button> - <Button - type="button" - variant="ghost" - size="sm" - onClick={() => removeVendorFile(index)} - > - 제거 - </Button> - </div> - </div> - ))} - </div> - </div> - )} {/* 기존 문서 목록 */} {existingDocuments.length > 0 && ( |
