This commit is contained in:
유병철
2026-01-21 20:56:38 +09:00
21 changed files with 2846 additions and 31 deletions

View File

@@ -58,6 +58,8 @@ import { getClients } from "../accounting/VendorManagement/actions";
import { isNextRedirectError } from "@/lib/utils/redirect-error";
import type { Vendor } from "../accounting/VendorManagement";
import type { BomMaterial, CalculationResults } from "./types";
import { useDevFill } from "@/components/dev";
import { generateQuoteData } from "@/components/dev/generators/quoteData";
// 견적 항목 타입
export interface QuoteItem {
@@ -203,6 +205,20 @@ export function QuoteRegistration({
// 현장명 자동완성 목록 상태
const [siteNames, setSiteNames] = useState<string[]>([]);
// DevToolbar용 폼 자동 채우기 등록
useDevFill(
'quote',
useCallback(() => {
// 실제 로드된 데이터를 기반으로 샘플 데이터 생성
const sampleData = generateQuoteData({
clients: clients.map(c => ({ id: c.id, name: c.vendorName })),
products: finishedGoods.map(p => ({ code: p.item_code, name: p.item_name, category: p.category })),
});
setFormData(sampleData);
toast.success('[Dev] 견적 폼이 자동으로 채워졌습니다.');
}, [clients, finishedGoods])
);
// 수량 반영 총합계 계산 (useMemo로 최적화)
const calculatedGrandTotal = useMemo(() => {
if (!calculationResults?.items) return 0;
@@ -1081,32 +1097,32 @@ export function QuoteRegistration({
const formItem = formData.items[itemResult.index];
const product = finishedGoods.find(fg => fg.item_code === formItem?.productName);
return (
<div key={idx} className="border border-green-200 rounded-lg p-4 bg-white">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Badge variant="outline" className="bg-green-100">
{itemResult.index + 1}
</Badge>
<span className="font-medium">
{itemResult.result.finished_goods?.name || product?.item_name || formItem?.productName || "-"}
</span>
<span className="text-sm text-muted-foreground">
({itemResult.result.finished_goods?.code || formItem?.productName || "-"})
</span>
return (
<div key={idx} className="border border-green-200 rounded-lg p-4 bg-white">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Badge variant="outline" className="bg-green-100">
{itemResult.index + 1}
</Badge>
<span className="font-medium">
{itemResult.result.finished_goods?.name || product?.item_name || formItem?.productName || "-"}
</span>
<span className="text-sm text-muted-foreground">
({itemResult.result.finished_goods?.code || formItem?.productName || "-"})
</span>
</div>
<div className="text-right">
<div className="text-sm text-muted-foreground">
: {(itemResult.result.grand_total || 0).toLocaleString()}
</div>
<div className="text-right">
<div className="text-sm text-muted-foreground">
: {itemResult.result.grand_total.toLocaleString()}
</div>
<div className="font-semibold text-green-700">
: {((itemResult.result.grand_total || 0) * (formItem?.quantity || 1)).toLocaleString()}
<span className="text-xs text-muted-foreground ml-1">
(×{formItem?.quantity || 1})
</span>
</div>
<div className="font-semibold text-green-700">
: {((itemResult.result.grand_total || 0) * (formItem?.quantity || 1)).toLocaleString()}
<span className="text-xs text-muted-foreground ml-1">
(×{formItem?.quantity || 1})
</span>
</div>
</div>
</div>
{/* BOM 상세 내역 */}
{itemResult.result.items && itemResult.result.items.length > 0 && (