summaryrefslogtreecommitdiff
path: root/components/bidding/manage/bidding-basic-info-editor.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'components/bidding/manage/bidding-basic-info-editor.tsx')
-rw-r--r--components/bidding/manage/bidding-basic-info-editor.tsx250
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 && (