diff --git a/src/components/production/WorkOrders/documents/bending/BottomBarSection.tsx b/src/components/production/WorkOrders/documents/bending/BottomBarSection.tsx
index 0324a415..2ce79584 100644
--- a/src/components/production/WorkOrders/documents/bending/BottomBarSection.tsx
+++ b/src/components/production/WorkOrders/documents/bending/BottomBarSection.tsx
@@ -55,9 +55,7 @@ export function BottomBarSection({ bendingInfo, mapping }: BottomBarSectionProps
{row.material} |
{fmt(row.length)} |
{fmt(row.quantity)} |
-
- {row.lotPrefix}-
- |
+ - |
{fmtWeight(row.weight)} |
))}
diff --git a/src/components/production/WorkOrders/documents/bending/GuideRailSection.tsx b/src/components/production/WorkOrders/documents/bending/GuideRailSection.tsx
index bad051fe..4fa924ad 100644
--- a/src/components/production/WorkOrders/documents/bending/GuideRailSection.tsx
+++ b/src/components/production/WorkOrders/documents/bending/GuideRailSection.tsx
@@ -60,9 +60,7 @@ function PartTable({ title, rows, imageUrl, lotNo, baseSize }: {
{row.partName === '하부BASE' ? (baseSize || '-') : fmt(row.length)}
{fmt(row.quantity)} |
-
- {row.lotPrefix}-
- |
+ - |
{fmtWeight(row.weight)} |
))}
@@ -79,11 +77,11 @@ export function GuideRailSection({ bendingInfo, mapping, lotNo }: GuideRailSecti
const productCode = bendingInfo.productCode;
const wallRows = wall
- ? buildWallGuideRailRows(wall.lengthData, wall.baseSize, mapping)
+ ? buildWallGuideRailRows(wall.lengthData, wall.baseDimension || '135*80', mapping)
: [];
const sideRows = side
- ? buildSideGuideRailRows(side.lengthData, mapping)
+ ? buildSideGuideRailRows(side.lengthData, side.baseDimension || '135*130', mapping)
: [];
if (wallRows.length === 0 && sideRows.length === 0) return null;
@@ -100,7 +98,7 @@ export function GuideRailSection({ bendingInfo, mapping, lotNo }: GuideRailSecti
rows={wallRows}
imageUrl={getBendingImageUrl('guiderail', productCode, 'wall')}
lotNo={lotNo}
- baseSize={wall?.baseSize}
+ baseSize={wall?.baseDimension || wall?.baseSize}
/>
)}
@@ -110,7 +108,7 @@ export function GuideRailSection({ bendingInfo, mapping, lotNo }: GuideRailSecti
rows={sideRows}
imageUrl={getBendingImageUrl('guiderail', productCode, 'side')}
lotNo={lotNo}
- baseSize="135*130"
+ baseSize={side?.baseDimension || '135*130'}
/>
)}
diff --git a/src/components/production/WorkOrders/documents/bending/ShutterBoxSection.tsx b/src/components/production/WorkOrders/documents/bending/ShutterBoxSection.tsx
index ee302b98..2db3eff4 100644
--- a/src/components/production/WorkOrders/documents/bending/ShutterBoxSection.tsx
+++ b/src/components/production/WorkOrders/documents/bending/ShutterBoxSection.tsx
@@ -70,9 +70,7 @@ function ShutterBoxSubSection({ box, index }: { box: ShutterBoxData; index: numb
{row.material} |
{row.dimension} |
{fmt(row.quantity)} |
-
- {row.lotPrefix}-
- |
+ - |
{fmtWeight(row.weight)} |
))}
diff --git a/src/components/production/WorkOrders/documents/bending/SmokeBarrierSection.tsx b/src/components/production/WorkOrders/documents/bending/SmokeBarrierSection.tsx
index 10b02b39..49518a54 100644
--- a/src/components/production/WorkOrders/documents/bending/SmokeBarrierSection.tsx
+++ b/src/components/production/WorkOrders/documents/bending/SmokeBarrierSection.tsx
@@ -55,7 +55,7 @@ export function SmokeBarrierSection({ bendingInfo }: SmokeBarrierSectionProps) {
{row.material} |
{fmt(row.length)} |
{fmt(row.quantity)} |
- {row.lotCode} |
+ - |
{fmtWeight(row.weight)} |
))}
diff --git a/src/components/production/WorkOrders/documents/bending/types.ts b/src/components/production/WorkOrders/documents/bending/types.ts
index 91b171ca..f0dd4ed8 100644
--- a/src/components/production/WorkOrders/documents/bending/types.ts
+++ b/src/components/production/WorkOrders/documents/bending/types.ts
@@ -14,7 +14,8 @@ export interface LengthQuantity {
// 가이드레일 타입별 데이터
export interface GuideRailTypeData {
lengthData: LengthQuantity[];
- baseSize: string; // "135*80" 또는 "135*130"
+ baseSize: string; // BOM 프로파일 사이즈 "130*75" (섹션 제목용)
+ baseDimension?: string; // 실제 하부BASE 물리 치수 "135*130" (작업일지 표시/무게계산용)
}
// 셔터박스 데이터
diff --git a/src/components/production/WorkOrders/documents/bending/utils.ts b/src/components/production/WorkOrders/documents/bending/utils.ts
index ee79d3ca..85152e8d 100644
--- a/src/components/production/WorkOrders/documents/bending/utils.ts
+++ b/src/components/production/WorkOrders/documents/bending/utils.ts
@@ -27,9 +27,8 @@ const EGI_DENSITY = 7.85; // g/cm3
// 가이드레일
const WALL_PART_WIDTH = 412; // mm - 벽면형 파트 폭
const SIDE_PART_WIDTH = 462; // mm - 측면형 파트 폭
-const WALL_BASE_HEIGHT_MIXED = 80; // 혼합형 벽면 하부BASE 높이
-const WALL_BASE_HEIGHT_ONLY = 130; // 벽면형 단독 하부BASE 높이
-const SIDE_BASE_HEIGHT = 130; // 측면형 하부BASE 높이
+const WALL_BASE_HEIGHT = 80; // 벽면형 하부BASE 높이 (legacy: wall_basesize 135*80)
+const SIDE_BASE_HEIGHT = 130; // 측면형 하부BASE 높이 (legacy: side_basesize 135*130)
const BASE_WIDTH = 135; // 하부BASE 폭
// 하단마감재
@@ -48,6 +47,21 @@ const GUIDE_RAIL_LENGTH_BUCKETS = [2438, 3000, 3500, 4000, 4300];
const SHUTTER_BOX_LENGTH_BUCKETS = [1219, 2438, 3000, 3500, 4000, 4150];
const SMOKE_W50_LENGTH_BUCKETS = [2438, 3000, 3500, 4000, 4300];
+// ============================================================
+// 하부BASE 치수 파싱 헬퍼
+// ============================================================
+
+/** baseDimension 문자열("135*130")에서 width/height 파싱. 없으면 기본값 사용 */
+function parseBaseDimension(baseDimension: string | undefined, fallbackHeight: number): { width: number; height: number } {
+ if (baseDimension) {
+ const parts = baseDimension.split('*').map(Number);
+ if (parts.length === 2 && parts[0] > 0 && parts[1] > 0) {
+ return { width: parts[0], height: parts[1] };
+ }
+ }
+ return { width: BASE_WIDTH, height: fallbackHeight };
+}
+
// ============================================================
// 핵심 함수: calWeight (PHP Lines 27-55)
// ============================================================
@@ -165,12 +179,10 @@ export function getSLengthCode(length: number, category: string): string | null
*/
export function buildWallGuideRailRows(
lengthData: LengthQuantity[],
- baseSize: string,
+ baseDimension: string,
mapping: MaterialMapping,
): GuideRailPartRow[] {
const rows: GuideRailPartRow[] = [];
- const baseHeight = baseSize === '135*80' ? WALL_BASE_HEIGHT_MIXED : WALL_BASE_HEIGHT_ONLY;
-
for (const ld of lengthData) {
if (ld.quantity <= 0) continue;
@@ -211,9 +223,11 @@ export function buildWallGuideRailRows(
}
// 하부BASE (길이 데이터와 무관하게 1행)
+ // baseDimension: "135*130" (KQTS01/KTE01) 또는 "135*80" (기타)
const totalQty = lengthData.reduce((sum, ld) => sum + ld.quantity, 0);
if (totalQty > 0) {
- const baseW = calcWeight('EGI 1.55T', BASE_WIDTH, baseHeight);
+ const { width: bw, height: bh } = parseBaseDimension(baseDimension, WALL_BASE_HEIGHT);
+ const baseW = calcWeight('EGI 1.55T', bw, bh);
rows.push({
partName: '하부BASE', lotPrefix: 'XX', material: 'EGI 1.55T',
length: 0, quantity: totalQty, weight: Math.round(baseW.weight * totalQty * 100) / 100,
@@ -228,6 +242,7 @@ export function buildWallGuideRailRows(
*/
export function buildSideGuideRailRows(
lengthData: LengthQuantity[],
+ baseDimension: string,
mapping: MaterialMapping,
): GuideRailPartRow[] {
const rows: GuideRailPartRow[] = [];
@@ -259,9 +274,11 @@ export function buildSideGuideRailRows(
}
// 하부BASE
+ // baseDimension: "135*130" (측면형은 항상 135*130)
const totalQty = lengthData.reduce((sum, ld) => sum + ld.quantity, 0);
if (totalQty > 0) {
- const baseW = calcWeight('EGI 1.55T', BASE_WIDTH, SIDE_BASE_HEIGHT);
+ const { width: bw, height: bh } = parseBaseDimension(baseDimension, SIDE_BASE_HEIGHT);
+ const baseW = calcWeight('EGI 1.55T', bw, bh);
rows.push({
partName: '하부BASE', lotPrefix: 'XX', material: 'EGI 1.55T',
length: 0, quantity: totalQty, weight: Math.round(baseW.weight * totalQty * 100) / 100,
@@ -341,93 +358,74 @@ export function buildShutterBoxRows(box: ShutterBoxData): ShutterBoxPartRow[] {
const { width: boxWidth, height: boxHeight } = parseBoxSize(box.size);
const isStandard = box.size === '500*380';
- for (const ld of box.lengthData) {
- if (ld.quantity <= 0) continue;
+ // 방향별 파트 정의
+ let parts: { name: string; prefix: string; dim: number }[];
- if (isStandard) {
- // 표준 500*380 구성
- const parts = [
- { name: '①전면부', prefix: 'CF', dim: boxHeight + 122 },
- { name: '②린텔부', prefix: 'CL', dim: boxWidth - 330 },
- { name: '③⑤점검구', prefix: 'CP', dim: boxWidth - 200 },
- { name: '④후면코너부', prefix: 'CB', dim: 170 },
- ];
- for (const p of parts) {
- const w = calcWeight(BOX_FINISH_MATERIAL, p.dim, ld.length);
- rows.push({
- partName: p.name, lotPrefix: p.prefix, material: BOX_FINISH_MATERIAL,
- dimension: `${ld.length}`, quantity: ld.quantity,
- weight: Math.round(w.weight * ld.quantity * 100) / 100,
- });
- }
- } else if (box.direction === '양면') {
- const parts = [
- { name: '①전면부', prefix: 'XX', dim: boxHeight + 122 },
- { name: '②린텔부', prefix: 'CL', dim: boxWidth - 330 },
- { name: '③점검구', prefix: 'XX', dim: boxWidth - 200 },
- { name: '④후면코너부', prefix: 'CB', dim: 170 },
- { name: '⑤점검구', prefix: 'XX', dim: boxHeight - 100 },
- ];
- for (const p of parts) {
- const w = calcWeight(BOX_FINISH_MATERIAL, p.dim, ld.length);
- rows.push({
- partName: p.name, lotPrefix: p.prefix, material: BOX_FINISH_MATERIAL,
- dimension: `${ld.length}`, quantity: ld.quantity,
- weight: Math.round(w.weight * ld.quantity * 100) / 100,
- });
- }
- } else if (box.direction === '밑면') {
- const parts = [
- { name: '①전면부', prefix: 'XX', dim: boxHeight + 122 },
- { name: '②린텔부', prefix: 'CL', dim: boxWidth - 330 },
- { name: '③점검구', prefix: 'XX', dim: boxWidth - 200 },
- { name: '④후면부', prefix: 'CB', dim: boxHeight + 85 * 2 },
- ];
- for (const p of parts) {
- const w = calcWeight(BOX_FINISH_MATERIAL, p.dim, ld.length);
- rows.push({
- partName: p.name, lotPrefix: p.prefix, material: BOX_FINISH_MATERIAL,
- dimension: `${ld.length}`, quantity: ld.quantity,
- weight: Math.round(w.weight * ld.quantity * 100) / 100,
- });
- }
- } else if (box.direction === '후면') {
- const parts = [
- { name: '①전면부', prefix: 'XX', dim: boxHeight + 122 },
- { name: '②린텔부', prefix: 'CL', dim: boxWidth + 85 * 2 },
- { name: '③점검구', prefix: 'XX', dim: boxHeight - 200 },
- { name: '④후면코너부', prefix: 'CB', dim: boxHeight + 85 * 2 },
- ];
- for (const p of parts) {
- const w = calcWeight(BOX_FINISH_MATERIAL, p.dim, ld.length);
- rows.push({
- partName: p.name, lotPrefix: p.prefix, material: BOX_FINISH_MATERIAL,
- dimension: `${ld.length}`, quantity: ld.quantity,
- weight: Math.round(w.weight * ld.quantity * 100) / 100,
- });
- }
+ if (isStandard) {
+ parts = [
+ { name: '①전면부', prefix: 'CF', dim: boxHeight + 122 },
+ { name: '②린텔부', prefix: 'CL', dim: boxWidth - 330 },
+ { name: '③⑤점검구', prefix: 'CP', dim: boxWidth - 200 },
+ { name: '④후면코너부', prefix: 'CB', dim: 170 },
+ ];
+ } else if (box.direction === '양면') {
+ parts = [
+ { name: '①전면부', prefix: 'XX', dim: boxHeight + 122 },
+ { name: '②린텔부', prefix: 'CL', dim: boxWidth - 330 },
+ { name: '③점검구', prefix: 'XX', dim: boxWidth - 200 },
+ { name: '④후면코너부', prefix: 'CB', dim: 170 },
+ { name: '⑤점검구', prefix: 'XX', dim: boxHeight - 100 },
+ ];
+ } else if (box.direction === '밑면') {
+ parts = [
+ { name: '①전면부', prefix: 'XX', dim: boxHeight + 122 },
+ { name: '②린텔부', prefix: 'CL', dim: boxWidth - 330 },
+ { name: '③점검구', prefix: 'XX', dim: boxWidth - 200 },
+ { name: '④후면부', prefix: 'CB', dim: boxHeight + 85 * 2 },
+ ];
+ } else if (box.direction === '후면') {
+ parts = [
+ { name: '①전면부', prefix: 'XX', dim: boxHeight + 122 },
+ { name: '②린텔부', prefix: 'CL', dim: boxWidth + 85 * 2 },
+ { name: '③점검구', prefix: 'XX', dim: boxHeight - 200 },
+ { name: '④후면코너부', prefix: 'CB', dim: boxHeight + 85 * 2 },
+ ];
+ } else {
+ parts = [];
+ }
+
+ // 구성요소 기준 정렬: 파트 → 길이 순서
+ for (const p of parts) {
+ for (const ld of box.lengthData) {
+ if (ld.quantity <= 0) continue;
+ const w = calcWeight(BOX_FINISH_MATERIAL, p.dim, ld.length);
+ rows.push({
+ partName: p.name, lotPrefix: p.prefix, material: BOX_FINISH_MATERIAL,
+ dimension: `${ld.length}`, quantity: ld.quantity,
+ weight: Math.round(w.weight * ld.quantity * 100) / 100,
+ });
}
}
- // 상부덮개 (비표준일 때)
- if (!isStandard && box.coverQty > 0) {
+ // 상부덮개
+ if (box.coverQty > 0) {
const coverWidth = boxWidth - 111;
const w = calcWeight(BOX_FINISH_MATERIAL, coverWidth, BOX_COVER_LENGTH);
rows.push({
- partName: '⑥상부덮개', lotPrefix: 'XX', material: BOX_FINISH_MATERIAL,
+ partName: isStandard ? '⑤상부덮개' : (box.direction === '양면' ? '⑥상부덮개' : '⑤상부덮개'),
+ lotPrefix: 'XX', material: BOX_FINISH_MATERIAL,
dimension: `1219 * ${coverWidth}`, quantity: box.coverQty,
weight: Math.round(w.weight * box.coverQty * 100) / 100,
});
}
- // 마구리 (비표준일 때)
- if (!isStandard && box.finCoverQty > 0) {
- const finWidth = boxWidth + 5;
- const finHeight = boxHeight + 5;
- const w = calcWeight(BOX_FINISH_MATERIAL, finWidth, finHeight);
+ // 마구리 (레거시: 무게는 원본 box 크기로 계산, 표시 치수만 +5)
+ if (box.finCoverQty > 0) {
+ const w = calcWeight(BOX_FINISH_MATERIAL, boxWidth, boxHeight);
rows.push({
- partName: '⑦측면부(마구리)', lotPrefix: 'XX', material: BOX_FINISH_MATERIAL,
- dimension: `${finWidth} * ${finHeight}`, quantity: box.finCoverQty,
+ partName: isStandard ? '⑥측면부(마구리)' : (box.direction === '양면' ? '⑦측면부(마구리)' : '⑥측면부(마구리)'),
+ lotPrefix: 'XX', material: BOX_FINISH_MATERIAL,
+ dimension: `${boxWidth + 5} * ${boxHeight + 5}`, quantity: box.finCoverQty,
weight: Math.round(w.weight * box.finCoverQty * 100) / 100,
});
}
@@ -493,8 +491,6 @@ export function calculateProductionSummary(
// 가이드레일 - 벽면형
if (bendingInfo.guideRail.wall) {
- const baseHeight = bendingInfo.guideRail.wall.baseSize === '135*80'
- ? WALL_BASE_HEIGHT_MIXED : WALL_BASE_HEIGHT_ONLY;
for (const ld of bendingInfo.guideRail.wall.lengthData) {
if (ld.quantity <= 0) continue;
addWeight(mapping.guideRailFinish, WALL_PART_WIDTH, ld.length, ld.quantity);
@@ -504,7 +500,8 @@ export function calculateProductionSummary(
}
}
const totalWallQty = bendingInfo.guideRail.wall.lengthData.reduce((s, l) => s + l.quantity, 0);
- addWeight('EGI 1.55T', BASE_WIDTH, baseHeight, totalWallQty);
+ const wallBase = parseBaseDimension(bendingInfo.guideRail.wall.baseDimension, WALL_BASE_HEIGHT);
+ addWeight('EGI 1.55T', wallBase.width, wallBase.height, totalWallQty);
}
// 가이드레일 - 측면형
@@ -515,7 +512,8 @@ export function calculateProductionSummary(
addWeight(mapping.bodyMaterial, SIDE_PART_WIDTH, ld.length, ld.quantity * 3);
}
const totalSideQty = bendingInfo.guideRail.side.lengthData.reduce((s, l) => s + l.quantity, 0);
- addWeight('EGI 1.55T', BASE_WIDTH, SIDE_BASE_HEIGHT, totalSideQty);
+ const sideBase = parseBaseDimension(bendingInfo.guideRail.side.baseDimension, SIDE_BASE_HEIGHT);
+ addWeight('EGI 1.55T', sideBase.width, sideBase.height, totalSideQty);
}
// 하단마감재