feat: 수주/견적 기능 개선 및 PDF 생성 업데이트

- 수주 상세 뷰/수정 컴포넌트 개선
- 견적 위치 패널 업데이트
- PDF 생성 API 수정
- 레이아웃 및 공통코드 API 업데이트
- 패키지 의존성 업데이트
This commit is contained in:
2026-01-29 01:12:58 +09:00
parent d2a39de576
commit 6bcd298995
12 changed files with 272 additions and 81 deletions

View File

@@ -402,7 +402,7 @@ export function LocationDetailPanel({
<SelectContent>
{finishedGoods.map((fg) => (
<SelectItem key={fg.item_code} value={fg.item_code}>
{fg.item_code}
{fg.item_code} {fg.item_name}
</SelectItem>
))}
</SelectContent>
@@ -477,8 +477,8 @@ export function LocationDetailPanel({
</div>
</div>
{/* 3행: 제작사이즈, 산출중량, 산출면적, 수량 */}
<div className="grid grid-cols-4 gap-3 text-sm pt-2 border-t border-gray-200">
{/* 3행: 제작사이즈, 산출중량, 산출면적, 수량, 산출하기 */}
<div className="grid grid-cols-5 gap-3 text-sm pt-2 border-t border-gray-200">
<div>
<span className="text-xs text-gray-500"></span>
<p className="font-semibold">
@@ -503,6 +503,24 @@ export function LocationDetailPanel({
: "-"}
</p>
</div>
<div>
<span className="text-xs text-gray-500"> (QTY)</span>
<QuantityInput
value={location.quantity}
onChange={(newQty) => {
if (!location || disabled) return;
// 수량 변경 시 totalPrice 재계산
const unitPrice = location.unitPrice || 0;
onUpdateLocation(location.id, {
quantity: newQty,
totalPrice: unitPrice * newQty,
});
}}
className="h-8 text-sm font-semibold"
min={1}
disabled={disabled}
/>
</div>
<div className="flex items-end">
<Button
onClick={() => onCalculateLocation?.(location.id)}
@@ -600,7 +618,41 @@ export function LocationDetailPanel({
<TableCell className="text-center">
<QuantityInput
value={item.quantity}
onChange={() => {}}
onChange={(newQty) => {
if (!location || disabled) return;
const existingBomResult = location.bomResult;
if (!existingBomResult) return;
// 해당 아이템 찾아서 수량 및 금액 업데이트
const updatedItems = (existingBomResult.items || []).map((bomItem: any, i: number) => {
if (bomItemsByTab[tab.value]?.[index] === bomItem) {
const newTotalPrice = (bomItem.unit_price || 0) * newQty;
return {
...bomItem,
quantity: newQty,
total_price: newTotalPrice,
};
}
return bomItem;
});
// grand_total 재계산
const newGrandTotal = updatedItems.reduce(
(sum: number, item: any) => sum + (item.total_price || 0),
0
);
// location 업데이트 (unitPrice, totalPrice 포함)
onUpdateLocation(location.id, {
unitPrice: newGrandTotal,
totalPrice: newGrandTotal * location.quantity,
bomResult: {
...existingBomResult,
items: updatedItems,
grand_total: newGrandTotal,
},
});
}}
className="w-14 h-7 text-center text-xs"
min={1}
disabled={disabled}

View File

@@ -324,7 +324,7 @@ export function LocationListPanel({
<SelectContent>
{finishedGoods.map((fg) => (
<SelectItem key={fg.item_code} value={fg.item_code}>
{fg.item_code}
{fg.item_code} {fg.item_name}
</SelectItem>
))}
</SelectContent>