fix(WEB): 견적 수정 화면 탭 복원 개선 (#8)

이슈 #8: 수정 화면에서 14개 탭 대신 1개 탭으로 올바르게 표시

주요 변경:
- edit/page.tsx: calculation_inputs.items 기반 폼 복원
- [id]/page.tsx: 상세 화면 데이터 표시 개선
- new/page.tsx: 신규 등록 화면 개선
This commit is contained in:
2026-01-06 21:21:03 +09:00
parent b52e9c70af
commit 14556251f1
3 changed files with 77 additions and 6 deletions

View File

@@ -30,8 +30,18 @@ export default function QuoteEditPage() {
setIsLoading(true);
try {
const result = await getQuoteById(quoteId);
console.log('[EditPage] API 응답 result.data:', JSON.stringify({
calculationInputs: result.data?.calculationInputs,
items: result.data?.items?.map(i => ({ quantity: i.quantity, unitPrice: i.unitPrice }))
}, null, 2));
if (result.success && result.data) {
const formData = transformQuoteToFormData(result.data);
console.log('[EditPage] 변환된 formData.items[0]:', JSON.stringify({
quantity: formData.items[0]?.quantity,
wingSize: formData.items[0]?.wingSize,
inspectionFee: formData.items[0]?.inspectionFee,
}, null, 2));
setQuote(formData);
} else {
toast.error(result.error || "견적 정보를 불러오는데 실패했습니다.");

View File

@@ -21,6 +21,8 @@ import {
sendQuoteKakao,
transformQuoteToFormData,
} from "@/components/quotes";
import { getCompanyInfo } from "@/components/settings/CompanyInfoManagement/actions";
import type { CompanyFormData } from "@/components/settings/CompanyInfoManagement/types";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -54,6 +56,7 @@ export default function QuoteDetailPage() {
const quoteId = params.id as string;
const [quote, setQuote] = useState<QuoteFormData | null>(null);
const [companyInfo, setCompanyInfo] = useState<CompanyFormData | null>(null);
const [isLoading, setIsLoading] = useState(true);
const [isProcessing, setIsProcessing] = useState(false);
@@ -72,7 +75,33 @@ export default function QuoteDetailPage() {
try {
const result = await getQuoteById(quoteId);
if (result.success && result.data) {
// 디버깅: Quote 변환 전 데이터
console.log('[QuoteDetail] Quote data:', {
clientId: result.data.clientId,
clientName: result.data.clientName,
calculationInputs: result.data.calculationInputs,
items: result.data.items?.map(item => ({
productName: item.productName,
quantity: item.quantity,
unitPrice: item.unitPrice,
totalAmount: item.totalAmount,
})),
});
const formData = transformQuoteToFormData(result.data);
// 디버깅: QuoteFormData 변환 후 데이터
console.log('[QuoteDetail] FormData:', {
clientId: formData.clientId,
clientName: formData.clientName,
items: formData.items?.map(item => ({
productName: item.productName,
quantity: item.quantity,
inspectionFee: item.inspectionFee,
totalAmount: item.totalAmount,
})),
});
setQuote(formData);
} else {
toast.error(result.error || "견적 정보를 불러오는데 실패했습니다.");
@@ -86,9 +115,22 @@ export default function QuoteDetailPage() {
}
}, [quoteId, router]);
// 회사 정보 조회
const fetchCompanyInfo = useCallback(async () => {
try {
const result = await getCompanyInfo();
if (result.success && result.data) {
setCompanyInfo(result.data);
}
} catch (error) {
console.error('[QuoteDetail] Failed to fetch company info:', error);
}
}, []);
useEffect(() => {
fetchQuote();
}, [fetchQuote]);
fetchCompanyInfo();
}, [fetchQuote, fetchCompanyInfo]);
const handleBack = () => {
router.push("/sales/quote-management");
@@ -190,10 +232,12 @@ export default function QuoteDetailPage() {
return amount.toLocaleString("ko-KR");
};
// 총 금액 계산
// 총 금액 계산 (실제 금액 우선, 없으면 검사비 사용)
const totalAmount =
quote?.items?.reduce((sum, item) => {
return sum + (item.inspectionFee || 0) * (item.quantity || 1);
// totalAmount가 있으면 사용, 없으면 unitPrice * quantity, 마지막으로 inspectionFee
const itemAmount = item.totalAmount || (item.unitPrice || 0) * (item.quantity || 1) || (item.inspectionFee || 0) * (item.quantity || 1);
return sum + itemAmount;
}, 0) || 0;
if (isLoading) {
@@ -395,7 +439,7 @@ export default function QuoteDetailPage() {
<div>
<span className="text-gray-500"></span>
<p className="font-medium text-blue-600">
{formatAmount((item.inspectionFee || 0) * (item.quantity || 1))}
{formatAmount(item.totalAmount || (item.unitPrice || 0) * (item.quantity || 1) || (item.inspectionFee || 0) * (item.quantity || 1))}
</p>
</div>
</div>
@@ -489,7 +533,7 @@ export default function QuoteDetailPage() {
{/* 문서 영역 */}
<div className="flex-1 overflow-y-auto bg-gray-100 p-4">
<div className="max-w-[210mm] mx-auto bg-white shadow-lg rounded-lg p-8">
<QuoteDocument quote={quote} />
<QuoteDocument quote={quote} companyInfo={companyInfo} />
</div>
</div>
</DialogContent>
@@ -598,6 +642,7 @@ export default function QuoteDetailPage() {
<div className="max-w-[210mm] mx-auto bg-white shadow-lg rounded-lg p-8">
<QuoteCalculationReport
quote={quote}
companyInfo={companyInfo}
documentType="견적산출내역서"
showDetailedBreakdown={showDetailedBreakdown}
showMaterialList={showMaterialList}
@@ -676,7 +721,7 @@ export default function QuoteDetailPage() {
{/* 문서 영역 */}
<div className="flex-1 overflow-y-auto bg-gray-100 p-4">
<div className="max-w-[210mm] mx-auto bg-white shadow-lg rounded-lg p-8">
<PurchaseOrderDocument quote={quote} />
<PurchaseOrderDocument quote={quote} companyInfo={companyInfo} />
</div>
</div>
</DialogContent>

View File

@@ -23,9 +23,25 @@ export default function QuoteNewPage() {
setIsSaving(true);
try {
// DEBUG: 원본 formData 확인
console.log('[QuoteNewPage] formData 원본:', {
writer: formData.writer,
manager: formData.manager,
contact: formData.contact,
remarks: formData.remarks,
});
// FormData를 API 요청 형식으로 변환
const apiData = transformFormDataToApi(formData);
// DEBUG: 변환된 apiData 확인
console.log('[QuoteNewPage] apiData 변환 후:', {
author: (apiData as any).author,
manager: (apiData as any).manager,
contact: (apiData as any).contact,
remarks: (apiData as any).remarks,
});
const result = await createQuote(apiData as any);
if (result.success && result.data) {