|
|
|
|
@@ -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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 하단마감재
|
|
|
|
|
|