E-BOM 확인/수정쪽 속도개선
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
<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.min.js"></script>
|
||||
<script type="text/javascript" src="/js/tabulator/tabulator.min.js"></script>
|
||||
<style>
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
@@ -103,10 +103,8 @@ $(function(){
|
||||
// Tabulator 초기화
|
||||
fn_initRightGrid();
|
||||
|
||||
// 초기 로드 시 자동으로 파트 데이터 조회
|
||||
if($("#bomReportObjId").val()) {
|
||||
fn_searchPart();
|
||||
}
|
||||
// 초기 로드 제거 - 검색 버튼 클릭 시에만 데이터 로드
|
||||
// 사용자가 검색 조건 입력 후 조회하도록 유도
|
||||
});
|
||||
|
||||
var _rightGrid;
|
||||
@@ -163,38 +161,74 @@ function fn_initRightGrid(){
|
||||
height: "600px",
|
||||
pagination: false,
|
||||
columns: columns,
|
||||
placeholder: "조회된 부품이 없습니다.",
|
||||
data: []
|
||||
placeholder: "검색 버튼을 클릭하여 품목을 조회하세요"
|
||||
});
|
||||
}
|
||||
|
||||
function fn_searchPart(){
|
||||
// 전체 품목 데이터 조회 (검색 조건 적용)
|
||||
$.ajax({
|
||||
url: "/partMng/getPartMngList_ajax.do",
|
||||
method: 'post',
|
||||
data: $("#form1").serialize(),
|
||||
dataType: 'json',
|
||||
beforeSend: function(){
|
||||
// 로딩 스피너 표시
|
||||
_startLoading("파트 목록 조회 중...");
|
||||
},
|
||||
complete: function(){
|
||||
// 로딩 스피너 숨김 (성공/실패 관계없이 항상 실행)
|
||||
_endLoading();
|
||||
},
|
||||
success: function(data) {
|
||||
console.log('조회 성공:', data.length + '건');
|
||||
|
||||
// Tabulator에 데이터 설정
|
||||
if(_rightGrid){
|
||||
_rightGrid.setData(data);
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
console.error('Ajax 에러:', status, error);
|
||||
Swal.fire('조회 중 오류가 발생했습니다.');
|
||||
}
|
||||
});
|
||||
url: "/partMng/getPartMngList_ajax.do",
|
||||
type: "POST",
|
||||
data: $("#form1").serialize(),
|
||||
dataType: "json",
|
||||
beforeSend: function(){
|
||||
// 로딩 스피너 표시
|
||||
Swal.fire({
|
||||
title: '조회 중...',
|
||||
html: '품목 데이터를 불러오는 중입니다.',
|
||||
allowOutsideClick: false,
|
||||
didOpen: () => {
|
||||
Swal.showLoading();
|
||||
}
|
||||
});
|
||||
|
||||
if(_rightGrid){
|
||||
_rightGrid.clearData();
|
||||
}
|
||||
},
|
||||
success: function(response) {
|
||||
// 로딩 스피너 닫기
|
||||
Swal.close();
|
||||
|
||||
console.log('조회 완료:', response.data ? response.data.length + '건' : '0건');
|
||||
|
||||
// Tabulator에 데이터 설정
|
||||
if(_rightGrid){
|
||||
_rightGrid.setData(response.data || []);
|
||||
}
|
||||
|
||||
// 결과 메시지
|
||||
if(!response.data || response.data.length === 0){
|
||||
Swal.fire({
|
||||
icon: 'info',
|
||||
title: '조회 결과 없음',
|
||||
text: '검색 조건에 맞는 품목이 없습니다.'
|
||||
});
|
||||
} else {
|
||||
// 성공 토스트 메시지
|
||||
Swal.fire({
|
||||
toast: true,
|
||||
position: 'top-end',
|
||||
icon: 'success',
|
||||
title: response.data.length + '건 조회 완료',
|
||||
showConfirmButton: false,
|
||||
timer: 2000
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function(jqxhr, status, error){
|
||||
// 로딩 스피너 닫기
|
||||
Swal.close();
|
||||
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: '조회 실패',
|
||||
text: '데이터 조회 중 오류가 발생했습니다.'
|
||||
});
|
||||
console.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -609,19 +609,30 @@ public class PartMngController {
|
||||
* @param paramMap
|
||||
* @return
|
||||
*/
|
||||
/**
|
||||
* PART 목록 조회 (전체 데이터 조회 - 재귀 CTE 제거로 성능 개선)
|
||||
* @param request
|
||||
* @param paramMap
|
||||
* @return JSON 형태의 전체 데이터
|
||||
*/
|
||||
@RequestMapping("/partMng/getPartMngList_ajax.do")
|
||||
public String getPartList_ajax(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
@ResponseBody
|
||||
public Map<String, Object> getPartList_ajax(HttpServletRequest request, @RequestParam Map<String, Object> paramMap){
|
||||
paramMap.put("status", "complete");
|
||||
|
||||
System.out.println("getPArtList_ajax paramMap : "+paramMap);
|
||||
paramMap.put("IS_LAST","1");
|
||||
//paramMap.put("STATUS", "release");
|
||||
|
||||
System.out.println("getPartList_ajax paramMap : "+paramMap);
|
||||
|
||||
// 전체 데이터 조회 (페이징 제거, 재귀 CTE 제거로 속도 대폭 향상)
|
||||
List list = partMngService.getToConnectPartMngList(request, paramMap);
|
||||
|
||||
// Gson을 사용하여 안전하게 JSON 변환 (특수문자, 이스케이프 처리 자동)
|
||||
String jsonResult = JsonUtil.ListToJson(list);
|
||||
request.setAttribute("RESULT", jsonResult);
|
||||
return "/ajax/ajaxResult";
|
||||
// 응답 데이터 구성
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("data", list);
|
||||
|
||||
System.out.println("데이터 조회 완료 - " + list.size() + "건");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -266,8 +266,22 @@
|
||||
<!-- Part 관리 기본 조회 -->
|
||||
<sql id="partMngBase">
|
||||
(
|
||||
WITH V_FILE AS (
|
||||
SELECT
|
||||
-- 파일 개수 집계 (성능 최적화)
|
||||
WITH V_FILE_COUNTS AS (
|
||||
SELECT
|
||||
TARGET_OBJID,
|
||||
COUNT(CASE WHEN DOC_TYPE = '3D_CAD' THEN 1 END) AS CU01_CNT,
|
||||
COUNT(CASE WHEN DOC_TYPE = '2D_DRAWING_CAD' THEN 1 END) AS CU02_CNT,
|
||||
COUNT(CASE WHEN DOC_TYPE = '2D_PDF_CAD' THEN 1 END) AS CU03_CNT,
|
||||
COUNT(CASE WHEN DOC_TYPE IN ('2D_PDF_CAD', '2D_DRAWING_CAD') THEN 1 END) AS CU_TOTAL_CNT,
|
||||
COUNT(CASE WHEN DOC_TYPE = 'ECD_DOC' THEN 1 END) AS ECD_CNT
|
||||
FROM ATTACH_FILE_INFO
|
||||
WHERE STATUS = 'Active'
|
||||
AND DOC_TYPE IN ('PART_SHAPE_IMG','ECD_DOC','3D_CAD','2D_DRAWING_CAD','2D_PDF_CAD')
|
||||
GROUP BY TARGET_OBJID
|
||||
),
|
||||
V_FILE AS (
|
||||
SELECT DISTINCT ON (TARGET_OBJID, DOC_TYPE)
|
||||
TARGET_OBJID
|
||||
, SAVED_FILE_NAME
|
||||
, REAL_FILE_NAME
|
||||
@@ -276,8 +290,9 @@
|
||||
, STATUS
|
||||
FROM ATTACH_FILE_INFO
|
||||
WHERE 1 = 1
|
||||
AND DOC_TYPE IN ('PART_SHAPE_IMG','ECD_DOC','3D_CAD','2D_DRAWING_CAD','2D_PDF_CAD')
|
||||
AND DOC_TYPE IN ('PART_SHAPE_IMG','ECD_DOC')
|
||||
AND STATUS = 'Active'
|
||||
ORDER BY TARGET_OBJID, DOC_TYPE, OBJID
|
||||
)
|
||||
|
||||
SELECT DISTINCT
|
||||
@@ -327,31 +342,17 @@
|
||||
P.SOURCING_CODE,
|
||||
CC_SOURCING.CODE_NAME AS SOURCING_NAME,
|
||||
|
||||
AF.SAVED_FILE_NAME,
|
||||
AF.REAL_FILE_NAME,
|
||||
REPLACE(AF.FILE_PATH, '\', '\\') AS FILE_PATH,
|
||||
case when CAD.SAVED_FILE_NAME is NOT NULL
|
||||
then 1
|
||||
else 0 end as CU01_CNT,
|
||||
|
||||
case when DRAWING.SAVED_FILE_NAME is NOT NULL
|
||||
then 1
|
||||
else 0 end as CU02_CNT,
|
||||
|
||||
case when PDF.SAVED_FILE_NAME is NOT NULL
|
||||
then 1
|
||||
else 0 end as CU03_CNT,
|
||||
|
||||
case when PDFDRA.SAVED_FILE_NAME is NOT NULL
|
||||
then 1
|
||||
else 0 end as CU_TOTAL_CNT,
|
||||
AF_IMG.SAVED_FILE_NAME,
|
||||
AF_IMG.REAL_FILE_NAME,
|
||||
REPLACE(AF_IMG.FILE_PATH, '\', '\\') AS FILE_PATH,
|
||||
COALESCE(FC.CU01_CNT, 0) AS CU01_CNT,
|
||||
COALESCE(FC.CU02_CNT, 0) AS CU02_CNT,
|
||||
COALESCE(FC.CU03_CNT, 0) AS CU03_CNT,
|
||||
COALESCE(FC.CU_TOTAL_CNT, 0) AS CU_TOTAL_CNT,
|
||||
AF_ECD.SAVED_FILE_NAME AS ECD_SAVED_FILE_NAME,
|
||||
AF_ECD.REAL_FILE_NAME AS ECD_REAL_FILE_NAME,
|
||||
REPLACE(AF_ECD.FILE_PATH, '\', '\\') AS ECD_FILE_PATH,
|
||||
CASE
|
||||
WHEN AF_ECD.SAVED_FILE_NAME IS NOT NULL THEN 'Y'
|
||||
ELSE 'N'
|
||||
END ECD_FLAG,
|
||||
CASE WHEN FC.ECD_CNT > 0 THEN 'Y' ELSE 'N' END AS ECD_FLAG,
|
||||
THICKNESS,
|
||||
WIDTH,
|
||||
HEIGHT,
|
||||
@@ -367,43 +368,15 @@
|
||||
LEFT JOIN COMM_CODE CC_DESIGN ON CC_DESIGN.CODE_ID = P.DESIGN_APPLY_POINT
|
||||
LEFT JOIN COMM_CODE CC_SOURCING ON CC_SOURCING.CODE_ID = P.SOURCING_CODE
|
||||
LEFT JOIN admin_supply_mng SUP ON SUP.objid::varchar = P.SUPPLY_CODE
|
||||
|
||||
LEFT OUTER JOIN V_FILE AF
|
||||
ON P.OBJID = AF.TARGET_OBJID
|
||||
AND AF.DOC_TYPE IN ('PART_SHAPE_IMG')
|
||||
<!--
|
||||
AND AF.STATUS = 'Active'
|
||||
-->
|
||||
-- 파일 개수 집계 조인 (한 번만)
|
||||
LEFT JOIN V_FILE_COUNTS FC ON P.OBJID = FC.TARGET_OBJID
|
||||
-- 파일 정보 조인 (첫 번째만)
|
||||
LEFT OUTER JOIN V_FILE AF_IMG
|
||||
ON P.OBJID = AF_IMG.TARGET_OBJID
|
||||
AND AF_IMG.DOC_TYPE = 'PART_SHAPE_IMG'
|
||||
LEFT OUTER JOIN V_FILE AF_ECD
|
||||
ON P.OBJID = AF_ECD.TARGET_OBJID
|
||||
AND AF_ECD.DOC_TYPE IN ('ECD_DOC')
|
||||
<!--
|
||||
AND AF_ECD.STATUS = 'Active'
|
||||
-->
|
||||
LEFT OUTER JOIN V_FILE CAD
|
||||
ON P.OBJID = CAD.TARGET_OBJID
|
||||
AND CAD.DOC_TYPE IN ('3D_CAD')
|
||||
<!--
|
||||
AND CAD.STATUS = 'Active'
|
||||
-->
|
||||
LEFT OUTER JOIN V_FILE DRAWING
|
||||
ON P.OBJID = DRAWING.TARGET_OBJID
|
||||
AND DRAWING.DOC_TYPE IN ('2D_DRAWING_CAD')
|
||||
<!--
|
||||
AND DRAWING.STATUS = 'Active'
|
||||
-->
|
||||
LEFT OUTER JOIN V_FILE PDF
|
||||
ON P.OBJID = PDF.TARGET_OBJID
|
||||
AND PDF.DOC_TYPE IN ('2D_PDF_CAD')
|
||||
<!--
|
||||
AND PDF.STATUS = 'Active'
|
||||
-->
|
||||
LEFT OUTER JOIN V_FILE PDFDRA
|
||||
ON P.OBJID = PDFDRA.TARGET_OBJID
|
||||
AND PDFDRA.DOC_TYPE IN ('2D_PDF_CAD', '2D_DRAWING_CAD')
|
||||
<!--
|
||||
AND PDFDRA.STATUS = 'Active'
|
||||
-->
|
||||
AND AF_ECD.DOC_TYPE = 'ECD_DOC'
|
||||
|
||||
<!--
|
||||
LEFT OUTER JOIN
|
||||
@@ -2467,69 +2440,17 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
)A WHERE 1=1
|
||||
</select> -->
|
||||
|
||||
<!-- PART 관리 목록 조회 -->
|
||||
<!-- PART 관리 목록 조회 (전체 데이터, 재귀 CTE 제거로 성능 개선) -->
|
||||
<select id="getToConnectPartMngList" parameterType="map" resultType="map">
|
||||
WITH RECURSIVE VIEW_BOM(
|
||||
OBJID,
|
||||
PART_NO,
|
||||
BOM_REPORT_OBJID,
|
||||
PARENT_PART_NO,
|
||||
QTY,
|
||||
LEV,
|
||||
PATH,
|
||||
CYCLE
|
||||
) AS (
|
||||
SELECT
|
||||
A.OBJID,
|
||||
A.PART_NO,
|
||||
A.BOM_REPORT_OBJID,
|
||||
A.PARENT_PART_NO,
|
||||
A.QTY,
|
||||
1,
|
||||
ARRAY [A.PART_NO],
|
||||
FALSE
|
||||
FROM
|
||||
PART_BOM_QTY A
|
||||
WHERE 1=1
|
||||
AND (A.PARENT_PART_NO IS NULL OR A.PARENT_PART_NO = '')
|
||||
AND A.BOM_REPORT_OBJID = #{bomReportObjId}::NUMERIC
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
B.OBJID,
|
||||
B.PART_NO,
|
||||
B.BOM_REPORT_OBJID,
|
||||
B.PARENT_PART_NO,
|
||||
B.QTY,
|
||||
LEV + 1,
|
||||
PATH,
|
||||
B.PARENT_PART_NO = ANY(PATH)
|
||||
FROM
|
||||
PART_BOM_QTY B
|
||||
JOIN
|
||||
VIEW_BOM
|
||||
ON B.PARENT_PART_NO = VIEW_BOM.PART_NO
|
||||
AND VIEW_BOM.BOM_REPORT_OBJID = B.BOM_REPORT_OBJID
|
||||
)
|
||||
SELECT
|
||||
T.*,
|
||||
ROW_NUMBER() OVER(ORDER BY EXCEL_UPLOAD_SEQ ASC) RNUM
|
||||
ROW_NUMBER() OVER(ORDER BY EXCEL_UPLOAD_SEQ ASC, PART_NO ASC) RNUM
|
||||
FROM(
|
||||
SELECT
|
||||
T.*
|
||||
FROM
|
||||
<include refid="partMngBase"/> T
|
||||
WHERE 1=1
|
||||
<!-- AND IS_LAST = '1' -->
|
||||
<!-- AND NOT EXISTS
|
||||
(
|
||||
SELECT
|
||||
1
|
||||
FROM VIEW_BOM V
|
||||
WHERE 1=1
|
||||
AND V.PART_NO = T.PART_NO
|
||||
) -->
|
||||
<!-- EO 기능 말들고 추가 필요 -->
|
||||
<if test="search_eo != null and search_eo != ''">
|
||||
AND UPPER(EO_NO) LIKE UPPER('%${search_eo}%')
|
||||
@@ -2582,7 +2503,113 @@ SELECT T1.LEV, T1.BOM_REPORT_OBJID, T1.ROOT_PART_NO, T1.PATH, T1.LEAF, T2.*
|
||||
AND UPG_NO = #{search_product_mgmt_upg}
|
||||
</if>
|
||||
|
||||
ORDER BY PART_NO
|
||||
ORDER BY EXCEL_UPLOAD_SEQ ASC, PART_NO ASC
|
||||
) T
|
||||
</select>
|
||||
|
||||
<!-- PART 관리 목록 총 개수 조회 (페이징용) -->
|
||||
<select id="getToConnectPartMngListCount" parameterType="map" resultType="int">
|
||||
WITH RECURSIVE VIEW_BOM(
|
||||
OBJID,
|
||||
PART_NO,
|
||||
BOM_REPORT_OBJID,
|
||||
PARENT_PART_NO,
|
||||
QTY,
|
||||
LEV,
|
||||
PATH,
|
||||
CYCLE
|
||||
) AS (
|
||||
SELECT
|
||||
A.OBJID,
|
||||
A.PART_NO,
|
||||
A.BOM_REPORT_OBJID,
|
||||
A.PARENT_PART_NO,
|
||||
A.QTY,
|
||||
1,
|
||||
ARRAY [A.PART_NO],
|
||||
FALSE
|
||||
FROM
|
||||
PART_BOM_QTY A
|
||||
WHERE 1=1
|
||||
AND (A.PARENT_PART_NO IS NULL OR A.PARENT_PART_NO = '')
|
||||
AND A.BOM_REPORT_OBJID = #{bomReportObjId}::NUMERIC
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
B.OBJID,
|
||||
B.PART_NO,
|
||||
B.BOM_REPORT_OBJID,
|
||||
B.PARENT_PART_NO,
|
||||
B.QTY,
|
||||
LEV + 1,
|
||||
PATH,
|
||||
B.PARENT_PART_NO = ANY(PATH)
|
||||
FROM
|
||||
PART_BOM_QTY B
|
||||
JOIN
|
||||
VIEW_BOM
|
||||
ON B.PARENT_PART_NO = VIEW_BOM.PART_NO
|
||||
AND VIEW_BOM.BOM_REPORT_OBJID = B.BOM_REPORT_OBJID
|
||||
)
|
||||
SELECT
|
||||
COUNT(*)
|
||||
FROM(
|
||||
SELECT
|
||||
T.OBJID
|
||||
FROM
|
||||
<include refid="partMngBase"/> T
|
||||
WHERE 1=1
|
||||
<if test="search_eo != null and search_eo != ''">
|
||||
AND UPPER(EO_NO) LIKE UPPER('%${search_eo}%')
|
||||
</if>
|
||||
<if test="search_except_eo != null and search_except_eo != ''">
|
||||
AND EO != #{search_except_eo}
|
||||
AND (EO IS NULL OR EO = '' OR EO = '0')
|
||||
</if>
|
||||
<if test="search_eo_date_from != null and search_eo_date_from != ''">
|
||||
AND EO_DATE <![CDATA[ >= ]]> #{search_eo_date_from}::TIMESTAMP
|
||||
</if>
|
||||
<if test="search_eo_date_to != null and search_eo_date_to != ''">
|
||||
AND EO_DATE <![CDATA[ <= ]]> #{search_eo_date_to}::TIMESTAMP
|
||||
</if>
|
||||
<if test="search_product_mgmt_objid != null and search_product_mgmt_objid != ''">
|
||||
AND PRODUCT_MGMT_OBJID = #{search_product_mgmt_objid}
|
||||
</if>
|
||||
<if test="search_part_no != null and search_part_no != ''">
|
||||
AND UPPER(PART_NO) LIKE UPPER('%${search_part_no}%')
|
||||
</if>
|
||||
<if test="search_part_name != null and search_part_name != ''">
|
||||
AND UPPER(PART_NAME) LIKE UPPER('%${search_part_name}%')
|
||||
</if>
|
||||
<if test="search_spec != null and search_spec != ''">
|
||||
AND UPPER(SPEC) LIKE UPPER('%${search_spec}%')
|
||||
</if>
|
||||
<if test="search_maker != null and search_maker != ''">
|
||||
AND UPPER(MAKER) LIKE UPPER('%${search_maker}%')
|
||||
</if>
|
||||
<if test="search_writer != null and search_writer != ''">
|
||||
AND WRITER = #{search_writer}
|
||||
</if>
|
||||
<if test="IS_LAST != null and IS_LAST != ''">
|
||||
AND IS_LAST = #{IS_LAST}
|
||||
</if>
|
||||
<if test="STATUS != null and STATUS != ''">
|
||||
AND STATUS = #{STATUS}
|
||||
</if>
|
||||
<if test="searchTargetStatus != null and searchTargetStatus != '' and 'create'.equals(searchTargetStatus)">
|
||||
AND STATUS = 'create'
|
||||
</if>
|
||||
<if test="searchTargetStatus != null and searchTargetStatus != '' and 'deploy'.equals(searchTargetStatus)">
|
||||
AND STATUS = 'release'
|
||||
</if>
|
||||
<if test="searchTargetStatus != null and searchTargetStatus != '' and 'changeDesign'.equals(searchTargetStatus)">
|
||||
AND STATUS = 'release'
|
||||
</if>
|
||||
|
||||
<if test="search_product_mgmt_upg != null and !''.equals(search_product_mgmt_upg)">
|
||||
AND UPG_NO = #{search_product_mgmt_upg}
|
||||
</if>
|
||||
) T
|
||||
</select>
|
||||
|
||||
|
||||
@@ -1538,6 +1538,28 @@ public class PartMngService extends BaseService {
|
||||
return CommonUtils.toUpperCaseMapKey(resultList);
|
||||
}
|
||||
|
||||
/**
|
||||
* PART 목록 총 개수 조회 (페이징용)
|
||||
*/
|
||||
public int getToConnectPartMngListCount(HttpServletRequest request, Map paramMap){
|
||||
int totalCount = 0;
|
||||
SqlSession sqlSession = null;
|
||||
try{
|
||||
sqlSession = SqlMapConfig.getInstance().getSqlSession();
|
||||
|
||||
setPartMngCommonCD(paramMap);
|
||||
|
||||
totalCount = (Integer)sqlSession.selectOne("partMng.getToConnectPartMngListCount", paramMap);
|
||||
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
}finally{
|
||||
sqlSession.close();
|
||||
}
|
||||
|
||||
return totalCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user