855 lines
22 KiB
Plaintext
855 lines
22 KiB
Plaintext
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||
<%@ page import="com.pms.common.utils.*"%>
|
||
<%@ page import="java.util.*" %>
|
||
<%@include file= "/init.jsp" %>
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
<title><%=Constants.SYSTEM_NAME%></title>
|
||
<link href="/css/tabulator/tabulator.min.css" rel="stylesheet">
|
||
<script type="text/javascript" src="/js/tabulator/tabulator.min.js"></script>
|
||
<style>
|
||
::-webkit-scrollbar {
|
||
width: 10px;
|
||
height: 15px;
|
||
}
|
||
#mBomTableWrap {
|
||
width: 99%;
|
||
margin: 10px auto;
|
||
overflow-x: auto;
|
||
overflow-y: hidden;
|
||
}
|
||
#mBomName {
|
||
margin-bottom: 10px;
|
||
font-weight: bold;
|
||
font-size: 16px;
|
||
}
|
||
body {
|
||
overflow: hidden;
|
||
}
|
||
/* Tabulator 커스텀 스타일 */
|
||
.tabulator-row.level-1 { background-color: #fde9d9 !important; }
|
||
.tabulator-row.level-2 { background-color: #daeef3 !important; }
|
||
.tabulator-row.level-3 { background-color: #e4dfec !important; }
|
||
.tabulator-row.level-4 { background-color: #ebf1de !important; }
|
||
.tabulator-row.level-5 { background-color: #f2f2f2 !important; }
|
||
.tabulator-row.level-6 { background-color: #f2dcdb !important; }
|
||
.tabulator-row.level-7 { background-color: #eeece1 !important; }
|
||
.tabulator-row.level-8 { background-color: #dce6f1 !important; }
|
||
.tabulator-row.level-9 { background-color: #FFFFEB !important; }
|
||
.tabulator-row.level-10 { background-color: #ffffff !important; }
|
||
</style>
|
||
<script>
|
||
var _tabulGrid;
|
||
// 프로젝트 수주수량 (최상위 프레임에서 가져오기)
|
||
var projectQuantity = 1; // 기본값
|
||
|
||
$(function(){
|
||
// 최상위 프레임(mBomPopupHeaderFs.jsp)에서 프로젝트 수주수량 가져오기
|
||
try {
|
||
if(parent && parent.parent && parent.parent.PROJECT_QUANTITY) {
|
||
projectQuantity = parseFloat(parent.parent.PROJECT_QUANTITY) || 1;
|
||
console.log("프로젝트 수주수량:", projectQuantity);
|
||
} else {
|
||
console.log("PROJECT_QUANTITY를 찾을 수 없습니다. 기본값 1 사용");
|
||
}
|
||
} catch(e) {
|
||
console.log("프로젝트 수주수량 가져오기 실패:", e);
|
||
}
|
||
|
||
// Tabulator 초기화
|
||
fn_initGrid();
|
||
});
|
||
|
||
// Tabulator 그리드 초기화
|
||
function fn_initGrid() {
|
||
var maxLevel = ${empty MAXLEV ? 1 : MAXLEV};
|
||
|
||
// 컬럼 정의
|
||
var columns = [];
|
||
|
||
// 라디오 버튼 컬럼 (E-BOM과 동일)
|
||
columns.push({
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 40,
|
||
title: '선택',
|
||
field: 'RADIO',
|
||
frozen: true,
|
||
formatter: function(cell) {
|
||
var rowData = cell.getData();
|
||
return '<input type="radio" name="checkedPartNo" value="' + (rowData.CHILD_OBJID || '') + '" ' +
|
||
'data-OBJID="' + (rowData.OBJID || '') + '" ' +
|
||
'data-PART_NO="' + (rowData.PART_NO || '') + '" ' +
|
||
'data-PARENT_PART_NO="' + (rowData.PARENT_PART_NO || '') + '" ' +
|
||
'data-PART_NO_QTY="' + (rowData.LAST_PART_OBJID || '') + '" ' +
|
||
'data-PARENT_PARTS="' + (rowData.PARENT_PARTS || '') + '" ' +
|
||
'data-LAST_PART_OBJID="' + (rowData.LAST_PART_OBJID || rowData.BOM_LAST_PART_OBJID || '') + '" ' +
|
||
'data-PARENT_OBJID="' + (rowData.PARENT_OBJID || '') + '" ' +
|
||
'data-PART_OBJID="' + (rowData.PART_OBJID || '') + '" ' +
|
||
'data-BOM_LAST_PART_OBJID="' + (rowData.BOM_LAST_PART_OBJID || rowData.LAST_PART_OBJID || '') + '" ' +
|
||
'data-CHILD_OBJID="' + (rowData.CHILD_OBJID || '') + '" ' +
|
||
'data-LEVEL="' + (rowData.LEVEL || 1) + '" ' +
|
||
'data-PART_NO="' + (rowData.PART_NO || '') + '">';
|
||
}
|
||
});
|
||
|
||
// 수준 컬럼 그룹
|
||
var levelColumns = [];
|
||
for(var i = 1; i <= maxLevel; i++) {
|
||
levelColumns.push({
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 10,
|
||
title: i,
|
||
field: 'LEVEL_' + i,
|
||
formatter: function(cell) {
|
||
return cell.getValue() === '*' ? '*' : '';
|
||
}
|
||
});
|
||
}
|
||
|
||
columns.push({
|
||
title: '수준',
|
||
headerHozAlign: 'center',
|
||
frozen: true,
|
||
columns: levelColumns
|
||
});
|
||
|
||
// 기본 정보 컬럼들 (E-BOM 정보)
|
||
columns.push(
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
widthGrow: 2,
|
||
title: '품번',
|
||
field: 'PART_NO',
|
||
frozen: true
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
widthGrow: 3,
|
||
title: '품명',
|
||
field: 'PART_NAME',
|
||
frozen: true
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 60,
|
||
title: '수량',
|
||
field: 'QTY_TEMP',
|
||
visible: true
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 80,
|
||
title: '항목 수량',
|
||
field: 'ITEM_QTY',
|
||
visible: true
|
||
},
|
||
/* 주석처리: Rev, 규격, 제품구분, 상태 컬럼
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 80,
|
||
title: 'Rev',
|
||
field: 'REVISION'
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 150,
|
||
title: '규격',
|
||
field: 'SPEC'
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 100,
|
||
title: '제품구분',
|
||
field: 'PRODUCT_NAME'
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 100,
|
||
title: '상태',
|
||
field: 'STATUS_NAME'
|
||
},
|
||
*/
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 60,
|
||
title: '3D',
|
||
field: 'CU01_CNT',
|
||
visible: true,
|
||
formatter: function(cell) {
|
||
var value = cell.getValue();
|
||
return value && value > 0 ? '<span class="file_icon"></span>' : '<span class="file_empty_icon"></span>';
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 60,
|
||
title: '2D',
|
||
field: 'CU02_CNT',
|
||
visible: true,
|
||
formatter: function(cell) {
|
||
var value = cell.getValue();
|
||
return value && value > 0 ? '<span class="file_icon"></span>' : '<span class="file_empty_icon"></span>';
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 60,
|
||
title: 'PDF',
|
||
field: 'CU03_CNT',
|
||
visible: true,
|
||
formatter: function(cell) {
|
||
var value = cell.getValue();
|
||
return value && value > 0 ? '<span class="file_icon"></span>' : '<span class="file_empty_icon"></span>';
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 100,
|
||
title: '재료',
|
||
field: 'MATERIAL',
|
||
visible: true
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 120,
|
||
title: '열처리경도',
|
||
field: 'HEAT_TREATMENT_HARDNESS',
|
||
visible: true
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 120,
|
||
title: '열처리방법',
|
||
field: 'HEAT_TREATMENT_METHOD',
|
||
visible: true
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 100,
|
||
title: '표면처리',
|
||
field: 'SURFACE_TREATMENT',
|
||
visible: true
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 150,
|
||
title: '메이커',
|
||
field: 'MAKER',
|
||
visible: true
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 100,
|
||
title: '범주이름',
|
||
field: 'PART_TYPE_TITLE',
|
||
visible: true
|
||
}
|
||
);
|
||
|
||
// 생산관리 컬럼 그룹
|
||
columns.push({
|
||
title: '생산관리',
|
||
headerHozAlign: 'center',
|
||
columns: [
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 100,
|
||
title: '자급/사급',
|
||
field: 'SUPPLY_TYPE',
|
||
editor: 'list',
|
||
editorParams: {
|
||
values: ['자급', '사급']
|
||
},
|
||
cellEdited: function(cell) {
|
||
var row = cell.getRow();
|
||
var data = row.getData();
|
||
// 자급 선택 시 소재 관련 필드 초기화
|
||
if(data.SUPPLY_TYPE === '자급') {
|
||
row.update({
|
||
RAW_MATERIAL: '-',
|
||
SIZE: '-',
|
||
RAW_MATERIAL_NO: '-',
|
||
REQUIRED_QTY: '-'
|
||
});
|
||
} else {
|
||
// 사급 선택 시 초기화
|
||
row.update({
|
||
RAW_MATERIAL: '',
|
||
SIZE: '',
|
||
RAW_MATERIAL_NO: '',
|
||
REQUIRED_QTY: ''
|
||
});
|
||
}
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 100,
|
||
title: '소재',
|
||
field: 'RAW_MATERIAL',
|
||
editor: 'list',
|
||
editorParams: {
|
||
values: ['SM45C', 'STS304', 'STS316', 'AL6061', 'AL7075'] // TODO: 실제 소재 목록으로 교체
|
||
},
|
||
editable: function(cell) {
|
||
return cell.getRow().getData().SUPPLY_TYPE === '사급';
|
||
},
|
||
formatter: function(cell) {
|
||
var data = cell.getRow().getData();
|
||
if(data.SUPPLY_TYPE === '자급') return '-';
|
||
return cell.getValue() || '';
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 100,
|
||
title: '사이즈',
|
||
field: 'SIZE',
|
||
editor: 'list',
|
||
editorParams: {
|
||
values: ['Φ10', 'Φ20', 'Φ30', '10x10', '20x20'] // TODO: 실제 사이즈 목록으로 교체
|
||
},
|
||
editable: function(cell) {
|
||
return cell.getRow().getData().SUPPLY_TYPE === '사급';
|
||
},
|
||
formatter: function(cell) {
|
||
var data = cell.getRow().getData();
|
||
if(data.SUPPLY_TYPE === '자급') return '-';
|
||
return cell.getValue() || '';
|
||
},
|
||
cellEdited: function(cell) {
|
||
// 소재, 사이즈 선택 시 소재품번 자동 생성
|
||
var row = cell.getRow();
|
||
var data = row.getData();
|
||
if(data.RAW_MATERIAL && data.SIZE) {
|
||
var materialNo = data.RAW_MATERIAL + '-' + data.SIZE;
|
||
row.update({RAW_MATERIAL_NO: materialNo});
|
||
}
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 120,
|
||
title: '소재품번',
|
||
field: 'RAW_MATERIAL_NO',
|
||
editor: false,
|
||
formatter: function(cell) {
|
||
var data = cell.getRow().getData();
|
||
if(data.SUPPLY_TYPE === '자급') return '-';
|
||
return cell.getValue() || '';
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'right',
|
||
width: 100,
|
||
title: '소재소요량',
|
||
field: 'REQUIRED_QTY',
|
||
editor: 'number',
|
||
editorParams: {
|
||
min: 0,
|
||
step: 0.01 // 소수 가능
|
||
},
|
||
editable: function(cell) {
|
||
return cell.getRow().getData().SUPPLY_TYPE === '사급';
|
||
},
|
||
formatter: function(cell) {
|
||
var data = cell.getRow().getData();
|
||
if(data.SUPPLY_TYPE === '자급') return '-';
|
||
var value = cell.getValue();
|
||
return value ? Number(value).toLocaleString() : '0';
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'right',
|
||
width: 120,
|
||
title: '소재발주수량',
|
||
field: 'ORDER_QTY',
|
||
editor: false,
|
||
formatter: function(cell) {
|
||
// 항목수량 × 프로젝트 수주수량 (수정 불가)
|
||
var data = cell.getRow().getData();
|
||
var itemQty = parseFloat(data.ITEM_QTY) || 0;
|
||
var orderQty = itemQty * projectQuantity;
|
||
|
||
// 실제 데이터에도 저장 (getMbomTreeData에서 사용)
|
||
cell.getRow().update({ORDER_QTY: orderQty}, false);
|
||
|
||
return orderQty.toLocaleString();
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'right',
|
||
width: 80,
|
||
title: '항목수량',
|
||
field: 'ITEM_QTY',
|
||
editor: false,
|
||
visible: true
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'right',
|
||
width: 100,
|
||
title: '제작수량',
|
||
field: 'PRODUCTION_QTY',
|
||
editor: 'number',
|
||
editorParams: {
|
||
min: 0,
|
||
step: 1
|
||
},
|
||
formatter: function(cell) {
|
||
// 저장된 값이 있으면 그대로 사용, 없으면 항목수량 × 수주수량으로 계산
|
||
var value = cell.getValue();
|
||
|
||
if(value === undefined || value === null || value === '' || value === 0) {
|
||
var data = cell.getRow().getData();
|
||
var itemQty = parseFloat(data.ITEM_QTY) || 0;
|
||
value = itemQty * projectQuantity;
|
||
|
||
// 실제 데이터에도 저장 (getMbomTreeData에서 사용)
|
||
cell.getRow().update({PRODUCTION_QTY: value}, false);
|
||
}
|
||
return Number(value).toLocaleString();
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 150,
|
||
title: '가공업체',
|
||
field: 'PROCESSING_VENDOR',
|
||
editor: 'list',
|
||
editorParams: {
|
||
values: ['업체A', '업체B', '업체C'] // TODO: 실제 가공업체 목록으로 교체
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 100,
|
||
title: '가공납기',
|
||
field: 'PROCESSING_DEADLINE',
|
||
editor: 'date'
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'center',
|
||
width: 100,
|
||
title: '연삭납기',
|
||
field: 'GRINDING_DEADLINE',
|
||
editor: 'date'
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'left',
|
||
width: 150,
|
||
title: '공급업체',
|
||
field: 'VENDOR',
|
||
editor: false, // 구매쪽에서 입력
|
||
formatter: function(cell) {
|
||
return cell.getValue() || '-';
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'right',
|
||
width: 100,
|
||
title: '단가',
|
||
field: 'UNIT_PRICE',
|
||
editor: false, // 구매쪽에서 입력
|
||
formatter: function(cell) {
|
||
var value = cell.getValue();
|
||
return value ? Number(value).toLocaleString() : '-';
|
||
}
|
||
},
|
||
{
|
||
headerHozAlign: 'center',
|
||
hozAlign: 'right',
|
||
width: 100,
|
||
title: '금액',
|
||
field: 'TOTAL_PRICE',
|
||
editor: false,
|
||
formatter: function(cell) {
|
||
// 항목수량 × 단가
|
||
var data = cell.getRow().getData();
|
||
var itemQty = parseFloat(data.ITEM_QTY) || 0;
|
||
var unitPrice = parseFloat(data.UNIT_PRICE) || 0;
|
||
var totalPrice = itemQty * unitPrice;
|
||
return totalPrice > 0 ? totalPrice.toLocaleString() : '-';
|
||
}
|
||
}
|
||
]
|
||
});
|
||
|
||
// 구매 컬럼 그룹 (제작수량 기준)
|
||
// columns.push({
|
||
// title: '구매',
|
||
// headerHozAlign: 'center',
|
||
// columns: [
|
||
// {
|
||
// headerHozAlign: 'center',
|
||
// hozAlign: 'left',
|
||
// width: 150,
|
||
// title: '소재품번',
|
||
// field: 'MATERIAL_PART_NO',
|
||
// editor: 'input'
|
||
// },
|
||
// {
|
||
// headerHozAlign: 'center',
|
||
// hozAlign: 'center',
|
||
// width: 100,
|
||
// title: '정미수량',
|
||
// field: 'NET_QTY',
|
||
// editor: false,
|
||
// formatter: function(cell) {
|
||
// // 소요량 × 제작수량 (소수점 무조건 올림)
|
||
// var data = cell.getRow().getData();
|
||
// var requiredQty = parseFloat(data.REQUIRED_QTY) || 0;
|
||
// var productionQty = parseFloat(data.PRODUCTION_QTY) || 0;
|
||
// var netQty = requiredQty * productionQty;
|
||
// return Math.ceil(netQty); // 무조건 올림
|
||
// }
|
||
// },
|
||
// {
|
||
// headerHozAlign: 'center',
|
||
// hozAlign: 'center',
|
||
// width: 100,
|
||
// title: '발주수량',
|
||
// field: 'PO_QTY',
|
||
// editor: 'number',
|
||
// editorParams: {
|
||
// min: 0,
|
||
// step: 1
|
||
// }
|
||
// },
|
||
// {
|
||
// headerHozAlign: 'center',
|
||
// hozAlign: 'left',
|
||
// width: 150,
|
||
// title: '공급업체',
|
||
// field: 'VENDOR',
|
||
// editor: 'input'
|
||
// },
|
||
// {
|
||
// headerHozAlign: 'center',
|
||
// hozAlign: 'right',
|
||
// width: 100,
|
||
// title: '단가',
|
||
// field: 'UNIT_PRICE',
|
||
// editor: 'number',
|
||
// editorParams: {
|
||
// min: 0,
|
||
// step: 0.01
|
||
// },
|
||
// formatter: function(cell) {
|
||
// var value = cell.getValue();
|
||
// return value ? Number(value).toLocaleString() : '0';
|
||
// }
|
||
// },
|
||
// {
|
||
// headerHozAlign: 'center',
|
||
// hozAlign: 'right',
|
||
// width: 100,
|
||
// title: '총단가',
|
||
// field: 'TOTAL_PRICE',
|
||
// editor: false,
|
||
// formatter: function(cell) {
|
||
// // 발주수량 × 단가
|
||
// var data = cell.getRow().getData();
|
||
// var poQty = parseFloat(data.PO_QTY) || 0;
|
||
// var unitPrice = parseFloat(data.UNIT_PRICE) || 0;
|
||
// var totalPrice = poQty * unitPrice;
|
||
// return totalPrice.toLocaleString();
|
||
// }
|
||
// }
|
||
// ]
|
||
// });
|
||
|
||
// 서버에서 전달받은 데이터 확인
|
||
var bomTreeData = ${bomTreeListJson};
|
||
console.log("bomTreeData:", bomTreeData);
|
||
console.log("bomTreeData length:", bomTreeData ? bomTreeData.length : 0);
|
||
|
||
// 데이터 전처리: SUPPLY_TYPE 기본값 설정
|
||
if(bomTreeData && bomTreeData.length > 0) {
|
||
bomTreeData.forEach(function(row) {
|
||
// SUPPLY_TYPE이 없으면 '사급'으로 설정
|
||
if(!row.SUPPLY_TYPE) {
|
||
row.SUPPLY_TYPE = '사급';
|
||
}
|
||
});
|
||
}
|
||
|
||
// 모든 컬럼에 headerSort: false 일괄 적용
|
||
columns.forEach(function(col) {
|
||
col.headerSort = false;
|
||
// 중첩된 컬럼이 있는 경우 (수준 컬럼 등)
|
||
if(col.columns) {
|
||
col.columns.forEach(function(subCol) {
|
||
subCol.headerSort = false;
|
||
});
|
||
}
|
||
});
|
||
|
||
// Tabulator 생성
|
||
_tabulGrid = new Tabulator("#mBomTableWrap", {
|
||
layout: "fitData",
|
||
height: "calc(100vh - 70px)",
|
||
columns: columns,
|
||
data: bomTreeData,
|
||
rowFormatter: function(row) {
|
||
var data = row.getData();
|
||
var level = data.LEVEL || 1;
|
||
row.getElement().classList.add('level-' + level);
|
||
}
|
||
});
|
||
|
||
// 셀 편집 이벤트 등록
|
||
_tabulGrid.on("cellEdited", function(cell) {
|
||
var field = cell.getField();
|
||
var row = cell.getRow();
|
||
var data = row.getData();
|
||
|
||
// 지급/사급 변경 시 소재, 사이즈, 소요량 필드 재계산
|
||
if(field === 'SUPPLY_TYPE') {
|
||
if(data.SUPPLY_TYPE === '자급') {
|
||
// 자급인 경우 소재, 사이즈, 소요량 초기화
|
||
row.update({
|
||
RAW_MATERIAL: '',
|
||
SIZE: 0,
|
||
REQUIRED_QTY: 0
|
||
});
|
||
}
|
||
// 행 전체 재렌더링
|
||
row.reformat();
|
||
}
|
||
|
||
// 제작수량 변경 시 정미수량 자동 계산
|
||
if(field === 'PRODUCTION_QTY' || field === 'REQUIRED_QTY') {
|
||
var requiredQty = parseFloat(data.REQUIRED_QTY) || 0;
|
||
var productionQty = parseFloat(data.PRODUCTION_QTY) || 0;
|
||
var netQty = Math.ceil(requiredQty * productionQty);
|
||
row.update({NET_QTY: netQty});
|
||
}
|
||
|
||
// 발주수량 또는 단가 변경 시 총단가 자동 계산
|
||
if(field === 'PO_QTY' || field === 'UNIT_PRICE') {
|
||
var poQty = parseFloat(data.PO_QTY) || 0;
|
||
var unitPrice = parseFloat(data.UNIT_PRICE) || 0;
|
||
var totalPrice = poQty * unitPrice;
|
||
row.update({TOTAL_PRICE: totalPrice});
|
||
}
|
||
|
||
// Q'ty 초기값 설정 (발주수량에서 가져오기)
|
||
if(field === 'ORDER_QTY' && !data.QTY) {
|
||
row.update({QTY: data.ORDER_QTY});
|
||
}
|
||
});
|
||
}
|
||
|
||
// 필터 적용 함수
|
||
function fn_applyFilter() {
|
||
var partNo = $("#filterPartNo").val().trim();
|
||
var partName = $("#filterPartName").val().trim();
|
||
|
||
if(!partNo && !partName) {
|
||
_tabulGrid.clearFilter();
|
||
return;
|
||
}
|
||
|
||
_tabulGrid.setFilter([
|
||
[
|
||
{field: "PART_NO", type: "like", value: partNo},
|
||
{field: "PART_NAME", type: "like", value: partName}
|
||
]
|
||
]);
|
||
}
|
||
|
||
// 필터 초기화 함수
|
||
function fn_resetFilter() {
|
||
$("#filterPartNo").val("");
|
||
$("#filterPartName").val("");
|
||
_tabulGrid.clearFilter();
|
||
}
|
||
|
||
// M-BOM 조회 (헤더 프레임에서 호출)
|
||
function fn_searchMbom(searchParams) {
|
||
console.log("fn_searchMbom (left) 호출됨:", searchParams);
|
||
|
||
$.ajax({
|
||
url: "/productionplanning/getMbomList.do",
|
||
method: 'post',
|
||
data: searchParams,
|
||
dataType: 'json',
|
||
success: function(data) {
|
||
console.log("M-BOM 조회 결과:", data);
|
||
if(data && data.list) {
|
||
console.log("데이터 개수:", data.list.length);
|
||
|
||
// ORDER_QTY, PRODUCTION_QTY 제거하여 formatter에서 재계산되도록
|
||
var processedData = data.list.map(function(item) {
|
||
delete item.ORDER_QTY;
|
||
delete item.PRODUCTION_QTY;
|
||
return item;
|
||
});
|
||
|
||
_tabulGrid.setData(processedData);
|
||
} else {
|
||
console.log("데이터 없음");
|
||
_tabulGrid.setData([]);
|
||
}
|
||
},
|
||
error: function(jqxhr, status, error){
|
||
console.error("M-BOM 조회 오류:", error);
|
||
console.error("응답:", jqxhr.responseText);
|
||
_tabulGrid.setData([]);
|
||
}
|
||
});
|
||
}
|
||
|
||
// 가공납기/연삭납기 일괄 적용
|
||
function applyBulkDeadline(processingDeadline, grindingDeadline) {
|
||
if(!_tabulGrid) {
|
||
console.error("그리드가 초기화되지 않았습니다.");
|
||
return 0;
|
||
}
|
||
|
||
console.log("일괄 적용 시작");
|
||
console.log("가공납기:", processingDeadline);
|
||
console.log("연삭납기:", grindingDeadline);
|
||
|
||
var allRows = _tabulGrid.getRows();
|
||
console.log("전체 행 수:", allRows.length);
|
||
|
||
var updatedCount = 0;
|
||
|
||
allRows.forEach(function(row) {
|
||
var updateData = {};
|
||
|
||
if(processingDeadline) {
|
||
updateData.PROCESSING_DEADLINE = processingDeadline;
|
||
}
|
||
if(grindingDeadline) {
|
||
updateData.GRINDING_DEADLINE = grindingDeadline;
|
||
}
|
||
|
||
// 행 직접 업데이트
|
||
row.update(updateData);
|
||
updatedCount++;
|
||
});
|
||
|
||
console.log("업데이트 완료 - 업데이트된 행:", updatedCount);
|
||
return updatedCount;
|
||
}
|
||
|
||
// M-BOM 트리 데이터 수집 (저장용)
|
||
function getMbomTreeData() {
|
||
var allData = _tabulGrid.getData();
|
||
|
||
// 숫자 변환 헬퍼 함수
|
||
function toNumber(value) {
|
||
if (value === null || value === undefined || value === '') return null;
|
||
var num = parseFloat(value);
|
||
return isNaN(num) ? null : num;
|
||
}
|
||
|
||
// 데이터 구조 변환 (MBOM_DETAIL 테이블에 필요한 모든 필드 포함)
|
||
var mbomData = allData.map(function(row) {
|
||
return {
|
||
// BOM 구조 정보
|
||
parentObjid: row.PARENT_OBJID,
|
||
childObjid: row.CHILD_OBJID,
|
||
seq: row.SEQ,
|
||
level: row.LEVEL,
|
||
|
||
// 품목 정보
|
||
partObjid: row.PART_OBJID || row.LAST_PART_OBJID,
|
||
partNo: row.PART_NO,
|
||
partName: row.PART_NAME,
|
||
|
||
// 수량 정보 (숫자로 변환)
|
||
qty: toNumber(row.QTY_TEMP || row.QTY || row.ITEM_QTY),
|
||
unit: row.UNIT,
|
||
|
||
// 생산 정보
|
||
supplyType: row.SUPPLY_TYPE,
|
||
makeOrBuy: row.MAKE_OR_BUY,
|
||
rawMaterial: row.RAW_MATERIAL,
|
||
rawMaterialSpec: row.RAW_MATERIAL_SPEC,
|
||
rawMaterialSize: row.SIZE,
|
||
rawMaterialPartNo: row.RAW_MATERIAL_NO,
|
||
processingVendor: row.PROCESSING_VENDOR,
|
||
processingDeadline: row.PROCESSING_DEADLINE,
|
||
grindingDeadline: row.GRINDING_DEADLINE,
|
||
requiredQty: toNumber(row.REQUIRED_QTY),
|
||
orderQty: toNumber(row.ORDER_QTY),
|
||
productionQty: toNumber(row.PRODUCTION_QTY),
|
||
stockQty: toNumber(row.STOCK_QTY),
|
||
shortageQty: toNumber(row.SHORTAGE_QTY),
|
||
|
||
// 구매 정보
|
||
vendor: row.VENDOR,
|
||
unitPrice: toNumber(row.UNIT_PRICE),
|
||
totalPrice: toNumber(row.TOTAL_PRICE),
|
||
currency: row.CURRENCY,
|
||
leadTime: toNumber(row.LEAD_TIME),
|
||
minOrderQty: toNumber(row.MIN_ORDER_QTY),
|
||
|
||
// 기타
|
||
status: row.STATUS,
|
||
remark: row.REMARK,
|
||
revision: row.REVISION,
|
||
spec: row.SPEC,
|
||
writer: row.WRITER,
|
||
editer: row.EDITER,
|
||
objid: row.OBJID
|
||
};
|
||
});
|
||
|
||
return mbomData;
|
||
}
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<!-- <div id="mBomName">
|
||
<c:choose>
|
||
<c:when test="${not empty ebomInfo}">
|
||
E-BOM: ${ebomInfo.PART_NO} - ${ebomInfo.PART_NAME}
|
||
</c:when>
|
||
<c:otherwise>
|
||
할당된 E-BOM이 없습니다.
|
||
</c:otherwise>
|
||
</c:choose>
|
||
</div> -->
|
||
<div id="mBomTableWrap"></div>
|
||
</body>
|
||
</html>
|
||
|