Files
wace_plm/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp

1150 lines
30 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<%@ 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">
<link href="/css/select2/select2.min.css" rel="stylesheet">
<script type="text/javascript" src="/js/tabulator/tabulator.min.js"></script>
<script type="text/javascript" src="/js/select2/select2.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; }
/* 편집 가능한 컬럼 헤더 스타일 */
.editable-header {
background-color: #fff9c4 !important;
}
/* 선택된 행 하이라이트 스타일 */
.tabulator-row.row-selected {
background-color: #b8daff !important;
border: 1px solid #007bff !important;
}
/* Select2 in Tabulator 스타일 */
.tabulator-cell .select2-container {
width: 100% !important;
}
.tabulator-cell .select2-container--default .select2-selection--single {
height: 100%;
border: none;
background: transparent;
}
.tabulator-cell .select2-container--default .select2-selection--single .select2-selection__rendered {
line-height: normal;
padding-left: 0;
}
.tabulator-cell .select2-container--default .select2-selection--single .select2-selection__arrow {
height: 100%;
}
.select2-container--open {
z-index: 9999 !important;
}
.select2-results__option {
font-size: 12px;
}
</style>
<script>
var _tabulGrid;
var selectedRowData = null; // 선택된 행 데이터
// 프로젝트 수주수량 (최상위 프레임에서 가져오기)
var projectQuantity = 1; // 기본값
// 소재 목록 전역 변수
var materialList = [];
// 공급업체(가공업체) 목록 전역 변수
var supplyVendorList = [];
$(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);
}
// 소재 목록 로드
fn_loadMaterialList();
// 공급업체(가공업체) 목록 로드
fn_loadSupplyVendorList();
// Tabulator 초기화
fn_initGrid();
});
// 소재 목록 로드
function fn_loadMaterialList() {
$.ajax({
url: '/admin/getMaterialList.do',
method: 'POST',
async: false,
success: function(response) {
if(response && response.list) {
// 중복 제거하여 소재 코드만 추출
var uniqueMaterials = {};
response.list.forEach(function(item) {
uniqueMaterials[item.MATERIAL_CODE] = true;
});
materialList = Object.keys(uniqueMaterials);
console.log("소재 목록 로드 완료:", materialList);
}
},
error: function() {
console.error("소재 목록 로드 실패");
materialList = [];
}
});
}
// 가공업체 목록 로드 (CLIENT_MNG 테이블)
function fn_loadSupplyVendorList() {
$.ajax({
url: '/common/getClientMngList.do',
method: 'POST',
async: false,
dataType: 'json',
success: function(data) {
if(data && data.length > 0) {
// {id: CODE_ID(OBJID), text: NAME(CLIENT_NM)} 형태로 변환
supplyVendorList = data.map(function(item) {
return {
id: item.CODE_ID,
text: item.NAME
};
});
console.log("가공업체 목록 로드 완료:", supplyVendorList.length + "개");
}
},
error: function() {
console.error("가공업체 목록 로드 실패");
supplyVendorList = [];
}
});
}
// Select2 커스텀 에디터 생성 함수
function createSelect2Editor(options) {
return function(cell, onRendered, success, cancel, editorParams) {
var cellValue = cell.getValue();
var container = document.createElement("span");
var select = document.createElement("select");
select.style.width = "100%";
// 빈 옵션 추가
var emptyOption = document.createElement("option");
emptyOption.value = "";
emptyOption.text = "선택";
select.appendChild(emptyOption);
// 옵션 추가
options.forEach(function(opt) {
var option = document.createElement("option");
if(typeof opt === 'object') {
option.value = opt.id || opt.value || '';
option.text = opt.text || opt.label || '';
} else {
option.value = opt;
option.text = opt;
}
if(option.value == cellValue) {
option.selected = true;
}
select.appendChild(option);
});
container.appendChild(select);
onRendered(function() {
$(select).select2({
width: '100%',
dropdownAutoWidth: true,
placeholder: '선택',
allowClear: true,
dropdownParent: $('body'), // 드롭다운이 셀 밖으로 나오도록
templateResult: function(data) {
return data.text;
},
templateSelection: function(data) {
return data.text;
}
});
$(select).on('select2:select select2:clear', function(e) {
success($(select).val() || null);
});
$(select).on('select2:close', function(e) {
// 포커스 잃었을 때 처리
});
// Select2 열기
$(select).select2('open');
});
return container;
};
}
// 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: 25,
minWidth: 25,
maxWidth: 25,
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: 50,
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: 50,
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: 50,
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: 70,
title: '자급/사급',
field: 'SUPPLY_TYPE',
titleFormatter: function() { return '<span class="editable-header">자급/사급</span>'; },
editor: createSelect2Editor([{id: '자급', text: '자급'}, {id: '사급', text: '사급'}]),
cellEdited: function(cell) {
var row = cell.getRow();
var data = row.getData();
// 자급 선택 시 소재 관련 필드 초기화 (null로 설정하여 DB에서 NULL 처리)
if(data.SUPPLY_TYPE === '자급') {
row.update({
RAW_MATERIAL: null,
SIZE: null,
RAW_MATERIAL_NO: null,
REQUIRED_QTY: null
});
} else {
// 사급 선택 시 초기화
row.update({
RAW_MATERIAL: null,
SIZE: null,
RAW_MATERIAL_NO: null,
REQUIRED_QTY: null
});
}
}
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '소재',
field: 'RAW_MATERIAL',
titleFormatter: function() { return '<span class="editable-header">소재</span>'; },
editor: function(cell, onRendered, success, cancel, editorParams) {
// 소재 목록을 Select2용 형태로 변환
var options = materialList.map(function(m) { return {id: m, text: m}; });
return createSelect2Editor(options)(cell, onRendered, success, cancel, editorParams);
},
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();
row.update({
SIZE: '',
RAW_MATERIAL_NO: ''
});
}
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '사이즈',
field: 'SIZE',
titleFormatter: function() { return '<span class="editable-header">사이즈</span>'; },
editor: function(cell, onRendered, success, cancel, editorParams) {
// 선택된 소재에 따라 동적으로 사이즈 목록 로드
var data = cell.getRow().getData();
var materialCode = data.RAW_MATERIAL;
if(!materialCode) {
cancel();
return;
}
// 서버에서 해당 소재의 사이즈 목록 가져오기
var sizes = [];
$.ajax({
url: '/admin/getMaterialSizes.do',
method: 'POST',
data: {materialCode: materialCode},
async: false,
success: function(response) {
if(response && response.list) {
sizes = response.list.map(function(item) {
return {id: item.SIZE_SPEC, text: item.SIZE_SPEC};
});
}
}
});
return createSelect2Editor(sizes)(cell, onRendered, success, cancel, editorParams);
},
editable: function(cell) {
var data = cell.getRow().getData();
return data.SUPPLY_TYPE === '사급' && data.RAW_MATERIAL;
},
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) {
// 서버에서 소재품번 조회
$.ajax({
url: '/admin/getMaterialPartNo.do',
method: 'POST',
data: {
materialCode: data.RAW_MATERIAL,
sizeSpec: data.SIZE
},
success: function(response) {
if(response && response.MATERIAL_PART_NO) {
row.update({RAW_MATERIAL_NO: response.MATERIAL_PART_NO});
}
}
});
}
}
},
{
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',
titleFormatter: function() { return '<span class="editable-header">소재소요량</span>'; },
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',
titleFormatter: function() { return '<span class="editable-header">제작수량</span>'; },
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',
titleFormatter: function() { return '<span class="editable-header">가공업체</span>'; },
editor: function(cell, onRendered, success, cancel, editorParams) {
// 가공업체 목록 Select2 에디터
return createSelect2Editor(supplyVendorList)(cell, onRendered, success, cancel, editorParams);
},
formatter: function(cell) {
var value = cell.getValue();
// 저장된 값이 없으면 기본값 '5001'(RPS) 설정
if(value === undefined || value === null || value === '') {
value = '5001';
cell.getRow().update({PROCESSING_VENDOR: value}, false);
}
// OBJID로 업체명 조회하여 표시
for(var i = 0; i < supplyVendorList.length; i++) {
if(supplyVendorList[i].id == value) {
return supplyVendorList[i].text;
}
}
return value;
}
},
/* 주석처리: 가공납기, 연삭납기 컬럼
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '가공납기',
field: 'PROCESSING_DEADLINE',
titleFormatter: function() { return '<span class="editable-header">가공납기</span>'; },
editor: 'date'
},
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '연삭납기',
field: 'GRINDING_DEADLINE',
titleFormatter: function() { return '<span class="editable-header">연삭납기</span>'; },
editor: 'date'
},
*/
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 150,
title: '공급업체',
field: 'VENDOR_NAME',
editor: false, // 구매쪽에서 입력
formatter: function(cell) {
return cell.getValue() || '-';
}
},
// 숨김 컬럼: 공급업체 코드 (저장 시 필요)
{
field: 'VENDOR',
visible: false
},
// 숨김 컬럼: 품의서 작성일 (저장 시 기존 값 유지)
{
field: 'PROPOSAL_DATE',
visible: false
},
// 숨김 컬럼: 순수량 (저장 시 기존 값 유지)
{
field: 'NET_QTY',
visible: false
},
// 숨김 컬럼: 발주수량 (저장 시 기존 값 유지)
{
field: 'PO_QTY',
visible: false
},
{
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("rowClick", function(e, row) {
// 링크 클릭 시에는 기본 동작 유지
if($(e.target).is('a')) {
return;
}
// 기존 선택 해제
$('.tabulator-row.row-selected').removeClass('row-selected');
$('input[name=checkedPartNo]').prop('checked', false);
// 현재 행 선택
$(row.getElement()).addClass('row-selected');
var rowData = row.getData();
selectedRowData = rowData;
// 해당 행의 라디오 버튼 선택
$(row.getElement()).find('input[name=checkedPartNo]').prop('checked', true);
});
// 셀 편집 이벤트 등록
_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 === '자급') {
// 자급인 경우 소재, 사이즈, 소요량 초기화 (null로 설정)
row.update({
RAW_MATERIAL: null,
SIZE: null,
REQUIRED_QTY: null
});
}
// 행 전체 재렌더링
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;
}
*/
// 선택된 행 데이터 가져오기 (Center 프레임에서 사용)
function getSelectedRowData() {
return selectedRowData;
}
// M-BOM 트리 데이터 수집 (저장용)
function getMbomTreeData() {
var allData = _tabulGrid.getData();
// 숫자 변환 헬퍼 함수 (빈 문자열, '-', 숫자가 아닌 값 → null)
function toNumber(value) {
if (value === null || value === undefined || value === '' || value === '-') return null;
var num = parseFloat(value);
return isNaN(num) ? null : num;
}
// 문자열 변환 헬퍼 함수 ('-' → null)
function toString(value) {
if (value === null || value === undefined || value === '-') return null;
return value;
}
// 데이터 구조 변환 (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: toString(row.RAW_MATERIAL), // 자급 시 '-' → null
rawMaterialSpec: toString(row.RAW_MATERIAL_SPEC),
rawMaterialSize: toString(row.SIZE), // 자급 시 '-' → null
rawMaterialPartNo: toString(row.RAW_MATERIAL_NO), // 자급 시 '-' → null
processingVendor: row.PROCESSING_VENDOR,
processingDeadline: row.PROCESSING_DEADLINE,
grindingDeadline: row.GRINDING_DEADLINE,
requiredQty: toNumber(row.REQUIRED_QTY), // 자급 시 '-' → null
orderQty: toNumber(row.ORDER_QTY),
productionQty: toNumber(row.PRODUCTION_QTY),
stockQty: toNumber(row.STOCK_QTY),
shortageQty: toNumber(row.SHORTAGE_QTY),
// 구매 정보
vendor: row.VENDOR || row.VENDOR_PM, // 공급업체 코드/OBJID (기존 값 유지)
unitPrice: toNumber(row.UNIT_PRICE),
// totalPrice 계산: 항목수량 × 단가
totalPrice: (function() {
var itemQty = parseFloat(row.ITEM_QTY) || 0;
var unitPrice = parseFloat(row.UNIT_PRICE) || 0;
return itemQty * unitPrice;
})(),
currency: row.CURRENCY,
leadTime: toNumber(row.LEAD_TIME),
minOrderQty: toNumber(row.MIN_ORDER_QTY),
netQty: toNumber(row.NET_QTY), // 순수량
poQty: toNumber(row.PO_QTY), // 발주수량
proposalDate: row.PROPOSAL_DATE, // 품의서 작성일 (기존 값 유지)
// 기타
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>