diff --git a/src/app/[locale]/(protected)/construction/project/bidding/estimates/[id]/edit/page.tsx b/src/app/[locale]/(protected)/construction/project/bidding/estimates/[id]/edit/page.tsx index ec5a3f80..815b3c85 100644 --- a/src/app/[locale]/(protected)/construction/project/bidding/estimates/[id]/edit/page.tsx +++ b/src/app/[locale]/(protected)/construction/project/bidding/estimates/[id]/edit/page.tsx @@ -9,190 +9,6 @@ interface EstimateEditPageProps { params: Promise<{ id: string }>; } -// 목업 데이터 - 추후 API 연동 -function getEstimateDetail(id: string): EstimateDetail { - // TODO: 실제 API 연동 - const mockData: EstimateDetail = { - id, - estimateCode: '123123', - partnerId: '1', - partnerName: '회사명', - projectName: '현장명', - estimatorId: 'hong', - estimatorName: '이름', - estimateCompanyManager: '홍길동', - estimateCompanyManagerContact: '01012341234', - itemCount: 21, - estimateAmount: 1420000, - completedDate: null, - bidDate: '2025-12-12', - status: 'pending', - createdAt: '2025-12-01', - updatedAt: '2025-12-01', - createdBy: 'hong', - siteBriefing: { - briefingCode: '123123', - partnerName: '회사명', - companyName: '회사명', - briefingDate: '2025-12-12', - attendee: '이름', - }, - bidInfo: { - projectName: '현장명', - bidDate: '2025-12-12', - siteCount: 21, - constructionPeriod: '2026-01-01 ~ 2026-12-10', - constructionStartDate: '2026-01-01', - constructionEndDate: '2026-12-10', - vatType: 'excluded', - workReport: '업무 보고 내용', - documents: [ - { - id: '1', - fileName: 'abc.zip', - fileUrl: '#', - fileSize: 1024000, - }, - ], - }, - summaryItems: [ - { - id: '1', - name: '서터 심창측공사', - quantity: 1, - unit: '식', - materialCost: 78540000, - laborCost: 15410000, - totalCost: 93950000, - remarks: '', - }, - ], - expenseItems: [ - { - id: '1', - name: 'public_1', - amount: 10000, - }, - ], - priceAdjustments: [ - { - id: '1', - category: '배합비', - unitPrice: 10000, - coating: 10000, - batting: 10000, - boxReinforce: 10500, - painting: 10500, - total: 51000, - }, - { - id: '2', - category: '재단비', - unitPrice: 1375, - coating: 0, - batting: 0, - boxReinforce: 0, - painting: 0, - total: 1375, - }, - { - id: '3', - category: '판매단가', - unitPrice: 0, - coating: 10000, - batting: 10000, - boxReinforce: 10500, - painting: 10500, - total: 41000, - }, - { - id: '4', - category: '조립단가', - unitPrice: 10300, - coating: 10300, - batting: 10300, - boxReinforce: 10500, - painting: 10200, - total: 51600, - }, - ], - detailItems: [ - { - id: '1', - no: 1, - name: 'FS530외/주차', - material: 'screen', - width: 2350, - height: 2500, - quantity: 1, - box: 1, - assembly: 0, - coating: 0, - batting: 0, - mounting: 0, - fitting: 0, - controller: 0, - widthConstruction: 0, - heightConstruction: 0, - materialCost: 1420000, - laborCost: 510000, - quantityPrice: 1930000, - expenseQuantity: 5500, - expenseTotal: 5500, - totalCost: 1930000, - otherCost: 0, - marginCost: 0, - totalPrice: 1930000, - unitPrice: 1420000, - expense: 0, - marginRate: 0, - unitQuantity: 1, - expenseResult: 0, - marginActual: 0, - }, - { - id: '2', - no: 2, - name: 'FS530외/주차', - material: 'screen', - width: 7500, - height: 2500, - quantity: 1, - box: 1, - assembly: 0, - coating: 0, - batting: 0, - mounting: 0, - fitting: 0, - controller: 0, - widthConstruction: 0, - heightConstruction: 0, - materialCost: 4720000, - laborCost: 780000, - quantityPrice: 5500000, - expenseQuantity: 5500, - expenseTotal: 5500, - totalCost: 5500000, - otherCost: 0, - marginCost: 0, - totalPrice: 5500000, - unitPrice: 4720000, - expense: 0, - marginRate: 0, - unitQuantity: 1, - expenseResult: 0, - marginActual: 0, - }, - ], - approval: { - approvers: [], - references: [], - }, - }; - - return mockData; -} - export default function EstimateEditPage({ params }: EstimateEditPageProps) { const { id } = use(params); const [data, setData] = useState(null); diff --git a/src/app/[locale]/(protected)/construction/project/bidding/estimates/[id]/page.tsx b/src/app/[locale]/(protected)/construction/project/bidding/estimates/[id]/page.tsx index 5e392531..4778e319 100644 --- a/src/app/[locale]/(protected)/construction/project/bidding/estimates/[id]/page.tsx +++ b/src/app/[locale]/(protected)/construction/project/bidding/estimates/[id]/page.tsx @@ -9,190 +9,6 @@ interface EstimateDetailPageProps { params: Promise<{ id: string }>; } -// 목업 데이터 - 추후 API 연동 -function getEstimateDetail(id: string): EstimateDetail { - // TODO: 실제 API 연동 - const mockData: EstimateDetail = { - id, - estimateCode: '123123', - partnerId: '1', - partnerName: '회사명', - projectName: '현장명', - estimatorId: 'hong', - estimatorName: '이름', - estimateCompanyManager: '홍길동', - estimateCompanyManagerContact: '01012341234', - itemCount: 21, - estimateAmount: 1420000, - completedDate: null, - bidDate: '2025-12-12', - status: 'pending', - createdAt: '2025-12-01', - updatedAt: '2025-12-01', - createdBy: 'hong', - siteBriefing: { - briefingCode: '123123', - partnerName: '회사명', - companyName: '회사명', - briefingDate: '2025-12-12', - attendee: '이름', - }, - bidInfo: { - projectName: '현장명', - bidDate: '2025-12-12', - siteCount: 21, - constructionPeriod: '2026-01-01 ~ 2026-12-10', - constructionStartDate: '2026-01-01', - constructionEndDate: '2026-12-10', - vatType: 'excluded', - workReport: '업무 보고 내용', - documents: [ - { - id: '1', - fileName: 'abc.zip', - fileUrl: '#', - fileSize: 1024000, - }, - ], - }, - summaryItems: [ - { - id: '1', - name: '서터 심창측공사', - quantity: 1, - unit: '식', - materialCost: 78540000, - laborCost: 15410000, - totalCost: 93950000, - remarks: '', - }, - ], - expenseItems: [ - { - id: '1', - name: 'public_1', - amount: 10000, - }, - ], - priceAdjustments: [ - { - id: '1', - category: '배합비', - unitPrice: 10000, - coating: 10000, - batting: 10000, - boxReinforce: 10500, - painting: 10500, - total: 51000, - }, - { - id: '2', - category: '재단비', - unitPrice: 1375, - coating: 0, - batting: 0, - boxReinforce: 0, - painting: 0, - total: 1375, - }, - { - id: '3', - category: '판매단가', - unitPrice: 0, - coating: 10000, - batting: 10000, - boxReinforce: 10500, - painting: 10500, - total: 41000, - }, - { - id: '4', - category: '조립단가', - unitPrice: 10300, - coating: 10300, - batting: 10300, - boxReinforce: 10500, - painting: 10200, - total: 51600, - }, - ], - detailItems: [ - { - id: '1', - no: 1, - name: 'FS530외/주차', - material: 'screen', - width: 2350, - height: 2500, - quantity: 1, - box: 1, - assembly: 0, - coating: 0, - batting: 0, - mounting: 0, - fitting: 0, - controller: 0, - widthConstruction: 0, - heightConstruction: 0, - materialCost: 1420000, - laborCost: 510000, - quantityPrice: 1930000, - expenseQuantity: 5500, - expenseTotal: 5500, - totalCost: 1930000, - otherCost: 0, - marginCost: 0, - totalPrice: 1930000, - unitPrice: 1420000, - expense: 0, - marginRate: 0, - unitQuantity: 1, - expenseResult: 0, - marginActual: 0, - }, - { - id: '2', - no: 2, - name: 'FS530외/주차', - material: 'screen', - width: 7500, - height: 2500, - quantity: 1, - box: 1, - assembly: 0, - coating: 0, - batting: 0, - mounting: 0, - fitting: 0, - controller: 0, - widthConstruction: 0, - heightConstruction: 0, - materialCost: 4720000, - laborCost: 780000, - quantityPrice: 5500000, - expenseQuantity: 5500, - expenseTotal: 5500, - totalCost: 5500000, - otherCost: 0, - marginCost: 0, - totalPrice: 5500000, - unitPrice: 4720000, - expense: 0, - marginRate: 0, - unitQuantity: 1, - expenseResult: 0, - marginActual: 0, - }, - ], - approval: { - approvers: [], - references: [], - }, - }; - - return mockData; -} - export default function EstimateDetailPage({ params }: EstimateDetailPageProps) { const { id } = use(params); const [data, setData] = useState(null); diff --git a/src/components/business/construction/estimates/actions.ts b/src/components/business/construction/estimates/actions.ts index 052c4996..57d0c525 100644 --- a/src/components/business/construction/estimates/actions.ts +++ b/src/components/business/construction/estimates/actions.ts @@ -48,6 +48,42 @@ interface ApiQuote { // 연관 데이터 items?: ApiQuoteItem[]; site_briefing?: ApiSiteBriefing; + // 옵션 데이터 (JSON) + options?: ApiQuoteOptions; +} + +interface ApiQuoteOptions { + summary_items?: ApiSummaryItem[]; + expense_items?: ApiExpenseItem[]; + price_adjustments?: ApiPriceAdjustment[]; +} + +interface ApiSummaryItem { + id: string; + name: string; + quantity: number; + unit: string; + material_cost: number; + labor_cost: number; + total_cost: number; + remarks?: string; +} + +interface ApiExpenseItem { + id: string; + name: string; + amount: number; +} + +interface ApiPriceAdjustment { + id: string; + category: string; + unit_price: number; + coating: number; + batting: number; + box_reinforce: number; + painting: number; + total: number; } interface ApiQuoteItem { @@ -210,9 +246,36 @@ function transformQuoteToEstimateDetail(apiData: ApiQuote): EstimateDetail { documents: [], }; - const summaryItems: EstimateSummaryItem[] = []; - const expenseItems: ExpenseItem[] = []; - const priceAdjustments: PriceAdjustmentItem[] = []; + // options에서 데이터 변환 + const opts = apiData.options; + + const summaryItems: EstimateSummaryItem[] = (opts?.summary_items || []).map((item) => ({ + id: item.id, + name: item.name, + quantity: item.quantity, + unit: item.unit, + materialCost: item.material_cost, + laborCost: item.labor_cost, + totalCost: item.total_cost, + remarks: item.remarks || '', + })); + + const expenseItems: ExpenseItem[] = (opts?.expense_items || []).map((item) => ({ + id: item.id, + name: item.name, + amount: item.amount, + })); + + const priceAdjustments: PriceAdjustmentItem[] = (opts?.price_adjustments || []).map((item) => ({ + id: item.id, + category: item.category, + unitPrice: item.unit_price, + coating: item.coating, + batting: item.batting, + boxReinforce: item.box_reinforce, + painting: item.painting, + total: item.total, + })); const detailItems: EstimateDetailItem[] = (apiData.items || []).map((item, index) => ({ id: String(item.id), @@ -286,6 +349,47 @@ function transformToApiRequest(data: Partial): Record = {}; + + if (data.summaryItems !== undefined) { + options.summary_items = data.summaryItems.map((item) => ({ + id: item.id, + name: item.name, + quantity: item.quantity, + unit: item.unit, + material_cost: item.materialCost, + labor_cost: item.laborCost, + total_cost: item.totalCost, + remarks: item.remarks, + })); + } + + if (data.expenseItems !== undefined) { + options.expense_items = data.expenseItems.map((item) => ({ + id: item.id, + name: item.name, + amount: item.amount, + })); + } + + if (data.priceAdjustments !== undefined) { + options.price_adjustments = data.priceAdjustments.map((item) => ({ + id: item.id, + category: item.category, + unit_price: item.unitPrice, + coating: item.coating, + batting: item.batting, + box_reinforce: item.boxReinforce, + painting: item.painting, + total: item.total, + })); + } + + if (Object.keys(options).length > 0) { + apiData.options = options; + } + return apiData; }