DatePicker 공통화: - date-picker.tsx 공통 컴포넌트 신규 추가 - 전체 폼 컴포넌트 DatePicker 통일 적용 (50+ 파일) - DateRangeSelector 개선 공정관리: - RuleModal 대폭 리팩토링 (-592줄 → 간소화) - ProcessForm, StepForm 개선 - ProcessDetail 수정, actions 확장 작업자화면: - WorkerScreen 기능 대폭 확장 (+543줄) - WorkItemCard 개선 - types 확장 회계/인사/영업/품질: - BadDebtDetail, BillDetail, DepositDetail, SalesDetail 등 DatePicker 적용 - EmployeeForm, VacationDialog 등 DatePicker 적용 - OrderRegistration, QuoteRegistration DatePicker 적용 - InspectionCreate, InspectionDetail DatePicker 적용 공사관리/CEO대시보드: - BiddingDetail, ContractDetail, HandoverReport 등 DatePicker 적용 - ScheduleDetailModal, TodayIssueSection 개선 기타: - WorkOrderCreate/Edit/Detail/List 개선 - ShipmentCreate/Edit, ReceivingDetail 개선 - calendar, calendarEvents 수정 - datepicker 마이그레이션 체크리스트 추가 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
533 lines
24 KiB
TypeScript
533 lines
24 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useCallback, useMemo } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { Input } from '@/components/ui/input';
|
|
import { DatePicker } from '@/components/ui/date-picker';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Textarea } from '@/components/ui/textarea';
|
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select';
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from '@/components/ui/table';
|
|
import { toast } from 'sonner';
|
|
import { IntegratedDetailTemplate } from '@/components/templates/IntegratedDetailTemplate';
|
|
import { biddingConfig } from './biddingConfig';
|
|
import type { BiddingDetail, BiddingDetailFormData } from './types';
|
|
import {
|
|
BIDDING_STATUS_OPTIONS,
|
|
BIDDING_STATUS_STYLES,
|
|
BIDDING_STATUS_LABELS,
|
|
VAT_TYPE_OPTIONS,
|
|
getEmptyBiddingDetailFormData,
|
|
biddingDetailToFormData,
|
|
} from './types';
|
|
import { updateBidding } from './actions';
|
|
import { formatNumber } from '@/utils/formatAmount';
|
|
|
|
interface BiddingDetailFormProps {
|
|
mode: 'view' | 'edit';
|
|
biddingId: string;
|
|
initialData?: BiddingDetail;
|
|
}
|
|
|
|
export default function BiddingDetailForm({
|
|
mode,
|
|
biddingId,
|
|
initialData,
|
|
}: BiddingDetailFormProps) {
|
|
const router = useRouter();
|
|
const isViewMode = mode === 'view';
|
|
|
|
// 폼 데이터
|
|
const [formData, setFormData] = useState<BiddingDetailFormData>(
|
|
initialData ? biddingDetailToFormData(initialData) : getEmptyBiddingDetailFormData()
|
|
);
|
|
|
|
|
|
// 공과 합계 계산
|
|
const expenseTotal = useMemo(() => {
|
|
return formData.expenseItems.reduce((sum, item) => sum + item.amount, 0);
|
|
}, [formData.expenseItems]);
|
|
|
|
// 견적 상세 합계 계산 (견적 상세 페이지와 동일)
|
|
const estimateDetailTotals = useMemo(() => {
|
|
return formData.estimateDetailItems.reduce(
|
|
(acc, item) => ({
|
|
weight: acc.weight + (item.weight || 0),
|
|
area: acc.area + (item.area || 0),
|
|
steelScreen: acc.steelScreen + (item.steelScreen || 0),
|
|
caulking: acc.caulking + (item.caulking || 0),
|
|
rail: acc.rail + (item.rail || 0),
|
|
bottom: acc.bottom + (item.bottom || 0),
|
|
boxReinforce: acc.boxReinforce + (item.boxReinforce || 0),
|
|
shaft: acc.shaft + (item.shaft || 0),
|
|
painting: acc.painting + (item.painting || 0),
|
|
motor: acc.motor + (item.motor || 0),
|
|
controller: acc.controller + (item.controller || 0),
|
|
widthConstruction: acc.widthConstruction + (item.widthConstruction || 0),
|
|
heightConstruction: acc.heightConstruction + (item.heightConstruction || 0),
|
|
unitPrice: acc.unitPrice + (item.unitPrice || 0),
|
|
expense: acc.expense + (item.expense || 0),
|
|
quantity: acc.quantity + (item.quantity || 0),
|
|
cost: acc.cost + (item.cost || 0),
|
|
costExecution: acc.costExecution + (item.costExecution || 0),
|
|
marginCost: acc.marginCost + (item.marginCost || 0),
|
|
marginCostExecution: acc.marginCostExecution + (item.marginCostExecution || 0),
|
|
expenseExecution: acc.expenseExecution + (item.expenseExecution || 0),
|
|
}),
|
|
{
|
|
weight: 0,
|
|
area: 0,
|
|
steelScreen: 0,
|
|
caulking: 0,
|
|
rail: 0,
|
|
bottom: 0,
|
|
boxReinforce: 0,
|
|
shaft: 0,
|
|
painting: 0,
|
|
motor: 0,
|
|
controller: 0,
|
|
widthConstruction: 0,
|
|
heightConstruction: 0,
|
|
unitPrice: 0,
|
|
expense: 0,
|
|
quantity: 0,
|
|
cost: 0,
|
|
costExecution: 0,
|
|
marginCost: 0,
|
|
marginCostExecution: 0,
|
|
expenseExecution: 0,
|
|
}
|
|
);
|
|
}, [formData.estimateDetailItems]);
|
|
|
|
// 저장 핸들러
|
|
const handleSubmit = useCallback(async (): Promise<{ success: boolean; error?: string }> => {
|
|
try {
|
|
const result = await updateBidding(biddingId, formData);
|
|
if (result.success) {
|
|
toast.success('수정이 완료되었습니다.');
|
|
router.push(`/ko/construction/project/bidding/${biddingId}?mode=view`);
|
|
router.refresh();
|
|
return { success: true };
|
|
} else {
|
|
toast.error(result.error || '저장에 실패했습니다.');
|
|
return { success: false, error: result.error || '저장에 실패했습니다.' };
|
|
}
|
|
} catch (error) {
|
|
const errorMsg = error instanceof Error ? error.message : '저장에 실패했습니다.';
|
|
toast.error(errorMsg);
|
|
return { success: false, error: errorMsg };
|
|
}
|
|
}, [router, biddingId, formData]);
|
|
|
|
// 필드 변경 핸들러
|
|
const handleFieldChange = useCallback(
|
|
(field: keyof BiddingDetailFormData, value: string | number) => {
|
|
setFormData((prev) => ({
|
|
...prev,
|
|
[field]: value,
|
|
}));
|
|
},
|
|
[]
|
|
);
|
|
|
|
// 폼 콘텐츠 렌더링
|
|
const renderFormContent = () => (
|
|
<div className="space-y-6">
|
|
{/* 입찰 정보 섹션 */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-base">입찰 정보</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
{/* 입찰번호 */}
|
|
<div className="space-y-2">
|
|
<Label>입찰번호</Label>
|
|
<Input value={formData.biddingCode} disabled className="bg-muted" />
|
|
</div>
|
|
|
|
{/* 입찰자 */}
|
|
<div className="space-y-2">
|
|
<Label>입찰자</Label>
|
|
<Input value={formData.bidderName} disabled className="bg-muted" />
|
|
</div>
|
|
|
|
{/* 거래처명 */}
|
|
<div className="space-y-2">
|
|
<Label>거래처명</Label>
|
|
<Input value={formData.partnerName} disabled className="bg-muted" />
|
|
</div>
|
|
|
|
{/* 현장명 */}
|
|
<div className="space-y-2">
|
|
<Label>현장명</Label>
|
|
<Input value={formData.projectName} disabled className="bg-muted" />
|
|
</div>
|
|
|
|
{/* 입찰일자 */}
|
|
<div className="space-y-2">
|
|
<Label>입찰일자</Label>
|
|
{isViewMode ? (
|
|
<Input value={formData.biddingDate} disabled className="bg-muted" />
|
|
) : (
|
|
<DatePicker
|
|
value={formData.biddingDate}
|
|
onChange={(date) => handleFieldChange('biddingDate', date)}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
{/* 개소 */}
|
|
<div className="space-y-2">
|
|
<Label>개소</Label>
|
|
<Input value={formData.totalCount} disabled className="bg-muted" />
|
|
</div>
|
|
|
|
{/* 공사기간 */}
|
|
<div className="space-y-2">
|
|
<Label>공사기간</Label>
|
|
<div className="flex items-center gap-2">
|
|
{isViewMode ? (
|
|
<Input
|
|
value={`${formData.constructionStartDate} ~ ${formData.constructionEndDate}`}
|
|
disabled
|
|
className="bg-muted"
|
|
/>
|
|
) : (
|
|
<>
|
|
<DatePicker
|
|
value={formData.constructionStartDate}
|
|
onChange={(date) => handleFieldChange('constructionStartDate', date)}
|
|
className="flex-1"
|
|
/>
|
|
<span>~</span>
|
|
<DatePicker
|
|
value={formData.constructionEndDate}
|
|
onChange={(date) => handleFieldChange('constructionEndDate', date)}
|
|
className="flex-1"
|
|
/>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 부가세 */}
|
|
<div className="space-y-2">
|
|
<Label>부가세</Label>
|
|
{isViewMode ? (
|
|
<Input
|
|
value={
|
|
VAT_TYPE_OPTIONS.find((opt) => opt.value === formData.vatType)?.label ||
|
|
formData.vatType
|
|
}
|
|
disabled
|
|
className="bg-muted"
|
|
/>
|
|
) : (
|
|
<Select
|
|
value={formData.vatType}
|
|
onValueChange={(value) => handleFieldChange('vatType', value)}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{VAT_TYPE_OPTIONS.map((option) => (
|
|
<SelectItem key={option.value} value={option.value}>
|
|
{option.label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
)}
|
|
</div>
|
|
|
|
{/* 입찰금액 */}
|
|
<div className="space-y-2">
|
|
<Label>입찰금액</Label>
|
|
<Input
|
|
value={formatNumber(formData.biddingAmount)}
|
|
disabled
|
|
className="bg-muted text-right font-medium"
|
|
/>
|
|
</div>
|
|
|
|
{/* 상태 */}
|
|
<div className="space-y-2">
|
|
<Label>상태</Label>
|
|
{isViewMode ? (
|
|
<div
|
|
className={`flex h-10 items-center rounded-md border px-3 ${BIDDING_STATUS_STYLES[formData.status]}`}
|
|
>
|
|
{BIDDING_STATUS_LABELS[formData.status]}
|
|
</div>
|
|
) : (
|
|
<Select
|
|
value={formData.status}
|
|
onValueChange={(value) => handleFieldChange('status', value)}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{BIDDING_STATUS_OPTIONS.filter((opt) => opt.value !== 'all').map(
|
|
(option) => (
|
|
<SelectItem key={option.value} value={option.value}>
|
|
{option.label}
|
|
</SelectItem>
|
|
)
|
|
)}
|
|
</SelectContent>
|
|
</Select>
|
|
)}
|
|
</div>
|
|
|
|
{/* 투찰일 */}
|
|
<div className="space-y-2">
|
|
<Label>투찰일</Label>
|
|
{isViewMode ? (
|
|
<Input
|
|
value={formData.submissionDate || '-'}
|
|
disabled
|
|
className="bg-muted"
|
|
/>
|
|
) : (
|
|
<DatePicker
|
|
value={formData.submissionDate}
|
|
onChange={(date) => handleFieldChange('submissionDate', date)}
|
|
/>
|
|
)}
|
|
</div>
|
|
|
|
{/* 확정일 */}
|
|
<div className="space-y-2">
|
|
<Label>확정일</Label>
|
|
{isViewMode ? (
|
|
<Input
|
|
value={formData.confirmDate || '-'}
|
|
disabled
|
|
className="bg-muted"
|
|
/>
|
|
) : (
|
|
<DatePicker
|
|
value={formData.confirmDate}
|
|
onChange={(date) => handleFieldChange('confirmDate', date)}
|
|
/>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 비고 */}
|
|
<div className="mt-4 space-y-2">
|
|
<Label>비고</Label>
|
|
{isViewMode ? (
|
|
<Textarea
|
|
value={formData.remarks || '-'}
|
|
disabled
|
|
className="min-h-[80px] resize-none bg-muted"
|
|
/>
|
|
) : (
|
|
<Textarea
|
|
value={formData.remarks}
|
|
onChange={(e) => handleFieldChange('remarks', e.target.value)}
|
|
placeholder="비고를 입력하세요"
|
|
className="min-h-[80px] resize-none"
|
|
/>
|
|
)}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* 공과 상세 섹션 (읽기 전용) */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-base">공과 상세</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="rounded-md border">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead className="w-[60%]">공과</TableHead>
|
|
<TableHead className="text-right">금액</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{formData.expenseItems.length === 0 ? (
|
|
<TableRow>
|
|
<TableCell colSpan={2} className="h-24 text-center text-muted-foreground">
|
|
공과 내역이 없습니다.
|
|
</TableCell>
|
|
</TableRow>
|
|
) : (
|
|
<>
|
|
{formData.expenseItems.map((item) => (
|
|
<TableRow key={item.id}>
|
|
<TableCell>{item.name}</TableCell>
|
|
<TableCell className="text-right">
|
|
{formatNumber(item.amount)}원
|
|
</TableCell>
|
|
</TableRow>
|
|
))}
|
|
<TableRow className="bg-muted/50 font-medium">
|
|
<TableCell>합계</TableCell>
|
|
<TableCell className="text-right">
|
|
{formatNumber(expenseTotal)}원
|
|
</TableCell>
|
|
</TableRow>
|
|
</>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
{/* 견적 상세 섹션 (읽기 전용 - 견적 상세 페이지와 동일) */}
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-base">견적 상세</CardTitle>
|
|
</CardHeader>
|
|
<CardContent>
|
|
<div className="overflow-x-auto max-h-[600px] rounded-md border">
|
|
<Table>
|
|
<TableHeader className="sticky top-0 bg-white z-10">
|
|
<TableRow className="bg-gray-100">
|
|
<TableHead className="w-[100px] text-center">명칭</TableHead>
|
|
<TableHead className="w-[80px] text-center">제품</TableHead>
|
|
<TableHead className="w-[70px] text-right">가로</TableHead>
|
|
<TableHead className="w-[70px] text-right">세로</TableHead>
|
|
<TableHead className="w-[70px] text-right">무게</TableHead>
|
|
<TableHead className="w-[70px] text-right">면적</TableHead>
|
|
<TableHead className="w-[90px] text-right">철제,스크린</TableHead>
|
|
<TableHead className="w-[80px] text-right">코킹</TableHead>
|
|
<TableHead className="w-[80px] text-right">레일</TableHead>
|
|
<TableHead className="w-[80px] text-right">하장</TableHead>
|
|
<TableHead className="w-[90px] text-right">박스+보강</TableHead>
|
|
<TableHead className="w-[80px] text-right">샤프트</TableHead>
|
|
<TableHead className="w-[80px] text-right">도장</TableHead>
|
|
<TableHead className="w-[80px] text-right">모터</TableHead>
|
|
<TableHead className="w-[80px] text-right">제어기</TableHead>
|
|
<TableHead className="w-[100px] text-right">가로시공비</TableHead>
|
|
<TableHead className="w-[100px] text-right">세로시공비</TableHead>
|
|
<TableHead className="w-[90px] text-right">단가</TableHead>
|
|
<TableHead className="w-[70px] text-right">공과율</TableHead>
|
|
<TableHead className="w-[80px] text-right">공과</TableHead>
|
|
<TableHead className="w-[50px] text-right">수량</TableHead>
|
|
<TableHead className="w-[90px] text-right">원가</TableHead>
|
|
<TableHead className="w-[90px] text-right">원가실행</TableHead>
|
|
<TableHead className="w-[90px] text-right">마진원가</TableHead>
|
|
<TableHead className="w-[100px] text-right">마진원가실행</TableHead>
|
|
<TableHead className="w-[90px] text-right">공과실행</TableHead>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
{formData.estimateDetailItems.length === 0 ? (
|
|
<TableRow>
|
|
<TableCell colSpan={26} className="h-24 text-center text-muted-foreground">
|
|
견적 상세 내역이 없습니다.
|
|
</TableCell>
|
|
</TableRow>
|
|
) : (
|
|
<>
|
|
{formData.estimateDetailItems.map((item) => (
|
|
<TableRow key={item.id}>
|
|
<TableCell className="bg-gray-50">{item.name}</TableCell>
|
|
<TableCell className="bg-gray-50">{item.material}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{item.width?.toFixed(2) || '0.00'}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{item.height?.toFixed(2) || '0.00'}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{item.weight?.toFixed(2) || '0.00'}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{item.area?.toFixed(2) || '0.00'}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.steelScreen || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.caulking || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.rail || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.bottom || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.boxReinforce || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.shaft || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.painting || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.motor || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.controller || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.widthConstruction || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.heightConstruction || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50 font-medium">{formatNumber(item.unitPrice || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{item.expenseRate || 0}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.expense || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{item.quantity || 0}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.cost || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.costExecution || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.marginCost || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50 font-medium">{formatNumber(item.marginCostExecution || 0)}</TableCell>
|
|
<TableCell className="text-right bg-gray-50">{formatNumber(item.expenseExecution || 0)}</TableCell>
|
|
</TableRow>
|
|
))}
|
|
{/* 합계 행 */}
|
|
<TableRow className="bg-orange-50 font-medium border-t-2 border-orange-300">
|
|
<TableCell colSpan={4} className="text-center font-bold">합계</TableCell>
|
|
<TableCell className="text-right">{estimateDetailTotals.weight.toFixed(2)}</TableCell>
|
|
<TableCell className="text-right">{estimateDetailTotals.area.toFixed(2)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.steelScreen)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.caulking)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.rail)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.bottom)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.boxReinforce)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.shaft)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.painting)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.motor)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.controller)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.widthConstruction)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.heightConstruction)}</TableCell>
|
|
<TableCell className="text-right font-bold">{formatNumber(estimateDetailTotals.unitPrice)}</TableCell>
|
|
<TableCell className="text-right">-</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.expense)}</TableCell>
|
|
<TableCell className="text-right">{estimateDetailTotals.quantity}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.cost)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.costExecution)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.marginCost)}</TableCell>
|
|
<TableCell className="text-right font-bold">{formatNumber(estimateDetailTotals.marginCostExecution)}</TableCell>
|
|
<TableCell className="text-right">{formatNumber(estimateDetailTotals.expenseExecution)}</TableCell>
|
|
</TableRow>
|
|
</>
|
|
)}
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
|
|
// 템플릿 동적 설정
|
|
// Note: IntegratedDetailTemplate이 모드에 따라 '상세'/'수정' 자동 추가
|
|
const dynamicConfig = {
|
|
...biddingConfig,
|
|
title: '입찰',
|
|
};
|
|
|
|
return (
|
|
<IntegratedDetailTemplate
|
|
config={dynamicConfig}
|
|
mode={mode}
|
|
initialData={{}}
|
|
itemId={biddingId}
|
|
isLoading={false}
|
|
onSubmit={handleSubmit}
|
|
renderView={() => renderFormContent()}
|
|
renderForm={() => renderFormContent()}
|
|
/>
|
|
);
|
|
} |