이호영 이호영 2024-08-14
문자전송 엑셀기능 작업중
@a985ce5d6d3c26d835bf457ce96a4fadc2fcfe4c
src/main/java/itn/let/mjo/addr/service/AddrVO.java
--- src/main/java/itn/let/mjo/addr/service/AddrVO.java
+++ src/main/java/itn/let/mjo/addr/service/AddrVO.java
@@ -360,6 +360,57 @@
 	}
 
 
+	
+	private String addrGroupNm;
+	private String addrPhone;
+	private String addrName;
+	private String addrRep1;
+	private String addrRep2;
+	private String addrRep3;
+	private String addrRep4;
+	public String getAddrGroupNm() {
+		return addrGroupNm;
+	}
+	public void setAddrGroupNm(String addrGroupNm) {
+		this.addrGroupNm = addrGroupNm;
+	}
+	public String getAddrPhone() {
+		return addrPhone;
+	}
+	public void setAddrPhone(String addrPhone) {
+		this.addrPhone = addrPhone;
+	}
+	public String getAddrName() {
+		return addrName;
+	}
+	public void setAddrName(String addrName) {
+		this.addrName = addrName;
+	}
+	public String getAddrRep1() {
+		return addrRep1;
+	}
+	public void setAddrRep1(String addrRep1) {
+		this.addrRep1 = addrRep1;
+	}
+	public String getAddrRep2() {
+		return addrRep2;
+	}
+	public void setAddrRep2(String addrRep2) {
+		this.addrRep2 = addrRep2;
+	}
+	public String getAddrRep3() {
+		return addrRep3;
+	}
+	public void setAddrRep3(String addrRep3) {
+		this.addrRep3 = addrRep3;
+	}
+	public String getAddrRep4() {
+		return addrRep4;
+	}
+	public void setAddrRep4(String addrRep4) {
+		this.addrRep4 = addrRep4;
+	}
 
 
+	
 }
src/main/java/itn/let/mjo/msgdata/service/MjonMsgDataService.java
--- src/main/java/itn/let/mjo/msgdata/service/MjonMsgDataService.java
+++ src/main/java/itn/let/mjo/msgdata/service/MjonMsgDataService.java
@@ -172,5 +172,7 @@
 	
 	//대용량 문자 전송시 사용자 마지막 PK 값 조회하기
 	public String selectMsgUserLastIdgen(MjonMsgVO mjonMsgVO) throws Exception;
+
+	public List<AddrVO> selectMsgAddrListAjax_advc(AddrVO addrVO) throws Exception;
 	
 }
src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataDAO.java
--- src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataDAO.java
+++ src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataDAO.java
@@ -350,5 +350,10 @@
 	public String selectMsgUserLastIdgen(MjonMsgVO mjonMsgVO) throws Exception{
 		return (String) select("mjonMsgDAO.selectMsgUserLastIdgen", mjonMsgVO);
 	}
+
+
+	public List<AddrVO> selectMsgAddrListAjax_advc(AddrVO addrVO) {
+		return (List<AddrVO>) list("mjonMsgDAO.selectMsgAddrListAjax_advc", addrVO);
+	}
 	
 }
src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataServiceImpl.java
--- src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataServiceImpl.java
+++ src/main/java/itn/let/mjo/msgdata/service/impl/MjonMsgDataServiceImpl.java
@@ -3050,6 +3050,12 @@
 	public String selectMsgUserLastIdgen(MjonMsgVO mjonMsgVO) throws Exception{
 		return mjonMsgDataDAO.selectMsgUserLastIdgen(mjonMsgVO);
 	}
+
+	@Override
+	public List<AddrVO> selectMsgAddrListAjax_advc(AddrVO addrVO) throws Exception {
+		
+		return mjonMsgDataDAO.selectMsgAddrListAjax_advc(addrVO);
+	}
 	
 	
 }
src/main/java/itn/let/mjo/msgdata/web/MjonMsgDataController.java
--- src/main/java/itn/let/mjo/msgdata/web/MjonMsgDataController.java
+++ src/main/java/itn/let/mjo/msgdata/web/MjonMsgDataController.java
@@ -1756,8 +1756,18 @@
 		    	return modelAndView;
 	    		
 	    	}
-	    	
-	    	List<AddrVO> resultAddrList = mjonMsgDataService.selectMsgAddrListAjax(addrVO);
+
+	        long startTime = System.currentTimeMillis(); // 시작 시간 측정
+	        
+//	    	List<AddrVO> resultAddrList = mjonMsgDataService.selectMsgAddrListAjax(addrVO);
+	    	List<AddrVO> resultAddrList = mjonMsgDataService.selectMsgAddrListAjax_advc(addrVO);
+
+	        long endTime = System.currentTimeMillis(); // 종료 시간 측정
+
+	        long elapsedTime = endTime - startTime; // 소요 시간 계산
+	        System.out.println("소요 시간: " + elapsedTime + " 밀리초");
+	        
+	        
 	    	
 	    	modelAndView.addObject("resultAddrList", resultAddrList);
 	    	modelAndView.addObject("result", "success");
src/main/resources/egovframework/sqlmap/let/msg/MjonMsgData_SQL_mysql.xml
--- src/main/resources/egovframework/sqlmap/let/msg/MjonMsgData_SQL_mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/msg/MjonMsgData_SQL_mysql.xml
@@ -3708,6 +3708,64 @@
 	
 	</select>
 	
