Files
wace_plm/WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp
2025-11-18 14:37:36 +09:00

600 lines
14 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">
<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;
$(function(){
// Tabulator 초기화
fn_initGrid();
});
// Tabulator 그리드 초기화
function fn_initGrid() {
var maxLevel = ${empty MAXLEV ? 1 : MAXLEV};
// 컬럼 정의
var columns = [];
// 라디오 버튼 컬럼 (E-BOM과 동일)
columns.push({
headerHozAlign: 'center',
hozAlign: 'center',
width: 60,
title: '선택',
field: 'RADIO',
headerSort: false,
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 || '') + '">';
}
});
// 수준 컬럼 그룹
var levelColumns = [];
for(var i = 1; i <= maxLevel; i++) {
levelColumns.push({
headerHozAlign: 'center',
hozAlign: 'center',
width: 25,
title: i,
field: 'LEVEL_' + i,
formatter: function(cell) {
return cell.getValue() === '*' ? '*' : '';
}
});
}
columns.push({
title: '수준',
headerHozAlign: 'center',
columns: levelColumns
});
// 기본 정보 컬럼들 (E-BOM 정보)
columns.push(
{
headerHozAlign: 'center',
hozAlign: 'left',
widthGrow: 2,
title: '품번',
field: 'PART_NO'
},
{
headerHozAlign: 'center',
hozAlign: 'left',
widthGrow: 3,
title: '품명',
field: 'PART_NAME'
},
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 60,
title: '수량',
field: 'QTY_TEMP',
visible: false
},
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 80,
title: '항목 수량',
field: 'ITEM_QTY',
visible: false
},
/* 주석처리: 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: false,
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: false,
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: false,
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: false
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 120,
title: '열처리경도',
field: 'HEAT_TREATMENT_HARDNESS',
visible: false
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 120,
title: '열처리방법',
field: 'HEAT_TREATMENT_METHOD',
visible: false
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '표면처리',
field: 'SURFACE_TREATMENT',
visible: false
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 150,
title: '공급업체',
field: 'SUPPLIER',
visible: false
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '범주이름',
field: 'CATEGORY_NAME',
visible: false
}
);
// 생산관리 컬럼 그룹
columns.push({
title: '생산관리',
headerHozAlign: 'center',
columns: [
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '지급/사급',
field: 'SUPPLY_TYPE',
editor: 'list',
editorParams: {
values: ['지급', '사급', '자급']
}
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '소재',
field: 'RAW_MATERIAL',
editor: 'input',
editable: function(cell) {
// 자급인 경우 입력 불가
return cell.getRow().getData().SUPPLY_TYPE !== '자급';
}
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 100,
title: '사이즈',
field: 'SIZE',
editor: false,
formatter: function(cell) {
// 항목수량 × 수주수량 (수정 불가)
var data = cell.getRow().getData();
var itemQty = data.ITEM_QTY || 0;
var orderQty = data.ORDER_QTY || 0;
return itemQty * orderQty;
}
},
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '소요량',
field: 'REQUIRED_QTY',
editor: false
},
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '발주수량',
field: 'ORDER_QTY',
editor: false,
formatter: function(cell) {
// 항목수량 (수정 불가)
return cell.getRow().getData().ITEM_QTY || 0;
}
},
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 80,
title: "Q'ty",
field: 'QTY',
editor: 'number',
editorParams: {
min: 0,
step: 1
}
},
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '제작수량',
field: 'PRODUCTION_QTY',
editor: 'number',
editorParams: {
min: 0,
step: 1
}
},
{
headerHozAlign: 'center',
hozAlign: 'left',
width: 150,
title: '가공업체',
field: 'PROCESSING_VENDOR',
editor: 'input'
},
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '가공납기',
field: 'PROCESSING_DEADLINE',
editor: 'date'
},
{
headerHozAlign: 'center',
hozAlign: 'center',
width: 100,
title: '연삭납기',
field: 'GRINDING_DEADLINE',
editor: 'date'
}
]
});
// 구매 컬럼 그룹 (제작수량 기준)
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);
// Tabulator 생성
_tabulGrid = new Tabulator("#mBomTableWrap", {
layout: "fitData",
height: "calc(100vh - 150px)",
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);
_tabulGrid.setData(data.list);
} else {
console.log("데이터 없음");
_tabulGrid.setData([]);
}
},
error: function(jqxhr, status, error){
console.error("M-BOM 조회 오류:", error);
console.error("응답:", jqxhr.responseText);
_tabulGrid.setData([]);
}
});
}
// M-BOM 트리 데이터 수집 (저장용)
function getMbomTreeData() {
var allData = _tabulGrid.getData();
// 데이터 구조 변환 (필요한 필드만 추출)
var mbomData = allData.map(function(row) {
return {
PART_NO: row.PART_NO,
PART_NAME: row.PART_NAME,
QTY: row.QTY_TEMP || row.ITEM_QTY,
LEVEL: row.LEVEL,
REVISION: row.REVISION,
SPEC: row.SPEC,
PRODUCT_NAME: row.PRODUCT_NAME,
STATUS_NAME: row.STATUS_NAME,
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>