auto commit
This commit is contained in:
@@ -2530,18 +2530,18 @@ SELECT option_objid::VARCHAR AS CODE
|
||||
AND PRODUCT_MGMT_OBJID::VARCHAR = #{codeId}::VARCHAR
|
||||
</select>
|
||||
|
||||
<select id="getRevNoselect" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
T.OBJID::varchar AS CODE
|
||||
,T.REV AS NAME
|
||||
,T1.PRODUCT_CODE AS CODE_CD
|
||||
,'' AS STATUS
|
||||
,T.spec_name AS ID
|
||||
,'' AS EXT_VAL
|
||||
FROM PART_BOM_REPORT T,PRODUCT_MGMT T1
|
||||
WHERE T.PRODUCT_MGMT_OBJID = T1.OBJID
|
||||
AND T1.OBJID = #{code}::numeric
|
||||
ORDER BY T.REV
|
||||
<select id="getRevNoselect" parameterType="map" resultType="map">
|
||||
SELECT
|
||||
T.OBJID::varchar AS CODE
|
||||
,COALESCE(T.REVISION, T.REV, '1.0') AS NAME
|
||||
,T1.PRODUCT_CODE AS CODE_CD
|
||||
,'' AS STATUS
|
||||
,T.spec_name AS ID
|
||||
,'' AS EXT_VAL
|
||||
FROM PART_BOM_REPORT T,PRODUCT_MGMT T1
|
||||
WHERE T.PRODUCT_MGMT_OBJID = T1.OBJID
|
||||
AND T1.OBJID = #{code}::numeric
|
||||
ORDER BY COALESCE(T.REVISION, T.REV, '1.0')
|
||||
|
||||
</select>
|
||||
|
||||
|
||||
@@ -2870,8 +2870,9 @@
|
||||
ORDER BY SUBSTRING(PROJECT_NO,POSITION('-' IN PROJECT_NO)+1) DESC
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 관리 목록 조회 -->
|
||||
<!-- M-BOM 관리 목록 조회 - 품목별로 나눠서 보이기 (판매관리와 동일) -->
|
||||
<select id="mBomMgmtGridList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
/* productionplanning.mBomMgmtGridList - 품목별로 나눠서 조회 (CONTRACT_ITEM 기준) */
|
||||
SELECT
|
||||
PM.OBJID,
|
||||
PM.CONTRACT_OBJID,
|
||||
@@ -2906,54 +2907,40 @@
|
||||
ELSE ''
|
||||
END
|
||||
) AS PAID_TYPE_NAME,
|
||||
COALESCE(PM.PART_NO, '') AS PART_NO,
|
||||
COALESCE(PM.PART_NAME, '') AS PART_NAME,
|
||||
-- S/N: CONTRACT_ITEM_SERIAL에서 조회
|
||||
-- 품목 정보: CONTRACT_ITEM에서 가져오기 (품목별로 펼쳐서 보이기)
|
||||
COALESCE(CI.PART_NO, PM.PART_NO, '') AS PART_NO,
|
||||
COALESCE(CI.PART_NAME, PM.PART_NAME, '') AS PART_NAME,
|
||||
CI.PART_OBJID,
|
||||
-- S/N: 해당 품목의 시리얼 번호만 표시
|
||||
(SELECT
|
||||
CASE
|
||||
WHEN COUNT(*) = 0 THEN ''
|
||||
WHEN COUNT(*) = 1 THEN MIN(CIS.SERIAL_NO)
|
||||
ELSE MIN(CIS.SERIAL_NO) || ' 외 ' || (COUNT(*) - 1)::TEXT || '건'
|
||||
END
|
||||
FROM CONTRACT_ITEM CI
|
||||
LEFT JOIN CONTRACT_ITEM_SERIAL CIS ON CI.OBJID = CIS.ITEM_OBJID AND UPPER(CIS.STATUS) = 'ACTIVE'
|
||||
WHERE CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = PM.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
FROM CONTRACT_ITEM_SERIAL CIS
|
||||
WHERE CIS.ITEM_OBJID = CI.OBJID
|
||||
AND UPPER(CIS.STATUS) = 'ACTIVE'
|
||||
AND CIS.SERIAL_NO IS NOT NULL) AS SERIAL_NO,
|
||||
COALESCE(PM.QUANTITY::numeric, 0) AS QUANTITY,
|
||||
-- 요청납기: CONTRACT_ITEM 우선, 없으면 PROJECT_MGMT, 없으면 CONTRACT_MGMT
|
||||
COALESCE(
|
||||
(SELECT CI.DUE_DATE
|
||||
FROM CONTRACT_ITEM CI
|
||||
WHERE CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = PM.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE' LIMIT 1),
|
||||
PM.DUE_DATE,
|
||||
CM.req_del_date
|
||||
) AS REQ_DEL_DATE,
|
||||
-- 수량: CONTRACT_ITEM의 수량
|
||||
COALESCE(CI.ORDER_QUANTITY::numeric, PM.QUANTITY::numeric, 0) AS QUANTITY,
|
||||
-- 요청납기: CONTRACT_ITEM 우선
|
||||
COALESCE(CI.DUE_DATE, PM.DUE_DATE, CM.req_del_date) AS REQ_DEL_DATE,
|
||||
-- 고객요청사항: CONTRACT_ITEM에서 가져옴
|
||||
COALESCE(
|
||||
(SELECT CI.CUSTOMER_REQUEST
|
||||
FROM CONTRACT_ITEM CI
|
||||
WHERE CI.CONTRACT_OBJID = PM.CONTRACT_OBJID
|
||||
AND CI.PART_OBJID = PM.PART_OBJID
|
||||
AND CI.STATUS = 'ACTIVE' LIMIT 1),
|
||||
''
|
||||
) AS CUSTOMER_REQUEST,
|
||||
-- E-BOM 정보: PM.PART_OBJID가 E-BOM OBJID를 직접 가리킴
|
||||
PM.PART_OBJID AS BOM_REPORT_OBJID,
|
||||
COALESCE(CI.CUSTOMER_REQUEST, '') AS CUSTOMER_REQUEST,
|
||||
-- E-BOM 정보: CI.PART_OBJID가 E-BOM OBJID를 가리킴
|
||||
COALESCE(CI.PART_OBJID, PM.PART_OBJID) AS BOM_REPORT_OBJID,
|
||||
COALESCE(
|
||||
(SELECT PBR.STATUS
|
||||
FROM PART_BOM_REPORT PBR
|
||||
WHERE PBR.OBJID::VARCHAR = PM.PART_OBJID
|
||||
WHERE PBR.OBJID::VARCHAR = COALESCE(CI.PART_OBJID, PM.PART_OBJID)
|
||||
LIMIT 1),
|
||||
''
|
||||
) AS EBOM_STATUS,
|
||||
COALESCE(
|
||||
(SELECT TO_CHAR(PBR.REGDATE, 'YYYY-MM-DD')
|
||||
FROM PART_BOM_REPORT PBR
|
||||
WHERE PBR.OBJID::VARCHAR = PM.PART_OBJID
|
||||
WHERE PBR.OBJID::VARCHAR = COALESCE(CI.PART_OBJID, PM.PART_OBJID)
|
||||
LIMIT 1),
|
||||
''
|
||||
) AS EBOM_REGDATE,
|
||||
@@ -2963,18 +2950,27 @@
|
||||
FROM
|
||||
PROJECT_MGMT PM
|
||||
LEFT JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
-- CONTRACT_ITEM과 LEFT JOIN하여 품목별로 펼쳐서 보이기
|
||||
LEFT JOIN CONTRACT_ITEM CI ON CM.OBJID::VARCHAR = CI.CONTRACT_OBJID
|
||||
AND CI.STATUS = 'ACTIVE'
|
||||
WHERE 1=1
|
||||
AND PM.PROJECT_NO IS NOT NULL
|
||||
AND PM.PROJECT_NO != ''
|
||||
<!-- 품번 검색 (대소문자 구분 없음) -->
|
||||
<if test="search_part_no != null and search_part_no != ''">
|
||||
AND UPPER(PM.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
|
||||
AND (
|
||||
UPPER(PM.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
|
||||
OR UPPER(CI.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
|
||||
)
|
||||
</if>
|
||||
<!-- 품명 검색 (대소문자 구분 없음) -->
|
||||
<if test="search_part_name != null and search_part_name != ''">
|
||||
AND UPPER(PM.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
|
||||
AND (
|
||||
UPPER(PM.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
|
||||
OR UPPER(CI.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
|
||||
)
|
||||
</if>
|
||||
ORDER BY PM.REGDATE DESC
|
||||
ORDER BY PM.REGDATE DESC, CI.PART_NO
|
||||
</select>
|
||||
|
||||
<!-- E-BOM을 PROJECT_MGMT에 할당 -->
|
||||
@@ -3003,4 +2999,299 @@
|
||||
LEFT JOIN USER_INFO UI ON UI.USER_ID = T.WRITER
|
||||
WHERE T.OBJID::VARCHAR = #{objid}
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 상세 조회 (PROJECT_MGMT + CONTRACT_MGMT 정보) -->
|
||||
<select id="getProjectMgmtDetail" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
PM.OBJID,
|
||||
PM.CONTRACT_OBJID,
|
||||
PM.PROJECT_NO,
|
||||
PM.BOM_REPORT_OBJID,
|
||||
PM.PART_NO,
|
||||
PM.PART_NAME,
|
||||
CM.CATEGORY_CD,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.CATEGORY_CD LIMIT 1),
|
||||
''
|
||||
) AS CATEGORY_NAME,
|
||||
CM.PRODUCT,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.PRODUCT LIMIT 1),
|
||||
''
|
||||
) AS PRODUCT_NAME,
|
||||
CM.AREA_CD,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = CM.AREA_CD LIMIT 1),
|
||||
''
|
||||
) AS AREA_NAME,
|
||||
CM.CUSTOMER_OBJID,
|
||||
COALESCE(
|
||||
(SELECT SUPPLY_NAME FROM SUPPLY_MNG WHERE OBJID = CM.CUSTOMER_OBJID::NUMERIC LIMIT 1),
|
||||
''
|
||||
) AS CUSTOMER_NAME,
|
||||
CM.PAID_TYPE,
|
||||
CM.REQ_DEL_DATE,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS RECEIPT_DATE,
|
||||
TO_CHAR(PM.REGDATE, 'YYYY-MM-DD') AS MBOM_REGDATE
|
||||
FROM
|
||||
PROJECT_MGMT PM
|
||||
INNER JOIN CONTRACT_MGMT CM ON PM.CONTRACT_OBJID = CM.OBJID
|
||||
WHERE
|
||||
PM.OBJID::VARCHAR = #{objId}
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
<!-- E-BOM 목록 조회 -->
|
||||
<select id="getEbomList" parameterType="map" resultType="com.pms.common.UpperKeyMap">
|
||||
SELECT
|
||||
T.OBJID,
|
||||
T.PRODUCT_CD,
|
||||
COALESCE(
|
||||
(SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = T.PRODUCT_CD LIMIT 1),
|
||||
''
|
||||
) AS PRODUCT_NAME,
|
||||
T.PART_NO,
|
||||
T.PART_NAME,
|
||||
T.STATUS,
|
||||
T.REVISION,
|
||||
TO_CHAR(T.REGDATE, 'YYYY-MM-DD') AS REG_DATE,
|
||||
UI.USER_NAME AS WRITER_NAME,
|
||||
UI.DEPT_NAME,
|
||||
COALESCE(PM.MATERIAL, '') AS MATERIAL,
|
||||
COALESCE(PM.MAKER, '') AS SUPPLIER
|
||||
FROM
|
||||
PART_BOM_REPORT T
|
||||
LEFT JOIN USER_INFO UI ON UI.USER_ID = T.WRITER
|
||||
LEFT JOIN PART_MNG PM ON PM.PART_NO = T.PART_NO AND PM.STATUS = 'release'
|
||||
WHERE 1=1
|
||||
<!-- 품번, 품명이 비어있지 않은 것만 조회 -->
|
||||
AND T.PART_NO IS NOT NULL
|
||||
AND TRIM(T.PART_NO) != ''
|
||||
AND T.PART_NAME IS NOT NULL
|
||||
AND TRIM(T.PART_NAME) != ''
|
||||
<!-- 품번 검색 -->
|
||||
<if test="search_part_no != null and search_part_no != ''">
|
||||
AND UPPER(T.PART_NO) LIKE '%' || UPPER(#{search_part_no}) || '%'
|
||||
</if>
|
||||
<!-- 품명 검색 -->
|
||||
<if test="search_part_name != null and search_part_name != ''">
|
||||
AND UPPER(T.PART_NAME) LIKE '%' || UPPER(#{search_part_name}) || '%'
|
||||
</if>
|
||||
<!-- 재료 검색 -->
|
||||
<if test="search_material != null and search_material != ''">
|
||||
AND UPPER(PM.MATERIAL) LIKE '%' || UPPER(#{search_material}) || '%'
|
||||
</if>
|
||||
<!-- 공급업체 검색 -->
|
||||
<if test="search_supplier != null and search_supplier != ''">
|
||||
AND UPPER(PM.MAKER) LIKE '%' || UPPER(#{search_supplier}) || '%'
|
||||
</if>
|
||||
ORDER BY T.REGDATE DESC
|
||||
LIMIT 100
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 목록 조회 -->
|
||||
<select id="getMbomList" resultType="map" parameterType="map">
|
||||
SELECT
|
||||
MH.OBJID,
|
||||
MH.MBOM_NO,
|
||||
MH.PART_NO,
|
||||
MH.PART_NAME,
|
||||
MH.SAVE_DATE,
|
||||
MH.CREATE_USER,
|
||||
MH.CREATE_DATE,
|
||||
MH.UPDATE_USER,
|
||||
MH.UPDATE_DATE
|
||||
FROM
|
||||
MBOM_HEADER MH
|
||||
WHERE 1=1
|
||||
<!-- 품번 검색 -->
|
||||
<if test="partNo != null and partNo != ''">
|
||||
AND UPPER(MH.PART_NO) LIKE '%' || UPPER(#{partNo}) || '%'
|
||||
</if>
|
||||
<!-- 품명 검색 -->
|
||||
<if test="partName != null and partName != ''">
|
||||
AND UPPER(MH.PART_NAME) LIKE '%' || UPPER(#{partName}) || '%'
|
||||
</if>
|
||||
<!-- M-BOM 품번 검색 -->
|
||||
<if test="mbomPartNo != null and mbomPartNo != ''">
|
||||
AND UPPER(MH.MBOM_NO) LIKE '%' || UPPER(#{mbomPartNo}) || '%'
|
||||
</if>
|
||||
<!-- 저장일 검색 -->
|
||||
<if test="saveDate != null and saveDate != ''">
|
||||
AND DATE(MH.SAVE_DATE) = #{saveDate}
|
||||
</if>
|
||||
ORDER BY MH.SAVE_DATE DESC
|
||||
LIMIT 100
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 상세 데이터 조회 (프로젝트별) -->
|
||||
<select id="getMbomDetailByProject" resultType="map" parameterType="map">
|
||||
SELECT
|
||||
MD.OBJID,
|
||||
MD.MBOM_HEADER_OBJID,
|
||||
MD.PART_NO,
|
||||
MD.PART_NAME,
|
||||
MD.QTY,
|
||||
MD.QTY_TEMP,
|
||||
MD.ITEM_QTY,
|
||||
MD.LEVEL,
|
||||
MD.REVISION,
|
||||
MD.SPEC,
|
||||
MD.PRODUCT_NAME,
|
||||
MD.STATUS_NAME,
|
||||
MD.LEVEL_1,
|
||||
MD.LEVEL_2,
|
||||
MD.LEVEL_3,
|
||||
MD.LEVEL_4,
|
||||
MD.LEVEL_5,
|
||||
MD.LEVEL_6,
|
||||
MD.LEVEL_7,
|
||||
MD.LEVEL_8,
|
||||
MD.LEVEL_9,
|
||||
MD.LEVEL_10
|
||||
FROM
|
||||
MBOM_DETAIL MD
|
||||
INNER JOIN
|
||||
MBOM_HEADER MH ON MD.MBOM_HEADER_OBJID = MH.OBJID
|
||||
WHERE
|
||||
MH.PROJECT_MGMT_OBJID = #{objId}
|
||||
ORDER BY
|
||||
MD.LEVEL, MD.PART_NO
|
||||
</select>
|
||||
|
||||
<!-- M-BOM 헤더 저장 -->
|
||||
<insert id="insertMbomHeader" parameterType="map">
|
||||
<selectKey keyProperty="OBJID" resultType="string" order="BEFORE">
|
||||
SELECT REPLACE(UUID(),'-','') FROM DUAL
|
||||
</selectKey>
|
||||
INSERT INTO MBOM_HEADER (
|
||||
OBJID,
|
||||
MBOM_NO,
|
||||
PART_NO,
|
||||
PART_NAME,
|
||||
SAVE_DATE,
|
||||
CREATE_USER,
|
||||
CREATE_DATE,
|
||||
UPDATE_USER,
|
||||
UPDATE_DATE
|
||||
) VALUES (
|
||||
#{OBJID},
|
||||
CONCAT('MBOM-', DATE_FORMAT(NOW(), '%Y%m%d%H%i%s')),
|
||||
#{PART_NO},
|
||||
#{PART_NAME},
|
||||
NOW(),
|
||||
#{CREATE_USER},
|
||||
NOW(),
|
||||
#{UPDATE_USER},
|
||||
NOW()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- M-BOM 상세 저장 -->
|
||||
<insert id="insertMbomDetail" parameterType="map">
|
||||
<selectKey keyProperty="OBJID" resultType="string" order="BEFORE">
|
||||
SELECT REPLACE(UUID(),'-','') FROM DUAL
|
||||
</selectKey>
|
||||
INSERT INTO MBOM_DETAIL (
|
||||
OBJID,
|
||||
MBOM_HEADER_OBJID,
|
||||
PART_NO,
|
||||
PART_NAME,
|
||||
QTY,
|
||||
LEVEL,
|
||||
REVISION,
|
||||
SPEC,
|
||||
PRODUCT_NAME,
|
||||
STATUS_NAME,
|
||||
CREATE_USER,
|
||||
CREATE_DATE,
|
||||
UPDATE_USER,
|
||||
UPDATE_DATE
|
||||
) VALUES (
|
||||
#{OBJID},
|
||||
#{MBOM_HEADER_OBJID},
|
||||
#{PART_NO},
|
||||
#{PART_NAME},
|
||||
#{QTY},
|
||||
#{LEVEL},
|
||||
#{REVISION},
|
||||
#{SPEC},
|
||||
#{PRODUCT_NAME},
|
||||
#{STATUS_NAME},
|
||||
#{CREATE_USER},
|
||||
NOW(),
|
||||
#{UPDATE_USER},
|
||||
NOW()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<!-- E-BOM을 M-BOM으로 복사 -->
|
||||
<insert id="saveMbomFromEbom" parameterType="map">
|
||||
/* productionplanning.saveMbomFromEbom - E-BOM을 M-BOM으로 복사 */
|
||||
/* 1. 새로운 PART_BOM_REPORT 생성 (M-BOM용) */
|
||||
WITH new_bom_report AS (
|
||||
INSERT INTO PART_BOM_REPORT (
|
||||
OBJID,
|
||||
PART_NO,
|
||||
PART_NAME,
|
||||
WRITER,
|
||||
REGDATE,
|
||||
STATUS
|
||||
) VALUES (
|
||||
(SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000)::INTEGER),
|
||||
#{PART_NO},
|
||||
#{PART_NAME},
|
||||
#{USER_ID},
|
||||
NOW(),
|
||||
'Y'
|
||||
)
|
||||
RETURNING OBJID
|
||||
),
|
||||
/* 2. E-BOM의 BOM_PART_QTY 데이터를 새 M-BOM으로 복사 */
|
||||
copied_bom_data AS (
|
||||
INSERT INTO BOM_PART_QTY (
|
||||
BOM_REPORT_OBJID,
|
||||
OBJID,
|
||||
PARENT_OBJID,
|
||||
CHILD_OBJID,
|
||||
PARENT_PART_NO,
|
||||
PART_NO,
|
||||
QTY,
|
||||
ITEM_QTY,
|
||||
QTY_TEMP,
|
||||
REGDATE,
|
||||
WRITER,
|
||||
SEQ,
|
||||
STATUS,
|
||||
LAST_PART_OBJID
|
||||
)
|
||||
SELECT
|
||||
(SELECT OBJID FROM new_bom_report),
|
||||
(SELECT (FLOOR(RANDOM() * 1000000000) + 1000000000 + ROW_NUMBER() OVER (ORDER BY OBJID))::INTEGER),
|
||||
PARENT_OBJID,
|
||||
CHILD_OBJID,
|
||||
PARENT_PART_NO,
|
||||
PART_NO,
|
||||
QTY,
|
||||
ITEM_QTY,
|
||||
QTY_TEMP,
|
||||
NOW(),
|
||||
#{USER_ID},
|
||||
ROW_NUMBER() OVER (ORDER BY OBJID),
|
||||
'adding',
|
||||
LAST_PART_OBJID
|
||||
FROM BOM_PART_QTY
|
||||
WHERE BOM_REPORT_OBJID::VARCHAR = #{SOURCE_BOM_OBJID}
|
||||
AND COALESCE(STATUS, '') NOT IN ('deleting', 'deleted')
|
||||
RETURNING 1
|
||||
)
|
||||
/* 3. PROJECT_MGMT 업데이트 */
|
||||
UPDATE PROJECT_MGMT
|
||||
SET
|
||||
BOM_REPORT_OBJID = (SELECT OBJID FROM new_bom_report),
|
||||
MBOM_STATUS = 'Y',
|
||||
PART_NO = #{PART_NO},
|
||||
PART_NAME = #{PART_NAME}
|
||||
WHERE OBJID::VARCHAR = #{PROJECT_OBJID}
|
||||
</insert>
|
||||
</mapper>
|
||||
|
||||
@@ -134,6 +134,14 @@ var selectedBomType = null; // 'EBOM' 또는 'MBOM'
|
||||
var bomGridData = []; // BOM 그리드 데이터
|
||||
|
||||
$(function(){
|
||||
// 페이지 로드 시 프로젝트 정보가 있으면 품번/품명 자동 입력
|
||||
<c:if test="${not empty projectInfo}">
|
||||
console.log("projectInfo가 있습니다. 품번/품명 설정 중...");
|
||||
$("#COPY_PART_NO").val("${projectInfo.PART_NO}");
|
||||
$("#COPY_PART_NAME").val("${projectInfo.PART_NAME}");
|
||||
// E-BOM 품번은 사용자가 직접 입력하도록 비워둠 (M-BOM 품번과 다를 수 있음)
|
||||
</c:if>
|
||||
|
||||
// 담기 버튼 - 선택한 BOM을 복사 대상으로 설정
|
||||
$("#btnAddItem").click(function(){
|
||||
var partNo = $("#COPY_PART_NO").val().trim();
|
||||
@@ -207,6 +215,8 @@ $(function(){
|
||||
|
||||
// BOM 미리보기 로드
|
||||
function fn_loadBomPreview(partNo, bomType) {
|
||||
console.log("fn_loadBomPreview 호출:", partNo, bomType);
|
||||
|
||||
// 먼저 품번으로 BOM OBJID 조회
|
||||
$.ajax({
|
||||
url: "/partMng/getBomObjIdByPartNo.do",
|
||||
@@ -214,6 +224,8 @@ function fn_loadBomPreview(partNo, bomType) {
|
||||
data: { partNo: partNo },
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
console.log("getBomObjIdByPartNo 응답:", response);
|
||||
|
||||
if(response && response.OBJID) {
|
||||
$("#bomPartName").text(partNo);
|
||||
// 전역 변수에 저장
|
||||
@@ -222,10 +234,12 @@ function fn_loadBomPreview(partNo, bomType) {
|
||||
// BOM 트리 데이터 로드
|
||||
fn_loadBomTree(response.OBJID);
|
||||
} else {
|
||||
console.error("BOM OBJID를 찾을 수 없음:", response);
|
||||
Swal.fire('해당 품번의 BOM을 찾을 수 없습니다.');
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
error: function(xhr, status, error) {
|
||||
console.error("getBomObjIdByPartNo 에러:", xhr, status, error);
|
||||
Swal.fire('BOM 조회 중 오류가 발생했습니다.');
|
||||
}
|
||||
});
|
||||
@@ -233,6 +247,8 @@ function fn_loadBomPreview(partNo, bomType) {
|
||||
|
||||
// BOM 트리 데이터 로드
|
||||
function fn_loadBomTree(bomObjId) {
|
||||
console.log("fn_loadBomTree 호출:", bomObjId);
|
||||
|
||||
$.ajax({
|
||||
url: "/partMng/getStructureTreeJson.do",
|
||||
type: "POST",
|
||||
@@ -243,6 +259,8 @@ function fn_loadBomTree(bomObjId) {
|
||||
},
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
console.log("getStructureTreeJson 응답:", response);
|
||||
|
||||
if(response && response.length > 0) {
|
||||
var maxLevel = response[0].MAX_LEVEL || 3;
|
||||
|
||||
@@ -260,11 +278,13 @@ function fn_loadBomTree(bomObjId) {
|
||||
|
||||
fn_initGrid(processedData, maxLevel);
|
||||
} else {
|
||||
console.warn("BOM 트리 데이터가 비어있음");
|
||||
bomGridData = [];
|
||||
fn_initGrid([], 3);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
error: function(xhr, status, error) {
|
||||
console.error("getStructureTreeJson 에러:", xhr, status, error);
|
||||
Swal.fire('BOM 트리 조회 중 오류가 발생했습니다.');
|
||||
}
|
||||
});
|
||||
@@ -506,6 +526,10 @@ function fn_saveBomCopy() {
|
||||
text: 'M-BOM이 성공적으로 생성되었습니다.',
|
||||
icon: 'success'
|
||||
}).then(() => {
|
||||
// 부모 창(M-BOM 관리) 새로고침하여 아이콘 업데이트
|
||||
if(window.opener && !window.opener.closed) {
|
||||
window.opener.location.reload();
|
||||
}
|
||||
window.close();
|
||||
});
|
||||
} else {
|
||||
@@ -607,11 +631,6 @@ function fn_excel() {
|
||||
<div id="structureGrid"></div>
|
||||
</div>
|
||||
|
||||
<!-- 하단: 저장/닫기 버튼 -->
|
||||
<div class="bottom-button-section">
|
||||
<input type="button" value="저장" class="plm_btns" id="btnSaveItem" style="margin-right: 5px;">
|
||||
<input type="button" value="닫기" class="plm_btns" id="btnClose" onclick="fn_close();">
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -422,16 +422,14 @@ function fn_changeRelatePartInfo(objId,rightObjId,leftObjId,leftPartNoQty,leftPa
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="backcolor" style="border:border:1px solid #ccc;">
|
||||
<body>
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<input type="hidden" name="objId" id="objId" value="${param.objId}" />
|
||||
|
||||
<div id="structurePopupBtnW" style="padding-top:20px;">
|
||||
<div id="structurePopupBtnW">
|
||||
<input type="button" value="변경" class="plm_btns" id="moveChange">
|
||||
<br>
|
||||
<input type="button" value="<<" class="plm_btns" id="moveLeft" style="margin-left:0px;">
|
||||
<br>
|
||||
<input type="button" value=">>" class="plm_btns" id="moveRight" style="margin-left:0px;">
|
||||
<input type="button" value="<<" class="plm_btns" id="moveLeft">
|
||||
<input type="button" value=">>" class="plm_btns" id="moveRight">
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,439 @@
|
||||
<%@ 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>
|
||||
|
||||
<script>
|
||||
// confirm/alert 헬퍼 함수
|
||||
function showConfirm(options) {
|
||||
if(typeof options === 'string') {
|
||||
alert(options);
|
||||
return Promise.resolve({isConfirmed: true});
|
||||
}
|
||||
|
||||
var message = '';
|
||||
if(options.title) message += options.title + '\n\n';
|
||||
if(options.html) {
|
||||
// HTML 태그 제거
|
||||
message += options.html.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]+>/g, '');
|
||||
} else if(options.text) {
|
||||
message += options.text;
|
||||
}
|
||||
|
||||
if(options.showCancelButton !== false && (options.icon === 'warning' || options.icon === 'question')) {
|
||||
var result = confirm(message);
|
||||
return Promise.resolve({isConfirmed: result});
|
||||
} else {
|
||||
alert(message);
|
||||
return Promise.resolve({isConfirmed: true});
|
||||
}
|
||||
}
|
||||
|
||||
$(function(){
|
||||
|
||||
$('.select2').select2();
|
||||
|
||||
//Part 연결
|
||||
$("#moveLeft").click(function(){
|
||||
// Tabulator에서 선택된 오른쪽 행 데이터 가져오기
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
||||
|
||||
if(rightSelectedRows.length === 0) {
|
||||
showConfirm("선택된 파트가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 왼쪽 프레임에서 선택된 행 데이터 가져오기
|
||||
var leftPartNoObj = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
|
||||
|
||||
var leftPartChildObjId = null;
|
||||
var leftPartNo = null;
|
||||
var leftPartNoQty = null;
|
||||
var leftParentObjId = null;
|
||||
var leftPartLastObjId = null;
|
||||
var leftQtyParObjId = null;
|
||||
var leftParentParts = "";
|
||||
|
||||
if(leftPartNoObj.length > 0) {
|
||||
leftPartChildObjId = leftPartNoObj.val();
|
||||
leftPartNo = leftPartNoObj.attr("data-PART_NO");
|
||||
leftPartNoQty = leftPartNoObj.attr("data-PART_NO_QTY");
|
||||
leftParentObjId = leftPartNoObj.attr("data-OBJID");
|
||||
leftPartLastObjId = leftPartNoObj.attr("data-LAST_PART_OBJID");
|
||||
leftQtyParObjId = leftPartNoObj.attr("data-PART_OBJID");
|
||||
leftParentParts = leftPartNoObj.attr("data-PARENT_PARTS") || "";
|
||||
}
|
||||
|
||||
// 같은 Part를 연결한건지 체크
|
||||
var isSamePart = false;
|
||||
for(var i = 0; i < rightSelectedRows.length; i++){
|
||||
var rowData = rightSelectedRows[i].getData();
|
||||
var rightPartNo = rowData.PART_NO;
|
||||
if(rightPartNo == leftPartNo){
|
||||
showConfirm({
|
||||
title: '연결 불가',
|
||||
html: '오류 Part No : <strong>['+rightPartNo+']</strong><br>같은 Part No끼리 연결할 수 없습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
isSamePart = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isSamePart) return false;
|
||||
|
||||
// 연결하려는 part가 상위에 있는 part인지 확인
|
||||
var deniedPartArr = [];
|
||||
if(fnc_checkNull(leftParentParts).indexOf(",") > 0){
|
||||
deniedPartArr = leftParentParts.split(",");
|
||||
}
|
||||
var isDeniedPart = false;
|
||||
|
||||
for(var i = 0; i < rightSelectedRows.length; i++){
|
||||
var rowData = rightSelectedRows[i].getData();
|
||||
var rightPartNo = rowData.PART_NO;
|
||||
var rightPartType = rowData.PART_TYPE;
|
||||
|
||||
if("unique" == rightPartType){
|
||||
for(var j = 0 ; j < deniedPartArr.length ; j++){
|
||||
if(rightPartNo == deniedPartArr[j]){
|
||||
showConfirm({
|
||||
title: '연결 불가',
|
||||
html: '오류 Part No : <strong>['+rightPartNo+']</strong><br>이미 상위에 등록된 Part No 입니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
isDeniedPart = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(isDeniedPart) break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isDeniedPart) return;
|
||||
|
||||
// 선택된 파트의 OBJID 배열 생성
|
||||
var rightCheckedArr = [];
|
||||
for(var i = 0; i < rightSelectedRows.length; i++){
|
||||
var rowData = rightSelectedRows[i].getData();
|
||||
rightCheckedArr.push(rowData.OBJID);
|
||||
}
|
||||
|
||||
if(fnc_checkNull(leftPartNo) == ""){
|
||||
var flag = fn_checkSameTopPartNo(rightCheckedArr);
|
||||
if(flag == "true"){
|
||||
showConfirm({
|
||||
title: '중복 등록 불가',
|
||||
text: '1레벨에 같은 Part No가 중복 등록될 수 없습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Part 연결 확인
|
||||
showConfirm({
|
||||
title: 'Part 연결',
|
||||
text: '선택한 Part를 연결하시겠습니까?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '연결',
|
||||
cancelButtonText: '취소',
|
||||
reverseButtons: false
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_relatePartInfo(leftPartChildObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
|
||||
}
|
||||
});
|
||||
});
|
||||
//end of Part 연결
|
||||
|
||||
//연결된 part 삭제
|
||||
$("#moveRight").click(function(){
|
||||
var leftPartNoObj = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
|
||||
var leftPartChildObjId = leftPartNoObj.val();
|
||||
var leftPartNo = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PART_NO");
|
||||
var leftParentPartNo = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PARENT_PART_NO");
|
||||
var leftParentObjId = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PARENT_OBJID");
|
||||
var leftPartLastObjId = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-LAST_PART_OBJID");
|
||||
|
||||
fn_deletePartRelateInfo(leftPartNoObj.val(), leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId);
|
||||
});
|
||||
//end of 연결된 part 삭제
|
||||
|
||||
//연결된 part 변경
|
||||
$("#moveChange").click(function(){
|
||||
var leftPartNoList = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
|
||||
|
||||
if(leftPartNoList.length === 0){
|
||||
showConfirm("선택된 파트가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(leftPartNoList.length > 1){
|
||||
showConfirm("한번에 1개의 파트만 변경가능합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var leftPartNo = leftPartNoList.attr("data-PART_NO");
|
||||
var leftPartObjid = leftPartNoList.attr("data-BOM_LAST_PART_OBJID");
|
||||
var leftParentPartObjid = leftPartNoList.attr("data-PARENT_PART_NO");
|
||||
var leftPartChildObjId = leftPartNoList.val();
|
||||
var leftPartBomQtyObjId = leftPartNoList.attr("data-OBJID");
|
||||
|
||||
// Tabulator에서 선택된 오른쪽 행 데이터 가져오기
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
||||
|
||||
if(rightSelectedRows.length === 0){
|
||||
showConfirm("선택된 파트가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(rightSelectedRows.length > 1){
|
||||
showConfirm("한번에 1개의 파트만 변경가능합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var rightRowData = rightSelectedRows[0].getData();
|
||||
var rightPartNo = rightRowData.PART_NO;
|
||||
var rightPartRev = rightRowData.REVISION || "";
|
||||
var rightObjId = rightRowData.OBJID;
|
||||
|
||||
// Part 변경 확인
|
||||
showConfirm({
|
||||
title: 'Part 변경',
|
||||
html: '선택한 Part를 변경하시겠습니까?<br><br>' +
|
||||
'<strong>기존:</strong> ' + leftPartNo + '<br>' +
|
||||
'<strong>변경:</strong> ' + rightPartNo,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '변경',
|
||||
cancelButtonText: '취소',
|
||||
reverseButtons: false
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_changeRelatePartInfo(leftPartBomQtyObjId, rightObjId, leftPartChildObjId, leftParentPartObjid, leftPartChildObjId, leftPartObjid, rightPartNo, rightPartRev);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
//1레벨에 같은 Part No가 등록되어있는지 확인.
|
||||
function fn_checkSameTopPartNo(rightCheckedArr){
|
||||
var result = false;
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/checkSameTopPartNo.do",
|
||||
method: 'post',
|
||||
traditional: true, // 배열 파라미터 처리를 위한 옵션
|
||||
data: {"OBJID":$("#objId").val(), "rightCheckedArr[]":rightCheckedArr}, // [] 추가
|
||||
dataType: 'json',
|
||||
async:false,
|
||||
success: function(data) {
|
||||
result = data.result;
|
||||
}
|
||||
, error: function(jqxhr, status, error){
|
||||
/* alert(jqxhr.statusText + ", " + status + ", " + error);
|
||||
alert(jqxhr.status);
|
||||
alert(jqxhr.responseText); */
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
//end of 1레벨에 같은 Part No가 등록되어있는지 확인.
|
||||
|
||||
//구조 연결 해제
|
||||
function fn_deletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId){
|
||||
if(leftObjId == null){
|
||||
showConfirm("연결 해제할 Part를 선택해 주시기 바랍니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
showConfirm({
|
||||
title: 'Part 연결 해제',
|
||||
text: '선택한 Part의 연결을 해제하시겠습니까?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '연결 해제',
|
||||
cancelButtonText: '취소',
|
||||
reverseButtons: false
|
||||
}).then(result => {
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
fn_executeDeletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId);
|
||||
});
|
||||
}
|
||||
|
||||
// 실제 Part 연결 해제 실행 함수
|
||||
function fn_executeDeletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId){
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/deleteStatusPartRelateInfo.do",
|
||||
method: 'post',
|
||||
data: {"OBJID":$("#objId").val(), "leftObjId":leftObjId, "partObjId":leftPartLastObjId, "BOM_REPORT_OBJID":$("#objId").val()
|
||||
, "leftPartChildObjId":leftPartChildObjId, "leftParentPartNo":leftParentPartNo, "leftParentObjId":leftParentObjId},
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data.result){
|
||||
$(parent.frames['leftFrame'].document.location.reload());
|
||||
//$(parent.frames['rightFrame'].fn_searchPart());
|
||||
|
||||
// 부모 창(M-BOM 목록) 새로고침
|
||||
if(window.opener && window.opener.fn_search) {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
}
|
||||
}
|
||||
, error: function(jqxhr, status, error){
|
||||
/* alert(jqxhr.statusText + ", " + status + ", " + error);
|
||||
alert(jqxhr.status);
|
||||
alert(jqxhr.responseText); */
|
||||
}
|
||||
});
|
||||
}
|
||||
//end of 구조 연결 해제
|
||||
|
||||
//구조 연결
|
||||
function fn_relatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId){
|
||||
if(typeof rightCheckedArr != "undefined" && rightCheckedArr.length == 0){
|
||||
showConfirm("선택된 Part가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(leftObjId == null){
|
||||
showConfirm({
|
||||
title: '1레벨 등록 확인',
|
||||
html: '좌측에 선택된 Part정보가 없습니다.<br>이대로 연결하면 1레벨로 등록됩니다.<br><br>진행하시겠습니까?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '진행',
|
||||
cancelButtonText: '취소',
|
||||
reverseButtons: false
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_executeRelatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
fn_executeRelatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
|
||||
}
|
||||
|
||||
// 실제 Part 연결 실행 함수
|
||||
function fn_executeRelatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId){
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/relatePartInfo.do",
|
||||
method: 'post',
|
||||
traditional: true, // 배열 파라미터 처리를 위한 옵션
|
||||
data: {
|
||||
"leftObjId": leftObjId,
|
||||
"leftPartNoQty": leftPartNoQty,
|
||||
"OBJID": $("#objId").val(),
|
||||
"rightCheckedArr[]": rightCheckedArr, // Spring의 @RequestParam(value = "rightCheckedArr[]") 형식
|
||||
"partObjId": leftPartLastObjId,
|
||||
"BOM_REPORT_OBJID": $("#objId").val(),
|
||||
"leftPartChildObjId": leftPartChildObjId,
|
||||
"leftQtyParObjId": leftQtyParObjId
|
||||
},
|
||||
dataType: 'json',
|
||||
async:false,
|
||||
success: function(data) {
|
||||
if(data.result){
|
||||
// 왼쪽 프레임 새로고침
|
||||
$(parent.frames['leftFrame'].document.location.reload());
|
||||
|
||||
// 오른쪽 프레임 선택 해제 (Tabulator)
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
if(rightFrame.clearSelection) {
|
||||
rightFrame.clearSelection();
|
||||
}
|
||||
|
||||
// 부모 창(M-BOM 목록) 새로고침
|
||||
if(window.opener && window.opener.fn_search) {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
}
|
||||
}
|
||||
, error: function(jqxhr, status, error){
|
||||
/* alert(jqxhr.statusText + ", " + status + ", " + error);
|
||||
alert(jqxhr.status);
|
||||
alert(jqxhr.responseText); */
|
||||
}
|
||||
});
|
||||
}
|
||||
//end of 구조 연결
|
||||
|
||||
//구조 연결 변경
|
||||
function fn_changeRelatePartInfo(objId,rightObjId,leftObjId,leftPartNoQty,leftPartChildObjId,leftPartObjid,rightPartNo,rightPartRev){
|
||||
$.ajax({
|
||||
url: "/productionplanning/changeRelatePartInfo.do",
|
||||
method: 'post',
|
||||
data: {"rightObjId":rightObjId, "OBJID":objId,"BOM_REPORT_OBJID":$("#objId").val(),
|
||||
"leftObjId":leftObjId,"leftPartNoQty":leftPartNoQty,"leftPartChildObjId":leftPartChildObjId,
|
||||
"leftPartObjid":leftPartObjid, "rightPartNo":rightPartNo, "rightPartRev":rightPartRev},
|
||||
dataType: 'json',
|
||||
async:false,
|
||||
success: function(data) {
|
||||
if(data.result){
|
||||
// 왼쪽 프레임 새로고침
|
||||
$(parent.frames['leftFrame'].document.location.reload());
|
||||
|
||||
// 오른쪽 프레임 검색 다시 수행
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
if(rightFrame.fn_searchPart) {
|
||||
rightFrame.fn_searchPart();
|
||||
}
|
||||
|
||||
// 오른쪽 프레임 선택 해제 (Tabulator)
|
||||
if(rightFrame.clearSelection) {
|
||||
rightFrame.clearSelection();
|
||||
}
|
||||
|
||||
// 부모 창(M-BOM 목록) 새로고침
|
||||
if(window.opener && window.opener.fn_search) {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
}
|
||||
}
|
||||
, error: function(jqxhr, status, error){
|
||||
/* alert(jqxhr.statusText + ", " + status + ", " + error);
|
||||
alert(jqxhr.status);
|
||||
alert(jqxhr.responseText); */
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="backcolor" style="border:border:1px solid #ccc;">
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<input type="hidden" name="objId" id="objId" value="${param.objId}" />
|
||||
|
||||
<div id="structurePopupBtnW" style="padding-top:20px;">
|
||||
<input type="button" value="변경" class="plm_btns" id="moveChange">
|
||||
<br>
|
||||
<input type="button" value="<<" class="plm_btns" id="moveLeft" style="margin-left:0px;">
|
||||
<br>
|
||||
<input type="button" value=">>" class="plm_btns" id="moveRight" style="margin-left:0px;">
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
584
WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp
Normal file
584
WebContent/WEB-INF/view/productionplanning/mBomHeaderPopup.jsp
Normal file
@@ -0,0 +1,584 @@
|
||||
<%@ 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>
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
height: auto;
|
||||
}
|
||||
#plmSearchZon td.label,
|
||||
#plmSearchZon td:first-child {
|
||||
text-align: right;
|
||||
padding-right: 5px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
// confirm/alert 헬퍼 함수
|
||||
function showConfirm(options) {
|
||||
if(typeof options === 'string') {
|
||||
alert(options);
|
||||
return Promise.resolve({isConfirmed: true});
|
||||
}
|
||||
|
||||
var message = '';
|
||||
if(options.title) message += options.title + '\n\n';
|
||||
if(options.html) {
|
||||
// HTML 태그 제거
|
||||
message += options.html.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]+>/g, '');
|
||||
} else if(options.text) {
|
||||
message += options.text;
|
||||
}
|
||||
|
||||
if(options.showCancelButton !== false && (options.icon === 'warning' || options.icon === 'question')) {
|
||||
var result = confirm(message);
|
||||
return Promise.resolve({isConfirmed: result});
|
||||
} else {
|
||||
alert(message);
|
||||
return Promise.resolve({isConfirmed: true});
|
||||
}
|
||||
}
|
||||
|
||||
$(function(){
|
||||
|
||||
$('.select2').select2();
|
||||
|
||||
//Part 연결
|
||||
$("#moveLeft").click(function(){
|
||||
// Tabulator에서 선택된 오른쪽 행 데이터 가져오기
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
||||
|
||||
if(rightSelectedRows.length === 0) {
|
||||
showConfirm("선택된 파트가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 왼쪽 프레임에서 선택된 행 데이터 가져오기
|
||||
var leftPartNoObj = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
|
||||
|
||||
var leftPartChildObjId = null;
|
||||
var leftPartNo = null;
|
||||
var leftPartNoQty = null;
|
||||
var leftParentObjId = null;
|
||||
var leftPartLastObjId = null;
|
||||
var leftQtyParObjId = null;
|
||||
var leftParentParts = "";
|
||||
|
||||
if(leftPartNoObj.length > 0) {
|
||||
leftPartChildObjId = leftPartNoObj.val();
|
||||
leftPartNo = leftPartNoObj.attr("data-PART_NO");
|
||||
leftPartNoQty = leftPartNoObj.attr("data-PART_NO_QTY");
|
||||
leftParentObjId = leftPartNoObj.attr("data-OBJID");
|
||||
leftPartLastObjId = leftPartNoObj.attr("data-LAST_PART_OBJID");
|
||||
leftQtyParObjId = leftPartNoObj.attr("data-PART_OBJID");
|
||||
leftParentParts = leftPartNoObj.attr("data-PARENT_PARTS") || "";
|
||||
}
|
||||
|
||||
// 같은 Part를 연결한건지 체크
|
||||
var isSamePart = false;
|
||||
for(var i = 0; i < rightSelectedRows.length; i++){
|
||||
var rowData = rightSelectedRows[i].getData();
|
||||
var rightPartNo = rowData.PART_NO;
|
||||
if(rightPartNo == leftPartNo){
|
||||
showConfirm({
|
||||
title: '연결 불가',
|
||||
html: '오류 Part No : <strong>['+rightPartNo+']</strong><br>같은 Part No끼리 연결할 수 없습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
isSamePart = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isSamePart) return false;
|
||||
|
||||
// 연결하려는 part가 상위에 있는 part인지 확인
|
||||
var deniedPartArr = [];
|
||||
if(fnc_checkNull(leftParentParts).indexOf(",") > 0){
|
||||
deniedPartArr = leftParentParts.split(",");
|
||||
}
|
||||
var isDeniedPart = false;
|
||||
|
||||
for(var i = 0; i < rightSelectedRows.length; i++){
|
||||
var rowData = rightSelectedRows[i].getData();
|
||||
var rightPartNo = rowData.PART_NO;
|
||||
var rightPartType = rowData.PART_TYPE;
|
||||
|
||||
if("unique" == rightPartType){
|
||||
for(var j = 0 ; j < deniedPartArr.length ; j++){
|
||||
if(rightPartNo == deniedPartArr[j]){
|
||||
showConfirm({
|
||||
title: '연결 불가',
|
||||
html: '오류 Part No : <strong>['+rightPartNo+']</strong><br>이미 상위에 등록된 Part No 입니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
isDeniedPart = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(isDeniedPart) break;
|
||||
}
|
||||
}
|
||||
|
||||
if(isDeniedPart) return;
|
||||
|
||||
// 선택된 파트의 OBJID 배열 생성
|
||||
var rightCheckedArr = [];
|
||||
for(var i = 0; i < rightSelectedRows.length; i++){
|
||||
var rowData = rightSelectedRows[i].getData();
|
||||
rightCheckedArr.push(rowData.OBJID);
|
||||
}
|
||||
|
||||
if(fnc_checkNull(leftPartNo) == ""){
|
||||
var flag = fn_checkSameTopPartNo(rightCheckedArr);
|
||||
if(flag == "true"){
|
||||
showConfirm({
|
||||
title: '중복 등록 불가',
|
||||
text: '1레벨에 같은 Part No가 중복 등록될 수 없습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Part 연결 확인
|
||||
showConfirm({
|
||||
title: 'Part 연결',
|
||||
text: '선택한 Part를 연결하시겠습니까?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '연결',
|
||||
cancelButtonText: '취소',
|
||||
reverseButtons: false
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_relatePartInfo(leftPartChildObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
|
||||
}
|
||||
});
|
||||
});
|
||||
//end of Part 연결
|
||||
|
||||
//연결된 part 삭제
|
||||
$("#moveRight").click(function(){
|
||||
var leftPartNoObj = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
|
||||
var leftPartChildObjId = leftPartNoObj.val();
|
||||
var leftPartNo = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PART_NO");
|
||||
var leftParentPartNo = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PARENT_PART_NO");
|
||||
var leftParentObjId = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-PARENT_OBJID");
|
||||
var leftPartLastObjId = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document).attr("data-LAST_PART_OBJID");
|
||||
|
||||
fn_deletePartRelateInfo(leftPartNoObj.val(), leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId);
|
||||
});
|
||||
//end of 연결된 part 삭제
|
||||
|
||||
//연결된 part 변경
|
||||
$("#moveChange").click(function(){
|
||||
var leftPartNoList = $("input[name=checkedPartNo]:checked", parent.frames['leftFrame'].document);
|
||||
|
||||
if(leftPartNoList.length === 0){
|
||||
showConfirm("선택된 파트가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(leftPartNoList.length > 1){
|
||||
showConfirm("한번에 1개의 파트만 변경가능합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var leftPartNo = leftPartNoList.attr("data-PART_NO");
|
||||
var leftPartObjid = leftPartNoList.attr("data-BOM_LAST_PART_OBJID");
|
||||
var leftParentPartObjid = leftPartNoList.attr("data-PARENT_PART_NO");
|
||||
var leftPartChildObjId = leftPartNoList.val();
|
||||
var leftPartBomQtyObjId = leftPartNoList.attr("data-OBJID");
|
||||
|
||||
// Tabulator에서 선택된 오른쪽 행 데이터 가져오기
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
||||
|
||||
if(rightSelectedRows.length === 0){
|
||||
showConfirm("선택된 파트가 없습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(rightSelectedRows.length > 1){
|
||||
showConfirm("한번에 1개의 파트만 변경가능합니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var rightRowData = rightSelectedRows[0].getData();
|
||||
var rightPartNo = rightRowData.PART_NO;
|
||||
var rightPartRev = rightRowData.REVISION || "";
|
||||
var rightObjId = rightRowData.OBJID;
|
||||
|
||||
// Part 변경 확인
|
||||
showConfirm({
|
||||
title: 'Part 변경',
|
||||
html: '선택한 Part를 변경하시겠습니까?<br><br>' +
|
||||
'<strong>기존:</strong> ' + leftPartNo + '<br>' +
|
||||
'<strong>변경:</strong> ' + rightPartNo,
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '변경',
|
||||
cancelButtonText: '취소',
|
||||
reverseButtons: false
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_changeRelatePartInfo(leftPartBomQtyObjId, rightObjId, leftPartChildObjId, leftParentPartObjid, leftPartChildObjId, leftPartObjid, rightPartNo, rightPartRev);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 조회 버튼 클릭
|
||||
$("#btnSearch").click(function(){
|
||||
fn_searchMbom();
|
||||
});
|
||||
|
||||
// 저장 버튼 클릭
|
||||
$("#btnSave").click(function(){
|
||||
fn_saveMbom();
|
||||
});
|
||||
|
||||
// BOM 복사 버튼 클릭
|
||||
$("#btnBomCopy").click(function(){
|
||||
fn_openBomCopyPopup();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
//1레벨에 같은 Part No가 등록되어있는지 확인.
|
||||
function fn_checkSameTopPartNo(rightCheckedArr){
|
||||
var result = false;
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/checkSameTopPartNo.do",
|
||||
method: 'post',
|
||||
traditional: true, // 배열 파라미터 처리를 위한 옵션
|
||||
data: {"OBJID":$("#objId").val(), "rightCheckedArr[]":rightCheckedArr}, // [] 추가
|
||||
dataType: 'json',
|
||||
async:false,
|
||||
success: function(data) {
|
||||
result = data.result;
|
||||
}
|
||||
, error: function(jqxhr, status, error){
|
||||
/* alert(jqxhr.statusText + ", " + status + ", " + error);
|
||||
alert(jqxhr.status);
|
||||
alert(jqxhr.responseText); */
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
//end of 1레벨에 같은 Part No가 등록되어있는지 확인.
|
||||
|
||||
//구조 연결 해제
|
||||
function fn_deletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId){
|
||||
if(leftObjId == null){
|
||||
showConfirm("연결 해제할 Part를 선택해 주시기 바랍니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
showConfirm({
|
||||
title: 'Part 연결 해제',
|
||||
text: '선택한 Part의 연결을 해제하시겠습니까?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '연결 해제',
|
||||
cancelButtonText: '취소',
|
||||
reverseButtons: false
|
||||
}).then(result => {
|
||||
if (!result.isConfirmed) return;
|
||||
|
||||
fn_executeDeletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId);
|
||||
});
|
||||
}
|
||||
|
||||
// 실제 Part 연결 해제 실행 함수
|
||||
function fn_executeDeletePartRelateInfo(leftObjId, leftPartLastObjId, leftParentPartNo, leftParentObjId, leftPartChildObjId){
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/deleteStatusPartRelateInfo.do",
|
||||
method: 'post',
|
||||
data: {"OBJID":$("#objId").val(), "leftObjId":leftObjId, "partObjId":leftPartLastObjId, "BOM_REPORT_OBJID":$("#objId").val()
|
||||
, "leftPartChildObjId":leftPartChildObjId, "leftParentPartNo":leftParentPartNo, "leftParentObjId":leftParentObjId},
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data.result){
|
||||
$(parent.frames['leftFrame'].document.location.reload());
|
||||
//$(parent.frames['rightFrame'].fn_searchPart());
|
||||
|
||||
// 부모 창(E-BOM 목록) 새로고침
|
||||
if(window.opener && window.opener.fn_search) {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
}
|
||||
}
|
||||
, error: function(jqxhr, status, error){
|
||||
/* alert(jqxhr.statusText + ", " + status + ", " + error);
|
||||
alert(jqxhr.status);
|
||||
alert(jqxhr.responseText); */
|
||||
}
|
||||
});
|
||||
}
|
||||
//end of 구조 연결 해제
|
||||
|
||||
//구조 연결
|
||||
function fn_relatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId){
|
||||
if(typeof rightCheckedArr != "undefined" && rightCheckedArr.length == 0){
|
||||
showConfirm("선택된 Part가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(leftObjId == null){
|
||||
showConfirm({
|
||||
title: '1레벨 등록 확인',
|
||||
html: '좌측에 선택된 Part정보가 없습니다.<br>이대로 연결하면 1레벨로 등록됩니다.<br><br>진행하시겠습니까?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '진행',
|
||||
cancelButtonText: '취소',
|
||||
reverseButtons: false
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_executeRelatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
fn_executeRelatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId);
|
||||
}
|
||||
|
||||
// 실제 Part 연결 실행 함수
|
||||
function fn_executeRelatePartInfo(leftObjId, rightCheckedArr, leftPartNoQty, leftPartLastObjId, leftPartChildObjId, leftQtyParObjId){
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/relatePartInfo.do",
|
||||
method: 'post',
|
||||
traditional: true, // 배열 파라미터 처리를 위한 옵션
|
||||
data: {
|
||||
"leftObjId": leftObjId,
|
||||
"leftPartNoQty": leftPartNoQty,
|
||||
"OBJID": $("#objId").val(),
|
||||
"rightCheckedArr[]": rightCheckedArr, // Spring의 @RequestParam(value = "rightCheckedArr[]") 형식
|
||||
"partObjId": leftPartLastObjId,
|
||||
"BOM_REPORT_OBJID": $("#objId").val(),
|
||||
"leftPartChildObjId": leftPartChildObjId,
|
||||
"leftQtyParObjId": leftQtyParObjId
|
||||
},
|
||||
dataType: 'json',
|
||||
async:false,
|
||||
success: function(data) {
|
||||
if(data.result){
|
||||
// 왼쪽 프레임 새로고침
|
||||
$(parent.frames['leftFrame'].document.location.reload());
|
||||
|
||||
// 오른쪽 프레임 선택 해제 (Tabulator)
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
if(rightFrame.clearSelection) {
|
||||
rightFrame.clearSelection();
|
||||
}
|
||||
|
||||
// 부모 창(E-BOM 목록) 새로고침
|
||||
if(window.opener && window.opener.fn_search) {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
}
|
||||
}
|
||||
, error: function(jqxhr, status, error){
|
||||
/* alert(jqxhr.statusText + ", " + status + ", " + error);
|
||||
alert(jqxhr.status);
|
||||
alert(jqxhr.responseText); */
|
||||
}
|
||||
});
|
||||
}
|
||||
//end of 구조 연결
|
||||
|
||||
//구조 연결 변경
|
||||
function fn_changeRelatePartInfo(objId,rightObjId,leftObjId,leftPartNoQty,leftPartChildObjId,leftPartObjid,rightPartNo,rightPartRev){
|
||||
$.ajax({
|
||||
url: "/productionplanning/changeRelatePartInfo.do",
|
||||
method: 'post',
|
||||
data: {"rightObjId":rightObjId, "OBJID":objId,"BOM_REPORT_OBJID":$("#objId").val(),
|
||||
"leftObjId":leftObjId,"leftPartNoQty":leftPartNoQty,"leftPartChildObjId":leftPartChildObjId,
|
||||
"leftPartObjid":leftPartObjid, "rightPartNo":rightPartNo, "rightPartRev":rightPartRev},
|
||||
dataType: 'json',
|
||||
async:false,
|
||||
success: function(data) {
|
||||
if(data.result){
|
||||
// 왼쪽 프레임 새로고침
|
||||
$(parent.frames['leftFrame'].document.location.reload());
|
||||
|
||||
// 오른쪽 프레임 검색 다시 수행
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
if(rightFrame.fn_searchPart) {
|
||||
rightFrame.fn_searchPart();
|
||||
}
|
||||
|
||||
// 오른쪽 프레임 선택 해제 (Tabulator)
|
||||
if(rightFrame.clearSelection) {
|
||||
rightFrame.clearSelection();
|
||||
}
|
||||
|
||||
// 부모 창(E-BOM 목록) 새로고침
|
||||
if(window.opener && window.opener.fn_search) {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
}
|
||||
}
|
||||
, error: function(jqxhr, status, error){
|
||||
/* alert(jqxhr.statusText + ", " + status + ", " + error);
|
||||
alert(jqxhr.status);
|
||||
alert(jqxhr.responseText); */
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// M-BOM 조회
|
||||
function fn_searchMbom() {
|
||||
var partNo = $("#search_part_no").val().trim();
|
||||
var partName = $("#search_part_name").val().trim();
|
||||
var mbomPartNo = $("#search_mbom_part_no").val().trim();
|
||||
var saveDate = $("#search_save_date").val().trim();
|
||||
|
||||
// 왼쪽 프레임의 조회 함수 호출
|
||||
var leftFrame = parent.frames['leftFrame'];
|
||||
if(leftFrame && leftFrame.fn_searchMbom) {
|
||||
leftFrame.fn_searchMbom({
|
||||
partNo: partNo,
|
||||
partName: partName,
|
||||
mbomPartNo: mbomPartNo,
|
||||
saveDate: saveDate
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// M-BOM 저장
|
||||
function fn_saveMbom() {
|
||||
// 왼쪽 프레임에서 M-BOM 트리 데이터 가져오기
|
||||
var leftFrame = parent.frames['leftFrame'];
|
||||
if(!leftFrame) {
|
||||
alert("M-BOM 데이터를 가져올 수 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 트리 데이터 수집 (leftFrame에서 구현 필요)
|
||||
var mbomData = leftFrame.getMbomTreeData ? leftFrame.getMbomTreeData() : null;
|
||||
|
||||
if(!mbomData || mbomData.length === 0) {
|
||||
alert("저장할 M-BOM 데이터가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 저장 확인
|
||||
if(!confirm("M-BOM을 저장하시겠습니까?")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 저장 API 호출
|
||||
$.ajax({
|
||||
url: "/productionplanning/saveMbom.do",
|
||||
method: 'post',
|
||||
data: JSON.stringify({
|
||||
mbomData: mbomData,
|
||||
partNo: $("#search_part_no").val().trim(),
|
||||
partName: $("#search_part_name").val().trim()
|
||||
}),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data && data.result === "success") {
|
||||
alert("M-BOM이 저장되었습니다.");
|
||||
|
||||
// 조회 새로고침
|
||||
fn_searchMbom();
|
||||
|
||||
// 부모 창 새로고침
|
||||
if(window.opener && window.opener.fn_search) {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
} else {
|
||||
alert("M-BOM 저장에 실패했습니다.");
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("M-BOM 저장 오류:", error);
|
||||
alert("M-BOM 저장 중 오류가 발생했습니다.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// BOM 복사 팝업 열기
|
||||
function fn_openBomCopyPopup() {
|
||||
var objId = $("#objId").val();
|
||||
|
||||
if(!objId || objId === "-1") {
|
||||
alert("프로젝트 정보를 찾을 수 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// BOM 복사 팝업 열기 (저번에 만든 화면)
|
||||
var url = "/partMng/structureBomCopyFormPopup.do?objId=" + objId;
|
||||
var popupName = "bomCopyPopup";
|
||||
var popupWidth = 1400;
|
||||
var popupHeight = 800;
|
||||
var left = (screen.width - popupWidth) / 2;
|
||||
var top = (screen.height - popupHeight) / 2;
|
||||
|
||||
window.open(url, popupName, "width=" + popupWidth + ",height=" + popupHeight + ",left=" + left + ",top=" + top + ",scrollbars=yes,resizable=yes");
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<input type="hidden" name="objId" id="objId" value="${param.objId}" />
|
||||
|
||||
<div id="plmSearchZon">
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="search_part_no">품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_part_no" id="search_part_no" value="">
|
||||
</td>
|
||||
|
||||
<td class="label"><label for="search_part_name">품명</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_part_name" id="search_part_name" value="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="search_mbom_part_no">M-BOM 품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_mbom_part_no" id="search_mbom_part_no" value="">
|
||||
</td>
|
||||
|
||||
<td class="label"><label for="search_save_date">저장일</label></td>
|
||||
<td>
|
||||
<input type="date" name="search_save_date" id="search_save_date" value="">
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="button" value="조회" class="plm_btns" id="btnSearch">
|
||||
<input type="button" value="저장" class="plm_btns" id="btnSave">
|
||||
<input type="button" value="BOM 복사" class="plm_btns" id="btnBomCopy">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
@@ -205,8 +205,20 @@ var columns = [
|
||||
field: 'MBOM_STATUS',
|
||||
formatter: fnc_subInfoValueFormatter,
|
||||
cellClick: function(e, cell) {
|
||||
var objid = fnc_checkNull(cell.getData().OBJID);
|
||||
fn_openMBomPopup(objid);
|
||||
var rowData = cell.getData();
|
||||
var objid = fnc_checkNull(rowData.OBJID);
|
||||
var mbomStatus = fnc_checkNull(rowData.MBOM_STATUS);
|
||||
|
||||
// 파란색(저장된 M-BOM)일 때만 팝업 열기
|
||||
if(mbomStatus !== '' && mbomStatus !== '0') {
|
||||
fn_openMBomFormPopup(objid);
|
||||
} else {
|
||||
Swal.fire({
|
||||
title: '알림',
|
||||
text: 'M-BOM이 생성되지 않았습니다.\nBOM 복사 버튼을 통해 먼저 M-BOM을 생성해주세요.',
|
||||
icon: 'info'
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -271,12 +283,20 @@ function fn_openEBomSelectPopup(projectMgmtObjid, partNo, partName, bomReportObj
|
||||
fn_centerPopup(popup_width, popup_height, url, 'ebomSelectPopup');
|
||||
}
|
||||
|
||||
// M-BOM 팝업
|
||||
// M-BOM 조회 팝업 (읽기 전용)
|
||||
function fn_openMBomPopup(objId) {
|
||||
var popup_width = 1000;
|
||||
var popup_height = 700;
|
||||
var url = "/productionplanning/mBomViewPopup.do?objId=" + objId;
|
||||
fn_centerPopup(popup_width, popup_height, url, 'mbomViewPopup');
|
||||
}
|
||||
|
||||
// M-BOM 편집 팝업 (왼쪽 트리 + 중앙 버튼 + 오른쪽 E-BOM)
|
||||
function fn_openMBomFormPopup(objId) {
|
||||
var popup_width = 1800;
|
||||
var popup_height = 800;
|
||||
var popup_height = 900;
|
||||
var url = "/productionplanning/mBomFormPopup.do?objId=" + objId;
|
||||
fn_centerPopup(popup_width, popup_height, url, 'mbomPopup');
|
||||
fn_centerPopup(popup_width, popup_height, url, 'mbomFormPopup');
|
||||
}
|
||||
|
||||
// BOM 복사 팝업
|
||||
@@ -335,22 +355,10 @@ function fn_openBomCopyPopup() {
|
||||
|
||||
// BOM 복사 팝업 창 열기
|
||||
function fn_openBomCopyPopupWindow(objId) {
|
||||
var popup_width = 1400;
|
||||
var popup_height = 800;
|
||||
var url = "/partMng/setBomCopyFormPopup.do?objId=" + objId;
|
||||
var left = (screen.width - popup_width) / 2;
|
||||
var top = (screen.height - popup_height) / 2;
|
||||
|
||||
var popup = window.open(url, "bomCopyPopup", "width=" + popup_width + ",height=" + popup_height + ",left=" + left + ",top=" + top + ",scrollbars=yes,resizable=yes");
|
||||
|
||||
// 팝업이 닫힐 때 그리드 새로고침
|
||||
var checkPopup = setInterval(function() {
|
||||
if(popup.closed) {
|
||||
clearInterval(checkPopup);
|
||||
console.log("BOM 복사 팝업 닫힘 - 그리드 새로고침");
|
||||
fn_search();
|
||||
}
|
||||
}, 500);
|
||||
var popup_width = 1800;
|
||||
var popup_height = 900;
|
||||
var url = "/partMng/structureBomCopyFormPopup.do?objId=" + objId;
|
||||
fn_centerPopup(popup_width, popup_height, url, 'bomCopyPopup');
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
146
WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp
Normal file
146
WebContent/WEB-INF/view/productionplanning/mBomPopupCenter.jsp
Normal file
@@ -0,0 +1,146 @@
|
||||
<%@ 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>
|
||||
|
||||
<script>
|
||||
// confirm/alert 헬퍼 함수
|
||||
function showConfirm(options) {
|
||||
if(typeof options === 'string') {
|
||||
alert(options);
|
||||
return Promise.resolve({isConfirmed: true});
|
||||
}
|
||||
|
||||
var message = '';
|
||||
if(options.title) message += options.title + '\n\n';
|
||||
if(options.html) {
|
||||
// HTML 태그 제거
|
||||
message += options.html.replace(/<br\s*\/?>/gi, '\n').replace(/<[^>]+>/g, '');
|
||||
} else if(options.text) {
|
||||
message += options.text;
|
||||
}
|
||||
|
||||
if(options.showCancelButton !== false && (options.icon === 'warning' || options.icon === 'question')) {
|
||||
var result = confirm(message);
|
||||
return Promise.resolve({isConfirmed: result});
|
||||
} else {
|
||||
alert(message);
|
||||
return Promise.resolve({isConfirmed: true});
|
||||
}
|
||||
}
|
||||
|
||||
$(function(){
|
||||
|
||||
$('.select2').select2();
|
||||
|
||||
// E-BOM 할당 버튼 (변경)
|
||||
$("#moveChange").click(function(){
|
||||
showConfirm({
|
||||
title: 'E-BOM 할당',
|
||||
text: 'E-BOM을 선택하여 이 프로젝트에 할당하시겠습니까?',
|
||||
icon: 'question',
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: '#3085d6',
|
||||
cancelButtonColor: '#d33',
|
||||
confirmButtonText: '할당',
|
||||
cancelButtonText: '취소'
|
||||
}).then(result => {
|
||||
if (result.isConfirmed) {
|
||||
fn_assignEbom();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// << 버튼 (현재는 사용 안 함)
|
||||
$("#moveLeft").click(function(){
|
||||
showConfirm("이 기능은 현재 사용할 수 없습니다.");
|
||||
});
|
||||
|
||||
// >> 버튼 (현재는 사용 안 함)
|
||||
$("#moveRight").click(function(){
|
||||
showConfirm("이 기능은 현재 사용할 수 없습니다.");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// E-BOM 할당 함수
|
||||
function fn_assignEbom(){
|
||||
// 오른쪽 프레임에서 선택된 E-BOM 가져오기
|
||||
var rightFrame = parent.frames['rightFrame'];
|
||||
var rightSelectedRows = rightFrame.getSelectedRows ? rightFrame.getSelectedRows() : [];
|
||||
|
||||
if(rightSelectedRows.length === 0){
|
||||
showConfirm("할당할 E-BOM을 선택해주세요.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(rightSelectedRows.length > 1){
|
||||
showConfirm("한 번에 1개의 E-BOM만 할당할 수 있습니다.");
|
||||
return false;
|
||||
}
|
||||
|
||||
var rowData = rightSelectedRows[0].getData();
|
||||
var bomReportObjid = rowData.OBJID;
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/assignEbomToMbom.do",
|
||||
method: 'post',
|
||||
data: {
|
||||
"projectMgmtObjid": $("#objId").val(),
|
||||
"bomReportObjid": bomReportObjid
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data.result){
|
||||
showConfirm({
|
||||
title: '할당 완료',
|
||||
text: 'E-BOM이 성공적으로 할당되었습니다.',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 왼쪽 프레임 새로고침
|
||||
parent.frames['leftFrame'].location.reload();
|
||||
|
||||
// 부모 창(M-BOM 목록) 새로고침
|
||||
if(window.opener && window.opener.fn_search) {
|
||||
window.opener.fn_search();
|
||||
}
|
||||
} else {
|
||||
showConfirm({
|
||||
title: '할당 실패',
|
||||
text: 'E-BOM 할당 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
showConfirm({
|
||||
title: '오류',
|
||||
text: 'E-BOM 할당 중 오류가 발생했습니다.',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<input type="hidden" name="objId" id="objId" value="${param.objId}" />
|
||||
|
||||
<div id="structurePopupBtnW" style="padding-top:20px;">
|
||||
<input type="button" value="변경" class="plm_btns" id="moveChange">
|
||||
<br>
|
||||
<input type="button" value="<<" class="plm_btns" id="moveLeft" style="margin-left:0px;">
|
||||
<br>
|
||||
<input type="button" value=">>" class="plm_btns" id="moveRight" style="margin-left:0px;">
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
<%String objId = com.pms.common.utils.CommonUtils.checkNull(request.getParameter("objId"));%>
|
||||
<frameset cols="*, 100px, *" border="0" noresize>
|
||||
<frame src="/productionplanning/mBomPopupLeft.do?objId=<%=objId%>" name="leftFrame">
|
||||
<frame src="/productionplanning/mBomPopupCenter.do?objId=<%=objId%>" name="centerFrame">
|
||||
<frame src="/productionplanning/mBomPopupRight.do?objId=<%=objId%>" name="rightFrame">
|
||||
</frameset><noframes></noframes>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
|
||||
<%
|
||||
java.util.Map map = (java.util.HashMap)request.getAttribute("info");
|
||||
if(map == null || map.isEmpty()) {
|
||||
response.sendRedirect("/common/error500.do");
|
||||
return;
|
||||
}
|
||||
String objId = com.pms.common.utils.CommonUtils.checkNull(map.get("OBJID"));
|
||||
%>
|
||||
<frameset rows="100px, *" border="0" noresize>
|
||||
<frame src="/productionplanning/mBomHeaderPopup.do?objId=<%=objId%>">
|
||||
<frame src="/productionplanning/mBomBottomPopupFS.do?objId=<%=objId%>">
|
||||
</frameset><noframes></noframes>
|
||||
|
||||
231
WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp
Normal file
231
WebContent/WEB-INF/view/productionplanning/mBomPopupLeft.jsp
Normal file
@@ -0,0 +1,231 @@
|
||||
<%@ 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;
|
||||
}
|
||||
#mBomName {
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
/* 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 = [];
|
||||
|
||||
// 수준 컬럼 그룹
|
||||
var levelColumns = [];
|
||||
for(var i = 1; i <= maxLevel; i++) {
|
||||
levelColumns.push({
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 30,
|
||||
title: i,
|
||||
field: 'LEVEL_' + i,
|
||||
formatter: function(cell) {
|
||||
return cell.getValue() === '*' ? '*' : '';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
columns.push({
|
||||
title: '수준',
|
||||
headerHozAlign: 'center',
|
||||
columns: levelColumns
|
||||
});
|
||||
|
||||
// 나머지 컬럼 추가
|
||||
columns.push(
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 150,
|
||||
title: '품번',
|
||||
field: 'PART_NO'
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'left',
|
||||
width: 250,
|
||||
title: '품명',
|
||||
field: 'PART_NAME'
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 80,
|
||||
title: '수량',
|
||||
field: 'QTY_TEMP'
|
||||
},
|
||||
{
|
||||
headerHozAlign: 'center',
|
||||
hozAlign: 'center',
|
||||
width: 100,
|
||||
title: '항목 수량',
|
||||
field: 'ITEM_QTY'
|
||||
},
|
||||
{
|
||||
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'
|
||||
}
|
||||
);
|
||||
|
||||
// Tabulator 생성
|
||||
_tabulGrid = new Tabulator("#mBomTableWrap", {
|
||||
layout: "fitColumns",
|
||||
height: "calc(100vh - 150px)",
|
||||
columns: columns,
|
||||
data: ${bomTreeListJson},
|
||||
rowFormatter: function(row) {
|
||||
var data = row.getData();
|
||||
var level = data.LEVEL || 1;
|
||||
row.getElement().classList.add('level-' + level);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 필터 적용 함수
|
||||
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) {
|
||||
$.ajax({
|
||||
url: "/productionplanning/getMbomList.do",
|
||||
method: 'post',
|
||||
data: searchParams,
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data && data.list) {
|
||||
_tabulGrid.setData(data.list);
|
||||
} else {
|
||||
_tabulGrid.setData([]);
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("M-BOM 조회 오류:", error);
|
||||
_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>
|
||||
|
||||
161
WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp
Normal file
161
WebContent/WEB-INF/view/productionplanning/mBomPopupRight.jsp
Normal file
@@ -0,0 +1,161 @@
|
||||
<%@ 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>
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
#plmSearchZon {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
#plmSearchZon table {
|
||||
width: 100%;
|
||||
}
|
||||
#plmSearchZon td {
|
||||
padding: 2px 5px;
|
||||
}
|
||||
#plmSearchZon td.label,
|
||||
#plmSearchZon td:first-child {
|
||||
text-align: right;
|
||||
padding-right: 5px;
|
||||
}
|
||||
#ebomTable {
|
||||
height: calc(100% - 80px);
|
||||
}
|
||||
</style>
|
||||
<link href="/css/tabulator/tabulator.min.css" rel="stylesheet">
|
||||
<script type="text/javascript" src="/js/tabulator/tabulator.min.js"></script>
|
||||
</head>
|
||||
<body class="backcolor">
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
|
||||
<div id="plmSearchZon">
|
||||
<table>
|
||||
<tr>
|
||||
<td><label for="search_part_no">품번</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_part_no" id="search_part_no" value="">
|
||||
</td>
|
||||
|
||||
<td class="label"><label for="search_part_name">품명</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_part_name" id="search_part_name" value="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="search_material">재료</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_material" id="search_material" value="">
|
||||
</td>
|
||||
|
||||
<td class="label"><label for="search_supplier">공급업체</label></td>
|
||||
<td>
|
||||
<input type="text" name="search_supplier" id="search_supplier" value="">
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<input type="button" value="조회" class="plm_btns" id="btnSearch">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="ebomTable"></div>
|
||||
</form>
|
||||
|
||||
<script>
|
||||
var ebomTable;
|
||||
|
||||
$(document).ready(function(){
|
||||
initEbomTable();
|
||||
fn_searchEbom();
|
||||
|
||||
// 조회 버튼 클릭 이벤트
|
||||
$("#btnSearch").click(function(){
|
||||
fn_searchEbom();
|
||||
});
|
||||
|
||||
// 엔터키 이벤트
|
||||
$("#search_part_no, #search_part_name, #search_material, #search_supplier").on('keypress', function(e){
|
||||
if(e.keyCode == 13 || e.which == 13){
|
||||
e.preventDefault();
|
||||
fn_searchEbom();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Tabulator 초기화
|
||||
function initEbomTable() {
|
||||
ebomTable = new Tabulator("#ebomTable", {
|
||||
layout: "fitColumns",
|
||||
height: "100%",
|
||||
selectable: true,
|
||||
columns: [
|
||||
{formatter:"rowSelection", titleFormatter:"rowSelection", hozAlign:"center", vertAlign:"middle", headerSort:false, width: 40},
|
||||
{title: "품번", field: "PART_NO", widthGrow: 1.5, vertAlign:"middle"},
|
||||
{title: "품명", field: "PART_NAME", widthGrow: 2, vertAlign:"middle"},
|
||||
{title: "재료", field: "MATERIAL", widthGrow: 1.2, vertAlign:"middle"},
|
||||
{title: "공급업체", field: "SUPPLIER", widthGrow: 1.5, vertAlign:"middle"}
|
||||
],
|
||||
placeholder: "검색 결과가 없습니다."
|
||||
});
|
||||
}
|
||||
|
||||
// E-BOM 검색
|
||||
function fn_searchEbom() {
|
||||
var partNo = $("#search_part_no").val().trim();
|
||||
var partName = $("#search_part_name").val().trim();
|
||||
var material = $("#search_material").val().trim();
|
||||
var supplier = $("#search_supplier").val().trim();
|
||||
|
||||
$.ajax({
|
||||
url: "/productionplanning/getEbomList.do",
|
||||
method: 'post',
|
||||
data: {
|
||||
"search_part_no": partNo,
|
||||
"search_part_name": partName,
|
||||
"search_material": material,
|
||||
"search_supplier": supplier
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data && data.list) {
|
||||
// 품번과 품명이 비어있지 않은 데이터만 필터링
|
||||
var filteredList = data.list.filter(function(item) {
|
||||
return item.PART_NO && item.PART_NO.trim() !== '' &&
|
||||
item.PART_NAME && item.PART_NAME.trim() !== '';
|
||||
});
|
||||
ebomTable.setData(filteredList);
|
||||
} else {
|
||||
ebomTable.setData([]);
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("E-BOM 조회 오류:", error);
|
||||
ebomTable.setData([]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 선택된 행 가져오기 (중앙 프레임에서 호출)
|
||||
function getSelectedRows() {
|
||||
return ebomTable.getSelectedRows();
|
||||
}
|
||||
|
||||
// 선택 해제
|
||||
function clearSelection() {
|
||||
ebomTable.deselectRow();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
140
WebContent/WEB-INF/view/productionplanning/mBomPopupTop.jsp
Normal file
140
WebContent/WEB-INF/view/productionplanning/mBomPopupTop.jsp
Normal file
@@ -0,0 +1,140 @@
|
||||
<%@ 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>
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: visible;
|
||||
height: auto;
|
||||
}
|
||||
.plm_menu_name {
|
||||
margin: 5px 15px 0 15px !important;
|
||||
}
|
||||
.plm_menu_name h2 {
|
||||
margin: 5px 0 !important;
|
||||
padding: 5px 0;
|
||||
}
|
||||
#plmSearchZon {
|
||||
margin-bottom: 0 !important;
|
||||
padding-bottom: 5px !important;
|
||||
overflow: visible !important;
|
||||
position: relative;
|
||||
z-index: 1000;
|
||||
}
|
||||
.select2-container {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
.select2-dropdown {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
// 엔터키 이벤트 바인딩
|
||||
$("#filterPartNo, #filterPartName").on('keypress', function(e){
|
||||
if(e.keyCode == 13 || e.which == 13){
|
||||
e.preventDefault();
|
||||
fn_applyFilter();
|
||||
}
|
||||
});
|
||||
|
||||
// 페이지 로드 시 품번/품명이 있으면 자동으로 필터 적용
|
||||
var partNo = $("#filterPartNo").val().trim();
|
||||
var partName = $("#filterPartName").val().trim();
|
||||
if(partNo || partName) {
|
||||
setTimeout(function() {
|
||||
fn_applyFilter();
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
|
||||
// 필터 적용 함수
|
||||
function fn_applyFilter() {
|
||||
var partNo = $("#filterPartNo").val().trim();
|
||||
var partName = $("#filterPartName").val().trim();
|
||||
|
||||
try {
|
||||
// 프레임 구조: parent(headerFs) -> frames[1](bottomFs) -> frames[0](leftFrame)
|
||||
var leftFrame = parent.frames[1].frames['leftFrame'];
|
||||
|
||||
if(leftFrame && leftFrame.fn_applyFilter) {
|
||||
leftFrame.$("#filterPartNo").val(partNo);
|
||||
leftFrame.$("#filterPartName").val(partName);
|
||||
leftFrame.fn_applyFilter();
|
||||
} else {
|
||||
console.error("leftFrame not found or fn_applyFilter not available");
|
||||
}
|
||||
} catch(e) {
|
||||
console.error("Error accessing leftFrame:", e);
|
||||
alert("필터를 적용할 수 없습니다. 프레임 구조를 확인해주세요.");
|
||||
}
|
||||
}
|
||||
|
||||
// 필터 초기화 함수
|
||||
function fn_resetFilter() {
|
||||
$("#filterPartNo").val("");
|
||||
$("#filterPartName").val("");
|
||||
|
||||
try {
|
||||
var leftFrame = parent.frames[1].frames['leftFrame'];
|
||||
|
||||
if(leftFrame && leftFrame.fn_resetFilter) {
|
||||
leftFrame.fn_resetFilter();
|
||||
}
|
||||
} catch(e) {
|
||||
console.error("Error accessing leftFrame:", e);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body class="backcolor">
|
||||
<form name="form1" id="form1" action="" method="post">
|
||||
<div class="plm_menu_name">
|
||||
<h2>
|
||||
<span>M-BOM 확인</span>
|
||||
<c:if test="${not empty projectNo}">
|
||||
<span style="font-size: 14px; font-weight: normal; color: #666; margin-left: 20px;">
|
||||
프로젝트번호: <strong style="color: #333;">${projectNo}</strong>
|
||||
<c:if test="${not empty partNo}">
|
||||
/ 품번: <strong style="color: #333;">${partNo}</strong>
|
||||
</c:if>
|
||||
<c:if test="${not empty partName}">
|
||||
/ 품명: <strong style="color: #333;">${partName}</strong>
|
||||
</c:if>
|
||||
</span>
|
||||
</c:if>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<!-- 검색 필터 영역 -->
|
||||
<div id="plmSearchZon">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="label"><label for="filterPartNo">품번</label></td>
|
||||
<td>
|
||||
<input type="text" id="filterPartNo" name="filterPartNo" value="${partNo}">
|
||||
</td>
|
||||
|
||||
<td class="label"><label for="filterPartName">품명</label></td>
|
||||
<td>
|
||||
<input type="text" id="filterPartName" name="filterPartName" value="${partName}">
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<button type="button" class="plm_btns" onclick="fn_applyFilter()">검색</button>
|
||||
<button type="button" class="plm_btns" onclick="fn_resetFilter()">초기화</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
183
WebContent/WEB-INF/view/productionplanning/mBomViewPopup.jsp
Normal file
183
WebContent/WEB-INF/view/productionplanning/mBomViewPopup.jsp
Normal file
@@ -0,0 +1,183 @@
|
||||
<%@ 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>
|
||||
<style>
|
||||
body, html {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
.header {
|
||||
padding: 15px 20px;
|
||||
background: #f5f5f5;
|
||||
border-bottom: 2px solid #ddd;
|
||||
}
|
||||
.header h3 {
|
||||
margin: 0 0 10px 0;
|
||||
color: #333;
|
||||
}
|
||||
.info-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.info-table td {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.info-table label {
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.content {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
overflow: auto;
|
||||
}
|
||||
.tree-container {
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
min-height: 400px;
|
||||
}
|
||||
.tree-node {
|
||||
padding: 5px 0;
|
||||
cursor: default;
|
||||
}
|
||||
.tree-node-content {
|
||||
padding: 5px 10px;
|
||||
display: inline-block;
|
||||
}
|
||||
.tree-node-content:hover {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.tree-children {
|
||||
margin-left: 30px;
|
||||
}
|
||||
.footer {
|
||||
padding: 15px 20px;
|
||||
background: #f5f5f5;
|
||||
border-top: 1px solid #ddd;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.12/themes/default/style.min.css" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jstree/3.3.12/jstree.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h3>M-BOM 조회</h3>
|
||||
<table class="info-table">
|
||||
<tr>
|
||||
<td>
|
||||
<label>프로젝트 번호:</label>
|
||||
<span id="projectNo">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<label>품번:</label>
|
||||
<span id="partNo">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<label>품명:</label>
|
||||
<span id="partName">-</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div id="mbomTree" class="tree-container"></div>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<input type="button" value="닫기" class="plm_btns" onclick="window.close();">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var objId = "${param.objId}";
|
||||
|
||||
$(document).ready(function(){
|
||||
loadProjectInfo();
|
||||
loadMBomTree();
|
||||
});
|
||||
|
||||
// 프로젝트 정보 로드
|
||||
function loadProjectInfo() {
|
||||
$.ajax({
|
||||
url: "/productionplanning/getMBomHeaderInfo.do",
|
||||
method: 'post',
|
||||
data: { objId: objId },
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data && data.info) {
|
||||
$("#projectNo").text(data.info.PROJECT_NO || '-');
|
||||
$("#partNo").text(data.info.PART_NO || '-');
|
||||
$("#partName").text(data.info.PART_NAME || '-');
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("프로젝트 정보 로드 오류:", error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// M-BOM 트리 로드
|
||||
function loadMBomTree() {
|
||||
$.ajax({
|
||||
url: "/productionplanning/getMBomTree.do",
|
||||
method: 'post',
|
||||
data: { objId: objId },
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
if(data && data.tree) {
|
||||
initTree(data.tree);
|
||||
} else {
|
||||
$("#mbomTree").html('<p style="padding: 20px; text-align: center; color: #999;">저장된 M-BOM이 없습니다.</p>');
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error("M-BOM 트리 로드 오류:", error);
|
||||
$("#mbomTree").html('<p style="padding: 20px; text-align: center; color: #f00;">데이터 로드 중 오류가 발생했습니다.</p>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// jsTree 초기화
|
||||
function initTree(treeData) {
|
||||
$('#mbomTree').jstree({
|
||||
'core': {
|
||||
'data': treeData,
|
||||
'check_callback': false,
|
||||
'themes': {
|
||||
'responsive': true
|
||||
}
|
||||
},
|
||||
'plugins': ['types'],
|
||||
'types': {
|
||||
'default': {
|
||||
'icon': 'fa fa-folder'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 트리 로드 완료 후 모두 펼치기
|
||||
$('#mbomTree').on('ready.jstree', function() {
|
||||
$('#mbomTree').jstree('open_all');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user