+	<!-- 등록 주소록 그룹 선택시 리스트 불러오기 -->
+	<select id="mjonMsgDAO.selectMsgAddrListAjax_advc" parameterClass="addrVO" resultClass="addrVO">
+		
+		SELECT   A.ADDR_ID AS addrId,
+		         A.ADDR_GRP_ID AS addrGrpId,
+		         A.MBER_ID AS mberId,
+		         A.ADDR_NM AS addrName,
+		         A.ADDR_PHONE_NO AS addrPhone,
+		         A.ADDR_INFO1 AS addrRep1,
+		         A.ADDR_INFO2 AS addrRep2,
+		         A.ADDR_INFO3 AS addrRep3,
+		         A.ADDR_INFO4 AS addrRep4,
+		         A.DELETE_YN AS deleteYn,
+		         A.BOOKMARK AS bookmark,
+		         IFNULL(B.ADDR_GRP_NM,'그룹미지정') AS addrGroupNm
+		FROM     MJ_ADDR A
+		LEFT OUTER JOIN 
+			MJ_ADDR_GRP B
+		ON 
+			A.ADDR_GRP_ID = B.ADDR_GRP_ID
+		WHERE    A.MBER_ID = #mberId#
+		AND	(A.RECV_STATUS = 'Y' OR A.RECV_STATUS = 'S' OR A.RECV_STATUS IS NULL)
+		AND      A.DELETE_YN = 'N'
+		<isNotEmpty property="type">
+			<isEqual property="type" compareValue="none">
+				AND		A.ADDR_GRP_ID = '0' 
+				AND 	A.BOOKMARK = 'N'
+			</isEqual>
+			<isEqual property="type" compareValue="book">
+				AND		A.BOOKMARK = 'Y' 
+			</isEqual>
+			<isEqual property="type" compareValue="grp">
+				AND		A.ADDR_GRP_ID = #searchAddrGrpId#
+			</isEqual>
+		</isNotEmpty>
+		<isNotEmpty property="searchCondition">
+			<isEqual property="searchCondition" compareValue="0">
+				AND		
+				( 
+					A.ADDR_NM LIKE CONCAT('%', #searchKeyword#, '%') 
+					OR A.ADDR_PHONE_NO LIKE CONCAT('%', #searchKeyword#, '%')
+					OR B.ADDR_GRP_NM LIKE CONCAT('%', #searchKeyword#, '%') 
+				)
+			</isEqual>
+			<isEqual property="searchCondition" compareValue="1">
+				AND		B.ADDR_GRP_NM LIKE CONCAT('%', #searchKeyword#, '%')
+			</isEqual>
+			<isEqual property="searchCondition" compareValue="2">
+				AND		A.ADDR_NM LIKE CONCAT('%', #searchKeyword#, '%')
+			</isEqual>
+			<isEqual property="searchCondition" compareValue="3">
+				AND		A.ADDR_PHONE_NO LIKE CONCAT('%', #searchKeyword#, '%')
+			</isEqual>
+		</isNotEmpty>
+		ORDER BY A.ADDR_NM ASC, A.LAST_UPDT_PNTTM DESC
+	
+	</select>
+	
 	<select id="MjonMsgDataDAO.selectMsgAddInfoAjax" parameterClass="mjonMsgDataVO" resultClass="mjonMsgDataVO">
 		
 		SELECT MSG_ID AS msgId,
src/main/webapp/WEB-INF/jsp/web/addr/AddrList.jsp
--- src/main/webapp/WEB-INF/jsp/web/addr/AddrList.jsp
+++ src/main/webapp/WEB-INF/jsp/web/addr/AddrList.jsp
@@ -333,7 +333,6 @@
 		setSenderList_advc();
 	}
 }
-/* 
 function setSenderList_advc(){
 
 	// tab에 해당하는 타블레이터 가져오기
@@ -386,10 +385,9 @@
 		}
 	});
 }
- */
  
  
- 
+ /* 
 function setSenderList_advc(){
     var $objTabul = fn_utils_getTabulator();
     var dataToSend = $objTabul.getData();
@@ -455,7 +453,7 @@
     $('.loading_layer').removeClass('active');
 }
 
- 
+  */
  
 //주소록그룹 콤보박스 유지
 function setSelectMassSetting(selectMassVal) {
@@ -631,6 +629,7 @@
 	getAddrGroupList();
 }
 
+
 </script>
 
 <div class="loading_layer">
@@ -657,36 +656,32 @@
 		<div class="tooltip-wrap" id="addrMassLoad">
 			<div class="popup-com adr_layer adr_popup01" tabindex="0" data-tooltip-con="adr_popup01" data-focus="adr_popup01" data-focus-prev="adr_popup01-close" style="width: 1000px;">
 				<div class="popup_heading">
-					   <p>주소록 대량등록</p>
-					   <button type="button" class="tooltip-close" data-focus="adr_popup01-close" onclick="setAddrMassClose();"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+					<p>주소록 대량등록</p>
+					<button type="button" class="tooltip-close" data-focus="adr_popup01-close" onclick="setAddrMassClose();"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+			   </div>
+				<div class="layer_in" style="padding: 25px 30px;">
+				   <div class="list_tab_wrap2">
+					   <!-- tab button -->
+					   <ul class="list_tab" id="tbTabl"> 
+						   <li class="tab active" data-tabul="tableExcel"><button type="button" onclick="popupTab(this,'1'); fn_tabToggle('1');">엑셀입력</button></li>
+						   <li class="tab" data-tabul="tableClip"><button type="button" onclick="popupTab(this,'2'); fn_tabToggle('2');">붙여넣기</button></li>
+						   <li class="tab" data-tabul="tableSelf"><button type="button" onclick="popupTab(this,'3'); fn_tabToggle('3');">직접입력</button></li>
+					   </ul><!--// tab button -->
 				   </div>
-				   <div class="layer_in" style="padding: 25px 30px;">
-					   <div class="list_tab_wrap2">
-						   <!-- tab button -->
-						   <ul class="list_tab" id="tbTabl"> 
-							   <li class="tab active" data-tabul="tableExcel"><button type="button" onclick="popupTab(this,'1'); fn_tabToggle('1');">엑셀입력</button></li>
-							   <li class="tab" data-tabul="tableClip"><button type="button" onclick="popupTab(this,'2'); fn_tabToggle('2');">붙여넣기</button></li>
-							   <li class="tab" data-tabul="tableSelf"><button type="button" onclick="popupTab(this,'3'); fn_tabToggle('3');">직접입력</button></li>
-						   </ul><!--// tab button -->
-					   </div>
-					   
-					   
-						<div id="tab1" class="tab_c tableExcel">
-					  		<%@include file="/WEB-INF/jsp/web/addr/include/addrListforExcel.jsp" %>
-						</div>
-						<div id="tab2" class="tab_c tableClip" style="display: none;">
-					  		<%@include file="/WEB-INF/jsp/web/addr/include/addrListforClipboard.jsp" %>
-						</div>
-<!-- 						<div id="tab3" class="tab_c" style="display: none;"> -->
-						<div id="tab3" class="tab_c tableSelf" style="display: none;">
-					  		<%@include file="/WEB-INF/jsp/web/addr/include/addrListforSelf.jsp" %>
-						</div>
-						   
-					   <div class="popup_btn_wrap2" style="margin: 0 auto 30px auto;">
-						   <button type="button" id="btnAddrMassReg">등록</button>
-						   <button type="button" id="btnAddrMassClose" class="tooltip-close" data-focus="adr_popup01-close"  data-focus-next="popup02">닫기</button>                      
-					   </div>
-				   	
+					<div id="tab1" class="tab_c tableExcel">
+				  		<%@include file="/WEB-INF/jsp/web/addr/include/addrListforExcel.jsp" %>
+					</div>
+					<div id="tab2" class="tab_c tableClip" style="display: none;">
+				  		<%@include file="/WEB-INF/jsp/web/addr/include/addrListforClipboard.jsp" %>
+					</div>
+					<div id="tab3" class="tab_c tableSelf" style="display: none;">
+				  		<%@include file="/WEB-INF/jsp/web/addr/include/addrListforSelf.jsp" %>
+					</div>
+					<div class="popup_btn_wrap2" style="margin: 0 auto 30px auto;">
+						<button type="button" id="btnAddrMassReg">등록</button>
+						<button type="button" id="btnAddrMassClose" class="tooltip-close" data-focus="adr_popup01-close"  data-focus-next="popup02">닫기</button>                      
+					</div>
+				
 				</div>
 			</div>
 		</div>
src/main/webapp/WEB-INF/jsp/web/addr/include/addrListforExcel.jsp
--- src/main/webapp/WEB-INF/jsp/web/addr/include/addrListforExcel.jsp
+++ src/main/webapp/WEB-INF/jsp/web/addr/include/addrListforExcel.jsp
@@ -364,37 +364,33 @@
 //파일 드래그앤드롭 종료
 
 function excelFileChange(file) {
-    if (file) {
-    	fn_loadAddActive();
-        var reader = new FileReader();
-        var extension = file.name.split('.').pop().toLowerCase();
-        reader.onload = function(e) {
-            setTimeout(() => { // 파일 읽기 완료 후 실행되도록 함
-	            if (extension === 'xlsx') {
-	                var data = new Uint8Array(e.target.result);
-	                var workbook = XLSX.read(data, {type: 'array'});
-	                var firstSheet = workbook.Sheets[workbook.SheetNames[0]];
-	                var jsonData = XLSX.utils.sheet_to_json(firstSheet, {header: 1});
-	                processExcelData(jsonData);
-	            } else if (extension === 'txt') {
-	                var textData = e.target.result;
-	                processTextData(textData);
-	            } else {
-	                alert('지원되지 않는 파일 형식입니다.');
-	            }
-	            fn_loadRemoveActive();
-            }, 0); // 지연 없이 즉시 실행되도록 0ms 지연을 설정
-        };
-
-        if (extension === 'xlsx') {
-            reader.readAsArrayBuffer(file);
-        } else if (extension === 'txt') {
-            reader.readAsText(file);
-        }
-    }
-
-    // 로딩창 hide
-    
+	if (file) {
+		fn_loadAddActive();
+		var reader = new FileReader();
+		var extension = file.name.split('.').pop().toLowerCase();
+		reader.onload = function(e) {
+			setTimeout(() => { // 파일 읽기 완료 후 실행되도록 함
+				if (extension === 'xlsx') {
+					var data = new Uint8Array(e.target.result);
+					var workbook = XLSX.read(data, {type: 'array'});
+					var firstSheet = workbook.Sheets[workbook.SheetNames[0]];
+					var jsonData = XLSX.utils.sheet_to_json(firstSheet, {header: 1});
+					processExcelData(jsonData);
+				} else if (extension === 'txt') {
+					var textData = e.target.result;
+					processTextData(textData);
+				} else {
+					alert('지원되지 않는 파일 형식입니다.');
+				}
+				fn_loadRemoveActive();
+			}, 0); // 지연 없이 즉시 실행되도록 0ms 지연을 설정
+		};
+		if (extension === 'xlsx') {
+			reader.readAsArrayBuffer(file);
+		} else if (extension === 'txt') {
+			reader.readAsText(file);
+		}
+	}
 }
 
 // 엑셀 데이터 처리 함수
@@ -415,7 +411,7 @@
     });
 
     updateTable(tableData);
-} 
+}
 
 
 // 텍스트 데이터 처리 함수
