fix(WEB): 견적 수정 화면 탭 복원 개선 (#8)
이슈 #8: 수정 화면에서 14개 탭 대신 1개 탭으로 올바르게 표시 주요 변경: - edit/page.tsx: calculation_inputs.items 기반 폼 복원 - [id]/page.tsx: 상세 화면 데이터 표시 개선 - new/page.tsx: 신규 등록 화면 개선
This commit is contained in:
@@ -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 || "견적 정보를 불러오는데 실패했습니다.");
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user