summaryrefslogtreecommitdiff
path: root/lib/bidding/list
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-10-13 08:56:27 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-10-13 08:56:27 +0000
commitb9a2081a76e669688d5884f20482b37cc8acca22 (patch)
tree385e78c05d193a54daaced836f1e1152696153a8 /lib/bidding/list
parente84cf02a1cb4959a9d3bb5bbf37885c13a447f78 (diff)
(최겸, 임수민) 구매 입찰, 견적(그룹코드, tbe에러) 수정, data-room 수정
Diffstat (limited to 'lib/bidding/list')
-rw-r--r--lib/bidding/list/biddings-stats-cards.tsx4
-rw-r--r--lib/bidding/list/biddings-table-columns.tsx34
-rw-r--r--lib/bidding/list/biddings-table.tsx5
-rw-r--r--lib/bidding/list/create-bidding-dialog.tsx650
-rw-r--r--lib/bidding/list/edit-bidding-sheet.tsx4
5 files changed, 333 insertions, 364 deletions
diff --git a/lib/bidding/list/biddings-stats-cards.tsx b/lib/bidding/list/biddings-stats-cards.tsx
index 2926adac..14e29c16 100644
--- a/lib/bidding/list/biddings-stats-cards.tsx
+++ b/lib/bidding/list/biddings-stats-cards.tsx
@@ -60,9 +60,9 @@ export function BiddingsStatsCards({
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{total.toLocaleString()}</div>
- <p className="text-xs text-muted-foreground">
+ {/* <p className="text-xs text-muted-foreground">
이번 달 <span className="font-medium text-green-600">+{thisMonthCount}</span>건
- </p>
+ </p> */}
</CardContent>
</Card>
diff --git a/lib/bidding/list/biddings-table-columns.tsx b/lib/bidding/list/biddings-table-columns.tsx
index 7f0b8e40..4900d18a 100644
--- a/lib/bidding/list/biddings-table-columns.tsx
+++ b/lib/bidding/list/biddings-table-columns.tsx
@@ -5,6 +5,7 @@ import { type ColumnDef } from "@tanstack/react-table"
import { Checkbox } from "@/components/ui/checkbox"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
+import { getUserCodeByEmail } from "@/lib/bidding/service"
import {
Eye, Edit, MoreHorizontal, FileText, Users, Calendar,
Building, Package, DollarSign, Clock, CheckCircle, XCircle,
@@ -26,6 +27,12 @@ import {
import { DataTableColumnHeaderSimple } from "@/components/data-table/data-table-column-simple-header"
import { BiddingListItem } from "@/db/schema"
import { DataTableRowAction } from "@/types/table"
+
+// BiddingListItem에 manager 정보 추가
+type BiddingListItemWithManagerCode = BiddingListItem & {
+ managerName?: string | null
+ managerCode?: string | null
+}
import {
biddingStatusLabels,
contractTypeLabels,
@@ -35,7 +42,7 @@ import {
import { formatDate } from "@/lib/utils"
interface GetColumnsProps {
- setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<BiddingListItem> | null>>
+ setRowAction: React.Dispatch<React.SetStateAction<DataTableRowAction<BiddingListItemWithManagerCode> | null>>
}
// 상태별 배지 색상
@@ -78,7 +85,8 @@ const formatCurrency = (amount: string | number | null, currency = 'KRW') => {
-export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef<BiddingListItem>[] {
+export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef<BiddingListItemWithManagerCode>[] {
+
return [
// ═══════════════════════════════════════════════════════════════
// 선택 및 기본 정보
@@ -191,11 +199,11 @@ export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef
{
accessorKey: "managerName",
header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="입찰담당자" />,
- cell: ({ row }) => (
- <div className="truncate max-w-[100px]" title={row.original.managerName || ''}>
- {row.original.managerName || '-'}
- </div>
- ),
+ cell: ({ row }) => {
+ const name = row.original.managerName || "-";
+ const managerCode = row.original.managerCode || "";
+ return name === "-" ? "-" : `${name}(${managerCode})`;
+ },
size: 100,
meta: { excelHeader: "입찰담당자" },
},
@@ -237,10 +245,12 @@ export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef
<div className="truncate max-w-[200px]" title={row.original.title}>
<Button
variant="link"
- className="p-0 h-auto text-left justify-start"
+ className="p-0 h-auto text-left justify-start font-bold underline"
onClick={() => setRowAction({ row, type: "view" })}
>
- {row.original.title}
+ <div className="whitespace-pre-line">
+ {row.original.title}
+ </div>
</Button>
</div>
),
@@ -394,7 +404,7 @@ export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef
header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="예산" />,
cell: ({ row }) => (
<span className="text-sm font-medium">
- {formatCurrency(row.original.budget, row.original.currency)}
+ {row.original.budget}
</span>
),
size: 120,
@@ -406,7 +416,7 @@ export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef
header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="내정가" />,
cell: ({ row }) => (
<span className="text-sm font-medium text-orange-600">
- {formatCurrency(row.original.targetPrice, row.original.currency)}
+ {row.original.targetPrice}
</span>
),
size: 120,
@@ -418,7 +428,7 @@ export function getBiddingsColumns({ setRowAction }: GetColumnsProps): ColumnDef
header: ({ column }) => <DataTableColumnHeaderSimple column={column} title="최종입찰가" />,
cell: ({ row }) => (
<span className="text-sm font-medium text-green-600">
- {formatCurrency(row.original.finalBidPrice, row.original.currency)}
+ {row.original.finalBidPrice}
</span>
),
size: 120,
diff --git a/lib/bidding/list/biddings-table.tsx b/lib/bidding/list/biddings-table.tsx
index 2ecfaa73..8920d9db 100644
--- a/lib/bidding/list/biddings-table.tsx
+++ b/lib/bidding/list/biddings-table.tsx
@@ -14,6 +14,7 @@ import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-adv
import { getBiddingsColumns } from "./biddings-table-columns"
import { getBiddings, getBiddingStatusCounts } from "@/lib/bidding/service"
import { BiddingListItem } from "@/db/schema"
+import { BiddingListItemWithManagerCode } from "./biddings-table-columns"
import { BiddingsTableToolbarActions } from "./biddings-table-toolbar-actions"
import {
biddingStatusLabels,
@@ -42,11 +43,11 @@ export function BiddingsTable({ promises }: BiddingsTableProps) {
const [isCompact, setIsCompact] = React.useState<boolean>(false)
const [specMeetingDialogOpen, setSpecMeetingDialogOpen] = React.useState(false)
const [prDocumentsDialogOpen, setPrDocumentsDialogOpen] = React.useState(false)
- const [selectedBidding, setSelectedBidding] = React.useState<BiddingListItem | null>(null)
+ const [selectedBidding, setSelectedBidding] = React.useState<BiddingListItemWithManagerCode | null>(null)
console.log(data,"data")
- const [rowAction, setRowAction] = React.useState<DataTableRowAction<BiddingListItem> | null>(null)
+ const [rowAction, setRowAction] = React.useState<DataTableRowAction<BiddingListItemWithManagerCode> | null>(null)
const router = useRouter()
diff --git a/lib/bidding/list/create-bidding-dialog.tsx b/lib/bidding/list/create-bidding-dialog.tsx
index e99ac06f..50246f58 100644
--- a/lib/bidding/list/create-bidding-dialog.tsx
+++ b/lib/bidding/list/create-bidding-dialog.tsx
@@ -126,7 +126,7 @@ interface PRItemInfo {
}
// 탭 순서 정의
-const TAB_ORDER = ["basic", "contract", "schedule", "conditions", "details", "manager"] as const
+const TAB_ORDER = ["basic", "schedule", "details", "manager"] as const
type TabType = typeof TAB_ORDER[number]
export function CreateBiddingDialog() {
@@ -184,11 +184,11 @@ export function CreateBiddingDialog() {
// 파일 첨부를 위해 선택된 아이템 ID
const [selectedItemForFile, setSelectedItemForFile] = React.useState<string | null>(null)
- // 입찰 조건 상태
+ // 입찰 조건 상태 (기본값 설정 포함)
const [biddingConditions, setBiddingConditions] = React.useState({
- paymentTerms: "",
- taxConditions: "",
- incoterms: "",
+ paymentTerms: "", // 초기값 빈값, 데이터 로드 후 설정
+ taxConditions: "", // 초기값 빈값, 데이터 로드 후 설정
+ incoterms: "", // 초기값 빈값, 데이터 로드 후 설정
contractDeliveryDate: "",
shippingPort: "",
destinationPort: "",
@@ -202,26 +202,49 @@ export function CreateBiddingDialog() {
try {
const data = await getPaymentTermsForSelection();
setPaymentTermsOptions(data);
+ // 기본값 설정 로직: P008이 있으면 P008로, 없으면 첫 번째 항목으로 설정
+ const setDefaultPaymentTerms = () => {
+ const p008Exists = data.some(item => item.code === "P008");
+ if (p008Exists) {
+ setBiddingConditions(prev => ({ ...prev, paymentTerms: "P008" }));
+ }
+ };
+
+ setDefaultPaymentTerms();
} catch (error) {
console.error("Failed to load payment terms:", error);
toast.error("결제조건 목록을 불러오는데 실패했습니다.");
+ // 에러 시 기본값 초기화
+ if (biddingConditions.paymentTerms === "P008") {
+ setBiddingConditions(prev => ({ ...prev, paymentTerms: "" }));
+ }
} finally {
setProcurementLoading(false);
}
- }, []);
+ }, [biddingConditions.paymentTerms]);
const loadIncoterms = React.useCallback(async () => {
setProcurementLoading(true);
try {
const data = await getIncotermsForSelection();
setIncotermsOptions(data);
+
+ // 기본값 설정 로직: DAP가 있으면 DAP로, 없으면 첫 번째 항목으로 설정
+ const setDefaultIncoterms = () => {
+ const dapExists = data.some(item => item.code === "DAP");
+ if (dapExists) {
+ setBiddingConditions(prev => ({ ...prev, incoterms: "DAP" }));
+ }
+ };
+
+ setDefaultIncoterms();
} catch (error) {
console.error("Failed to load incoterms:", error);
toast.error("운송조건 목록을 불러오는데 실패했습니다.");
} finally {
setProcurementLoading(false);
}
- }, []);
+ }, [biddingConditions.incoterms]);
const loadShippingPlaces = React.useCallback(async () => {
setProcurementLoading(true);
@@ -249,13 +272,19 @@ export function CreateBiddingDialog() {
}
}, []);
- // 다이얼로그 열릴 때 procurement 데이터 로드
+ // 다이얼로그 열릴 때 procurement 데이터 로드 및 기본값 설정
React.useEffect(() => {
if (open) {
loadPaymentTerms();
loadIncoterms();
loadShippingPlaces();
loadDestinationPlaces();
+
+ // 세금조건 기본값 설정 (V1이 있는지 확인하고 설정)
+ const v1Exists = TAX_CONDITIONS.some(item => item.code === "V1");
+ if (v1Exists) {
+ setBiddingConditions(prev => ({ ...prev, taxConditions: "V1" }));
+ }
}
}, [open, loadPaymentTerms, loadIncoterms, loadShippingPlaces, loadDestinationPlaces])
@@ -294,6 +323,7 @@ export function CreateBiddingDialog() {
contractType: "general",
biddingType: "equipment",
+ biddingTypeCustom: "",
awardCount: "single",
contractStartDate: "",
contractEndDate: "",
@@ -344,10 +374,8 @@ export function CreateBiddingDialog() {
return {
basic: {
- isValid: formValues.projectId > 0 &&
- formValues.itemName.trim() !== "" &&
- formValues.title.trim() !== "",
- hasErrors: !!(formErrors.projectId || formErrors.itemName || formErrors.title)
+ isValid: formValues.title.trim() !== "",
+ hasErrors: !!(formErrors.title)
},
contract: {
isValid: formValues.contractType &&
@@ -399,11 +427,18 @@ export function CreateBiddingDialog() {
return representativeItem?.prNumber || ""
}, [prItems])
- // hasPrDocument 필드와 prNumber를 자동으로 업데이트
+ // 대표 품목명 자동 계산 (첫 번째 PR 아이템의 itemInfo)
+ const representativeItemName = React.useMemo(() => {
+ const representativeItem = prItems.find(item => item.isRepresentative)
+ return representativeItem?.itemInfo || ""
+ }, [prItems])
+
+ // hasPrDocument 필드와 prNumber, itemName을 자동으로 업데이트
React.useEffect(() => {
form.setValue("hasPrDocument", hasPrDocuments)
form.setValue("prNumber", representativePrNumber)
- }, [hasPrDocuments, representativePrNumber, form])
+ form.setValue("itemName", representativeItemName)
+ }, [hasPrDocuments, representativePrNumber, representativeItemName, form])
@@ -525,7 +560,7 @@ export function CreateBiddingDialog() {
if (!isCurrentTabValid()) {
// 특정 탭별 에러 메시지
if (activeTab === "basic") {
- toast.error("기본 정보를 모두 입력해주세요 (프로젝트, 품목명, 입찰명)")
+ toast.error("기본 정보를 모두 입력해주세요 (품목명, 입찰명)")
} else if (activeTab === "contract") {
toast.error("계약 정보를 모두 입력해주세요")
} else if (activeTab === "schedule") {
@@ -535,7 +570,7 @@ export function CreateBiddingDialog() {
toast.error("제출 시작일시와 마감일시를 입력해주세요")
}
} else if (activeTab === "conditions") {
- toast.error("입찰 조건을 모두 입력해주세요 (지급조건, 세금조건, 운송조건, 계약납품일, 선적지, 하역지)")
+ toast.error("입찰 조건을 모두 입력해주세요 (지급조건, 세금조건, 운송조건, 계약납품일)")
} else if (activeTab === "details") {
toast.error("품목정보, 수량/단위 또는 중량/중량단위를 입력해주세요")
}
@@ -617,6 +652,7 @@ export function CreateBiddingDialog() {
content: "",
contractType: "general",
biddingType: "equipment",
+ biddingTypeCustom: "",
awardCount: "single",
contractStartDate: "",
contractEndDate: "",
@@ -625,9 +661,6 @@ export function CreateBiddingDialog() {
hasSpecificationMeeting: false,
prNumber: "",
currency: "KRW",
- budget: "",
- targetPrice: "",
- finalBidPrice: "",
status: "bidding_generated",
isPublic: false,
managerName: "",
@@ -780,20 +813,6 @@ export function CreateBiddingDialog() {
</button>
<button
type="button"
- onClick={() => setActiveTab("contract")}
- className={`relative px-3 py-2 text-sm font-medium rounded-md transition-all whitespace-nowrap flex-shrink-0 ${
- activeTab === "contract"
- ? "bg-background text-foreground shadow-sm"
- : "text-muted-foreground hover:text-foreground"
- }`}
- >
- 계약정보
- {!tabValidation.contract.isValid && (
- <span className="absolute -top-1 -right-1 h-2 w-2 bg-red-500 rounded-full"></span>
- )}
- </button>
- <button
- type="button"
onClick={() => setActiveTab("schedule")}
className={`relative px-3 py-2 text-sm font-medium rounded-md transition-all whitespace-nowrap flex-shrink-0 ${
activeTab === "schedule"
@@ -801,27 +820,13 @@ export function CreateBiddingDialog() {
: "text-muted-foreground hover:text-foreground"
}`}
>
- 일정회의
+ 입찰계획
{!tabValidation.schedule.isValid && (
<span className="absolute -top-1 -right-1 h-2 w-2 bg-red-500 rounded-full"></span>
)}
</button>
<button
type="button"
- onClick={() => setActiveTab("conditions")}
- className={`relative px-3 py-2 text-sm font-medium rounded-md transition-all whitespace-nowrap flex-shrink-0 ${
- activeTab === "conditions"
- ? "bg-background text-foreground shadow-sm"
- : "text-muted-foreground hover:text-foreground"
- }`}
- >
- 입찰조건
- {!tabValidation.conditions.isValid && (
- <span className="absolute -top-1 -right-1 h-2 w-2 bg-red-500 rounded-full"></span>
- )}
- </button>
- <button
- type="button"
onClick={() => setActiveTab("details")}
className={`relative px-3 py-2 text-sm font-medium rounded-md transition-all whitespace-nowrap flex-shrink-0 ${
activeTab === "details"
@@ -853,7 +858,7 @@ export function CreateBiddingDialog() {
<TabsContent value="basic" className="mt-0 space-y-6">
<Card>
<CardHeader>
- <CardTitle>기본 정보</CardTitle>
+ <CardTitle>기본 정보 및 계약 정보</CardTitle>
</CardHeader>
<CardContent className="space-y-6">
{/* 프로젝트 선택 */}
@@ -863,7 +868,7 @@ export function CreateBiddingDialog() {
render={({ field }) => (
<FormItem>
<FormLabel>
- 프로젝트 <span className="text-red-500">*</span>
+ 프로젝트
</FormLabel>
<FormControl>
<ProjectSelector
@@ -877,9 +882,9 @@ export function CreateBiddingDialog() {
)}
/>
- <div className="grid grid-cols-2 gap-6">
+ {/* <div className="grid grid-cols-2 gap-6"> */}
{/* 품목명 */}
- <FormField
+ {/* <FormField
control={form.control}
name="itemName"
render={({ field }) => (
@@ -896,10 +901,10 @@ export function CreateBiddingDialog() {
<FormMessage />
</FormItem>
)}
- />
+ /> */}
{/* 리비전 */}
- <FormField
+ {/* <FormField
control={form.control}
name="revision"
render={({ field }) => (
@@ -916,8 +921,8 @@ export function CreateBiddingDialog() {
<FormMessage />
</FormItem>
)}
- />
- </div>
+ /> */}
+ {/* </div> */}
{/* 입찰명 */}
<FormField
@@ -957,17 +962,8 @@ export function CreateBiddingDialog() {
</FormItem>
)}
/>
- </CardContent>
- </Card>
- </TabsContent>
- {/* 계약 정보 탭 */}
- <TabsContent value="contract" className="mt-0 space-y-6">
- <Card>
- <CardHeader>
- <CardTitle>계약 정보</CardTitle>
- </CardHeader>
- <CardContent className="space-y-6">
+ {/* 계약 정보 섹션 */}
<div className="grid grid-cols-2 gap-6">
{/* 계약구분 */}
<FormField
@@ -1024,6 +1020,28 @@ export function CreateBiddingDialog() {
</FormItem>
)}
/>
+
+ {/* 기타 입찰유형 직접입력 */}
+ {form.watch("biddingType") === "other" && (
+ <FormField
+ control={form.control}
+ name="biddingTypeCustom"
+ render={({ field }) => (
+ <FormItem>
+ <FormLabel>
+ 기타 입찰유형 <span className="text-red-500">*</span>
+ </FormLabel>
+ <FormControl>
+ <Input
+ placeholder="직접 입력하세요"
+ {...field}
+ />
+ </FormControl>
+ <FormMessage />
+ </FormItem>
+ )}
+ />
+ )}
</div>
<div className="grid grid-cols-2 gap-6">
@@ -1091,15 +1109,8 @@ export function CreateBiddingDialog() {
)}
/>
</div>
- </CardContent>
- </Card>
- <Card>
- <CardHeader>
- <CardTitle>가격 정보</CardTitle>
- </CardHeader>
- <CardContent className="space-y-6">
- {/* 통화 */}
+ {/* 통화 선택만 유지 */}
<FormField
control={form.control}
name="currency"
@@ -1126,71 +1137,204 @@ export function CreateBiddingDialog() {
)}
/>
- <div className="grid grid-cols-3 gap-6">
- {/* 예산 */}
- <FormField
- control={form.control}
- name="budget"
- render={({ field }) => (
- <FormItem>
- <FormLabel>예산</FormLabel>
- <FormControl>
- <Input
- type="number"
- step="0.01"
- placeholder="0"
- {...field}
- />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
+ {/* 입찰 조건 섹션 */}
+ <Card>
+ <CardHeader>
+ <CardTitle>입찰 조건</CardTitle>
+ <p className="text-sm text-muted-foreground">
+ 벤더가 사전견적 시 참고할 입찰 조건을 설정하세요
+ </p>
+ </CardHeader>
+ <CardContent className="space-y-6">
+ <div className="grid grid-cols-2 gap-6">
+ <div className="space-y-2">
+ <label className="text-sm font-medium">
+ 지급조건 <span className="text-red-500">*</span>
+ </label>
+ <Select
+ value={biddingConditions.paymentTerms}
+ onValueChange={(value) => setBiddingConditions(prev => ({
+ ...prev,
+ paymentTerms: value
+ }))}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder="지급조건 선택" />
+ </SelectTrigger>
+ <SelectContent>
+ {paymentTermsOptions.length > 0 ? (
+ paymentTermsOptions.map((option) => (
+ <SelectItem key={option.code} value={option.code}>
+ {option.code} {option.description && `(${option.description})`}
+ </SelectItem>
+ ))
+ ) : (
+ <SelectItem value="loading" disabled>
+ 데이터를 불러오는 중...
+ </SelectItem>
+ )}
+ </SelectContent>
+ </Select>
+ </div>
- {/* 내정가 */}
- <FormField
- control={form.control}
- name="targetPrice"
- render={({ field }) => (
- <FormItem>
- <FormLabel>내정가</FormLabel>
- <FormControl>
- <Input
- type="number"
- step="0.01"
- placeholder="0"
- {...field}
- />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
+ <div className="space-y-2">
+ <label className="text-sm font-medium">
+ 세금조건 <span className="text-red-500">*</span>
+ </label>
+ <Select
+ value={biddingConditions.taxConditions}
+ onValueChange={(value) => setBiddingConditions(prev => ({
+ ...prev,
+ taxConditions: value
+ }))}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder="세금조건 선택" />
+ </SelectTrigger>
+ <SelectContent>
+ {TAX_CONDITIONS.map((condition) => (
+ <SelectItem key={condition.code} value={condition.code}>
+ {condition.name}
+ </SelectItem>
+ ))}
+ </SelectContent>
+ </Select>
+ </div>
- {/* 최종입찰가 */}
- <FormField
- control={form.control}
- name="finalBidPrice"
- render={({ field }) => (
- <FormItem>
- <FormLabel>최종입찰가</FormLabel>
- <FormControl>
- <Input
- type="number"
- step="0.01"
- placeholder="0"
- {...field}
- />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
- </div>
+ <div className="space-y-2">
+ <label className="text-sm font-medium">
+ 운송조건(인코텀즈) <span className="text-red-500">*</span>
+ </label>
+ <Select
+ value={biddingConditions.incoterms}
+ onValueChange={(value) => setBiddingConditions(prev => ({
+ ...prev,
+ incoterms: value
+ }))}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder="인코텀즈 선택" />
+ </SelectTrigger>
+ <SelectContent>
+ {incotermsOptions.length > 0 ? (
+ incotermsOptions.map((option) => (
+ <SelectItem key={option.code} value={option.code}>
+ {option.code} {option.description && `(${option.description})`}
+ </SelectItem>
+ ))
+ ) : (
+ <SelectItem value="loading" disabled>
+ 데이터를 불러오는 중...
+ </SelectItem>
+ )}
+ </SelectContent>
+ </Select>
+ </div>
+
+ <div className="space-y-2">
+ <label className="text-sm font-medium">
+ 계약 납품일 <span className="text-red-500">*</span>
+ </label>
+ <Input
+ type="date"
+ value={biddingConditions.contractDeliveryDate}
+ onChange={(e) => setBiddingConditions(prev => ({
+ ...prev,
+ contractDeliveryDate: e.target.value
+ }))}
+ />
+ </div>
+
+ <div className="space-y-2">
+ <label className="text-sm font-medium">선적지 (선택사항)</label>
+ <Select
+ value={biddingConditions.shippingPort}
+ onValueChange={(value) => setBiddingConditions(prev => ({
+ ...prev,
+ shippingPort: value
+ }))}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder="선적지 선택" />
+ </SelectTrigger>
+ <SelectContent>
+ {shippingPlaces.length > 0 ? (
+ shippingPlaces.map((place) => (
+ <SelectItem key={place.code} value={place.code}>
+ {place.code} {place.description && `(${place.description})`}
+ </SelectItem>
+ ))
+ ) : (
+ <SelectItem value="loading" disabled>
+ 데이터를 불러오는 중...
+ </SelectItem>
+ )}
+ </SelectContent>
+ </Select>
+ </div>
+
+ <div className="space-y-2">
+ <label className="text-sm font-medium">하역지 (선택사항)</label>
+ <Select
+ value={biddingConditions.destinationPort}
+ onValueChange={(value) => setBiddingConditions(prev => ({
+ ...prev,
+ destinationPort: value
+ }))}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder="하역지 선택" />
+ </SelectTrigger>
+ <SelectContent>
+ {destinationPlaces.length > 0 ? (
+ destinationPlaces.map((place) => (
+ <SelectItem key={place.code} value={place.code}>
+ {place.code} {place.description && `(${place.description})`}
+ </SelectItem>
+ ))
+ ) : (
+ <SelectItem value="loading" disabled>
+ 데이터를 불러오는 중...
+ </SelectItem>
+ )}
+ </SelectContent>
+ </Select>
+ </div>
+ </div>
+
+ <div className="flex items-center space-x-2">
+ <Switch
+ id="price-adjustment"
+ checked={biddingConditions.isPriceAdjustmentApplicable}
+ onCheckedChange={(checked) => setBiddingConditions(prev => ({
+ ...prev,
+ isPriceAdjustmentApplicable: checked
+ }))}
+ />
+ <label htmlFor="price-adjustment" className="text-sm font-medium">
+ 연동제 적용 요건 문의
+ </label>
+ </div>
+
+ <div className="space-y-2">
+ <label className="text-sm font-medium">스페어파트 옵션</label>
+ <Textarea
+ placeholder="스페어파트 관련 옵션을 입력하세요"
+ value={biddingConditions.sparePartOptions}
+ onChange={(e) => setBiddingConditions(prev => ({
+ ...prev,
+ sparePartOptions: e.target.value
+ }))}
+ rows={3}
+ />
+ </div>
+ </CardContent>
+ </Card>
</CardContent>
</Card>
</TabsContent>
+
{/* 일정 & 회의 탭 */}
<TabsContent value="schedule" className="mt-0 space-y-6">
<Card>
@@ -1444,204 +1588,40 @@ export function CreateBiddingDialog() {
)}
</CardContent>
</Card>
- </TabsContent>
- {/* 입찰 조건 탭 */}
- <TabsContent value="conditions" className="mt-0 space-y-6">
+ {/* 긴급 입찰 설정 */}
<Card>
<CardHeader>
- <CardTitle>입찰 조건</CardTitle>
- <p className="text-sm text-muted-foreground">
- 벤더가 사전견적 시 참고할 입찰 조건을 설정하세요
- </p>
+ <CardTitle>긴급 입찰 설정</CardTitle>
</CardHeader>
<CardContent className="space-y-6">
- <div className="grid grid-cols-2 gap-6">
- <div className="space-y-2">
- <label className="text-sm font-medium">
- 지급조건 <span className="text-red-500">*</span>
- </label>
- <Select
- value={biddingConditions.paymentTerms}
- onValueChange={(value) => setBiddingConditions(prev => ({
- ...prev,
- paymentTerms: value
- }))}
- >
- <SelectTrigger>
- <SelectValue placeholder="지급조건 선택" />
- </SelectTrigger>
- <SelectContent>
- {paymentTermsOptions.length > 0 ? (
- paymentTermsOptions.map((option) => (
- <SelectItem key={option.code} value={option.code}>
- {option.code} {option.description && `(${option.description})`}
- </SelectItem>
- ))
- ) : (
- <SelectItem value="loading" disabled>
- 데이터를 불러오는 중...
- </SelectItem>
- )}
- </SelectContent>
- </Select>
- </div>
-
- <div className="space-y-2">
- <label className="text-sm font-medium">
- 세금조건 <span className="text-red-500">*</span>
- </label>
- <Select
- value={biddingConditions.taxConditions}
- onValueChange={(value) => setBiddingConditions(prev => ({
- ...prev,
- taxConditions: value
- }))}
- >
- <SelectTrigger>
- <SelectValue placeholder="세금조건 선택" />
- </SelectTrigger>
- <SelectContent>
- {TAX_CONDITIONS.map((condition) => (
- <SelectItem key={condition.code} value={condition.code}>
- {condition.name}
- </SelectItem>
- ))}
- </SelectContent>
- </Select>
- </div>
-
- <div className="space-y-2">
- <label className="text-sm font-medium">
- 운송조건(인코텀즈) <span className="text-red-500">*</span>
- </label>
- <Select
- value={biddingConditions.incoterms}
- onValueChange={(value) => setBiddingConditions(prev => ({
- ...prev,
- incoterms: value
- }))}
- >
- <SelectTrigger>
- <SelectValue placeholder="인코텀즈 선택" />
- </SelectTrigger>
- <SelectContent>
- {incotermsOptions.length > 0 ? (
- incotermsOptions.map((option) => (
- <SelectItem key={option.code} value={option.code}>
- {option.code} {option.description && `(${option.description})`}
- </SelectItem>
- ))
- ) : (
- <SelectItem value="loading" disabled>
- 데이터를 불러오는 중...
- </SelectItem>
- )}
- </SelectContent>
- </Select>
- </div>
-
- <div className="space-y-2">
- <label className="text-sm font-medium">
- 계약 납품일 <span className="text-red-500">*</span>
- </label>
- <Input
- type="date"
- value={biddingConditions.contractDeliveryDate}
- onChange={(e) => setBiddingConditions(prev => ({
- ...prev,
- contractDeliveryDate: e.target.value
- }))}
- />
- </div>
-
- <div className="space-y-2">
- <label className="text-sm font-medium">선적지 <span className="text-red-500">*</span></label>
- <Select
- value={biddingConditions.shippingPort}
- onValueChange={(value) => setBiddingConditions(prev => ({
- ...prev,
- shippingPort: value
- }))}
- >
- <SelectTrigger>
- <SelectValue placeholder="선적지 선택" />
- </SelectTrigger>
- <SelectContent>
- {shippingPlaces.length > 0 ? (
- shippingPlaces.map((place) => (
- <SelectItem key={place.code} value={place.code}>
- {place.code} {place.description && `(${place.description})`}
- </SelectItem>
- ))
- ) : (
- <SelectItem value="loading" disabled>
- 데이터를 불러오는 중...
- </SelectItem>
- )}
- </SelectContent>
- </Select>
- </div>
-
- <div className="space-y-2">
- <label className="text-sm font-medium">하역지 <span className="text-red-500">*</span></label>
- <Select
- value={biddingConditions.destinationPort}
- onValueChange={(value) => setBiddingConditions(prev => ({
- ...prev,
- destinationPort: value
- }))}
- >
- <SelectTrigger>
- <SelectValue placeholder="하역지 선택" />
- </SelectTrigger>
- <SelectContent>
- {destinationPlaces.length > 0 ? (
- destinationPlaces.map((place) => (
- <SelectItem key={place.code} value={place.code}>
- {place.code} {place.description && `(${place.description})`}
- </SelectItem>
- ))
- ) : (
- <SelectItem value="loading" disabled>
- 데이터를 불러오는 중...
- </SelectItem>
- )}
- </SelectContent>
- </Select>
- </div>
- </div>
-
- <div className="flex items-center space-x-2">
- <Switch
- id="price-adjustment"
- checked={biddingConditions.isPriceAdjustmentApplicable}
- onCheckedChange={(checked) => setBiddingConditions(prev => ({
- ...prev,
- isPriceAdjustmentApplicable: checked
- }))}
- />
- <label htmlFor="price-adjustment" className="text-sm font-medium">
- 연동제 적용 가능
- </label>
- </div>
-
- <div className="space-y-2">
- <label className="text-sm font-medium">스페어파트 옵션</label>
- <Textarea
- placeholder="스페어파트 관련 옵션을 입력하세요"
- value={biddingConditions.sparePartOptions}
- onChange={(e) => setBiddingConditions(prev => ({
- ...prev,
- sparePartOptions: e.target.value
- }))}
- rows={3}
- />
- </div>
+ <FormField
+ control={form.control}
+ name="isUrgent"
+ render={({ field }) => (
+ <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
+ <div className="space-y-0.5">
+ <FormLabel className="text-base">
+ 긴급 입찰
+ </FormLabel>
+ <FormDescription>
+ 긴급 입찰 여부를 설정합니다
+ </FormDescription>
+ </div>
+ <FormControl>
+ <Switch
+ checked={field.value}
+ onCheckedChange={field.onChange}
+ />
+ </FormControl>
+ </FormItem>
+ )}
+ />
</CardContent>
</Card>
</TabsContent>
+
{/* 세부내역 탭 */}
<TabsContent value="details" className="mt-0 space-y-6">
<Card>
@@ -2029,28 +2009,6 @@ export function CreateBiddingDialog() {
)}
/>
- <FormField
- control={form.control}
- name="isUrgent"
- render={({ field }) => (
- <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4">
- <div className="space-y-0.5">
- <FormLabel className="text-base">
- 긴급 입찰
- </FormLabel>
- <FormDescription>
- 긴급 입찰 여부를 설정합니다
- </FormDescription>
- </div>
- <FormControl>
- <Switch
- checked={field.value}
- onCheckedChange={field.onChange}
- />
- </FormControl>
- </FormItem>
- )}
- />
<FormField
control={form.control}
@@ -2073,7 +2031,7 @@ export function CreateBiddingDialog() {
</Card>
{/* 입찰 생성 요약 */}
- <Card>
+ {/* <Card>
<CardHeader>
<CardTitle>입찰 생성 요약</CardTitle>
</CardHeader>
@@ -2129,7 +2087,7 @@ export function CreateBiddingDialog() {
</div>
</div>
</CardContent>
- </Card>
+ </Card> */}
</TabsContent>
</div>
diff --git a/lib/bidding/list/edit-bidding-sheet.tsx b/lib/bidding/list/edit-bidding-sheet.tsx
index dc24d0cf..ed3d3f41 100644
--- a/lib/bidding/list/edit-bidding-sheet.tsx
+++ b/lib/bidding/list/edit-bidding-sheet.tsx
@@ -389,7 +389,7 @@ export function EditBiddingSheet({
/>
</div>
- <FormField
+ {/* <FormField
control={form.control}
name="status"
render={({ field }) => (
@@ -412,7 +412,7 @@ export function EditBiddingSheet({
<FormMessage />
</FormItem>
)}
- />
+ /> */}
<div className="space-y-3">
<FormField