@@ -438,25 +434,26 @@
 
 //공통 테이블 업데이트 함수
 function updateTable(tableData) {
- $tableExcel.setColumns([ // 열 정의를 다시 설정
-     {formatter: "rowSelection", titleFormatter: "rowSelection", clipboard: false, hozAlign: "center", headerHozAlign: "center", headerSort: false, cellClick: function(e, cell) {
-         cell.getRow().toggleSelect();
-     }},
-     {title: "A", field: "A", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
-     {title: "B", field: "B", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
-     {title: "C", field: "C", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
-     {title: "D", field: "D", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
-     {title: "E", field: "E", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
-     {title: "F", field: "F", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
-     {title: "G", field: "G", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]}
- ]);
+	$tableExcel.setColumns([ // 열 정의를 다시 설정
+		{formatter: "rowSelection", titleFormatter: "rowSelection", clipboard: false, hozAlign: "center", headerHozAlign: "center", headerSort: false, cellClick: function(e, cell) {
+			cell.getRow().toggleSelect();
+		}},
+		{formatter:"rownum", align:"center", title:"No", hozAlign:"center", headerHozAlign:"center", width:40},
+		{title: "A", field: "A", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "B", field: "B", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "C", field: "C", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "D", field: "D", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "E", field: "E", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "F", field: "F", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "G", field: "G", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]}
+	]);
 
- $tableExcel.setData(tableData).then(() => {
-     // rowTotCnt 업데이트
-     document.getElementById("rowTotCnt").innerText = tableData.length;
- });
+	$tableExcel.setData(tableData).then(() => {
+		// rowTotCnt 업데이트
+		document.getElementById("rowTotCnt").innerText = tableData.length;
+	});
 
- fn_loadRemoveActive();
+	fn_loadRemoveActive();
 }
     
 
@@ -618,7 +615,7 @@
                     <div class="adr_excel" style="margin-top: 13px;">
                         <!-- thead -->
                         <div class="adr_hd select_adr_hd" data-group="tableExcel">
-                            <div></div>
+                            <div style="width: 80px;"></div>
                             <div style="width: 125px;">
                             	<label for="" class="label"></label>
 								<select class="field-selector">
src/main/webapp/WEB-INF/jsp/web/msgdata/MsgDataSMLView.jsp
--- src/main/webapp/WEB-INF/jsp/web/msgdata/MsgDataSMLView.jsp
+++ src/main/webapp/WEB-INF/jsp/web/msgdata/MsgDataSMLView.jsp
@@ -28,6 +28,79 @@
 }
 
 //주소록 불러오기에서 수신자 리스트 tabulator에 데이터 추가해주기
+function addPhoneInfo_advc(tableAddr){
+
+		
+		var addrData = tableAddr.getData().map((row, index) => ({
+		    no: index+1,
+		    name: row.addrName,
+		    phone: removeDash(row.addrPhone),
+		    rep1: row.addrRep1,
+		    rep2: row.addrRep2,
+		    rep3: row.addrRep3,
+		    rep4: row.addrRep4,
+		}));
+
+		tableL.setData(addrData);
+		
+		/* 
+		var idx = 0;
+		var newData = data;//중복 연락처는 하나만 남기고 모두 제거
+		
+		var recTableData = tableL.getRows();		 // 받는사람 리스트의 전체 목록을 저장
+		var tableData = [];
+		
+		//기존 받는사람 리스트를 배열에 미리 담아둔다.
+		if(recTableData.length > 0){
+			
+			for(var j=0; j < recTableData.length; j++){
+				
+				tableData.push({phone: removeDash(recTableData[j].getData().phone) , name: recTableData[j].getData().name, rep1: recTableData[j].getData().rep1, rep2: recTableData[j].getData().rep2, rep3: recTableData[j].getData().rep3, rep4: recTableData[j].getData().rep4});
+			
+			}
+		
+		}
+		
+		//받는사람 리스트를 담아둔 배열에 신규 추가 데이터를 추가해 준다.
+		for(var i=0; i < newData.length; i++){
+			
+			tableData.push({phone: removeDash(newData[i].phone) , name: newData[i].name, rep1: newData[i].rep1, rep2: newData[i].rep2, rep3: newData[i].rep3, rep4: newData[i].rep4});
+			
+		}
+		
+// 		var temp = tableData.length;
+		
+		//기존 수신 리스트를 지워준 후 신규 전체 리스트를 추가해준다.
+		tableL.clearData(); //기존 받는사람 목록을 삭제.
+		//tableL.addData(dupliPhoneData(tableData)); // 받는사람 목록에 주소 정보 입력하기
+		tableL.addData(getSpupDupliPhoneDataChk(tableData)); // 받는사람 목록에 주소 정보 입력하기
+		
+		_fileForm2 = []; //form file data 초기화
+		_fileIdx = 0;	//form file idx 초기화
+		
+		
+		//일괄변환 문구 결제금액 처리
+		*/
+		totRows = tableL.getRows().length; 
+		updateTotCnt(totRows); //전체 데이터 갯수 구하기
+		var smsTxtArea = $('#smsTxtArea').val();
+		if(smsTxtArea.indexOf("[*이름*]")  > -1 
+				|| smsTxtArea.indexOf("[*1*]") > -1
+				|| smsTxtArea.indexOf("[*2*]") > -1
+				|| smsTxtArea.indexOf("[*3*]") > -1
+				|| smsTxtArea.indexOf("[*4*]") > -1){
+			
+			fnReplCell();
+			
+		}else{
+			
+			//결제 금액 구하기
+		    totalPriceSum(totRows);
+			
+		} 
+		
+	
+}
 function addPhoneInfo(data){
 	
 	if(data == null){
@@ -61,7 +134,7 @@
 			
 		}
 		
-		var temp = tableData.length;
+// 		var temp = tableData.length;
 		
 		//기존 수신 리스트를 지워준 후 신규 전체 리스트를 추가해준다.
 		tableL.clearData(); //기존 받는사람 목록을 삭제.
@@ -560,41 +633,32 @@
 	tableL = new Tabulator(".callList_box", {
 		height:"255px",
 	    layout:"fitColumns",
-	    //data:tabledata,
-	    //autoColumns:true,
 	    headerHozAlign:"center",
 	    validationMode:"highlight",
-	    //clipboard:false,
-	    //clipboardCopySelector:"table",
-	    //clipboardPasteAction:"insert", // insert, update, replace
 	    placeholder:"복사(Ctrl+C)한 내용을 여기에 붙여넣기(Ctrl+V) 해주세요.", //fit columns to width of table (optional)
 	    resizableColumns:false,
 	 	columns:[ //Define Table Columns
-	 		{formatter:"rowSelection", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", headerSort:false, cellClick:function(e, cell){
+	 		{formatter:"rowSelection", headerHozAlign:"center", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", width:5, headerSort:false, cellClick:function(e, cell){
 	 	        cell.getRow().toggleSelect();
 		 	}}, 
-		 	{title:"이름", hozAlign:"center", field:"name", editor:"input", validator:["maxLength:12"], cellEdited:function(cell){
-		 	    //cell - cell component
+// 			{formatter:"rownum", align:"center", title:"No", hozAlign:"center", headerHozAlign:"center", field:"No", width:30},
+			{formatter:"rownum", align:"center" ,title:"No", hozAlign:"center", headerHozAlign:"center", width:40},
+		 	{title:"이름", hozAlign:"center", headerHozAlign:"center", field:"name", editor:"input", validator:["maxLength:12"], cellEdited:function(cell){
 		 	    fnReplCell();
 		    }},
-		 	{title:"휴대폰", hozAlign:"center", field:"phone", editor:"input", width:100, validator:["required","minLength:10", "maxLength:12"], cellEdited:function(cell){
-		 	    //cell - cell component
+		 	{title:"휴대폰", hozAlign:"center", headerHozAlign:"center", field:"phone", editor:"input", width:100, validator:["required","minLength:10", "maxLength:12"], cellEdited:function(cell){
 		 	    fnDuplPhone();
 		    }},
-		 	{title:"[*1*]", hozAlign:"center", field:"rep1", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
-		 	    //cell - cell component
+		 	{title:"[*1*]", hozAlign:"center", headerHozAlign:"center", field:"rep1", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
 		 	    fnReplCell();
 		    }},
-		 	{title:"[*2*]", hozAlign:"center", field:"rep2", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
-		 	    //cell - cell component
+		 	{title:"[*2*]", hozAlign:"center", headerHozAlign:"center", field:"rep2", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
 		 		fnReplCell();
 		    }},
-		 	{title:"[*3*]", hozAlign:"center", field:"rep3", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
-		 	    //cell - cell component
+		 	{title:"[*3*]", hozAlign:"center", headerHozAlign:"center", field:"rep3", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
 		 		fnReplCell();
 		    }},
-		 	{title:"[*4*]", hozAlign:"center", field:"rep4", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
-		 	    //cell - cell component
+		 	{title:"[*4*]", hozAlign:"center", headerHozAlign:"center", field:"rep4", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
 		 		fnReplCell();
 		    }},
 		 	
@@ -1010,14 +1074,11 @@
 			
 			if(confirm("선택하신 받는 사람을 삭제하시겠습니까?")){
 				
-				for(var i=0; i < selectedData.length; i++){
-					
-					selectedData[i].delete();
-				
-				}
-			
-				totRows = tableL.getRows().length;
+				// 선택 데이터 삭제
+			    selectedData.forEach(row => row.delete());
 			    
+			    
+				totRows = tableL.getRows().length;
 				updateTotCnt(totRows);
 			    
 				var smsTxtArea = $('#smsTxtArea').val();
@@ -2696,6 +2757,7 @@
         async: true,
         cache: false,
         success: function (returnData, status) {
+        	console.log('returnData : ', returnData);
 			if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
 				
 				if(returnData.result == "success"){
@@ -2711,14 +2773,33 @@
 					}
 					
 					//받는사람 리스트를 담아둔 배열에 신규 추가 데이터를 추가해 준다.
-					for(var i=0; i < addrList.length; i++){
-						
-						tableData.push({addrGroupNm: addrList[i].addrGrpNm, addrPhone: removeDash(addrList[i].addrPhoneNo) , addrName: addrList[i].addrNm, addrRep1: addrList[i].addrInfo1, addrRep2: addrList[i].addrInfo2, addrRep3: addrList[i].addrInfo3, addrRep4: addrList[i].addrInfo4});
-						
-					}
+// 					for(var i=0; i < addrList.length; i++){
+// 						tableData.push({
+// 								addrGroupNm: addrList[i].addrGrpNm
+// 								, addrPhone: removeDash(addrList[i].addrPhoneNo) 
+// 								, addrName: addrList[i].addrNm
+// 								, addrRep1: addrList[i].addrInfo1
+// 								, addrRep2: addrList[i].addrInfo2
+// 								, addrRep3: addrList[i].addrInfo3
+// 								, addrRep4: addrList[i].addrInfo4
+// 							});
+// 					}
+					
+// 					addrList.forEach(function(addr){
+// 						tableData.push({
+// 							addrGroupNm: addr.addrGrpNm,
+// 							addrPhone: removeDash(addr.addrPhoneNo),
+// 							addrName: addr.addrNm,
+// 							addrRep1: addr.addrInfo1,
+// 							addrRep2: addr.addrInfo2,
+// 							addrRep3: addr.addrInfo3,
+// 							addrRep4: addr.addrInfo4
+// 						});
+//                     });
 					
 					//우측 주소록 리스트 Tabulator에 입력해주기
-					tableAddr.setData(tableData);
+// 					tableAddr.setData(tableData);
+					tableAddr.setData(addrList);
 					
 				}else{
 					
@@ -2774,6 +2855,31 @@
 	
 		//선택한 데이터 받는사람 리스트에 추가해 주기
 		addPhoneInfo(tableData);
+		$(".closeAddr").trigger("click");
+		
+		//주소록 레이어 팝업의 Tabulator 데이터 지워주기
+		tableAddr.clearData();
+
+	}
+	
+}
+
+//주소록 불러오기에서 수신자 리스트 추가해 주기
+function addrToList_advc(){
+	console.log('tableAddr :: ', tableAddr);
+// 	var selectedData = tableAddr.getSelectedRows();
+	var tableSize = tableAddr.getDataCount();
+	var tableData = [];
+	
+	if(tableSize < 1){
+		
+		alert("주소록을 선택해 주세요.");
+		return false;
+	
+	}else{ // 선택한 Row 데이터 저장해주기
+		
+		//선택한 데이터 받는사람 리스트에 추가해 주기
+		addPhoneInfo_advc(tableAddr);
 		$(".closeAddr").trigger("click");
 		
 		//주소록 레이어 팝업의 Tabulator 데이터 지워주기
@@ -3345,13 +3451,15 @@
 	<!-- 엑셀 불러오기 -->
 	<form id="excelForm" name="excelForm" method="post">
 		<div class="tooltip-wrap">
-			<div class="popup-com import_layer popup02" tabindex="0" data-tooltip-con="popup02" data-focus="popup02" data-focus-prev="popup02-close">
-				<div class="popup_heading">
+<!-- 			<div class="popup-com import_layer popup02" tabindex="0" data-tooltip-con="popup02" data-focus="popup02" data-focus-prev="popup02-close"> -->
+			<div class="popup-com adr_layer popup02" tabindex="0" data-tooltip-con="popup02" data-focus="popup02" data-focus-prev="popup02-close" style="width: 1000px;">
+			  		<%@include file="/WEB-INF/jsp/web/msgdata/include/msgDataIncludeExcel.jsp" %>
+				<!-- <div class="popup_heading">
 					<p><span>엑셀</span> 불러오기</p>
 					<button type="button" class="tooltip-close" data-focus="popup02-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
 				</div>
 				<div class="layer_in">
-					<!-- 엑셀파일 불러오기 -->
+					엑셀파일 불러오기
 					<div class="hascont">
 						<div class="titBox">
 							<p>- 최대 2만 건까지 등록할 수 있습니다.</p>
@@ -3359,7 +3467,7 @@
 							<p>- 이름 : 20byte, [*1*]~[*4*] : 40byte까지 입력 가능합니다.</p>
 							<p>- 휴대폰 항목은 숫자, 하이픈(-)만 인식하며, 번호 앞에 0이 생략되어도 정상 등록됩니다.
 							</p>
-							<!-- <button type="button" class="excel_btn" onclick="location.href='/cmm/fms/FileDown.do?atchFileId=FILE_000000000011651&fileSn=1'"><i></i>샘플파일 다운로드</button> -->
+							<button type="button" class="excel_btn" onclick="location.href='/cmm/fms/FileDown.do?atchFileId=FILE_000000000011651&fileSn=1'"><i></i>샘플파일 다운로드</button>
 							<button type="button" class="excel_btn" onclick="location.href='/download/msg/엑셀주소록_등록양식.xlsx'"><i class="downroad"></i>샘플파일 다운로드</button>
 						</div>
 						<div class="attachedFile">
@@ -3369,12 +3477,17 @@
 							<button type="button" class="btnType btnType6 c3">찾아보기</button>
 							<p><span class="vMiddle">*</span> 첨부된 파일은 <span class="c_e40000">[추가]버튼을 클릭</span>하셔야 받는 사람에 등록됩니다.</p>
 						</div>
-					</div><!--// 엑셀파일 불러오기 -->
+					</div>// 엑셀파일 불러오기
 					<div class="popup_btn_wrap2">
 						<button type="button" class="tooltip-close" data-focus="popup02-close"  data-focus-next="popup02" id="excelAdd">추가</button>
 						<button type="button" class="tooltip-close" data-focus="popup02-close"  data-focus-next="popup02">닫기</button>                      
 					</div>
 				</div>
+				
+				
+				
+				 -->
+				 
 			</div>
 		</div><!--// 엑셀 불러오기 -->
 	</form>
@@ -3470,7 +3583,8 @@
 								<!--// table -->
 							</div>
 							<div class="popup_btn_wrap2">
-								<button type="button" onClick="javascript:addrToList(); return false;">추가</button>
+<!-- 								<button type="button" onClick="javascript:addrToList(); return false;">추가</button> -->
+								<button type="button" onClick="javascript:addrToList_advc(); return false;">추가</button>
 								<button type="button" onClick="javascript:addrClose(); return false;">닫기</button>
 							</div>
 							<%-- 주소록 레이어 팝업 닫기 실행 코드 --%>
@@ -3862,10 +3976,11 @@
 										<label for="callTo" class="label">받는 번호입력</label>
 										<input type="text" id="callTo" name="callTo" oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*)\./g, '$1');"  placeholder="번호를 입력하세요" onfocus="this.placeholder=''" onblur="this.placeholder='번호를 입력하세요'" style="width:340px;">
 										<button type="button" class="btnType btnType6 addCallToF">번호추가</button>
-										<span><span class="vMiddle">*</span> 중복번호는 한번만 발송됩니다.</span>
+										<span><span class="vMiddle">*</span> 중복번호는 한번만 추가됩니다.</span>
 									</div>
                                     <div class="receipt_num_midde">
-                                        <div class="listType list01 callList_box" id="callList_box">
+                                        <div class="listType list01 callList_box">
+                                        <!-- 
 											<div class="list_table list_head">
 												<div class="cb_wrap">
 													<label for="" class="label"></label>
@@ -3881,7 +3996,7 @@
 													<img src="/publish/images/sortUp.png">
 													<img src="/publish/images/sortDown.png">
 												</div>
-											</div>
+											</div> -->
 										</div>
 										<div class="put_right">
 											<div class="btn_popup_wrap spc_wrap">
 
src/main/webapp/WEB-INF/jsp/web/msgdata/include/msgDataIncludeExcel.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/web/msgdata/include/msgDataIncludeExcel.jsp
@@ -0,0 +1,625 @@
+<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
+<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
+<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
+
+<script type="text/javascript" src="<c:url value='/publish/js/content.js'/>"></script>
+
+<script type="text/javascript">
+
+var $tableExcel = null; //엑셀입력 탭
+$(document).ready(function(){
+	// 엑셀 중복번호 버튼
+	$("#tableExcelDupliBtn").hide();
+
+
+	//Tabulator AJAX Data Loading
+	$tableExcel = new Tabulator("#tabulator_excel", {
+		height:"255px",
+		width:"100%",
+	    layout:"fitColumns",
+	    autoColumns:false,
+	    headerHozAlign:"center", 
+	    validationMode:"highlight",
+	    clipboard:false,
+	    clipboardCopySelector:"table",
+	    clipboardPasteAction:"insert", // insert, update, replace
+	    placeholder:"Excel 파일을 업로드 해주세요.", //fit columns to width of table (optional)
+	 	columns:[ //Define Table Columns
+	 		{formatter:"rowSelection", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", headerSort:false, cellClick:function(e, cell){
+	 	        cell.getRow().toggleSelect();
+		 		}
+		 	}, 
+			{formatter:"rownum", align:"center" ,title:"No", hozAlign:"center", headerHozAlign:"center", width:40},
+		 	{title:"A", field:"A", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]},
+		 	{title:"B", field:"B", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]},
+		 	{title:"C", field:"C", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]},
+		 	{title:"D", field:"D", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]},
+		 	{title:"E", field:"E", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]},
+		 	{title:"F", field:"F", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]},
+		 	{title:"G", field:"G", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]}
+	 	],
+	 	validationFailed:function(cell, value, parameters){ // 유효성 체크 함수 
+	        var valid = cell.isValid();
+	 		if(!valid){
+	 			alert("양식에 맞지 않는 정보가 입력되었습니다.");
+	 			
+	 			//해당 셀 데이터 삭제
+	 			cell.setValue("");
+	 		}
+	 		return value % parameters.phone;
+	    },
+	});
+
+    $("#excelFile").on("change", function(event) {
+    	var fileInfo =  event.target.files;
+    	if(fileInfo.length > 0){
+        	excelFileChange(fileInfo[0]);
+    	}
+    });
+	
+
+
+  //#############################################################################################
+  //파일업로드 드래그앤 드롭
+  //#############################################################################################
+  var objDragAndDrop = $(".upload_area");
+  $(document).on("dragenter",".upload_area",function(e){
+    e.stopPropagation();
+    e.preventDefault();
+    //$(this).css('border', '2px solid #0B85A1');
+  });
+  $(document).on("dragover",".upload_area",function(e){
+    e.stopPropagation();
+    e.preventDefault();
+  });
+  $(document).on("drop",".upload_area",function(e){
+//   	fn_loadAddActive();
+  	e.preventDefault();
+  	var files = e.originalEvent.dataTransfer.files;
+  	excelFileChange(files[0]);
+  });
+
+  $(document).on('dragenter', function (e){
+    e.stopPropagation();
+    e.preventDefault();
+  });
+  $(document).on('dragover', function (e){
+  	e.stopPropagation();
+  	e.preventDefault();
+  //objDragAndDrop.css('border', '2px dotted #0B85A1');
+  });
+  $(document).on('drop', function (e){
+    e.stopPropagation();
+    e.preventDefault();
+  });
+  //파일 드래그앤드롭 종료
+	
+	
+	
+	
+
+	//타이틀 select 선택 이벤트
+	 $('.field-selector').on('change', function() {
+		fn_loadAddActive();
+		var selectedFields = [];
+		var isDuplicate = false;
+
+		if($tableExcel.getData().length < 1){
+			alert('데이터 입력 후 선택해 주세요.');
+			$(this).val(""); 
+			fn_loadRemoveActive();
+			return false;
+		}
+		
+		// 중복체크
+		$('.field-selector').each(function() {
+			var selectedField = $(this).val();
+			if (selectedField) {
+				if (selectedFields.includes(selectedField)) {
+					alert("중복된 필드를 선택할 수 없습니다.");
+					$(this).val(""); // 중복 필드를 선택한 경우 빈 값으로 초기화
+					isDuplicate = true;
+					return false; // 반복문 종료
+				}
+				selectedFields.push(selectedField);
+			}
+		});
+
+
+		// 
+		updateTableFields($tableExcel);
+		
+		// 필드가 휴대폰이면 열 중복체크
+		if($(this).val() == 'addrPhoneNo'){
+			fn_phoneDupl($tableExcel);
+		}
+		fn_loadRemoveActive();
+		
+	});
+	
+  
+
+		// 받는사람 선택삭제 버튼 처리해주기
+		$('#in_select_del').click(function(){
+			
+			if(tableL == null || tableL == ""){
+				
+				alert("받는사람을 추가해 주세요.");
+				return false;
+			
+			}
+			
+			var selectedData = tableL.getSelectedRows();
+			
+			if(selectedData == "" || selectedData == null){
+				
+				alert("삭제할 연락처를 선택해주세요.");
+				return false;
+			
+			}else{ // 선택한 Row 데이터 삭제하기
+				
+				if(confirm("선택하신 받는 사람을 삭제하시겠습니까?")){
+					
+					// 선택 데이터 삭제
+				    selectedData.forEach(row => row.delete());
+				    
+				    
+					totRows = tableL.getRows().length;
+					updateTotCnt(totRows);
+				    
+					var smsTxtArea = $('#smsTxtArea').val();
+					
+					//일괄변환 문구 결제금액 처리
+					if(smsTxtArea.indexOf("[*이름*]") > -1
+							|| smsTxtArea.indexOf("[*1*]") > -1
+							|| smsTxtArea.indexOf("[*2*]") > -1
+							|| smsTxtArea.indexOf("[*3*]") > -1
+							|| smsTxtArea.indexOf("[*4*]") > -1){
+						
+						fnReplCell();
+					}else{
+						//결제 금액 구하기
+					    totalPriceSum(totRows);
+					}
+					
+				}
+
+			}
+			
+		});
+  
+  
+  
+  
+  
+});
+
+
+
+function excelFileChange(file) {
+	if (file) {
+		fn_loadAddActive();
+		var reader = new FileReader();
+		var extension = file.name.split('.').pop().toLowerCase();
+		reader.onload = function(e) {
+			setTimeout(() => { // 파일 읽기 완료 후 실행되도록 함
+				if (extension === 'xlsx') {
+					var data = new Uint8Array(e.target.result);
+					var workbook = XLSX.read(data, {type: 'array'});
+					var firstSheet = workbook.Sheets[workbook.SheetNames[0]];
+					var jsonData = XLSX.utils.sheet_to_json(firstSheet, {header: 1});
+					processExcelData(jsonData);
+				} else if (extension === 'txt') {
+					var textData = e.target.result;
+					processTextData(textData);
+				} else {
+					alert('지원되지 않는 파일 형식입니다.');
+				}
+				fn_loadRemoveActive();
+			}, 0); // 지연 없이 즉시 실행되도록 0ms 지연을 설정
+		};
+		if (extension === 'xlsx') {
+			reader.readAsArrayBuffer(file);
+		} else if (extension === 'txt') {
+			reader.readAsText(file);
+		}
+	}
+}
+
+
+// 엑셀 데이터 처리 함수
+function processExcelData(data) {
+ var keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
+ var tableData = [];
+ var totalRows = data.length - 2; // 전체 데이터 수 (1, 2행 제외)
+
+
+ // 3번째 행부터 입력 
+ data.slice(2).forEach((row, index) => {
+     var rowData = {};
+     keys.forEach((key, idx) => { // index 변수명 변경 (내부와 외부에서 사용되므로 충돌 방지)
+         rowData[key] = row[idx] ? row[idx].trim() : ""; // 각 컬럼에 대해 기본값을 설정
+     });
+     tableData.push(rowData);
+
+ });
+
+ updateTable(tableData);
+}
+
+
+// 텍스트 데이터 처리 함수
+function processTextData(text) {
+	var lines = text.split('\n'); // 각 줄을 배열로 분리
+	var keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
+	var tableData = [];
+	
+	lines.forEach(line => {
+		var rowData = {};
+		var row = line.split(','); // 쉼표로 분리
+		keys.forEach((key, index) => {
+			rowData[key] = row[index] ? row[index].trim() : ""; // 각 컬럼에 대해 기본값을 설정
+		});
+		tableData.push(rowData);
+	});
+	
+	updateTable(tableData);
+}
+
+//공통 테이블 업데이트 함수
+function updateTable(tableData) {
+	$tableExcel.setColumns([ // 열 정의를 다시 설정
+		{formatter: "rowSelection", titleFormatter: "rowSelection", clipboard: false, hozAlign: "center", headerHozAlign: "center", headerSort: false, cellClick: function(e, cell) {
+			cell.getRow().toggleSelect();
+		}},
+		{formatter:"rownum", align:"center" ,title:"No", hozAlign:"center", headerHozAlign:"center", width:40},
+		{title: "A", field: "A", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "B", field: "B", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "C", field: "C", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "D", field: "D", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "E", field: "E", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "F", field: "F", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]},
+		{title: "G", field: "G", hozAlign: "center", headerHozAlign: "center", width: 125, validator: ["maxLength:100", "string"]}
+	]);
+
+	$tableExcel.setData(tableData).then(() => {
+		// rowTotCnt 업데이트
+		document.getElementById("rowTotCnt").innerText = tableData.length;
+	});
+	
+	fn_loadRemoveActive();
+}
+
+
+
+/* 
+* 타이틀 select 선택할때마다 실행해서         
+* 데이터테이블 필드값 수정                  
+*/
+function updateTableFields($objTabul) {
+	var currentData = $objTabul.getData();
+	var columns = [
+		{formatter: "rowSelection", titleFormatter: "rowSelection", clipboard: false, hozAlign: "center", headerHozAlign: "center", headerSort: false, cellClick: function(e, cell) {
+			cell.getRow().toggleSelect();
+		}}
+		,{formatter:"rownum", align:"center", title:"No", hozAlign:"center", headerHozAlign:"center", width:40}
+	];
+
+	var fieldMapping = [];
+	$('.field-selector').each(function(index) {
+		var selectedField = $(this).val();
+		//  ASCII 문자 코드 사용 - 65=A, 66=B ...
+		var field = String.fromCharCode(65 + index);
+		if (selectedField) {
+			columns.push({title: field, field: selectedField, hozAlign: "center", headerHozAlign: "center", editor: "input", width: 125, validator: ["maxLength:100", "string"]});
+			fieldMapping.push(selectedField);
+		} else {
+			columns.push({title: field, field: field, hozAlign: "center", headerHozAlign: "center", editor: "input", width: 125, validator: ["maxLength:100", "string"]});
+			fieldMapping.push(field);
+		}
+	});
+
+	var updatedData = currentData.map(row => {
+		var newRow = {};
+		fieldMapping.forEach((field, index) => {
+			newRow[field] = row[Object.keys(row)[index]] || "";
+		});
+		return newRow;
+	});
+
+	$objTabul.setColumns(columns);
+	$objTabul.setData(updatedData);
+}
+
+/**
+ * @ 핸드폰 중복 데이터
+ * */
+function fn_phoneDupl($objTabul) {
+	    var data = $objTabul.getData();
+	    var uniquePhones = new Set();
+	    var dupliPhoneDataRealList = [];
+	    var rowsToKeep = [];
+	    var rowsToDelete = [];
+	    var phoneNumberChk = false;
+
+
+	    
+	    data.forEach((row, index) => {
+
+	        if (!isValidKoreanPhoneNumber(row.addrPhoneNo)) {
+	        	phoneNumberChk = true
+	        	return false;
+	        }
+	    	
+	        if (uniquePhones.has(row.addrPhoneNo)) {
+	        	dupliPhoneDataRealList.push(row.addrPhoneNo);
+	            rowsToDelete.push(index); // 중복된 행의 인덱스를 기록
+	        } else {
+	            uniquePhones.add(row.addrPhoneNo);
+	            rowsToKeep.push(row); // 고유한 데이터만 추가
+	        }
+	    });
+	    
+	    if(phoneNumberChk){
+	    	alert('휴대폰 형식에 맞지 않는 데이터가 있습니다.\n 확인해 주세요');
+	    }
+
+	    $("#rowDupCnt").text(dupliPhoneDataRealList.length);
+
+	    if (dupliPhoneDataRealList.length > 0) {
+//	        alert("중복된 휴대폰 번호가 있습니다: \n" + duplicatePhones.join(", "));
+	    	makeAddrMassDupliPop(dupliPhoneDataRealList);
+	    }
+
+	    // 중복된 행 삭제
+	    rowsToDelete.reverse().forEach(index => {
+	        $objTabul.deleteRow(index);
+	    });
+
+	    // 고유한 데이터만 남기고 테이블 업데이트
+	    $objTabul.setData(rowsToKeep);
+	    $("#rowTotCnt").text(rowsToKeep.length);
+	}
+
+
+
+
+function fn_dupliPopupShow(){
+	$('#tableExcelDupliBtn').show()
+}
+
+//한국의 핸드폰 번호 형식 검사 함수
+function isValidKoreanPhoneNumber(phone) {
+    // 하이픈(-)을 제거하고 숫자만 남긴 후 검사
+    var cleaned = phone.replace(/-/g, '');
+    // 010, 011, 016, 017, 018, 019로 시작하고 10~11자리인 경우 유효
+    var valid = /^(010|011|016|017|018|019)\d{7,8}$/.test(cleaned);
+    return valid;
+}
+
+// 상단 설명 더보기 
+function popMore(e){
+	$(e).closest(".pop_more_cont").toggleClass("pop_more_click");
+	
+	if($(e).closest(".pop_more_cont").is(".pop_more_click")){
+		$(e).html('숨기기');
+		$(e).append('<i></i>');
+	}else {
+		$(e).html('더보기');
+		$(e).append('<i></i>');
+	}
+}
+
+</script>
+
+				<div class="popup_heading">
+					<p>주소록 대량등록</p>
+					<button type="button" class="tooltip-close" data-focus="popup02-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+			   </div>
+				<div class="layer_in" style="padding: 25px 30px;">
+<!-- 					<div class="list_tab_wrap2"> -->
+						<!-- tab button -->
+<!-- 						<ul class="list_tab" id="tbTabl">  -->
+<!-- 							<li class="tab active" data-tabul="tableExcel"><button type="button" onclick="popupTab(this,'1'); fn_tabToggle('1');">엑셀입력</button></li> -->
+<!-- 							<li class="tab" data-tabul="tableClip"><button type="button" onclick="popupTab(this,'2'); fn_tabToggle('2');">붙여넣기</button></li> -->
+<!-- 							<li class="tab" data-tabul="tableSelf"><button type="button" onclick="popupTab(this,'3'); fn_tabToggle('3');">직접입력</button></li> -->
+<!-- 						</ul>// tab button -->
+<!-- 					</div> -->
+					<!-- 엑셀입력 -->
+					<div class="popCont current pop_more_cont" id="popCont_1">
+						<div class="titBox">
+							<p>- 엑셀(EXCEL) 파일로 주소록을 한 번에 최대 2만건까지 등록하여 간편하게 발송 및 관리하실 수 있습니다.</p>
+							<p>- 반드시 샘플파일을 다운로드하여 작성방법을 확인하신 후 정해진 양식에 맞추어 주소록을 작성하셔야 합니다.</p>
+							<p>  &nbsp;&nbsp;※ 주소록 관리 메뉴에서 다운로드 받으신 엑셀 파일 또한 업로드 양식에 맞추어 작성하셔야 하며, </p>
+							<p>  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;주소록에 이미 등록된 휴대폰 번호는 업데이트 되지 않으므로 기존 주소록에서 해당 휴대폰 번호를 삭제한 후 재등록해 주시기 바랍니다.</p>
+							<p>- 쉼표(,), 구분선(|), 역슬래시(\, ₩), 작은따옴표('), 큰따옴표(") 등 발송불가 특수문자는 저장되지 않습니다.</p>
+							<p>- 휴대폰 번호는 필수입력 항목입니다.</p>
+							<p>- 전화번호 형태는 010-1234-5678 또는 01012345678 모두 가능합니다. 단, 공백은 허용되지 않습니다.</p>
+							<p>- 엑셀 파일에 비밀번호 설정, 제한된 보기, 수식 등이 설정되어 있는 경우 업로드가 불가합니다.</p>
+							<p>- 이름 20byte, [*1*]~[*4*] 40byte, 메모 250byte까지 입력 가능합니다.</p>
+							<p>- 첨부가능 파일 : xlsx, xls(최대용량 3MB)</p>
+							<p>- ‘오류 검사’를 통해 등록된 데이터에 전화번호 입력 오류를 확인하실 수 있습니다.</p>
+							<p>- 주소록 등록이 어려우신 경우에는 주소록 입력대행 메뉴를 이용하시면 됩니다.</p>
+							<button type="button" class="excel_btn" onclick="location.href='/download/addr/주소록_대량등록.xlsx'"><i class="downroad"></i>샘플파일 다운로드</button>
+						</div>
+						<div class="pop_more_wrap">
+								<button type="button" class="pop_more" onclick="popMore(this);">더보기<i></i></button>
+						</div>
+					</div><!--// 엑셀입력 -->
+
+					<!-- 공통 -->
+					<div>
+		                <table class="layer_tType1">
+		                    <caption>엑셀입력 표</caption>
+		                    <colgroup>
+		                        <col style="width: 95px">
+		                        <col style="width: auto">
+		                    </colgroup>
+		                    <tbody>
+		                        <tr>
+		                            <th>그룹 선택</th>
+		                            <td>
+		                                <label for="" class="label">그룹 선택</label>
+		                                <select id="addrGrpIdInfo" name="addrGrpIdInfo">
+		                                </select>
+	                                    <label for="" class="label">그룹명 입력</label>
+	                                    <input type="text" id="addrGrpNm" name="addrGrpNm" placeholder="새 그룹명을 입력해주세요." onfocus="this.placeholder=''" onblur="this.placeholder='새 그룹명을 입력해주세요.'"class="inputLight" style="width: 300px;">
+		                                <input type="file" id="excelFile" accept=".xls, .xlsx, .txt" style="display:none"/>
+		                                <button type="button" class="excel_btn2 btnType c3"><i class="uproad"></i>엑셀, TXT파일 업로드</button>
+		                            </td>
+		                        </tr>
+		                    </tbody>
+		                </table>
+	                </div>
+					<div class="file_add upload_area">
+						<p><img src="/publish/images/content/file_add.png" alt="파일 붙여넣기">마우스로 엑셀, TXT파일을 여기에 끌어다 놓으세요</p>
+					</div>
+					<div class="excel_middle2">
+						<p>
+							총 <span class="c_e40000 fwBold" id="rowTotCnt">0</span>건 / 중복 <span class="c_002c9a fwBold" id="rowDupCnt">0</span>건
+							&nbsp; 
+							<button type="button" class="btnType btnType6" data-tooltip="addrMassDupli_layer" id="tableExcelDupliBtn">중복번호</button>
+<!-- 							&nbsp; -->
+<!-- 							<button type="button" class="btnType btnType6" data-tooltip="addrMassSaveDupli_layer" onclick="GetAddrMassSaveDupli()" id="btnAddrMassSaveDupli">중복번호</button> -->
+						</p>
+<!-- 						<button type="button" class="btnType btnType6 addCallToF">번호추가</button> -->
+					</div>
+					
+					
+					
+
+                    <div class="adr_excel" style="margin-top: 13px;">
+                        <!-- thead -->
+                        <div class="adr_hd select_adr_hd" data-group="tableExcel">
+                            <div style="width: 80px;"></div>
+                            <div style="width: 125px;">
+                            	<label for="" class="label"></label>
+								<select class="field-selector">
+									<option value="">선택하기</option>
+									<option value="addrNm">이름</option>
+									<option value="addrPhoneNo">휴대폰</option>
+									<option value="addrInfo1">[*1*]</option>
+									<option value="addrInfo2">[*2*]</option>
+									<option value="addrInfo3">[*3*]</option>
+									<option value="addrInfo4">[*4*]</option>
+									<option value="addrComment">메모</option>
+								</select>
+                            </div>
+                            <div style="width: 125px;">
+                                <label for="" class="label"></label>
+								<select class="field-selector">
+									<option value="">선택하기</option>
+									<option value="addrNm">이름</option>
+									<option value="addrPhoneNo">휴대폰</option>
+									<option value="addrInfo1">[*1*]</option>
+									<option value="addrInfo2">[*2*]</option>
+									<option value="addrInfo3">[*3*]</option>
+									<option value="addrInfo4">[*4*]</option>
+									<option value="addrComment">메모</option>
+								</select>
+                            </div>
+                            <div style="width: 125px;">
+                                <label for="" class="label"></label>
+								<select class="field-selector">
+									<option value="">선택하기</option>
+									<option value="addrNm">이름</option>
+									<option value="addrPhoneNo">휴대폰</option>
+									<option value="addrInfo1">[*1*]</option>
+									<option value="addrInfo2">[*2*]</option>
+									<option value="addrInfo3">[*3*]</option>
+									<option value="addrInfo4">[*4*]</option>
+									<option value="addrComment">메모</option>
+								</select>
+                            </div>
+                            <div style="width: 125px;">
+                                <label for="" class="label"></label>
+								<select class="field-selector">
+									<option value="">선택하기</option>
+									<option value="addrNm">이름</option>
+									<option value="addrPhoneNo">휴대폰</option>
+									<option value="addrInfo1">[*1*]</option>
+									<option value="addrInfo2">[*2*]</option>
+									<option value="addrInfo3">[*3*]</option>
+									<option value="addrInfo4">[*4*]</option>
+									<option value="addrComment">메모</option>
+								</select>
+                            </div>
+                            <div style="width: 125px;">
+                                <label for="" class="label"></label>
+								<select class="field-selector">
+									<option value="">선택하기</option>
+									<option value="addrNm">이름</option>
+									<option value="addrPhoneNo">휴대폰</option>
+									<option value="addrInfo1">[*1*]</option>
+									<option value="addrInfo2">[*2*]</option>
+									<option value="addrInfo3">[*3*]</option>
+									<option value="addrInfo4">[*4*]</option>
+									<option value="addrComment">메모</option>
+								</select>
+                            </div>
+                            <div style="width: 125px;">
+                                <label for="" class="label"></label>
+								<select class="field-selector">
+									<option value="">선택하기</option>
+									<option value="addrNm">이름</option>
+									<option value="addrPhoneNo">휴대폰</option>
+									<option value="addrInfo1">[*1*]</option>
+									<option value="addrInfo2">[*2*]</option>
+									<option value="addrInfo3">[*3*]</option>
+									<option value="addrInfo4">[*4*]</option>
+									<option value="addrComment">메모</option>
+								</select>
+                            </div>
+                            <div style="width: 125px;">
+                                <label for="" class="label"></label>
+								<select class="field-selector">
+									<option value="">선택하기</option>
+									<option value="addrNm">이름</option>
+									<option value="addrPhoneNo">휴대폰</option>
+									<option value="addrInfo1">[*1*]</option>
+									<option value="addrInfo2">[*2*]</option>
+									<option value="addrInfo3">[*3*]</option>
+									<option value="addrInfo4">[*4*]</option>
+									<option value="addrComment">메모</option>
+								</select>
+                            </div>
+                        </div>
+                     </div>					
+					
+					<div class="drag_drop_wrap callList_includ_box" id="tabulator_excel">
+<!-- 						<img src="/publish/images/content/excel.jpg" style="width: 100%;"> -->
+					</div>
+					<div class="excel_middle">
+						<div class="select_btnWrap clearfix">
+							<div>
+								<button type="button" id="all_del"><i class="remove_img"></i>전체삭제</button>
+								<button type="button" id="in_select_del"><i class="remove_img"></i>선택삭제</button>
+								<button type="button" id="chkVali_del"><i class="remove_img"></i>오류번호삭제</button>
+								<button type="button" id="check_validity">오류 검사 <i></i></button>
+								<div class="error_hover_cont send_hover_cont addr_hover_cont">
+									<p>휴대폰 번호 입력 시 해당 휴대폰 번호에 대한 형식이 어긋나거나 휴대폰 번호에 오류가 있는지 등을 검사하는 기능</p>
+									<span>(예시) 010-1234-0001(O) / 010-123-0001(X)</span>
+								</div>
+							</div>
+	
+						</div>
+					</div><!--// 공통 -->     
+	
+					<!-- 붙여놓기 설명 -->
+	                <div class="req_area">
+	                  	<div class="text_box">
+	                    	- 휴대폰 번호가 입력된 txt 파일을 열어 복사(Ctrl+c) + 붙여넣기(Ctrl+v)로도 입력하실 수 있습니다.<br>
+							- 휴대폰 번호는 필수입력 항목입니다.<br>
+							- 이름,휴대폰 번호,[*1*],[*2*],[*3*],[*4*],메모 순서대로 입력해주세요.(예 : 010-1234-5678,홍길동,변수1…메모)<br>
+							- 이름은 24byte, [*1*]~[*4*] 40byte, 메모는 250byte까지 입력 가능합니다.<br>
+							- '오류 검사'를 통해 등록된 데이터에 전화번호 입력 오류를 확인하실 수 있습니다.
+						</div>
+	                </div>
+					<div class="popup_btn_wrap2" style="margin: 0 auto 30px auto;">
+						<button type="button" id="btnAddrMassReg">등록</button>
+						<button type="button" id="btnAddrMassClose" class="tooltip-close" data-focus="adr_popup01-close"  data-focus-next="popup02">닫기</button>                      
+					</div>
+				
+				</div>(No newline at end of file)
src/main/webapp/js/kakao/at/addr.js
--- src/main/webapp/js/kakao/at/addr.js
+++ src/main/webapp/js/kakao/at/addr.js
@@ -141,6 +141,7 @@
 }
 
 function loadAddrList(){
+	console.log(' loadAddrList() ');
 
 	/*
 		serialize 를 사용할때는 processData, contentType 옵션 제가할것
@@ -157,8 +158,8 @@
         async: false,
         cache: false,
         success: function (returnData, status) {
+			console.log('returnData : ', returnData);
 			if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
-				
 				if(returnData.result == "success"){
 					
 					var addrList = returnData.resultAddrList;
src/main/webapp/js/web/addr/event.js
--- src/main/webapp/js/web/addr/event.js
+++ src/main/webapp/js/web/addr/event.js
@@ -115,6 +115,7 @@
 			{formatter: "rowSelection", titleFormatter: "rowSelection", clipboard: false, hozAlign: "center", headerHozAlign: "center", headerSort: false, cellClick: function(e, cell) {
 				cell.getRow().toggleSelect();
 			}}
+			,{formatter:"rownum", align:"center", title:"No", hozAlign:"center", headerHozAlign:"center", width:40}
 		];
 
 		var fieldMapping = [];
@@ -144,14 +145,14 @@
 	}
 }); 
 
-
-function fn_loadAddActive(){
-	$('.loading_layer').addClass('active');
-}
-
-function fn_loadRemoveActive(){
-	$('.loading_layer').removeClass('active');
-}
+//
+//function fn_loadAddActive(){
+//	$('.loading_layer').addClass('active');
+//}
+//
+//function fn_loadRemoveActive(){
+//	$('.loading_layer').removeClass('active');
+//}
 
 //중복 연락처
 function makeAddrMassDupliPop(dupliPhoneDataRealList) {
src/main/webapp/js/web/addr/init.js
--- src/main/webapp/js/web/addr/init.js
+++ src/main/webapp/js/web/addr/init.js
@@ -37,6 +37,7 @@
 	 	        cell.getRow().toggleSelect();
 		 		}
 		 	}, 
+			{formatter:"rownum", align:"center" ,title:"No", hozAlign:"center", headerHozAlign:"center", width:40},
 		 	{title:"A", field:"A", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]},
 		 	{title:"B", field:"B", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]},
 		 	{title:"C", field:"C", hozAlign:"center", headerHozAlign: "center", width:125, validator:["maxLength:100", "string"]},
src/main/webapp/publish/js/content.js
--- src/main/webapp/publish/js/content.js
+++ src/main/webapp/publish/js/content.js
@@ -1553,4 +1553,12 @@
 	
 	//미리보기 추가된 버튼 정보 삭제처리하기
 	$('.btnEmpty').eq(btnIndex).remove();
-}
(No newline at end of file)
+}
+
+function fn_loadAddActive(){
+	$('.loading_layer').addClass('active');
+}
+
+function fn_loadRemoveActive(){
+	$('.loading_layer').removeClass('active');
+}
Add a comment
List