김진영 김진영 09-15
1차 commit
@cd663d7727709b4f1a45964dbbfb5a68ab8d3ae5
pom.xml
--- pom.xml
+++ pom.xml
@@ -55,7 +55,7 @@
 	<repositories>
 		<repository>
             <id>maven-public</id>
-            <url>http://nexus.iten.co.kr:9999/repository/maven-public/</url>
+            <url>http://nexus.iten.co.kr/repository/maven-public/</url>
             <releases>
                 <enabled>true</enabled>
             </releases>
src/main/java/itn/com/api/web/ApiRestController.java
--- src/main/java/itn/com/api/web/ApiRestController.java
+++ src/main/java/itn/com/api/web/ApiRestController.java
@@ -4,11 +4,19 @@
 
 import javax.annotation.Resource;
 
+import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;
+import itn.com.cmm.LoginVO;
+import itn.com.cmm.RestResponse;
+import itn.com.utl.fcc.service.EgovStringUtil;
+import itn.let.mjo.msgdata.service.MjonMsgDataService;
+import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
 
 import itn.let.kakao.admin.kakaoAt.service.MjonKakaoAtStatVO;
@@ -42,7 +50,10 @@
 	
 	@Resource(name = "KakaoStatisticsService")
     private KakaoStatisticsService kakaoStatisticsService;
-	
+
+	@Resource(name = "MjonMsgDataService")
+	private MjonMsgDataService mjonMsgDataService;
+
 	/** 
 	 * @methodName	: mailSendItnContactUs 
 	 * @author		: 이호영
@@ -83,7 +94,34 @@
 			return ResponseEntity.ok().body(new StatusResponse(HttpStatus.OK, "알림톡 발송건수 통계 생성을 실패하였습니다.", LocalDateTime.now()));
 		}
 		return ResponseEntity.ok().body(new StatusResponse(HttpStatus.OK, "알림톡 발송건수 통계 생성을 성공적으로 마쳤습니다.", LocalDateTime.now()));
-	}	
-	
+	}
 
+
+	/**
+	 * @methodName	: findByIdQuatMgmtAjax
+	 * @author		: 이호영
+	 * @date		: 2026.03.31
+	 * @description	: 갱신된 금액 가져오는 ajax
+	 * @return
+	 * @throws Exception
+	 */
+	@RequestMapping(value="/web/api/getBeforeCashDataAjax.do")
+	public ResponseEntity<?> getBeforeCashDataAjax() throws Exception {
+
+
+		//로그인 권한정보 불러오기
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+
+		if(StringUtils.isEmpty(userId)) {
+			return ResponseEntity.ok(
+					RestResponse.builder()
+							.status(HttpStatus.UNAUTHORIZED) // 401 권한 인증 에러
+							.msg("로그인을 하셔야 이용 가능합니다.")
+							.build()
+			);
+		}
+
+		return ResponseEntity.ok(mjonMsgDataService.getBeforeCashDataAjax(userId));
+	}
 }
src/main/java/itn/com/cmm/util/XssFilterUtil.java
--- src/main/java/itn/com/cmm/util/XssFilterUtil.java
+++ src/main/java/itn/com/cmm/util/XssFilterUtil.java
@@ -7,25 +7,26 @@
 		String test_str_low= test_str.toLowerCase();
 		boolean returnSts = true;
 		
-		if(test_str_low.contains("union")|| 
-				test_str_low.contains("select") || 
-				test_str_low.contains("insert") || 
-				test_str_low.contains("drop") || 
-				test_str_low.contains("update") || 
-				test_str_low.contains("delete") || 
-				test_str_low.contains(" join ") || 
-				test_str_low.contains("from") || 
-				test_str_low.contains("where") ||
-				test_str_low.contains("dbms") ||
-				test_str_low.contains("receive_message") ||
-				test_str_low.contains("chr(") ||
-				test_str_low.contains("pipe") ||
-				test_str_low.contains("substr") || 
-				test_str_low.contains("script")|| 
-				test_str_low.contains("alert")|| 
-				test_str_low.contains("javascript")|| 
-				test_str_low.contains("location")||
-				test_str_low.contains("href")|| 
+		if(
+//				test_str_low.contains("union")||
+//				test_str_low.contains("select") ||
+//				test_str_low.contains("insert") ||
+//				test_str_low.contains("drop") ||
+//				test_str_low.contains("update") ||
+//				test_str_low.contains("delete") ||
+//				test_str_low.contains(" join ") ||
+//				test_str_low.contains("from") ||
+//				test_str_low.contains("where") ||
+//				test_str_low.contains("dbms") ||
+//				test_str_low.contains("receive_message") ||
+//				test_str_low.contains("chr(") ||
+//				test_str_low.contains("pipe") ||
+//				test_str_low.contains("substr") ||
+//				test_str_low.contains("script")||
+//				test_str_low.contains("alert")||
+//				test_str_low.contains("javascript")||
+//				test_str_low.contains("location")||
+//				test_str_low.contains("href")||
 				test_str_low.contains("./")||
 				test_str_low.contains("../")||
 				test_str_low.contains("..//")||
src/main/java/itn/let/mjo/mjocommon/MjonCommon.java
--- src/main/java/itn/let/mjo/mjocommon/MjonCommon.java
+++ src/main/java/itn/let/mjo/mjocommon/MjonCommon.java
@@ -766,7 +766,10 @@
 		//문자 바이트 계산에 필요한 캐릭터 셋 : 한글 2Byte로 계산
 		String charset = "euc-kr"; 						
 		if(org.apache.commons.lang3.StringUtils.isNotEmpty(smsTxt)) {
-			String smsCont = smsTxt.replace("\r\n", "\n");
+//			String smsCont = smsTxt.replace("\r\n", "\n");
+			String smsCont = smsTxt
+					.replace("\r\n", "\n");
+
 			smsBytes = smsCont.getBytes(charset).length;
 		}
 //		log.info(" + smsBytes :: [{}]", smsBytes);
src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java
--- src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java
+++ src/main/java/itn/let/mjo/msg/service/MjonMsgVO.java
@@ -321,6 +321,8 @@
 	private List<MjonMsgSendVO> mjonMsgSendVOList = new ArrayList<>();
 	
 	private String cmId;			//다우기술 cmId
-	
+
+	private String send_adYn;			//선거문자 체크
+
 
 }
src/main/java/itn/let/mjo/msgcampain/service/MjonCandidateService.java
--- src/main/java/itn/let/mjo/msgcampain/service/MjonCandidateService.java
+++ src/main/java/itn/let/mjo/msgcampain/service/MjonCandidateService.java
@@ -2,59 +2,79 @@
 
 import java.util.List;
 
+import egovframework.rte.fdl.cmmn.exception.FdlException;
+import itn.com.cmm.RestResponse;
 import itn.let.mjo.msg.service.MjonMsgVO;
 
 public interface MjonCandidateService {
 
 	// 선거문자 후보자 정보 불러오기
-		public MjonCandidateVO selectCandidateDataInfo(String userId) throws Exception;
-		
-		// 선거문자 후보자 등록 처리
-		public int insertCandidateDataInfo(MjonCandidateVO mjonCandidateVO) throws Exception;
-		
-		// 선거문자 후보자 정보 수정
-		public int updateCandidateDataInfo(MjonCandidateVO mjonCandidateVO) throws Exception;
-		
-		// 선거문자 후보자 삭제 처리
-		public int deleteCandidateDataInfo(MjonCandidateVO mjonCandidateVO) throws Exception;
-		
-		// 선거문자 후보자 등록/수정시 회원정보 테이블 세금계산서 정보 수정해주기
-		public int updateTaxBillMemberInfo(MjonCandidateVO mjonCandidateVO) throws Exception;
-		
-		//선거문자 20건 발송 전체 수신목록 입력
-		public int insertCandidateTWCallToData(List<MjonCandidateTWVO> mjonCandidateTWVO) throws Exception;
-		
-		//선거문자 20건 기존 등록 수신목록 모두 취소 시키기
-		public int updateCandidateTWCallToDataCancel(String mberId) throws Exception;
-		
-		//선거문자 20건 회원 Call_seq 최대값 불러오기
-		public int selectCandidateTWMaxCallSeq(String mberId) throws Exception;
-		
-		//선거문자 20건 수신목록 20개 불러오기 페이징 처리
-		public List<?> selectCampainTWCalltoList(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
-		
-		//선거문자 20건 수신목록 초기화 기능 - 등록된 수신목록 send_flag를 C로 변경 처리함.
-		public int updateMsgTWCallToListResetByMberId(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
-		
-		//선거문자 20건 수신목록 선택 삭제기능
-		public int updateMsgTWCallToListChkDel(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
-		
-		//선거문자 20건 수신목록 건수 표시 정보 조회(전체건수, 발송완료 건수, 미방송 건수)
-		public MjonCandidateTWVO selectMsgTWCallToTotCount(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
-		
-		//선거문자 20건 받는사람 정보 단건추가 진행 - 번호추가 기능에서 사용
-		public int insertCandidateTWCallToDataOnlyAdd(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
-		
-		//선거문자 20건 중복연락처 조회 
-		public int selectCandidateTWCallToDupleCnt(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
-		
-		//선거문자 20건 마지막 번호 불러오기
-		public int selectMsgCallToSeqNum(String mberId) throws Exception;
-		
-		//선거문자 20건 전송 후 CallTo 상태값 전송 완료로 변경 처리
-		public int updateMsgTWCallToListSendFlag(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
-		
-		//선거문자 대량 전송 주소록 그룹 정보 조회하기
-		public List<String> selectAddrGrpHGList(MjonMsgVO mjonMsgVO) throws Exception; 
-		
+	public MjonCandidateVO selectCandidateDataInfo(String userId) throws Exception;
+
+	// 선거문자 후보자 등록 처리
+	public int insertCandidateDataInfo(MjonCandidateVO mjonCandidateVO) throws Exception;
+
+	// 선거문자 후보자 정보 수정
+	public int updateCandidateDataInfo(MjonCandidateVO mjonCandidateVO) throws Exception;
+
+	// 선거문자 후보자 삭제 처리
+	public int deleteCandidateDataInfo(MjonCandidateVO mjonCandidateVO) throws Exception;
+
+	// 선거문자 후보자 등록/수정시 회원정보 테이블 세금계산서 정보 수정해주기
+	public int updateTaxBillMemberInfo(MjonCandidateVO mjonCandidateVO) throws Exception;
+
+	//선거문자 20건 발송 전체 수신목록 입력
+	public int insertCandidateTWCallToData(List<MjonCandidateTWVO> mjonCandidateTWVO) throws Exception;
+
+	//선거문자 20건 기존 등록 수신목록 모두 취소 시키기
+	public int updateCandidateTWCallToDataCancel(String mberId) throws Exception;
+
+	//선거문자 20건 회원 Call_seq 최대값 불러오기
+	public int selectCandidateTWMaxCallSeq(String mberId) throws Exception;
+
+	//선거문자 20건 수신목록 20개 불러오기 페이징 처리
+	public List<?> selectCampainTWCalltoList(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
+
+	//선거문자 20건 수신목록 초기화 기능 - 등록된 수신목록 send_flag를 C로 변경 처리함.
+	public int updateMsgTWCallToListResetByMberId(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
+
+	//선거문자 20건 수신목록 선택 삭제기능
+	public int updateMsgTWCallToListChkDel(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
+
+	//선거문자 20건 수신목록 건수 표시 정보 조회(전체건수, 발송완료 건수, 미방송 건수)
+	public MjonCandidateTWVO selectMsgTWCallToTotCount(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
+
+	//선거문자 20건 받는사람 정보 단건추가 진행 - 번호추가 기능에서 사용
+	public int insertCandidateTWCallToDataOnlyAdd(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
+
+	//선거문자 20건 중복연락처 조회
+	public int selectCandidateTWCallToDupleCnt(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
+
+	//선거문자 20건 마지막 번호 불러오기
+	public int selectMsgCallToSeqNum(String mberId) throws Exception;
+
+	//선거문자 20건 전송 후 CallTo 상태값 전송 완료로 변경 처리
+	public int updateMsgTWCallToListSendFlag(MjonCandidateTWVO mjonCandidateTWVO) throws Exception;
+
+	//선거문자 대량 전송 주소록 그룹 정보 조회하기
+	public List<String> selectAddrGrpHGList(MjonMsgVO mjonMsgVO) throws Exception;
+
+	RestResponse insertMyAddrTWCallToAjax_advc(List<MjonCandidateTWJobVO> mjonCandidateTWJobVOList) throws Exception;
+
+	RestResponse selectCampainTWCalltoAdvcList(MjonCandidateTWJobVO jobVO);
+
+	RestResponse chkTmpJobStatus(String userId);
+
+	RestResponse deleteCandidateTWCallToData(MjonCandidateTWJobVO jobVO);
+
+	RestResponse updateSendResultAfterSend(MjonCandidateTWVO mjonCandidateTWVO);
+
+
+	MjonCandidateTWJobVO selectMjCampainTmpJobByUserIdAndJobStatus(String userId);
+
+	RestResponse updateCampainJobStatus(MjonCandidateTWJobVO jobVO);
+
+	RestResponse insertMjCampainTmpJob(MjonCandidateTWJobVO mjonCandidateTWJob) throws FdlException;
+
+	RestResponse updateMjCampainTmpJob(MjonCandidateTWJobVO mjonCandidateTWJob);
 }
 
src/main/java/itn/let/mjo/msgcampain/service/MjonCandidateTWJobVO.java (added)
+++ src/main/java/itn/let/mjo/msgcampain/service/MjonCandidateTWJobVO.java
@@ -0,0 +1,42 @@
+package itn.let.mjo.msgcampain.service;
+
+import itn.let.uss.umt.service.UserDefaultVO;
+import lombok.*;
+import lombok.experimental.SuperBuilder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Getter
+@Setter
+@ToString
+@NoArgsConstructor
+@AllArgsConstructor
+public class MjonCandidateTWJobVO extends MjonCandidateTWVO{
+
+
+	private String tmpJobId;            // 작업 ID (PK)
+	private String jobStatus;         // 작업 상태 (P:처리중, C:완료, D:삭제)
+	private Long totalCount;          // 전체 대상 건수 (예: 300,000건)
+
+	/** 처리중 (데이터 저장 진행 중) */
+	public static final String STATUS_PROCESSING = "P";
+
+	/** 완료 (모든 데이터 저장 완료) */
+	public static final String STATUS_COMPLETE = "C";
+
+	/** 삭제 (작업 무효 처리 또는 삭제 상태) */
+	public static final String STATUS_DELETE = "D";
+
+
+	@Builder
+	public MjonCandidateTWJobVO(String mberId, String tmpJobId, String jobStatus, Long totalCount) {
+		this.setMberId(mberId);
+		this.tmpJobId = tmpJobId;
+		this.jobStatus = jobStatus;
+		this.totalCount = totalCount;
+	}
+
+}
+
+
src/main/java/itn/let/mjo/msgcampain/service/MjonCandidateTWVO.java
--- src/main/java/itn/let/mjo/msgcampain/service/MjonCandidateTWVO.java
+++ src/main/java/itn/let/mjo/msgcampain/service/MjonCandidateTWVO.java
@@ -1,9 +1,17 @@
 package itn.let.mjo.msgcampain.service;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import itn.let.uss.umt.service.UserDefaultVO;
+import lombok.*;
+import lombok.experimental.SuperBuilder;
 
+@Getter
+@Setter
+@ToString
+@NoArgsConstructor
+@AllArgsConstructor
 public class MjonCandidateTWVO extends UserDefaultVO{
 
 	/**
@@ -16,6 +24,7 @@
 	private String mberId;
 	private int callSeq;
 	private String callTo;
+	private String callNm;
 	private List<String> callToList;
 	private String[] callToArr;
 	private String sendFlag;
@@ -28,98 +37,9 @@
 	private int sendComplete;
 	private int sendReady;
 	private int totCallToCnt;
-	
-	public int getCampainTmpId() {
-		return campainTmpId;
-	}
-	public void setCampainTmpId(int campainTmpId) {
-		this.campainTmpId = campainTmpId;
-	}
 
-	public List<Integer> getCampainTmpIdList() {
-		return campainTmpIdList;
-	}
-	public void setCampainTmpIdList(List<Integer> campainTmpIdList) {
-		this.campainTmpIdList = campainTmpIdList;
-	}
-	public String getMberId() {
-		return mberId;
-	}
-	public void setMberId(String mberId) {
-		this.mberId = mberId;
-	}
-	public int getCallSeq() {
-		return callSeq;
-	}
-	public void setCallSeq(int callSeq) {
-		this.callSeq = callSeq;
-	}
-	public String getCallTo() {
-		return callTo;
-	}
-	public void setCallTo(String callTo) {
-		this.callTo = callTo;
-	}
-	public List<String> getCallToList() {
-		return callToList;
-	}
-	public void setCallToList(List<String> callToList) {
-		this.callToList = callToList;
-	}
-	public String[] getCallToArr() {
-		return callToArr;
-	}
-	public void setCallToArr(String[] callToArr) {
-		this.callToArr = callToArr;
-	}
-	public String getSendFlag() {
-		return sendFlag;
-	}
-	public void setSendFlag(String sendFlag) {
-		this.sendFlag = sendFlag;
-	}
-	public String getFrstRegisterId() {
-		return frstRegisterId;
-	}
-	public void setFrstRegisterId(String frstRegisterId) {
-		this.frstRegisterId = frstRegisterId;
-	}
-	public String getFrstRegistPnttm() {
-		return frstRegistPnttm;
-	}
-	public void setFrstRegistPnttm(String frstRegistPnttm) {
-		this.frstRegistPnttm = frstRegistPnttm;
-	}
-	public String getLastUpdtPnttm() {
-		return lastUpdtPnttm;
-	}
-	public void setLastUpdtPnttm(String lastUpdtPnttm) {
-		this.lastUpdtPnttm = lastUpdtPnttm;
-	}
-	public String getLastUpdusrId() {
-		return lastUpdusrId;
-	}
-	public void setLastUpdusrId(String lastUpdusrId) {
-		this.lastUpdusrId = lastUpdusrId;
-	}
-	public int getSendComplete() {
-		return sendComplete;
-	}
-	public void setSendComplete(int sendComplete) {
-		this.sendComplete = sendComplete;
-	}
-	public int getSendReady() {
-		return sendReady;
-	}
-	public void setSendReady(int sendReady) {
-		this.sendReady = sendReady;
-	}
-	public int getTotCallToCnt() {
-		return totCallToCnt;
-	}
-	public void setTotCallToCnt(int totCallToCnt) {
-		this.totCallToCnt = totCallToCnt;
-	}
+	private List<String> successPhones = new ArrayList<>();
+	private List<String> failPhones = new ArrayList<>();
 
 	
 }
 
src/main/java/itn/let/mjo/msgcampain/service/MjonMsgCampainDataService.java (added)
+++ src/main/java/itn/let/mjo/msgcampain/service/MjonMsgCampainDataService.java
@@ -0,0 +1,10 @@
+package itn.let.mjo.msgcampain.service;
+
+import itn.let.mail.service.StatusResponse;
+import itn.let.mjo.msg.service.MjonMsgVO;
+
+import javax.servlet.http.HttpServletRequest;
+
+public interface MjonMsgCampainDataService {
+    StatusResponse sendMsgData_advc(MjonMsgVO mjonMsgVO, HttpServletRequest request);
+}
src/main/java/itn/let/mjo/msgcampain/service/impl/MjonCandidateDAO.java
--- src/main/java/itn/let/mjo/msgcampain/service/impl/MjonCandidateDAO.java
+++ src/main/java/itn/let/mjo/msgcampain/service/impl/MjonCandidateDAO.java
@@ -3,6 +3,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import itn.let.mjo.msgcampain.service.MjonCandidateTWJobVO;
 import org.springframework.stereotype.Repository;
 
 import egovframework.rte.psl.dataaccess.EgovAbstractDAO;
@@ -42,6 +43,10 @@
 	//선거문자 20건 발송 전체 수신목록 입력
 	public int insertCandidateTWCallToData(List<MjonCandidateTWVO> mjonCandidateTWVO) throws Exception{
 		return update("mjonCandidateDAO.insertCandidateTWCallToData", mjonCandidateTWVO);
+	}	//선거문자 20건 발송 전체 수신목록 입력
+
+	public int insertCandidateTWCallToData_advc(List<MjonCandidateTWJobVO> mjonCandidateTWJobVOList) throws Exception{
+		return update("mjonCandidateDAO.insertCandidateTWCallToData_advc", mjonCandidateTWJobVOList);
 	}
 	
 	public int updateCandidateTWCallToDataCancel(String mberId) throws Exception{
@@ -225,5 +230,45 @@
 		
 		return resultList;
 	}
-	
+
+	public List<MjonCandidateTWJobVO> selectCampainTWCalltoList_advc(MjonCandidateTWJobVO jobVO) {
+		return (List<MjonCandidateTWJobVO>) list("mjonCandidateDAO.selectCampainTWCalltoList_advc", jobVO);
+	}
+
+	public void deleteCandidateTWCallToData(MjonCandidateTWJobVO jobVO) {
+		update("mjonCandidateDAO.deleteCandidateTWCallToData", jobVO);
+	}
+
+	public int updateFailSendResultAfterSend(MjonCandidateTWVO mjonCandidateTWVO) {
+		return update("mjonCandidateDAO.updateFailSendResultAfterSend", mjonCandidateTWVO);
+	}
+
+	public int updateSuccessSendResultAfterSend(MjonCandidateTWVO mjonCandidateTWVO) {
+		return update("mjonCandidateDAO.updateSuccessSendResultAfterSend", mjonCandidateTWVO);
+	}
+
+    public void insertMjCampainTmpJob(MjonCandidateTWJobVO jobVO) {
+
+		insert("mjonCandidateDAO.insertMjCampainTmpJob", jobVO);
+    }
+
+	public void updateCampainTmpJob(MjonCandidateTWJobVO jobVO) {
+		update("mjonCandidateDAO.updateCampainTmpJob", jobVO);
+	}
+
+	public MjonCandidateTWJobVO selectMjCampainTmpJobByUserIdAndJobStatus(String userId) {
+		return (MjonCandidateTWJobVO) select("mjonCandidateDAO.selectMjCampainTmpJobByUserIdAndJobStatus", userId);
+	}
+
+	public MjonCandidateTWJobVO chkTmpJobStatus(String mberId) {
+		return (MjonCandidateTWJobVO) select("mjonCandidateDAO.chkTmpJobStatus", mberId);
+	}
+
+	public void updateMjCampainTmpJob(MjonCandidateTWJobVO jobVO) {
+		update("mjonCandidateDAO.updateMjCampainTmpJob", jobVO);
+	}
+
+	public MjonCandidateTWJobVO selectMjCampainTmpJob(MjonCandidateTWJobVO mjonCandidateTWJob) {
+		return (MjonCandidateTWJobVO) select("mjonCandidateDAO.selectMjCampainTmpJob", mjonCandidateTWJob);
+	}
 }
src/main/java/itn/let/mjo/msgcampain/service/impl/MjonCandidateServiceImpl.java
--- src/main/java/itn/let/mjo/msgcampain/service/impl/MjonCandidateServiceImpl.java
+++ src/main/java/itn/let/mjo/msgcampain/service/impl/MjonCandidateServiceImpl.java
@@ -1,10 +1,19 @@
 package itn.let.mjo.msgcampain.service.impl;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.annotation.Resource;
 
+import egovframework.rte.fdl.cmmn.exception.FdlException;
+import egovframework.rte.fdl.idgnr.EgovIdGnrService;
+import itn.com.cmm.MjonMsgSendVO;
+import itn.com.cmm.RestResponse;
+import itn.let.mjo.msgcampain.service.MjonCandidateTWJobVO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
 import org.springframework.stereotype.Service;
 
 import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
@@ -13,12 +22,17 @@
 import itn.let.mjo.msgcampain.service.MjonCandidateTWVO;
 import itn.let.mjo.msgcampain.service.MjonCandidateVO;
 
+@Slf4j
 @Service("mjonCandidateService")
 public class MjonCandidateServiceImpl  extends EgovAbstractServiceImpl implements MjonCandidateService{
 
 	@Resource(name="mjonCandidateDAO")
 	private MjonCandidateDAO mjonCandidateDAO;
-	
+
+
+	@Resource(name = "mjCampainTmpJobIdGnrService")
+	private EgovIdGnrService mjCampainTmpJobId;
+
 	public MjonCandidateVO selectCandidateDataInfo(String userId) throws Exception{
 		
 		return mjonCandidateDAO.selectCandidateDataInfo(userId);
@@ -43,7 +57,185 @@
 	public int updateTaxBillMemberInfo(MjonCandidateVO mjonCandidateVO) throws Exception{
 		return mjonCandidateDAO.updateTaxBillMemberInfo(mjonCandidateVO);
 	}
-	
+
+
+	@Override
+	public RestResponse insertMyAddrTWCallToAjax_advc(List<MjonCandidateTWJobVO> mjonCandidateTWJobVOList) throws Exception {
+
+
+		mjonCandidateDAO.insertCandidateTWCallToData_advc(mjonCandidateTWJobVOList);
+
+		MjonCandidateTWJobVO mjonCandidateTWJobVO = mjonCandidateTWJobVOList.get(0);
+
+		MjonCandidateTWJobVO jobVO = MjonCandidateTWJobVO.builder()
+				.tmpJobId(mjonCandidateTWJobVO.getTmpJobId())
+				.jobStatus("C")
+				.build();
+
+
+		mjonCandidateDAO.updateCampainTmpJob(jobVO);
+
+
+		return RestResponse.builder()
+				.status(HttpStatus.OK) // 200, Series.SUCCESSFUL, "OK"
+				.msg("저장성공")
+				.data("")
+				.build();
+	}
+
+	@Override
+	public RestResponse selectCampainTWCalltoAdvcList(MjonCandidateTWJobVO jobVO) {
+
+
+
+		List<MjonCandidateTWJobVO> mjonCandidateTWJobVO = mjonCandidateDAO.selectCampainTWCalltoList_advc(jobVO);
+
+		return RestResponse.builder()
+				.status(HttpStatus.OK) // 200, Series.SUCCESSFUL, "OK"
+				.msg("조회 성공")
+				.data(mjonCandidateTWJobVO)
+				.build();
+	}
+
+	@Override
+	public RestResponse chkTmpJobStatus(String userId) {
+
+		MjonCandidateTWJobVO jobVO = mjonCandidateDAO.chkTmpJobStatus(userId);
+
+
+		return RestResponse.builder()
+				.status(HttpStatus.OK) // 200, Series.SUCCESSFUL, "OK"
+				.msg("조회 성공")
+				.data(jobVO)
+				.build();
+	}
+
+	@Override
+	public RestResponse deleteCandidateTWCallToData(MjonCandidateTWJobVO jobVO) {
+
+
+//
+//		MjonCandidateTWJobVO jobVO = MjonCandidateTWJobVO.builder()
+//				.mberId(mjonCandidateTWJobVOList.get(0).getMberId())
+//				.tmpJobId(nextJobId)
+//				.jobStatus(MjonCandidateTWJobVO.STATUS_PROCESSING)
+//				.totalCount((long) mjonCandidateTWJobVOList.size())
+//				.build();
+
+		mjonCandidateDAO.deleteCandidateTWCallToData(jobVO);
+
+		jobVO.setJobStatus("D");
+		mjonCandidateDAO.updateCampainTmpJob(jobVO);
+
+		return RestResponse.builder()
+				.status(HttpStatus.OK) // 200, Series.SUCCESSFUL, "OK"
+				.msg("초기화 성공")
+				.data(null)
+				.build();
+	}
+
+	@Override
+	public RestResponse updateSendResultAfterSend(MjonCandidateTWVO mjonCandidateTWVO) {
+
+		int failCnt = 0;
+		int successCnt = 0;
+
+		if(mjonCandidateTWVO.getFailPhones() != null && !mjonCandidateTWVO.getFailPhones().isEmpty()){
+			failCnt = mjonCandidateDAO.updateFailSendResultAfterSend(mjonCandidateTWVO);
+		}
+
+		if(mjonCandidateTWVO.getSuccessPhones() != null && !mjonCandidateTWVO.getSuccessPhones().isEmpty()){
+			successCnt = mjonCandidateDAO.updateSuccessSendResultAfterSend(mjonCandidateTWVO);
+		}
+
+		Map<String, Object> resultMap = new HashMap<String, Object>();
+		resultMap.put("failCnt", failCnt);
+		resultMap.put("successCnt", successCnt);
+		resultMap.put("totalCnt", failCnt + successCnt);
+
+		return RestResponse.builder()
+				.status(HttpStatus.OK)
+				.msg("발송 결과 업데이트 완료")
+				.data(resultMap)
+				.build();
+	}
+
+	@Override
+	public MjonCandidateTWJobVO selectMjCampainTmpJobByUserIdAndJobStatus(String userId) {
+		return mjonCandidateDAO.selectMjCampainTmpJobByUserIdAndJobStatus(userId);
+	}
+
+	@Override
+	public RestResponse updateCampainJobStatus(MjonCandidateTWJobVO jobVO) {
+
+		mjonCandidateDAO.updateCampainTmpJob(jobVO);
+
+		return RestResponse.builder()
+				.status(HttpStatus.OK)
+				.msg("JOB update 완료 : "+jobVO.getJobStatus())
+				.data("")
+				.build();
+	}
+
+	@Override
+	public RestResponse insertMjCampainTmpJob(MjonCandidateTWJobVO mjonCandidateTWJob) throws FdlException {
+
+
+		String nextJobId = mjCampainTmpJobId.getNextStringId();
+
+		mjonCandidateTWJob.setTmpJobId(nextJobId);
+		mjonCandidateTWJob.setJobStatus(MjonCandidateTWJobVO.STATUS_PROCESSING);
+
+
+		mjonCandidateDAO.insertMjCampainTmpJob(mjonCandidateTWJob);
+
+		return RestResponse.builder()
+				.status(HttpStatus.OK)
+				.msg("JOB insert 완료 : "+nextJobId)
+				.data(nextJobId)
+				.build();
+	}
+
+	@Override
+	public RestResponse updateMjCampainTmpJob(MjonCandidateTWJobVO jobVO) {
+
+
+
+
+		MjonCandidateTWJobVO returnJobVO = mjonCandidateDAO.selectMjCampainTmpJob(jobVO);
+
+		long returnCnt = returnJobVO.getTotalCount() != null ? returnJobVO.getTotalCount() : 0L;
+		long jobCnt = jobVO.getTotalCount() != null ? jobVO.getTotalCount() : 0L;
+
+		long totCnt = returnCnt + jobCnt;
+
+
+		if(totCnt > 300000){
+
+			return RestResponse.builder()
+					.status(HttpStatus.BAD_REQUEST)
+					.msg("30만건 이상은 수신자목록으로 추가할 수 없습니다.")
+					.data(null)
+					.build();
+		}
+
+		/*총 카운트 + update*/
+		/*총 카운트 + update*/
+		/*총 카운트 + update*/
+		/*총 카운트 + update*/
+		/*총 카운트 + update*/
+		/*총 카운트 + update*/
+
+		jobVO.setJobStatus(MjonCandidateTWJobVO.STATUS_PROCESSING);
+		mjonCandidateDAO.updateMjCampainTmpJob(jobVO);
+
+		return RestResponse.builder()
+				.status(HttpStatus.OK)
+				.msg("JOB insert 완료 : "+jobVO.getTmpJobId())
+				.data(null)
+				.build();
+	}
+
 	//선거문자 20건 발송 전체 수신목록 입력
 	public int insertCandidateTWCallToData(List<MjonCandidateTWVO> mjonCandidateTWVO) throws Exception{
 		
@@ -331,5 +523,6 @@
 		
 		return resultList;
 	}
-	
+
+
 }
 
src/main/java/itn/let/mjo/msgcampain/service/impl/MjonMsgCampainDataServiceImpl.java (added)
+++ src/main/java/itn/let/mjo/msgcampain/service/impl/MjonMsgCampainDataServiceImpl.java
@@ -0,0 +1,25 @@
+package itn.let.mjo.msgcampain.service.impl;
+
+import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
+import itn.let.mail.service.StatusResponse;
+import itn.let.mjo.msg.service.MjonMsgVO;
+import itn.let.mjo.msgcampain.service.MjonCandidateService;
+import itn.let.mjo.msgcampain.service.MjonCandidateTWVO;
+import itn.let.mjo.msgcampain.service.MjonCandidateVO;
+import itn.let.mjo.msgcampain.service.MjonMsgCampainDataService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+
+@Service("mjonMsgCampainDataService")
+public class MjonMsgCampainDataServiceImpl extends EgovAbstractServiceImpl implements MjonMsgCampainDataService {
+
+
+	@Override
+	public StatusResponse sendMsgData_advc(MjonMsgVO mjonMsgVO, HttpServletRequest request) {
+		return null;
+	}
+}
src/main/java/itn/let/mjo/msgcampain/web/MjonMsgCampainDataController.java
--- src/main/java/itn/let/mjo/msgcampain/web/MjonMsgCampainDataController.java
+++ src/main/java/itn/let/mjo/msgcampain/web/MjonMsgCampainDataController.java
@@ -17,6 +17,7 @@
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 
+import itn.let.mjo.msgcampain.service.MjonMsgCampainDataService;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.hssf.usermodel.HSSFCell;
 import org.apache.poi.hssf.usermodel.HSSFRow;
@@ -131,9 +132,12 @@
 	
 	@Resource (name = "AddrGroupService")
 	private AddrGroupService addrGroupService;
-	
+
 	@Resource(name = "mjonCandidateService")
-    private MjonCandidateService mjonCandidateService;
+	private MjonCandidateService mjonCandidateService;
+
+	@Resource(name = "mjonMsgCampainDataService")
+	private MjonMsgCampainDataService mjonMsgCampainDataService;
 	
 	@Resource(name = "EgovCmmUseService")
 	private EgovCmmUseService cmmUseService;
@@ -203,17 +207,15 @@
 			, CateCode cateCode
 			, HttpServletRequest request
 			, ModelMap model) throws Exception{
-		
-		
 
-		// 요청의 호스트명을 가져오기
-		String hostName = request.getServerName();
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
 
-		// 외부에서 선거발송 페이지로 들어오는걸 막음
-		// 20250102 이호영
-		/*if (!"localhost".equals(hostName) && !"119.193.215.98".equals(hostName)) {
-			return "redirect:/web/mjon/msgdata/selectMsgDataView.do";
-		}*/
+		if(userId == "") {
+			return "redirect:/web/user/login/login.do";
+		}
+
+		model.addAttribute("loginVO", loginVO);
 
 		String categoryType = cateCode.getCateType();
 		
@@ -237,10 +239,7 @@
 		if(letterVO.getPageUnit() != 10) {
 			letterVO.setPageUnit(letterVO.getPageUnit());
 		}
-		
-		//로그인 권한정보 불러오기
-		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
-		model.addAttribute("loginVO", loginVO);
+
 		
 		for(int i=0 ; i < cateConfList.size(); i++) {
 			if("선거".equals(cateConfList.get(i).getCateNm())) {
@@ -256,11 +255,8 @@
 		//주소록에서 전체전송 넘어오는 파라미터
 		if("Y".equals(searchVO.getMoveAddrAllFlag())) {
 			AddrVO addrVO = new AddrVO();
-			
-			String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
-			if(userId != "") {
-				addrVO.setMberId(userId);
-			} 
+
+			addrVO.setMberId(userId);
 			addrVO.setRecordCountPerPage(100000);
 			addrVO.setFirstIndex(0);
 			addrVO.setSearchAddrGrpId(request.getParameter("searchAddrGrpId"));
@@ -413,7 +409,7 @@
 		//2.사용자 개인 단가 정보 불러오기
 		MberManageVO mberManageVO = new MberManageVO(); 
 		
-		if(!userId.equals("") && !author.equals("ROLE_ADMIN")) {
+		if(!"".equals(userId) && !"ROLE_ADMIN".equals(author)) {
 			
 			mberManageVO = mjonMsgDataService.selectMberManageInfo(userId);
 			searchVO.setUserId(userId);
@@ -642,7 +638,7 @@
     		
         	MjonVOParamXssValues XssParam = new MjonVOParamXssValues();
         	
-        	int XssCnt = XssParam.buildUri(mjonCandidateVO);
+        	/*int XssCnt = XssParam.buildUri(mjonCandidateVO);
         	
         	if(XssCnt > 0) {
         		
@@ -650,7 +646,7 @@
         		modelAndView.addObject("message", "후보자 등록 정보에 잘못된 문자열이 있습니다.");
         		return modelAndView;
         		
-        	}
+        	}*/
         	
     		int resultCnt = 0;
     		String dataType = mjonCandidateVO.getDataType();
@@ -673,8 +669,7 @@
     		}
     		
     		/*
-    		 * 20231122 우영두 수정
-    		 * 후보자 등록/수정시 후보자 정보에 대한 세금계산서 정보가 등록되어야 함. 
+    		 * 후보자 등록/수정시 후보자 정보에 대한 세금계산서 정보가 등록되어야 함.
     		 * 선거문자를 이용하는 개인 회원은 세금계산서를 후보자에 대한 것을 신청하기 때문에 회원정보의 세금계산서 정보를 업데이트 하도록 함.
     		 * 
     		 * */
@@ -761,8 +756,7 @@
         	}
     		
         	MjonVOParamXssValues XssParam = new MjonVOParamXssValues();
-        	
-        	int XssCnt = XssParam.buildUri(mjonCandidateVO);
+
         	
     		int resultCnt = 0;
     		
@@ -2034,8 +2028,29 @@
 		
 		return "web/msgcampain/MyMsgListAjax";
 	}
-	
-	
+
+
+	/**
+	 *
+	 * @return	"/web/mjon/msgcampain/sendMsgDataAjax_advc.do"
+	 * @throws Exception
+	 */
+	@RequestMapping(value = "/web/mjon/msgcampain/sendMsgDataAjax_advc.do")
+	public ResponseEntity<StatusResponse> sendMsgData_advc(
+			@RequestBody MjonMsgVO mjonMsgVO,
+			HttpServletRequest request,
+			ModelMap model) throws Exception {
+		System.out.println(" :: msgcampain sendMsgData_advc :: ");
+
+
+		// 디버깅 출력
+//	    System.out.println("mjonMsgVO : " + mjonMsgVO.getMjonMsgSendVOList().toString());
+//	    System.out.println("mjonMsgVO : " + mjonMsgVO.getMjonMsgSendVOList().size());
+
+//		return ResponseEntity.ok().body(mjonMsgCampainDataService.sendMsgData_advc(mjonMsgVO, request)) ;
+		return ResponseEntity.ok().body(mjonMsgDataService.sendMsgData_advc(mjonMsgVO, request)) ;
+
+	}
 	
     /**
      * 선거문자 문자 발송 화면 
src/main/java/itn/let/mjo/msgcampain/web/MjonMsgCampainTWDataController.java
--- src/main/java/itn/let/mjo/msgcampain/web/MjonMsgCampainTWDataController.java
+++ src/main/java/itn/let/mjo/msgcampain/web/MjonMsgCampainTWDataController.java
@@ -16,6 +16,9 @@
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 
+import itn.com.cmm.*;
+import itn.let.mjo.msgcampain.service.MjonCandidateTWJobVO;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.hssf.usermodel.HSSFCell;
 import org.apache.poi.hssf.usermodel.HSSFRow;
@@ -31,9 +34,12 @@
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.ModelMap;
 import org.springframework.web.bind.annotation.ModelAttribute;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.multipart.MultipartFile;
@@ -45,10 +51,6 @@
 import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;
 import egovframework.rte.psl.dataaccess.util.EgovMap;
 import egovframework.rte.ptl.mvc.tags.ui.pagination.PaginationInfo;
-import itn.com.cmm.ComDefaultCodeVO;
-import itn.com.cmm.EgovMessageSource;
-import itn.com.cmm.JsonResult;
-import itn.com.cmm.LoginVO;
 import itn.com.cmm.service.EgovCmmUseService;
 import itn.com.cmm.service.EgovFileMngService;
 import itn.com.cmm.service.EgovFileMngUtil;
@@ -93,6 +95,7 @@
 import itn.let.uss.umt.service.UserManageVO;
 import itn.let.utl.fcc.service.EgovCryptoUtil;
 
+@Slf4j
 @Controller
 public class MjonMsgCampainTWDataController {
 
@@ -192,25 +195,21 @@
 			, CateCode cateCode
 			, HttpServletRequest request
 			, ModelMap model) throws Exception{
-		
-		
+
+
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+
+		if(userId == "") {
+			return "redirect:/web/user/login/login.do";
+		}
+
+		//로그인 권한정보 불러오기
+		model.addAttribute("loginVO", loginVO);
 
 		// 요청의 호스트명을 가져오기
-		String hostName = request.getServerName();
+//		String hostName = request.getServerName();
 
-		// 외부에서 선거발송 페이지로 들어오는걸 막음
-		// 20250102 이호영
-		System.out.println("hostName :: "+ hostName);
-		System.out.println("hostName :: "+ hostName);
-		System.out.println("hostName :: "+ hostName);
-		System.out.println("hhhhhhhh hostName :: "+ hostName);
-		System.out.println("hostName :: "+ hostName);
-		System.out.println("hostName :: "+ hostName);
-//		if (!"localhost".equals(hostName) 
-//			&& !"119.193.215.98".equals(hostName))
-//		{
-//				return "redirect:/web/mjon/msgdata/selectMsgDataView.do";
-//		}
 		
 		String categoryType = cateCode.getCateType();
 		
@@ -234,10 +233,7 @@
 		if(letterVO.getPageUnit() != 10) {
 			letterVO.setPageUnit(letterVO.getPageUnit());
 		}
-		
-		//로그인 권한정보 불러오기
-		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
-		model.addAttribute("loginVO", loginVO);
+
 		
 		for(int i=0 ; i < cateConfList.size(); i++) {
 			if("선거".equals(cateConfList.get(i).getCateNm())) {
@@ -253,11 +249,8 @@
 		//주소록에서 선택시 넘어오는 파라미터
 		if("Y".equals(searchVO.getMoveAddrAllFlag())) {
 			AddrVO addrVO = new AddrVO();
-			
-			String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
-			if(userId != "") {
-				addrVO.setMberId(userId);
-			} 
+
+			addrVO.setMberId(userId);
 			addrVO.setRecordCountPerPage(100000);
 			addrVO.setFirstIndex(0);
 			addrVO.setSearchAddrGrpId(request.getParameter("searchAddrGrpId"));
@@ -292,6 +285,8 @@
 		model.addAttribute("resultPhoList", resultPhoList);
 		paginationInfo.setTotalRecordCount( resultPhoList.size()> 0 ? ((Long)((EgovMap)resultPhoList.get(0)).get("totCnt")).intValue() : 0);
 		model.addAttribute("paginationInfo", paginationInfo);
+
+
 		
 		//발송결과 문자 재전송에서 넘어오는 경우 파마리터 전달
 		List<String> temp = searchVO.getMsgSeqList();
@@ -326,7 +321,8 @@
     	LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
     	String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
     	String author = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getAuthority());
-    	
+
+
 		String categoryType = cateCode.getCateType();
 		
 		if(categoryType == null) {
@@ -500,25 +496,23 @@
 		
 		//선거 후보자 정보 불러오기
 		MjonCandidateVO mjonCandidateVO = new MjonCandidateVO();
-		
-		if(userId != ""){
-			
-			mjonCandidateVO = mjonCandidateService.selectCandidateDataInfo(userId);
-			
-			//String cryptText = egovCryptoUtil.encrypt(plainText);
 
-			if(mjonCandidateVO != null) {
-				
-				// 주민번호 복호화 하기
-				String regidentNo1 = egovCryptoUtil.decrypt(mjonCandidateVO.getRegidentNo1());
-		    	String regidentNo2 = egovCryptoUtil.decrypt(mjonCandidateVO.getRegidentNo2());
-		    	
-		    	mjonCandidateVO.setRegidentNo1(regidentNo1);
-		    	mjonCandidateVO.setRegidentNo2(regidentNo2);
-				
-			}
 			
+		mjonCandidateVO = mjonCandidateService.selectCandidateDataInfo(userId);
+
+		//String cryptText = egovCryptoUtil.encrypt(plainText);
+
+		if(mjonCandidateVO != null) {
+
+			// 주민번호 복호화 하기
+			String regidentNo1 = egovCryptoUtil.decrypt(mjonCandidateVO.getRegidentNo1());
+			String regidentNo2 = egovCryptoUtil.decrypt(mjonCandidateVO.getRegidentNo2());
+
+			mjonCandidateVO.setRegidentNo1(regidentNo1);
+			mjonCandidateVO.setRegidentNo2(regidentNo2);
+
 		}
+
 		
 		model.addAttribute("mjonCandidateVO", mjonCandidateVO);
 		
@@ -594,14 +588,63 @@
 		paginationInfo.setTotalRecordCount( resultPhoList.size()> 0 ? ((Long)((EgovMap)resultPhoList.get(0)).get("totCnt")).intValue() : 0);
 		model.addAttribute("paginationInfo", paginationInfo);
 		model.addAttribute("mberManageVO", mberManageVO);
-		
+
+
+//		MjonCandidateTWJobVO mjonCandidateTWJobVO = mjonCandidateService.selectMjCampainTmpJobByUserIdAndJobStatus(userId);
+
+//		model.addAttribute("jobVO", mjonCandidateTWJobVO);
+
 		//기존 작업하던 수신목록 정보가 있는지 확인
 		int callSeq = mjonCandidateService.selectMsgCallToSeqNum(userId);
 		model.addAttribute("callSeq", callSeq);
 		
 		return "web/msgcampain/tw/MsgTWDataSMLView";
 	}
-	
+
+
+	//선거문자 20건 받는사람 목록 불러오기
+	@ResponseBody
+	@RequestMapping(value="/web/mjon/msgcampain/selectMsgTWCallToListAjax_advc.do")
+	public ResponseEntity<?> selectMsgTWCallToListAjax_advc(ModelMap model,
+	@RequestBody MjonCandidateTWJobVO jobVO) throws Exception{
+
+
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+			if(StringUtils.isEmpty(userId)) {	//KISA 보안취약점 조치 (2018-12-10, 이정은)
+				return ResponseEntity.ok(
+						RestResponse.builder()
+								.status(HttpStatus.UNAUTHORIZED) // 401 권한 인증 에러
+								.msg("로그인을 하셔야 이용 가능합니다.")
+								.build()
+				);
+			}
+
+		jobVO.setMberId(userId);
+			log.info(" .getTmpJobId() :: [{}]", jobVO.getTmpJobId());
+		return ResponseEntity.ok(mjonCandidateService.selectCampainTWCalltoAdvcList(jobVO));
+	}
+
+
+	//선거문자 20건 받는사람 목록 불러오기
+	@RequestMapping(value="/web/mjon/msgcampain/chkTmpJobStatusAjax.do")
+	public ResponseEntity<?> chkTmpJobStatusAjax(ModelMap model) throws Exception{
+
+
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+		if(StringUtils.isEmpty(userId)) {	//KISA 보안취약점 조치 (2018-12-10, 이정은)
+			return ResponseEntity.ok(
+					RestResponse.builder()
+							.status(HttpStatus.UNAUTHORIZED) // 401 권한 인증 에러
+							.msg("로그인을 하셔야 이용 가능합니다.")
+							.build()
+			);
+		}
+
+		return ResponseEntity.ok(mjonCandidateService.chkTmpJobStatus(userId));
+	}
+
 	//선거문자 20건 받는사람 목록 불러오기
 	@RequestMapping(value="/web/mjon/msgcampain/selectMsgTWCallToListAjax.do")
 	public String selectMsgTWCallToListAjax(MjonCandidateTWVO mjonCandidateTWVO, ModelMap model, RedirectAttributes redirectAttributes) throws Exception{
@@ -644,8 +687,114 @@
 		
 		return "web/msgcampain/tw/MsgTWDataCallToListView";
 	}
-	
-	
+
+
+
+	@ResponseBody
+	@RequestMapping(value="/web/mjon/msgcampain/updateCampainJobStatus.do")
+	public ResponseEntity<?> udpateCampainJobStatus(@RequestBody MjonCandidateTWJobVO jobVO) throws Exception {
+
+
+		//로그인 권한정보 불러오기
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+
+		if(StringUtils.isEmpty(userId)) {
+			return ResponseEntity.ok(
+					RestResponse.builder()
+							.status(HttpStatus.UNAUTHORIZED) // 401 권한 인증 에러
+							.msg("로그인을 하셔야 이용 가능합니다.")
+							.build()
+			);
+		}
+
+		log.info("jobVO :: [{}] , [{}]", jobVO.getJobStatus(), jobVO.getTmpJobId());
+
+		return ResponseEntity.ok(mjonCandidateService.updateCampainJobStatus(jobVO));
+	}
+
+	@ResponseBody
+	@RequestMapping(value="/web/mjon/msgcampain/insertMyAddrTWCallToAjax_advc.do")
+	public ResponseEntity<?> findByIdQuatMgmtAjax(
+			HttpServletRequest request
+			,@RequestBody List<MjonCandidateTWJobVO> mjonCandidateTWJobList) throws Exception {
+
+
+
+		//로그인 권한정보 불러오기
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+
+		if(StringUtils.isEmpty(userId)) {
+			return ResponseEntity.ok(
+					RestResponse.builder()
+							.status(HttpStatus.UNAUTHORIZED) // 401 권한 인증 에러
+							.msg("로그인을 하셔야 이용 가능합니다.")
+							.build()
+			);
+		}
+		mjonCandidateTWJobList.forEach(item -> item.setMberId(userId));
+
+
+		return ResponseEntity.ok(mjonCandidateService.insertMyAddrTWCallToAjax_advc(mjonCandidateTWJobList));
+	}
+
+
+
+	@ResponseBody
+	@RequestMapping(value="/web/mjon/msgcampain/updateMjCampainTmpJob.do")
+	public ResponseEntity<?> updateMjCampainTmpJob(
+			HttpServletRequest request
+			,@RequestBody MjonCandidateTWJobVO mjonCandidateTWJob) throws Exception {
+
+
+
+		//로그인 권한정보 불러오기
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+
+		if(StringUtils.isEmpty(userId)) {
+			return ResponseEntity.ok(
+					RestResponse.builder()
+							.status(HttpStatus.UNAUTHORIZED) // 401 권한 인증 에러
+							.msg("로그인을 하셔야 이용 가능합니다.")
+							.build()
+			);
+
+		}
+		mjonCandidateTWJob.setMberId(userId);
+
+
+		return ResponseEntity.ok(mjonCandidateService.updateMjCampainTmpJob(mjonCandidateTWJob));
+	}
+
+	@ResponseBody
+	@RequestMapping(value="/web/mjon/msgcampain/insertMjCampainTmpJob.do")
+	public ResponseEntity<?> insertMjCampainTmpJob(
+			HttpServletRequest request
+			,@RequestBody MjonCandidateTWJobVO mjonCandidateTWJob) throws Exception {
+
+
+
+		//로그인 권한정보 불러오기
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+
+		if(StringUtils.isEmpty(userId)) {
+			return ResponseEntity.ok(
+					RestResponse.builder()
+							.status(HttpStatus.UNAUTHORIZED) // 401 권한 인증 에러
+							.msg("로그인을 하셔야 이용 가능합니다.")
+							.build()
+			);
+
+		}
+		mjonCandidateTWJob.setMberId(userId);
+
+
+		return ResponseEntity.ok(mjonCandidateService.insertMjCampainTmpJob(mjonCandidateTWJob));
+	}
+
 	@RequestMapping(value="/web/mjon/msgcampain/insertMyAddrTWCallToAjax.do")
 	public ModelAndView insertMyAddrTWCallToAjax(MjonCandidateTWVO mjonCandidateTWVO) throws Exception{
 		
@@ -784,6 +933,38 @@
 		
 		return modelAndView;
 	}
+
+	@ResponseBody
+	@RequestMapping("/web/mjon/msgcampain/updateSendFlagAfterSend.do")
+	public ResponseEntity<?>  updateSendFlagAfterSend(@RequestBody MjonCandidateTWVO mjonCandidateTWVO) {
+
+
+		//로그인 권한정보 불러오기
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+
+
+
+		if(StringUtils.isEmpty(userId)) {
+			return ResponseEntity.ok(
+					RestResponse.builder()
+							.status(HttpStatus.UNAUTHORIZED) // 401 권한 인증 에러
+							.msg("로그인을 하셔야 이용 가능합니다.")
+							.build()
+			);
+		}
+
+		mjonCandidateTWVO.setMberId(userId);
+
+		return ResponseEntity.ok(mjonCandidateService.updateSendResultAfterSend(mjonCandidateTWVO));
+	}
+
+
+
+
+
+
+
 	
 	/*
 	 * 받는사람 목록 선택 삭제 데이터 취소 처리
@@ -2648,5 +2829,29 @@
 		}
 		
 	}
+
+
+
+	@ResponseBody
+	@RequestMapping(value="/web/mjon/msgcampain/deleteCandidateTWCallToData.do")
+	public ResponseEntity<?> findByIdQuatMgmtAjax(@RequestBody MjonCandidateTWJobVO jobVO) throws Exception {
+
+
+		//로그인 권한정보 불러오기
+		LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()? (LoginVO)EgovUserDetailsHelper.getAuthenticatedUser():null;
+		String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
+
+		if(StringUtils.isEmpty(userId)) {
+			return ResponseEntity.ok(
+					RestResponse.builder()
+							.status(HttpStatus.UNAUTHORIZED) // 401 권한 인증 에러
+							.msg("로그인을 하셔야 이용 가능합니다.")
+							.build()
+			);
+		}
+
+		return ResponseEntity.ok(mjonCandidateService.deleteCandidateTWCallToData(jobVO));
+	}
+
 	
 }
src/main/java/itn/let/mjo/msgcampain/web/MjonVOParamXssValues.java
--- src/main/java/itn/let/mjo/msgcampain/web/MjonVOParamXssValues.java
+++ src/main/java/itn/let/mjo/msgcampain/web/MjonVOParamXssValues.java
@@ -103,29 +103,30 @@
 		String test_str_low= test_str.toLowerCase();
 		int cnt = 0;
 		
-		if(test_str_low.contains("union")|| 
-				test_str_low.contains("select") || 
-				test_str_low.contains("insert") || 
-				test_str_low.contains("drop") || 
-				test_str_low.contains("update") || 
-				test_str_low.contains("delete") || 
-				test_str_low.contains("join") || 
-				test_str_low.contains("from") || 
-				test_str_low.contains("where") || 
-				test_str_low.contains("substr") || 
-				test_str_low.contains("user_tables")|| 
-				test_str_low.contains("script")|| 
+		if(
+//				test_str_low.contains("union")||
+//				test_str_low.contains("select") ||
+//				test_str_low.contains("insert") ||
+//				test_str_low.contains("drop") ||
+//				test_str_low.contains("update") ||
+//				test_str_low.contains("delete") ||
+//				test_str_low.contains("join") ||
+//				test_str_low.contains("from") ||
+//				test_str_low.contains("where") ||
+//				test_str_low.contains("substr") ||
+//				test_str_low.contains("user_tables")||
+//				test_str_low.contains("script")||
 				test_str_low.contains("<")|| 
 				test_str_low.contains(">")|| 
-				test_str_low.contains("alert")|| 
-				test_str_low.contains("javascript")|| 
+//				test_str_low.contains("alert")||
+//				test_str_low.contains("javascript")||
 				test_str_low.contains("=")|| 
 				test_str_low.contains("!")|| 
-				test_str_low.contains("or")|| 
-				test_str_low.contains("user_tables")|| 
+//				test_str_low.contains("or")||
+//				test_str_low.contains("user_tables")||
 				test_str_low.contains("\\(")|| 
 				test_str_low.contains("\\)")|| 
-				test_str_low.contains("user_tables")|| 
+//				test_str_low.contains("user_tables")||
 				test_str_low.contains("&lt;") ||
 				test_str_low.contains("\"") ||
 				test_str_low.contains("%") ||
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
@@ -4,6 +4,7 @@
 
 import javax.servlet.http.HttpServletRequest;
 
+import itn.com.cmm.RestResponse;
 import itn.let.lett.service.LetterVO;
 import itn.let.mail.service.StatusResponse;
 import itn.let.mjo.addr.service.AddrDTO;
@@ -191,6 +192,7 @@
 	public MjonMsgReturnVO sendSysMsgData(MjonMsgVO mjonMsgVO, HttpServletRequest request) throws Exception;
 
 	public Boolean selectSysMsgTodaySendYn(SendLogVO sendLogVO) throws Exception;
-	
-	
+
+
+	RestResponse getBeforeCashDataAjax(String userId) throws Exception;
 }
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
@@ -18,6 +18,9 @@
 import javax.annotation.Resource;
 import javax.servlet.http.HttpServletRequest;
 
+import itn.com.cmm.RestResponse;
+import itn.let.mjo.msgcampain.service.MjonCandidateVO;
+import itn.let.mjo.msgcampain.service.impl.MjonCandidateDAO;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
@@ -142,6 +145,9 @@
 	/** userManageDAO */
 	@Resource(name = "userManageDAO")
 	private UserManageDAO userManageDAO;
+
+	@Resource(name="mjonCandidateDAO")
+	private MjonCandidateDAO mjonCandidateDAO;
 
 	@Autowired
 	private PriceAndPoint priceAndPoint;
@@ -3966,7 +3972,7 @@
 					: null;
 			userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
 
-			if (userId.equals("")) {
+			if ("".equals(userId)) {
 				return new StatusResponse(HttpStatus.BAD_REQUEST, "로그인 후 이용이 가능합니다.");
 			}
 
@@ -3994,12 +4000,49 @@
 					, "STAT_1070");
 		}
 
+
+		// 선거문자라면
+		if("C".equals(mjonMsgVO.getMsgKind()))
+		{
+			String dept = mjonMsgDataDAO.selectMberManageInfo(userId).getDept();
+
+			// 개인-p , 기업-C
+			if("c".equals(dept)){
+				log.info("\"c\".equals(dept) :: [{}]", "c".equals(dept));
+//				return StatusResponse.statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "선거문자 발송은 개인회원이 후보자 등록 후 이용 가능합니다.", "");
+				return StatusResponse.statusResponseSet(statusResponse, HttpStatus.FORBIDDEN, "선거문자 발송은 개인회원이 후보자 등록 후 이용 가능합니다.", "");
+			}
+
+			MjonCandidateVO mjonCandidateVO = mjonCandidateDAO.selectCandidateDataInfo(userId);
+
+//			if( "p".equals(dept) && mjonCandidateVO == null){
+			if(mjonCandidateVO == null){
+				log.info("mjonCandidateVO == null :: [{}]", mjonCandidateVO == null);
+//				return StatusResponse.statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "선거문자 발송은 후보자 등록 후 이용 가능합니다. \n등록을 먼저 진행해주세요.", "");
+				return StatusResponse.statusResponseSet(statusResponse, HttpStatus.FORBIDDEN, "선거문자 발송은 후보자 등록 후 이용 가능합니다. \n등록을 먼저 진행해주세요.", "");
+
+			}
+
+		}
+
+
+
 		String smsTxt = mjonMsgVO.getSmsTxtArea();
 		smsTxt = StringUtils.isEmpty(smsTxt) ? "" : smsTxt;
 		// 광고문자면 처리 - 광고 A
 		if ("A".equals(mjonMsgVO.getMsgKind())) {
 			smsTxt = "(광고)" + smsTxt + "\n" + "무료거부 0808800858";
+		}else if ("C".equals(mjonMsgVO.getMsgKind())) {
+			if(StringUtils.isNotEmpty(mjonMsgVO.getSend_adYn())
+					&& "Y".equals(mjonMsgVO.getSend_adYn())) {
+				smsTxt = "(선거운동정보)" +"\n"
+						+ smsTxt + "\n"
+						+ "불법수집정보신고 선거관리위원회 1390"+"\n"
+						+ "무료거부 0808800858";
+			}
 		}
+
+
 		mjonMsgVO.setSmsTxt(smsTxt);
 
 		
@@ -4022,13 +4065,26 @@
 		List<String> userBlockList = mjonMsgDAO.selectUserBlockList(mjonMsgVO);
 
 		// 리스트 초기 크기
-		mjonMsgSendVOList.removeIf(vo -> userBlockList.contains(vo.getPhone()));
+//		mjonMsgSendVOList.removeIf(vo -> userBlockList.contains(vo.getPhone()));
+
+		// 삭제된 전화번호들을 담을 리스트 (임시)
+		List<String> resultBlockList = new ArrayList<>();
+		// removeIf 하면서 삭제된 phone만 수집
+		mjonMsgSendVOList.removeIf(vo -> {
+			if (userBlockList.contains(vo.getPhone())) {
+				resultBlockList.add(vo.getPhone());   // phone만 저장
+				return true;   // 삭제
+			}
+			return false;
+		});
+
 		// 삭제 후 리스트 크기 저장
 		int finalSize = mjonMsgSendVOList.size();
 		// 삭제된 건 수 계산
 		int deletedCount = initialSize - finalSize;
 		// 수신거부 목록
 		returnMap.put("resultBlockSts", deletedCount);
+		returnMap.put("resultBlockList", resultBlockList); // 수신거부 된 목록
 		apiReturnMap.put("resultBlockSts", deletedCount);
 
 		if (mjonMsgSendVOList.size() < 1) {
@@ -5207,4 +5263,30 @@
 		return mjonMsgDataDAO.selectSysMsgTodaySendYn(sendLogVO);
 	}
 
+	@Override
+	public RestResponse getBeforeCashDataAjax(String userId) throws Exception {
+
+		MjonMsgVO mjonMsgVO = new MjonMsgVO();
+		mjonMsgVO.setUserId(userId);
+
+		Double userMoney = Double.parseDouble(mjonMsgDataDAO.selectBeforeCashData(mjonMsgVO));
+
+
+		//이벤트 회원 정보 테이블에서 대상자의 정보를 불러온다.
+		MjonEventVO mjonEventVO = new MjonEventVO();
+		mjonEventVO.setMberId(userId);
+		MjonEventVO eventMberInfo = mjonEventService.selectEventMsgMberDefaultInfo(mjonEventVO);
+
+		Map<String,Object> resutlMap = new HashMap<>();
+		resutlMap.put("eventMberInfo",eventMberInfo);
+		resutlMap.put("userMoney",userMoney);
+
+
+		return RestResponse.builder()
+				.status(HttpStatus.OK) // 200, Series.SUCCESSFUL, "OK"
+				.msg("금액불러오기 성공")
+				.data(resutlMap)
+				.build();
+	}
+
 }
src/main/java/itn/let/mjo/rejt/web/MjonRejectController.java
--- src/main/java/itn/let/mjo/rejt/web/MjonRejectController.java
+++ src/main/java/itn/let/mjo/rejt/web/MjonRejectController.java
@@ -92,8 +92,8 @@
 	
 	@ResponseBody
 	@RequestMapping(value = "/mjonRejectReceive_advc.do")
-	public HashMap<String, String> mjonRejectReceive_advc(@RequestBody MjonRejectVO rejectVO) throws Exception {
-		
+	public HashMap<String, String> mjonRejectReceive_advc() throws Exception {
+
 		
 		//ModelAndView mv = new ModelAndView();
 		//mv.setViewName("jsonView");
@@ -110,11 +110,8 @@
 			
 			MjonBlockVO blockVO =  new MjonBlockVO();
 			List<String> phoneNumberList = Arrays.asList(
-				    "01083584250",
-				    "01030266269",
-				    "01012341234",
-				    "01030266222",
-				    "01012341237"
+				    "01079833871",
+				    "01098076412"
 				);
 
 			
src/main/java/itn/let/uat/uia/service/impl/EgovMberManageServiceImpl.java
--- src/main/java/itn/let/uat/uia/service/impl/EgovMberManageServiceImpl.java
+++ src/main/java/itn/let/uat/uia/service/impl/EgovMberManageServiceImpl.java
@@ -300,8 +300,13 @@
 	@Override
 	public List<String> selectMblDnCheck(String mblDn) throws Exception {
 		return mberManageDAO.selectMblDnCheck(mblDn);
-	}	
-	
+	}
+
+	@Override
+	public String selectMblDnCheckSttus(String mblDn) throws Exception {
+		return mberManageDAO.selectMblDnCheckSttus(mblDn);
+	}
+
 	@Override
 	public List<String> selectMblDnCheckById(MberManageVO mberManageVO) throws Exception {
 		return mberManageDAO.selectMblDnCheckById(mberManageVO);
src/main/java/itn/let/uat/uia/service/impl/MberManageDAO.java
--- src/main/java/itn/let/uat/uia/service/impl/MberManageDAO.java
+++ src/main/java/itn/let/uat/uia/service/impl/MberManageDAO.java
@@ -127,6 +127,10 @@
 	public List<String> selectMblDnCheck(String mblDn) {
 		return (List<String>) list("mberManageDAO.selectMblDnCheck", mblDn);
 	}
+
+	public String selectMblDnCheckSttus(String mblDn) {
+		return (String) select("mberManageDAO.selectMblDnCheckSttus", mblDn);
+	}
 	
 	public List<String> selectMblDnCheckById(MberManageVO mberManageVO) {
 		return (List<String>) list("mberManageDAO.selectMblDnCheckById", mberManageVO);
src/main/java/itn/let/uat/uia/web/EgovLoginController.java
--- src/main/java/itn/let/uat/uia/web/EgovLoginController.java
+++ src/main/java/itn/let/uat/uia/web/EgovLoginController.java
@@ -288,6 +288,7 @@
 		if (isAuthenticated)
 			return "redirect:/";
 		//URL을 이용한 비정상적인 접근 차단
+
 		if("".equals(mberManageVO.getDept()) || mberManageVO.getDept() == null) {
 			redirectAttributes.addFlashAttribute("message", "잘못된 경로로 접속하여 메인화면으로 이동됩니다");
 			return "redirect:/web/main/mainPage.do";
@@ -419,12 +420,6 @@
 			redirectAttributes.addFlashAttribute("message", "잘못된 경로로 접속하여 메인화면으로 이동됩니다");
 			return "redirect:/web/main/mainPage.do";
 		}
-		
-		System.out.println("++++++++++++ 세션체크 ::: " + (MberManageVO) session.getAttribute("mberSession"));
-		if (null == session.getAttribute("mberSession")) { // 세션이 없을 시 메인화면으로 팅김
-			redirectAttributes.addFlashAttribute("message", "쿠키 설정을 확인하세요.");
-			return "redirect:/";
-		}
 
 		// 이메일 코드조회
 		ComDefaultCodeVO voComCode = new ComDefaultCodeVO();
@@ -445,9 +440,7 @@
 		model.addAttribute("joinType", joinType);
 
 		// 본인인증
-		// 회원타입(개인,기업) 담아둔 세션 조회
 		session = request.getSession();
-		MberManageVO mberSessionVO = (MberManageVO) session.getAttribute("mberSession");
 
 		if (joinType.equals("M") || joinType.equals("A")) {
 
@@ -484,8 +477,6 @@
 
 		}
 
-		model.addAttribute("mberSessionVO", mberSessionVO);
-
 		// 나이스 본인인증을 했을때 세션처리 후 데이터 저장해주기.
 		/*
 		 * MberManageVO VO = new MberManageVO(); if (null !=
@@ -505,10 +496,10 @@
 		if (blineCode != null && blineCode.length() != 0){
 		}
 		else {
-			blineCode = "N";			
+			blineCode = "N";
 		}
 		model.addAttribute("blineCode", blineCode);
-		
+
 		return "web/login/usrInsertView";
 	}
 
@@ -3718,11 +3709,15 @@
 				
 				String mberSttus = usedNmList.get(0).getMberSttus();
 				String message = "";
-				if(mberSttus.equals("B")) {
+
+				if ("B".equals(mberSttus)) {
 					message = "문자고 이용이 정지 된 회원 정보입니다.";
-					
-				}else {
+				} else if ("N".equals(mberSttus)) {
 					message = "문자고에서 탈퇴한 회원 정보입니다.";
+				} else if ("A".equals(mberSttus)) {
+					message = "기업회원 가입 절차가 완료되지 않았습니다. 고객센터로 문의해 주시기 바랍니다.";
+				} else {
+					message = "회원 상태를 확인할 수 없습니다.";
 				}
 				
 				modelAndView.addObject("message", message);
@@ -4395,11 +4390,15 @@
 				
 				String mberSttus = usedNmList.get(0).getMberSttus();
 				String message = "";
-				if(mberSttus.equals("B")) {
+
+				if ("B".equals(mberSttus)) {
 					message = "문자고 이용이 정지 된 회원 정보입니다.";
-					
-				}else {
+				} else if ("N".equals(mberSttus)) {
 					message = "문자고에서 탈퇴한 회원 정보입니다.";
+				} else if ("A".equals(mberSttus)) {
+					message = "기업회원 가입 절차가 완료되지 않았습니다. 고객센터로 문의해 주시기 바랍니다.";
+				} else {
+					message = "회원 상태를 확인할 수 없습니다.";
 				}
 				
 				modelAndView.addObject("message", message);
src/main/java/itn/let/uss/umt/service/EgovMberManageService.java
--- src/main/java/itn/let/uss/umt/service/EgovMberManageService.java
+++ src/main/java/itn/let/uss/umt/service/EgovMberManageService.java
@@ -154,7 +154,10 @@
 	
 	//문자고 중복가입 체크를 위한 모든 모바일 인증키
 	public List<String> selectMblDnCheck(String mblDn) throws Exception;
-	
+
+	//문자고 중복가입 체크 시 기존 회원의 상태(정상/탈퇴/이용정지) 조회
+	public String selectMblDnCheckSttus(String mblDn) throws Exception;
+
 	//문자고 담당자변경 시 다른 계정에서 사용하는 인증키 체크
 	public List<String> selectMblDnCheckById(MberManageVO mberManageVO) throws Exception;	
 	
src/main/java/itn/let/uss/umt/service/MberManageVO.java
--- src/main/java/itn/let/uss/umt/service/MberManageVO.java
+++ src/main/java/itn/let/uss/umt/service/MberManageVO.java
@@ -300,8 +300,23 @@
 	/**
 	 * 문자 수집 동의
 	 */
-	private String collectMsg;	
-	
+	private String collectMsg;
+
+	/**
+	 * 회원가입 서비스 이용약관(TERMS_00000022) 동의여부 - DB(TERMS_AGREE) 저장에 사용
+	 */
+	private String termsAgree;
+
+	/**
+	 * 회원가입 개인정보 수집 및 이용(TERMS_00000023) 동의여부 - 향후 확장용, 현재 DB 저장 없음
+	 */
+	private String privacyAgree;
+
+	/**
+	 * 회원가입 스팸 관련 규약 사항(TERMS_00000024) 동의여부 - 향후 확장용, 현재 DB 저장 없음
+	 */
+	private String spamAgree;
+
 	private float shortPrice; // 단문 단가
 	
 	private float longPrice; //장문 단가
@@ -1212,6 +1227,24 @@
 	public void setCollectMsg(String collectMsg) {
 		this.collectMsg = collectMsg;
 	}
+	public String getTermsAgree() {
+		return termsAgree;
+	}
+	public void setTermsAgree(String termsAgree) {
+		this.termsAgree = termsAgree;
+	}
+	public String getPrivacyAgree() {
+		return privacyAgree;
+	}
+	public void setPrivacyAgree(String privacyAgree) {
+		this.privacyAgree = privacyAgree;
+	}
+	public String getSpamAgree() {
+		return spamAgree;
+	}
+	public void setSpamAgree(String spamAgree) {
+		this.spamAgree = spamAgree;
+	}
 	public float getShortPrice() {
 		return shortPrice;
 	}
src/main/java/itn/let/uss/umt/web/EgovMberCmpHstController.java
--- src/main/java/itn/let/uss/umt/web/EgovMberCmpHstController.java
+++ src/main/java/itn/let/uss/umt/web/EgovMberCmpHstController.java
@@ -362,7 +362,7 @@
         	String contents = "";
         	if("02".equals(mberCmpHstVO.getHstSttus())) { //승인
         		if("01".equals(mberCmpHstVO.getHstType())) { //회원가입
-        			contents = "[문자고] 기업회원 가입 신청이 승인되었습니다.";
+					contents = "[문자고] 기업회원 가입 신청이 승인되었습니다. 회원가입을 진심으로 환영합니다.";
             	}else if("02".equals(mberCmpHstVO.getHstType())) { //기업회원 전환
             		contents = "[문자고] 기업회원 전환이 승인되었습니다.";
             	}
@@ -583,7 +583,7 @@
 	        	}
 	        	String contents = "";
         		if("01".equals(mberCmpHstVO.getHstType())) { //회원가입
-        			contents = "[문자고] 기업회원 가입 신청이 승인되었습니다.";
+					contents = "[문자고] 기업회원 가입 신청이 승인되었습니다. 회원가입을 진심으로 환영합니다.";
             	}else if("02".equals(mberCmpHstVO.getHstType())) { //기업회원 전환
             		contents = "[문자고] 기업회원 전환이 승인되었습니다.";
             	}
@@ -749,7 +749,7 @@
 	        	String contents = "";
 	        	if("02".equals(mberCmpHstVO.getHstSttus())) { //승인
 	        		if("01".equals(mberCmpHstVO.getHstType())) { //회원가입
-	        			contents = "[문자고] 기업회원 가입 신청이 승인되었습니다.";
+						contents = "[문자고] 기업회원 가입 신청이 승인되었습니다. 회원가입을 진심으로 환영합니다.";
 	            	}else if("02".equals(mberCmpHstVO.getHstType())) { //기업회원 전환
 	            		contents = "[문자고] 기업회원 전환이 승인되었습니다.";
 	            	}
src/main/java/itn/web/MainController.java
--- src/main/java/itn/web/MainController.java
+++ src/main/java/itn/web/MainController.java
@@ -48,18 +48,17 @@
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import itn.com.cmm.RestResponse;
 import org.json.simple.JSONArray;
 import org.json.simple.JSONObject;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
 import org.springframework.ui.Model;
 import org.springframework.ui.ModelMap;
 import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.SessionAttributes;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
 import org.springframework.web.multipart.MultipartFile;
@@ -1373,7 +1372,7 @@
 			return "web/site/"+siteId+"/"+siteManagerVO.getIsMobile()+"/com/webCommonHeader";
 		}
     }
-    
+
     
     @RequestMapping(value="/web/com/webCommonHeader_back.do")
     public String webCommonHeader_back(
src/main/resources/egovframework/spring/com/context-idgen.xml
--- src/main/resources/egovframework/spring/com/context-idgen.xml
+++ src/main/resources/egovframework/spring/com/context-idgen.xml
@@ -2927,6 +2927,21 @@
 		<property name="cipers" value="10" />
 		<property name="fillChar" value="0" />
 	</bean>
-	
+
+    <!-- 20건 선거문자 등록 IDGEN Generation  Strategy Config -->
+    <bean name="mjCampainTmpJobIdGnrService"
+          class="egovframework.rte.fdl.idgnr.impl.EgovTableIdGnrServiceImpl"
+          destroy-method="destroy">
+        <property name="dataSource" ref="dataSource" />
+        <property name="strategy" ref="mjCampainTmpJobStrategy" />
+        <property name="blockSize"  value="10"/>
+        <property name="table"      value="IDS"/>
+        <property name="tableName"  value="TMP_JOB_ID"/>
+    </bean>
+    <bean name="mjCampainTmpJobStrategy" class="egovframework.rte.fdl.idgnr.impl.strategy.EgovIdGnrStrategyImpl">
+        <property name="prefix" value="TMPJOB_" />
+        <property name="cipers" value="13" />
+        <property name="fillChar" value="0" />
+    </bean>
 		
 </beans>
src/main/resources/egovframework/sqlmap/let/mjo/kakao/KakaoSent_SQL_Mysql.xml
--- src/main/resources/egovframework/sqlmap/let/mjo/kakao/KakaoSent_SQL_Mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/mjo/kakao/KakaoSent_SQL_Mysql.xml
@@ -1453,7 +1453,12 @@
 						AND  B.SMS_TXT like CONCAT('%', #searchKeyword#, '%')
 					</isEqual>
 					<isEqual property="searchCondition" compareValue="4" >
-						AND A.CALL_TO LIKE CONCAT('%', #searchKeyword#, '%')
+						AND EXISTS (
+							SELECT 1 FROM MJ_MSG_DATA MD
+							WHERE MD.MSG_GROUP_ID = B.MSG_GROUP_ID
+								AND MD.DEL_FLAG = 'N'
+								AND REPLACE(MD.CALL_TO, '-', '') LIKE CONCAT('%', REPLACE(#searchKeyword#, '-', ''), '%')
+						)
 					</isEqual>
 				</isNotEmpty>
 				GROUP BY B.MSG_GROUP_ID
src/main/resources/egovframework/sqlmap/let/msg/MjonMsgCampainData_SQL_mysql.xml
--- src/main/resources/egovframework/sqlmap/let/msg/MjonMsgCampainData_SQL_mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/msg/MjonMsgCampainData_SQL_mysql.xml
@@ -3,15 +3,17 @@
   =========     =======    =================================================
   2021.08.06    우영두 	
 -->
-<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">
+<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd">
+
 <sqlMap namespace="Msg">
 	<typeAlias  alias="mjonCandidateVO" type="itn.let.mjo.msgcampain.service.MjonCandidateVO"/>
 	<typeAlias  alias="mjonCandidateTWVO" type="itn.let.mjo.msgcampain.service.MjonCandidateTWVO"/>
+	<typeAlias  alias="mjonCandidateTWJobVO" type="itn.let.mjo.msgcampain.service.MjonCandidateTWJobVO"/>
 	<typeAlias  alias="mjonMsgVO" type="itn.let.mjo.msg.service.MjonMsgVO"/>
 	
 	
 	<select id="mjonCandidateDAO.selectCandidateDataInfo" parameterClass="String" resultClass="mjonCandidateVO">
-		
+		/* mjonCandidateDAO.selectCandidateDataInfo */
 		SELECT CANDIDATE_ID AS candidateId,
 		       MBER_ID AS mberId,
 		       CANDIDATE_NM AS candidateNm,
@@ -101,40 +103,42 @@
 		WHERE MBER_ID = #mberId#
 	
 	</update>
-	
+
+
 	<insert id="mjonCandidateDAO.insertCandidateTWCallToData" parameterClass="java.util.List">
-		
+
 		INSERT
 		INTO   MJ_CAMPAIN_TMP_CALLTO
-		       (
-		              MBER_ID,
-		              CALL_TO,
-		              SEND_FLAG,
-		              CALL_SEQ,
-		              FRST_REGISTER_ID,
-		              FRST_REGIST_PNTTM,
-		              LAST_UPDUSR_ID,
-		              LAST_UPDT_PNTTM
-		       )
-		       VALUES
-		       <iterate conjunction=",">
-			       (
-			          #[].mberId#,
-			          #[].callTo#,
-			          'N',
-			          #[].callSeq#,
-			          #[].frstRegisterId#,
-			          NOW(),
-			          #[].lastUpdusrId#,
-			          NOW()
-			       )
-		       </iterate>
-	
+		(
+		MBER_ID,
+		CALL_TO,
+		SEND_FLAG,
+		CALL_SEQ,
+		FRST_REGISTER_ID,
+		FRST_REGIST_PNTTM,
+		LAST_UPDUSR_ID,
+		LAST_UPDT_PNTTM
+		)
+		VALUES
+		<iterate conjunction=",">
+			(
+			#[].mberId#,
+			#[].callTo#,
+			'N',
+			#[].callSeq#,
+			#[].frstRegisterId#,
+			NOW(),
+			#[].lastUpdusrId#,
+			NOW()
+			)
+		</iterate>
+
 	</insert>
+
 	
 	<update id="mjonCandidateDAO.updateCandidateTWCallToDataCancel" parameterClass="String">
 		
-		UPDATE MJ_CAMPAIN_TMP_CALLTO SET 
+		UPDATE  MJ_CAMPAIN_TMP_CALLTO SET
 			SEND_FLAG = 'C',
 			LAST_UPDUSR_ID = #mberId#,
 			LAST_UPDT_PNTTM = NOW()
@@ -166,6 +170,20 @@
 		ORDER BY CAMPAIN_TMP_ID
         LIMIT #recordCountPerPage# OFFSET #firstIndex#
 	
+	</select>
+	<select id="mjonCandidateDAO.selectCampainTWCalltoList_advc" parameterClass="mjonCandidateTWJobVO" resultClass="mjonCandidateTWJobVO">
+
+		SELECT /*CAMPAIN_TMP_ID AS campainTmpId,*/
+		       MBER_ID        AS mberId,
+		       CALL_TO        AS callTo,
+		       CALL_NM        AS callNm,
+		       SEND_FLAG      AS sendFlag
+		/*CALL_SEQ       AS callSeq*/
+		FROM   MJ_CAMPAIN_TMP_CALLTO
+		WHERE  MBER_ID   = #mberId#
+		AND TMP_JOB_ID = #tmpJobId#
+		ORDER BY CAMPAIN_TMP_ID
+
 	</select>
 	
 	<update id="mjonCandidateDAO.updateMsgTWCallToListResetByMberId" parameterClass="mjonCandidateTWVO">
@@ -264,14 +282,44 @@
 			</iterate>
 	
 	</update>
-	
+
+
+
+	<update id="mjonCandidateDAO.updateSuccessSendResultAfterSend" parameterClass="mjonCandidateTWVO">
+		UPDATE MJ_CAMPAIN_TMP_CALLTO
+		SET SEND_FLAG = 'Y',
+		LAST_UPDUSR_ID = #mberId#,
+		LAST_UPDT_PNTTM = NOW()
+		WHERE MBER_ID = #mberId#
+		AND SEND_FLAG = 'N'
+		AND CALL_TO IN
+		<iterate property="successPhones" open="(" conjunction="," close=")">
+			#successPhones[]#
+		</iterate>
+	</update>
+
+
+	<update id="mjonCandidateDAO.updateFailSendResultAfterSend" parameterClass="mjonCandidateTWVO">
+		UPDATE MJ_CAMPAIN_TMP_CALLTO
+		SET SEND_FLAG = 'F',
+		LAST_UPDUSR_ID = #mberId#,
+		LAST_UPDT_PNTTM = NOW()
+		WHERE MBER_ID = #mberId#
+		AND SEND_FLAG = 'N'
+		AND CALL_TO IN
+		<iterate property="failPhones" open="(" conjunction="," close=")">
+			#failPhones[]#
+		</iterate>
+	</update>
+
+
 	<delete id="mjonCandidateDAO.deleteCandidateTWCallToOldData" parameterClass="mjonCandidateTWVO">
-		
+
 		DELETE FROM MJ_CAMPAIN_TMP_CALLTO
 		WHERE MBER_ID = #mberId#
-		AND SEND_FLAG = #sendFlag#
+		  AND SEND_FLAG = #sendFlag#
 		<![CDATA[
-			AND CALL_SEQ < #callSeq#
+		  AND CALL_SEQ < #callSeq#
 		]]>
 	</delete>
 	
@@ -301,7 +349,120 @@
 		ORDER BY a.ADDR_PHONE_NO
 		
 	</select>
-	
+
+	<insert id="mjonCandidateDAO.insertCandidateTWCallToData_advc" parameterClass="java.util.List">
+		/* mjonCandidateDAO.insertCandidateTWCallToData_advc */
+
+		INSERT IGNORE INTO
+		MJ_CAMPAIN_TMP_CALLTO
+		(
+			TMP_JOB_ID,
+			MBER_ID,
+			CALL_TO,
+			CALL_NM,
+			SEND_FLAG,
+			FRST_REGISTER_ID,
+			FRST_REGIST_PNTTM
+		)
+		VALUES
+		<iterate conjunction=",">
+			(
+				#[].tmpJobId#,
+				#[].mberId#,
+				#[].callTo#,
+				#[].callNm#,
+				'N',
+				#[].mberId#,
+				NOW()
+			)
+		</iterate>
+
+	</insert>
+
+	<insert id="mjonCandidateDAO.insertMjCampainTmpJob" parameterClass="mjonCandidateTWJobVO">
+		/* mjonCandidateDAO.insertMjCampainTmpJob */
+		INSERT INTO mj_campain_tmp_job
+		(
+			TMP_JOB_ID,
+			MBER_ID,
+			JOB_STATUS,
+			TOTAL_COUNT,
+			FRST_REGIST_PNTTM,
+			LAST_UPDT_PNTTM
+		)
+		VALUES
+		(
+		 	#tmpJobId#,
+			#mberId#,
+			#jobStatus#,
+			#totalCount#,
+			NOW(),
+			NOW()
+		)
+
+	</insert>
+
+
+	<update id="mjonCandidateDAO.updateMjCampainTmpJob" parameterClass="mjonCandidateTWJobVO">
+		/* mjonCandidateDAO.updateMjCampainTmpJob */
+
+		UPDATE MJ_CAMPAIN_TMP_JOB
+		SET JOB_STATUS = #jobStatus#
+			, TOTAL_COUNT = #totalCount#
+		  	, LAST_UPDT_PNTTM = NOW()
+		WHERE TMP_JOB_ID = #tmpJobId#
+		AND MBER_ID = #mberId#
+
+
+	</update>
+
+	<delete id="mjonCandidateDAO.deleteCandidateTWCallToData" parameterClass="mjonCandidateTWJobVO">
+		DELETE FROM MJ_CAMPAIN_TMP_CALLTO
+		WHERE TMP_JOB_ID = #tmpJobId#
+	</delete>
+
+	<update id="mjonCandidateDAO.updateCampainTmpJob" parameterClass="mjonCandidateTWJobVO">
+		UPDATE MJ_CAMPAIN_TMP_JOB
+		SET JOB_STATUS = #jobStatus#,
+			LAST_UPDT_PNTTM = NOW()
+		WHERE TMP_JOB_ID = #tmpJobId#
+	</update>
+
+
+	<select id="mjonCandidateDAO.selectMjCampainTmpJobByUserIdAndJobStatus" resultClass="mjonCandidateTWJobVO" parameterClass="String">
+		select
+		    TMP_JOB_ID as tmpJobId
+		,	JOB_STATUS as jobStatus
+		from MJ_CAMPAIN_TMP_JOB
+		WHERE MBER_ID = #userId#
+		and JOB_STATUS != 'D'
+	</select>
+
+
+	<select id="mjonCandidateDAO.selectMjCampainTmpJob" resultClass="mjonCandidateTWJobVO" parameterClass="mjonCandidateTWJobVO">
+		select
+			TMP_JOB_ID			as tmpJobId
+			, MBER_ID			as mberId
+			, JOB_STATUS		as jobStatus
+			, TOTAL_COUNT		as totalCount
+			, FRST_REGIST_PNTTM	as frstRegistPnttm
+			, LAST_UPDT_PNTTM	as lastUpdtPnttm
+		from MJ_CAMPAIN_TMP_JOB
+		WHERE TMP_JOB_ID = #tmpJobId#
+		  and MBER_ID = #mberId#
+	</select>
+
+	<select id="mjonCandidateDAO.chkTmpJobStatus" resultClass="mjonCandidateTWJobVO" parameterClass="String">
+		select
+		    TMP_JOB_ID as tmpJobId
+			,JOB_STATUS as jobStatus
+		from MJ_CAMPAIN_TMP_JOB
+		WHERE MBER_ID = #userId#
+		  AND (JOB_STATUS = 'P' OR JOB_STATUS = 'C')
+
+	</select>
+
+
 </sqlMap>  
 
 
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
@@ -2119,6 +2119,8 @@
 	</delete>
 	
 	<select id="mjonMsgDAO.selectSendPhonNumList" parameterClass="String" resultClass="String">
+
+	/* mjonMsgDAO.selectSendPhonNumList */
 	
 		SELECT PHONE_NUMBER
 		FROM   MJ_PHONE_MEMBER
src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml
--- src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml
+++ src/main/resources/egovframework/sqlmap/let/uss/umt/EgovUserManage_SQL_Mysql.xml
@@ -922,6 +922,7 @@
 			RECEIVE_KAKAO,
 			RECEIVE_MAIL,
 			COLLECT_MSG,
+			TERMS_AGREE,
 			SHORT_PRICE,
 			LONG_PRICE,
 			PICTURE_PRICE,
@@ -977,6 +978,7 @@
               #receiveKakao# ,
               #receivemail# ,
               #collectMsg# ,
+              #termsAgree# ,
               #shortPrice# ,
               #longPrice# ,
               #picturePrice#,
@@ -1150,7 +1152,14 @@
 		FROM LETTNGNRLMBER
 		WHERE CRTFC_DN_VALUE = #mblDn#
 	</select>
-	
+
+	<select id="mberManageDAO.selectMblDnCheckSttus" parameterClass="String" resultClass="String">
+		SELECT MBER_STTUS
+		FROM LETTNGNRLMBER
+		WHERE CRTFC_DN_VALUE = #mblDn#
+		LIMIT 1
+	</select>
+
 	<select id="mberManageDAO.selectMblDnCheckById" parameterClass="mberVO" resultClass="String">
 		SELECT CRTFC_DN_VALUE AS mblDn
 		FROM LETTNGNRLMBER
src/main/webapp/WEB-INF/decorators.xml
--- src/main/webapp/WEB-INF/decorators.xml
+++ src/main/webapp/WEB-INF/decorators.xml
@@ -129,6 +129,7 @@
       <pattern>/uss/ion/sign/SignPopup.do</pattern><!-- 결제신청팝업-->
       <pattern>/uss/ion/sign/OrgChartPopup.do</pattern><!-- 조직도 선택 팝업-->
       <pattern>/*Ajax.do</pattern>
+      <pattern>/*Ajax_advc.do</pattern>
       <pattern>/*AjaxView.do</pattern>
       <pattern>/itn/mail/intSendMailForm.do</pattern>
       <pattern>/uss/umt/user/EgovGnrlselectedUserView.do</pattern>
src/main/webapp/WEB-INF/jsp/sym/mnu/mpm/EgovMenuCreatSelectJtree.jsp
--- src/main/webapp/WEB-INF/jsp/sym/mnu/mpm/EgovMenuCreatSelectJtree.jsp
+++ src/main/webapp/WEB-INF/jsp/sym/mnu/mpm/EgovMenuCreatSelectJtree.jsp
@@ -213,7 +213,10 @@
 			$.ajax({
 				type:"POST",
 				url:"<c:url value='/sym/mnu/mcm/EgovMenuInfoInsertAjax.do' />",
-				data:{ "menuNm" : menuNm, "upperMenuId" :  upperMenuId,  "menuOrdr" : menuOrdr , "authorCode" : $('#authorCode').val() },
+				data:{ "menuNm" : menuNm
+					, "upperMenuId" :  upperMenuId
+					,  "menuOrdr" : menuOrdr
+					, "authorCode" : $('#authorCode').val() },
 				dataType:'json',
 				//timeout:(1000*30),
 				success : function(returnData, status) {
 
src/main/webapp/WEB-INF/jsp/web/com/include/specialCharacterPopup.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/web/com/include/specialCharacterPopup.jsp
@@ -0,0 +1,86 @@
+<%@ 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" %>
+
+
+<button type="button" class="btnType btnType7" onclick="miniPopup(this);">특수문자</button>
+<div class="send_miniPop spc_character">
+    <div class="tab_character">
+        <a href="#none" class="on">특수문자</a>
+        <a href="#none">웃음</a>
+        <a href="#none">슬픔</a>
+        <a href="#none">분노</a>
+        <a href="#none">사랑</a>
+        <a href="#none">그외</a>
+    </div>
+
+    <!-- 특수문자 부분 -->
+    <div class="cnt_character on">
+        <div class="box_character">
+            <c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+                <c:if test="${symbolList.symbolType == 'D'}">
+                    <a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}"><c:out value="${symbolList.symbol}"/></a>
+                </c:if>
+            </c:forEach>
+        </div>
+    </div>
+    <!-- 웃음 -->
+    <div class="cnt_character emt_character">
+        <div class="box_character">
+            <c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+                <c:if test="${symbolList.symbolType == 'S'}">
+                    <a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+                </c:if>
+            </c:forEach>
+        </div>
+    </div>
+    <!-- //웃음 -->
+    <!-- 슬픔 -->
+    <div class="cnt_character emt_character">
+        <div class="box_character">
+            <c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+                <c:if test="${symbolList.symbolType == 'C'}">
+                    <a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+                </c:if>
+            </c:forEach>
+        </div>
+    </div>
+    <!-- //슬픔 -->
+    <!-- 분노 -->
+    <div class="cnt_character emt_character">
+        <div class="box_character">
+            <c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+                <c:if test="${symbolList.symbolType == 'A'}">
+                    <a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+                </c:if>
+            </c:forEach>
+        </div>
+    </div>
+    <!-- //분노 -->
+    <!-- 사랑 -->
+    <div class="cnt_character emt_character">
+        <div class="box_character">
+            <c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+                <c:if test="${symbolList.symbolType == 'L'}">
+                    <a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+                </c:if>
+            </c:forEach>
+        </div>
+    </div>
+    <!-- //사랑 -->
+    <!-- 그외 -->
+    <div class="cnt_character emt_character emt_etc ">
+        <div class="box_character">
+            <c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+                <c:if test="${symbolList.symbolType == 'E'}">
+                    <a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+                </c:if>
+            </c:forEach>
+        </div>
+    </div>
+    <!-- //그외 -->
+
+    <button type="button" class="btn_close" onclick="miniPopup(this);">닫기</button>
+</div>(No newline at end of file)
src/main/webapp/WEB-INF/jsp/web/com/webCommonHeader.jsp
--- src/main/webapp/WEB-INF/jsp/web/com/webCommonHeader.jsp
+++ src/main/webapp/WEB-INF/jsp/web/com/webCommonHeader.jsp
@@ -1458,11 +1458,11 @@
 										<%-- 후보자 정보가 없는 경우 메뉴를 보여주지 않는다. --%>
 										<li style="display:none;">
 									</c:if>
-								</c:when>																												
+								</c:when>
 								<c:otherwise>
 									<li>
 								</c:otherwise>
-							</c:choose>	                   			           		
+							</c:choose>
 								<c:choose>
 									<c:when test="${fn:contains(resultListOne.url, '/web/mjon/msgcampain/selectMsgDataView.do')}">
 										<c:if test="${userCandidateYn eq 'Y'}">
@@ -1474,7 +1474,7 @@
 									</c:when>
 									<c:when test="${fn:contains(resultListOne.url, '/web/mjon/fax/faxDataView.do')}">
 										<a href="${empty resultListOne.url ? '#' : resultListOne.url }" >${resultListOne.menuNm}</a>
-									</c:when>																
+									</c:when>
 									<c:when test="${fn:contains(resultListOne.url, '/web/mjon/custom/selectMsgCustomView.do')}">
 										<a href="${empty resultListOne.url ? '#' : resultListOne.url }" >${resultListOne.menuNm}</a>
 									</c:when>
@@ -1490,17 +1490,17 @@
 									<c:otherwise>
 										<a href="${empty resultListOne.url ? '#' : resultListOne.url }">${resultListOne.menuNm}</a>
 									</c:otherwise>
-								</c:choose>	                   	
+								</c:choose>
 			           			<div class="depth2">
 			           				<ul class="subMenu">
-			           			<c:forEach var="resultListTwo" items="${menuResultList}" varStatus="status"> 
+			           			<c:forEach var="resultListTwo" items="${menuResultList}" varStatus="status">
 									<c:if test="${resultListTwo.depth eq '2' && resultListOne.menuNo  eq resultListTwo.upperMenuId }">
 										<li><a href="${empty resultListTwo.url ? '#' : resultListTwo.url }" ${resultListTwo.menuType eq 'O' ? 'target="_blank"' : ""} >${resultListTwo.menuNm}<c:if test="${resultListTwo.menuType eq 'O' }"><i class="link"></i></c:if></a></li>
 									</c:if>
-								</c:forEach>	
+								</c:forEach>
 			           				</ul>
 			           			</div>
-			           		</li>	
+			           		</li>
 			           		</c:if>
 		           		</c:forEach>
 	                </ul>
@@ -1792,9 +1792,9 @@
 		                        		</c:otherwise>
 		                        	</c:choose>
 		                        </div>
-		                        <div class="session">
+		                        <div class="session" style="width:110px">
 		                        	<div>
-										<span id="ViewTimer">
+										<span id="ViewTimer" />
 									</div>
 									<button type="button" onclick="sessionExpend(); return false;">연장</button>
 									<!-- <a href="#" onclick="sessionExpend(); return false;">
@@ -1890,8 +1890,8 @@
 			                        <button type="button" class="btnType btnType1" onclick="location.href='/web/member/pay/PayView.do'">충전</button>
 			                    </div>
 		                    </div>
-		                    
-		                    
+
+
 		                    <%-- <div class="point">
 								<i></i>
 								<fmt:formatNumber type="number" maxFractionDigits="3" value="${userPoint}" var="commaPoint" />
@@ -1902,8 +1902,8 @@
 		                	    <span><i></i>이달의 이벤트</span>
 	                    		<button type="button" class="btnType btnType2" onclick="location.href='/web/cop/bbs/EventList.do'">GO</button>
 		                    </div> -->
-		                    
-		                    
+
+
 		                </div>
 		                <!-- <div class="login_right">
 		                    <button type="button" data-tooltip="popupJunk" class="btnType btnType14 tab1"><i></i>통신사 스팸규격안내</button>
src/main/webapp/WEB-INF/jsp/web/cop/bbs/TermsListAgreement_2025_Ajax.jsp
--- src/main/webapp/WEB-INF/jsp/web/cop/bbs/TermsListAgreement_2025_Ajax.jsp
+++ src/main/webapp/WEB-INF/jsp/web/cop/bbs/TermsListAgreement_2025_Ajax.jsp
@@ -73,7 +73,7 @@
                                 	</ol>
                                 </li>
                                 <li><strong>3조(약관의 게시와 개정)</strong>① 회사는 이 약관의 내용을 서비스 화면에 이용자가 확인하기 쉽게 게시하며, 이용자가 이에 동의함으로써 그 효력이 발생합니다.<br>
-                                    ② 회사는 「약관의 규제에 관한 법률」, 「정보통신망법」, 「전자문서 및 전자거래 기본법」, 「전자상거래 등에서의 소비자보호에 관한 법률(이하 “전자상거래법”이라 한다」 등 관련 법을 위배하지 않는 범위에서 이 약관을 개정할 수 있습니다.<br>
+                                    ② 회사는 「약관의 규제에 관한 법률」, 「정보통신망법」, 「전자문서 및 전자거래 기본법」, 「전자상거래 등에서의 소비자보호에 관한 법률」(이하 “전자상거래법”이라 한다) 등 관련 법을 위배하지 않는 범위에서 이 약관을 개정할 수 있습니다.<br>
                                     ③ 회사가 이 약관을 개정하는 경우에는 적용일자 및 개정사유를 명시하여 현행약관과 함께 제1항의 방식에 따라 그 적용일자 7일 전부터 적용일자 전까지 공지합니다. 다만, 이용자의 권리 또는 의무에 관한 중요한 규정의 변경은 최소한 30일 전에 공지하고 일정기간 서비스 내 공지사항, 전자우편 등의 전자적 수단을 통해 이를 통지하도록 합니다. 
                                     <br>
                                     ④ 회사가 제3항에 따라 개정약관을 공지 또는 통지하면서 이용자에게 약관 변경 적용일까지 거부의사를 표시하지 않으면 동의한 것으로 본다는 뜻을 명확하게 공지 또는 통지하였음에도 이용자가 명시적으로 거부의 의사표시를 하지 아니한 경우에는 개정약관에 동의한 것으로 봅니다.<br>
@@ -330,7 +330,7 @@
 								  </ol>
 								   ③ 회사는 불법스팸을 전송하였다고 확인된 이용자가 이용 중인 다른 번호가 불법스팸에 악용되고 있거나 악용될 우려가 있다는 객관적 정황이 있는 경우에는 그 다른 번호에 대한 서비스도 해지할 수 있습니다.<br>
 								  ④ 회사는 제2항 및 제3항에 따른 해지시, 이를 이용자에게 통지하여야 하며, 만약 이용자의 책임 있는 사유로 통지할 수 없는 경우에는 이용자가 사전 제출한 정보로 통지를 발송한 때에 도달된 것으로 봅니다. 다만, 회사가 긴급하게 해지할 필요가 있다고 인정하는 경우에는 지체 없이 사후 통지(재고지, 홈페이지 또는 이메일 공지)로 대체 할 수 있습니다.<br>
-								  ⑤ 회사는 휴면아이디가 휴면상태로 3년 이상 지속될 경우 이용계약을 해지할 수 있습니다. 
+								  ⑤ 회사는 휴면아이디가 휴면상태로 3년 이상 지속될 경우 이용계약을 해지할 수 있습니다.
                                 </li>
                                 <li><strong>18조(각종 자료의 저장기간)</strong>
                                 ① 회사는 서비스 이용과 관련하여 이용자가 저장한 자료 및 서비스 제공 과정에서 생성되는 메시지 발송 기록, 전송 결과 등 관련 자료를 일정한 기간 동안 저장할 수 있으며 필요에 따라 그 기간을 변경할 수 있습니다. 또한, 서비스 이용과 관련된 분쟁이 발생한 경우, 회사는 해당자료 또는 시스템 기록을 근거로 사실관계를 확인할 수 있습니다. <br />
@@ -365,7 +365,7 @@
 									  <ol class="conlist8">
 									  	<li>1. 이용자가 충전금을 일부 사용한 경우</li>
 									  	<li>2. 그 밖에 거래의 안전을 위하여 법령으로 정하는 경우</li>
-									  </ol>									  
+									  </ol>
 									  ③ 제1항에도 불구하고 회사가 이용자에게 제시한 충전금에 대한 내용이 표시, 광고된 내용과 다르거나 회사가 이용자에게 안내한 내용과 다르게 이행된 경우에는 그 거래가 있었던 날로부터 3개월 이내, 그 사실을 안 날 또는 알 수 있었던 날로부터 30일 이내에 청약 철회를 할 수 있습니다.<br>
 									  ④ 청약철회를 할 수 있는 경우에 해당하는 경우, 이용자는 거래 취소 등 결제한 수단과 같은 수단으로 결제금액을 환급하는 것을 원칙으로 합니다. 단, 거래 취소를 할 수 없거나 결제한 수단과 같은 수단으로 결제금액을 환급할 수 없는 경우에는 현금으로 환급할 수 있습니다.<br>
 									  ⑤ 회사는 제2항에 따라 청약철회 등이 불가능한 경우에는 그 사실을 이용자가 쉽게 알 수 있는 곳에 명확하게 적시하는 등의 방법으로 청약철회 등의 권리 행사가 방해 받지 아니하도록 조치하여야 합니다.만약 회사가 이러한 조치를 하지 아니한 경우에는 제2항의 청약철회 제한사유에도 불구하고 이용자는 청약철회를 할 수 있습니다.<br>
@@ -426,7 +426,7 @@
   ③ 회사 및 타인에게 피해를 주어 피해자의 고발 또는 소송 제기로 인하여 손해배상이 청구된 이용자는 이에 응하여야 합니다.<br>
   ④ 이용자는 불법스팸, 불법정보, 발신번호 조작 등으로 인지되는 메시지 발송을 통해 회사에 손해를 끼치는 경우, 이를 배상하여야 합니다.                            	
                             	</li>
-                            	<li><strong>27조(면책)</strong>① 제25조에도 불구하고, 회사는 다음 각 호의 어느 하나의 사유로 서비스를 제공할 수 없는 경우, 이로 인하여 이용자에게 발생한 손해에 대해서는 책임을 부담하지 않습니다. 
+                            	<li><strong>27조(면책)</strong>① 제25조에도 불구하고, 회사는 다음 각 호의 어느 하나의 사유로 서비스를 제공할 수 없는 경우, 이로 인하여 이용자에게 발생한 손해에 대해서는 책임을 부담하지 않습니다.
 								   <ol class="conlist8">
 								   	 <li>1. 천재지변 또는 이에 준하는 불가항력의 상태가 있는 경우</li>
 								   	 <li>2. 회사의 고의 또는 과실이 없는 사유로 인한 경우</li>
src/main/webapp/WEB-INF/jsp/web/cop/bbs/TermsListAgreement_2026_Ajax.jsp
--- src/main/webapp/WEB-INF/jsp/web/cop/bbs/TermsListAgreement_2026_Ajax.jsp
+++ src/main/webapp/WEB-INF/jsp/web/cop/bbs/TermsListAgreement_2026_Ajax.jsp
@@ -74,7 +74,7 @@
                                 </li>
                                 <li><strong>3조(약관의 게시와 개정)</strong>① 회사는 이 약관의 내용을 서비스 화면에 이용자가 확인하기 쉽게 게시하며, 이용자가 이에 동의함으로써 그 효력이 발생합니다.<br>
                                     ② 회사는 「약관의 규제에 관한 법률」, 「정보통신망법」, 「전자문서 및 전자거래 기본법」, 「전자상거래 등에서의 소비자보호에 관한 법률(이하 “전자상거래법”이라 한다」 등 관련 법을 위배하지 않는 범위에서 이 약관을 개정할 수 있습니다.<br>
-                                    ③ 회사가 이 약관을 개정하는 경우에는 적용일자 및 개정사유를 명시하여 현행약관과 함께 제1항의 방식에 따라 그 적용일자 7일 전부터 적용일자 전까지 공지합니다. 다만, 이용자의 권리 또는 의무에 관한 중요한 규정의 변경은 최소한 30일 전에 공지하고 일정기간 서비스 내 공지사항, 전자우편 등의 전자적 수단을 통해 이를 통지하도록 합니다. 
+                                    ③ 회사가 이 약관을 개정하는 경우에는 적용일자 및 개정사유를 명시하여 현행약관과 함께 제1항의 방식에 따라 그 적용일자 7일 전부터 적용일자 전까지 공지합니다. 다만, 이용자의 권리 또는 의무에 관한 중요한 규정의 변경은 최소한 30일 전에 공지하고 일정기간 서비스 내 공지사항, 전자우편 등의 전자적 수단을 통해 이를 통지하도록 합니다.
                                     <br>
                                     ④ 회사가 제3항에 따라 개정약관을 공지 또는 통지하면서 이용자에게 약관 변경 적용일까지 거부의사를 표시하지 않으면 동의한 것으로 본다는 뜻을 명확하게 공지 또는 통지하였음에도 이용자가 명시적으로 거부의 의사표시를 하지 아니한 경우에는 개정약관에 동의한 것으로 봅니다.<br>
                                     ⑤ 이용자는 개정약관에 동의하지 않는 경우 서비스 이용을 중단하고 이용계약을 해지할 수 있습니다.<br>
@@ -126,8 +126,8 @@
 								  	</ol>
 								  	③ 이용자는 아이디 및 비밀번호가 도용되거나 제3자가 사용하고 있음을 인지한 경우에는 이를 즉시 회사에 통지하고 회사의 안내에 따라야 합니다.<br>
 								  	④ 회사는 이용자가 제3항에 따른 통지를 하지 않거나, 통지를 한 이후 회사의 안내에 따르지 않아 발생한 불이익에 대하여 책임지지 않습니다.<br>
-								  	⑤ 회사는 보안 강화를 위해, 신규 가입한 이용자 또는 마지막 로그인 시점으로부터 3개월간 로그인하지 않은 이용자의 부정로그인을 방지하는 보안 로그인 기능(이용자가 사전에 등록한 휴대폰 번호에 대한 점유 인증이 완료된 경우에만 서비스 홈페이지 로그인이 가능하도록 하는 기능)을 이용자의 기본 로그인 방식으로 설정할 수 있습니다.<br> 
-								  	⑥ 이용자가 제5항에 따른 보안 로그인 설정을 해제함으로써 발생하는 손해에 대하여 회사는 책임을 지지 않습니다.                                
+								  	⑤ 회사는 보안 강화를 위해, 신규 가입한 이용자 또는 마지막 로그인 시점으로부터 3개월간 로그인하지 않은 이용자의 부정로그인을 방지하는 보안 로그인 기능(이용자가 사전에 등록한 휴대폰 번호에 대한 점유 인증이 완료된 경우에만 서비스 홈페이지 로그인이 가능하도록 하는 기능)을 이용자의 기본 로그인 방식으로 설정할 수 있습니다.<br>
+								  	⑥ 이용자가 제5항에 따른 보안 로그인 설정을 해제함으로써 발생하는 손해에 대하여 회사는 책임을 지지 않습니다.
                                 </li>
                                 <li><strong>8조(이용자정보의 변경)</strong>이용자는 이용 신청 시 기재한 이용자정보가 변경되었을 경우 즉시 온라인으로 직접 수정하여야 하며, 관리자에게도 수정을 요청할 수 있습니다. 만약, 이용자가 이용자정보를 변경하지 않아 발생하는 문제에 대하여는 회사가 책임지지 않습니다. 
                                 </li>
@@ -330,7 +330,7 @@
 								  </ol>
 								   ③ 회사는 불법스팸을 전송하였다고 확인된 이용자가 이용 중인 다른 번호가 불법스팸에 악용되고 있거나 악용될 우려가 있다는 객관적 정황이 있는 경우에는 그 다른 번호에 대한 서비스도 해지할 수 있습니다.<br>
 								  ④ 회사는 제2항 및 제3항에 따른 해지시, 이를 이용자에게 통지하여야 하며, 만약 이용자의 책임 있는 사유로 통지할 수 없는 경우에는 이용자가 사전 제출한 정보로 통지를 발송한 때에 도달된 것으로 봅니다. 다만, 회사가 긴급하게 해지할 필요가 있다고 인정하는 경우에는 지체 없이 사후 통지(재고지, 홈페이지 또는 이메일 공지)로 대체 할 수 있습니다.<br>
-								  ⑤ 회사는 휴면아이디가 휴면상태로 3년 이상 지속될 경우 이용계약을 해지할 수 있습니다. 
+								  ⑤ 회사는 휴면아이디가 휴면상태로 3년 이상 지속될 경우 이용계약을 해지할 수 있습니다.
                                 </li>
                                 <li><strong>18조(각종 자료의 저장기간)</strong>
                                 ① 회사는 서비스 이용과 관련하여 이용자가 저장한 자료 및 서비스 제공 과정에서 생성되는 메시지 발송 기록, 전송 결과 등 관련 자료를 일정한 기간 동안 저장할 수 있으며 필요에 따라 그 기간을 변경할 수 있습니다. 또한, 서비스 이용과 관련된 분쟁이 발생한 경우, 회사는 해당자료 또는 시스템 기록을 근거로 사실관계를 확인할 수 있습니다. <br />
@@ -365,7 +365,7 @@
 									  <ol class="conlist8">
 									  	<li>1. 이용자가 충전금을 일부 사용한 경우</li>
 									  	<li>2. 그 밖에 거래의 안전을 위하여 법령으로 정하는 경우</li>
-									  </ol>									  
+									  </ol>
 									  ③ 제1항에도 불구하고 회사가 이용자에게 제시한 충전금에 대한 내용이 표시, 광고된 내용과 다르거나 회사가 이용자에게 안내한 내용과 다르게 이행된 경우에는 그 거래가 있었던 날로부터 3개월 이내, 그 사실을 안 날 또는 알 수 있었던 날로부터 30일 이내에 청약 철회를 할 수 있습니다.<br>
 									  ④ 청약철회를 할 수 있는 경우에 해당하는 경우, 이용자는 거래 취소 등 결제한 수단과 같은 수단으로 결제금액을 환급하는 것을 원칙으로 합니다. 단, 거래 취소를 할 수 없거나 결제한 수단과 같은 수단으로 결제금액을 환급할 수 없는 경우에는 현금으로 환급할 수 있습니다.<br>
 									  ⑤ 회사는 제2항에 따라 청약철회 등이 불가능한 경우에는 그 사실을 이용자가 쉽게 알 수 있는 곳에 명확하게 적시하는 등의 방법으로 청약철회 등의 권리 행사가 방해 받지 아니하도록 조치하여야 합니다.만약 회사가 이러한 조치를 하지 아니한 경우에는 제2항의 청약철회 제한사유에도 불구하고 이용자는 청약철회를 할 수 있습니다.<br>
src/main/webapp/WEB-INF/jsp/web/cop/bbs/include/agree_private/agreeSelectVersion.jsp
--- src/main/webapp/WEB-INF/jsp/web/cop/bbs/include/agree_private/agreeSelectVersion.jsp
+++ src/main/webapp/WEB-INF/jsp/web/cop/bbs/include/agree_private/agreeSelectVersion.jsp
@@ -9,7 +9,8 @@
     <p>이용약관 개정이력 보기</p>
     <div class="privacy_content_select_wrap"><!-- option 선택 시 해당페이지로 이동 -->
         <select name="termsMastNo" id="termsMastNo" class="selType2 version_change_select" onchange="getTermsOtherVersion();">
-            <option value="2025" <c:if test="${termsMstNo eq '2025'}"> selected</c:if> >2025.07.30</option>
+        	<option value="2026" <c:if test="${termsMstNo eq '2026'}"> selected</c:if> >2026.10.15.</option>
+            <option value="2025" <c:if test="${termsMstNo eq '2025'}"> selected</c:if> >2025.07.30 ~ 2026.10.14. 적용</option>
             <option value="2024" <c:if test="${termsMstNo eq '2024'}"> selected</c:if> >2024.11.29. ~ 2025.07.29. 적용</option>
             <option value="2023" <c:if test="${termsMstNo eq '2023'}"> selected</c:if> >2023.04.26. ~ 2024.11.28. 적용</option>
             <option value="2022" <c:if test="${termsMstNo eq '2022'}"> selected</c:if> >2022.08.01. ~ 2023.04.25. 적용</option>
src/main/webapp/WEB-INF/jsp/web/cop/bbs/include/bbsTabType.jsp
--- src/main/webapp/WEB-INF/jsp/web/cop/bbs/include/bbsTabType.jsp
+++ src/main/webapp/WEB-INF/jsp/web/cop/bbs/include/bbsTabType.jsp
@@ -8,7 +8,7 @@
 
        			<ul class="tabType4">
 					<li class="tab"><button type="button" onclick="TabType5(this,'1');location.href='/web/cop/bbs/NoticeList.do'">공지사항</button></li>
-					<li class="tab"><button type="button" onclick="TabType5(this,'2');location.href='/web/cop/bbs/TermsList.do'">이용약관</button></li>
+					<li class="tab"><button type="button" onclick="TabType5(this,'2');location.href='/web/cop/bbs/TermsList.do?menuNm=02&termsMastNo=2025'">이용약관</button></li>
 					<li class="tab"><button type="button" onclick="TabType5(this,'3');location.href='/web/cop/bbs/FaqList.do'">자주하는 질문</button></li>
 					<li class="tab"><button type="button" onclick="TabType5(this,'4');location.href='/web/cop/bbs/QnaList.do'">1:1 문의</button></li>
 					<li class="tab"><button type="button" onclick="TabType5(this,'5');location.href='/web/cop/bbs/SuggestList.do'">불편신고</button></li>
src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkTopMenuTap.jsp
--- src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkTopMenuTap.jsp
+++ src/main/webapp/WEB-INF/jsp/web/kakao/include/KaKaoAlimtalkTopMenuTap.jsp
@@ -16,11 +16,13 @@
 	
 	var menuTopTab = '${paramKakaoVO.menuTopTab}';
 	
+	
 	if(menuTopTab == ''){
 		
 		menuTopTab = form.menuTopTab.value;
 		
 	}
+	console.log('menuTopTab : ', menuTopTab);
 	
 	if(menuTopTab == 'tabConf'){
 		$(".topTab").removeClass("active");
@@ -37,6 +39,10 @@
 	}else if(menuTopTab == 'tabIntro'){
 		$(".topTab").removeClass("active");
 		$("#tabIntro").addClass("active");
+		
+	}else if(menuTopTab == 'tabBrandMsg'){
+		$(".topTab").removeClass("active");
+		$("#tabBt").addClass("active");
 	}
 		
 }
@@ -64,7 +70,12 @@
 		
 		url = "<c:url value='/web/mjon/kakao/alimtalk/kakaotalkIntrdView.do'/>";
 		
+	}else if(tabInfo == 'tabBrandMsg'){
+		
+		url = "<c:url value='/web/mjon/kakao/brandMsg/kakaoBrandMsgDataView.do'/>";
+		
 	}
+	
 	
 	//form.action =url;
 	//form.submit();
@@ -142,7 +153,8 @@
 
 	<ul class="tabType4">
         <li id="tabAt" class="tab topTab"><button type="button" onclick="javascript:fnLinkPageTopTab('tabAlim');">알림톡</button></li>
-	    <!-- <li id="tabFt" class="tab topTab"><button type="button" onclick="javascript:fnLinkPageTopTab('tabFriend');">친구톡</button></li> -->
+<%--	    <li id="tabBt" class="tab topTab"><button type="button" onclick="javascript:fnLinkPageTopTab('tabBrandMsg');">브랜드메시지</button></li>--%>
+<%--	    <li id="tabFt" class="tab topTab"><button type="button" onclick="javascript:fnLinkPageTopTab('tabFriend');">친구톡</button></li>--%>
         <li id="tabConf" class="tab topTab"><button type="button" onclick="javascript:fnLinkPageTopTab('tabConf');">카카오톡 설정</button></li>
         <li id="tabIntro" class="tab topTab"><button type="button" onclick="javascript:fnLinkPageTopTab('tabKakaotalkIntrd');">카카오톡 소개</button></li>
     </ul>
(No newline at end of file)
src/main/webapp/WEB-INF/jsp/web/login/findUserId.jsp
--- src/main/webapp/WEB-INF/jsp/web/login/findUserId.jsp
+++ src/main/webapp/WEB-INF/jsp/web/login/findUserId.jsp
@@ -158,7 +158,11 @@
 						alert("문자고 이용이 정지 된 회원 정보입니다.");
 						userCheck = false;
 						return userCheck;
-					}else if(data.userSttus == null){
+					}else if(data.userSttus == "A"){
+						alert("기업회원 가입 절차가 완료되지 않았습니다. 고객센터로 문의해 주시기 바랍니다.");
+						userCheck = false;
+						return userCheck;
+					}else if(data.userSttus == null || data.userSttus == ""){
 						alert("입력하신 아이디/이름에 맞는 회원 정보가 없습니다.");
 						userCheck = false;
 						return userCheck;
src/main/webapp/WEB-INF/jsp/web/login/test_usrCheckTerms.jsp
--- src/main/webapp/WEB-INF/jsp/web/login/test_usrCheckTerms.jsp
+++ src/main/webapp/WEB-INF/jsp/web/login/test_usrCheckTerms.jsp
@@ -128,8 +128,14 @@
 				}else{
 					checkForm.collectMsg.value = 'N';
 				}
-					
-				
+
+				//서비스 이용약관(TERMS_00000022) 동의여부 - 동의 이력 저장용
+				if($("#agree_TERMS_00000022").is(":checked")){
+					checkForm.termsAgree.value = 'Y';
+				}else{
+					checkForm.termsAgree.value = 'N';
+				}
+
 				 var modiForm = $("form[name=modiForm]").serialize() ;
 	
 				       $.ajax({
@@ -180,17 +186,27 @@
 						}
 						//이미 mblDn이 존재할 경우
 						if(returnData.checkMblDnCnt > 0 ){
-							alert("이미 사용중이거나 탈퇴한 휴대폰번호입니다.");
-							
+							if(returnData.mberSttus == 'Y'){
+								alert("이미 사용중인 회원 정보입니다.");
+							}else if(returnData.mberSttus == 'N'){
+								alert("문자온에서 탈퇴한 회원 정보입니다.");
+							}else if(returnData.mberSttus == 'B'){
+								alert("이용이 정지된 회원 정보입니다.");
+							}else if(returnData.mberSttus == 'A'){
+								alert("기업회원 가입 심사 승인이 완료되지 않은 회원 정보입니다.");
+							}else{
+								alert("이미 사용중이거나 탈퇴한 휴대폰번호입니다.");
+							}
+
 							//location.href="/web/user/login/selectUserDept.do";
-							
+
 							return false;
 						}
 						//이미 존재하지 않을 경우
 						else{
 							
 							document.modiForm.action = "<c:url value='/web/user/login/insertUsrView.do'/>";
-							document.modiForm.action = "<c:url value='/web/user/login/new_insertUsrView.do'/>";
+							//document.modiForm.action = "<c:url value='/web/user/login/new_insertUsrView.do'/>";
 						    document.modiForm.submit();
 						}
 					}else{
@@ -419,6 +435,7 @@
     	<input type="hidden" name="receiveKakao" value="" />
     	<input type="hidden" name="receivemail" value="" />
     	<input type="hidden" name="collectMsg" value="" />
+    	<input type="hidden" name="termsAgree" value="" />
     	<input type="hidden" name="niceNm" value="" />
     	birthDay<input type="text" name="birthDay" value="19731223" />
     	<input type="hidden" name="moblphonNo" value="" />
src/main/webapp/WEB-INF/jsp/web/login/usrCheckTerms.jsp
--- src/main/webapp/WEB-INF/jsp/web/login/usrCheckTerms.jsp
+++ src/main/webapp/WEB-INF/jsp/web/login/usrCheckTerms.jsp
@@ -145,8 +145,14 @@
 				}else{
 					checkForm.collectMsg.value = 'N';
 				}
-					
-				
+
+				//서비스 이용약관(TERMS_00000022) 동의여부 - 동의 이력 저장용
+				if($("#agree_TERMS_00000022").is(":checked")){
+					checkForm.termsAgree.value = 'Y';
+				}else{
+					checkForm.termsAgree.value = 'N';
+				}
+
 				 var modiForm = $("form[name=modiForm]").serialize() ;
 	
 				       $.ajax({
@@ -191,10 +197,20 @@
 						}
 						//이미 mblDn이 존재할 경우
 						if(returnData.checkMblDnCnt > 0 ){
-							alert("이미 사용중이거나 탈퇴한 휴대폰번호입니다.");
-							
+							if(returnData.mberSttus == 'Y'){
+								alert("이미 사용중인 회원 정보입니다.");
+							}else if(returnData.mberSttus == 'N'){
+								alert("문자온에서 탈퇴한 회원 정보입니다.");
+							}else if(returnData.mberSttus == 'B'){
+								alert("이용이 정지된 회원 정보입니다.");
+							}else if(returnData.mberSttus == 'A'){
+								alert("기업회원 가입 심사 승인이 완료되지 않은 회원 정보입니다.");
+							}else{
+								alert("이미 사용중이거나 탈퇴한 휴대폰번호입니다.");
+							}
+
 							//location.href="/web/user/login/selectUserDept.do";
-							
+
 							return false;
 						}
 						//이미 존재하지 않을 경우
@@ -620,6 +636,7 @@
     	<input type="hidden" name="receiveKakao" value="" />
     	<input type="hidden" name="receivemail" value="" />
     	<input type="hidden" name="collectMsg" value="" />
+    	<input type="hidden" name="termsAgree" value="" />
     	<input type="hidden" name="niceNm" value="" />
     	<input type="hidden" name="birthDay" value="" />
     	<input type="hidden" name="moblphonNo" value="" />
src/main/webapp/WEB-INF/jsp/web/login/usrInsertView.jsp
--- src/main/webapp/WEB-INF/jsp/web/login/usrInsertView.jsp
+++ src/main/webapp/WEB-INF/jsp/web/login/usrInsertView.jsp
@@ -726,10 +726,11 @@
 		action="/web/user/login/usrJoinInsert.do" method="post"
 		enctype="Multipart/form-data">
 		<input type="hidden" name="dept" id="dept" value="<c:out value='${mberManageVO.dept}' />" /> 
-		<input type="hidden" name="receiveMsg" value="<c:out value='${mberSessionVO.receiveMsg}' />" /> 
-		<input type="hidden" name="receiveKakao" value="<c:out value='${mberSessionVO.receiveKakao}' />" /> 
-		<input type="hidden" name="receivemail" value="<c:out value='${mberSessionVO.receivemail}' />" /> 
-		<input type="hidden" name="collectMsg" value="<c:out value='${mberSessionVO.collectMsg}' />" /> 
+		<input type="hidden" name="receiveMsg" value="<c:out value='${mberManageVO.receiveMsg}' />" />
+		<input type="hidden" name="receiveKakao" value="<c:out value='${mberManageVO.receiveKakao}' />" />
+		<input type="hidden" name="receivemail" value="<c:out value='${mberManageVO.receivemail}' />" />
+		<input type="hidden" name="collectMsg" value="<c:out value='${mberManageVO.collectMsg}' />" />
+		<input type="hidden" name="termsAgree" value="<c:out value='${mberManageVO.termsAgree}' />" />
 		<input type="hidden" name="sexdstnCode" value="<c:out value='${mberManageVO.sexdstnCode}' />" />
 		<input type="hidden" name="birthDay" value="<c:out value='${mberManageVO.birthDay}' />" />
 		<input type="hidden" name="mblDn" value="<c:out value='${mberManageVO.mblDn}' />" /> 
src/main/webapp/WEB-INF/jsp/web/msgcampain/MsgDataSMLView.jsp
--- src/main/webapp/WEB-INF/jsp/web/msgcampain/MsgDataSMLView.jsp
+++ src/main/webapp/WEB-INF/jsp/web/msgcampain/MsgDataSMLView.jsp
@@ -24,6 +24,10 @@
 var excelAddr = []; //엑셀 불러오기에서 내용 저장하는 배열 변수
 
 $(document).ready(function (){
+
+	// 기업회원 및 선거후보자 체크
+	deptCandidateChk();
+
 	// 발송금액 단가표시
 	SetPriceWrapOpen();	
 	
@@ -124,7 +128,7 @@
 	 	        cell.getRow().toggleSelect();
 		 	}}, 
 	        {formatter: "rownum", align: "center", title: "No", hozAlign: "center", headerHozAlign: "center", width: 60},
-	        {title: "그룹명", hozAlign: "center", field: "groupNm", editor: false, width: 100, validator: ["required", "minLength:2", "maxLength:40"]},
+	        {title: "그룹명", hozAlign: "center", field: "addrGroupNm", editor: false, width: 100, validator: ["required", "minLength:2", "maxLength:40"]},
 	        {title: "이름", hozAlign: "center", field: "name", editor: false, width: 100, validator: ["maxLength:12"]},
 	        {title: "휴대폰번호", hozAlign: "center", field: "phone", editor: false, width: 100, validator: ["required", "minLength:10", "maxLength:11"]},
 	        {title: "[*1*]", hozAlign: "center", field: "rep1", editor: false, width: 84, validator: ["maxLength:40"]},
@@ -336,58 +340,41 @@
 			}			
 		}
 	});
-	
+
 	//받는사람 번호 버튼 클릭시 Tabulator에 데이터 넣어주기
-	$('.addCallToF').click(function(){ 
-		
-		var callToNum = $('#callTo').val();
-		if(callToNum == null || callToNum == ""){
-			
+	$('.addCallToF').click(function(){
+
+		var textarea = $('#callTo');
+		if (textarea.val() == null || textarea.val() == "") {
 			alert("받는사람 번호를 입력해 주세요.");
 			return false;
-			
-		}else if(!checkHpNum(callToNum)){	
-			
-			alert("올바른 전화번호를 입력해 주세요.");
-			$('#callTo').val("");
-			return false;
 		}
-		
-		//핸드폰 번호에 '-' 문자 제거하기
-		callToNum = removeDash(callToNum);
-	    
-	    //기존 받는사람 연락처 모두 불러오기
-	    var data = tableL.getRows();
-	    var tableData = [];
-	    var dpCnt = 0;
-	    for(var i=0; i < tableL.getRows().length; i++){
-	    	if(callToNum == data[i].getData().phone){
-	    		dpCnt++;
-	    	}
-	    }
-	    
-	    if(dpCnt > 0){
-	    	alert("받는사람 리스트에 동일한 연락처가 있습니다.");
-	    	$('#callTo').val("");
-	    	return false;
-	    }else{
-	    	
-	    	tabledata = [{phone: callToNum},];
-	    	
-	    	//빈 row 데이터 삭제하기
-	    	var befData = tableL.getRows();
-	    	var totLen = tableL.getRows().length;
-	    	
-	    	for(var i=0; i < totLen; i++){
-		    	tableData.push({phone: data[i].getData().phone.trim(), name: data[i].getData().name});
-		    }
-			
-	    	//연락처 추가해 주기
-			addPhoneInfo(tabledata);
-		    $('#callTo').val("");
-	    }
+
+		const numbers = textarea.val().split('\n')
+				.map(num => removeDash(num.trim()))
+				.filter(num => num !== "")
+				.filter(num => isValidPhoneNumber(num)); // 유효한 번호만 필터링;
+
+		console.log('numbers : ', numbers);
+		const addrData = processPhoneNumbers(numbers);
+
+
+		// 기존 tableL의 데이터를 가져옵니다.
+		var existingData = tableL.getData();
+
+		// 데이터 병합 및 중복 제거
+		const result = mergeAndValidateData(existingData, addrData);
+
+
+		// 테이블 데이터 업데이트
+		if (!updateTableData(tableL, result)) return false;
+
+		// textarea 초기화
+		textarea.val(''); // jQuery 객체에서 값을 초기화할 때는 .val('') 사용
+
 	});
-	
+
+
 	//받는사람 전체삭제 버튼 처리
 	$('.all_del').click(function(){
 		
@@ -460,7 +447,8 @@
 			return false;
 		}
 		
-		$("#addrGroupLoad").load("/web/mjon/msgcampain/selectAddrGroupListAjax.do", "" ,function(response, status, xhr){
+		// $("#addrGroupLoad").load("/web/mjon/msgcampain/selectAddrGroupListAjax.do", "" ,function(response, status, xhr){
+		$("#addrGroupLoad").load("/web/mjon/msgdata/selectAddrGroupListAjax.do", "" ,function(response, status, xhr){
 			//리스트 스크롤 처리해주기
 			$(".adr_pop_list").mCustomScrollbar({
 				axis: 'y',
@@ -1178,6 +1166,22 @@
 	});
 });
 
+function updateButtons(currentIndex ) {
+}
+// 기업회원 및 선거후보자 체크
+function deptCandidateChk(){
+
+	var candidateNm = $.trim($("#candidateNmChk").val());
+	var dept = $.trim($("#deptChk").val());
+
+	// 기업회원이면
+	if(dept == 'c'){
+		$('[data-tooltip="alert_layer_popup02"]').trigger('click'); // 기업회원 팝업
+	}else if(!candidateNm){	// 값이 없으면
+		$('[data-tooltip="alert_layer_popup"]').trigger('click'); // 후보자 등록 팝업
+	}
+}
+
 //전체 데이터 갯수 구하는 함수
 function updateTotCnt(data){
 	var rowTotCnt = data;
@@ -1283,21 +1287,21 @@
 	var adTxtLeng = conByteLeng($('.ad_txt').text());
 	var denyTxtLeng = 0;
 	var denyTxt = $('.deny_txt').html();
-	
+
 	//선거문자 하단 문구 줄바꿈 처리하기
 	if(typeof denyTxt !='undefined' && denyTxt != null){
 		denyTxt = denyTxt.replaceAll("<br>","\n");
 		denyTxt = denyTxt.replaceAll("<br/>","\n");
 		denyTxtLeng = conByteLeng(denyTxt);
 	}
-	
-	
+
+
 	$('#msgLeng').html("");
 	$('#limitLeng').html("");
 	var conLeng = conByteLeng(contents); // 내용 문자 입력 바이트 수 계산하기
-	
+
 	console.log(contents);
-	
+
 	//일반문자, 광고문자에 따른 문자 길이 변경해주기
 	if(adverYn == "N"){
 		
@@ -1391,10 +1395,15 @@
  		alert("문자 내용은 2000byte를 넘을 수 없습니다.");
 		return false;
 	}
-	
-	//수신목록 전체 데이터 갯수 구하기
+
+// tableL이 초기화되었을 때만 카운트 업데이트를 수행하도록 방어막을 칩니다.
+	if (tableL) {
+		// 6.2 버전에서는 getDataCount()가 성능상 훨씬 유리합니다.
+		totRows = tableL.getDataCount();
+	}
 	updateTotCnt(totRows);
-	
+	// updateTotCnt(totRows);
+
 	//일괄변환 문구 결제금액 처리
 	if(contents.indexOf("[*이름*]")  > -1
 			|| contents.indexOf("[*1*]") > -1
@@ -2050,17 +2059,6 @@
 	}
 }
 
-//후보자 등록 시 로그인 여부 체크
-function fn_candidateLoginChk(){
-	alert("후보자 등록은 로그인 후 이용 가능합니다.");
-	return false;
-}
-
-// 후보자 등록 시 회원여부 체크
-function fn_mberDeptChk(){
-	alert("선거문자는 개인 회원만 이용 가능합니다.");
-	return false;
-}
 
 // 선거문자 맞춤제작 팝업 열기
 function goToCustom(){
@@ -2072,7 +2070,7 @@
 function infoPop(pageUrl){
 	document.popForm.pageType.value = pageUrl;
 	document.popForm.action = "/web/pop/infoPop.do";
-	document.popForm.method = "post"; 
+	document.popForm.method = "post";
 	window.open("about:blank", 'infoPop', 'width=790, height=1500, top=100, left=100, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbars=yes');
 	document.popForm.target = "infoPop";
 	document.popForm.submit();
@@ -2397,7 +2395,7 @@
 // 						var spmFilterTxt = returnData.spmFilterTxt;
 						spamStatus = true;
 						//alert("문자 내용에 \"" + spmFilterTxt + "\"의 스팸문자가 포함되어 있습니다.");
-						alert("전송 문자내용 중 스팸문구로 의심되는 단어가 포함되어 있어 문자발송이 불가합니다.\n자세한 사항은 문자고 고객센터를 통해 문의주시기 바랍니다.");
+						alert("전송 문자내용 중 스팸문구로 의심되는 단어가 포함되어 있어 문자발송이 불가합니다.\n자세한 사항은 문자온 고객센터를 통해 문의주시기 바랍니다.");
 						return false;
 						
 					}
@@ -2473,13 +2471,32 @@
 //선택 발신번호를 이용한 문자내용 설정
 function advMsgInsert(){
 	var callFrom = $("#callFromList option:selected").val();
-	
+
+	var advStr = '<div class="ad_txt"><p>' + SMS_CONFIG.prefix + '</p></div>';
+
+	var advDenyStr = '<div class="deny_txt">'
+			+ SMS_CONFIG.suffix[0] + '<br/>'
+			+ SMS_CONFIG.suffix[1]
+			+ '</div>';
+
+	var preAdvStr = '<p class="ad_tit">' + SMS_CONFIG.prefix + '</p>';
+
+	var preAdvDenyStr = '<div class="deny_txt">'
+			+ SMS_CONFIG.suffix[0] + '<br/>'
+			+ SMS_CONFIG.suffix[1]
+			+ '</div>';
+
+
+
+
+/*
 	var advStr = '<div class="ad_txt"><p>(선거운동정보)</p></div>';
-	var advDenyStr = '<div class="deny_txt">후보자전화번호 ' + callFrom + '<br/>불법수집정보 신고번호 : 선거관리위원회 ☎1390<br/>무료거부 0808800858</div>';
-	
+	var advDenyStr = '<div class="deny_txt">불법수집정보신고 선거관리위원회 1390<br/>무료거부 0808800858</div>';
+
 	var preAdvStr = '<p class="ad_tit">(선거운동정보)</p>';
-	var preAdvDenyStr = '<p class="deny_receipt">후보자전화번호 ' + callFrom + '<br>불법수집정보 신고번호 : 선거관리위원회 ☎1390<br>무료거부 0808800858</p>';
-	
+	var preAdvDenyStr = '<div class="deny_txt">불법수집정보신고 선거관리위원회 1390<br/>무료거부 0808800858</div>';
+*/
+
 	//광고 및 무료수신거부 텍스트 추가
 	if ($("#send_adYnY").val() == 'Y'){
 
@@ -2491,9 +2508,9 @@
 		$('.deny_receipt').remove();
 		
 		//문자 내용에 광고 문자 추가해주기
-		$(advStr).insertBefore('textarea[name=smsTxtArea]'); 
+		$(advStr).insertBefore('textarea[name=smsTxtArea]');
 		$(advDenyStr).insertBefore('div[name=afterDeny]');
-		
+
 		//미리보기에 광고 문자 추가해주기
 		$(preAdvStr).insertBefore('.none_txt');
 		$(preAdvDenyStr).insertAfter('.realtime');
@@ -2534,7 +2551,7 @@
 	var totCnt = divideCnt + "" + event.key;
 	if(Number(totCnt) > 5000){
 		alert("분할전송 건수는 5,000건을 초과할 수 없습니다.");
-		$('#divideCnt').val("20");
+		$('#divideCnt').val("500");
 		return false;
 	}
   return true;
@@ -2596,13 +2613,60 @@
 	</div>
 </div>
 <!--// 2023 10 16  재전송 팝업 -->
-	
+
+
+<!-- [기업회원일 경우]선거문자 이용안내 data-tooltip:alert_layer_popup -->
+<div class="tooltip-wrap">
+	<div class="popup-com alert_layer_popup alert_layer_popup02" tabindex="0" data-tooltip-con="alert_layer_popup02" data-focus="alert_layer_popup" data-focus-prev="alert_layer_popup02-close" style="width: 450px;">
+		<div class="popup_heading">
+			<!-- 기업회원일 경우 -->
+			<p>선거문자 이용안내</p>
+			<button type="button" class="tooltip-close" data-focus="alert_layer_popup02-close" onclick="location.href='/web/main/mainPage.do'"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+
+		<div class="layer_in">
+			<p>선거문자 발송은 개인회원이 후보자 등록 후 <br />이용 가능합니다.</p>
+			<div class="btn_wrap popup">
+				<button type="button" class="btnType fill_blue tooltip-close" onclick="location.href='/web/main/mainPage.do'">메인화면 바로가기</button>
+			</div>
+		</div>
+
+	</div>
+</div>
+
+<!-- [개인회원일 경우]선거문자 이용안내 data-tooltip:alert_layer_popup -->
+<div class="tooltip-wrap">
+	<div class="popup-com alert_layer_popup" tabindex="0" data-tooltip-con="alert_layer_popup" data-focus="alert_layer_popup" data-focus-prev="alert_layer_popup-close" style="width: 450px;display:none;opacity: 1;left: 50%;top: 50%;transform: translate(-50%, -50%);">
+		<div class="popup_heading">
+			<p>선거문자 이용안내</p>
+			<button type="button" class="tooltip-close" data-focus="alert_layer_popup-close" onclick="location.href='/web/main/mainPage.do'"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+
+		<div class="layer_in">
+			<p>선거문자 발송은 후보자 등록 후 이용 가능합니다. <br />등록을 먼저 진행해주세요.</p>
+			<div class="btn_wrap popup">
+				<button type="button" class="btnType fill_blue tooltip-close" data-tooltip="candidate_popup01">확인</button>
+				<button type="button" class="btnType fill_gray tooltip-close" onclick="location.href='/web/main/mainPage.do'">닫기</button>
+			</div>
+		</div>
+
+	</div>
+</div>
+
 <!-- 후보자등록 팝업 data-tooltip:candidate_popup01 -->
 <div class="tooltip-wrap">
 	<div class="popup-com candidate_layer candidate_popup01" tabindex="0" data-tooltip-con="candidate_popup01" data-focus="candidate_popup01" data-focus-prev="candidate_popup01-close" style="width: 620px;">
 		<div class="popup_heading">
-			<p>후보자 등록</p>
-			<button type="button" class="tooltip-close" data-focus="candidate_popup01-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+			<c:choose>
+				<c:when test="${not empty mjonCandidateVO.candidateNm}">
+					<p>후보자 수정</p>
+					<button type="button" class="tooltip-close" data-focus="candidate_popup01-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+				</c:when>
+				<c:otherwise>
+					<p>후보자 등록</p>
+					<button type="button" class="tooltip-close" data-focus="candidate_popup01-close" onclick="location.href='/web/main/mainPage.do'"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+				</c:otherwise>
+			</c:choose>
 		</div>
 		
 		<form id="candiForm" name="candiForm" method="post">
@@ -2697,12 +2761,13 @@
                 	<c:choose>
                 		<c:when test="${not empty mjonCandidateVO.candidateNm}">
 		                    <button type="button" onclick="javascript:fnCandidateUpt('Upt'); return false;">수정</button>
+							<button type="button" class="tooltip-close" data-focus="candidate_popup01-close" data-focus-next="candidate_popup01">닫기</button>
                 		</c:when>
                 		<c:otherwise>
                 			<button type="button" onclick="javascript:fnCandidateUpt('Reg'); return false;">등록</button>
+							<button type="button" class="tooltip-close" data-focus="candidate_popup01-close" data-focus-next="candidate_popup01" onclick="location.href='/web/main/mainPage.do'">닫기</button>
                 		</c:otherwise>
                 	</c:choose>
-                    <button type="button" class="tooltip-close" data-focus="candidate_popup01-close" data-focus-next="candidate_popup01">닫기</button>                      
                 </div>
 			</div>
 			
@@ -2715,7 +2780,7 @@
 	
 <!-- 주소록 불러오기 -->
 <div class="tooltip-wrap">
-	<div class="popup-com import_layer popup06" tabindex="0" data-tooltip-con="popup06" data-focus="popup06" data-focus-prev="popup06-close" style="width: 1000px">
+	<div class="popup-com import_layer popup06 adr_call_popup" tabindex="0" data-tooltip-con="popup06" data-focus="popup06" data-focus-prev="popup06-close" style="width: 1000px">
 		<div class="popup_heading">
 			<p><span>주소록 불러오기</p>
 			<button type="button" onClick="javascript:addrClose(); return false;">
@@ -2973,10 +3038,10 @@
 						<li>
 							<div>
 								<i class="benefit1"></i>
-								<p>한 번에 대량으로 보내야 한다면?<span>10만건까지 동시 전송 가능</span></p>
+								<p>한 번에 대량으로 보내야 한다면?<span>30만건까지 동시 전송 가능</span></p>
 							</div>
 							<p>문자고의 대량전송(엑셀·TXT) 모듈을 통해
-								10만건의 대량문자도 쉽고 빠르게 전송 가능합니다.</p>
+								30만건의 대량문자도 쉽고 빠르게 전송 가능합니다.</p>
 						</li>
 						<li>
 							<div>
@@ -3020,9 +3085,9 @@
 						<li>
 							<div>
 								<i class="benefit7"></i>
-								<p>20건씩 나눠서 보내야한다면?<span>20건씩 분할 예약 전송 가능</span></p>
+								<p>대량 문자를 나눠서 보내야한다면?<span>조건 설정 후 자동 분할 예약 가능</span></p>
 							</div>
-							<p>누구나 쉽고 편리하게 20건씩 나눠서 분할 전송이 가능합니다.</p>
+							<p>설정한 건수와 간격에 따라 자동으로 분할 예약 발송됩니다.</p>
 						</li>
 						<li>
 							<div>
@@ -3093,9 +3158,17 @@
 </div>
 	
 <form id="msgForm" name="msgForm" method="post">
+
+	<input type="hidden" id="candidateNmChk" value="<c:out value="${mjonCandidateVO.candidateNm}"/>" /><!-- 선거 후보자 이름 있는지 호가인 -->
+	<input type="hidden" id="deptChk" value="<c:out value="${mberManageVO.dept}"/>" /><!-- 선거 후보자 이름 있는지 호가인 -->
+
+	<input type="hidden" id="send_adYnY" name="send_adYn" value="Y">
+
 	<input type="hidden" id="msgType" name="msgType" value="4" /><!-- 문자 종류 : 단문 - 4, 장문/그림 - 6 -->
 	<input type="hidden" id="imgFilePath" name="imgFilePath" value="" /><!-- 선택 이미지 파일 경로 정보 , 로 구분 최대 3장까지 -->
+	<input type="hidden" id="imgFileIdAdvc" name="imgFileIdAdvc" value="" /><!-- 선택 이미지 파일 아이디 정보 , 로 구분 최대 3장까지 -->
 	<input type="hidden" id="imgFileId" name="imgFileId" value="" /><!-- 선택 이미지 파일 아이디 정보 , 로 구분 최대 3장까지 -->
+	<input type="hidden" id="imgFilePathAdvc" name="imgFilePathAdvc" value="" /><!-- 선택 이미지 파일 경로 정보 , 로 구분 최대 3장까지 -->
 	<input type="hidden" id="fileCnt" name="fileCnt" value="0" /><!-- 첨부파일 추가 갯수 -->
 	<input type="hidden" id="callToList" name="callToList" value=""/><!-- 수신자 전화번호 리스트 -->
 	<input type="hidden" id="callFrom" name="callFrom" value=""/> <!-- 발신자 전화번호 -->
@@ -3112,6 +3185,7 @@
 	<input type="hidden" id="rep3List" name="rep3List" value=""/><!-- 문자발송 문자 치환3 리스트 -->
 	<input type="hidden" id="rep4List" name="rep4List" value=""/><!-- 문자발송 문자 치환4 리스트 -->
 	<input type="hidden" name="templateYn" />
+	<input type="hidden" name="templateYnAdvc" />
 	<input type="hidden" id="sPrice" name="sPrice" value="<c:out value="${shortPrice}"/>"/><!-- 단문문자 단가 -->
 	<input type="hidden" id="mPrice" name="mPrice" value="<c:out value="${longPrice}"/>"/><!-- 장문문자 단가 -->
 	<input type="hidden" id="pPrice" name="pPrice" value="<c:out value="${picturePrice}"/>"/><!-- 그림문자 단가 -->
@@ -3148,24 +3222,14 @@
 	<input type="hidden" id="evnLongMsgCnt" name="evnLongMsgCnt" value="0"/><!-- 치환 이벤트 장문 건수 -->
 
     <div class="heading">
-        <h2>선거 문자전송</h2>
+        <h2>선거-자동동보문자</h2>
         <div class="election_btnWrap">
-        	<button type="button" class="button2 info" onclick="infoPop('selectMsgDataView2');">발송규정</button>
-        	<button type="button" class="button2 info" data-tooltip="candidate_popup03">사용안내</button>
-        	<c:choose>
-        		<c:when test="${empty LoginVO}">
-					<button type="button" class="btnType" onclick="javascript:fn_candidateLoginChk(); return false;"><i class="election_btn1"></i>후보자 등록</button>	        		
-        		</c:when>
-        		<c:when test="${not empty mberManageVO && mberManageVO.dept eq 'c'}">
-        			<button type="button" class="btnType" onclick="javascript:fn_mberDeptChk(); return false;"><i class="election_btn1"></i>후보자 등록</button>
-        		</c:when>
-        		<c:otherwise>
-        			<button type="button" class="btnType" data-tooltip="candidate_popup01"><i class="election_btn1"></i>후보자 등록</button>	
-        		</c:otherwise>
-        	</c:choose>
-               <button type="button" class="btnType" onclick="location.href='/web/member/pay/BillPub.do'"><i class="election_btn2"></i>세금계산서</button>
-               <button type="button" class="btnType" onclick="location.href='/web/mjon/msgsent/selectMsgSentView.do'"><i class="election_btn3"></i>발송결과 출력하기</button>
-           </div>
+			<button type="button" class="button2 info" onclick="infoPop('selectMsgDataView2');">발송규정</button>
+			<button type="button" class="button2 info" data-tooltip="candidate_popup03">사용안내</button>
+			<button type="button" class="btnType" data-tooltip="candidate_popup01"><i class="election_btn1"></i>후보자 등록</button>
+			<button type="button" id="autoElectionBtn" class="btnType" data-tooltip="alert_layer_popup" style="display:none;" /> <%----%>
+			<button type="button" id="autoElectionBtn" class="btnType" data-tooltip="alert_layer_popup02" style="display:none;" />
+	   </div>
     </div>
     <div class="send_general">
         <div class="send_left">
@@ -3176,10 +3240,9 @@
                     <col style="width: auto;">
                 </colgroup>
                 <tbody>
-					<tr>
-						<input type="hidden" id="send_adYnY" name="send_adYn" value="Y">
-	                    <td colspan="2" class="ele_te">※ 자동동보문자를 <span>한번에 20,000건 이상 보내실 경우에는 꼭 고객센터(1661-3553)</span>로 연락주시어 발송 요청 후 진행해 주시길 바랍니다<span id="hdnLink">.</span></td>
-                    </tr>
+<%--					<tr>--%>
+<%--	                    <td colspan="2" class="ele_te">※ 자동1동보문자를 <span>한번에 20,000건 이상 보내실 경우에는 꼭 고객센터(1551-8011)</span>로 연락주시어 발송 요청 후 진행해 주시길 바랍니다<span id="hdnLink">.</span></td>--%>
+<%--                    </tr>--%>
                     <tr>
 						<th scope="row">발신번호</th>
 						<td class="put_num">
@@ -3204,9 +3267,9 @@
 					    <td>
 					   		<ul class="title_wrap">
 					   			<li>
-					   				<input id="title_y" type="radio"name="title_status" value="Y" onchange="titleStatus(this);">
+					   				<input id="title_y" type="radio" name="subjectChkYn" value="Y" onchange="titleStatus(this);">
 					             <label for="title_y">사용</label>
-					             <input id="title_n" type="radio" name="title_status" value="N" onchange="titleStatus(this);" checked="checked">
+					             <input id="title_n" type="radio" name="subjectChkYn" value="N" onchange="titleStatus(this);" checked="checked">
 					             <label for="title_n">사용안함</label>
 					   			</li>
 					   			<li class="textbox">
@@ -3355,10 +3418,33 @@
 						<td class="putText">
 							<div class="clearfix receipt_num">
 								<div class="receipt_num_top">
-									<label for="callTo" class="label">받는 번호입력</label>
+
+									<label for="" class="label">받는 번호입력</label>
+									<textarea name="callTo" id="callTo" cols="30" rows="10" class="receipt_num"
+											  placeholder="번호를 입력하세요"
+											  onfocus="this.placeholder=''"
+											  onblur="this.placeholder='번호를 입력하세요'"
+											  style="width:340px;"></textarea>
+									<!-- <button type="button" class="btnType btnType6">번호추가</button> -->
+									<div class="btn_popup_wrap">
+										<button type="button" class="btnType btnType6 btn_add_number addCallToF">번호추가<i class="qmMark"></i></button>
+										<span style="display:block;margin:10px 0 0 0;"><span class="vMiddle">*</span> 중복번호는 한번만 추가됩니다.</span>
+										<div class="error_hover_cont send_hover_cont">
+											<!-- 												<p>휴대폰 번호 입력 시 해당 휴대폰 번호에 대한 형식이 어긋나거나 휴대폰 번호에 오류가 있는지 등을 검사하는 기능</p> -->
+											<p>줄바꿈(Enter) 기준으로 핸드폰 번호 입력이 가능합니다.</p>
+											<span>
+													(예시)<br/>
+													010-1234-0001↵<br/>
+													010-1235-0002↵<br/>
+													01012350003↵<br/>
+													01012350004↵<br/>
+												</span>
+										</div>
+									</div>
+									<%--<label for="callTo" class="label">받는 번호입력</label>
 									<input type="text" id="callTo" name="callTo"  placeholder="번호를 입력하세요" oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*)\./g, '$1');" 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">
@@ -3395,13 +3481,13 @@
 										<div class="btn_popup_wrap">
 											<button type="button" data-tooltip="popup05" class="btnType btnType7 tab2" onclick="getMjMsgSentListAll('1');">재전송</button>
 										</div>
-										<div class="btn_popup_wrap check_validity_wrap">
+										<%--<div class="btn_popup_wrap check_validity_wrap">
 											<button type="button" class="btnType btnType7 check_validity">오류 검사 <i class="qmMark"></i></button>
 											<div class="error_hover_cont send_hover_cont">
 												<p>휴대폰 번호 입력 시 해당 휴대폰 번호에 대한 형식이 어긋나거나 휴대폰 번호에 오류가 있는지 등을 검사하는 기능</p>
 												<span>(예시) 010-1234-0001(O) / 010-12345-0001(X)</span>
 											</div>
-										</div>
+										</div>--%>
 									</div>
 								</div>
 								<div class="list_bottom clearfix">
@@ -3427,7 +3513,7 @@
 	                                   		단문 : <strong>20</strong>건<span>/</span>장문 : <strong>150</strong>건<span>/</span>그림문자 : <strong>30</strong>건
 	                                   	</div>
 									</div>
-									<p class="price" ><span id="totalPriceTxt">0</span>원<span>(부가세 포함)</span></p>
+									<p class="price" ><span id="totalPriceTxt">0</span>원</p>
 								</div>
 								<c:if test="${eventRemainCash > 0  && eventMberInfo.eventStatus eq 'Y'}">
 									<p style="text-align: right; font-size: 14px; color: #666; margin: -10px 0 15px 0; font-weight: 300;">* 이벤트회원의 발송금액은 이벤트단가를 적용하여 계산된 금액이므로 실제 발송금액과 다를 수 있습니다.</p>
 
src/main/webapp/WEB-INF/jsp/web/msgcampain/MsgDataSMLView_backup_20260223.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/web/msgcampain/MsgDataSMLView_backup_20260223.jsp
@@ -0,0 +1,3628 @@
+<%@ 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" src="<c:url value='/js/txtSpecialReplace.js?date=202304250001'/>"></script>
+<!-- 주소록 유효성 체크 공통유틸로 인해 추가 -->
+<script type="text/javascript" src="<c:url value='/js/web/addr/cmn.js?date=202409021440'/>"></script>
+
+<% pageContext.setAttribute("newLineChar", "\r\n"); %>
+<script type="text/javascript">
+
+
+var tableErrorData = [];
+var totRows = 0; // 좌측 받는사람 총 갯수
+
+/* 파일등록 */
+var _fileIdx = 0;
+var _fileForm2 = new Array();
+var fileExt = ""; // 첨부파일 확장자
+var excelAddr = []; //엑셀 불러오기에서 내용 저장하는 배열 변수
+
+$(document).ready(function (){
+	// 발송금액 단가표시
+	SetPriceWrapOpen();	
+	
+	//미리보기 이미지 영역 숨김 처리
+	$('.preiew_img').hide();
+	$('.prePhoto').hide();
+	
+	//최초 화면 문자열 길이 체크해주기
+	var strCon = $('#smsTxtArea').val();
+	fnByteString(strCon);
+	
+	//선거문자 텍스트 내용 추가해주기
+	advMsgInsert();
+		
+	
+	//문자 내용 입력시 바이트수 계산하기
+	$('#smsTxtArea').keyup(function(e){
+		
+		var contents = $(this).val();
+		 
+		fnByteString(contents);
+		
+	});//문자 바이트수 계산하기 끝
+	
+	
+	//받는사람 연락처  Tabulator 처리
+	//Tabulator AJAX Data Loading
+	tableL = new Tabulator(".callList_box", {
+		height:"255px",
+	    layout:"fitColumns",
+	    headerHozAlign:"center",
+	    validationMode:"highlight",
+	    placeholder:"복사(Ctrl+C)한 내용을 여기에 붙여넣기(Ctrl+V) 해주세요.", //fit columns to width of table (optional)
+	    resizableColumns:false,
+	    columnDefaults:{ // 공통설정
+	        hozAlign: "center",
+	        headerHozAlign: "center",
+	        editor: "input",
+	        editor: false
+	    },
+	 	columns:[ //Define Table Columns
+	 		{formatter:"rowSelection", headerHozAlign:"center", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", width:5, headerSort:false, cellClick:function(e, cell){
+	 	        cell.getRow().toggleSelect();
+		 	}}, 
+			{formatter:"rownum", align:"center" ,title:"No", hozAlign:"center", headerHozAlign:"center", width:40},
+		 	{title:"이름", field:"name", editor:false, validator:["maxLength:12"], cellEdited:function(cell){
+		 	    fnReplCell();
+		    }},
+		 	{title:"휴대폰", field:"phone", width:100, editor:false, validator:["required","minLength:10", "maxLength:12"]},
+		 	{title:"[*1*]", field:"rep1", minWidth:60, editor:false, validator:["maxLength:40"], cellEdited:function(cell){
+		 	    fnReplCell();
+		    }},
+		 	{title:"[*2*]", field:"rep2", minWidth:60, editor:false, validator:["maxLength:40"], cellEdited:function(cell){
+		 		fnReplCell();
+		    }},
+		 	{title:"[*3*]", field:"rep3", minWidth:60, editor:false, validator:["maxLength:40"], cellEdited:function(cell){
+		 		fnReplCell();
+		    }},
+		 	{title:"[*4*]", field:"rep4", minWidth:60, editor:false, validator:["maxLength:40"], cellEdited:function(cell){
+		 		fnReplCell();
+		    }},
+		 	
+	 	],
+	 	validationFailed:function(cell, value, parameters){ // 유효성 체크 함수 - 아직 잘 모르겠음 
+	        //take action on validation fail
+	 		var valid = cell.isValid();
+	 		var fieldNm = cell.getField();
+	 		var cellVal = cell.getValue();
+	 		var returnVal = "";
+	 		if(!valid){
+	 			if(fieldNm == "name"){
+	 				alert("받는사람 이름은 최대 12글자까지만 입력 가능합니다.");
+	 				cell.setValue(strMaxLengthSubstring(cellVal, 11)); //스크립트 함수가 0부터 시작이므로 원하는 글자수 -1을 해줘야한다.
+	 				cell.clearValidation();
+	 			}else if(fieldNm == "phone"){
+	 				alert("휴대폰번호는 하이픈(-)을 제외한 숫자만 정확히 입력해 주세요.");
+	 			}else{
+		 			alert("치환문자를 정확히 입력해 주세요. 40글자 이내로 입력 가능합니다.");
+		 			cell.setValue(strMaxLengthSubstring(cellVal, 39));
+		 			cell.clearValidation();
+	 			}
+	 		}
+	 		return value % parameters.phone;
+	    },
+	});
+	
+	// 주소록 불러오기 Tabulator 초기화
+	tableAddr = new Tabulator(".callAddr_box", {
+	    height: "255px",
+	    layout: "fitColumns",
+	    headerHozAlign: "center",
+	    validationMode: "highlight",
+	    placeholder: "주소록 그룹을 선택해 주세요.", 
+	    resizableColumns: false,
+		progressiveLoad:"scroll",
+	    columns: [
+	    	{formatter:"rowSelection", headerHozAlign:"center", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", width:5, headerSort:false, cellClick:function(e, cell){
+	 	        cell.getRow().toggleSelect();
+		 	}}, 
+	        {formatter: "rownum", align: "center", title: "No", hozAlign: "center", headerHozAlign: "center", width: 60},
+	        {title: "그룹명", hozAlign: "center", field: "groupNm", editor: false, width: 100, validator: ["required", "minLength:2", "maxLength:40"]},
+	        {title: "이름", hozAlign: "center", field: "name", editor: false, width: 100, validator: ["maxLength:12"]},
+	        {title: "휴대폰번호", hozAlign: "center", field: "phone", editor: false, width: 100, validator: ["required", "minLength:10", "maxLength:11"]},
+	        {title: "[*1*]", hozAlign: "center", field: "rep1", editor: false, width: 84, validator: ["maxLength:40"]},
+	        {title: "[*2*]", hozAlign: "center", field: "rep2", editor: false, width: 84, validator: ["maxLength:40"]},
+	        {title: "[*3*]", hozAlign: "center", field: "rep3", editor: false, width: 84, validator: ["maxLength:40"]},
+	        {title: "[*4*]", hozAlign: "center", field: "rep4", editor: false, width: 84, validator: ["maxLength:40"]},
+	    ],
+	    validationFailed: function(cell, value, parameters) {
+	        var valid = cell.isValid();
+	        var fieldNm = cell.getField();
+	        if (!valid) {
+	            if (fieldNm == "addrName") {
+	                alert("받는사람 이름은 최대 12글자까지만 입력 가능합니다.");
+	            } else if (fieldNm == "addrPhone") {
+	                alert("휴대폰번호는 하이픈(-)을 제외한 숫자만 정확히 입력해 주세요.");
+	            } else if (fieldNm == "addrGroupNm") {
+	                alert("그룹명을 정확히 입력해 주세요. 2 ~ 40글자 이내로 입력 가능합니다.");
+	            } else {
+	                alert("치환문자를 정확히 입력해 주세요. 100글자 이내로 입력 가능합니다.");
+	            }
+	            cell.setValue("");
+	        }
+	        console.log('parameters : ', parameters);
+	        return value % parameters.addrPhone;
+	    },
+	});
+	
+	
+	//핸드폰 번호 Tabulator에서 수정시 중복 체크
+	function fnDuplPhone(){
+		
+		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.trim()) , 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});
+			}
+		}
+		
+		//수신목록에서 중복 휴대폰문자가 있는지 체크해주기
+		var dupCnt = dupliPhoneDataChk(tableData);
+		if(dupCnt > 0){
+			if(confirm("동일한 휴대폰 번호가 받는사람 목록에 등록되어 있습니다. 중복 번호를 삭제하시겠습니까?")){
+				
+				//수신목록에서 중복 휴대폰 번호 삭제해주기
+				tableL.clearData(); //기존 받는사람 목록을 삭제.
+				tableL.addData(dupliPhoneData(tableData)); // 받는사람 목록에 주소 정보 입력하기
+				_fileForm2 = []; //form file data 초기화
+				_fileIdx = 0;	//form file idx 초기화
+				
+				totRows = tableL.getRows().length; 
+				updateTotCnt(totRows); //전체 데이터 갯수 구하기
+			}
+		}
+	}
+	
+	//받는사람 목록에 복사/붙여넣기 기능 처리
+	$('.callList_box').on('paste', function (e) {
+		
+		var element = e.originalEvent.clipboardData.getData('text'); // 클립보드에 복사한 데이터 가져오기
+		
+		var elmSplit= [];
+		  
+		elmSplit = element.split("\n");
+		
+		var elmLen = elmSplit.length;
+		
+		  
+		if(elmLen < 0){
+			  
+			alert("붙여넣을 연락처를 복사해주세요.");
+			return false;
+			  
+		}else{
+			tableErrorData.length = 0;	// 오류 번호 배열 초기화
+			
+			var splitData = [];
+			var realPhone = [];
+			for(var i=0; i < elmLen; i++){
+				  
+				var splitStr = elmSplit[i]; 
+				var tabData = [];
+				var comData = [];
+				
+				if(splitStr.indexOf('\t') != -1){
+					splitData = splitStr.split('\t'); //탭 구분으로 데이터 분할
+				}else if(splitStr.indexOf(',') != -1){
+					splitData = splitStr.split(','); //콤마 구분으로 데이터 분할
+				}else{
+					splitData = splitStr.split(' ');
+				}
+				
+				
+				if(splitData.length == 0){// 데이터가 없는경우
+					
+					alert("탭으로 구분하여 데이터를 복사해 주세요.");
+				  	return false;
+				  
+				}else if(splitData.length == 1){// 데이터가 탭으로 구분이 없는 경우
+					
+					for(var j=0; j < splitData.length; j++){
+						if(checkHpNum(splitData[j].trim())){//핸드폰 양식이 맞는지 확인
+							//배열 끝에 데이터 추가해 주기
+							realPhone.push({phone: removeDash(splitData[j].trim()), name: ""});
+						}
+						else {
+							if (splitData[j].trim() != '' && splitData[j].trim() != null && splitData[j].trim() != undefined) {
+								tableErrorData.push(splitData[j].trim());
+							}
+						}
+					}
+				
+				}else{//데이터가 탭으로 구분되어 이름, 연락처로 구분된 경우
+					
+					var phone = "";	//핸드폰번호
+					var name = "";	//이름
+					var rep1 = "";	//치환문자1
+					var rep2 = "";	//치환문자2
+					var rep3 = "";	//치환문자3
+					var rep4 = "";	//치환문자4
+					var isPhoneValid = false;
+					for(var j=0; j < splitData.length; j++){
+
+						if(j == 0){
+							name = splitData[j].trim();
+						}
+						
+						if(j == 1){
+							if(checkHpNum(splitData[j].trim())){//핸드폰 양식이 맞는지 확인
+								phone = removeDash(splitData[j].trim());
+								isPhoneValid = true;
+							}else{
+								if (splitData[j].trim() != '' && splitData[j].trim() != null && splitData[j].trim() != undefined) {
+									tableErrorData.push(splitData[j].trim());
+								}
+							}
+						}
+						
+						if(j == 2){	//치환문자1
+							rep1 = splitData[j].trim();
+						}
+						
+						if(j == 3){	//치환문자2
+							rep2 = splitData[j].trim();
+						}
+						
+						if(j == 4){	//치환문자3
+							rep3 = splitData[j].trim();
+						}
+						
+						if(j == 5){	//치환문자4
+							rep4 = splitData[j].trim();
+						}
+					}
+					
+					if (isPhoneValid == true) {
+						//배열 끝에 데이터 추가해 주기
+						realPhone.push({phone: phone, name: name, rep1 : rep1, rep2 : rep2, rep3 : rep3, rep4 : rep4 });
+					}
+					
+				}//else end
+				  
+			}
+			
+			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.trim()) , 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,  });
+				}
+			}
+			
+			if(realPhone.length > 0){
+				for(var j=0; j < realPhone.length; j++){
+					tableData.push({phone: removeDash(realPhone[j].phone.trim()) , name: realPhone[j].name, rep1: realPhone[j].rep1, rep2: realPhone[j].rep2, rep3: realPhone[j].rep3, rep4: realPhone[j].rep4});
+				}
+			}
+				
+			//중복 연락처 1개만 남기고 삭제하기
+			var removeDuplPhone = dupliPhoneData(tableData);
+			  
+			//수신자 리스트에 전화번호 추가해주기
+			tableL.setData(removeDuplPhone);
+			
+			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);
+			}
+
+			if (tableErrorData.length > 0) {
+				alert("올바르지 않은 휴대폰 번호가 "+ tableErrorData.length +" 건 있습니다.");
+			}			
+		}
+	});
+	
+	//받는사람 번호 버튼 클릭시 Tabulator에 데이터 넣어주기
+	$('.addCallToF').click(function(){ 
+		
+		var callToNum = $('#callTo').val();
+		if(callToNum == null || callToNum == ""){
+			
+			alert("받는사람 번호를 입력해 주세요.");
+			return false;
+			
+		}else if(!checkHpNum(callToNum)){	
+			
+			alert("올바른 전화번호를 입력해 주세요.");
+			$('#callTo').val("");
+			return false;
+		}
+		
+		//핸드폰 번호에 '-' 문자 제거하기
+		callToNum = removeDash(callToNum);
+	    
+	    //기존 받는사람 연락처 모두 불러오기
+	    var data = tableL.getRows();
+	    var tableData = [];
+	    var dpCnt = 0;
+	    for(var i=0; i < tableL.getRows().length; i++){
+	    	if(callToNum == data[i].getData().phone){
+	    		dpCnt++;
+	    	}
+	    }
+	    
+	    if(dpCnt > 0){
+	    	alert("받는사람 리스트에 동일한 연락처가 있습니다.");
+	    	$('#callTo').val("");
+	    	return false;
+	    }else{
+	    	
+	    	tabledata = [{phone: callToNum},];
+	    	
+	    	//빈 row 데이터 삭제하기
+	    	var befData = tableL.getRows();
+	    	var totLen = tableL.getRows().length;
+	    	
+	    	for(var i=0; i < totLen; i++){
+		    	tableData.push({phone: data[i].getData().phone.trim(), name: data[i].getData().name});
+		    }
+			
+	    	//연락처 추가해 주기
+			addPhoneInfo(tabledata);
+		    $('#callTo').val("");
+	    }
+	});
+	
+	//받는사람 전체삭제 버튼 처리
+	$('.all_del').click(function(){
+		
+		var data = tableL.getRows();	
+	
+		if(data == null || data == ""){
+			alert("받는사람을 추가해 주세요.");
+			return false;
+		}else{
+			if(confirm("받는사람 목록을 모두 삭제하시겠습니까?")){
+				tableL.clearData();
+				$("#rowTotCnt").text(0); //총건수 수정
+				$("#rowDupCnt").text(0); //중복건수 수정
+				totalPriceSum(0);		 //결제 금액 수정
+			}
+		}
+	});
+	
+	// 받는사람 선택삭제 버튼 처리해주기
+	$('.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("선택하신 받는 사람을 삭제하시겠습니까?")){
+				
+				for(var i=0; i < selectedData.length; i++){
+					selectedData[i].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);
+				}
+			}
+		}
+	});
+	
+	//주소록 불러오기 버튼 클릭시
+	$('.popupAddr').click(function(){
+		
+		var login = '${LoginVO.id}';
+		
+		if(login == null || login == ''){
+			alert("로그인 후 이용이 가능합니다.");
+			return false;
+		}
+		
+		$("#addrGroupLoad").load("/web/mjon/msgcampain/selectAddrGroupListAjax.do", "" ,function(response, status, xhr){
+			//리스트 스크롤 처리해주기
+			$(".adr_pop_list").mCustomScrollbar({
+				axis: 'y',
+				scrollbarPosition: "outside",
+				theme: "dark",
+				autoHideScrollbar: false
+			});
+		});
+		
+	});
+	
+	//엑섹불러오기 버튼 클릭시 파일 첨부 실행
+	$('.c3').click(function(){ // 엑셀파일 불러오기 선택 시
+		$("#excelFile").click();
+	});
+	
+	//최근전송내역 팝업 선택추가 버튼 처리(체크내역 받는사람 리스트로 추가해주기)
+	$(document).on('click', '#latestAddPhone', function (){
+		var addPhoneList = []; //신규로 추가할 전화번호 저장변수
+		$("input:checkbox[name='latAddrChk']:checked").each(function(index){
+			var chkPhone = $(this).val();
+			if(!checkHpNum(chkPhone)){
+				alert("올바른 전화번호가 아닙니다.");
+				return false;
+			}else{
+				addPhoneList.push({phone: removeDash(chkPhone.trim())});
+			}
+		});
+		
+		if(addPhoneList.length > 0){
+			//연락처 추가해 주기
+			addPhoneInfo(addPhoneList);
+			$("#btnLatestAddPhoneClose").trigger("click");
+		}
+		else {
+			alert("연락처를 선택해주세요.");
+			return false;
+		}		
+	});
+	
+	//최근전송내역 팝업 전체추가 버튼 처리
+	$(document).on('click', '#latestAddPhoneAll', function (){
+		var addPhoneList = []; //신규로 추가할 전화번호 저장변수
+		$("input:checkbox[name='latAddrChk']").each(function(index){
+			var chkPhone = $(this).val();
+			if(!checkHpNum(chkPhone)){
+				alert("올바른 전화번호가 아닙니다.");
+				return false;
+			}else{
+				addPhoneList.push({phone: removeDash(chkPhone.trim())});
+			}
+		});
+		
+		if(addPhoneList.length > 0){
+			//연락처 추가해 주기
+			addPhoneInfo(addPhoneList);
+			$("#btnLatestAddPhoneClose").trigger("click");
+		}
+		else {
+			alert("연락처가 없습니다.");
+			return false;
+		}		
+	});
+	
+	//최근전송내역 팝업 선택 취소 버튼 처리
+	$(document).on('click', '#latestCancelPhone', function (){
+		$("input[name=latAddrChk]").prop("checked", false);
+	});
+	
+	//최근전송내역 팝업 삭제 버튼 처리
+	$(document).on('click', '#latestAddrDel', function (){
+		$(this).parent("#latestLi").remove();
+	});
+	
+	//자주보내는 번호 팝업 선택추가 버튼 처리(체크내역 받는사람 리스트로 추가해주기)
+	$(document).on('click', '#bookMarkAddPhone', function (){
+		var addPhoneList = []; //신규로 추가할 전화번호 저장변수
+		$("input:checkbox[name='bookAddrChk']:checked").each(function(index){
+			var chkPhone = $(this).val();
+			if(!checkHpNum(chkPhone)){
+				alert("올바른 전화번호가 아닙니다.");
+				return false;
+			}else{
+				addPhoneList.push({phone: removeDash(chkPhone.trim())});
+			}
+		});
+		
+		if(addPhoneList.length > 0){
+			//연락처 추가해 주기
+			addPhoneInfo(addPhoneList);
+			$("#btnLatestAddPhoneClose").trigger("click");
+		}
+		else {
+			alert("연락처를 선택해주세요.");
+			return false;
+		}		
+	});
+	
+	//자주보내는 번호 팝업 선택추가 버튼 처리(체크내역 받는사람 리스트로 추가해주기)
+	$(document).on('click', '#bookMarkAddPhoneAll', function (){
+		var addPhoneList = []; //신규로 추가할 전화번호 저장변수
+		$("input:checkbox[name='bookAddrChk']").each(function(index){
+			var chkPhone = $(this).val();
+			if(!checkHpNum(chkPhone)){
+				alert("올바른 전화번호가 아닙니다.");
+				return false;
+			}else{
+				addPhoneList.push({phone: removeDash(chkPhone.trim())});
+			}
+		});
+		
+		if(addPhoneList.length > 0){
+			//연락처 추가해 주기
+			addPhoneInfo(addPhoneList);
+			$("#btnLatestAddPhoneClose").trigger("click");
+		}
+		else {
+			alert("연락처가 없습니다.");
+			return false;
+		}		
+	});
+	
+	//자주보내는 번호 팝업 선택 취소 버튼 처리
+	$(document).on('click', '#bookMarkCancelPhone', function (){
+		$("input[name=bookAddrChk]").prop("checked", false);
+	});
+	
+	//자주보내는 번호 팝업 삭제 버튼 처리
+	$(document).on('click', '#bookMarkAddrDel', function (){
+		$(this).parent("#bookMarkLi").remove();
+	});
+	
+	
+	//오류 검사 버튼 처리
+	$('.check_validity').click(function(){
+		
+		var invalid = tableL.getInvalidCells();		//오류 데이터 체크
+		var dataLen = tableL.getRows().length;		//연락처 데이터 갯수
+		var totLen = invalid.length;				//오류 데이터 갯수
+		var errMsg = "";							//최종 alert에 표시할 메시지 저장 변수
+		
+		if(dataLen > 0){ //연락처 정보가 있으면 수행
+			
+			if(totLen > 0){ //내용에 오류가 있으면 수행
+				
+				//오류 데이터 값 저장
+				for(var i=0; i < totLen; i++){
+					var cellValue = invalid[i].getValue();
+					if(i == 0){
+						errMsg = cellValue;
+					}else{
+						errMsg = errMsg +", "+ cellValue;
+					}
+				}
+				
+				if(errMsg == "" || errMsg == null){
+					alert("내용에 오류가 있습니다.");
+					return false;
+				}else{
+					alert(errMsg + "의 내용에 오류가 있습니다.");
+					return false;
+				}
+				
+			}else{
+				alert("오류 데이터가 없습니다.");
+				return false;
+			}
+			
+		}else{
+			alert("연락처를 입력해 주세요.");
+			return false;
+		}
+	});
+	
+	//문자입력창의 첨부된 이미지 순서를 바꿀 때
+	$(document).on('mouseup', '.thumb_wrap img', function (){
+		//미리보기 창의 이미지 순서를 변경한다
+		setTimeout(function() { 
+			var previewHtml = "";
+			var imgCnt = $("#imgCnt").val();
+			//이미지 갯수만큼 for문 돌림
+
+			for(var i=0; i<imgCnt; i++) {
+				var imgTag = $(".thumb_wrap li:eq("+i+") div").html(); // 썸네일에 있는 이미지 태그 가져오기
+				previewHtml += '<div class="img_box preBoxF on_scroll_img" id="preBoxF'+(i+1)+'">'
+				previewHtml += imgTag;
+				previewHtml += '</div>'
+			}
+			$('.preViewShort div').remove(); //미리보기 영역에 있던 이미지 다 지우고
+			$('.preViewShort').append(previewHtml);  //새로 sorting된 이미지 그려주기
+		}, 100);
+		
+	});
+	
+	//문자 샘플 탭, 그림문자 샘플 탭 선택시 옵션 초기화
+	$('.tab').click(function(){
+
+		var index = $(this).index();
+		var form = document.letterForm;
+		
+		if($(this).hasClass("active") === true){
+			if(index == 0){
+				form.pageIndex.value = 1;
+				form.letterType.value = "S";
+				form.categoryCode.value = "";
+				form.hashTag.value = "";
+			}else if(index == 1){
+				form.pageIndex.value = 1;
+				form.letterType.value = "P";
+				form.categoryCode.value = "";
+				form.hashTag.value = "";
+			}else if(index == 2){
+				setTimeout(function(){ 
+			    	map.relayout();
+			    	map.setCenter(testcoords);
+			    }, 0);
+			}
+		}
+	});
+	
+	
+	//이미지 선택시 그림문자 처리
+	$(document).on('click', '.photoOnImg', function(){ 
+		
+		// 클릭 시 조회수 증가 로직
+		var letterId = $(this).attr('id');
+		
+		var url = "/web/mjon/msgdata/updateSmsTemplateCntAjax.do";
+		
+		$.ajax({
+			type: "POST",
+			url: url,
+			data: {'letterId':letterId},
+			dataType:'json',
+			async: false,
+			cache: false,
+			success: function (returnData, status) {
+				console.log("status : ", status);
+			},
+			error: function (e) {console.log("ERROR : ", e); }
+		});
+		// 클릭 시 조회수 증가 로직 끝
+		
+		var imgId = $(this).parent().find("input").val();
+		imageControl($(this), "edit_n", "Template", imgId);
+		
+		var contents = $('#smsTxtArea').val();
+		//(contents);
+		
+		totRows = tableL.getRows().length; 
+		updateTotCnt(totRows); //전체 데이터 갯수 구하기
+		
+		//일괄변환 문구 결제금액 처리
+		if(contents.indexOf("[*이름*]")  > -1
+				|| contents.indexOf("[*1*]") > -1
+				|| contents.indexOf("[*2*]") > -1
+				|| contents.indexOf("[*3*]") > -1
+				|| contents.indexOf("[*4*]") > -1){
+			
+			fnReplCell();
+			
+		}else{
+			
+			//결제금액 표시해주기
+			var totalPrice  = totalPriceSum(totRows);
+			$('#totalPrice').text(totalPrice);
+			$('#txtReplYn').val("N");
+		}
+
+		var sendOfT=$('.send_top').offset().top;
+		$('html,body').stop().animate({'scrollTop':sendOfT-60},250);
+	});
+	
+	
+	//그림문자 이미지 삭제 처리 - 동적으로 추가한 객체는 on 함수로 불러올 수 있다.
+	$(document).on('click', '.file_close', function(){ 
+		var delImgPath = ""; //삭제하려는 이미지 경로 받아오기 
+		var index = $(this).parent().index(); // 현재 선택 된 객체 인덱스 번호 받아오기
+		var imgCnt = $("#imgCnt").val(); // 현재 첨부된 이미지의 갯수
+		var contents = $('#smsTxtArea').val();
+		
+		//선택한 태그의 부모 이미지 li 객체 삭제
+		$(this).parent(".delLi").remove();
+		
+		//미리보기 화면에서의 이미지 객체 삭제
+		//삭제하려는 이미지 경로 받아오기
+		delImgPath = $('.preBoxF').eq(index).find("img").attr("src");
+		
+		$('.preBoxF').eq(index).remove();
+		
+		// 삭제한 이미지 경로 배열에서 삭제해 주기
+		for(var i=0; i < imgFilePath.length; i++){
+			
+			if(imgFilePath[i] == delImgPath){
+				
+				imgFilePath.splice(i, 1); //이미지 경로 삭제
+				imgFileId.splice(i, 1);   //이미지 아이디 삭제 - 내 문자 보관함 저장용으로 사용
+				i--;
+			}
+		}
+		
+		$("#imgCnt").val(Number(imgCnt) - 1);
+		
+		//미리보기 포토 1,2,3 번 번호 표시 변경
+		$('.photo_num_02').hide();
+		$('.photo_num_03').hide();
+		if(imgCnt > 2){
+			$('.photo_num_01').show();
+			$('.photo_num_02').show();
+		}else if(imgCnt > 1){
+			$('.photo_num_01').show();
+		}else{
+			
+			//그림을 모두 삭제 했을때 단문으로 변경
+			$('.preShort').show();
+			$('.prePhoto').hide();
+			
+			$('.msg_com').removeClass("msg_photo");
+			$('.msg_com').addClass("msg_short");
+			$('.put_left').removeClass("photo");
+			$('#msgType').val("4"); // 메세지 타입 설정
+			
+			fnByteString(contents);
+		}
+		
+		//수신목록 전체 데이터 갯수 구하기
+		updateTotCnt(totRows);
+		
+		//일괄변환 문구 결제금액 처리
+		if(contents.indexOf("[*이름*]")  > -1
+				|| contents.indexOf("[*1*]") > -1
+				|| contents.indexOf("[*2*]") > -1
+				|| contents.indexOf("[*3*]") > -1
+				|| contents.indexOf("[*4*]") > -1){
+			
+			fnReplCell();
+			
+		}else{
+			
+			//결제금액 표시해주기
+			var totalPrice  = totalPriceSum(totRows);
+			$('#totalPrice').text(totalPrice);
+			$('#txtReplYn').val("N");
+		}
+		
+		var scrollHei = $(".mCustomScrollBox").height();
+		if(scrollHei > 488) {
+			$(".img_box").removeClass("on_scroll_img");
+		}
+	}); 
+	
+	// 초기화 버튼 처리
+	$('.btnReset').click(function(){
+		
+		//일반문자 라이오 선택해 주기
+		$("#send_adYnN").prop("checked", true);
+		
+		$('.delLi').each(function(){
+			$(this).remove();
+		});
+		
+		$('.preBoxF').each(function(){
+			$(this).remove();
+		});
+		
+		//그림 카운트 초기화
+		$('#imgCnt').val(0);
+		
+		//그림을 모두 삭제 했을때 단문으로 변경
+		$('.preShort').show();
+		$('.prePhoto').hide();
+		
+		$('.msg_com').removeClass("msg_photo");
+		$('.msg_com').addClass("msg_short");
+		$('#msgType').val("4"); // 메세지 타입 설정
+		
+		//메세지 내용 초기화
+		$('#smsTxtArea').val("");
+		fnByteString("");
+		
+	});
+	
+	// 동적으로 추가해주기 때문에 on 사용
+	$(document).on('click', '.letterMsg', function(){ //문자 템플릿 선택시 상단 문자 내용에 입력해주기 
+	
+		// 클릭 시 조회수 증가 로직
+		var letterId = $(this).attr('id');
+		
+		var url = "/web/mjon/msgdata/updateSmsTemplateCntAjax.do";
+		
+		$.ajax({
+			type: "POST",
+			url: url,
+			data: {'letterId':letterId},
+			dataType:'json',
+			async: false,
+			cache: false,
+			success: function (returnData, status) {
+				console.log("status : ", status);
+			},
+			error: function (e) {console.log("ERROR : ", e); }
+		});
+		// 클릭 시 조회수 증가 로직 끝
+		
+		var smsTxtArea = $(this).find('.msg_text').html();
+				
+		smsTxtArea = smsTxtArea.replace(/(<br>|<br\/>|<br \/>)/g, '\n');
+		$('#smsTxtArea').val("");
+		$('#smsTxtArea').val(smsTxtArea);
+		fnByteString(smsTxtArea);
+
+		var sendOfT=$('.send_top').offset().top;
+		$('html,body').stop().animate({'scrollTop':sendOfT-60},250);
+		
+	});
+	
+	// 동적으로 추가해주기 때문에 on 사용
+	$(document).on('click', '.btnSearchF', function(){ // 검색 기능 실행 
+		
+		var formL = document.letterForm;
+		var formM = document.myMsgForm;
+		formL.categoryCode.value = ""; //해시태그 검색 시 카테고리 제거
+		formL.upperCateNo.value = ""; //해시태그 검색 시 카테고리 제거
+		
+		var tabIndex = $(".selectedTab").children(".active").index();
+
+		//문자 리스트 불러오기 
+		if(tabIndex == 0) {
+			formL.letterType.value="S";
+			fnLetterListAjax();
+		}
+		//그림 문자 리스트 불러오기
+		if(tabIndex == 1) {
+			formL.letterType.value="P";
+			fnPhotoListAjax();
+		}
+		//내문자함 리스트 불러오기
+		if(tabIndex == 3) {
+			formM.searchKeyword.value = formL.searchKeyword.value; //letterForm의 검색어를 문자함 검색어 부분에 입력해줌
+			fnMyMsgListAjax();
+		}
+		$('.bottom_content.current .area_total_count').show();
+		return false;
+	});
+	
+	//탭 선택시에 검색자 초기화하여 검색하기
+	$(document).on('click', '.selectedTab', function(){ 
+		var formL = document.letterForm;
+		var formM = document.myMsgForm;
+		formL.categoryCode.value = ""; //탭 선택시 카테고리 제거
+		formL.upperCateNo.value = ""; //탭 선택시 카테고리 제거
+		
+		var tabIndex = $(".selectedTab").children(".active").index();
+		
+		//2줄보기, 4줄보기 초기화
+		$("#LPageUnit option:eq(0)").prop("selected", true);
+		$("#PhPageUnit option:eq(0)").prop("selected", true);
+		$("#msgPageUnit option:eq(0)").prop("selected", true);
+
+		$('.bottom_content .area_total_count').hide();
+		 
+		//문자 리스트 불러오기 
+		if(tabIndex == 0) {
+			formL.letterType.value="S";
+			formL.pageUnit.value = "10";
+			formL.searchKeyword.value="";
+			fnLetterListAjax(1);
+		}
+		//그림 문자 리스트 불러오기
+		if(tabIndex == 1) {
+			formL.letterType.value="P";
+			formL.pageUnit.value = "10";
+			formL.searchKeyword.value="";
+			fnPhotoListAjax(1);
+		}
+		//내문자함 리스트 불러오기
+		if(tabIndex == 3) {
+			formL.pageUnit.value = "10";
+			formM.searchKeyword.value = "";
+			fnMyMsgListAjax(1);
+		}
+	});
+	
+	/*
+		단문 / 장문 탭 옵션 선택시 실행 
+	**/
+	
+	$('.tDep1_mType').click(function(){ // 전체,기업, 개인 선택 옵션 처리
+		
+		var mType = $(this).find('.on').text();
+		var form = document.letterForm;
+		
+		if(mType == "전체"){
+			form.memberType.value = "";
+		}else if(mType == "기업"){
+			form.memberType.value = "B";
+		}else{
+			form.memberType.value = "P";
+		}
+		
+		//문자 리스트 불러오기
+		form.categoryCode.value = "";
+		form.hashTag.value = "";
+		form.pageIndex.value = 1;
+		
+		//문자 리스트 불러오기
+		fnLetterListAjax(1);
+		
+	});
+	
+	$('.tDep1_letType').click(function(){ // 단문, 장문 선택 시 옵션처리
+		
+		var letterType = $(this).find('.on').attr("value");
+		var form = document.letterForm;
+		
+		form.letterType.value = letterType;
+		
+		//문자 리스트 불러오기
+		fnLetterListAjax(1);
+		
+	});
+	
+	$('.tDep1_cateCode').click(function(){ // 카테고리 선택 시 옵션 처리
+		
+		var cateCode = $(this).find('.on').attr("value");
+		var form = document.letterForm;
+		
+		if(cateCode == "all"){ //전체 선택시
+			
+			cateCode = "";	
+		
+		} else {
+			//카테고리 코드 클릭 시 해쉬태그 초기화 후 전체 선택
+			form.hashTag.value="";
+			$('.tDep1_hashTag').find('.on').removeClass('on');
+			$('.tDep1_hashTag').find('.hashAll').addClass('on');
+		}
+		form.upperCateNo.value = "";
+		form.categoryCode.value = cateCode;
+		form.pageIndex.value = 1;
+		//카테고리 클릭 시 검색자 초기화
+		form.searchKeyword.value = "";
+		
+		//문자 리스트 불러오기
+		fnLetterListAjax(1);
+		
+	});
+	
+	$('.tDep1_threeCateCode').click(function(){ // 하위 카테고리 선택 시 문자샘플 조회
+		var cateCode = $(this).find('.on').attr("value");
+		var form = document.letterForm;
+		var upperCateNo = $(this).siblings('div').find('.on').attr('value');
+		form.upperCateNo.value = upperCateNo;
+		form.categoryCode.value=cateCode;
+		//해쉬태그 검색자 초기화
+		form.searchKeyword.value = "";
+		form.pageIndex.value = 1;
+		
+		//문자 리스트 불러오기
+		fnLetterListAjax(1);
+		
+	});
+	
+	$('.tDep1_hashTag').click(function(){ // 해시 태그 선택 시 옵션 처리
+		var hashTag = $(this).find('.on').attr("value");
+		var form = document.letterForm;
+		
+		//해쉬태그 클릭 시 카테고리코드 초기화 후 전체 선택
+		form.categoryCode.value="";
+		$('.tDep1_cateCode').find('.on').removeClass('on');
+		$('.tDep1_cateCode').find('.cateAll').addClass('on');
+		//해쉬태그 클릭 시 검색자 초기화
+		form.searchKeyword.value = "";
+		
+		form.hashTag.value = hashTag;
+		form.pageIndex.value = 1;
+		
+		//문자 리스트 불러오기
+		fnLetterListAjax(1);
+	});
+	
+	
+	/*
+		그림문자 탭 옵션 선택시 사용
+	*/
+	
+	$('.tDep2_mType').click(function(){ // 전체,기업, 개인 선택 옵션 처리
+		
+		var mType = $(this).find('.on').text();
+		var form = document.letterForm;
+		
+		if(mType == "전체"){
+			form.memberType.value = "";
+		}else if(mType == "기업"){
+			form.memberType.value = "B";
+		}else{
+			form.memberType.value = "P";
+		}
+		
+		//문자 리스트 불러오기
+		form.letterType.value = "P";
+		form.categoryCode.value = "";
+		form.hashTag.value = "";
+		form.pageIndex.value = 1;
+		
+		fnPhotoListAjax();
+	});
+	
+	$('.tDep2_letType').click(function(){ // 그림문자 선택 
+		var letterType = $(this).find('.on').attr("value");
+		var form = document.letterForm;
+		form.letterType.value = 'P';
+		
+		//문자 리스트 불러오기
+		fnPhotoListAjax(1);
+	});
+	
+	$('.tDep2_cateCode').click(function(){ // 그림 문자 카테고리 선택 시 옵션 처리
+		
+		var cateCode = $(this).find('.on').attr("value");
+		var form = document.letterForm;
+		
+		if(cateCode == "all"){ //전체 선택시
+			cateCode = "";	
+		} else {
+			//카테고리 코드 클릭 시 해쉬태그 초기화 후 전체 선택
+			form.hashTag.value="";
+			$('.tDep2_hashTag').find('.on').removeClass('on');
+			$('.tDep2_hashTag').find('.hashAll').addClass('on');
+		}
+		form.upperCateNo.value = "";
+		form.categoryCode.value = cateCode;
+		form.pageIndex.value = 1;
+		//카테고리 클릭 시 검색자 초기화
+		form.searchKeyword.value = "";
+		//문자 리스트 불러오기
+		fnPhotoListAjax(1);
+		
+	});
+	
+	$('.tDep2_threeCateCode').click(function(){ // 하위 카테고리 선택 시 문자샘플 조회
+		var cateCode = $(this).find('.on').attr("value");
+		var form = document.letterForm;
+		var upperCateNo = $(this).siblings('div').find('.on').attr('value');
+		form.upperCateNo.value = upperCateNo;
+		form.categoryCode.value=cateCode;
+		//해쉬태그 검색자 초기화
+		form.searchKeyword.value = "";
+		form.pageIndex.value = 1;
+		
+		//그림문자 리스트 불러오기
+		fnPhotoListAjax(1);		
+	});
+	
+	$('.tDep2_hashTag').click(function(){ // 그림문자 해시 태그 선택 시 옵션 처리
+		var hashTag = $(this).find('.on').attr("value");
+		var form = document.letterForm;
+		
+		//해쉬태그 클릭 시 카테고리코드 초기화 후 전체 선택
+		form.categoryCode.value="";
+		$('.tDep2_cateCode').find('.on').removeClass('on');
+		$('.tDep2_cateCode').find('.cateAll').addClass('on');
+		//해쉬태그 클릭 시 검색자 초기화
+		form.searchKeyword.value = "";
+		
+		form.hashTag.value = hashTag;
+		form.pageIndex.value = 1;
+		
+		//문자 리스트 불러오기
+		fnPhotoListAjax(1);
+	});
+	
+	
+	$(".fontPlus").click(function () {
+		var currentSize = $(".preview_auto").css("fontSize");
+		var size = parseInt(currentSize, 10) * 1.2;
+		var unit = currentSize.slice(-2);
+		if(size > 65){
+			return false;
+		}
+		$(".preview_auto").css("fontSize", size+unit);
+	});
+	
+	$(".fontMinus").click(function () {
+		var currentSize = $(".preview_auto").css("fontSize");
+		var size = parseInt(currentSize, 10) / 1.2;
+		var unit = currentSize.slice(-2);
+		if(size < 10){
+			return false;
+		}
+		$(".preview_auto").css("fontSize", size+unit);
+	});
+	
+	//즉시, 예약 선택시 날짜 영역 초기 표시
+	var reYn = $("input[name=reserYn]:checked").val();
+	
+	if(reYn == "N"){
+		$('.rev_selected').hide();
+	}else{
+		$('.rev_selected').show();
+	}
+	
+	//즉시 발송 라디오 버튼 선택시 숨김처리
+	$("#reserYnN").on('click', function(){
+		$('.rev_selected').hide();
+		$('.send_rev .send_content').css('padding-bottom','108px');
+		$('.send_btn .btnType:first-child').html('발송하기');
+	});
+	
+	//예약 발송 라디오 버튼 선택시 숨김 해제처리
+	$("#reserYnY").on('click', function(){
+		$('.rev_selected').show();
+		$('.send_rev .send_content').css('padding-bottom','0');
+		$('.send_btn .btnType:first-child').html('예약하기');
+	});
+});
+
+//전체 데이터 갯수 구하는 함수
+function updateTotCnt(data){
+	var rowTotCnt = data;
+	$("#rowTotCnt").text(numberWithCommas(rowTotCnt));
+}
+
+//주소록 불러오기에서 수신자 리스트 tabulator에 데이터 추가해주기
+function addPhoneInfo(data){
+	
+	if(data == null){
+		
+		alert("연락처 정보가 없습니다.");
+		return;
+		
+	}else{
+		
+		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 getStrFileSize(filesize){
+	var sizeStr="";
+	var sizeKB = filesize/1024;
+	if(parseInt(sizeKB) > 1024){
+	    var sizeMB = sizeKB/1024;
+	    sizeStr = sizeMB.toFixed(2)+" MB";
+	}else{
+	    sizeStr = sizeKB.toFixed(2)+" KB";
+	}
+	return sizeStr;
+}
+
+//발송금액 단가표시
+function SetPriceWrapOpen() {
+	var loginVO = '${LoginVO}';
+	//로그인 체크
+	if(loginVO == "" || loginVO == null){
+	}
+	else {
+		// 발송금액 가격안내
+		$("#myPriceWrap").show();		
+	}
+}
+
+//선거 후보자 등록 알림 메세지 처리
+function fn_candidateChk(){
+	alert("선거 후보자를 등록이 되어야 문자 발송이 가능합니다. 후보자 등록을 해주세요.");
+	return false;
+	
+}
+	
+//문자 바이트수 계산하기 함수
+function fnByteString(contents){
+	
+	var totalByte = 0; 
+	var adverYn = $("input[name='send_adYn']:checked").val();
+	var adTxtLeng = conByteLeng($('.ad_txt').text());
+	var denyTxtLeng = 0;
+	var denyTxt = $('.deny_txt').html();
+	
+	//선거문자 하단 문구 줄바꿈 처리하기
+	if(typeof denyTxt !='undefined' && denyTxt != null){
+		denyTxt = denyTxt.replaceAll("<br>","\n");
+		denyTxt = denyTxt.replaceAll("<br/>","\n");
+		denyTxtLeng = conByteLeng(denyTxt);
+	}
+	
+	
+	$('#msgLeng').html("");
+	$('#limitLeng').html("");
+	var conLeng = conByteLeng(contents); // 내용 문자 입력 바이트 수 계산하기
+	
+	console.log(contents);
+	
+	//일반문자, 광고문자에 따른 문자 길이 변경해주기
+	if(adverYn == "N"){
+		
+		$('#msgLeng').text(conLeng);
+		
+		//문자 길이 변수에 저장해주기
+		$('#smsLen').val(conLeng);
+		
+	}else{
+		
+		conLeng = adTxtLeng + conLeng + denyTxtLeng +2; // 상단 광고 텍스트 , 하단 080 문자내용 길이 더해주기 , +2는 엔터 적용
+		$('#msgLeng').text(conLeng);
+		
+		//문자 길이 변수에 저장해주기
+		$('#smsLen').val(conLeng);
+		
+	}
+	
+	var photoSts = $('.delLi').length;
+	if(photoSts > 0){
+		
+		$('#msgLeng').html(conLeng + " / ");
+		$('#limitLeng').html("2000");
+		$('.msg_com').html("그림");
+		$('#msgType').val("6"); // 메세지 타입 설정
+		
+		$('.msg_com').removeClass("msg_short"); //단문 클래스 삭제하고
+		$('.put_left').removeClass("short"); //내용 입력 박스 클래스 삭제
+		$('.msg_com').removeClass("msg_long"); //장문 클래스 삭제하고
+		$('.put_left').removeClass("long"); //내용 입력 박스 클래스 삭제
+		$('.msg_com').addClass("msg_photo"); // 그림 클래스 삽입
+		$('.put_left').addClass("photo");  // 내용 입력 박스에 클래스 삽입
+		$('.put_left').css("display","block");  // 내용 입력 박스에 클래스 삽입
+		$('.msg_title').addClass('active');
+		
+	}else{
+		
+		if(conLeng > 90){
+			
+			$('#msgLeng').html(conLeng + " / ");
+			$('#limitLeng').html("2000");
+			$('.msg_com').html("장문");
+			$('#msgType').val("6"); // 메세지 타입 설정
+			
+			$('.msg_com').removeClass("msg_short"); //단문 클래스 삭제하고
+			$('.put_left').removeClass("short"); //내용 입력 박스 클래스 삭제
+			$('.msg_com').addClass("msg_long"); // 장문 클래스 삽입
+			$('.put_left').addClass("long");  // 내용 입력 박스에 클래스 삽입
+			$('.msg_title').addClass('active');
+			
+		}else{
+			
+			$('#msgLeng').html(conLeng + " / ");
+			$('#limitLeng').html("90");
+			$('.msg_com').html("단문");
+			$('#msgType').val("4"); // 메세지 타입 설정
+			$('.msg_com').removeClass("msg_long"); //단문 클래스 삭제하고
+			$('.put_left').removeClass("long"); //내용 입력 박스 클래스 삭제
+			$('.msg_com').addClass("msg_short"); // 장문 클래스 삽입
+			$('.put_left').addClass("short");  // 내용 입력 박스에 클래스 삽입
+			$('.msg_title, .title_wrap .textbox').removeClass('active');
+			$('#mmsSubject').val("");
+			$('#title_y').prop('checked',false);
+			$('#title_n').prop('checked',true);
+		}
+	}
+	
+	// 미리보기 데이터 입력해 주기 , 줄바꿈 문자 변환해주기
+	if(conLeng > 0){
+		$('.none_txt').text("");
+	}else{
+		$('.none_txt').text("내용을 입력해주세요.");
+	}
+	
+	//미리보기에 내용 입력해 주기
+	$('.realtime').text(contents);
+
+	// 2000byte 초과시 메세지 알림
+	if(conLeng > 2000){
+		
+		//2000바이트 초과시 문자열 잘라서 보여주기
+		var subUnderStr = strUnderLineSubstring(contents, 2000);
+		$('#smsTxtArea').val(subUnderStr);
+		
+		//문자 바이트수 수정해주기
+		$('#msgLeng').text(conByteLeng(subUnderStr));
+		
+		//문자 길이 변수에 저장해주기
+		$('#smsLen').val(conByteLeng(subUnderStr));
+		
+ 		alert("문자 내용은 2000byte를 넘을 수 없습니다.");
+		return false;
+	}
+	
+	//수신목록 전체 데이터 갯수 구하기
+	updateTotCnt(totRows);
+	
+	//일괄변환 문구 결제금액 처리
+	if(contents.indexOf("[*이름*]")  > -1
+			|| contents.indexOf("[*1*]") > -1
+			|| contents.indexOf("[*2*]") > -1
+			|| contents.indexOf("[*3*]") > -1
+			|| contents.indexOf("[*4*]") > -1){
+		
+		fnReplCell();
+		
+	}else{
+		
+		var totalPrice  = totalPriceSum(totRows);
+		$('#totalPrice').text(totalPrice);
+		$('#txtReplYn').val("N");
+		
+	}
+	
+}
+	
+function openPhotoEditor() {
+	var imgCnt = $("#imgCnt").val();
+	
+	if(imgCnt >= 3) {
+		alert("메시지에 첨부할 수 있는 이미지는 최대 3장입니다.");
+		return;		
+	}
+	
+    //만들려는 팝업의 크기
+    var popup_wid = '1100';
+    var popup_ht = '851';
+
+    //중앙 정렬을 위해 윈도우 스크린의 width,height 구하는 변수 만듦
+    var popup_left = (window.screen.width / 2) - (popup_wid / 2);
+    var popup_top =(window.screen.height / 2) - (popup_ht / 2);
+
+    window.open('<c:url value='/web/mjon/msgcampain/openImageEditorPopup.do'/>', 'a', 'width=' + popup_wid +', height='+ popup_ht +', left=' + popup_left + ', top='+ popup_top + ', scrollbar=no' );
+}
+
+//그림샘플 이미지 선택시 문자 내용에 입력 처리
+function imageControl(obj, editYn, imageName, imgId) {
+	
+	var imgCnt = $("#imgCnt").val(); // 현재 페이지에 첨부된 이미지 갯수
+	var imgSrc = obj.attr("src");
+	
+	if(imgCnt >= 3){
+		alert("이미지는 3장만 선택할 수 있습니다.");
+		return false;
+	}
+
+	$('.preShort').hide();
+	$('.prePhoto').show();
+	
+	if($('.msg_com').hasClass("msg_short") === true){
+		
+		$('.msg_com').removeClass("msg_short"); //단문 클래스 삭제하고
+		$('.msg_com').addClass("msg_photo"); // 그림문자용 클래스 삽입
+		$('.put_left').removeClass("short");
+		$('.put_left').addClass("photo");
+		$('.msg_com').html("그림");
+		$('#msgType').val("6"); // 메세지 타입 설정
+		
+		//제목 입력 항목 활성화
+		//document.getElementById("mmsSubject").disabled = false;
+		
+	}else{
+		
+		$('.msg_com').removeClass("msg_long"); //장문 클래스 삭제하고
+		$('.msg_com').addClass("msg_photo"); // 그림문자용 클래스 삽입
+		$('.put_left').removeClass("long");
+		$('.put_left').addClass("photo");
+		$('.msg_com').html("그림");
+		$('#msgType').val("6"); // 메세지 타입 설정
+		
+		//제목 입력 항목 활성화
+		//document.getElementById("mmsSubject").disabled = false;
+		
+	}
+	
+	//이미지 카운트 증가시키기
+	//imgCnt ++;
+	$("#imgCnt").val(Number(imgCnt)+1);
+	
+	
+	//문자 내용 상단에 이미지 이름 영역 객체 추가해주기
+	var imgPath = '<img src="' + imgSrc + '" class="thumb_img '+ editYn +'" alt="thumb1"/>';
+	var liPath = '<li class="delLi '+imageName+'" id="delLi'+ imgCnt +'">'
+				+ '<div>'+ imgPath+ '</div>'
+				+ '<button type="button" class="file_close"><img src="/publish/images/content/thumb_del.png" alt="첨부파일 삭제"></button>'
+				+ '<button type="button" class="file_close_on"><img src="/publish/images/content/thumb_del_on.png" alt="첨부파일 삭제"></button>'
+				+ '</li>';
+				
+				
+		/* "<li class=\"delLi\"><p>" + imgPath + "</p><button type=\"button\" class=\"file_close\"><img class=\"delImg\" src=\"/publish/images/content/file_close.png\" alt=\"첨부파일 삭제\"></button></li>" */
+	$('.liOnImg').append(liPath);	
+		
+	//미리보기 보여주기
+	$('.preiew_img').show();
+	
+	var imgHtml = "";
+	var imgPath = "<div class=\"img_box preBoxF\" id=preBoxF"+ imgCnt +"><img src=\"" + imgSrc + "\" /></div>";
+
+	if($("#imgCnt").val() == 1){
+		$('.preViewShort').append(imgPath);
+		$('.photo_num_01').show();
+		$('.photo_num_02').hide();
+		$('.photo_num_03').hide();
+		//$(".thumb_wrap li:eq(0)").addClass("on");
+		
+	}else if($("#imgCnt").val() == 2){
+		$('.preViewShort').append(imgPath);
+		$('.photo_num_02').show();
+		$(".thumb_wrap li").removeClass("on");
+		//$(".thumb_wrap li:eq(1)").addClass("on");
+		
+	}else if($("#imgCnt").val() == 3){
+		$('.preViewShort').append(imgPath);
+		$('.photo_num_03').show();
+		$(".thumb_wrap li").removeClass("on");
+		//$(".thumb_wrap li:eq(2)").addClass("on");
+		
+	}
+	
+	// 배열에 선택한 이미지 경로 저장해주기
+	imgFilePath.push(imgSrc);
+	
+	// 배열에 선택한 이미지 아이디 저장해주기 - 내 문자 보관함 저장용으로 사용
+	if(typeof(imgId) != 'undefined' && imgId != null && editYn != 'edit_y'){
+		imgFileId.push(imgId);
+	}
+	//문자 길이 및 타입 변경해주기
+	var contents = $('#smsTxtArea').val();
+	fnByteString(contents);
+	
+	var scrollHei = $(".mCustomScrollBox").height();
+	if(scrollHei > 488) {
+		$(".img_box").addClass("on_scroll_img");
+	}
+	
+}
+
+//그림샘플 이미지 선택시 문자 내용에 입력 처리
+function myMsgImageControl(imgSrc, editYn, imageName, imgId) {
+	
+	var imgCnt = $("#imgCnt").val(); // 현재 페이지에 첨부된 이미지 갯수
+	var imgSrc = imgSrc;
+	if(imgCnt >= 3){
+		alert("이미지는 3장만 선택할 수 있습니다.");
+		return false;
+	}
+
+	$('.preShort').hide();
+	$('.prePhoto').show();
+	
+	if($('.msg_com').hasClass("msg_short") === true){
+		
+		$('.msg_com').removeClass("msg_short"); //단문 클래스 삭제하고
+		$('.msg_com').addClass("msg_photo"); // 그림문자용 클래스 삽입
+		$('.put_left').removeClass("short");
+		$('.put_left').addClass("photo");
+		$('.msg_com').html("그림");
+		$('#msgType').val("6"); // 메세지 타입 설정
+		
+		//제목 입력 항목 활성화
+		//document.getElementById("mmsSubject").disabled = false;
+		
+	}else{
+		
+		$('.msg_com').removeClass("msg_long"); //장문 클래스 삭제하고
+		$('.msg_com').addClass("msg_photo"); // 그림문자용 클래스 삽입
+		$('.put_left').removeClass("long");
+		$('.put_left').addClass("photo");
+		$('.msg_com').html("그림");
+		$('#msgType').val("6"); // 메세지 타입 설정
+		
+		//제목 입력 항목 활성화
+		//document.getElementById("mmsSubject").disabled = false;
+		
+	}
+	
+	//이미지 카운트 증가시키기
+	//imgCnt ++;
+	$("#imgCnt").val(Number(imgCnt)+1);
+	
+	//문자 내용 상단에 이미지 이름 영역 객체 추가해주기
+	var imgPath = '<img src="' + imgSrc + '" class="thumb_img '+ editYn +'" alt="thumb1"/>';
+	var liPath = '<li class="delLi '+imageName+'" id="delLi'+ imgCnt +'">'
+				+ '<div>'+ imgPath+ '</div>'
+				+ '<button type="button" class="file_close"><img src="/publish/images/content/thumb_del.png" alt="첨부파일 삭제"></button>'
+				+ '<button type="button" class="file_close_on"><img src="/publish/images/content/thumb_del_on.png" alt="첨부파일 삭제"></button>'
+				+ '</li>';
+				
+	$('.liOnImg').append(liPath);	
+		
+	//미리보기 보여주기
+	$('.preiew_img').show();
+	
+	var imgHtml = "";
+	var imgPath = "<div class=\"img_box preBoxF\" id=preBoxF"+ imgCnt +"><img src=\"" + imgSrc + "\" /></div>";
+
+	if($("#imgCnt").val() == 1){
+		$('.preViewShort').append(imgPath);
+		$('.photo_num_01').show();
+		$('.photo_num_02').hide();
+		$('.photo_num_03').hide();
+	}else if($("#imgCnt").val() == 2){
+		$('.preViewShort').append(imgPath);
+		$('.photo_num_02').show();
+		$(".thumb_wrap li").removeClass("on");
+	}else if($("#imgCnt").val() == 3){
+		$('.preViewShort').append(imgPath);
+		$('.photo_num_03').show();
+		$(".thumb_wrap li").removeClass("on");
+	}
+	
+	// 배열에 선택한 이미지 경로 저장해주기
+	imgFilePath.push(imgSrc);
+	// 배열에 선택한 이미지 아이디 저장해주기 - 내 문자 보관함 저장용으로 사용
+	if(typeof(imgId) != 'undefined' && imgId != null){
+		imgFileId.push(imgId);
+	}
+	//문자 길이 및 타입 변경해주기
+	var contents = $('#smsTxtArea').val();
+	fnByteString(contents);
+	
+	var scrollHei = $(".mCustomScrollBox").height();
+	if(scrollHei > 488) {
+		$(".img_box").addClass("on_scroll_img");
+	}
+	
+}
+
+
+$(document).on('click', '.symbolButton, .changeWord', function (){
+	// 커서 위치에 삽입
+	setCursorInsertText("smsTxtArea", $(this).attr("value"));
+	fnByteString($('#smsTxtArea').val());
+});
+
+$(document).on('click', '#recommBtn', function(){
+	
+	var recommId = $('#recommId').val();
+	
+	if(recommId == ''){
+		alert("추천인 ID를 입력해 주세요.");
+		return false;
+	}
+	
+	var data = new FormData(document.msgForm);
+	var url = "/web/mjon/msgcampain/selectRecommIdCheckAjax.do";
+	
+	$.ajax({
+        type: "POST",
+        enctype: 'multipart/form-data',
+        url: url,
+        data: data,
+        dataType:'json',
+        async: false,
+        processData: false,
+        contentType: false,
+        cache: false,
+        //timeout: 600000,
+        success: function (returnData, status) {
+			if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+				
+				if(returnData.status == "success"){
+					
+					alert("추천인 아이디가 확인 되었습니다.");
+					return false;
+				}else{
+					
+					alert("존재하지 않는 추천인 아이디 입니다.");
+					return false;
+				}
+				
+			} else if(status== 'fail'){
+				alert("추천인 확인에 실패하였습니다. !!");
+			}
+		},
+        error: function (e) { alert("추천인 확인에 실패하였습니다."); console.log("ERROR : ", e); }
+    });
+});
+
+//주소록 불러오기 그룹명 검색 기능처리
+function fnAddrGrpSearch(){
+	
+	var form = document.searchAddrGrpForm;
+	form.searchKeyword.value = form.searchGrpKeyword.value;
+	form.searchCondition.value = "";
+	
+	var sendData = $(document.searchAddrGrpForm).serializeArray();
+	
+	$("#addrGroupLoad").load("/web/mjon/msgcampain/selectAddrGroupListAjax.do", sendData ,function(response, status, xhr){
+		//리스트 스크롤 처리해주기
+		$(".adr_pop_list").mCustomScrollbar({
+			axis: 'y',
+			scrollbarPosition: "outside",
+			theme: "dark",
+			autoHideScrollbar: false
+		});
+	});
+}
+
+//주소록 불러오기 팝업의 그룹 선택시 우측에 주소록 불러오기
+function fnSelectAddrList(type,addrGrpId,item){
+	
+	// 주소록 그룹 열림, 닫힘 폴더이미지 초기화
+	$(".adr_pop_list div p").each(function (index, item) {
+		$(item).find("img").attr("src", "/publish/images/content/close_folder2.png");
+		$(item).find("img").attr("alt", "폴더 닫힘");
+	});
+	
+	var form = document.searchAddrGrpForm;
+	form.type.value = type;
+	form.searchAddrGrpId.value = addrGrpId;
+	form.searchKeyword.value = "";
+	form.searchCondition.value = form.searchAddrCondition.value;
+	
+	//왼쪽 그룹리스트의 그룸명을 선택시 검색어를 초기화해준다.
+	form.searchAddrKeyword.value="";
+	   
+	$(item).find("img").attr("src", "/publish/images/content/open_folder2.png");
+	$(item).find("img").attr("alt", "폴더 열림");
+	
+	loadAddrList();
+}
+
+// 주소록 불러오기 팝업 검색 이벤트
+function fnAddrSearch(){
+	var form = document.searchAddrGrpForm;
+	form.searchKeyword.value = form.searchAddrKeyword.value;
+	form.searchCondition.value = form.searchAddrCondition.value;
+	loadAddrList();
+}
+
+//주소록 불러오기 팝업 검색 리스트 조회
+function loadAddrList(){
+
+	/* serialize 를 사용할때는 processData, contentType 옵션 제가할것 */
+	var data = $("#searchAddrGrpForm").serialize();
+	var url = "/web/mjon/msgcampain/selectMsgAddrListAjaxQ.do";
+	
+	$.ajax({
+        type: "POST",
+        url: url,
+        data: data,
+        dataType:'json',
+        async: true,
+        cache: false,
+        success: function (data) {
+        	console.log('data : ', data);
+			if(data.status == "OK"){
+				
+				var addrList = data.object;
+					
+				if(addrList.length == 0){
+					alert("주소록 정보가 없습니다.");
+					return false;
+				}
+				
+				//우측 주소록 리스트 Tabulator에 입력해주기
+				tableAddr.setData(addrList);
+				
+			} else if(status== 'fail'){
+				alert("주소록 불러오기에 실패하였습니다. !!");
+			}
+		},
+        error: function (e) { 
+        	alert("주소록 불러오기에 실패하였습니다."); console.log("ERROR : ", e); 
+        },
+		beforeSend : function(xmlHttpRequest) {
+        	//로딩창 show
+        	$('.loading_layer').addClass('active');				
+		},	        	        
+        complete : function(xhr, textStatus) {
+        	//로딩창 hide
+        	$('.loading_layer').removeClass('active');
+		}
+    });
+}
+
+//주소록 불러오기에서 수신자 리스트 추가해 주기
+function addrToList_advc(type){
+	var tableSize = tableAddr.getDataCount();
+	var tableData = [];
+	
+	if(tableSize < 1){
+		
+		alert("주소록을 선택해 주세요.");
+		return false;
+	
+	}else{ // 선택한 Row 데이터 저장해주기
+		
+		// 기존 tableL의 데이터를 가져옵니다.
+		var existingData = tableL.getData();
+		var addrData;
+
+		if(type == 'all'){
+			addrData = tableAddr.getData();
+		}else{
+			addrData = tableAddr.getSelectedData();
+		}
+		
+		// 기존 데이터와 새로운 데이터를 합칩니다.
+		var combinedData = existingData.concat(addrData);
+		
+		// 합쳐진 데이터를 tableL에 설정합니다.
+		tableL.setData(combinedData);
+		
+		//일괄변환 문구 결제금액 처리
+		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);
+		} 
+	
+		$(".closeAddr").trigger("click");
+		//주소록 레이어 팝업의 Tabulator 데이터 지워주기
+		tableAddr.clearData();
+	}
+}
+
+
+//주소록 팝업 닫기 기능
+function addrClose(){
+	$(".closeAddr").trigger("click");
+	
+	//주소록 레이어 팝업의 Tabulator 데이터 지워주기
+	tableAddr.clearData();
+}
+
+//내문자함 선택시 저장된 내용 문자 입력영역에 처리해주기
+function fnMyMsgAdd(msgId){
+	
+	var form = document.addMyMsgForm;
+	form.msgId.value = msgId;
+	form.pageType.value = "myMsg";
+	
+	var url = "/web/mjon/msgcampain/selectMsgAddInfoAjax.do";
+	var data = new FormData(document.addMyMsgForm);
+	
+	$.ajax({
+        type: "POST",
+        url: url,
+        data: data,
+        dataType:'json',
+        async: false,
+        processData: false,
+        contentType: false,
+        cache: false,
+        success: function (returnData, status) {
+			if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+				
+				if(returnData.result == "success"){
+					
+					var msgData = returnData.resultMsgInfo;
+					var fileData = returnData.resultMsgAddPhotoInfo;
+					
+					var smsTxt = msgData.smsTxt;
+					var subject = msgData.subject;
+					var fileId = "";
+					var filePath = "";
+					var len = fileData.length;
+					
+					//기존 내용 지워주기
+					//$(".btnReset").trigger("click");
+					$('.delLi').each(function(){
+						$(this).remove();
+					});
+					
+					$('.preBoxF').each(function(){
+						$(this).remove();
+					});
+
+					$('#imgCnt').val(0);
+					
+					//기존 imgFileId, imgFilePath 배열에 있는 내용 초기화 해주기
+					imgFilePath = [];
+					imgFileId = [];
+					
+					//내문자함 텍스트 내용 입력해주기
+					$('#smsTxtArea').val(smsTxt);
+					
+					//첨부 이미지가 있는경우 이미지 처리해주기
+					if(len > 0){
+						
+						for(var i=0; i < len; i++){
+							
+							var num = i + 1;
+							var imgId = fileData[i].atchFileId;
+							var imgSn = fileData[i].fileSn;
+							var fileStreCours = fileData[i].fileStreCours;
+							var streFileNm = fileData[i].streFileNm;
+							var fileExtsn = fileData[i].fileExtsn;
+							
+							/* var imgSrc = fileStreCours + "/" + streFileNm + "." + fileExtsn; */
+							var imgSrc = '/cmm/fms/getImage2.do?atchFileId=' + imgId + '&fileSn=' + imgSn;
+							myMsgImageControl(imgSrc, "edit_n", "Template", imgId);
+						}
+						
+						fnByteString(smsTxt);
+						
+					}else{
+						fnByteString(smsTxt);
+					}
+					
+					//내 문자함 가져오기에서 글자길이 계산을 다시한다.
+					$("#smsTxtArea").trigger("keyup");
+					
+					// 문자전송 상단으로 이동
+					var sendOfT=$('.send_top').offset().top;
+					$('html,body').stop().animate({'scrollTop':sendOfT-60},250);					
+				}else{
+					alert("내문자함 내용을 불러오지 못하였습니다.");
+					return false;
+				}
+				
+			} else if(status== 'fail'){
+				alert("내문자함 내용 입력에 실패하였습니다. !!");
+			}
+		},
+        error: function (e) { alert("내문자함 내용 입력에 실패하였습니다."); console.log("ERROR : ", e); }
+    });
+}
+
+// 후보자 이메일 등록 시 도메인 선택 이벤트(1: 직접입력, 2: 도메인 선택 시)
+function emailChange(email){
+	var emailTxt =  $("input[name=emailDomain]");
+	
+	if(email.value == '1'){
+		$("input[name=emailDomain]").attr('readonly', false);
+		emailTxt.val('');
+	}else{
+		emailTxt.val(email.value);
+		$("input[name=emailDomain]").attr('readonly', true);
+	}
+}
+
+// 후보자 등록 / 수정 이벤트
+function fnCandidateUpt(dataType){
+	
+	var form = document.candiForm;
+	form.dataType.value = dataType;
+	
+	if(form.candidateNm.value == ""){
+		alert("후보자 이름을 입력해 주세요.");
+		return false;
+	}
+	
+	if(form.regidentNo1.value == ""){
+		alert("후보자 주민등록번호 앞자리를 입력해 주세요.");
+		return false;
+	}else if(!Number(form.regidentNo1.value)){
+		alert("후보자 주민등록번호 앞자리를 정확히 입력해 주세요.");
+		return false;
+	}
+	
+	if(form.regidentNo2.value == ""){
+		alert("후보자 주민등록번호 뒷자리를 입력해 주세요.");
+		return false;
+	}else if(!Number(form.regidentNo2.value)){
+		alert("후보자 주민등록번호 뒷자리를 정확히 입력해 주세요.");
+		return false;
+	}
+	
+	if(form.candidateAddr.value == ""){
+		alert("후보자 주소를 입력해 주세요.");
+		return false;
+	}
+	
+	if(form.managerNm.value == ""){
+		alert("담당자 이름을 입력해 주세요.");
+		return false;
+	}
+	
+	if(form.phoneNo.value == ""){
+		alert("담당자 휴대폰 번호를 입력해 주세요.");
+		return false;
+	}else if(!checkHpNum(removeDash(form.phoneNo.value))){
+		alert("정확한 휴대폰 번호를 입력해 주세요.");
+		return false;
+	}
+	
+	var emailChk = form.email.value + "@" + form.emailDomain.value;
+	
+	if(emailChk == ""){
+		alert("이메일을 입력해 주세요.");
+		return false;
+	}else if(!checkEmail(emailChk)){
+		alert("정확한 이메일을 입력해 주세요.");
+		return false;
+	}
+	
+	var msg = "";
+	
+	if(dataType == 'Upt'){
+		msg="후보자 정보를 수정하시겠습니까?";
+	}else{
+		msg="후보자를 등록 하시겠습니까?";
+	}
+	
+	if(confirm(msg)){
+		
+		//XSS 취약점 제거
+		form.candidateNm.value = XSSCheck(form.candidateNm.value);
+		form.regidentNo1.value = XSSCheck(form.regidentNo1.value);
+		form.regidentNo2.value = XSSCheck(form.regidentNo2.value);
+		form.candidateAddr.value = XSSCheck(form.candidateAddr.value);
+		form.managerNm.value = XSSCheck(form.managerNm.value);
+		form.phoneNo.value = XSSCheck(form.phoneNo.value);
+		form.email.value = XSSCheck(form.email.value);
+		form.emailDomain.value = XSSCheck(form.emailDomain.value);
+		
+		var url = "/web/mjon/msgcampain/insertCandidateDataInfoAjax.do";
+		var data = new FormData(document.candiForm);
+		
+		$.ajax({
+	        type: "POST",
+	        url: url,
+	        data: data,
+	        dataType:'json',
+	        async: false,
+	        processData: false,
+	        contentType: false,
+	        cache: false,
+	        success: function (returnData, status) {
+				if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+					if(returnData.result == "loginFail"){
+						alert(returnData.message);
+						return false;
+					}else if(returnData.result == "success"){
+						alert(returnData.message);
+						location.reload();
+					}else{
+						alert(returnData.message);
+						return false;
+					}
+					
+				} else if(status== 'fail'){
+					alert("후보자 등록에 실패하였습니다. !!");
+				}
+			},
+	        error: function (e) { alert("후보자 등록에 실패하였습니다."); console.log("ERROR : ", e); }
+	    });
+	}
+}
+
+//후보자 등록 시 로그인 여부 체크
+function fn_candidateLoginChk(){
+	alert("후보자 등록은 로그인 후 이용 가능합니다.");
+	return false;
+}
+
+// 후보자 등록 시 회원여부 체크
+function fn_mberDeptChk(){
+	alert("선거문자는 개인 회원만 이용 가능합니다.");
+	return false;
+}
+
+// 선거문자 맞춤제작 팝업 열기
+function goToCustom(){
+	var form = document.goToCustomForm;
+	form.submit();
+}
+
+// 발송규정 윈도우 팝업 열기
+function infoPop(pageUrl){
+	document.popForm.pageType.value = pageUrl;
+	document.popForm.action = "/web/pop/infoPop.do";
+	document.popForm.method = "post"; 
+	window.open("about:blank", 'infoPop', 'width=790, height=1500, top=100, left=100, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbars=yes');
+	document.popForm.target = "infoPop";
+	document.popForm.submit();
+}
+
+// 주소록에 등록 버튼 레이어팝업 오픈 이벤트
+$(document).on('click', '.addressregi_btn', function() {
+	var tableData = tableL.getRows();
+	var dataLen = tableL.getRows().length;
+	if(dataLen == 0){
+		alert("연락처 정보를 등록해 주세요.");
+		return false;
+	}else{
+		$('.addressregi_layer').css({'width':'680px','display':'block','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+		setTimeout(function(){
+			$('.addressregi_layer').css({'opacity':'1'});
+		},150);
+		$('.mask').addClass('on');
+		getAddrGroupList();
+	}
+});
+
+// 주소록에 등록 레이어팝업 종료 이벤트
+$(document).on('click', '.addressregi_layer .tooltip-close', function() {
+	$('.addressregi_layer').attr('style','');
+	$("#addrGrpNm").val("");
+});
+
+//주소록에 등록 레이어팝업 그룹 선택 이벤트
+$(document).on('change', '#addrGrpIdInfo', function() {
+	if ($("#addrGrpIdInfo option:selected").val() != "NEW") {
+		$("#addrGrpNm").val(""); //	새그룹명 Clear;
+	}
+});
+
+//주소록 그룹정보 불러오기
+function getAddrGroupList() {
+ $.ajax({
+     type : "POST",
+     async : false,
+     url : "/web/mjon/addr/addrGroupListAjax.do",
+     data : {},
+     dataType:'json',
+     success : function(data) {
+		// Show Html
+		getAddrGroupListShow(data.addrGroupList);
+     },
+     error : function(xhr, status, error) {
+         alert(error);
+         return false;
+     }
+ });	    	
+}
+
+//Show Html
+function getAddrGroupListShow(jsonList) {
+	var sHtml = "";
+	sHtml += "<option value='NEW'>그룹추가</option>";
+	sHtml += "<option value='0'>그룹미지정</option>";
+	sHtml += "<option value='bookmark'>자주보내는 번호</option>";
+	for (var j = 0; j < jsonList.length; j++) {
+		sHtml += "	<option value='" + $.trim(jsonList[j].addrGrpId) + "' />" + $.trim(jsonList[j].addrGrpNm) + "</option>";
+	}
+	    	
+	$("#addrGrpIdInfo").html(sHtml);
+}
+
+//주소록 그룹 중복체크
+function getAddrGroupDuplCheckAjax() {
+	var isReturn = true;
+	
+	$.ajax({
+		url : "<c:url value='/web/addr/getAddrGroupDuplCheckAjax.do' />", 
+		type : 'POST', 
+		data : {"addrGrpNm" : $("#addrGrpNm").val()},
+		dataType:'json',
+		async: false,			// 동기
+		success : function(data, status){
+			if(data.isSuccess == true) {
+				if(data.isDupl == true) {
+					//alert("중복된 그룹명입니다.");
+					isReturn = false;
+				}
+			} 
+		},
+		error: function (e) {
+			//alert("주소록 중복체크에 실패했습니다.");
+		}
+	});
+	
+	return isReturn;	
+}
+
+//문자발송 받는사람 목록 주소록에 등록하기 기능 처리
+$('.registAddr').click(function(){
+	
+	var tableData = tableL.getRows();
+	var dataLen = tableL.getRows().length;
+	
+	var nameList = [];		//치환문자 이름
+	var phoneNum = [];		//받는사람
+	var rep1List = [];		//치환문자1
+	var rep2List = [];		//치환문자2
+	var rep3List = [];		//치환문자3
+	var rep4List = [];		//치환문자4
+	
+	if(dataLen > 0){
+		
+		for(var i=0; i < dataLen; i++){
+			
+			var name = tableData[i].getData().name;
+			var phone = removeDash(tableData[i].getData().phone);
+			var rep1 = tableData[i].getData().rep1;
+			var rep2 = tableData[i].getData().rep2;
+			var rep3 = tableData[i].getData().rep3;
+			var rep4 = tableData[i].getData().rep4;
+			
+			if(phone == "" || phone == null){
+				
+				alert("수신 목록에 핸드폰 번호가 없는 항목이 있습니다.");
+				return false;
+			}else if(!checkHpNum(phone)){
+				
+				alert("수신 목록에 잘 못된 핸드폰 번호가 있습니다. 핸드폰 번호 : " + phone + " 입니다.");
+				return false;
+			}
+			
+			
+			phoneNum[i] = phone;
+			
+			if(name == "" || name == null){
+				nameList[i] = "";
+			}else{
+				nameList[i] = name.replaceAll(",","§");
+			}
+			
+			if(rep1 == "" || rep1 == null){
+				rep1List[i] = "-";
+			}else{
+				rep1List[i] = rep1.replaceAll(",","§");
+			}
+			
+			if(rep2 == "" || rep2 == null){
+				rep2List[i] = "-";
+			}else{
+				rep2List[i] = rep2.replaceAll(",","§");
+			}
+			
+			if(rep3 == "" || rep3 == null){
+				rep3List[i] = "-";
+			}else{
+				rep3List[i] = rep3.replaceAll(",","§");
+			}
+			
+			if(rep4 == "" || rep4 == null){
+				rep4List[i] = "-";
+			}else{
+				rep4List[i] = rep4.replaceAll(",","§");
+			}
+		}
+		
+		//주소록 정보를 Form에 넣어준다.
+		
+		var form = document.msgForm;
+		form.callToList.value = phoneNum;
+		form.nameList.value = nameList;
+		form.rep1List.value = rep1List;
+		form.rep2List.value = rep2List;
+		form.rep3List.value = rep3List;
+		form.rep4List.value = rep4List;
+		form.addrGrpId.value = $("#addrGrpIdInfo").val();
+		form.addrGrpNm.value = $("#addrGrpNm").val();
+		
+		if ($("#addrGrpIdInfo option:selected").val() == "NEW" && ($("#addrGrpNm").val() == "" || $("#addrGrpNm").val() == null || $("#addrGrpNm").val() == undefined)) {
+			alert("저장할 그룹을 선택하거나 새 그룹명을 입력해주세요.");
+			return false;		
+		}else if ($("#addrGrpIdInfo option:selected").val() == "NEW" && $("#addrGrpNm").val() != "") {
+			//주소록 중복체크
+			if (getAddrGroupDuplCheckAjax() == false) {
+				alert("중복된 그룹명입니다. 새 그룹명을 입력해주세요.");
+				return false;			
+			}
+		}
+		if(confirm("연락처 정보를 주소록에 등록 하시겠습니까?")){
+			
+			var data = new FormData(form);
+			var url = "/web/mjon/msgdata/insertMsgAddrListAjax.do";
+			
+			$.ajax({
+		        type: "POST",
+		        enctype: 'multipart/form-data',
+		        url: url,
+		        data: data,
+		        dataType:'json',
+		        async: true,
+		        processData: false,
+		        contentType: false,
+		        cache: false,
+		        //timeout: 600000,
+		        success: function (returnData, status) {
+					if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+						
+						if(returnData.result == "success"){
+							var alertMsg = "총 " + returnData.resultCnt + "건의 " +returnData.message;
+							
+							if(returnData.dupliCnt > 0) {
+								alertMsg += "\n"+numberWithCommas(returnData.dupliCnt) + "건은 이미 등록되어있는 번호입니다.";
+							}
+
+							alert(alertMsg);
+							$("#addrGrpNm").val("");
+							$('.addressregi_layer').attr('style','');
+							$('.mask').removeClass('on');
+							return false;
+							
+						}else if(returnData.result == "allDupl") {
+							alert("요청하신 "+returnData.dupliCnt+"건의 번호가 주소록에 이미 등록되어있습니다.");
+							$("#addrGrpNm").val("");
+							$('.addressregi_layer').attr('style','');
+							$('.mask').removeClass('on');
+							return false;
+						}else{
+							alert(returnData.message);
+							$("#addrGrpNm").val("");
+							$('.addressregi_layer').attr('style','');
+							$('.mask').removeClass('on');
+							return false;
+							
+						}
+						
+					} else if(status== 'fail'){
+						alert("주소록 등록에 실패하였습니다. !!");
+					}
+				},
+		        error: function (e) { 
+		        	alert("주소록 등록에 실패하였습니다."); 
+		        	console.log("ERROR : ", e); 
+		        },
+				beforeSend : function(xmlHttpRequest) {
+		        	//로딩창 show
+		        	$('.loading_layer').addClass('active');				
+				},	        	        
+		        complete : function(xhr, textStatus) {
+		        	//로딩창 hide
+		        	$('.loading_layer').removeClass('active');
+				}
+		    });
+			
+		}
+		
+	}else{
+		
+		alert("연락처 정보를 등록해 주세요.");
+		return false;
+	}
+});
+
+ //테스트발송 열기
+function fnTestSend(){
+	
+	if(!checkConf()){	//문자온 conf-check
+		alert("현재 문자 발송하기 기능 점검 중입니다.\n\n1분 후 다시 시도해주세요.");
+		return false;
+	}
+	
+	var msgForm = document.msgForm;
+	var form = document.testSendForm;
+	var loginVO = '${LoginVO}';
+	var spamStatus = false;
+	var callFrom = $("#callFromList option:selected").val();
+	
+	//로그인 체크
+	if(loginVO == "" || loginVO == null){
+		alert("문자발송 서비스는 로그인 후 이용 가능합니다.");
+		return false;
+	}
+	
+	//문자내용에 이모지가 있는지 체크
+	var strCont = msgForm.smsTxtArea.value;
+	if(!emojiCheck(strCont)) return false;
+	
+	// 발신번호 체크
+	if(callFrom == ""){
+		alert("발신번호를 입력해 주세요.");
+		return false;
+	}
+
+	//그림문자가 아닌데 본문 비어있는지 확인
+	if(imgFilePath.length == 0) {
+		if(msgForm.smsTxtArea.value == "") {
+			alert("문자 내용을 입력해 주세요.");
+			return false;
+		}
+	}else{//문자내용에 스팸 단어 포함여부 체크
+		var spmData = new FormData(msgForm);
+		url = "/web/mjon/msgdata/selectSpamTxtChkAjax.do";
+		
+		$.ajax({
+	        type: "POST",
+	        url: url,
+	        data: spmData,
+	        dataType:'json',
+	        async: false,
+	        processData: false,
+	        contentType: false,
+	        cache: false,
+	        success: function (returnData, status) {
+				if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+					
+					if("fail" == returnData.result){
+						
+						alert(returnData.message);
+						return false;
+						
+					}else if("loginFail" == returnData.result){
+						
+						alert(returnData.message);
+						return false;
+							
+					}else if("spams" == returnData.result){
+						
+// 						var spmFilterTxt = returnData.spmFilterTxt;
+						spamStatus = true;
+						//alert("문자 내용에 \"" + spmFilterTxt + "\"의 스팸문자가 포함되어 있습니다.");
+						alert("전송 문자내용 중 스팸문구로 의심되는 단어가 포함되어 있어 문자발송이 불가합니다.\n자세한 사항은 문자온 고객센터를 통해 문의주시기 바랍니다.");
+						return false;
+						
+					}
+					
+				} else if(status== 'fail'){
+					alert(returnData.message);
+					return false;
+				}
+			},
+	        error: function (e) { alert("시스템 오류가 발생하였습니다."); console.log("ERROR : ", e); return false;}
+	    });
+	}
+
+
+	//단문 장문 그림(몇장인지) 판별하기 - 발송금액 계산
+	if($('#nowMsgType').text() == "그림"){
+		
+		msgType = 'P';
+		
+		if(imgFilePath.length == 1) {
+			form.eachPrice.value = '<c:out value="${picturePrice}" />';
+		} else if(imgFilePath.length == 2) {
+			form.eachPrice.value = '<c:out value="${picture2Price}" />';
+		} else if(imgFilePath.length == 3) {
+			form.eachPrice.value = '<c:out value="${picture3Price}" />';
+		}
+		
+		//제목 사용한 경우
+		if($("input[name=title_status]:checked").val() == 'Y') {
+			form.mmsSubject.value = msgForm.mmsSubject.value;
+		} else {
+			form.mmsSubject.value = ""; //초기화
+		}
+
+	}else if($('#nowMsgType').text() == "장문"){
+		
+		msgType = 'L';
+		form.eachPrice.value = '<c:out value="${longPrice}" />';
+		
+		//제목 사용한 경우
+		if($("input[name=title_status]:checked").val() == 'Y') {
+			form.mmsSubject.value = msgForm.mmsSubject.value;
+		} else {
+			form.mmsSubject.value = ""; //초기화
+		}
+		
+	}else{
+		msgType = 'S';
+		form.eachPrice.value = '<c:out value="${shortPrice}" />';
+		form.mmsSubject.value = ""; // 장문/그림 제목 초기화
+	}
+	
+	form.msgType.value = msgType;
+	
+	//발신번호 세팅
+	form.callFrom.value = callFrom;
+	
+	//이미지 path 보내기
+	form.imgFilePath.value = imgFilePath;
+	
+	form.action = "/web/pop/testSendPop.do";
+	form.method = "post"; 
+	window.open("about:blank", 'testSendPop', 'width=770, height=850, top=100, left=100, fullscreen=no, menubar=no, status=no, toolbar=no, titlebar=yes, location=no, scrollbars=1');
+	form.target = "testSendPop";
+	form.submit();
+}
+
+//발신번호 선택
+function setCandidatePhone() {
+	advMsgInsert();
+}
+
+//선택 발신번호를 이용한 문자내용 설정
+function advMsgInsert(){
+	var callFrom = $("#callFromList option:selected").val();
+	
+	var advStr = '<div class="ad_txt"><p>(선거운동정보)</p></div>';
+	var advDenyStr = '<div class="deny_txt">후보자전화번호 ' + callFrom + '<br/>불법수집정보 신고번호 : 선거관리위원회 ☎1390<br/>무료거부 0808800858</div>';
+	
+	var preAdvStr = '<p class="ad_tit">(선거운동정보)</p>';
+	var preAdvDenyStr = '<p class="deny_receipt">후보자전화번호 ' + callFrom + '<br>불법수집정보 신고번호 : 선거관리위원회 ☎1390<br>무료거부 0808800858</p>';
+	
+	//광고 및 무료수신거부 텍스트 추가
+	if ($("#send_adYnY").val() == 'Y'){
+
+		//문자내용 광고문자 삭제하기
+		$(".ad_txt").remove();
+		$(".deny_txt").remove();
+		//미리보기 광고 문자 삭제하기
+		$('.ad_tit').remove();
+		$('.deny_receipt').remove();
+		
+		//문자 내용에 광고 문자 추가해주기
+		$(advStr).insertBefore('textarea[name=smsTxtArea]'); 
+		$(advDenyStr).insertBefore('div[name=afterDeny]');
+		
+		//미리보기에 광고 문자 추가해주기
+		$(preAdvStr).insertBefore('.none_txt');
+		$(preAdvDenyStr).insertAfter('.realtime');
+		
+	}else{ //광고 및 무료수신거부 텍스트 삭제
+		
+		//문자내용 광고문자 삭제하기
+		$('.ad_txt').remove();
+		$('.deny_txt').remove();
+		
+		//미리보기 광고 문자 삭제하기
+		$('.ad_tit').remove();
+		$('.deny_receipt').remove();
+		
+	}
+	
+	//문자 바이트수 계산하기
+	fnByteString($('#smsTxtArea').val());
+	
+}
+
+//이벤트 잔액 로그인 체크
+$(".btn_event_cash").off().on("click", function(){
+	var loginVO = '${LoginVO}';
+	if(loginVO == "" || loginVO == null){
+		alert("로그인 후 이용이 가능합니다.");
+		return false;
+	}
+});	
+
+// 분활전송 수량 체크
+function checkNumber(event) {
+	var divideCnt = $('#divideCnt').val();
+	if(!(event.key >= 0 && event.key <= 9)) {
+		return false;
+	}
+	
+	var totCnt = divideCnt + "" + event.key;
+	if(Number(totCnt) > 5000){
+		alert("분할전송 건수는 5,000건을 초과할 수 없습니다.");
+		$('#divideCnt').val("20");
+		return false;
+	}
+  return true;
+}
+
+//문자 발송목록
+function getMjMsgSentListAll(pageNo) {
+	document.sentListForm.pageIndex.value = pageNo;
+	document.sentListForm.msgSentType.value = "02";		// 01:문자전송, 02:선거문자
+	
+	var sendData= $(document.sentListForm).serializeArray();
+	$("#mjMsgSentListAllLoad").load("/web/mjon/msgdata/selectMjMsgSentListAjax.do", sendData ,function(response, status, xhr){
+
+	});
+}
+
+$(document).on('click', '#hdnLink', function() {
+	location.href="/web/mjon/msgcampain/huge/selectMsgHGDataView.do";
+})
+
+</script>
+<div class="loading_layer">
+	<div class="loading_container">
+		<div class="bar"></div>
+		<div class="text">Loading</div>
+	</div>
+</div>
+	
+<!-- 2023 10 16 재전송 : 상세내용 팝업 -->
+<div class="tooltip-wrap" style="z-index:110;">
+	<div class="popup-com adr_layer rev_popup01" tabindex="0" data-tooltip-con="rev_popup01"
+		data-focus="rev_popup01" data-focus-prev="rev_popup01-close" style="width: 440px;">
+		<div class="popup_heading">
+			<p>문자내용</p>
+			<button type="button" class="tooltip-close" data-focus="rev_popup01-close"><img
+					src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		<div class="layer_in" id="msgSentDetailPopLoad" style="padding-bottom: 0px;">
+		</div>
+		<div class="popup_btn_wrap2" style="justify-content: center; margin-bottom: 30px;">
+			<button type="button" class="tooltip-close" data-focus="rev_popup01-close" data-focus-next="rev_popup01">닫기</button>
+		</div>
+	</div>
+</div>
+<!--// 2023 10 16  재전송 : 상세내용 팝업 -->	
+	
+<!-- 2023 10 16  재전송 팝업 -->  
+<div class="tooltip-wrap">
+	<div class="popup-com import_layer popup05" tabindex="0" data-tooltip-con="popup05" data-focus="popup05" data-focus-prev="popup05-close" style="width: 900px;">
+		<div class="popup_heading">
+			<p><span>전송내역</p>
+			<button type="button" class="tooltip-close" data-focus="popup05-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		<div class="layer_in" id="mjMsgSentListAllLoad" style="padding-bottom: 0px; min-height:428px;">
+		</div>
+		<div class="popup_btn_wrap2" style="margin-bottom: 30px;">
+			<button type="button" class="tooltip-close" data-focus="popup05-close"  data-focus-next="popup05">닫기</button>                      
+		</div>			
+	</div>
+</div>
+<!--// 2023 10 16  재전송 팝업 -->
+	
+<!-- 후보자등록 팝업 data-tooltip:candidate_popup01 -->
+<div class="tooltip-wrap">
+	<div class="popup-com candidate_layer candidate_popup01" tabindex="0" data-tooltip-con="candidate_popup01" data-focus="candidate_popup01" data-focus-prev="candidate_popup01-close" style="width: 620px;">
+		<div class="popup_heading">
+			<p>후보자 등록</p>
+			<button type="button" class="tooltip-close" data-focus="candidate_popup01-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		
+		<form id="candiForm" name="candiForm" method="post">
+			<input type="hidden" id="dataType" name="dataType" value="Reg"/>
+		
+			<div class="layer_in">
+                <p class="adr_pop_title">선거문자는 반드시 <span class="c_002c9a">후보자 등록</span>을 하셔야만 이용 가능합니다. <br/>입력하신 내용은 세금계산서 발행을 위한 정보로만 사용됩니다.</p>
+				<div class="candidate_table">
+                    <p>후보자</p>
+                    <table>
+                        <caption>후보자 등록을 위한 성명, 주민등록번호, 주소를 입력하는 표</caption>
+                        <colgroup>
+                            <col style="width: 125px;">
+                            <col style="width: auto;">
+                        </colgroup>
+                        <tbody>
+                            <tr>
+                                <th scope="row">성명</th>
+                                <td>
+                                    <label for="candidateNm" class="label"></label>
+                                    <input type="text" id="candidateNm" name="candidateNm" value="<c:out value='${mjonCandidateVO.candidateNm}'/>" placeholder="후보자 성명 입력" onfocus="this.placeholder=''" onblur="this.placeholder='후보자 성명 입력'" class="inputLight">
+                                </td>
+                            </tr>
+                            <tr class="residentNum">
+                                <th scope="row">주민등록번호</th>
+                                <td>
+                                    <label for="regidentNo1" class="label"></label>
+                                    <input type="text" id="regidentNo1" name="regidentNo1" value="<c:out value='${mjonCandidateVO.regidentNo1}'/>" maxlength="6" placeholder="주민등록번호 앞 6자리" onfocus="this.placeholder=''" onblur="this.placeholder='주민등록번호 앞 6자리'" class="inputLight">
+                                    <span>-</span>
+                                    <label for="regidentNo2" class="label"></label>
+                                    <input type="password" id="regidentNo2" name="regidentNo2" value="<c:out value='${mjonCandidateVO.regidentNo2}'/>" maxlength="7" placeholder="주민등록번호 뒤 7자리" onfocus="this.placeholder=''" onblur="this.placeholder='주민등록번호 뒤 7자리'" class="inputLight">
+                                </td>
+                            </tr>
+                            <tr>
+                                <th scope="row">주소</th>
+                                <td>
+                                    <label for="candidateAddr" class="label"></label>
+                                    <input type="text" id="candidateAddr" name="candidateAddr" value="<c:out value='${mjonCandidateVO.candidateAddr}'/>">
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="candidate_table" style="margin-top: 40px;">
+                    <p>담당자</p>
+                    <table>
+                        <caption>후보자 등록을 위한 성명, 주민등록번호, 주소를 입력하는 표</caption>
+                        <colgroup>
+                            <col style="width: 125px;">
+                            <col style="width: auto;">
+                        </colgroup>
+                        <tbody>
+                            <tr>
+                                <th scope="row">성명</th>
+                                <td>
+                                    <label for="managerNm" class="label"></label>
+                                    <input type="text" id="managerNm" name="managerNm" value="<c:out value='${mjonCandidateVO.managerNm}'/>" placeholder="담당자 성명 입력" onfocus="this.placeholder=''" onblur="this.placeholder='담당자 성명 입력'" class="inputLight">
+                                </td>
+                            </tr>
+                            <tr>
+                                <th scope="row">휴대폰</th>
+                                <td>
+                                    <label for="phoneNo" class="label"></label>
+                                    <input type="text" id="phoneNo" name="phoneNo" value="<c:out value='${mjonCandidateVO.phoneNo}'/>" placeholder="‘-’ 없이 숫자만 입력" onfocus="this.placeholder=''" onblur="this.placeholder='‘-’ 없이 숫자만 입력'" class="inputLight">
+                                </td>
+                            </tr>
+                            <tr class="emailWrap3">
+                                <th scope="row">이메일</th>
+                                <td>
+                                    <label for="email" class="label"></label>
+                                    <input type="text" id="email" name="email" value="<c:out value='${mjonCandidateVO.email}'/>">
+                                    <span>@</span>
+                                    <label for="emailDomain" class="label"></label>
+                                    <input type="text" id="emailDomain" name="emailDomain" value="<c:out value='${mjonCandidateVO.emailDomain}'/>">
+                                    <label for="" class="label">이메일 선택</label>
+                                    <select class="list_selType1" id="taxEmailSelect" onchange="emailChange(this)">
+                                        <c:forEach var="result" items="${emailCode}" varStatus="status">
+											<c:if test="${status.index eq 0 }">
+												<option value="1">${result.codeNm}</option>
+											</c:if>
+											<c:if test="${status.index ne 0 }">
+												<option value="${result.codeDc}">${result.codeNm}</option>
+											</c:if>
+										</c:forEach>
+                                    </select>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+                <div class="popup_btn_wrap2">
+                	<c:choose>
+                		<c:when test="${not empty mjonCandidateVO.candidateNm}">
+		                    <button type="button" onclick="javascript:fnCandidateUpt('Upt'); return false;">수정</button>
+                		</c:when>
+                		<c:otherwise>
+                			<button type="button" onclick="javascript:fnCandidateUpt('Reg'); return false;">등록</button>
+                		</c:otherwise>
+                	</c:choose>
+                    <button type="button" class="tooltip-close" data-focus="candidate_popup01-close" data-focus-next="candidate_popup01">닫기</button>                      
+                </div>
+			</div>
+			
+		 	<!-- Workaround to avoid corrupted XHR2 request body in IE10 / IE11 -->
+		 	<input type="hidden" name="_dontcare">				
+		</form>
+	</div>
+</div>
+<!--// 후보자등록 팝업 -->
+	
+<!-- 주소록 불러오기 -->
+<div class="tooltip-wrap">
+	<div class="popup-com import_layer popup06" tabindex="0" data-tooltip-con="popup06" data-focus="popup06" data-focus-prev="popup06-close" style="width: 1000px">
+		<div class="popup_heading">
+			<p><span>주소록 불러오기</p>
+			<button type="button" onClick="javascript:addrClose(); return false;">
+			<img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		<div class="layer_in">
+			<div class="titBox titBox_pad">
+				<p>- 주소록 수정 및 변경은 <span>[주소록 관리]</span>에서만 가능합니다.</p>
+				<button type="button" class="adr_admin" onClick="location.href='/web/mjon/addr/selectAddrList.do'">주소록 관리</button>
+			</div>
+			<div class="adr_wrap">
+				<form id="searchAddrGrpForm" name="searchAddrGrpForm" method="post" style="display: flex; justify-content: space-between;">
+					<input type="hidden" id="searchAddrGrpId" name="searchAddrGrpId" value=""/>
+					<input type="hidden" id="type" name="type" value="all"/>
+					<input type="hidden" id="searchKeyword" name="searchKeyword" value=""/>
+					<input type="hidden" name="searchCondition" id="searchCondition" value="0" />
+					<div class="adr_pop_left">
+						<div class="adr_left_search">
+							<label for="searchKeyword" class="label">그룹명 검색</label>
+							<input type="text" name="searchGrpKeyword" id="searchGrpKeyword"  placeholder="그룹명 검색" onfocus="this.placeholder=''" onblur="this.placeholder='그룹명 검색'" class="inputLight">
+							<button type="button" onClick="javascrit:fnAddrGrpSearch(); return false;"><img src="/publish/images/popup/search.png" alt="검색"></button>
+						</div>
+						<div class="adr_pop_box">
+							<div id="addrGroupLoad">
+							</div>
+						</div>
+						<!-- <div class="popup_btn">
+							<button type="button" class="btnType" onClick="javascript:fnSelectAddrGrpList(); return false;">선택 그룹 추가</button>
+						</div> -->
+					</div>
+					<div class="adr_pop_right">
+						<div class="clearfix">
+							<div class="btnWrap_last">
+								<label for="searchAddrCondition" class="label">카테고리 선택</label>
+								<select id="searchAddrCondition" name="searchAddrCondition" class="selType2">
+									<option value='0'>전체</option>
+									<option value='1'>그룹명</option>
+									<option value='2'>이름</option>
+									<option value='3'>핸드폰번호</option>
+								</select>
+								<label for="searchAddrKeyword" class="label">검색어 입력</label>
+								<input type="text" id="searchAddrKeyword" name="searchAddrKeyword" placeholder="검색어를 입력하세요"  onfocus="this.placeholder=''" onblur="this.placeholder='검색어를 입력하세요'" >
+								<button type="button" class="btnType btnType17"  onClick="javascrit:fnAddrSearch(); return false;">검색</button>
+							</div>
+							<!-- table -->
+							<div class="adr_excel adr_pop_list2 callAddr_box">
+							</div>
+							<!--// table -->
+						</div>
+						<div class="popup_btn_wrap2">
+							<button type="button" onClick="javascript:addrToList_advc('all'); return false;">전체추가</button>
+							<button type="button" onClick="javascript:addrToList_advc('select'); return false;">선택추가</button>
+							<button type="button" onClick="javascript:addrClose(); return false;">닫기</button>
+						</div>
+						<%-- 주소록 레이어 팝업 닫기 실행 코드 --%>
+						<input type="hidden" name="btnAddrClose" id="btnAddrClose" class="tooltip-close closeAddr" data-focus="popup06-close" />     
+					</div>
+				</form>
+			</div>
+		</div>
+	</div>
+</div>
+<!--// 주소록 불러오기 -->
+	
+<!-- 엑셀 불러오기 -->
+<form id="excelForm" name="excelForm" method="post">
+	<div class="tooltip-wrap">
+		<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/msgcampain/include/msgDataIncludeExcel.jsp" %>
+		</div>
+	</div>
+</form>
+<!--// 엑셀 불러오기 -->
+	
+<!-- 전송내역 팝업 -->
+<div class="tooltip-wrap">
+	<div class="popup-com history_layer popup03" tabindex="0" data-tooltip-con="popup03" data-focus="popup03" data-focus-prev="popup03-close">
+		<div class="popup_heading">
+			<p><span>전송내역</p>
+			<button type="button" class="tooltip-close" data-focus="popup03-close" id="btnLatestAddPhoneClose"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		<div class="layer_in">
+			<!-- tab button -->
+			<ul class="tabType6"> 
+				<li class="tab active"><button type="button" onclick="TabType(this,'1');">최근 전송내역</button></li>
+				<li class="tab"><button type="button" onclick="TabType(this,'2');">자주보내는 번호</button></li>
+			</ul><!--// tab button -->
+			<!-- 최근 전송내역 -->
+			<div class="history_cont hascont current">
+				<div class="histroy_trans latestMsgArea" id="latestMsgArea">
+					<ul id="latestMsgUl">
+						<c:choose>
+							<c:when test="${not empty resultLatestMsgList}">
+								<c:forEach var="latestMsgList" items="${resultLatestMsgList}" varStatus="status">
+									<li id="latestLi">
+										<input type="checkbox" id="addrChk_${status.count}" name="latAddrChk" value="<c:out value='${latestMsgList.callTo}'/>">
+										<label for="addrChk_${status.count}" class="label">최근 전송내역</label>
+										<p><c:out value="${latestMsgList.callTo}"/></p>
+										<button type="button" id="latestAddrDel"><img src="/publish/images/popup/close3.png"  alt="전화번호 삭제"></button>
+									</li>
+								</c:forEach>
+							</c:when>
+							<c:otherwise>
+								<li>
+									<p>최근 발송 내역이 없습니다.</p>
+								</li>
+							</c:otherwise>
+						</c:choose>
+					</ul>
+				</div>
+				<div class="popup_btn_wrap2 hisroy_btn" style="width: 230px;">
+					<button type="button" id="latestAddPhoneAll">전체추가</button>
+					<button type="button" id="latestAddPhone">선택추가</button>
+					<button type="button" id="latestCancelPhone">선택취소</button>                      
+				</div>
+			</div>
+			<!--// 최근 전송내역 -->
+			<!-- 자주보내는 번호 -->
+			<div class="history_cont hascont">
+				<div class="histroy_trans" id="bookMarkMsgArea">
+					<ul id="bookMsgUl">
+						<c:choose>
+							<c:when test="${not empty resultBookMarkMsgList}">
+								<c:forEach var="bookMarkMsgList" items="${resultBookMarkMsgList}" varStatus="status">
+									<li id="bookMarkLi">
+										<input type="checkbox" id="bokAddrChk_${status.count}" name="bookAddrChk" value="<c:out value='${bookMarkMsgList.addrPhoneNo}'/>">
+										<label for="addrChk_${status.count}" class="label">최근 전송내역</label>
+										<p><c:out value="${bookMarkMsgList.addrPhoneNo}"/></p>
+										<button type="button" id="bookMarkAddrDel"><img src="/publish/images/popup/close3.png"  alt="전화번호 삭제"></button>
+									</li>
+								</c:forEach>
+							</c:when>
+							<c:otherwise>
+								<li>
+									<p>등록된 자주 보내는 번호 내역이 없습니다.</p>
+								</li>
+							</c:otherwise>
+						</c:choose>
+					</ul> 
+				</div>
+				<div class="popup_btn_wrap2 hisroy_btn" style="width: 230px;">
+					<button type="button" id="bookMarkAddPhoneAll">전체추가</button>
+					<button type="button" id="bookMarkAddPhone">선택추가</button>
+					<button type="button" id="bookMarkCancelPhone">선택취소</button>                      
+				</div>
+			</div>
+			<!--// 자주보내는 번호  -->         
+		</div>
+	</div>
+</div>
+<!--// 전송내역 팝업 -->
+	
+<!-- 주소록에 등록 data-tooltip:duplication_layer -->
+<div class="tooltip-wrap">
+	<div class="popup-com addressregi_layer" tabindex="0" data-tooltip-con="addressregi_layer" data-focus="addressregi_layer" data-focus-prev="addressregi_layer-close" style="width: 680px;">
+		<div class="popup_heading">
+			<p>주소록에 등록</p>
+			<button type="button" class="tooltip-close" data-focus="addressregi_layer-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		<div class="layer_in" style="padding: 30px 20px;">
+			<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" onchange="excelExport(event); return false;" style="display:none"/> -->
+						</td>
+					</tr>
+				</tbody>
+			</table>
+			<div class="popup_btn_wrap2">
+				<button type="button" class="registAddr">등록</button>
+				<button type="button" class="tooltip-close" data-focus="addressregi_layer-close" data-focus-next="addressregi_layer">닫기</button>
+			</div>
+		</div>
+	</div>
+</div>
+<!--// 주소록에 등록 팝업 -->
+	
+<!--선거문자 이용안내 팝업  -->
+<div class="tooltip-wrap">
+	<div class="popup-com ad_layer candidate_popup03" tabindex="0" data-tooltip-con="candidate_popup03" data-focus="candidate_popup03" data-focus-prev="candidate_popup03-close" style="width: 795px">
+		<div class="popup_heading">
+			<p>선거문자 안내</p>
+			<button type="button" class="tooltip-close" data-focus="candidate_popup03-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		<div class="layer_in">
+			<img src="/publish/images/content/candidatePop_banner.png" alt="선거문자 이용안내 배너" class="candidate_banner">
+			<ul class="info_list">
+	    		<li>- 90byte 초과 시, 자동으로 장문으로 전환됩니다.  장문 문자는 최대 2,000byte까지만 작성할 수 있습니다.</li>
+	    		<li>- 그림문자 1건당 최대 3장까지 이미지 첨부 가능  [권장 사이즈 : <strong>640 x 960</strong>픽셀 / 최대용량 : <strong>10MB</strong> 이내]</li>
+	    		<li>- 선거문자는 반드시 발송규정을 사전 확인 후 발송해 주시기 바랍니다.</li>
+	    	</ul>
+			<!-- 이용방법/혜택 -->
+			<div class="cdpop_cont current" id="listTab2_1">
+				<div>
+					<p class="cdpop_title">
+						<i class="cdpop_title_icon1"></i>선거문자 이용방법
+						<span class="customReq">
+							<button type="button" onclick="goToCustom();"><i></i>선거문자 맞춤제작</button>
+						</span>
+					</p>
+					<ul class="cdpop_info">
+						<li>
+							<i class="info_step1"></i>
+							<div>
+								<p>회원가입</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step2"></i>
+							<div>
+								<p>후보자등록</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step3"></i>
+							<div>
+								<p>전용계좌</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step4"></i>
+							<div>
+								<p>발신번호 인증</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step5"></i>
+							<div>
+								<p>문자전송</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step6"></i>
+							<div>
+								<p>세금계산서</p>
+							</div>
+						</li>
+					</ul>
+				</div>
+				<div>
+					<p class="cdpop_title"><i class="cdpop_title_icon2"></i>문자온 선거문자만의 장점 및 혜택</p>
+					<ul class="cdpop_benefit">
+						<li>
+							<div>
+								<i class="benefit1"></i>
+								<p>한 번에 대량으로 보내야 한다면?<span>10만건까지 동시 전송 가능</span></p>
+							</div>
+							<p>문자온의 대량전송(엑셀·TXT) 모듈을 통해
+								10만건의 대량문자도 쉽고 빠르게 전송 가능합니다.</p>
+						</li>
+						<li>
+							<div>
+								<i class="benefit2"></i>
+								<p>수신거부 번호가 필요하세요?<span>080 수신거부 번호 무료제공</span></p>
+							</div>
+							<p>선거문자 발송규정 준수를 위해
+								080 수신거부 번호를 무료로 제공해 드립니다.</p>
+						</li>
+						<li>
+							<div>
+								<i class="benefit3"></i>
+								<p>주소록 등록이 번거로우신가요?<span>주소록 등록 무료대행</span></p>
+							</div>
+							<p>주소록 등록파일(엑셀·TXT)을 문자온에 제공해
+								주시면 무료로 빠르고 신속하게 등록해 드립니다.</p>
+						</li>
+						<li>
+							<div>
+								<i class="benefit4"></i>
+								<p>홍보효과를 높이고 싶다면?<span>후보자만의 그림문자 맞춤제작</span></p>
+							</div>
+							<p>선거공약, 인사말, 후보자 사진 등을 넣어 그림문자를
+								맞춤 제작하여 홍보효과를 극대화할 수 있습니다.</p>
+						</li>
+						<li>
+							<div>
+								<i class="benefit5"></i>
+								<p>오류·실패건의 문자를 보상받고 싶다면?<span>오류·실패건 문자 100% 환불</span></p>
+							</div>
+							<p>번호오류, 수신거부, 수신실패 등으로 인해 문자전송이
+								실패한 경우 100% 환불(자동충전)해 드립니다.</p>
+						</li>
+						<li>
+							<div>
+								<i class="benefit6 "></i>
+								<p>전송결과가 궁금하다면?<span>실시간 전송결과 확인 가능</span></p>
+							</div>
+							<p>전송결과 및 실패사유를 실시간으로 제공해드립니다.</p>
+						</li>
+						<li>
+							<div>
+								<i class="benefit7"></i>
+								<p>20건씩 나눠서 보내야한다면?<span>20건씩 분할 예약 전송 가능</span></p>
+							</div>
+							<p>누구나 쉽고 편리하게 20건씩 나눠서 분할 전송이 가능합니다.</p>
+						</li>
+						<li>
+							<div>
+								<i class="benefit8"></i>
+								<p>필요한 서류가 있다면?<span>문자온에서 간편하게 신청 가능</span></p>
+							</div>
+							<p>문자온에서 발송내역서 출력이 가능하며,
+								세금계산서는 메일로 자동으로 발행됩니다.</p>
+						</li>
+					</ul>
+				</div>
+			</div><!--// 이용방법/혜택 -->
+		</div>
+		<div class="popup_btn_wrap2" style="margin: 0 auto 30px auto;">
+			<button type="button" class="tooltip-close" data-focus="candidate_popup03-close"  data-focus-next="candidate_popup03">닫기</button>                      
+		</div>
+	</div>
+</div>
+<!--// 선거문자 이용안내 팝업 -->
+	
+<!-- 이벤트 잔여 캐시 정보 표시 팝업 -->
+<div class="tooltip-wrap">
+	<div class="popup-com event_cash_popup popup07" tabindex="0" data-tooltip-con="popup07" data-focus="popup07" data-focus-prev="popup07-close">
+		<div class="popup_heading">
+			<p>이벤트 잔액</p>
+			<button type="button" class="tooltip-close" data-focus="popup07-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		<div class="layer_in">
+			<div class="table_wrap">
+				<div class="table_top">
+					<p class="popup_title_18">첫 결제 이벤트 잔액(캐시)</p>
+					<p><span class="c_e40000 fwBold"><fmt:formatNumber value="${eventRemainCash}" pattern="#,###.#"/></span>원</p>
+				</div>
+				<table class="popup_table_type2">
+					<colgroup>
+						<col style="width: 25%;">
+						<col style="width: auto;">
+					</colgroup>
+					<tbody>
+						<tr>
+							<th>단문(<fmt:formatNumber value="${eventMberInfo.eventShortPrice}" pattern="#,###.#"/>)</th>
+							<td><span class="c_002c9a fwBold"><fmt:formatNumber value="${(eventRemainCash / eventMberInfo.eventShortPrice) - ((eventRemainCash / eventMberInfo.eventShortPrice) % 1) }" pattern="#,###"/></span>건</td>
+						</tr>
+						<tr>
+							<th>장문(<fmt:formatNumber value="${eventMberInfo.eventLongPrice}" pattern="#,###.#"/>)</th>
+							<td><span class="c_002c9a fwBold"><fmt:formatNumber value="${(eventRemainCash / eventMberInfo.eventLongPrice) - ((eventRemainCash / eventMberInfo.eventLongPrice) % 1)}" pattern="#,###"/></span>건</td>
+						</tr>
+						<tr>
+							<th>그림 1장(<fmt:formatNumber value="${eventMberInfo.eventPicturePrice}" pattern="#,###.#"/>)</th>
+							<td><span class="c_002c9a fwBold"><fmt:formatNumber value="${(eventRemainCash / eventMberInfo.eventPicturePrice) - ((eventRemainCash / eventMberInfo.eventPicturePrice) % 1)}" pattern="#,###"/></span>건</td>
+						</tr>
+						<tr>
+							<th>그림 2장(<fmt:formatNumber value="${eventMberInfo.eventPicture2Price}" pattern="#,###.#"/>)</th>
+							<td><span class="c_002c9a fwBold"><fmt:formatNumber value="${(eventRemainCash / eventMberInfo.eventPicture2Price) - ((eventRemainCash / eventMberInfo.eventPicture2Price) % 1)}" pattern="#,###"/></span>건</td>
+						</tr>
+						<tr>
+							<th>그림 3장(<fmt:formatNumber value="${eventMberInfo.eventPicture3Price}" pattern="#,###.#"/>)</th>
+							<td><span class="c_002c9a fwBold"><fmt:formatNumber value="${(eventRemainCash / eventMberInfo.eventPicture3Price) - ((eventRemainCash / eventMberInfo.eventPicture3Price) % 1)}" pattern="#,###"/></span>건</td>
+						</tr>
+					</tbody>
+				</table>
+			</div>
+			<div class="popup_btn_wrap2">
+				<button type="button" class="tooltip-close" data-focus="popup07-close"  data-focus-next="popup07">닫기</button>
+			</div>
+		</div>
+	</div>
+</div>
+	
+<form id="msgForm" name="msgForm" method="post">
+	<input type="hidden" id="msgType" name="msgType" value="4" /><!-- 문자 종류 : 단문 - 4, 장문/그림 - 6 -->
+	<input type="hidden" id="imgFilePath" name="imgFilePath" value="" /><!-- 선택 이미지 파일 경로 정보 , 로 구분 최대 3장까지 -->
+	<input type="hidden" id="imgFileId" name="imgFileId" value="" /><!-- 선택 이미지 파일 아이디 정보 , 로 구분 최대 3장까지 -->
+	<input type="hidden" id="fileCnt" name="fileCnt" value="0" /><!-- 첨부파일 추가 갯수 -->
+	<input type="hidden" id="callToList" name="callToList" value=""/><!-- 수신자 전화번호 리스트 -->
+	<input type="hidden" id="callFrom" name="callFrom" value=""/> <!-- 발신자 전화번호 -->
+	<input type="hidden" id="eachPrice" name="eachPrice" value="0"/> <!-- 문자 개별 단가 금액 -->
+	<input type="hidden" id="totPrice" name="totPrice" value="0"/> <!-- 총 결제 금액 -->
+	<input type="hidden" id="smsLen" name="smsLen" value="0"/> <!-- 문자 길이 정보 -->
+	<input type="hidden" id="reserveYn" name="reserveYn" value="N"/> <!-- 즉시/예약 선택여부 -->
+	<input type="hidden" id="reqDate" name="reqDate" value=""/> <!-- 예약문자 날짜 -->
+	<input type="hidden" id="imgCnt" value="0" />
+	<input type="hidden" id="smsTxt" name="smsTxt" value=""/><!-- 문자발송 문자 내용 -->
+	<input type="hidden" id="nameList" name="nameList" value=""/><!-- 문자발송 문자 이름 리스트 -->
+	<input type="hidden" id="rep1List" name="rep1List" value=""/><!-- 문자발송 문자 치환1 리스트 -->
+	<input type="hidden" id="rep2List" name="rep2List" value=""/><!-- 문자발송 문자 치환2 리스트 -->
+	<input type="hidden" id="rep3List" name="rep3List" value=""/><!-- 문자발송 문자 치환3 리스트 -->
+	<input type="hidden" id="rep4List" name="rep4List" value=""/><!-- 문자발송 문자 치환4 리스트 -->
+	<input type="hidden" name="templateYn" />
+	<input type="hidden" id="sPrice" name="sPrice" value="<c:out value="${shortPrice}"/>"/><!-- 단문문자 단가 -->
+	<input type="hidden" id="mPrice" name="mPrice" value="<c:out value="${longPrice}"/>"/><!-- 장문문자 단가 -->
+	<input type="hidden" id="pPrice" name="pPrice" value="<c:out value="${picturePrice}"/>"/><!-- 그림문자 단가 -->
+	<input type="hidden" id="p2Price" name="p2Price" value="<c:out value="${picture2Price}"/>"/><!-- 그림2장문자 단가 -->
+	<input type="hidden" id="p3Price" name="p3Price" value="<c:out value="${picture3Price}"/>"/><!-- 그림3장문자 단가 -->
+	<input type="hidden" id="myPrice" name="myPrice" value="<c:out value="${userMoney}"/>"/>
+	<input name="msgKind" type="hidden" value="C"/><!-- 문자종류 일반:N , 광고:A , 선거:C -->
+	<input type="hidden" id="txtReplYn" name="txtReplYn" value="N"/><!-- 변환문자 유무 -->
+	<input type="hidden" id="shortMsgCnt" name="shortMsgCnt" value="0"/><!-- 단문 변환문자 건수  -->
+	<input type="hidden" id="longMsgCnt" name="longMsgCnt" value="0"/><!-- 장문 변환문자 건수 -->
+
+	<!-- 주소록 등록 -->
+	<input type="hidden" id="addrGrpId" name="addrGrpId" value=""/>
+	<input type="hidden" id="addrGrpNm" name="addrGrpNm" value=""/>		
+	
+	<!-- 이벤트 관련 변수 -->
+	<input type="hidden" id="eventStatus" name="eventStatus" value="<c:out value='${eventMberInfo.eventStatus}'/>"/>
+	<input type="hidden" id="eventRemainCash" name="eventRemainCash" value="<c:out value='${eventRemainCash}'/>"/>
+	<input type="hidden" id="eventYn" name="eventYn" value="N"/>
+	
+	<!-- 스팸문자 관련 변수 -->
+	<input type="hidden" id="spamKeyword" name="spamKeyword"/>
+	<input type="hidden" id="spamStatus" name="spamStatus"/>
+	<input type="hidden" id="exceptSpamYn" name="exceptSpamYn" value="<c:out value='${exceptSpamYn}'/>"/>
+	
+	<!-- 이벤트 캐시 부족시 일반캐시로 계산을 위해 저장, 우영두 2023.03.28 -->
+	<input type="hidden" id="norsPrice" name="norsPrice" value="<c:out value="${norShortPrice}"/>"/><!-- 단문문자 단가(이벤트 단가 제외) -->
+	<input type="hidden" id="normPrice" name="normPrice" value="<c:out value="${norLongPrice}"/>"/><!-- 장문문자 단가(이벤트 단가 제외) -->
+	<input type="hidden" id="norpPrice" name="norpPrice" value="<c:out value="${norPicturePrice}"/>"/><!-- 그림문자 단가(이벤트 단가 제외) -->
+	<input type="hidden" id="norp2Price" name="norp2Price" value="<c:out value="${norPicture2Price}"/>"/><!-- 그림2장문자 단가(이벤트 단가 제외) -->
+	<input type="hidden" id="norp3Price" name="norp3Price" value="<c:out value="${norPicture3Price}"/>"/><!-- 그림3장문자 단가(이벤트 단가 제외) -->	
+	<input type="hidden" id="evnPhoneNumCnt" name="evnPhoneNumCnt" value="0"/><!-- 치환 이벤트 발송 수신자 갯수 -->
+	<input type="hidden" id="evnShortMsgCnt" name="evnShortMsgCnt" value="0"/><!-- 치환 이벤트 단문 건수 -->
+	<input type="hidden" id="evnLongMsgCnt" name="evnLongMsgCnt" value="0"/><!-- 치환 이벤트 장문 건수 -->
+
+    <div class="heading">
+        <h2>선거 문자전송</h2>
+        <div class="election_btnWrap">
+        	<button type="button" class="button2 info" onclick="infoPop('selectMsgDataView2');">발송규정</button>
+        	<button type="button" class="button2 info" data-tooltip="candidate_popup03">사용안내</button>
+        	<c:choose>
+        		<c:when test="${empty LoginVO}">
+					<button type="button" class="btnType" onclick="javascript:fn_candidateLoginChk(); return false;"><i class="election_btn1"></i>후보자 등록</button>
+        		</c:when>
+        		<c:when test="${not empty mberManageVO && mberManageVO.dept eq 'c'}">
+        			<button type="button" class="btnType" onclick="javascript:fn_mberDeptChk(); return false;"><i class="election_btn1"></i>후보자 등록</button>
+        		</c:when>
+        		<c:otherwise>
+        			<button type="button" class="btnType" data-tooltip="candidate_popup01"><i class="election_btn1"></i>후보자 등록</button>	
+        		</c:otherwise>
+        	</c:choose>
+               <button type="button" class="btnType" onclick="location.href='/web/member/pay/BillPub.do'"><i class="election_btn2"></i>세금계산서</button>
+               <button type="button" class="btnType" onclick="location.href='/web/mjon/msgsent/selectMsgSentView.do'"><i class="election_btn3"></i>발송결과 출력하기</button>
+           </div>
+    </div>
+    <div class="send_general">
+        <div class="send_left">
+            <table class="tType1">
+                <caption>일반 문자보내기 분류 번호 내용 등을 입력하는 표</caption>
+                <colgroup>
+                    <col style="width: 100px;">
+                    <col style="width: auto;">
+                </colgroup>
+                <tbody>
+<%--					<tr>--%>
+<%--						<input type="hidden" id="send_adYnY" name="send_adYn" value="Y">--%>
+<%--	                    <td colspan="2" class="ele_te">※ 자동1동보문자를 <span>한번에 20,000건 이상 보내실 경우에는 꼭 고객센터(1551-8011)</span>로 연락주시어 발송 요청 후 진행해 주시길 바랍니다<span id="hdnLink">.</span></td>--%>
+<%--                    </tr>--%>
+                    <tr>
+						<th scope="row">발신번호</th>
+						<td class="put_num">
+							<label for="callFrom" class="label"></label>
+							<select id="callFromList" name="callFromList" class="sel_number" onchange="setCandidatePhone();">
+								<c:choose>
+									<c:when test="${not empty resultPhonList}">
+										<c:forEach var="phonList" items="${resultPhonList}" varStatus="status">
+											<option value="${phonList}">${phonList}</option>
+										</c:forEach>
+									</c:when>
+									<c:otherwise>
+										<option value="">등록된 발신 번호가 없습니다.</option>
+									</c:otherwise>
+								</c:choose>
+							</select>
+							<button type="button" class="btnType btnType6" onclick="location.href='/web/user/sendNumberManage.do'">번호등록</button>
+						</td>
+					</tr>
+					<tr class="msg_title">
+					    <th scope="row">제목</th>
+					    <td>
+					   		<ul class="title_wrap">
+					   			<li>
+					   				<input id="title_y" type="radio"name="title_status" value="Y" onchange="titleStatus(this);">
+					             <label for="title_y">사용</label>
+					             <input id="title_n" type="radio" name="title_status" value="N" onchange="titleStatus(this);" checked="checked">
+					             <label for="title_n">사용안함</label>
+					   			</li>
+					   			<li class="textbox">
+					   				<label for="mmsSubject" class="label"></label>
+									<input type="text" size="20" id="mmsSubject" name="mmsSubject" class="w100" maxlength="20" placeholder=""  onfocus="this.placeholder=''" >
+					   			</li>
+					   		</ul>
+						</td>
+					</tr>
+					<!-- 문자 내용 영역 -->
+					<tr>
+						<th scope="row" class="vTop">내용</th>
+                            <td class="putText">
+                                <div class="clearfix">
+                                    <div class="put_left short">
+                    					<!-- 업로드한 이미지의 썸네일 영역 -->
+                                    	<ul class="thumb_wrap liOnImg"></ul>
+                   						<!-- //업로드한 이미지의 썸네일 영역 -->
+                                        <label for="smsTxtArea" class="label"></label>
+                                        <textarea id="smsTxtArea" name="smsTxtArea" class="put_text" placeholder="내용을 입력해주세요.
+-90btye 초과 시 LMS 자동전환
+-파일첨부 시 MMS 자동전환">
+</textarea>
+									<div class="text_length">
+										<div name="afterDeny">
+											<p>
+												<span class="fwMd" id="msgLeng">0 /</span>
+												<span class="c_002c9a fwMd" id="limitLeng"> 90</span>byte
+											</p>
+											<span class="msg_com msg_short">단문</span>
+										</div>
+									</div>
+								</div>
+								<div class="put_right">
+									<div class="btn_popup_wrap spc_wrap">
+                                     	<button type="button" class="btnType btnType7" onclick="miniPopup(this);">특수문자</button>
+										<div class="send_miniPop spc_character">
+											<div class="tab_character">
+												<a href="#none" class="on">특수문자</a>
+												<a href="#none">웃음</a>
+												<a href="#none">슬픔</a>
+												<a href="#none">분노</a>
+												<a href="#none">사랑</a>
+												<a href="#none">그외</a>
+											</div>
+											<!-- 특수문자 부분 -->
+											<div class="cnt_character on">
+												<div class="box_character">
+													<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+														<c:if test="${symbolList.symbolType == 'D'}">
+															<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}"><c:out value="${symbolList.symbol}"/></a>
+														</c:if>
+													</c:forEach>
+												</div>
+											</div>
+											<!-- 웃음 -->
+											<div class="cnt_character emt_character">
+												<div class="box_character">
+													<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+														<c:if test="${symbolList.symbolType == 'S'}">
+															<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+														</c:if>
+													</c:forEach>
+												</div>
+											</div>
+											<!-- //웃음 -->
+											<!-- 슬픔 -->
+											<div class="cnt_character emt_character">
+												<div class="box_character">
+													<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+														<c:if test="${symbolList.symbolType == 'C'}">
+															<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+														</c:if>
+													</c:forEach>
+												</div>
+											</div>
+											<!-- //슬픔 -->
+											<!-- 분노 -->
+											<div class="cnt_character emt_character">
+												<div class="box_character">
+													<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+														<c:if test="${symbolList.symbolType == 'A'}">
+															<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+														</c:if>
+													</c:forEach>
+												</div>
+											</div>
+											<!-- //분노 -->
+											<!-- 사랑 -->
+											<div class="cnt_character emt_character">
+												<div class="box_character">
+													<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+														<c:if test="${symbolList.symbolType == 'L'}">
+															<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+														</c:if>
+													</c:forEach>
+												</div>
+											</div>
+											<!-- //사랑 -->
+											<!-- 그외 -->
+											<div class="cnt_character emt_character emt_etc ">
+												<div class="box_character">
+													<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
+														<c:if test="${symbolList.symbolType == 'E'}">
+															<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
+														</c:if>
+													</c:forEach>
+												</div>
+											</div>
+											<!-- //그외 -->
+											<button type="button" class="btn_close" onclick="miniPopup(this);">닫기</button>
+										</div>
+									</div>
+									<div class="btn_popup_wrap convers_wrap">
+										<button type="button" class="btnType btnType7" onclick="miniPopup(this)">특정문구 일괄변환<i class="qmMark"></i></button>
+										<div class="send_miniPop convers">
+											<div>
+												<div class="convers_top">
+													<span>특정문구 일괄변환이란?</span>
+													<p>주소록, 엑셀에 입력된 내용을 이용해 수신자마다 다른 내용의<br> 메시지를 발송하는 기능</p>
+												</div>
+												<div class="convers_middle"><a href="javascript:void(0)" class="changeWord" value="[*이름*]">[*이름*]</a></div>
+												<div class="convers_bottom">
+													<a href="javascript:void(0)" class="changeWord" value="[*1*]">[*1*]</a>
+													<a href="javascript:void(0)" class="changeWord" value="[*2*]">[*2*]</a>
+													<a href="javascript:void(0)" class="changeWord" value="[*3*]">[*3*]</a>
+													<a href="javascript:void(0)" class="changeWord" value="[*4*]">[*4*]</a>
+												</div>
+											</div>
+											<button type="button" class="btn_close" onclick="miniPopup(this);">닫기</button>
+										</div>
+									</div>
+									<button type="button" class="btnType btnType7" onclick="javascript:fnGoMyMsg(); return false;">내문자함</button>
+									<button type="button" class="btnType btnType8" onclick="openPhotoEditor();">이미지 불러오기</button>
+									<div class="send_btnWrap">
+	                                    <button type="button" class="btnType btnType9" onclick="javascript:fn_saveMyMsg(); return false;">문자저장</button>
+	                                	<button type="button" class="btnType btnType9 btnReset">초기화</button>
+	                            	</div>
+                            	</div>
+                            </div>
+                        	<p>* 현재 [<span id="nowMsgType">단문</span>] <span class="c_e40000 fwBold nowMsgCnt">0</span>건 발송 가능합니다.</p>
+						</td>
+					</tr>
+					<tr>
+						<th scope="row" class="vTop">받는사람</th>
+						<td class="putText">
+							<div class="clearfix receipt_num">
+								<div class="receipt_num_top">
+									<label for="callTo" class="label">받는 번호입력</label>
+									<input type="text" id="callTo" name="callTo"  placeholder="번호를 입력하세요" oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*)\./g, '$1');" onfocus="this.placeholder=''" onblur="this.placeholder='번호를 입력하세요'" style="width:340px;">
+									<button type="button" class="btnType btnType6 addCallToF">번호추가</button>
+									<span><span class="vMiddle">*</span> 중복번호는 한번만 발송됩니다.</span>
+								</div>
+								<div class="receipt_num_midde">
+									<div class="listType list01 callList_box" id="callList_box">
+										<div class="list_table list_head">
+											<div class="cb_wrap">
+												<label for="" class="label"></label>
+												<input type="checkbox">
+											</div>
+											<div class="list_table_num">
+												<p>번호</p>
+												<img src="/publish/images/sortUp.png">
+												<img src="/publish/images/sortDown.png">
+											</div>
+											<div class="list_table_name">
+												<p>이름</p>
+												<img src="/publish/images/sortUp.png">
+												<img src="/publish/images/sortDown.png">
+											</div>
+										</div>
+									</div>
+									<div class="put_right">
+										<div class="btn_popup_wrap spc_wrap">
+											<button type="button" data-tooltip="popup06" class="btnType btnType7 popupAddr">주소록 불러오기</button>
+										</div>
+										<div class="btn_popup_wrap">
+											<button type="button" data-tooltip="popup02" class="btnType btnType7">엑셀 불러오기</button>
+										</div>
+										<div class="btn_popup_wrap">
+											<button type="button" data-tooltip="popup03" class="btnType btnType7 tab1">최근 전송내역</button>
+										</div>
+										<div class="btn_popup_wrap">
+											<button type="button" data-tooltip="popup03" class="btnType btnType7 tab2">자주 보내는 번호</button>
+										</div>
+										<div class="btn_popup_wrap">
+											<button type="button" data-tooltip="popup05" class="btnType btnType7 tab2" onclick="getMjMsgSentListAll('1');">재전송</button>
+										</div>
+										<div class="btn_popup_wrap check_validity_wrap">
+											<button type="button" class="btnType btnType7 check_validity">오류 검사 <i class="qmMark"></i></button>
+											<div class="error_hover_cont send_hover_cont">
+												<p>휴대폰 번호 입력 시 해당 휴대폰 번호에 대한 형식이 어긋나거나 휴대폰 번호에 오류가 있는지 등을 검사하는 기능</p>
+												<span>(예시) 010-1234-0001(O) / 010-12345-0001(X)</span>
+											</div>
+										</div>
+									</div>
+								</div>
+								<div class="list_bottom clearfix">
+									<div class="remove_btnWrap">
+										<button type="button" class="btnType15 all_del"><i class="remove_img"></i>전체삭제</button>
+										<button type="button" class="btnType15 select_del"><i class="remove_img"></i>선택삭제</button>
+									</div>
+									<div class="list_bottom_right">
+										<p>총 <span class="c_e40000" id="rowTotCnt">0</span>건 / 중복 <span class="c_002c9a" id="rowDupCnt">0</span>건</p>
+										<button type="button" class="address_reg2 addressregi_btn">주소록에 등록</button>
+									</div>
+								</div>
+							</div>
+						</td>
+					</tr>
+					<tr>
+						<th colspan="2" class="billingAmount">
+							<div>
+								<div class="final_pay">
+									<div class="pay_info_list">
+	                                   	<p>발송금액 :</p>
+	                                   	<div class="info" id="repPriceTxt">
+	                                   		단문 : <strong>20</strong>건<span>/</span>장문 : <strong>150</strong>건<span>/</span>그림문자 : <strong>30</strong>건
+	                                   	</div>
+									</div>
+									<p class="price" ><span id="totalPriceTxt">0</span>원<span>(부가세 포함)</span></p>
+								</div>
+								<c:if test="${eventRemainCash > 0  && eventMberInfo.eventStatus eq 'Y'}">
+									<p style="text-align: right; font-size: 14px; color: #666; margin: -10px 0 15px 0; font-weight: 300;">* 이벤트회원의 발송금액은 이벤트단가를 적용하여 계산된 금액이므로 실제 발송금액과 다를 수 있습니다.</p>
+								</c:if>
+								<div class="pay_type clearfix">
+	                                <fmt:formatNumber type="number" maxFractionDigits="3" value="${userMoney}" var="commaPrice" />
+									<div>
+										<input type="radio" id="radio_bill_1" name="radio_bill" checked="checked">
+										<label for="radio_bill_1">보유잔액</label>
+										<label for="userMoney" class="label">보유잔액</label>
+										<input type="text" id="userMoney" name="userMoney" value="<c:out value='${commaPrice}'/>" readonly>
+										<span class="won">원</span>
+										<button type="button" class="btnType btnType21" onclick="location.href='/web/member/pay/PayView.do'">충전</button>
+									</div>
+									<c:if test="${eventRemainCash > 0  && eventMberInfo.eventStatus eq 'Y'}">
+										<div><button type="button" data-tooltip="popup07" class="btnType btnType3 btn_event_cash">이벤트 잔액</button></div>
+									</c:if>
+								</div>
+									
+								<!--발송금액 아래 등급별 가격안내 추가-->
+								<div class="my_price_wrap" id="myPriceWrap" style="display: none;">
+									<div class="center-line"></div>
+									<ul>
+										<li class="title">
+											<img src="/publish/images/content/icon_mypage_message.png" alt="">나의 단가 &nbsp;<span>:</span> &nbsp;
+										</li>
+										<li class="price_line">
+											<span class="type">단문</span>
+											<span class="price"><fmt:formatNumber value="${shortPrice}" pattern="###.#" /></span>원
+											<span class="line">/ &nbsp;</span>
+										</li>
+										<li class="price_line">
+											<span class="type">장문</span>
+											<span class="price"><fmt:formatNumber value="${longPrice}" pattern="###.#" /></span>원
+											<span class="line">/ &nbsp;</span>
+										</li>
+										<li class="price_line">
+											<span class="type">그림</span>
+											<span class="price"><fmt:formatNumber value="${picturePrice}" pattern="###.#" /></span>원 
+											(2장 : <fmt:formatNumber value="${picture2Price}" pattern="###.#" />원 / 3장 : <fmt:formatNumber value="${picture3Price}" pattern="###.#" />원)
+										</li>
+									</ul>
+								</div>	
+								<!-- End -->									
+							</div>
+						</th>
+					</tr>
+				</tbody>
+			</table>
+		</div>
+		<div class="send_right">
+			<div class="phone">
+				<div class="phoneIn">
+					<div>
+						<p><img src="/publish/images/search.png">미리보기</p>
+						<div class="text_length2 clearfix preShort">
+							<span class="msg_com msg_short">단문</span>
+							<div>
+								<span>글자크기</span>
+								<button type="button" class="fontPlus"><img src="/publish/images/content/font_plus.png"></button>
+								<button type="button" class="fontMinus"><img src="/publish/images/content/font_minus.png"></button>
+							</div>
+						</div>
+						<div class="text_length2 clearfix prePhoto">
+							<span class="msg_com msg_photo">포토</span>
+							<ul class="photo_msg_num">
+								<li class="photo_num_01" onclick="imgClick(0);"><a href="#none">1</a></li>
+								<li class="photo_num_02" onclick="imgClick(1);"><a href="#none">2</a></li>
+								<li class="photo_num_03" onclick="imgClick(2);"><a href="#none">3</a></li>
+							</ul>
+							<div>
+								<span>글자크기</span>
+								<button type="button" class="fontPlus"><img src="/publish/images/content/font_plus.png"></button>
+								<button type="button" class="fontMinus"><img src="/publish/images/content/font_minus.png"></button>
+							</div>
+						</div>
+						<!-- 텍스트 미리보기 -->
+						<div class="text_preview">
+							<div class="preiew_img preViewShort"></div>
+							<div class="preview_auto">
+								<p class="none_txt">내용을 입력해주세요.</p>
+								<pre class="realtime"></pre>
+							</div>
+						</div>
+						<!-- //텍스트 미리보기 -->
+					</div>
+				</div>
+				<p class="addText">※ 단말기 설정에 따라 다르게 보일 수 있습니다</p>
+			</div>
+			<div class="phone_bottom">
+				<div class="send_rev">
+					<div class="send_content">
+						<div class="rev_radio">
+							<ul>
+								<li><input type="radio" id="reserYnN" name="reserYn" value="N" checked="checked"><label for="reserYnN">즉시</label></li>
+								<li><input type="radio" id="reserYnY" name="reserYn" value="Y"><label for="reserYnY">예약</label></li>
+							</ul>
+						</div>
+						<div class="send_btn">
+							<button type="button" class="btnType btnType11" onclick="javascript:fn_sendMsgData(); return false;">발송하기</button>
+							<button type="button" class="btnType btnType10" onclick="javascript:fnTestSend(); return false;">테스트발송</button>
+						</div>
+					</div>
+					<div class="rev_selected">
+						<div class="rev_top">
+               		        <span>날짜 :</span>
+							<div class="calendar_wrap">
+								<input type="text" class="startDate2 inp resDate calendar02" title="검색 시작일" id="startDate2" name="startDate2" value="" data-datecontrol="true">
+							</div>
+							<label for="msgResHour" class="label">시 선택</label>
+							<div class="selBox">
+								<select class="selType1" id="msgResHour" name="msgResHour">
+		       		            	<c:forEach  var="hour"  begin="0" end="23" step="1" varStatus="status">
+		       		            		<c:choose>
+		       		            			<c:when test="${hour < 10}">
+		         		            			<option value="0${hour}">0${hour}시</option>
+		       		            			</c:when>
+		       		            			<c:otherwise>
+		       		            				<option value="${hour}">${hour}시</option>
+		       		            			</c:otherwise>
+		       		            		</c:choose>
+		       		            	</c:forEach>
+		       		            </select>
+		       		            <label for="msgResMin" class="label">분 선택</label>
+		       		            <select class="selType1" id="msgResMin" name="msgResMin">
+		       		            	<c:forEach var="min" begin="0" end="55" step="5">
+		       		            		<c:choose>
+		       		            			<c:when test="${min < 10}">
+		         		            			<option value="0${min}">0${min}분</option>
+		       		            			</c:when>
+		       		            			<c:otherwise>
+		       		            				<option value="${min}">${min}분</option>
+		       		            			</c:otherwise>
+		       		            		</c:choose>
+		       		            	</c:forEach>
+		       		            </select>
+							</div>
+               		    </div>
+						<div class="rev_bottom">
+							<input type="checkbox" id="divideChk" name="divideChk">
+							<label for="divideChk">분할전송</label>
+							<input type="text" class="dividType1" id="divideCnt" name="divideCnt" value="20" onkeypress='return checkNumber(event)' maxlength="4"/>
+							<label for="divideCnt">건씩</label>
+							<select class="selType1" id="divideTime" name="divideTime">
+								<option value="1">01분</option>
+								<option value="2">02분</option>
+								<option value="3">03분</option>
+								<option value="4">04분</option>
+								<option value="5">05분</option>
+								<option value="10">10분</option>
+								<option value="15">15분</option>
+								<option value="20">20분</option>
+								<option value="30">30분</option>
+							</select>
+							<label for="divideTime">간격</label>
+						</div>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+</form>
+
+<form id="sentListForm" name="sentListForm" method="post">
+	<input type="hidden" name="pageType"  value=""/>
+	<input type="hidden" name="pageIndex" value=""/>
+	<input type="hidden" name="msgSentType" value=""/>
+	<input type="hidden" name="searchSortCnd" value="" />
+	<input type="hidden" name="searchSortOrd" value="" />		
+</form>
+	
+<form id="latestMsgForm" name="latestMsgForm" method="post">
+	<input type="hidden" id="userId" name="userId" value="${LoginVO.id}"/>
+</form>
+
+<form id="addMyMsgForm" name="addMyMsgForm" method="post">
+	<input type="hidden" id="msgId" name="msgId" value=""/>
+	<input type="hidden" id="pageType1" name="pageType" value=""/>
+</form>
+
+<form name="popForm" id="popForm" method="post">
+	<input type="hidden"id="pageType2" name="pageType" value=""/> 
+</form>
+
+<form name="goToCustomForm" id="goToCustomForm" method="post" action="/web/mjon/custom/selectMsgCustomView.do">
+	<input type="hidden" id="pageType3" name="pageType" value="msgcampain"/> 
+</form>
+
+<form name="testSendForm" id="testSendForm" method="post">
+	<input type="hidden" name="msgKind" value="C"/> 
+	<input type="hidden" name="msgpreview" value=""/> 
+	<input type="hidden" name="mmsSubject" value=""/>
+	<input type="hidden" name="callFrom" value=""/>
+	<input type="hidden" name="imgFilePath" value=""/>
+	<input type="hidden" name="eachPrice" value=""/>
+	<input type="hidden" name="msgType" value=""/>
+	<input type="hidden" name="smsTxt" value=""/>
+</form>
src/main/webapp/WEB-INF/jsp/web/msgcampain/MsgDataView.jsp
--- src/main/webapp/WEB-INF/jsp/web/msgcampain/MsgDataView.jsp
+++ src/main/webapp/WEB-INF/jsp/web/msgcampain/MsgDataView.jsp
@@ -3,10 +3,21 @@
 <%@ taglib prefix="ui" uri="http://egovframework.gov/ctl/ui"%>
 <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
 <%@ page import="itn.com.cmm.LoginVO" %>
+<script type="text/javascript" src="<c:url value='/publish/js/content.js'/>"></script>
 
 <!-- <script src="/publish/js/content.js"></script> -->
 
 <script type="text/javascript">
+
+var popCustomScrT=0;	// 맞춤제작 요청 JSPark => 2023.02.21 추가
+
+const SMS_CONFIG = {
+	prefix: "(선거운동정보)",
+	suffix: [
+		"불법수집정보신고 선거관리위원회 1390",
+		"무료거부 0808800858"
+	]
+};
 
 var _regExp1 = /(^02.{0}|^01.{1}|^[0-9]{3})-?([0-9]{3,4})-?([0-9]{4})$/;
 
@@ -60,6 +71,10 @@
 
 //문자 그룹정보 => 재전송용
 function getMjMsgGroupInfoByResend() {
+	console.log('getMjMsgGroupInfoByResend : :::::');
+
+
+
 	$.ajax({
 		type: "POST",
 		url: "/web/mjon/msgdata/selectMjMsgGroupInfoByResendAjax.do",
@@ -69,6 +84,7 @@
 		success: function (data) {
 			//alert(JSON.stringify(data));
 			if(data.isSuccess == true){
+				console.log(data)
 				var msgData = data.resultMsgInfo;
 				var fileData = data.resultMsgAddPhotoInfo;
 				
@@ -110,13 +126,17 @@
 				
 				// 문자내용
 				// 선거 기본정보 제거
-				if (smsTxt.indexOf("(선거운동정보)") == 0) {
-					smsTxt = $.trim(smsTxt.replace("(선거운동정보)", ""));
-					var smsTxtLastIdxCnt = smsTxt.lastIndexOf("후보자전화번호");
-					if (smsTxtLastIdxCnt != -1) {
-						smsTxt = $.trim(smsTxt.substring(0, smsTxtLastIdxCnt));	
-					}
+				if (smsTxt.indexOf(SMS_CONFIG.prefix) == 0) {
+					smsTxt = smsTxt.replace(SMS_CONFIG.prefix, "");
+
+					SMS_CONFIG.suffix.forEach(function(text){
+						smsTxt = smsTxt.replace(text, "");
+					});
+
+					smsTxt = $.trim(smsTxt);
 				}
+
+
 				$('#smsTxtArea').val(smsTxt);
 				
 				// 첨부 이미지가 있는경우 이미지 처리해주기
@@ -763,8 +783,449 @@
 	return confCheck;
 }
 
+
+
+//폼 유효성 검사 함수
+function validateForm(form) {
+
+	// 타블레이터 호출
+	var $selectedData = tableL.getData(); // 데이터 가져오기
+
+	if($selectedData.length < 1){
+		alert("받는사람 내역을 입력해주세요.");
+		return false;
+	}
+
+
+	if(form.callFromList.value == ""){
+
+		alert("발신번호를 입력해 주세요.");
+		return false;
+
+	}
+
+	if (form.subjectChkYn.value === 'N') {
+		form.mmsSubject.value = "";
+	} else if (getSpacialStringChk(form.mmsSubject.value)) {
+		alert("문자 제목에는 치환문자(엑셀 내 *이름*, *1*, *2*, *3*, *4* 등)를 사용하실 수 없습니다.");
+		return false;
+	}
+
+	//문자제목에 이모지가 있는지 체크
+	var titleStatusYn = $("input[name='subjectChkYn']:checked").val();
+	if(titleStatusYn == 'Y') {
+		if(!emojiCheck(form.mmsSubject.value)) return false;
+	}
+
+	// 문자내용에 이모지가 있는지 체크
+	var strCont = form.smsTxtArea.value;
+	if (!emojiCheck(strCont)) return false;
+
+	var rtnStr = strChinJpnCheck(strCont);
+	if(rtnStr.length > 0){
+		alert("입력하신 문구 중 \" " + rtnStr + " \" 는 일부 휴대폰에서 표기되지 않을 수 있습니다.");
+	}
+
+	if (imgFilePath.length === 0 && !form.smsTxtArea.value) {
+		alert("문자내용을 입력해 주세요.");
+		return false;
+	}
+	return true;
+}
+
+
+//이벤트가 아닌 일반 개별 단가 셋팅해주기
+function getEventEachPrice(evnMsgType){
+
+	var eventEachPrice = 0;
+	var evnImgCnt = $("#imgCnt").val();
+
+	//일반 단가로 변경해주기
+	if(evnMsgType == '4'){
+
+		eventEachPrice = $("#sPrice").val();
+		console.log("eventEachPrice Short::: "+eventEachPrice);
+
+	}else if(evnMsgType == '6'){
+
+		if(evnImgCnt == 0){//장문 가격
+
+			eventEachPrice = $("#mPrice").val();
+			console.log("eventEachPrice Long ::: "+eventEachPrice);
+
+		}else if(evnImgCnt == 1){
+
+			eventEachPrice = $("#pPrice").val();
+			console.log("eventEachPrice p1 ::: "+eventEachPrice);
+
+		}else if(evnImgCnt == 2){
+
+			eventEachPrice = $("#p2Price").val();
+			console.log("eventEachPrice p2 ::: "+eventEachPrice);
+
+		}else if(evnImgCnt == 3){
+
+			eventEachPrice = $("#p3Price").val();
+			console.log("eventEachPrice p3 ::: "+eventEachPrice);
+
+		}
+
+	}
+
+	return eventEachPrice;
+}
+
 //문자발송 처리 함수
 function fn_sendMsgData(){
+
+	// 타블레이터 호출
+	var $selectedData = tableL.getData(); // 데이터 가져오기
+
+	if(!checkConf()){	//문자온 conf-check
+		alert("현재 문자 발송하기 기능 점검 중입니다.\n\n1분 후 다시 시도해주세요.");
+		return false;
+	}
+
+	var form = document.msgForm;
+	var totPriceOnly = stringReplaceAll(form.totPrice.value, ",", "");
+	var userMoneyOnly = stringReplaceAll(form.myPrice.value, ",", "");
+
+	// test 주석
+	if(parseFloat(userMoneyOnly) < parseFloat(totPriceOnly)){
+		alert("문자 발송에 필요한 회원님의 보유 잔액이 부족 합니다.");
+		return false;
+	}
+
+	// 폼 유효성 검사
+	if (!validateForm(form)) return false;
+
+	var spamStatus = false;
+	var exceptSpamYn = $("#exceptSpamYn").val(); //금지어 필터링 예외 여부 - N 일 경우만 스팸 검사를 진행
+
+
+	// var blineCodeYn = $("#blineCode").val();
+	// if(blineCodeYn != 'N'){
+	// 	if(!blineSendCheck(blineCodeYn)){	//문자온 conf-check
+	// 		alert("현재 문자 발송하기 기능 점검 중입니다.\n\n잠시 후 다시 시도해주세요.");
+	// 		return false;
+	// 	}
+	// }
+
+	if($selectedData.length > 300000){
+		alert("30만건까지 발송이 가능합니다.\n받는사람 목록을 확인해주세요.");
+		return false;
+	}
+
+
+
+	if(!confirm("문자를 전송하시겠습니까?")){
+		return false;
+	}
+
+	//총 결제금액 천단위 콤마 삭제 후 전송
+	var totPrice = form.totPrice.value;
+	form.totPrice.value = totPrice.replace(",","");
+
+
+	//이벤트 진행중 회원의 경우 이벤트 잔여금액 비교 처리 필요.
+	//이벤트 캐시가 부족한 경우 이벤트 캐시로 발송 가능한 만큼만 이벤트 금액으로 발송 처리해줌.
+	//이 후 나머지 발송 건수는 이벤트 캐시가 아닌 일반 단가로 발송 처리를 진행 함.
+	var eventStatus = form.eventStatus.value;
+
+	if(eventStatus == 'Y'){ //이벤트 진행 대상자이면 문자종류에 이벤트로 구분
+
+		form.eventYn.value = "Y"; //이벤트문자 종류 설정
+
+	}
+
+	var eventRemainCash = parseFloat(form.eventRemainCash.value);
+	console.log('eventStatus : ', eventStatus);
+
+	if(eventStatus == 'Y' && parseFloat(eventRemainCash) < parseFloat(totPriceOnly))
+	{
+
+		// 이벤트 금액 부족 상태 요청하신 모두 발송할 수 없습니다
+		console.log('eventRemainCash : ', eventRemainCash);
+		if(!confirm("고객님의 이벤트 캐시 잔액(" + eventRemainCash + "원) 부족으로 요청하신 문자("+numberWithCommas($selectedData.length)+"건)를 모두 발송할 수 없습니다. 이벤트 캐시 초과 건에 대해서는 일반 단가를 적용하여 발송하시겠습니까?")){
+			return false;
+		}
+
+		// 이벤트 캐시 초과 건에 대해서는 일반 단가를 적용하여 발송하시겠습니까
+
+		var evnMsgType = $("#msgType").val(); 				// 문자전송 타입
+		var norEachPrice = getNorEachPrice(evnMsgType);		// 일반전송 금액
+		var eventEachPrice = getEventEachPrice(evnMsgType);	// 이벤트 전송 금액
+		var eventCount = eventRemainCash/eventEachPrice;	// 이벤트금액으로 전송가능한 수량
+		console.log('eventCount : ', parseInt(eventCount));
+		var norCount = numberWithCommas($selectedData.length)-parseInt(eventCount);	// 일반금액으로 전송수량
+		console.log('norCount : ', parseInt(norCount));
+
+		var norAccount = norCount * norEachPrice;		// 일반금액으로 변경한 발송금액
+		var totAccount = userMoneyOnly - norAccount		//
+		console.log('norAccount : ', norAccount);
+		console.log('userMoneyOnly : ', userMoneyOnly);
+		console.log('totAccount : ', totAccount);
+
+		if(totAccount < 0){
+			alert("고객님의 이벤트 캐시 잔액(" + parseInt(totAccount)*-1 + "원) 부족으로 요청하신 문자("+numberWithCommas($selectedData.length)+"건)를 모두 발송할 수 없습니다.");
+			return false;
+		}
+	}
+
+	console.log(' !!! imgFilePath : ', imgFilePath);
+
+	// img 처리 영역
+	imgFilePath = [];
+	$('.thumb_wrap').find('.thumb_img').each(function(idx, el) {
+		if($("#delLi"+idx).hasClass("Template")){
+			templateYn.push("Y");
+		} else {
+			templateYn.push("N");
+		}
+
+		if($(el).hasClass("edit_y")) {
+			//이미지 변환
+			const imgBase64 = $(el).attr("src");
+			const decodImg = atob(imgBase64.split(',')[1]);  // base64~ 부분을 제외하고 데이터 디코딩
+
+
+			let array = [];
+			for (let i = 0; i < decodImg.length; i++) {
+				array.push(decodImg.charCodeAt(i));
+			}
+
+			const file = new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
+			const fileName = 'canvas_img_' + new Date().getMilliseconds() + '.jpg';
+			let formData = new FormData();
+			formData.append('file', file, fileName);
+
+			$.ajax({
+				type: 'post',
+				url: '/web/mjon/msgdata/insertEditImageAjax.do',
+				cache: false,
+				data: formData,
+				dataType:'json',
+				processData: false,
+				contentType: false,
+				async: false,
+				success: function (returnData, status) {
+					if(status == 'success'){
+						console.log('returnData : ',returnData)
+						// imgFilePath 에 배열로 담아주기(이미지 순서대로)
+						//console.log(imgFilePath);
+						imgFilePath.push(returnData.filefullPath);
+						imgFileId.push(returnData.atchFileId);
+
+					} else if(status== 'fail'){
+						alert(returnData.message);
+					}
+				},
+				error: function (e) { alert("이미지 업로드에 실패하였습니다."); console.log("ERROR : ", e); }
+			});
+
+		} else {
+			if(imgFilePath.length != imgFileId.length){
+				//에디터 안거친 템플릿 이미지면 바로 src 때림
+				imgFilePath.push($(el).attr("src"));
+			}
+		}
+	});
+
+
+	form.templateYnAdvc.value = templateYn;
+	form.imgFilePathAdvc.value = imgFilePath;
+	form.imgFileIdAdvc.value =  imgFileId;
+// 	form.imgFilePath.value = JSON.stringify(imgFilePath).replace(/\\/g, '');
+// 	form.imgFileId.value =  JSON.stringify(imgFileId).replace(/\\/g, '');
+	form.callFrom.value = removeDash($('#callFromList').val()); // 발신번호 대쉬(-) 문자 없애주기
+
+	//광고 종류 설정
+
+	// 예약 확인
+	var reserYn = $("input[name=reserYn]:checked").val(); // 예약 발송 여부 확인
+	form.reserveYn.value = reserYn; // 즉시 / 예약 문자 선택 여부
+
+	if(reserYn == 'Y'){
+
+		var date = $(".resDate").val();//form.msgResDate.value;
+		var hour = form.msgResHour.value;
+		var min = form.msgResMin.value;
+
+		if(date == ""){
+
+			alert("예약전송 날짜를 선택해 주세요.");
+			return false;
+
+		}else{
+
+			var now = new Date();
+			var reqDate = date + " " + hour + ":" + min + ":00";
+			var gapDate = getGapDayTime(date, hour, min);
+
+			if(gapDate < 0){ // 음수이면 이전날짜, 크면 이후 날짜.
+				alert("예약 날짜는 현재 시간 이후의 날짜 및 시간을 선택해 주세요.");
+				return false;
+			}else{
+				form.reqDate.value = reqDate;	//예약일자 파라미터 저장
+			}
+		}
+
+	}else{
+
+		form.reqDate.value = "";
+
+	}
+
+
+
+	//발송 Ajax 호출해주기
+	sendMsgAjax_advc();
+}
+
+
+
+function sendMsgAjax_advc(){
+	// 타블레이터 호출
+	var $selectedData = tableL.getData(); // 데이터 가져오기
+
+	// 폼 데이터를 배열로 직렬화
+	var form = $('#msgForm');
+	var formDataArray = form.serializeArray();
+
+	// 배열을 객체로 변환
+	var formData = {};
+	$.each(formDataArray, function(index, field) {
+		formData[field.name] = field.value;
+	});
+
+	// 빈 값 제거
+	removeEmptyValues(formData);
+
+	// 선택된 데이터 추가
+	formData["mjonMsgSendVOList"] = $selectedData;
+
+	// JSON 데이터 확인
+	console.log("최종 formData:", JSON.stringify(formData));
+
+	// var url = "/web/mjon/msgdata/sendMsgDataAjax_advc.do";
+	// var url = "/web/mjon/msgcampain/sendMsgDataAjax.do";
+	var url = "/web/mjon/msgcampain/sendMsgDataAjax_advc.do";
+	// 시작 시간
+
+	// 프로그래스파 시간을 위한 계산
+	var estimtedTime = calculateEstimatedTime($selectedData.length);
+
+
+	$.ajax({
+		type: "POST",
+		url: url,
+		data: JSON.stringify(formData),
+		contentType: 'application/json',
+		dataType: 'json',
+		success: function (data) {
+
+			console.log('자동동보문자 - 결과 :: ', data);
+
+			var status = data.status;
+			if("OK" == status){ // 성공
+
+				var smsCnt = Number(data.object.resultSts);
+				var blockCnt = Number(data.object.resultBlockSts);
+
+				if((smsCnt + blockCnt) == 0){
+
+					$('.pop_msg_spam').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+					$('.pop_msg_spam .msg_text').html("문자 발송(예약)에 실패하였습니다.<br/> 다시 시도해주세요. <br/>* 정상적으로 발송 시도하였으나 실패하신 경우 혹시 문자내용에 사용불가 이모지 <br/>또는 복사-붙여넣기로 인한 보이지 않는 특수문자가 포함되었는지 확인 후 다시 시도해주세요.");
+					$('.mask').addClass('on');
+
+				}else{
+
+					$('.pop_msg_success').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+					//예약발송 건의 경우 결과 팝업 문구 변경
+
+					var reserYn = $("input[name=reserYn]:checked").val();
+					var resText = (reserYn === 'Y') ? '예약' : '발송';
+
+					$('.pop_msg_success .msg_text').html(resText+" 성공 : <strong>"+ smsCnt + "</strong>건,수신거부 : <span>" + blockCnt + "</span>건의<br>문자가 "+resText+" 되었습니다.");
+
+					$('.mask').addClass('on');
+
+				}
+
+
+			}else if("BAD_REQUEST" == status){ // 오류
+
+				alert(data.message);
+				return false;
+
+			}else if("UNAUTHORIZED" == status){ // 정지 회원 처리
+
+				alert(data.message);
+				//문자발송 URL Move
+				goMsgUrlMove();
+				return false;
+
+			}else if("FORBIDDEN" == status){ // 정지 회원 처리
+
+				deptCandidateChk();
+				return false;
+
+			}else if("NO_CONTENT" == status){ // 발송로직에서 이미지 처리 오류 시 처리
+
+				$('.pop_msg_fails').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+				$('.pop_msg_fails .msg_text').html(returnData.message);
+				$('.mask').addClass('on');
+
+			}
+
+		},
+		beforeSend : function(xmlHttpRequest) {
+			// 프로그래스 바 실행
+			progressStart(estimtedTime);
+		},
+		complete : function(xhr, textStatus) {
+
+			// 프로그래스 바 종료
+			progressComplete();
+		},
+		error: function (e) { alert("문자 발송에 실패하였습니다."); console.log("ERROR : ", e); }
+	});
+
+}
+
+//빈 값이나 null 값을 제거하는 함수
+function removeEmptyValues(obj) {
+	Object.keys(obj).forEach(function(key) {
+		if (obj[key] === null || obj[key] === '') {
+			delete obj[key];
+		}
+	});
+}
+
+
+
+// 선택된 데이터의 길이에 따라 예상 시간 계산 함수
+function calculateEstimatedTime(selectedCount) {
+	//기준값
+	// const processTimePerBatch = 130; // 130초
+
+
+	// 30만건 기준 10분으로 기준을 잡아서
+	// 시간계산함
+	const processTimePerBatch = 600;
+	const batchSize = 300000;
+
+	// 1건당 처리 시간
+	const timePerRecord = processTimePerBatch / batchSize;
+
+	// 예상 시간 계산
+	const estimatedTimeInSeconds = selectedCount * timePerRecord;
+
+	return estimatedTimeInSeconds.toFixed(2);
+}
+
+//문자발송 처리 함수
+function fn_sendMsgData_backup(){
 	
 	if(!checkConf()){	//문자고 conf-check
 		alert("현재 문자 발송하기 기능 점검 중입니다.\n\n1분 후 다시 시도해주세요.");
@@ -1834,6 +2295,20 @@
 }
 //END
 </script>
+
+
+
+<div class="progress_bar_wrap">
+	<div class="progress_box">
+		<p class="time_text">0%</p>
+		<div class="bar">
+			<span class="change_bar"></span>
+		</div>
+	</div>
+	<div class="btn_wrap">
+	</div>
+
+</div>
 	<div class="tooltip-wrap">
 		<!-- 문자발송 성공 레이어팝업 -->
 		<div class="popup-com pop_msg_success">
@@ -1886,13 +2361,13 @@
             <!-- tab button -->
             <ul class="tabType1">
                 <li class="tab active">
-                	<%-- <button type="button" onclick="TabType1(this,'1');">단문 · 장문 · 그림 문자</button> --%>
-                	<button type="button" onclick="TabType1(this,'1');">단체문자(자동동보문자)</button>
+<%--					<button type="button" onclick="TabType1(this,'1');">단체문자(자동동보문자)</button>--%>
+					<button type="button" onclick="TabType1(this,'1');">자동동보문자</button>
                 </li>
                 <li class="tab">
                 	<%-- <button type="button" onclick="TabType1(this,'2');">대량 문자(엑셀·TXT)</button> --%>
                 	<%-- <button type="button" onclick="javascript:fnMsgExcelDataView(); return false;">단체문자(엑셀·TXT)</button> --%>
-                	<button type="button" onclick="javascript:fnMsgTWDataView(); return false;">20건 문자(수동문자)</button>
+                	<button type="button" onclick="javascript:fnMsgTWDataView(); return false;">20건 수동문자</button>
                 </li>
             </ul><!--// tab button -->
 			<!-- tab content1 -->
src/main/webapp/WEB-INF/jsp/web/msgcampain/excel/MsgExcelDataSMLView.jsp
--- src/main/webapp/WEB-INF/jsp/web/msgcampain/excel/MsgExcelDataSMLView.jsp
+++ src/main/webapp/WEB-INF/jsp/web/msgcampain/excel/MsgExcelDataSMLView.jsp
@@ -3187,9 +3187,9 @@
 							<li>
 								<div>
 									<i class="benefit7"></i>
-									<p>20건씩 나눠서 보내야한다면?<span>20건씩 분할 예약 전송 가능</span></p>
+									<p>대량 문자를 나눠서 보내야한다면?<span>조건 설정 후 자동 분할 예약 가능</span></p>
 								</div>
-								<p>누구나 쉽고 편리하게 20건씩 나눠서 분할 전송이 가능합니다.</p>
+								<p>설정한 건수와 간격에 따라 자동으로 분할 예약 발송됩니다.</p>
 							</li>
 							<li>
 								<div>
src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/MsgTWDataSMLView.jsp
--- src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/MsgTWDataSMLView.jsp
+++ src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/MsgTWDataSMLView.jsp
@@ -10,16 +10,48 @@
 
 <!--  -->
 <script type="text/javascript" src="<c:url value='/publish/js/publish.js?date=202402060001'/>"></script>
+<script type="text/javascript" src="<c:url value='/js/web/msgcampain/tw/tabulator.js'/>"></script>
+<script type="text/javascript" src="<c:url value='/js/web/msgcampain/tw/init.js'/>"></script>
+<script type="text/javascript" src="<c:url value='/js/web/msgcampain/tw/event.js'/>"></script>
+<script type="text/javascript" src="<c:url value='/js/web/addr/cmn.js?date=202409021440'/>"></script>
 
 <style>
 /* .send_top .send_right .phone_bottom{display:flex;align-items:center;} */
 .send_top .send_right .send_rev{margin:0 !important;}
 .send_top .send_right .phone_bottom{bottom:130px;}
 .send_top .send_right .send_rev .send_content{padding:0 !important;}
+.btn_list_detail{display:inline-flex;width:24px;height:24px;margin:-2px 0 0 0;border:1px solid #a5a5a5;border-radius:5px;justify-content:center;align-items:center;}
+.btn_list_detail img{width:calc(100% - 8px);}
+
+
+
+
+
+#sms-table .tabulator-cell.phone-cell{
+	cursor:default;
+}
+
+#sms-table{
+	user-select:none;
+	height:auto !important;
+	width:100%;
+}
+
+#sms-table .tabulator{
+	height:auto !important;
+}
+
+#sms-table .tabulator-tableholder{
+	overflow-y:hidden !important;
+	max-height:none !important;
+}
+
+
 </style>
 
 <% pageContext.setAttribute("newLineChar", "\r\n"); %>
 <script type="text/javascript">
+
 var tableErrorData = [];
 var totRows = 0; // 좌측 받는사람 총 갯수
 
@@ -66,7 +98,7 @@
 		
 		//받는사람 리스트를 담아둔 배열에 신규 추가 데이터를 추가해 준다.
 		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});
 			
 		}
@@ -282,7 +314,7 @@
 //받는 사람 20명 정보 리스트로 불러오기 
 function addTWCallToInfo(){
 	
-	var callSeq = $("#callSeq").val();
+	/*var callSeq = $("#callSeq").val();
 	var pageIndex = $("#callToForm #pageIndex").val();
 	//var sendData =  $(document.callToForm).serializeArray();
 	$("#twCallToList").load("/web/mjon/msgcampain/selectMsgTWCallToListAjax.do", {"callSeq":callSeq, "pageIndex":pageIndex} ,function(response, status, xhr){
@@ -355,7 +387,7 @@
 			
 		});
 		
-	});
+	});*/
 	
 	//후보자 등록 체크
 	var candiNm = '${mjonCandidateVO.candidateNm}';
@@ -373,83 +405,7 @@
 	
 }
 
-function fnCallToListReset(){
-	
-	var callSeq = $("#callSeq").val();
-	if(callSeq == 0){
-		
-		alert("받는사람 목록이 없습니다.");
-		return false;
-		
-	}else{
-		
-		if(!confirm("기존 받는사람을 모두 초기화하고 새로운 받는사람을 불러옵니다. 진행하시겠습니까?")){
-			return false;
-		}
 
-		var data = new FormData(document.callToForm);
-		
-		$.ajax({
-	        type: "POST",
-	        url: "/web/mjon/msgcampain/updateMsgTWCallToListResetAjax.do",
-	        data: data,
-	        dataType:'json',
-	        async: true,
-	        processData: false,
-	        contentType: false,
-	        cache: false,
-	        //timeout: 600000,
-	        success: function (returnData, status) {
-				if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
-					
-					var result = returnData.result;
-					var message = returnData.message;
-					
-					if(result == "loginFail"){
-						
-						alert(message);
-						return false;
-						
-					}else if(result == "fail"){
-						
-						alert(message);
-						return false;
-						
-					}else if(result == "success"){
-						
-						alert("수신목록의 초기화가 완료되었습니다.");
-						
-						//데이터 초기화 후 call_seq 번호를 초기화 해준다.
-						$("#callSeq").val("0");
-						addTWCallToInfo();
-						
-					}else{
-						alert(message);
-						return;
-						
-					}
-				} else if(status== 'fail'){
-					alert("수신목록 초기화 중 오류가 발생하였습니다.");
-					console.log("status : fail ~");
-				}
-			},
-			error: function (e) { 
-	        	alert("수신목록 초기화 중 오류가 발생하였습니다."); 
-	        	console.log("ERROR : ", e); 
-	        },
-			beforeSend : function(xmlHttpRequest) {
-	        	//로딩창 show
-	        	$('.loading_layer').addClass('active');				
-			},	        	        
-	        complete : function(xhr, textStatus) {
-	        	//로딩창 hide
-	        	$('.loading_layer').removeClass('active');
-			}
-	    });
-		
-	}
-	
-}
 
 //선택 수신목록 리스트 삭제 처리하기
 function fnCallToListDel(callToCnt){
@@ -528,48 +484,6 @@
 	
 }
 
-function txtExport(event){
-    var input = event.target; 
-    var reader = new FileReader();
-    var file = input.files[0];
-    var txtAddr = [];
-	var fileNm = input.files[0].name;
-    var fileExt = fileNm.split('.').pop().toLowerCase();
-    
-    if(fileExt != "txt"){
-    	
-    	alert("TXT 파일만 등록 할 수 있습니다.");
-    	return false;
-    	
-    }
-    
-    if (!file) {
-    	
-    	alert("첨부파일이 없습니다.");
-        return;
-    }
-    
-    //txt 파일 읽어 오기
-    var arrSplitData = [];
-    reader.onload = function(e) {
-        fileData = e.target.result;
-        arrSplitData = fileData.split("\n");
-        
-        for(var i=0; i < arrSplitData.length; i++){
-        	
-        	var arrTemp = arrSplitData[i].split("\t");
-        	txtAddr.push({phone: arrTemp[1].trim(), name: arrTemp[0].trim()});
-        	
-        }
-        
-      	//Tabulator에 데이터 입력해주기
-        addPhoneInfo(txtAddr);
-    };
-    reader.readAsText(file, 'UTF-8');
-    
-    //첨부파일 초기화 시켜주기
-    $("#txtFile").val("");
-} 
 
 //발송금액 단가표시
 function SetPriceWrapOpen() {
@@ -606,25 +520,25 @@
 }	
 
 
-
-//엔터키로 문자발송 처리해주기
-$(document).keypress(function(e){
-	
-	if(e.keyCode == 13 
-			&& !$(e.target).is('#smsTxtArea') 
-			&& !$(e.target).is('#callTo')
-			&& !$(e.target).is('#searchKeyword')
-			&& !$(e.target).is('#searchTxt')
-			&& !$(e.target).is('#id_text')
-			&& !$(e.target).is('#password_text')
-			&& !$(e.target).is('#searchWord')){
-		
-		enterSts = true;
-		fn_sendMsgData();
-		
-	}
-	
-});
+//
+// //엔터키로 문자발송 처리해주기
+// $(document).keypress(function(e){
+//
+// 	if(e.keyCode == 13
+// 			&& !$(e.target).is('#smsTxtArea')
+// 			&& !$(e.target).is('#callTo')
+// 			&& !$(e.target).is('#searchKeyword')
+// 			&& !$(e.target).is('#searchTxt')
+// 			&& !$(e.target).is('#id_text')
+// 			&& !$(e.target).is('#password_text')
+// 			&& !$(e.target).is('#searchWord')){
+//
+// 		enterSts = true;
+// 		fn_sendMsgData();
+//
+// 	}
+//
+// });
 
 $(document).ready(function (){
 	
@@ -664,448 +578,62 @@
 	//주소록 불러오기 팝업 내용
 	//Tabulator AJAX Data Loading
 	tableAddr = new Tabulator(".callAddr_box", {
-		height:"255px",
-	    layout:"fitColumns",
-	    headerHozAlign:"center",
-	    validationMode:"highlight",
-	    placeholder:"주소록 그룹을 선택해 주세요.", //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){
-	 	        cell.getRow().toggleSelect();
-		 		}
-		 	}, 
-		 	{title:"그룹명", hozAlign:"center", field:"addrGroupNm", editor:"input", width:100, validator:["required","minLength:2", "maxLength:40"]},
-		 	{title:"이름", hozAlign:"center", field:"addrName", editor:"input",  width:100, validator:["maxLength:12"]},
-		 	{title:"휴대폰번호", hozAlign:"center", field:"addrPhone", editor:"input", width:100, validator:["required","minLength:10", "maxLength:11"]},
-		 	{title:"[*1*]", hozAlign:"center", field:"addrRep1", editor:"input", width:84, validator:["maxLength:40"]},
-		 	{title:"[*2*]", hozAlign:"center", field:"addrRep2", editor:"input", width:84, validator:["maxLength:40"]},
-		 	{title:"[*3*]", hozAlign:"center", field:"addrRep3", editor:"input", width:84, validator:["maxLength:40"]},
-		 	{title:"[*4*]", hozAlign:"center", field:"addrRep4", editor:"input", width:84, validator:["maxLength:40"]},
-		 	
-	 	],
-	 	validationFailed:function(cell, value, parameters){ // 유효성 체크 함수 - 아직 잘 모르겠음 
-	 		var valid = cell.isValid();
-	 		var fieldNm = cell.getField();
-	 		if(!valid){
-	 			if(fieldNm == "addrName"){
-	 				alert("받는사람 이름은 최대 12글자까지만 입력 가능합니다.");
-	 			}else if(fieldNm == "addrPhone"){
-	 				alert("휴대폰번호는 하이픈(-)을 제외한 숫자만 정확히 입력해 주세요.");
-	 			}else if(fieldNm == "addrGroupNm"){
-	 				alert("그룹명을 정확히 입력해 주세요. 2 ~ 40글자 이내로 입력 가능합니다.");
-	 			}else{
-		 			alert("치환문자를 정확히 입력해 주세요. 40글자 이내로 입력 가능합니다.");
-	 			}
-	 			
-	 			//해당 셀 데이터 삭제
-	 			cell.setValue("");
-	 		}
-	 		return value % parameters.addrPhone;
-	    },
-
-	});
-	
-	//핸드폰 번호 Tabulator에서 수정시 중복 체크
-	function fnDuplPhone(){
-		
-		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.trim()) , 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});
-			
-			}
-		
-		}
-		
-		//수신목록에서 중복 휴대폰문자가 있는지 체크해주기
-		var dupCnt = dupliPhoneDataChk(tableData);
-		
-		if(dupCnt > 0){
-			
-			if(confirm("동일한 휴대폰 번호가 받는사람 목록에 등록되어 있습니다. 중복 번호를 삭제하시겠습니까?")){
-				
-				//수신목록에서 중복 휴대폰 번호 삭제해주기
-				tableL.clearData(); //기존 받는사람 목록을 삭제.
-				tableL.addData(dupliPhoneData(tableData)); // 받는사람 목록에 주소 정보 입력하기
-				_fileForm2 = []; //form file data 초기화
-				_fileIdx = 0;	//form file idx 초기화
-				
-				totRows = tableL.getRows().length; 
-				updateTotCnt(totRows); //전체 데이터 갯수 구하기
-				
-			}
-			
-		}
-		
-	}
-	
-	//받는사람 목록에 복사/붙여넣기 기능 처리
-	/* $('.callList_box').on('paste', function (e) {
-		
-		var element = e.originalEvent.clipboardData.getData('text'); // 클립보드에 복사한 데이터 가져오기
-		
-		var elmSplit= [];
-		  
-		elmSplit = element.split("\n");
-		
-		var elmLen = elmSplit.length;
-		
-		  
-		if(elmLen < 0){
-			  
-			alert("붙여넣을 연락처를 복사해주세요.");
-			return false;
-			  
-		}else{
-			tableErrorData.length = 0;	// 오류 번호 배열 초기화
-			
-			var splitData = [];
-			var realPhone = [];
-			for(var i=0; i < elmLen; i++){
-				  
-				var splitStr = elmSplit[i]; 
-				var tabData = [];
-				var comData = [];
-				
-				if(splitStr.indexOf('\t') != -1){
-					splitData = splitStr.split('\t'); //탭 구분으로 데이터 분할
-				}else if(splitStr.indexOf(',') != -1){
-					splitData = splitStr.split(','); //콤마 구분으로 데이터 분할
-				}else{
-					splitData = splitStr.split(' ');
-				}
-				
-				
-				if(splitData.length == 0){// 데이터가 없는경우
-					
-					alert("탭으로 구분하여 데이터를 복사해 주세요.");
-				  	return false;
-				  
-				}else if(splitData.length == 1){// 데이터가 탭으로 구분이 없는 경우
-					
-					for(var j=0; j < splitData.length; j++){
-						if(checkHpNum(splitData[j].trim())){//핸드폰 양식이 맞는지 확인
-							//배열 끝에 데이터 추가해 주기
-							realPhone.push({phone: removeDash(splitData[j].trim()), name: ""});
-						}
-						else {
-							if (splitData[j].trim() != '' && splitData[j].trim() != null && splitData[j].trim() != undefined) {
-								tableErrorData.push(splitData[j].trim());
-							}
-						}
-					}
-				
-				}else{//데이터가 탭으로 구분되어 이름, 연락처로 구분된 경우
-					
-					var phone = "";	//핸드폰번호
-					var name = "";	//이름
-					var rep1 = "";	//치환문자1
-					var rep2 = "";	//치환문자2
-					var rep3 = "";	//치환문자3
-					var rep4 = "";	//치환문자4
-					var isPhoneValid = false;
-					for(var j=0; j < splitData.length; j++){
-
-						if(j == 0){
-							
-							name = splitData[j].trim();
-							
-						}
-						
-						if(j == 1){
-							
-							if(checkHpNum(splitData[j].trim())){//핸드폰 양식이 맞는지 확인
-								phone = removeDash(splitData[j].trim());
-								isPhoneValid = true;
-							}else{
-								if (splitData[j].trim() != '' && splitData[j].trim() != null && splitData[j].trim() != undefined) {
-									tableErrorData.push(splitData[j].trim());
-								}
-							}
-							
-						}
-						
-						if(j == 2){	//치환문자1
-							
-							rep1 = splitData[j].trim();
-							
-						}
-						
-						if(j == 3){	//치환문자2
-							
-							rep2 = splitData[j].trim();
-							
-						}
-						
-						if(j == 4){	//치환문자3
-							
-							rep3 = splitData[j].trim();
-							
-						}
-						
-						if(j == 5){	//치환문자4
-							
-							rep4 = splitData[j].trim();
-							
-						}
-						
-					}
-					
-					if (isPhoneValid == true) {
-						//배열 끝에 데이터 추가해 주기
-						realPhone.push({phone: phone, name: name, rep1 : rep1, rep2 : rep2, rep3 : rep3, rep4 : rep4 });
-					}
-					
-				}//else end
-				  
-			}
-			
-			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.trim()) , 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,  });
-				
-				}
-			
-			}
-			
-			if(realPhone.length > 0){
-				
-				for(var j=0; j < realPhone.length; j++){
-					
-					tableData.push({phone: removeDash(realPhone[j].phone.trim()) , name: realPhone[j].name, rep1: realPhone[j].rep1, rep2: realPhone[j].rep2, rep3: realPhone[j].rep3, rep4: realPhone[j].rep4});
-				
-				}
-			
-			}
-			
-			//tableData.push(realPhone);
-				
-			//중복 연락처 1개만 남기고 삭제하기
-			var removeDuplPhone = dupliPhoneData(tableData);
-			  
-			//수신자 리스트에 전화번호 추가해주기
-			//tableL.addData(removeDuplPhone);
-			tableL.setData(removeDuplPhone);
-			
-			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);
-			}
-
-			if (tableErrorData.length > 0) {
-				alert("올바르지 않은 휴대폰 번호가 "+ tableErrorData.length +" 건 있습니다.");
-			}			
-			
-		}
-		  
-	}); */
-	
-	//받는사람 번호 버튼 클릭시 Tabulator에 데이터 넣어주기
-	$('.addCallToF').click(function(){ 
-		
-		var callToNum = $('#callTo').val();
-		if(callToNum == null || callToNum == ""){
-			
-			alert("받는사람 번호를 입력해 주세요.");
-			return false;
-			
-		}else if(!checkHpNum(callToNum)){	
-			
-			alert("올바른 전화번호를 입력해 주세요.");
-			$('#callTo').val("");
-			return false;
-		}
-		
-		//핸드폰 번호에 '-' 문자 제거하기
-		callToNum = removeDash(callToNum);
-		
-		var form = document.callToForm;
-		var callToArr = [];
-		
-		callToArr.push(callToNum);
-		form.callToArr.value = callToArr;
-		
-		var data = new FormData(form);
-		
-		var url = "/web/mjon/msgcampain/insertMsgTWCallToOneNumberAddAjax.do";
-		
-		$.ajax({
-	        type: "POST",
-	        url: url,
-	        data: data,
-	        dataType:'json',
-	        async: true,
-	        processData: false,
-	        contentType: false,
-	        cache: false,
-	        success: function (returnData, status) {
-				if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
-					
-					var result = returnData.result;
-					var message = returnData.message;
-					
-					if(result == "success"){
-						
-						var callSeq = returnData.callSeq;
-						
-						if(callSeq != null){
-							$("#callSeq").val(callSeq);
-						}
-						
-						//입력된 데이터베이스에서 받는사람 20건 불러와서 화면에 표시해주기
-						var callSeq = $("#callSeq").val();
-						if(callSeq > 0){
-							
-							//첨부파일로 불러온 데이터를 받는사람 목록에 추가해 준다.
-							addTWCallToInfo();
-							
-							$('#callTo').val("");
-							
-						}else{
-							
-							alert("추가할 연락처가 없습니다.");
-							return false;
-							
-						}
-						
-					}else{
-						alert(message);
-						$('#callTo').val("");
-						return;
-						
-					}
-				} else if(status== 'fail'){
-					alert("연락처를 추가하는 중 오류가 발생하였습니다.");
-					console.log("status : fail ~");
+		height: "255px",
+		layout: "fitData",
+		headerHozAlign: "center",
+		validationMode: "highlight",
+		resizableColumns: true,
+		progressiveLoad:"scroll",
+		progressiveRender: true,   // 렌더링 최적화 활성화
+		progressiveRenderSize: 100, // 한 번에 렌더링할 행 수를 줄임
+		placeholder: "주소록 그룹을 선택해 주세요.",
+		columns: [
+// 	        {formatter: "rowSelection", clipboard: false, hozAlign: "center", headerSort: false},
+			{formatter: "rowSelection", titleFormatter: "rowSelection", hozAlign: "center", headerSort: false,
+				cellClick: function(e, cell) {
+					fn_loadAddActive(); // 로딩 활성화
+					setTimeout(() => {
+						tableAddr.blockRedraw(); // 렌더링 차단
+						cell.getRow().toggleSelect(); // 선택 상태 토글
+						tableAddr.restoreRedraw(); // 렌더링 재개
+						fn_loadRemoveActive(); // 로딩 비활성화
+					}, 0); // 비동기적으로 실행
 				}
 			},
-			error: function (e) { 
-	        	alert("연락처를 추가하는 중 오류가 발생하였습니다."); 
-	        	console.log("ERROR : ", e); 
-	        },
-			beforeSend : function(xmlHttpRequest) {
-	        	//로딩창 show
-	        	$('.loading_layer').addClass('active');				
-			},	        	        
-	        complete : function(xhr, textStatus) {
-	        	//로딩창 hide
-	        	$('.loading_layer').removeClass('active');
+			{title: "No", hozAlign: "center", formatter: "rownum", align: "center", headerHozAlign: "center", width: 60},
+			{title: "그룹명", hozAlign: "center", field: "addrGroupNm", editor: false, width: 100},
+			{title: "이름", hozAlign: "center", field: "name", editor: false, width: 100},
+			{title: "휴대폰번호", hozAlign: "center", field: "phone", editor: false, width: 100},
+			{title: "[*1*]", hozAlign: "center", field: "rep1", editor: false, width: 84},
+			{title: "[*2*]", hozAlign: "center", field: "rep2", editor: false, width: 84},
+			{title: "[*3*]", hozAlign: "center", field: "rep3", editor: false, width: 84},
+			{title: "[*4*]", hozAlign: "center", field: "rep4", editor: false, width: 84},
+		 	
+	 	],
+		validationFailed: function(cell, value, parameters) {
+			var valid = cell.isValid();
+			var fieldNm = cell.getField();
+			if (!valid) {
+				if (fieldNm == "addrName") {
+					alert("받는사람 이름은 최대 12글자까지만 입력 가능합니다.");
+				} else if (fieldNm == "addrPhone") {
+					alert("휴대폰번호는 하이픈(-)을 제외한 숫자만 정확히 입력해 주세요.");
+				} else if (fieldNm == "addrGroupNm") {
+					alert("그룹명을 정확히 입력해 주세요. 2 ~ 40글자 이내로 입력 가능합니다.");
+				} else {
+					alert("치환문자를 정확히 입력해 주세요. 100글자 이내로 입력 가능합니다.");
+				}
+				cell.setValue("");
 			}
-	    });
-	    
-	});
-	
-	
-	//받는사람 전체삭제 버튼 처리
-	$('.all_del').click(function(){
-		
-		var data = $('.liCallTo').length;
-	
-		if(data == 0){
-			
-			alert("받는사람을 추가해 주세요.");
-			return false;
-		
-		}else{
-			
-			if(confirm("받는사람 목록을 모두 삭제하시겠습니까?")){
-				
-				var callToArr = [];
-				
-				//받는사람 목록의 리스트 전체 데이터 불러와서 배열에 저장
-				//화면에 불러와져있는 최대 20개의 리스트만 삭제
-				$("input[name=chkCallTo]").each(function(){
-					
-					var cmpTmpId = $(this).val();
-					callToArr.push(cmpTmpId);
-					
-				});
-				
-				var form = document.callToForm;
-				form.callToArr.value = callToArr;
-				
-				//수신목록 삭제 요청 한다.
-				fnCallToListDel(callToArr.length);
-				
-			}
-	
-		}
-		
-	});
-	
-	
-	// 받는사람 선택삭제 버튼 처리해주기
-	$('.select_del').click(function(){
-		
-		var data = $('.liCallTo').length;
-		
-		if(data == 0){
-			
-			alert("받는사람을 추가해 주세요.");
-			return false;
-		
-		}
-		
-		var chkSts = $('input:checkbox[name="chkCallTo"]').is(':checked');
-		
-		if(!chkSts){
-			alert("삭제할 연락처를 선택해 주세요.");
-			return false;
-		}else{ // 선택한 Row 데이터 삭제하기
-			
-			if(confirm("선택하신 받는 사람을 삭제하시겠습니까?")){
-				
-				var callToArr = [];
-				
-				//받는사람 목록의 리스트 체크선택된 값만 가져온다.
-				//화면에 체크된 수신목록만 삭제한다.
-				$("input:checkbox[name='chkCallTo']:checked").each(function(){
-					
-					var cmpTmpId = $(this).val();
-					callToArr.push(cmpTmpId);
-					
-				});
-				
-				var form = document.callToForm;
-				form.callToArr.value = callToArr;
-				
-				//선택된 수신목록 삭제 요청 한다.
-				fnCallToListDel(callToArr.length);
-				
-			}
+			console.log('parameters : ', parameters);
+			return value % parameters.addrPhone;
+		},
 
-		}
-		
 	});
 	
-	
+
 	//주소록 불러오기 버튼 클릭시
-	$('.popupAddr').click(function(){
+	$('#popupAddr').click(function(){
 		
 		var login = '${LoginVO.id}';
 		
@@ -1116,7 +644,8 @@
 			
 		}
 		
-		$("#addrGroupLoad").load("/web/mjon/msgcampain/selectAddrGroupListAjax.do", "" ,function(response, status, xhr){
+		// $("#addrGroupLoad").load("/web/mjon/msgcampain/selectAddrGroupListAjax.do", "" ,function(response, status, xhr){
+		$("#addrGroupLoad").load("/web/mjon/msgdata/selectAddrGroupListAjax.do", "" ,function(response, status, xhr){
 			//리스트 스크롤 처리해주기
 			$(".adr_pop_list").mCustomScrollbar({
 				axis: 'y',
@@ -1134,177 +663,8 @@
 		$("#excelFile").click();
 		
 	});
-	
-	//최근전송내역 팝업 선택추가 버튼 처리(체크내역 받는사람 리스트로 추가해주기)
-	$(document).on('click', '#latestAddPhone', function (){
-		var addPhoneList = []; //신규로 추가할 전화번호 저장변수
-		$("input:checkbox[name='latAddrChk']:checked").each(function(index){
-			var chkPhone = $(this).val();
-			if(!checkHpNum(chkPhone)){
-				alert("올바른 전화번호가 아닙니다.");
-				return false;
-			}else{
-				addPhoneList.push({phone: removeDash(chkPhone.trim())});
-			}
-		});
-		
-		if(addPhoneList.length > 0){
-			//연락처 추가해 주기
-			addPhoneInfo(addPhoneList);
-			$("#btnLatestAddPhoneClose").trigger("click");
-		}
-		else {
-			alert("연락처를 선택해주세요.");
-			return false;
-		}		
-	});
-	
-	//최근전송내역 팝업 전체추가 버튼 처리
-	$(document).on('click', '#latestAddPhoneAll', function (){
-		var addPhoneList = []; //신규로 추가할 전화번호 저장변수
-		$("input:checkbox[name='latAddrChk']").each(function(index){
-			var chkPhone = $(this).val();
-			if(!checkHpNum(chkPhone)){
-				alert("올바른 전화번호가 아닙니다.");
-				return false;
-			}else{
-				addPhoneList.push({phone: removeDash(chkPhone.trim())});
-			}
-		});
-		
-		if(addPhoneList.length > 0){
-			//연락처 추가해 주기
-			addPhoneInfo(addPhoneList);
-			$("#btnLatestAddPhoneClose").trigger("click");
-		}
-		else {
-			alert("연락처가 없습니다.");
-			return false;
-		}		
-	});
-	
-	//최근전송내역 팝업 선택 취소 버튼 처리
-	$(document).on('click', '#latestCancelPhone', function (){
-		
-		$("input[name=latAddrChk]").prop("checked", false);
-		
-	});
-	
-	//최근전송내역 팝업 삭제 버튼 처리
-	$(document).on('click', '#latestAddrDel', function (){
-		
-		$(this).parent("#latestLi").remove();
-		
-	});
-	
-	//자주보내는 번호 팝업 선택추가 버튼 처리(체크내역 받는사람 리스트로 추가해주기)
-	$(document).on('click', '#bookMarkAddPhone', function (){
-		var addPhoneList = []; //신규로 추가할 전화번호 저장변수
-		$("input:checkbox[name='bookAddrChk']:checked").each(function(index){
-			var chkPhone = $(this).val();
-			if(!checkHpNum(chkPhone)){
-				alert("올바른 전화번호가 아닙니다.");
-				return false;
-			}else{
-				addPhoneList.push({phone: removeDash(chkPhone.trim())});
-			}
-		});
-		
-		if(addPhoneList.length > 0){
-			//연락처 추가해 주기
-			addPhoneInfo(addPhoneList);
-			$("#btnLatestAddPhoneClose").trigger("click");
-		}
-		else {
-			alert("연락처를 선택해주세요.");
-			return false;
-		}		
-	});
-	
-	//자주보내는 번호 팝업 선택추가 버튼 처리(체크내역 받는사람 리스트로 추가해주기)
-	$(document).on('click', '#bookMarkAddPhoneAll', function (){
-		var addPhoneList = []; //신규로 추가할 전화번호 저장변수
-		$("input:checkbox[name='bookAddrChk']").each(function(index){
-			var chkPhone = $(this).val();
-			if(!checkHpNum(chkPhone)){
-				alert("올바른 전화번호가 아닙니다.");
-				return false;
-			}else{
-				addPhoneList.push({phone: removeDash(chkPhone.trim())});
-			}
-		});
-		
-		if(addPhoneList.length > 0){
-			//연락처 추가해 주기
-			addPhoneInfo(addPhoneList);
-			$("#btnLatestAddPhoneClose").trigger("click");
-		}
-		else {
-			alert("연락처가 없습니다.");
-			return false;
-		}		
-	});
-	
-	//자주보내는 번호 팝업 선택 취소 버튼 처리
-	$(document).on('click', '#bookMarkCancelPhone', function (){
-		
-		$("input[name=bookAddrChk]").prop("checked", false);
-		
-	});
-	
-	//자주보내는 번호 팝업 삭제 버튼 처리
-	$(document).on('click', '#bookMarkAddrDel', function (){
-		
-		$(this).parent("#bookMarkLi").remove();
-		
-	});
-	
-	
-	//오류 검사 버튼 처리
-	$('.check_validity').click(function(){
-		
-		var data = $("input[name='chkCallTo']").length;
-		
-		if(data == 0){
-			
-			alert("받는사람을 추가해 주세요.");
-			return false;
-		
-		}else{
-				
-			var callToChkArr = [];
-			//받는사람 목록의 리스트 전체 데이터 불러와서 배열에 저장
-			//화면에 불러와져있는 최대 20개의 리스트만 삭제
-			$("input[name='chkCallTo']").each(function(){
-		
-				var callTo = $(this).closest("div").next().text();
-				//전화번호 유효성 체크 해주기
-				var callSts = checkHpNum(callTo);
-				
-				if(!callSts){
-					
-					callToChkArr.push(callTo);
-					
-				}
-				
-			});
-			
-			if(callToChkArr.length > 0){
-				
-				alert("받는사람 목록 중 ["+ callToChkArr + "] 번호에 오류가 있습니다.");
-				return false;
-				
-			}else{
-				
-				alert("받는사람 번호에는 오류가 없습니다.");
-				return false;
-				
-			}
-			
-		}
-		
-	});
-	
+
+
 	//문자입력창의 첨부된 이미지 순서를 바꿀 때
 	$(document).on('mouseup', '.thumb_wrap img', function (){
 		//미리보기 창의 이미지 순서를 변경한다
@@ -1854,32 +1214,22 @@
 	}else{
 		$('.rev_selected').show();
 	}
-	
-	//즉시 발송 라디오 버튼 선택시 숨김처리
-	$("#reserYnN").on('click', function(){
-		$('.rev_selected').hide();
-		//$('.send_rev .send_content').css('padding-bottom','108px');
-		$(".send_top .send_right .phone_bottom").css("bottom","130px");
-		$('.send_btn .btnType:first-child').html('발송하기');
-		$("#lblEnterKey").text("Enter키로 발송하기");
-	});
-	
-	//예약 발송 라디오 버튼 선택시 숨김 해제처리
-	$("#reserYnY").on('click', function(){
-		$('.rev_selected').show();
-		/* $('.send_rev .send_content').css('padding-bottom','0'); */
-		$(".send_top .send_right .phone_bottom").css("bottom","64px");
-		$('.send_btn .btnType:first-child').html('예약하기');
-		$("#lblEnterKey").text("Enter키로 예약하기");
-	});
+
 	
 });
 
 //선거 후보자 등록 알림 메세지 처리
 function fn_candidateChk(){
-	alert("선거 후보자를 등록이 되어야 문자 발송이 가능합니다. 후보자 등록을 해주세요.");
-	return false;
-	
+
+	var candidateNm = $.trim($("#candidateNmChk").val());
+	var dept = $.trim($("#deptChk").val());
+
+	// 기업회원이면
+	if(dept == 'c'){
+		$('[data-tooltip="alert_layer_popup02"]').trigger('click'); // 기업회원 팝업
+	}else if(!candidateNm){	// 값이 없으면
+		$('[data-tooltip="alert_layer_popup"]').trigger('click'); // 후보자 등록 팝업
+	}
 }
 	
 //문자 바이트수 계산하기 함수
@@ -2246,13 +1596,27 @@
 }
 
 
-$(document).on('click', '.symbolButton, .changeWord', function (){
+$(document).on('click', '.symbolButton', function (){
 	//var smsTxtArea = $('#smsTxtArea').val();
 	//$('#smsTxtArea').val(smsTxtArea + $(this).attr("value"));
-	
+
+	console.log($(this).text());
+	console.log($(this).attr("class"));
+
 	// 커서 위치에 삽입
 	setCursorInsertText("smsTxtArea", $(this).attr("value"));
-	
+
+	fnByteString($('#smsTxtArea').val());
+});
+
+
+$(document).on('click', '#changeWord', function (){
+	//var smsTxtArea = $('#smsTxtArea').val();
+	//$('#smsTxtArea').val(smsTxtArea + $(this).attr("value"));
+
+	// 커서 위치에 삽입
+	setCursorInsertText("smsTxtArea", $(this).text());
+
 	fnByteString($('#smsTxtArea').val());
 });
 
@@ -2573,177 +1937,96 @@
 	
 }
 
+
 function loadAddrList(){
 
 	/*
-		serialize 를 사용할때는 processData, contentType 옵션 제가할것
+		serialize 를 사용할때는 processDa    ta, contentType 옵션 제가할것
 	*/
 	var data = $("#searchAddrGrpForm").serialize();
-	
-	var url = "/web/mjon/msgcampain/selectMsgAddrListAjax.do";
-	
+
+	var url = "/web/mjon/msgdata/selectMsgAddrListAjax_advc.do";
+
 	$.ajax({
-        type: "POST",
-        url: url,
-        data: data,
-        dataType:'json',
-        async: true,
-        cache: false,
-        success: function (returnData, status) {
-			if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
-				
-				if(returnData.result == "success"){
-					var addrList = returnData.resultAddrList;
-					var tableData = [];
-					
-					if(addrList.length == 0){
-						
-						alert("주소록 정보가 없습니다.");
-						tableAddr.setData(tableData);
-						return false;
-					}
-					//받는사람 리스트를 담아둔 배열에 신규 추가 데이터를 추가해 준다.
-					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});
-						
-					}
-					//우측 주소록 리스트 Tabulator에 입력해주기
-					tableAddr.setData(tableData);
-					
-				}else{
-					
-					alert(returnData.message);
+		type: "POST",
+		url: url,
+		data: data,
+		dataType:'json',
+		async: true,
+		cache: false,
+		success: function (data) {
+			console.log('data : ', data);
+			if(data.status == "OK"){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+
+				var addrList = data.object;
+
+				if(addrList.length == 0){
+
+					alert("주소록 정보가 없습니다.");
+// 	                    tableAddr.setData([]);
 					return false;
-					
 				}
-				
-			} else if(status== 'fail'){
+
+// 					console.log('data : ', data);
+				tableAddr.setData(addrList);
+			}
+			else
+			{
 				alert("주소록 불러오기에 실패하였습니다. !!");
 			}
 		},
-        error: function (e) { 
-        	alert("주소록 불러오기에 실패하였습니다."); console.log("ERROR : ", e); 
-        },
+		error: function (jqXHR, textStatus, errorThrown) {
+			alert("주소록 불러오기에 실패하였습니다.");
+			console.error("Error:", jqXHR.status, textStatus, errorThrown);
+			console.error("Response Text:", jqXHR.responseText);
+			try {
+				let json = JSON.parse(jqXHR.responseText);
+				console.log("Parsed JSON Response:", json);
+			} catch (e) {
+				console.error("JSON Parse Error:", e);
+			}
+		},
 		beforeSend : function(xmlHttpRequest) {
-        	//로딩창 show
-        	$('.loading_layer').addClass('active');				
-		},	        	        
-        complete : function(xhr, textStatus) {
-        	//로딩창 hide
-        	$('.loading_layer').removeClass('active');
+			//로딩창 show
+			$('.loading_layer').addClass('active');
+		},
+		complete : function(xhr, textStatus) {
+			//로딩창 hide
+			$('.loading_layer').removeClass('active');
 		}
-    });
-	
+	});
+
 }
 
 //주소록 불러오기에서 수신자 리스트 추가해 주기
-function addrToList(){
-	
-	var selectedData = tableAddr.getSelectedRows();
-	//var tableData = [];
-	var callToArr = [];
-	var form = document.callToForm;
-	
-	if(selectedData == "" || selectedData == null){
-		
+// function addrToList(){
+function addrToList_advc(type){
+
+
+	var tableSize = tableAddr.getDataCount();
+	if(tableSize < 1){
 		alert("주소록을 선택해 주세요.");
 		return false;
-	
-	}else{ // 선택한 Row 데이터 저장해주기
-		
-		for(var i=0; i < selectedData.length; i++){
-			
-			//좌측 받는사람 리스트를 담아둔 배열에 데이터를 추가해 준다.
-			callToArr[i] = selectedData[i].getData().addrPhone;
-		
-		}
-	
-		//기존 받는사람 목록에 데이터가 있으면 알림 메세지 표시해주기
-		var callToLiCnt = $('.ui-widget-content').length;
-		if(callToLiCnt > 0){
-			
-			if(!confirm("기존 받는사람을 모두 초기화하고 새로운 받는사람을 불러옵니다. 진행하시겠습니까?")){
-				return false;
-			}
-
-		}
-		
-		//선택한 데이터 받는사람 리스트에 추가해 주기
-		form.callToArr.value = callToArr;
-		var data = new FormData(form);
-		var url = "/web/mjon/msgcampain/insertMyAddrTWCallToAjax.do";
-		$.ajax({
-			type: "POST",
-	        url: url,
-	        data: data,
-	        dataType:'json',
-	        async: true,
-	        processData: false,
-	        contentType: false,
-	        cache: false,
-	        success: function (returnData, status) {
-				if(status == "success"){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
-					
-					var result = returnData.result;
-					var message = returnData.message;
-					var dupCallCnt = returnData.dupCallCnt;
-					var callSeq = returnData.maxCallSeq;
-					
-					if(result == "loginFail"){
-						
-						alert(message);
-						return false;
-						
-					}else if(result == "fail"){
-						
-						alert(message);
-						return false;
-						
-					}else if(result == "success"){
-						
-						if(Number(dupCallCnt) > 0){
-							alert("추가 주소록 리스트 중 중복 연락처 " + dupCallCnt + "건은 제외되었습니다.");
-						}
-						
-						if(Number(callSeq) > 0){
-							$("#callSeq").val(callSeq);
-							$("#callToForm #pageIndex").val("1");
-							//추가된 수신목록 20건 불러오기
-							addTWCallToInfo();
-						}
-						
-					}else{
-						alert(message);
-						return;
-						
-					}
-						
-				} else if(status== 'fail'){
-					alert("주소록을 불러오는 중 오류가 발생하였습니다.");
-					console.log("status : fail ~");
-				}
-			},
-			error: function (e) { 
-	        	alert("주소록을 불러오는 중 오류가 발생하였습니다."); 
-	        	console.log("ERROR : ", e); 
-	        },
-			beforeSend : function(xmlHttpRequest) {
-	        	//로딩창 show
-	        	$('.loading_layer').addClass('active');				
-			},	        	        
-	        complete : function(xhr, textStatus) {
-	        	//로딩창 hide
-	        	$('.loading_layer').removeClass('active');
-			}	
-	    });
-		
-		$(".closeAddr").trigger("click");
-		//주소록 레이어 팝업의 Tabulator 데이터 지워주기
-		tableAddr.clearData();
-
 	}
-	
+
+
+	var addrData;
+	if(type == 'all'){
+		addrData = tableAddr.getData();
+	}else{
+		addrData = tableAddr.getSelectedData();
+	}
+
+	// 새로 추가하려는 데이터 (대시 제거)
+	const setAddrData = addrData.map(row => ({
+		name: row.name,
+		phone: removeDash(row.phone)
+	}));
+	console.log("선택된 행 개수:", setAddrData.length);
+
+
+	updateTwSmSTable(setAddrData);
+	addrClose();
 }
 
 //주소록 팝업 닫기 기능
@@ -2755,6 +2038,8 @@
 	tableAddr.clearData();
 	
 }
+
+
 
 //내문자함 선택시 저장된 내용 문자 입력영역에 처리해주기
 function fnMyMsgAdd(msgId){
@@ -3107,22 +2392,6 @@
 	document.popForm.submit();
 }
 
-$(document).on('click', '.addressregi_btn', function() {
-	var tableData = tableL.getRows();
-	var dataLen = tableL.getRows().length;
-	if(dataLen == 0){
-		alert("연락처 정보를 등록해 주세요.");
-		return false;
-	}else{
-		$('.addressregi_layer').css({'width':'680px','display':'block','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
-		setTimeout(function(){
-			$('.addressregi_layer').css({'opacity':'1'});
-		},150);
-		$('.mask').addClass('on');
-		getAddrGroupList();
-	}
-});
-
 $(document).on('click', '.addressregi_layer .tooltip-close', function() {
 	$('.addressregi_layer').attr('style','');
 	$("#addrGrpNm").val("");
@@ -3307,7 +2576,7 @@
 		}
 		
 		//제목 사용한 경우
-		if($("input[name=title_status]:checked").val() == 'Y') {
+		if($("input[name=subjectChkYn]:checked").val() == 'Y') {
 			form.mmsSubject.value = msgForm.mmsSubject.value;
 		} else {
 			form.mmsSubject.value = ""; //초기화
@@ -3320,7 +2589,7 @@
 		form.eachPrice.value = '<c:out value="${longPrice}" />';
 		
 		//제목 사용한 경우
-		if($("input[name=title_status]:checked").val() == 'Y') {
+		if($("input[name=subjectChkYn]:checked").val() == 'Y') {
 			form.mmsSubject.value = msgForm.mmsSubject.value;
 		} else {
 			form.mmsSubject.value = ""; //초기화
@@ -3365,11 +2634,13 @@
 	var callFrom = $("#callFromList option:selected").val();
 	
 	var advStr = '<div class="ad_txt"><p>(선거운동정보)</p></div>';
-	var advDenyStr = '<div class="deny_txt">후보자전화번호 ' + callFrom + '<br/>불법수집정보 신고번호 : 선거관리위원회 ☎1390<br/>무료거부 0808800858</div>';
-	
+	var advDenyStr = '<div class="deny_txt">불법수집정보신고 선거관리위원회 1390<br/>무료거부 0808800858</div>';
+	// var advDenyStr = '<div class="deny_txt">후보자전화번호 ' + callFrom + '<br/>불법수집정보 신고번호 : 선거관리위원회 ☎1390<br/>무료거부 0808800858</div>';
+
 	var preAdvStr = '<p class="ad_tit">(선거운동정보)</p>';
-	var preAdvDenyStr = '<p class="deny_receipt">후보자전화번호 ' + callFrom + '<br>불법수집정보 신고번호 : 선거관리위원회 ☎1390<br>무료거부 0808800858</p>';
-	
+	var preAdvDenyStr = '<p class="deny_receipt">불법수집정보신고 선거관리위원회 1390<br>무료거부 0808800858</p>';
+	// var preAdvDenyStr = '<p class="deny_receipt">후보자전화번호 ' + callFrom + '<br>불법수집정보 신고번호 : 선거관리위원회 ☎1390<br>무료거부 0808800858</p>';
+
 	//광고 및 무료수신거부 텍스트 추가
 	if (!advMsgSts){//선거문자 필수문구 추가해주기
 
@@ -3456,11 +2727,63 @@
 }
 
 </script>
+<input type="hidden" id="tmpJobId" value="${jobVO.tmpJobId}" /> <%-- 수신자 목록 진행 JOB ID--%>
+<%--<input type="hidden" id="jobStatus" value="${jobVO.jobStatus}" /> &lt;%&ndash; 진행상태 - P:저장중, C:저장완료, D:삭제 &ndash;%&gt;--%>
+
 
 	<div class="loading_layer">
 		<div class="loading_container">
 			<div class="bar"></div>
 			<div class="text">Loading</div>
+		</div>
+	</div>
+
+
+	<!-- [기업회원일 경우]선거문자 이용안내 data-tooltip:alert_layer_popup -->
+	<div class="tooltip-wrap">
+		<div class="popup-com alert_layer_popup alert_layer_popup02" tabindex="0" data-tooltip-con="alert_layer_popup02" data-focus="alert_layer_popup" data-focus-prev="alert_layer_popup02-close" style="width: 450px;">
+			<div class="popup_heading">
+				<!-- 기업회원일 경우 -->
+				<p>선거문자 이용안내</p>
+				<button type="button" class="tooltip-close" data-focus="alert_layer_popup02-close" onclick="location.href='/web/main/mainPage.do'"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+			</div>
+
+			<div class="layer_in">
+				<p>선거문자 발송은 개인회원이 후보자 등록 후 <br />이용 가능합니다.</p>
+				<div class="btn_wrap popup">
+					<button type="button" class="btnType fill_blue tooltip-close" onclick="location.href='/web/main/mainPage.do'">메인화면 바로가기</button>
+				</div>
+			</div>
+
+		</div>
+	</div>
+
+	<!-- [개인회원일 경우]선거문자 이용안내 data-tooltip:alert_layer_popup -->
+	<div class="tooltip-wrap">
+		<div class="popup-com alert_layer_popup" tabindex="0" data-tooltip-con="alert_layer_popup" data-focus="alert_layer_popup" data-focus-prev="alert_layer_popup-close" style="width: 450px;display:none;opacity: 1;left: 50%;top: 50%;transform: translate(-50%, -50%);">
+			<div class="popup_heading">
+				<p>선거문자 이용안내</p>
+				<button type="button" class="tooltip-close" data-focus="alert_layer_popup-close" onclick="location.href='/web/main/mainPage.do'"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+			</div>
+
+			<div class="layer_in">
+				<p>선거문자 발송은 후보자 등록 후 이용 가능합니다. <br />등록을 먼저 진행해주세요.</p>
+				<div class="btn_wrap popup">
+					<button type="button" class="btnType fill_blue tooltip-close" data-tooltip="candidate_popup01">확인</button>
+					<button type="button" class="btnType fill_gray tooltip-close" onclick="location.href='/web/main/mainPage.do'">닫기</button>
+				</div>
+			</div>
+
+		</div>
+	</div>
+	<div class="progress_bar_wrap">
+		<div class="progress_box">
+			<p class="time_text">0%</p>
+			<div class="bar">
+				<span class="change_bar"></span>
+			</div>
+		</div>
+		<div class="btn_wrap">
 		</div>
 	</div>
 
@@ -3502,7 +2825,7 @@
 	<div class="tooltip-wrap">
 		<div class="popup-com import_layer popup05" tabindex="0" data-tooltip-con="popup05" data-focus="popup05" data-focus-prev="popup05-close" style="width: 900px;">
 			<div class="popup_heading">
-				<p><span>전송내역</p>
+				<p><span>전송내역</span></p>
 				<button type="button" class="tooltip-close" data-focus="popup05-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
 			</div>
 			<div class="layer_in" id="mjMsgSentListAllLoad" style="padding-bottom: 0px; min-height:428px;">
@@ -3513,134 +2836,136 @@
 		</div>
 	</div>
 	<!--// 2023 10 16  재전송 팝업 -->
-	
+
 	<!-- 후보자등록 팝업 data-tooltip:candidate_popup01 -->
 	<div class="tooltip-wrap">
 		<div class="popup-com candidate_layer candidate_popup01" tabindex="0" data-tooltip-con="candidate_popup01" data-focus="candidate_popup01" data-focus-prev="candidate_popup01-close" style="width: 620px;">
 			<div class="popup_heading">
-				<p>후보자 등록</p>
-				<button type="button" class="tooltip-close" data-focus="candidate_popup01-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+				<c:choose>
+					<c:when test="${not empty mjonCandidateVO.candidateNm}">
+						<p>후보자 수정</p>
+						<button type="button" class="tooltip-close" data-focus="candidate_popup01-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+					</c:when>
+					<c:otherwise>
+						<p>후보자 등록</p>
+						<button type="button" class="tooltip-close" data-focus="candidate_popup01-close" onclick="location.href='/web/main/mainPage.do'"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+					</c:otherwise>
+				</c:choose>
 			</div>
-			
+
 			<form id="candiForm" name="candiForm" method="post">
 				<input type="hidden" id="dataType" name="dataType" value="Reg"/>
-			
+
 				<div class="layer_in">
-	                <p class="adr_pop_title">선거문자는 반드시 <span class="c_002c9a">후보자 등록</span>을 하셔야만 이용 가능합니다. <br/>입력하신 내용은 세금계산서 발행을 위한 정보로만 사용됩니다.</p>
+					<p class="adr_pop_title">선거문자는 반드시 <span class="c_002c9a">후보자 등록</span>을 하셔야만 이용 가능합니다. <br/>입력하신 내용은 세금계산서 발행을 위한 정보로만 사용됩니다.</p>
 					<div class="candidate_table">
-	                    <p>후보자</p>
-	                    <table>
-	                        <caption>후보자 등록을 위한 성명, 주민등록번호, 주소를 입력하는 표</caption>
-	                        <colgroup>
-	                            <col style="width: 125px;">
-	                            <col style="width: auto;">
-	                        </colgroup>
-	                        <tbody>
-	                            <tr>
-	                                <th scope="row">성명</th>
-	                                <td>
-	                                    <label for="candidateNm" class="label"></label>
-	                                    <input type="text" id="candidateNm" name="candidateNm" value="<c:out value='${mjonCandidateVO.candidateNm}'/>" placeholder="후보자 성명 입력" onfocus="this.placeholder=''" onblur="this.placeholder='후보자 성명 입력'" class="inputLight">
-	                                </td>
-	                            </tr>
-	                            <tr class="residentNum">
-	                                <th scope="row">주민등록번호</th>
-	                                <td>
-	                                    <label for="regidentNo1" class="label"></label>
-	                                    <input type="text" id="regidentNo1" name="regidentNo1" value="<c:out value='${mjonCandidateVO.regidentNo1}'/>" maxlength="6" placeholder="주민등록번호 앞 6자리" onfocus="this.placeholder=''" onblur="this.placeholder='주민등록번호 앞 6자리'" class="inputLight">
-	                                    <span>-</span>
-	                                    <label for="regidentNo2" class="label"></label>
-	                                    <input type="password" id="regidentNo2" name="regidentNo2" value="<c:out value='${mjonCandidateVO.regidentNo2}'/>" maxlength="7" placeholder="주민등록번호 뒤 7자리" onfocus="this.placeholder=''" onblur="this.placeholder='주민등록번호 뒤 7자리'" class="inputLight">
-	                                </td>
-	                            </tr>
-	                            <tr>
-	                                <th scope="row">주소</th>
-	                                <td>
-	                                    <label for="candidateAddr" class="label"></label>
-	                                    <input type="text" id="candidateAddr" name="candidateAddr" value="<c:out value='${mjonCandidateVO.candidateAddr}'/>">
-	                                </td>
-	                            </tr>
-	                        </tbody>
-	                    </table>
-	                </div>
-	                <div class="candidate_table" style="margin-top: 40px;">
-	                    <p>담당자</p>
-	                    <table>
-	                        <caption>후보자 등록을 위한 성명, 주민등록번호, 주소를 입력하는 표</caption>
-	                        <colgroup>
-	                            <col style="width: 125px;">
-	                            <col style="width: auto;">
-	                        </colgroup>
-	                        <tbody>
-	                            <tr>
-	                                <th scope="row">성명</th>
-	                                <td>
-	                                    <label for="managerNm" class="label"></label>
-	                                    <input type="text" id="managerNm" name="managerNm" value="<c:out value='${mjonCandidateVO.managerNm}'/>" placeholder="담당자 성명 입력" onfocus="this.placeholder=''" onblur="this.placeholder='담당자 성명 입력'" class="inputLight">
-	                                </td>
-	                            </tr>
-	                            <%-- <tr>
-	                                <th scope="row">직위</th>
-	                                <td>
-	                                    <label for="office" class="label"></label>
-	                                    <input type="text" id="office" name="office" value="<c:out value='${mjonCandidateVO.office}'/>" placeholder="직위 입력" onfocus="this.placeholder=''" onblur="this.placeholder='직위 입력'" class="inputLight">
-	                                </td>
-	                            </tr> --%>
-	                            <tr>
-	                                <th scope="row">휴대폰</th>
-	                                <td>
-	                                    <label for="phoneNo" class="label"></label>
-	                                    <input type="text" id="phoneNo" name="phoneNo" value="<c:out value='${mjonCandidateVO.phoneNo}'/>" placeholder="‘-’ 없이 숫자만 입력" onfocus="this.placeholder=''" onblur="this.placeholder='‘-’ 없이 숫자만 입력'" class="inputLight">
-	                                </td>
-	                            </tr>
-	                            <tr class="emailWrap3">
-	                                <th scope="row">이메일</th>
-	                                <td>
-	                                    <label for="email" class="label"></label>
-	                                    <input type="text" id="email" name="email" value="<c:out value='${mjonCandidateVO.email}'/>">
-	                                    <span>@</span>
-	                                    <label for="emailDomain" class="label"></label>
-	                                    <input type="text" id="emailDomain" name="emailDomain" value="<c:out value='${mjonCandidateVO.emailDomain}'/>">
-	                                    <label for="" class="label">이메일 선택</label>
-	                                    <select class="list_selType1" id="taxEmailSelect" onchange="emailChange(this)">
-	                                        <c:forEach var="result" items="${emailCode}" varStatus="status">
-												<c:if test="${status.index eq 0 }">
-													<option value="1">${result.codeNm}</option>
-												</c:if>
-												<c:if test="${status.index ne 0 }">
-													<option value="${result.codeDc}">${result.codeNm}</option>
-												</c:if>
-											</c:forEach>
-	                                    </select>
-	                                </td>
-	                            </tr>
-	                        </tbody>
-	                    </table>
-	                </div>
-	                <div class="popup_btn_wrap2">
-	                	<c:choose>
-	                		<c:when test="${not empty mjonCandidateVO.candidateNm}">
-			                    <button type="button" onclick="javascript:fnCandidateUpt('Upt'); return false;">수정</button>
-			                    <%-- <button type="button" onclick="javascript:fnCandidateDel(); return false;">삭제</button> --%>
-	                		</c:when>
-	                		<c:otherwise>
-	                			<button type="button" onclick="javascript:fnCandidateUpt('Reg'); return false;">등록</button>
-	                		</c:otherwise>
-	                	</c:choose>
-	                    <button type="button" class="tooltip-close" data-focus="candidate_popup01-close" data-focus-next="candidate_popup01">닫기</button>                      
-	                </div>
+						<p>후보자</p>
+						<table>
+							<caption>후보자 등록을 위한 성명, 주민등록번호, 주소를 입력하는 표</caption>
+							<colgroup>
+								<col style="width: 125px;">
+								<col style="width: auto;">
+							</colgroup>
+							<tbody>
+							<tr>
+								<th scope="row">성명</th>
+								<td>
+									<label for="candidateNm" class="label"></label>
+									<input type="text" id="candidateNm" name="candidateNm" value="<c:out value='${mjonCandidateVO.candidateNm}'/>" placeholder="후보자 성명 입력" onfocus="this.placeholder=''" onblur="this.placeholder='후보자 성명 입력'" class="inputLight">
+								</td>
+							</tr>
+							<tr class="residentNum">
+								<th scope="row">주민등록번호</th>
+								<td>
+									<label for="regidentNo1" class="label"></label>
+									<input type="text" id="regidentNo1" name="regidentNo1" value="<c:out value='${mjonCandidateVO.regidentNo1}'/>" maxlength="6" placeholder="주민등록번호 앞 6자리" onfocus="this.placeholder=''" onblur="this.placeholder='주민등록번호 앞 6자리'" class="inputLight">
+									<span>-</span>
+									<label for="regidentNo2" class="label"></label>
+									<input type="password" id="regidentNo2" name="regidentNo2" value="<c:out value='${mjonCandidateVO.regidentNo2}'/>" maxlength="7" placeholder="주민등록번호 뒤 7자리" onfocus="this.placeholder=''" onblur="this.placeholder='주민등록번호 뒤 7자리'" class="inputLight">
+								</td>
+							</tr>
+							<tr>
+								<th scope="row">주소</th>
+								<td>
+									<label for="candidateAddr" class="label"></label>
+									<input type="text" id="candidateAddr" name="candidateAddr" value="<c:out value='${mjonCandidateVO.candidateAddr}'/>">
+								</td>
+							</tr>
+							</tbody>
+						</table>
+					</div>
+					<div class="candidate_table" style="margin-top: 40px;">
+						<p>담당자</p>
+						<table>
+							<caption>후보자 등록을 위한 성명, 주민등록번호, 주소를 입력하는 표</caption>
+							<colgroup>
+								<col style="width: 125px;">
+								<col style="width: auto;">
+							</colgroup>
+							<tbody>
+							<tr>
+								<th scope="row">성명</th>
+								<td>
+									<label for="managerNm" class="label"></label>
+									<input type="text" id="managerNm" name="managerNm" value="<c:out value='${mjonCandidateVO.managerNm}'/>" placeholder="담당자 성명 입력" onfocus="this.placeholder=''" onblur="this.placeholder='담당자 성명 입력'" class="inputLight">
+								</td>
+							</tr>
+							<tr>
+								<th scope="row">휴대폰</th>
+								<td>
+									<label for="phoneNo" class="label"></label>
+									<input type="text" id="phoneNo" name="phoneNo" value="<c:out value='${mjonCandidateVO.phoneNo}'/>" placeholder="‘-’ 없이 숫자만 입력" onfocus="this.placeholder=''" onblur="this.placeholder='‘-’ 없이 숫자만 입력'" class="inputLight">
+								</td>
+							</tr>
+							<tr class="emailWrap3">
+								<th scope="row">이메일</th>
+								<td>
+									<label for="email" class="label"></label>
+									<input type="text" id="email" name="email" value="<c:out value='${mjonCandidateVO.email}'/>">
+									<span>@</span>
+									<label for="emailDomain" class="label"></label>
+									<input type="text" id="emailDomain" name="emailDomain" value="<c:out value='${mjonCandidateVO.emailDomain}'/>">
+									<label for="" class="label">이메일 선택</label>
+									<select class="list_selType1" id="taxEmailSelect" onchange="emailChange(this)">
+										<c:forEach var="result" items="${emailCode}" varStatus="status">
+											<c:if test="${status.index eq 0 }">
+												<option value="1">${result.codeNm}</option>
+											</c:if>
+											<c:if test="${status.index ne 0 }">
+												<option value="${result.codeDc}">${result.codeNm}</option>
+											</c:if>
+										</c:forEach>
+									</select>
+								</td>
+							</tr>
+							</tbody>
+						</table>
+					</div>
+					<div class="popup_btn_wrap2">
+						<c:choose>
+							<c:when test="${not empty mjonCandidateVO.candidateNm}">
+								<button type="button" onclick="javascript:fnCandidateUpt('Upt'); return false;">수정</button>
+								<button type="button" class="tooltip-close" data-focus="candidate_popup01-close" data-focus-next="candidate_popup01">닫기</button>
+							</c:when>
+							<c:otherwise>
+								<button type="button" onclick="javascript:fnCandidateUpt('Reg'); return false;">등록</button>
+								<button type="button" class="tooltip-close" data-focus="candidate_popup01-close" data-focus-next="candidate_popup01" onclick="location.href='/web/main/mainPage.do'">닫기</button>
+							</c:otherwise>
+						</c:choose>
+					</div>
 				</div>
-				
-			 	<!-- Workaround to avoid corrupted XHR2 request body in IE10 / IE11 -->
-			 	<input type="hidden" name="_dontcare">				
+
+				<!-- Workaround to avoid corrupted XHR2 request body in IE10 / IE11 -->
+				<input type="hidden" name="_dontcare">
 			</form>
 		</div>
-	</div><!--// 후보자등록 팝업 -->
+	</div>
+	<!--// 후보자등록 팝업 -->
 	
 	<div class="tooltip-wrap">
 		<div class="popup-com history_layer popup03" tabindex="0" data-tooltip-con="popup03" data-focus="popup03" data-focus-prev="popup03-close">
 			<div class="popup_heading">
-				<p><span>전송내역</p>
+				<p><span>전송내역</span></p>
 				<button type="button" class="tooltip-close" data-focus="popup03-close" id="btnLatestAddPhoneClose"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
 			</div>
 			<div class="layer_in">
@@ -3713,7 +3038,10 @@
 	<!-- 엑셀 불러오기 -->
 	<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-com import_layer popup02" tabindex="0" data-tooltip-con="popup02" data-focus="popup02" data-focus-prev="popup02-close" style="width: 750px;">
+				<%@include file="/WEB-INF/jsp/web/msgcampain/tw/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>
@@ -3726,7 +3054,7 @@
 							<p>- [엑셀 불러오기]시 문서의 A열을 불러옵니다.(지원하는 파일 형식 : xls, xlsx)</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> --%>
+							&lt;%&ndash; <button type="button" class="excel_btn" onclick="location.href='/cmm/fms/FileDown.do?atchFileId=FILE_000000000011651&fileSn=1'"><i></i>샘플파일 다운로드</button> &ndash;%&gt;
 							<button type="button" class="excel_btn" onclick="location.href='/download/msg/선거문자_엑셀연락처_등록양식.xlsx'"><i class="downroad"></i>샘플파일 다운로드</button>
 						</div>
 						<div class="attachedFile">
@@ -3742,14 +3070,14 @@
 						<button type="button" class="tooltip-close" data-focus="popup02-close"  data-focus-next="popup02">닫기</button>                      
 					</div>
 				</div>
-			</div>
+			--%></div>
 		</div><!--// 엑셀 불러오기 -->
 	</form>
 	<!-- 주소록 불러오기 -->
 	<div class="tooltip-wrap">
-		<div class="popup-com import_layer popup06" tabindex="0" data-tooltip-con="popup06" data-focus="popup06" data-focus-prev="popup06-close" style="width: 1000px">
+		<div class="popup-com import_layer popup06 adr_call_popup" tabindex="0" data-tooltip-con="popup06" data-focus="popup06" data-focus-prev="popup06-close" style="width: 1000px">
 			<div class="popup_heading">
-				<p><span>주소록 불러오기</p>
+				<p><span>주소록 불러오기</span></p>
 				<button type="button" onClick="javascript:addrClose(); return false;">
 				<img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
 			</div>
@@ -3798,7 +3126,9 @@
 								<!--// table -->
 							</div>
 							<div class="popup_btn_wrap2">
-								<button type="button" onClick="javascript:addrToList(); return false;">추가</button>
+								<button type="button" onClick="javascript:addrToList_advc('all'); return false;">전체추가</button>
+								<button type="button" onClick="javascript:addrToList_advc('select'); return false;">선택추가</button>
+<%--								<button type="button" onClick="javascript:addrToList(); return false;">추가</button>--%>
 								<button type="button" onClick="javascript:addrClose(); return false;">닫기</button>
 							</div>
 							<%-- 주소록 레이어 팝업 닫기 실행 코드 --%>
@@ -3861,126 +3191,113 @@
 		    	</ul>
 				<!-- 이용방법/혜택 -->
 				<div class="cdpop_cont current" id="listTab2_1">
-					<div class="con">
-						<p class="cdpop_title">
-							<i class="tw_title01_icon"></i>20건 문자 이용절차
-							<!--
-							<span class="customReq">
-								<button type="button" onclick="goToCustom();"><i></i>선거문자 맞춤제작</button>
-							</span>
-							-->
-						</p>
-						<ul class="cdpop_info">
-							<li>
-								<i class="info_step1"></i>
-								<div>
-									<p>회원가입</p>
-								</div>
-							</li>
-							<li>
-								<i class="info_step2"></i>
-								<div>
-									<p>후보자등록</p>
-								</div>
-							</li>
-							<li>
-								<i class="info_step3"></i>
-								<div>
-									<p>전용계좌</p>
-								</div>
-							</li>
-							<li>
-								<i class="info_step4"></i>
-								<div>
-									<p>발신번호 인증</p>
-								</div>
-							</li>
-							<li>
-								<i class="info_step5"></i>
-								<div>
-									<p>문자전송</p>
-								</div>
-							</li>
-							<li>
-								<i class="info_step6"></i>
-								<div>
-									<p>세금계산서</p>
-								</div>
-							</li>
+				<div class="con">
+					<p class="cdpop_title">
+						<i class="tw_title01_icon"></i>20건 문자 이용절차
+						<!--
+						<span class="customReq">
+							<button type="button" onclick="goToCustom();"><i></i>선거문자 맞춤제작</button>
+						</span>
+						-->
+					</p>
+					<ul class="cdpop_info">
+						<li>
+							<i class="info_step1"></i>
+							<div>
+								<p>회원가입</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step2"></i>
+							<div>
+								<p>후보자등록</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step3"></i>
+							<div>
+								<p>전용계좌</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step4"></i>
+							<div>
+								<p>발신번호 인증</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step5"></i>
+							<div>
+								<p>문자전송</p>
+							</div>
+						</li>
+						<li>
+							<i class="info_step6"></i>
+							<div>
+								<p>세금계산서</p>
+							</div>
+						</li>
+					</ul>
+				</div>
+				<div class="con">
+					<p class="cdpop_title tw_title"><i class="tw_title02_icon"></i>후보자 등록 방법</p>
+					<div class="tw_con">
+						<ul>
+							<li>- 선거관리위원회에 등록된 후보자 정보와 세금계산서 담당자 정보를 입력합니다.</li>
+							<li class="sub_te">세금계산서 발행을 위한 정보로만 사용됩니다.</li>
 						</ul>
-					</div>
-					<div class="con">
-						<p class="cdpop_title tw_title"><i class="tw_title02_icon"></i>후보자 등록 방법</p>
-						<div class="tw_con">
-							<ul>
-								<li>- 선거관리위원회에 등록된 후보자 정보와 세금계산서 담당자 정보를 입력합니다.</li>
-								<li class="sub_te">세금계산서 발행을 위한 정보로만 사용됩니다.</li>
-							</ul>
-							<img src="/publish/images/popup/tw_popup/tw_con_01.jpg" alt="받는 사람 목록 불러오기">
-						</div>
-					</div>
-					<div class="con">
-						<p class="cdpop_title tw_title"><i class="tw_title03_icon"></i>받는 사람 목록 불러오기</p>
-						<div class="tw_con">
-							<ul>
-								<li>- 주소록 관리 메뉴에서 등록한 주소록을 불러오거나 PC에 저장된 엑셀 파일을 불러올 수 있습니다.</li>
-								<li>- 주소록 불러오기
-									<ul class="sub_li">
-										<li>① 그룹을 선택합니다.</li>
-										<li>② 체크박스 개별 또는 전체 선택을 통해 받는 사람 목록을 선택합니다.</li>
-										<li>③ 추가 버튼을 클릭합니다.</li>
-									</ul>
-								</li>
-								<li class="li_02">- 엑셀 불러오기
-									<ul class="sub_li">
-										<li>① 찾아보기를 클릭하여 불러올 엑셀 파일을 선택합니다.</li>
-										<li>② 추가 버튼을 클릭합니다.</li>
-									</ul>
-								</li>
-							</ul>
-							<img src="/publish/images/popup/tw_popup/tw_con_02.jpg" alt="받는 사람 목록 불러오기 1">
-							<ul>
-								<li class="te">- 받는 사람 목록 선택이 완료되면 20건 씩 받는 사람을 선택할 수 있도록 화면에 표시되며, 불러온 받는 사람 목록 전체에 대한 전체 받는사람 수, 전송완료 수, 잔여 받는사람 수를 확인할 수 있습니다.</li>
-								<li class="sub_te">불러온 받는 사람 목록은 재접속, 재로그인 시에도 유지되오니 목록을 삭제하고 싶은 경우에는<br>초기화 버튼을 눌러주세요.</li>
-							</ul>
-							<img src="/publish/images/popup/tw_popup/tw_con_03.jpg" alt="받는 사람 목록 불러오기 2">
-						</div>
-					</div>
-					<div class="con">
-						<p class="cdpop_title tw_title"><i class="tw_title04_icon"></i>20명 수동 선택 후 발송하기</p>
-						<div class="tw_con">
-							<ul>
-								<li>- 수동 선택 방법 (4가지 방법 가능)
-									<ul class="sub_li">
-										<li>① 체크박스를 하나씩 차례로 선택</li>
-										<li>② 받는 사람 목록 전화번호 위에서 마우스 왼쪽을 길게 누르고 드래그하여 영역 선택</li>
-										<li>③ 1명씩 선택 버튼을 계속 누르고 있으면 20명이 모두 선택</li>
-										<li>④ 전체버튼을 누르면 20명이 한번에 선택</li>
-									</ul>
-								</li>
-								<li class="te" style="margin-top: 10px;">
-									- 발송하기 버튼을 클릭하면 선택한 20건 문자가 발송되고 받는 사람 목록에 있는 다음 20건이 자동으로 화면에 표시됩니다.
-								</li>
-							</ul>
-							<img src="/publish/images/popup/tw_popup/tw_con_04.jpg" alt="20명 수동 선택 후 발송하기">
-						</div>
-					</div>
-					<div class="con">
-						<p class="cdpop_title tw_title"><i class="tw_title05_icon"></i>예약문자 발송하기</p>
-						<div class="tw_con">
-							<ul>
-								<li class="te">- 선택한 20건 문자의 발송이 예약되고, 받는 사람 목록에 있는 다음 20건이 자동으로 화면에 표시됩니다.
-									<ul class="sub_li" style="margin-top: 5px;">
-										<li>① 예약 라디오 버튼을 클릭합니다.</li>
-										<li>② 예약일자 및 시간을 선택합니다.</li>
-										<li>③ 예약하기 버튼을 클릭합니다.</li>
-									</ul>
-								</li>
-							</ul>
-							<img src="/publish/images/popup/tw_popup/tw_con_05.jpg" alt="예약문자 발송하기" style="margin-bottom: 0;">
-						</div>
+						<img src="/publish/images/popup/tw_popup/tw_con_01.jpg" alt="후보자 등록">
 					</div>
 				</div>
+				<div class="con">
+					<p class="cdpop_title tw_title"><i class="tw_title03_icon"></i>받는 사람 목록 불러오기</p>
+					<div class="tw_con">
+						<ul>
+							<li>- 등록한 주소록을 불러오거나 PC에 저장된 엑셀 파일을 불러올 수 있습니다.</li>
+							<li>- 주소록 불러오기
+								<ul class="sub_li">
+									<li>① 그룹을 선택합니다.</li>
+									<li>② 추가 버튼을 클릭합니다.</li>
+								</ul>
+							</li>
+							<li class="li_02">- 엑셀 불러오기
+								<ul class="sub_li">
+									<li>① 엑셀, TXT파일 업로드 버튼을 클릭합니다.</li>
+									<li>② 불러올 엑셀 파일을 선택합니다.</li>
+									<li>③ “선택하기”를 클릭하여 이름과 휴대폰을 지정합니다.</li>
+									<li>④ 추가 버튼을 클릭합니다.</li>
+								</ul>
+							</li>
+						</ul>
+						<img src="/publish/images/popup/tw_popup/tw_con_02.jpg" alt="받는 사람 목록 불러오기 1">
+						<ul>
+							<li class="te">- 받는사람 명단 등록 이후 20건씩 선택할 수 있도록 화면에 표시되며, 불러온 명단에 대한 전체 받는사람, 발송완료, 발송제외, 잔여 받는사람 수를 확인할 수 있습니다.</li>
+							<li class="sub_te">불러온 받는사람 목록은 재접속, 재로그인 시에도 유지되오니 목록을 삭제하고싶은 경우에는 초기화 버튼을 눌러주세요</li>
+						</ul>
+						<img src="/publish/images/popup/tw_popup/tw_con_03.jpg" alt="받는 사람 목록 불러오기 2">
+					</div>
+				</div>
+				<div class="con">
+					<p class="cdpop_title tw_title"><i class="tw_title04_icon"></i>20명 수동 선택 후 발송하기</p>
+					<div class="tw_con">
+						<ul>
+							<li>- 수동 선택 방법 (3가지 방법 가능)
+								<ul class="sub_li">
+									<li>① 체크박스를 하나씩 선택</li>
+									<li>② 받는사람 목록 전화번호 위에서 마우스를 드래그하여 영역 선택</li>
+									<li>③ 1명씩 선택 버튼을 계속 누르고 있으면 받는사람 연속 선택</li>
+								</ul>
+							</li>
+							<li class="te li_02" style="text-indent:-13px;margin:10px 0 0 13px;">- 발송하기 버튼을 클릭하면 선택한 문자가 발송되고 20건 문자 발송 시, 받는사람 목록에 있는 다음 20건이 자동으로 화면에 표시됩니다.
+								<ul class="sub_li">
+									<li>(다음페이지 자동넘김 선택 시)</li>
+								</ul>
+							</li>
+						</ul>
+						<img src="/publish/images/popup/tw_popup/tw_con_04.jpg" alt="20명 수동 선택 후 발송하기">
+					</div>
+				</div>
+			</div>
 				<!--// 이용방법/혜택 -->
 			</div>
 			<div class="popup_btn_wrap2" style="margin: 0 auto 30px auto;">
@@ -4044,13 +3361,21 @@
 		<input type="hidden" id="pageIndex" name="pageIndex" value="1" />
 	</form>
     <form id="msgForm" name="msgForm" method="post">
+
+		<input type="hidden" id="candidateNmChk" value="<c:out value="${mjonCandidateVO.candidateNm}"/>" /><!-- 선거 후보자 이름 있는지 호가인 -->
+		<input type="hidden" id="deptChk" value="<c:out value="${mberManageVO.dept}"/>" /><!-- 선거 후보자 이름 있는지 호가인 -->
     	<input type="hidden" id="send_adYn" name="send_adYn" value="N"/><!-- 문자종류 선거문자 여부 값 -->
     	<input type="hidden" id="divideChk" name="divideChk" value="N"/><!-- 예약문자 분할발송 여부 값 -->
     	<input type="hidden" id="divideCnt" name="divideCnt" value="20"/><!-- 예약문자 분할발송 분할갯수 값 -->
     	<input type="hidden" id="divideTime" name="divideTime" value="01"/><!-- 예약문자 분할발송 분할 간격 값 -->
+
 		<input type="hidden" id="msgType" name="msgType" value="4" /><!-- 문자 종류 : 단문 - 4, 장문/그림 - 6 -->
 		<input type="hidden" id="imgFilePath" name="imgFilePath" value="" /><!-- 선택 이미지 파일 경로 정보 , 로 구분 최대 3장까지 -->
+		<input type="hidden" id="imgFileIdAdvc" name="imgFileIdAdvc" value="" /><!-- 선택 이미지 파일 아이디 정보 , 로 구분 최대 3장까지 -->
 		<input type="hidden" id="imgFileId" name="imgFileId" value="" /><!-- 선택 이미지 파일 아이디 정보 , 로 구분 최대 3장까지 -->
+		<input type="hidden" id="imgFilePathAdvc" name="imgFilePathAdvc" value="" /><!-- 선택 이미지 파일 경로 정보 , 로 구분 최대 3장까지 -->
+
+
 		<input type="hidden" id="fileCnt" name="fileCnt" value="0" /><!-- 첨부파일 추가 갯수 -->
 		<input type="hidden" id="callToList" name="callToList" value=""/><!-- 수신자 전화번호 리스트 -->
 		<input type="hidden" id="callFrom" name="callFrom" value=""/> <!-- 발신자 전화번호 -->
@@ -4067,6 +3392,7 @@
 		<input type="hidden" id="rep3List" name="rep3List" value=""/><!-- 문자발송 문자 치환3 리스트 -->
 		<input type="hidden" id="rep4List" name="rep4List" value=""/><!-- 문자발송 문자 치환4 리스트 -->
 		<input type="hidden" name="templateYn" />
+		<input type="hidden" name="templateYnAdvc" />
 		<input type="hidden" id="sPrice" name="sPrice" value="<c:out value="${shortPrice}"/>"/><!-- 단문문자 단가 -->
 		<input type="hidden" id="mPrice" name="mPrice" value="<c:out value="${longPrice}"/>"/><!-- 장문문자 단가 -->
 		<input type="hidden" id="pPrice" name="pPrice" value="<c:out value="${picturePrice}"/>"/><!-- 그림문자 단가 -->
@@ -4105,42 +3431,18 @@
 		
 	<!-- <div class="top_content current" id="tab1_1"> -->
 	    <div class="heading">
-	        <h2>20건 문자(수동문자) 전송</h2>
-	        <div class="election_btnWrap">
-	        	<button type="button" class="button2 info" onclick="infoPop('selectMsgDataView2');">발송규정</button>
-	        	<button type="button" class="button2 info" data-tooltip="candidate_popup03">사용안내</button>
-	        	<c:choose>
-	        		<c:when test="${empty LoginVO}">
-						<button type="button" class="btnType" onclick="javascript:fn_candidateLoginChk(); return false;"><i class="election_btn1"></i>후보자 등록</button>	        		
-	        		</c:when>
-	        		<c:when test="${not empty mberManageVO && mberManageVO.dept eq 'c'}">
-	        			<button type="button" class="btnType" onclick="javascript:fn_mberDeptChk(); return false;"><i class="election_btn1"></i>후보자 등록</button>
-	        		</c:when>
-	        		<c:otherwise>
-	        			<button type="button" class="btnType" data-tooltip="candidate_popup01"><i class="election_btn1"></i>후보자 등록</button>	
-	        		</c:otherwise>
-	        	</c:choose>
-                <button type="button" class="btnType" onclick="location.href='/web/member/pay/BillPub.do'"><i class="election_btn2"></i>세금계산서</button>
-                <button type="button" class="btnType" onclick="location.href='/web/mjon/msgsent/selectMsgSentView.do'"><i class="election_btn3"></i>발송결과 출력하기</button>
-            </div>
+	        <h2>선거-20건 수동문자</h2>
+			<div class="election_btnWrap">
+				<button type="button" class="button2 info" onclick="infoPop('selectMsgDataView2');">발송규정</button>
+				<button type="button" class="button2 info" data-tooltip="candidate_popup03">사용안내</button>
+				<button type="button" class="btnType" data-tooltip="candidate_popup01"><i class="election_btn1"></i>후보자 등록</button>
+				<button type="button" id="autoElectionBtn" class="btnType" data-tooltip="alert_layer_popup" style="display:none;" />
+				<button type="button" id="autoElectionBtn" class="btnType" data-tooltip="alert_layer_popup02" style="display:none;" />
+			</div>
 	    </div>
-	    <%-- <div class="titBox">
-            <p>- 90byte 초과 시, 장문으로 전환됩니다. 장문 문자는 최대 2,000byte까지 작성할 수  있습니다.</p>
-			<p>- 그림문자 1건에 포토 최대 3장 첨부가능  [권장 사이즈 : <span class="c_222 fwRg">640 x 960</span>픽셀 / 최대용량 : <span class="c_222 fwRg">10MB</span>이내]</p>
-            <p>- 광고성 메시지는 반드시 유의사항 확인 후 발송해 주시기 바랍니다. <span><a href="#" data-tooltip="candidate_popup02">[선거문자 관련규정 안내]</a></span></p>
-        </div> --%>
 	    <div class="send_general">
-	        <div class="send_left">
-	        	<%-- <dl class="myprice_view">
-	        		<dt>나의 요금제</dt>
-	        		<dd>
-	        			<ul>
-							<li><span class="type">단문</span><span class="price"><c:out value="${shortPrice}"/></span>원</li>
-							<li><span class="type">장문</span><span class="price"><c:out value="${longPrice}"/></span>원</li>
-							<li><span class="type">그림</span><span class="price"><c:out value="${picturePrice}"/></span>원 <span class="count">(2장 : <c:out value="${picture2Price}"/>원 / 3장 : <c:out value="${picture3Price}"/>원)</span></li>
-						</ul>
-	        		</dd>
-	        	</dl> --%>
+	        <div class="send_left send_20">
+
 	            <table class="tType1">
 	                <caption>일반 문자보내기 분류 번호 내용 등을 입력하는 표</caption>
 	                <colgroup>
@@ -4148,13 +3450,6 @@
 	                    <col style="width: auto;">
 	                </colgroup>
 	                <tbody>
-	                    <!-- <tr>
-	                        <th scope="row">문자분류</th>
-	                        <td class="send_cf">
-	                            <input id="send_adYnY" type="radio" name="send_adYn" value="Y" checked="checked">
-	                            <label for="send_adYnY">선거</label>
-	                        </td>
-	                    </tr> -->
 	                    <tr>
                             <th scope="row">발신번호</th>
                             <td class="put_num">
@@ -4179,9 +3474,9 @@
                             <td>
                            		<ul class="title_wrap">
                            			<li>
-                           				<input id="title_y" type="radio"name="title_status" value="Y" onchange="titleStatus(this);">
+                           				<input id="title_y" type="radio" name="subjectChkYn" value="Y" onchange="titleStatus(this);">
 			                            <label for="title_y">사용</label>
-			                            <input id="title_n" type="radio" name="title_status" value="N" onchange="titleStatus(this);" checked="checked">
+			                            <input id="title_n" type="radio" name="subjectChkYn" value="N" onchange="titleStatus(this);" checked="checked">
 			                            <label for="title_n">사용안함</label>
                            			</li>
                            			<li class="textbox">
@@ -4216,86 +3511,23 @@
                                     </div>
                                     <div class="put_right">
                                         <div class="btn_popup_wrap spc_wrap">
-                                        	<button type="button" class="btnType btnType7" onclick="miniPopup(this);">특수문자</button>
-											<div class="send_miniPop spc_character">
-												<div class="tab_character">
-													<a href="#none" class="on">특수문자</a>
-													<a href="#none">웃음</a>
-													<a href="#none">슬픔</a>
-													<a href="#none">분노</a>
-													<a href="#none">사랑</a>
-													<a href="#none">그외</a>
-												</div>
-												<!-- 특수문자 부분 -->
-												<div class="cnt_character on">
-													<div class="box_character">
-														<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
-															<c:if test="${symbolList.symbolType == 'D'}">
-																<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}"><c:out value="${symbolList.symbol}"/></a>
-															</c:if>
-														</c:forEach>
-													</div>
-												</div>
-												<!-- 웃음 -->
-												<div class="cnt_character emt_character">
-													<div class="box_character">
-														<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
-															<c:if test="${symbolList.symbolType == 'S'}">
-																<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
-															</c:if>
-														</c:forEach>
-													</div>
-												</div>
-												<!-- //웃음 -->
-												<!-- 슬픔 -->
-												<div class="cnt_character emt_character">
-													<div class="box_character">
-														<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
-															<c:if test="${symbolList.symbolType == 'C'}">
-																<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
-															</c:if>
-														</c:forEach>
-													</div>
-												</div>
-												<!-- //슬픔 -->
-												<!-- 분노 -->
-												<div class="cnt_character emt_character">
-													<div class="box_character">
-														<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
-															<c:if test="${symbolList.symbolType == 'A'}">
-																<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
-															</c:if>
-														</c:forEach>
-													</div>
-												</div>
-												<!-- //분노 -->
-												<!-- 사랑 -->
-												<div class="cnt_character emt_character">
-													<div class="box_character">
-														<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
-															<c:if test="${symbolList.symbolType == 'L'}">
-																<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
-															</c:if>
-														</c:forEach>
-													</div>
-												</div>
-												<!-- //사랑 -->
-												<!-- 그외 -->
-												<div class="cnt_character emt_character emt_etc ">
-													<div class="box_character">
-														<c:forEach var="symbolList" items="${symbolList}" varStatus="status">
-															<c:if test="${symbolList.symbolType == 'E'}">
-																<a href="javascript:void(0)" class="symbolButton" value="${symbolList.symbol}">${symbolList.symbol}</a>
-															</c:if>
-														</c:forEach>
-													</div>
-												</div>
-												<!-- //그외 -->
-												<button type="button" class="btn_close" onclick="miniPopup(this);">닫기</button>
-											</div>
+											<%--특수문자--%>
+											<jsp:include page="/WEB-INF/jsp/web/com/include/specialCharacterPopup.jsp" />
 										</div>
+
+										<div class="btn_wrap btn_02">
+											<button type="button" class="btnType btnType7" id="changeWord" onclick="miniPopup(this)">[*이름*]</button>
+											<!-- <button type="button" class="btnType btnType7" onclick="miniPopup(this)">선거문구</button> -->
+											<label for="btnSendAd" class="election_button btnType btnType7">
+												<input type="checkbox" id="btnSendAd" onclick="advMsgInsert();"/>선거문구
+<%--												<button type="button" class="btnType btnType7" id="btnSendAd" onclick="advMsgInsert();">선거필수문구입력</button>--%>
+											</label>
+										</div>
+
 										<div class="btn_popup_wrap convers_wrap">
-											<button type="button" class="btnType btnType7" id="btnSendAd" onclick="advMsgInsert();">선거필수문구입력</button>
+
+
+
 									        <!-- <button type="button" class="btnType btnType7" onclick="miniPopup(this)">특정문구 일괄변환<i class="qmMark"></i></button>
 											<div class="send_miniPop convers">
 												<div>
@@ -4329,78 +3561,100 @@
                             <th scope="row" class="vTop">받는사람</th>
                             <td class="putText">
                                 <div class="clearfix receipt_num">
-									<div class="receipt_num_top">
+									<%--<div class="receipt_num_top">
 										<label for="callTo" class="label">받는 번호입력</label>
 										<input type="text" id="callTo" name="callTo"  placeholder="번호를 입력하세요" oninput="this.value = this.value.replace(/[^0-9.]/g, '').replace(/(\..*)\./g, '$1');" onfocus="this.placeholder=''" onblur="this.placeholder='번호를 입력하세요'" style="width:340px;">
 										<button type="button" class="btnType btnType6 addCallToF">번호추가</button>
 										<span><span class="vMiddle">*</span> 중복번호는 한번만 발송됩니다.</span>
-									</div>
-                                    <div class="receipt_num_midde receipt_number_table_wrap">
+									</div>--%>
+                                    <div class="receipt_num_midde receipt_number_table_wrap table_20">
 	                                    <%-- 받는 사람 리스트 박스 시작 --%>
 	                                    <div class="put_left" id="twCallToList">
-											<div class="listType list">
-												<ul class="thead_ul table_ul">
-													<li><!-- <div class="input_wrap"><input type="checkbox" id="checkAll" name="receipt_number_check"></div> --></li>
-													<li>
-														번호
-														<!-- <button type="button" class="btn_sort_up"><img src="/publish/images/sortUp.png"></button>
-														<button type="button" class="btn_sort_down"><img src="/publish/images/sortDown.png"></button> -->
-													</li>
-													<li></li>
-													<li>번호
-														<!-- <button type="button" class="btn_sort_up"><img src="/publish/images/sortUp.png"></button>
-														<button type="button" class="btn_sort_down"><img src="/publish/images/sortDown.png"></button> -->
-													</li>
-												</ul>
-												<!-- <ul class="tbody_ul table_ul">
-												</ul> -->
-											</div>
-											<div class="list_bottom">
-												<ul class="pagination">
-													<%-- <ui:pagination paginationInfo = "${paginationInfo}"  type="imageWeb" jsFunction="fnCallToListPaging" /> --%>
-													<li class="on"><button type="button"><a href="#" title="현재페이지">1</a></button></li>
-												</ul>
-												<div class="list_bottom_right">
-													<button type="button" class="btnType btn_gray fill" id="checkAll" name="receipt_number_check" value="N">전체선택</button>
+											<div class="receipt_num_top right">
+												<p class="c_e40000 caution_text"><i class="icon caution"></i>발송 시작 이후에는 받는사람을 추가할 수 없습니다.</p>
+												<div class="btn_wrap">
 													<div class="btn_popup_wrap">
 														<button type="button" class="btnType btn_yellow fill btn_check_one">1명씩 선택<i class="qmMark"></i></button>
 														<div class="error_hover_cont send_hover_cont">
-															<p style="line-height:1.3;">마우스를 계속 누르고 있으면 받는 사람이 연속으로 선택됩니다.</p>
+															<p>마우스를 누르고 있으면 받는사람을 연속적으로 20명까지 선택할 수 있습니다.</p>
 														</div>
 													</div>
+													<button type="button" class="btnType btn_gray fill" onclick="clearAllSelection();">선택해제</button>
 												</div>
 											</div>
+											<div id="sms-table" class="listType list">
+											<div id="sms-pagination" class="custom-pagination"></div>
 	                                    </div>
 	                                    <%-- 받는 사람 리스트 박스 종료 --%>
-										<div class="put_right">
-											<button type="button" data-tooltip="popup06"  class="btnType btnType7 popupAddr">주소록 불러오기</button>
-											<button type="button" data-tooltip="popup02"  class="btnType btnType7">엑셀 불러오기</button>
-											<div class="btn_popup_wrap">
-												<button type="button" class="btnType btnType3 check_validity">오류 검사 <i class="qmMark"></i></button>
-												<div class="error_hover_cont send_hover_cont">
-													<p>휴대폰 번호 입력 시 해당 휴대폰 번호에 대한 형식이 어긋나거나 휴대폰 번호에 오류가 있는지 등을 검사하는 기능</p>
-													<span>(예시) 010-1234-0001(O) / 010-12345-0001(X)</span>
-												</div>
-											</div>
+									</div>
+									
+									<div class="put_right">
+											<button type="button" data-tooltip="popup06"  class="btnType btnType7 callToBtn" id="popupAddr">주소록 불러오기</button>
+											<button type="button" data-tooltip="popup02"  class="btnType btnType7 callToBtn">엑셀 불러오기</button>
 											<dl class="receipt_info">
 												<dt>전체 받는사람<button type="button" class="btn_reset" onclick="fnCallToListReset();"><i></i>초기화</button></dt>
 												<dd>
 													<p><b id="totCallToCnt">0</b> 명</p>
 												</dd>
-												<dt>전송완료</dt>
+												<dt>
+													<div class="btn_popup_wrap">
+														<div class="title">
+															발송완료 <i class="icon qmMark"></i>
+														</div>
+														<div class="error_hover_cont send_hover_cont">
+															<p>실제 발송결과는 발송결과 페이지에서<br />확인하실 수 있습니다.</p>
+														</div>
+													</div>
+												</dt>
 												<dd>
-													<p><b class="c_e40000" id="sendComplete">0</b> 명</p>
+													<p><b class="c_666" id="sendCompleteCnt">0</b> 명</p>
+												</dd>
+												<dt>
+													<div class="btn_popup_wrap exclude">
+														<div class="title">
+															발송제외 <i class="icon qmMark"></i>
+														</div>
+														<div class="error_hover_cont send_hover_cont">
+															<p>수신거부로 인해 발송 대상에서<br />제외된 상태입니다.</p>
+														</div>
+													</div>
+												</dt>
+												<dd>
+													<p><b class="c_e40000" id="excludeSendCnt">0</b> 명</p>
 												</dd>
 												<dt>잔여 받는사람</dt>
 												<dd>
-													<p><b class="c_002c9a" id="sendReady">0</b> 명</p>
+													<p><b class="c_002c9a" id="remainCnt">0</b> 명</p>
+												</dd>
+
+												<dd class="info_text">
+													<i class="icon info"></i>
+													<p>
+														불러온 명단은 화면<br />
+														이동 시에도 유지되며,<br />필요시 초기화 할 수 있습니다.
+													</p>
 												</dd>
 											</dl>
+											<div class="form_wrap column">
+												<label class="option_item" for="autoPageMove">
+													<input type="checkbox" id="autoPageMove" name="autoPageMove" checked>
+													<span class="option_label">다음페이지 자동넘김</span>
+												</label>
+												<label class="option_item" for="sendBySpace">
+													<input type="checkbox" id="sendBySpace" name="sendBySpace">
+													<span class="option_label">스페이스바로 발송하기</span>
+												</label>
+											</div>
+
+											<div class="send_btn">
+												<button type="button" class="btnType btnType11 btn_send" onclick="fn_sendMsgData(event);">발송하기</button>
+											</div>
+
 										</div>
-									</div>
                                 </div>
                             </td>
                         </tr>
+<%--
                         <tr>
                             <th colspan="2" class="billingAmount">
                             	<div>
@@ -4421,7 +3675,7 @@
 										<div>
 											<input type="radio" id="radio_bill_1" name="radio_bill" checked="checked">
 											<label for="radio_bill_1">보유잔액</label>
-											<%-- <label for="radio_bill_1">내 충전금 (<span id="spUserMoney">
+											&lt;%&ndash; <label for="radio_bill_1">내 충전금 (<span id="spUserMoney">
 												<c:choose>
 													<c:when test="${not empty userMoney}">
 														<c:out value="${commaPrice}"/>
@@ -4430,7 +3684,7 @@
 														0
 													</c:otherwise>
 												</c:choose>
-											</span>원)</label> --%>
+											</span>원)</label> &ndash;%&gt;
 											<label for="userMoney" class="label">보유잔액</label>
 											<input type="text" id="userMoney" name="userMoney" value="<c:out value='${commaPrice}'/>" readonly>
 											<span class="won">원</span>
@@ -4470,6 +3724,7 @@
                                 </div>
                             </th>
                         </tr>
+--%>
                         <%-- <tr>
                             <th scope="row">추천인 ID</th>
                             <td class="check_num">
@@ -4526,81 +3781,6 @@
 					</div>
                        <p class="addText">※ 단말기 설정에 따라 다르게 보일 수 있습니다</p>
 				</div>
-				<div class="phone_bottom">
-                    <div class="send_rev">
-                    	<div class="send_content">
-		                    <div class="rev_radio">
-		                    	<ul>
-		                    		<li><input type="radio" id="reserYnN" name="reserYn" value="N" checked="checked"><label for="reserYnN">즉시</label></li>
-		                    		<li><input type="radio" id="reserYnY" name="reserYn" value="Y"><label for="reserYnY">예약</label></li>
-		                    	</ul>
-		                    </div>
-		                    <div class="send_btn">
-		                        <button type="button" class="btnType btnType11" onclick="javascript:fn_sendMsgData(); return false;">발송하기</button>
-		                        <button type="button" class="btnType btnType10" onclick="javascript:fnTestSend(); return false;">테스트발송</button>
-		                    </div>		                    
-	                    </div>
-	                    <!-- 엔터키로 발송 체크박스 -->
-	                    <div class="use_enter">
-	                    	<input type="checkbox" id="enterChk" name="enterChk">
-	                    	<label for="enterChk" id="lblEnterKey">Enter키로 발송하기</label><!-- 예약일땐 'Enter키로 예약하기'로 변경부탁드려요 -->
-	                    </div>
-                        <div class="rev_selected">
-                            <div class="rev_top">
-               		            <span>날짜 :</span>
-               		            <div class="calendar_wrap">
-									<input type="text" class="startDate2 inp resDate calendar02" title="검색 시작일" id="startDate2" name="startDate2" value="" data-datecontrol="true">
-								</div>
-               		            <label for="msgResHour" class="label">시 선택</label>
-								<div class="selBox">
-		       		            	<select class="selType1" id="msgResHour" name="msgResHour">
-		       		            		<c:forEach  var="hour"  begin="0" end="23" step="1" varStatus="status">
-		       		            			<c:choose>
-		       		            				<c:when test="${hour < 10}">
-		         		            			<option value="0${hour}">0${hour}시</option>
-		       		            				</c:when>
-		       		            				<c:otherwise>
-		       		            					<option value="${hour}">${hour}시</option>
-		       		            				</c:otherwise>
-		       		            			</c:choose>
-		       		            		</c:forEach>
-		       		            	</select>
-		       		            	<label for="msgResMin" class="label">분 선택</label>
-		       		            	<select class="selType1" id="msgResMin" name="msgResMin">
-		       		            		<c:forEach var="min" begin="0" end="59" step="1">
-		       		            			<c:choose>
-		       		            				<c:when test="${min < 10}">
-		         		            			<option value="0${min}">0${min}분</option>
-		       		            				</c:when>
-		       		            				<c:otherwise>
-		       		            					<option value="${min}">${min}분</option>
-		       		            				</c:otherwise>
-		       		            			</c:choose>
-		       		            		</c:forEach>
-		       		            	</select>
-								</div>
-               		        </div>
-                           	<!-- <div class="rev_bottom">
-             		            <input type="checkbox" id="divideChk" name="divideChk">
-             		            <label for="divideChk">분할전송</label>
-             		            <input type="text" class="dividType1" id="divideCnt" name="divideCnt" value="20" onkeypress='return checkNumber(event)' maxlength="4"/>
-     		            		<label for="divideCnt">건씩</label>
-             		            <select class="selType1" id="divideTime" name="divideTime">
-             		                <option value="1">01분</option>
-		        		            <option value="2">02분</option>
-		        		            <option value="3">03분</option>
-		        		            <option value="4">04분</option>
-             		                <option value="5">05분</option>
-             		                <option value="10">10분</option>
-             		                <option value="15">15분</option>
-             		                <option value="20">20분</option>
-             		                <option value="30">30분</option>
-             		            </select>
-             		            <label for="divideTime">간격</label>
-             		        </div> -->
-                        </div>
-                    </div>
-                </div>
              </div>
         </div>
     <!-- </div> --><!--// tab content1 -->
src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/MsgTWDataView.jsp
--- src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/MsgTWDataView.jsp
+++ src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/MsgTWDataView.jsp
@@ -848,729 +848,6 @@
 	return confCheck;
 }
 
-//문자발송 처리 함수
-function fn_sendMsgData(){
-	
-	var candiNm = $("#candidateNm").val();
-	
-	if(candiNm == ""){
-		fn_candidateChk();
-		return false;
-	}
-	
-	
-	if(!checkConf()){	//문자고 conf-check
-		alert("현재 문자 발송하기 기능 점검 중입니다.\n\n1분 후 다시 시도해주세요.");
-		return false;
-	}
-	
-	var form = document.msgForm;
-
-	//회원 보유 잔액 비교
-	var totPriceOnly = stringReplaceAll(form.totPrice.value, ",", "");
-	var userMoneyOnly = stringReplaceAll(form.myPrice.value, ",", "");
-	if(parseFloat(userMoneyOnly) < parseFloat(totPriceOnly)){
-		alert("문자 발송에 필요한 회원님의 보유 잔액이 부족 합니다.");
-		return false;
-	}	
-	
-	var loginVO = '${LoginVO}';
-	var adverYn = $("input[name='send_adYn']").val();
-	var spamStatus = false;
-	var exceptSpamYn = $("#exceptSpamYn").val(); //금지어 필터링 예외 여부 - N 일 경우만 스팸 검사를 진행
-	
-	if(loginVO == "" || loginVO == null){
-		
-		alert("문자발송 서비스는 로그인 후 이용 가능합니다.");
-		return false;
-		
-	}
-	
-	if(form.callFromList.value == ""){
-		
-		alert("발신번호를 입력해 주세요.");
-		return false;
-		
-	}
-	
-	var titleStatus = form.title_status.value;
-	if(titleStatus == 'N'){//장문 제목 사용안함으로 선택시 제목에 있는 데이터 지워주기
-		
-		form.mmsSubject.value = "";
-		
-	}else{//장문 제목에 치환문자 포함된 경우 입력 못하도록 처리.
-		
-		var mmsSubject = form.mmsSubject.value;
-		if(getSpacialStringChk(mmsSubject)){
-			alert("문자 제목에는 치환문자(엑셀 내 *이름*, *1*, *2*, *3*, *4* 등)를 사용하실 수 없습니다.");
-			return false;
-		}
-		
-	}
-	
-	//문자내용 첫글자에 특수기호 포함 여부 체크
-	var strCont = form.smsTxtArea.value;
-	var rtnStr = strChinJpnCheck(strCont);
-	
-	//문자제목에 이모지가 있는지 체크
-	var titleStatusYn = $("input[name='title_status']:checked").val();
-	if(titleStatusYn == 'Y') {
-		if(!emojiCheck(form.mmsSubject.value)) return false;
-	}
-	
-	//문자내용에 이모지가 있는지 체크
-	if(!emojiCheck(strCont)) return false;
-	
-	if(rtnStr.length > 0){
-		
-		alert("입력하신 문구 중 \" " + rtnStr + " \" 는 일부 휴대폰에서 표기되지 않을 수 있습니다.");
-		
-	}
-	
-	if(imgFilePath.length == 0){ // 그림문자일 경우 내용이 없어도 됨 , 장문 문자일 경우만 문자내용 체크함
-		
-		if(form.smsTxtArea.value == ""){
-			
-			alert("문자 내용을 입력해 주세요.");
-			return false;
-			
-		}
-		
-	}
-	
-	//선거 문자 내용 합쳐주기
-	if(adverYn == 'Y'){
-		
-		var adTxt = $('.ad_txt').text();
-		var denyTxt = $('.deny_txt').html();
-		var smsTxt = form.smsTxtArea.value;
-		
-		//선거운동정보 하단 테스트내용 줄바꿈 처리해주기
-		denyTxt = denyTxt.replaceAll("<br>","\n");
-		denyTxt = denyTxt.replaceAll("<br/>","\n");
-		
-		var adverTxt = adTxt + "\n" + smsTxt + "\n" + denyTxt;
-		form.smsTxt.value = adverTxt;
-		
-	}else{
-		
-		var smsTxt = form.smsTxtArea.value;
-		form.smsTxt.value = smsTxt;
-		
-	}
-	
-	var chkCalltoCnt =  $("input[name=chkCallTo]").length;
-	
-	if(Number(chkCalltoCnt) == 0){
-		
-		alert("받는사람을 추가해 주세요.");
-		return false;
-	}
-	
-	
-	//수신번호 리스트 체크하기
-	var numCnt = 0;
-	var nameList = [];		//치환문자 이름
-	var phoneNum = [];	//받는사람
-	var rep1List = [];		//치환문자1
-	var rep2List = [];		//치환문자2
-	var rep3List = [];		//치환문자3
-	var rep4List = [];		//치환문자4
-	
-	var chkSts = $('input:checkbox[name="chkCallTo"]').is(':checked');
-	
-	if(!chkSts){
-		
-		alert("받는사람 연락처를 한 건 이상 선택해주세요.");
-		return false;
-		
-	}
-	
-	//받는사람 목록에서 체크된 연락처만 전달하도록 함.
-	$("input:checkbox[name='chkCallTo']:checked").each(function(){
-		
-		var callToNum = $(this).closest("div").next().text();
-		
-		if(!checkHpNum(callToNum)){
-			alert("선택한 연락처 목록에 잘못된 연락처가 있습니다. 연락처 번호 : " + callToNum + " 입니다.");
-			return false;
-		}else{
-			phoneNum.push(callToNum);
-		}
-		
-	});
-	
-	var reserYn = $("input[name=reserYn]:checked").val(); // 예약 발송 여부 확인
-	
-	if(reserYn == 'Y'){
-		
-		var date = $(".resDate").val();//form.msgResDate.value;
-		var hour = form.msgResHour.value;
-		var min = form.msgResMin.value;
-		
-		if(date == ""){
-			
-			alert("예약전송 날짜를 선택해 주세요.");
-			return false;
-			
-		}else{
-			
-			var now = new Date();
-			var reqDate = date + " " + hour + ":" + min + ":00";
-			var gapDate = getGapDayTime(date, hour, min);
-			
-			if(gapDate < 0){ // 음수이면 이전날짜, 크면 이후 날짜.
-				alert("예약 날짜는 현재 시간 이후의 날짜 및 시간을 선택해 주세요.");
-				return false;
-			}else{
-				form.reqDate.value = reqDate;	//예약일자 파라미터 저장
-			}
-		}
-
-	}else{
-		
-		form.reqDate.value = "";
-		
-	}
-	
-	var fileLinks = document.getElementsByName("fileLinks");
-	
-	var conLeng = conByteLeng($('#smsTxt').val()); // 내용 문자 입력 바이트 수 계산하기
-	
-	if(conLeng > 2000){
-		
-		alert("문자 내용은 2000byte를 넘을 수 없습니다.");
-		return false;
-		
-	}
-	
-	//엔터키로 문자 전송 바로 처리하기 : 엔터키와 엔터키 체크박스 둘다 조건 만족시 메시지 없이 전송처리
-	var enterChk = $("#enterChk").is(':checked');
-	if(!enterChk || !enterSts){
-		
-		if(!confirm("문자를 전송하시겠습니까?")){
-			return false;
-		}
-		
-	}
-	
-	//if(confirm("문자를 전송하시겠습니까?")){
-
-		imgFilePath = [];
-		$('.thumb_wrap').find('.thumb_img').each(function(idx, el) {
-			if($("#delLi"+idx).hasClass("Template")){
-				templateYn.push("Y");
-			} else {
-				templateYn.push("N");
-			}
-			
-			if($(el).hasClass("edit_y")) {
-				//이미지 변환
-				const imgBase64 = $(el).attr("src");
-				const decodImg = atob(imgBase64.split(',')[1]);  // base64~ 부분을 제외하고 데이터 디코딩
-				
-		
-				let array = [];
-				for (let i = 0; i < decodImg.length; i++) {
-				  array.push(decodImg.charCodeAt(i));
-				}
-
-				const file = new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
-				const fileName = 'canvas_img_' + new Date().getMilliseconds() + '.jpg';
-				let formData = new FormData();
-				formData.append('file', file, fileName);
-				
-				$.ajax({
-					type: 'post',
-					url: '/web/mjon/msgcampain/insertEditImageAjax.do',
-					cache: false,
-					data: formData,
-					dataType:'json',
-					processData: false,
-					contentType: false,
-					async: false,
-					success: function (returnData, status) {
-						if(status == 'success'){
-							// imgFilePath 에 배열로 담아주기(이미지 순서대로)
-							//console.log(imgFilePath);
-							imgFilePath.push(returnData.filefullPath);
-							imgFileId.push(returnData.atchFileId);
-							
-						} else if(status== 'fail'){
-							alert(returnData.message);
-						}
-					},
-					error: function (e) { alert("이미지 업로드에 실패하였습니다."); console.log("ERROR : ", e); }
-				});
-				
-			} else {
-
-				if(imgFilePath.length != imgFileId.length){
-					//에디터 안거친 템플릿 이미지면 바로 src 때림
-					imgFilePath.push($(el).attr("src"));
-				}
-				
-			}	
-		});
-		
-		form.imgFilePath.value = imgFilePath; // 저장한 이미지 경로 담아주기
-		form.callToList.value = phoneNum; //수신자번호 리스트 저장해주기
-		form.callFrom.value = removeDash(form.callFromList.value); // 발신번호 대쉬(-) 문자 없애주기
-		form.reserveYn.value = reserYn; // 즉시 / 예약 문자 선택 여부 
-		form.templateYn.value = templateYn;
-		form.imgFileId.value = imgFileId;
-		form.nameList.value = nameList;
-		form.rep1List.value = rep1List;
-		form.rep2List.value = rep2List;
-		form.rep3List.value = rep3List;
-		form.rep4List.value = rep4List;
-		
-		//총 결제금액 천단위 콤마 삭제 후 전송
-		var totPrice = form.totPrice.value;
-		totPrice = totPrice.replace(",","");
-		form.totPrice.value = totPrice;
-		
-		//문자내용이 입력된 경우 스팸 필터링 실행
-		if(!form.smsTxtArea.value == "" && exceptSpamYn == "N"){
-			
-			console.log(smsTxtArea);
-			var spmData = new FormData(form);
-			url = "/web/mjon/msgdata/selectSpamTxtChkAjax.do";
-			
-			$.ajax({
-		        type: "POST",
-		        url: url,
-		        data: spmData,
-		        dataType:'json',
-		        async: false,
-		        processData: false,
-		        contentType: false,
-		        cache: false,
-		        success: function (returnData, status) {
-					if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
-						
-						if("fail" == returnData.result){
-							
-							alert(returnData.message);
-							return false;
-							
-						}else if("loginFail" == returnData.result){
-							
-							alert(returnData.message);
-							return false;
-								
-						}else if("spams" == returnData.result){
-							
-// 							var spmFilterTxt = returnData.spmFilterTxt;
-							spamStatus = true;
-							
-// 							form.spamKeyword.value = spmFilterTxt;
-							form.spamStatus.value='Y';
-						}else{
-							form.spamKeyword.value = '';
-							form.spamStatus.value='N';
-							
-						}
-						
-					} else if(status== 'fail'){
-						alert(returnData.message);
-						return false;
-					}
-				},
-		        error: function (e) { alert("문자 발송에 실패하였습니다."); console.log("ERROR : ", e); return false;}
-		    });
-			
-		}
-		
-		
-		//이벤트 진행중 회원의 경우 이벤트 잔여금액 비교 처리 필요.
-		//이벤트 캐시가 부족한 경우 이벤트 캐시로 발송 가능한 만큼만 이벤트 금액으로 발송 처리해줌.
-		//이 후 나머지 발송 건수는 이벤트 캐시가 아닌 일반 단가로 발송 처리를 진행 함.
-		var eventStatus = form.eventStatus.value;
-		
-		if(eventStatus == 'Y'){ //이벤트 진행 대상자이면 문자종류에 이벤트로 구분
-			
-			form.eventYn.value = "Y"; //이벤트문자 종류 설정
-			
-		}
-		
-		var eventRemainCash = parseFloat(form.eventRemainCash.value);
-		
-		if(eventStatus == 'Y'){
-			
-			if(parseFloat(eventRemainCash) < parseFloat(totPriceOnly)){
-				
-				if(confirm("고객님의 이벤트 캐시 잔액(" + eventRemainCash + "원) 부족으로 요청하신 문자("+numberWithCommas(phoneNum.length)+"건)를 모두 발송할 수 없습니다. 이벤트 캐시 초과 건에 대해서는 일반 단가를 적용하여 발송하시겠습니까?")){
-					
-					var smsTxtArea = $('#smsTxtArea').val();
-					var evnMsgType = $("#msgType").val();
-					var evnEachPrice = $("#eachPrice").val();	//form 에 저장된 이벤트 개별 단가 불러오기
-					var evnSendCnt = Math.floor(eventRemainCash / evnEachPrice);
-					var norEachPrice = 0;
-					var imgCnt = $("#imgCnt").val();	//그림 이미지 갯수
-					var txtReplYn = $("#txtReplYn").val();	//치환문자 포함 여부 
-					var evnPhoneNumCnt = Number($("#evnPhoneNumCnt").val());	//치환문자 체크하면서 단/장문 건수 카운팅하면서 이벤트 금액으로 발송가능한 수신자 갯수 정보
-					var myPrice = parseFloat($("#myPrice").val());	//회원보유 잔여 캐시 금액
-					
-					//수신목록 저장 배열 변수 
-					var evnPhoneNum = [];	//이벤트 단가 받는사람
-					var norPhoneNum = [];	//일반 단가 받는 사람
-					
-					//치환문자 포함 문자 저장 배열 변수(이벤트 문자 저장)
-					var evnName = [];
-					var evnRep1 = [];
-					var evnRep2 = [];
-					var evnRep3 = [];
-					var evnRep4 = [];
-					
-					//치환문자 포함 문자 저장 배열 변수(일반 문자 저장)
-					var norName = [];
-					var norRep1 = [];
-					var norRep2 = [];
-					var norRep3 = [];
-					var norRep4 = [];
-					
-					
-					/**
-					Desc:	1. 그림, 치환, 일반 문자에 대해서 각각 이벤트 단가로 전송할 리스트 와 일반단가로 전송할 리스트를 분리 하는 로직
-							2. 그림 및 일반 문자는 단순 이벤트 금액으로 보낼수 있는 건수를 계산하여 리스트[0] 부터 발송 건수만큼 추출하여 evnPhoneNum 배열에 입력 후 이벤트 금액으로 발송 진행
-							3. 이벤트 발송이 완료되면, 이벤트 건수를 제외한 나머지 건수를 norPhoneNum 배열에 입력 후 일반 금액으로 발송 진행
-							4. 일반 발송시에 전송 단가(eachPrice), 전체금액(totPrice) 등 변수 정보 변경
-							=====
-							5. 그림문자가 아닌 치환문자인 경우 치환 처리를 진행하면서 단문, 장문을 구분하고 이때 이벤트 금액에서 단문, 장문 가격을 차감하여 보낼 수량을 카운팅 함.
-							6. 치환 체크가 완료되면 치환시 나온 카운트 갯수만큼 이벤트 배열과 일반 배열에 분리처리 후 전송함.
-					Param Array : evnPhoneNum, norPhoneNum
-					function :  getNorEachPrice - 메세지 타입(msgType)에 따른 단문, 장문, 그림문자 개별 단가 금액 확인
-								sendMsgAjax 	- 문자 발송 요청 Ajax 처리
-					*/
-
-					//그림문자인 경우
-					if(imgCnt > 0){
-						
-						//이벤트 가격으로 전송 할 받는 사람 리스트 저장처리
-						for(var i=0; i< evnSendCnt; i++){
-							evnPhoneNum[i]= phoneNum[i];
-							
-							//그림문자에 치환문자가 포함된 경우
-							if(txtReplYn == 'Y'){
-								
-								evnPhoneNum[i] = phoneNum[i];
-								evnName[i] = nameList[i];
-								evnRep1[i] = rep1List[i];
-								evnRep2[i] = rep2List[i];
-								evnRep3[i] = rep3List[i];
-								evnRep4[i] = rep4List[i];
-								
-							}
-						}
-						
-						//일반 가격으로 전송 할 받는 사람 리스트 저장처리
-						for(var j=0; j < phoneNum.length - evnSendCnt; j++){
-							norPhoneNum[j]= phoneNum[j + evnSendCnt];
-							
-							//그림문자에 치환문자가 포함된 경우
-							if(txtReplYn == 'Y'){
-								
-								norPhoneNum[j]= phoneNum[j + evnSendCnt];
-								norName[j] = nameList[j + evnSendCnt];
-								norRep1[j] = rep1List[j + evnSendCnt];
-								norRep2[j] = rep2List[j + evnSendCnt];
-								norRep3[j] = rep3List[j + evnSendCnt];
-								norRep4[j] = rep4List[j + evnSendCnt];
-								
-							}
-							
-						};
-						
-					}else if(txtReplYn == 'Y'){//치환 문자가 있는 경우 , 그림문자에 치환이 있는 경우 그림문자 가격으로 발송
-						
-						//이벤트 가격으로 전송 할 받는 사람 리스트 저장처리
-						for(var i=0; i< evnPhoneNumCnt; i++){
-							evnPhoneNum[i] = phoneNum[i];
-							evnName[i] = nameList[i];
-							evnRep1[i] = rep1List[i];
-							evnRep2[i] = rep2List[i];
-							evnRep3[i] = rep3List[i];
-							evnRep4[i] = rep4List[i];
-							
-						}
-						
-						//일반 가격으로 전송 할 받는 사람 리스트 저장처리
-						for(var j=0; j < phoneNum.length - evnPhoneNumCnt; j++){
-							norPhoneNum[j]= phoneNum[j + evnPhoneNumCnt];
-							norName[j] = nameList[j + evnPhoneNumCnt];
-							norRep1[j] = rep1List[j + evnPhoneNumCnt];
-							norRep2[j] = rep2List[j + evnPhoneNumCnt];
-							norRep3[j] = rep3List[j + evnPhoneNumCnt];
-							norRep4[j] = rep4List[j + evnPhoneNumCnt];
-							
-						};
-						
-					}else{//치환문자 없는 경우 처리
-						
-						//이벤트 가격으로 전송 할 받는 사람 리스트 저장처리
-						for(var i=0; i< evnSendCnt; i++){
-							evnPhoneNum[i]= phoneNum[i];
-						}
-						
-						//일반 가격으로 전송 할 받는 사람 리스트 저장처리
-						for(var j=0; j < phoneNum.length - evnSendCnt; j++){
-							norPhoneNum[j]= phoneNum[j + evnSendCnt];
-						};
-					}
-						
-					var orgShortMsgCnt = $("#shortMsgCnt").val();	//단문 총 건수 백업
-					var orgLongMsgCnt = $("#longMsgCnt").val();		//장문 총 건수 백업
-					//이벤트 단가 문자 전송 처리 시작
-					if(evnPhoneNum.length > 0){
-						
-						form.callToList.value = evnPhoneNum; //수신자번호 리스트 저장해주기
-						form.totPrice.value = evnEachPrice * evnSendCnt;	//이벤트 단가 총 결제금액 셋팅해주기
-						form.eventStatus.value = 'Y';
-						form.eventYn.value = 'Y';
-						
-						var evnTotPrice = parseFloat(form.totPrice.value); 
-						
-						if(myPrice < evnTotPrice){
-						
-							alert("문자 발송에 필요한 회원님의 보유 잔액이 부족 합니다.");
-							return false;
-							
-						}else{
-							
-							myPrice = myPrice - evnTotPrice;
-							
-						}
-						
-						//치환문자가 있는 경우 변수 정보 담아주기(그림문자 아닌경우)
-						if(txtReplYn == 'Y' &&  imgCnt < 1){
-							
-							var evnShortMsgCnt = $("#evnShortMsgCnt").val();
-							var evnLongMsgCnt = $("#evnLongMsgCnt").val();
-							
-							form.shortMsgCnt.value = evnShortMsgCnt;
-							form.longMsgCnt.value = evnLongMsgCnt;
-							form.nameList.value = evnName;
-							form.rep1List.value = evnRep1;
-							form.rep2List.value = evnRep2;
-							form.rep3List.value = evnRep3;
-							form.rep4List.value = evnRep4;
-							
-						}else if(txtReplYn == 'Y' &&  imgCnt > 0){//치환문자가 있는 경우 변수 정보 담아주기(그림문자인 경우)
-							
-							form.nameList.value = evnName;
-							form.rep1List.value = evnRep1;
-							form.rep2List.value = evnRep2;
-							form.rep3List.value = evnRep3;
-							form.rep4List.value = evnRep4;
-							
-						}
-						
-						//이벤트 발송 실행 해주기
-						var form = document.msgForm;
-						
-						var data = new FormData(form);
-						url = "/web/mjon/msgcampain/sendMsgDataAjax.do";
-						
-						$.ajax({
-					        type: "POST",
-					        url: url,
-					        data: data,
-					        dataType:'json',
-					        async: true,
-					        processData: false,
-					        contentType: false,
-					        cache: false,
-					        success: function (returnData, status) {
-								if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
-									if("fail" == returnData.result){
-										
-										alert(returnData.message);
-										return false;
-										
-									}else if("loginFail" == returnData.result){
-										
-										alert(returnData.message);
-										return false;
-											
-									}else if("smsLengFail" == returnData.result){
-										
-										alert(returnData.message);
-										return false;
-											
-									}else if("imgSourceFail" == returnData.result){
-										
-										$('.pop_msg_fails').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
-										$('.pop_msg_fails .msg_text').html(returnData.message);
-										$('.mask').addClass('on');
-										
-									}else if("spamKeyWordFail" == returnData.result){//스팸 및 스미싱 단어가 들어간 문자 발송시 회원 이용정지 처리
-										
-										$('.pop_msg_spam').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
-										$('.pop_msg_spam .msg_text').html(returnData.message);
-										$('.mask').addClass('on');
-										
-									}else if("statusFail" == returnData.result){
-										
-										alert(returnData.message);
-										//문자발송 URL Move
-										goMsgUrlMove();
-										return false;
-										
-									}else{
-										
-										var smsCnt = returnData.resultSts;
-										var blockCnt = returnData.resultBlockSts;
-										
-										//이벤트 발송 처리가 완료 되면 나머지 일반 캐시로 발송할 문자 처리를 진행해 준다.
-										var norPhoneNumCnt = norPhoneNum.length; 
-										if(norPhoneNumCnt > 0){
-											
-											var norEachPrice = getNorEachPrice(evnMsgType); //일반 개별 단가 금액 셋팅해주기
-											
-											form.callToList.value = norPhoneNum;	//수신자번호 리스트 저장해주기
-											form.eachPrice.value =  norEachPrice;	//일반 개별 단가 금액 셋팅해주기
-											form.totPrice.value = norEachPrice * norPhoneNumCnt;	//일반 단가 총 결제 금액 셋팅해주기
-											form.sPrice.value = $("#norsPrice").val();
-											form.mPrice.value = $("#normPrice").val();
-											form.pPrice.value = $("#norpPrice").val();
-											form.p2Price.value = $("#norp2Price").val();
-											form.p3Price.value = $("#norp3Price").val();
-											form.eventStatus.value = 'N';
-											form.eventYn.value = 'N';
-											
-											var norTotPrice = parseFloat(form.totPrice.value); 
-											
-											if(myPrice < norTotPrice){
-											
-												var failMsg = "이벤트 캐시 잔액으로 발송한 문자("+smsCnt+"건)의 발송이 완료되었으나 일반 문자 발송("+norPhoneNumCnt+"건)에 필요한 회원님의 보유 잔액이 부족 합니다.";
-												
-												$('.loading_layer').removeClass('active');
-
-												$('.pop_msg_fails').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
-												$('.pop_msg_fails .msg_text').html(failMsg);
-												$('.mask').addClass('on');
-												
-												return false;
-												
-											}
-											
-											//치환문자가 있는 경우 변수 정보 담아주기(그림문자가 아닌경우)
-											if(txtReplYn == 'Y' &&  imgCnt < 1){
-												
-												//치환문자 단/장문 혼용된 경우 각 타입별 건수를 재 계산해준다.
-												//총 단/장문 각각 건수에서 이벤트로 발송한 건수를 빼준다.
-												var evnShortMsgCnt = $("#evnShortMsgCnt").val();
-												var evnLongMsgCnt = $("#evnLongMsgCnt").val();
-												
-												var shortMsgCnt = Number(orgShortMsgCnt) - Number(evnShortMsgCnt);
-												var longMsgCnt = Number(orgLongMsgCnt) - Number(evnLongMsgCnt);
-												
-												
-												//계산 값이 음수로 나오는 경우 0건으로 간주한다.
-												if(shortMsgCnt <= 0){
-													
-													shortMsgCnt = 0;
-													
-												}
-												
-												if(longMsgCnt <= 0){
-													
-													longMsgCnt = 0;
-													
-												}
-												
-												form.shortMsgCnt.value = shortMsgCnt;
-												form.longMsgCnt.value = longMsgCnt;
-												
-												form.nameList.value = norName;
-												form.rep1List.value = norRep1;
-												form.rep2List.value = norRep2;
-												form.rep3List.value = norRep3;
-												form.rep4List.value = norRep4;
-												
-											}else if(txtReplYn == 'Y' &&  imgCnt > 0){//치환문자가 있는 경우 변수 정보 담아주기(그림문자인 경우)
-												
-												form.nameList.value = norName;
-												form.rep1List.value = norRep1;
-												form.rep2List.value = norRep2;
-												form.rep3List.value = norRep3;
-												form.rep4List.value = norRep4;
-												
-											}
-											
-											
-											sendMsgAjax(smsCnt, blockCnt);
-										}
-										
-									}
-									
-								} else if(status== 'fail'){
-									alert(returnData.message);
-								}
-							},
-							beforeSend : function(xmlHttpRequest) {
-					        	//로딩창 show
-					        	$('.loading_layer').addClass('active');				
-							},	        	        
-					        complete : function(xhr, textStatus) {
-					        	//로딩창 hide
-					        	//$('.loading_layer').removeClass('active');
-							},	      			
-					        error: function (e) { alert("문자 발송에 실패하였습니다."); console.log("ERROR : ", e); }
-					    });
-						
-					}else{
-						
-						//이벤트 건수로 발송 할 수 없는 경우 일반 캐시 단가로 발송처리하기
-						if(norPhoneNum.length > 0){
-							
-							form.callToList.value = norPhoneNum; //수신자번호 리스트 저장해주기
-							form.eachPrice.value = getNorEachPrice(evnMsgType); //일반 개별 단가 금액 셋팅해주기
-							form.sPrice.value = $("#norsPrice").val();
-							form.mPrice.value = $("#normPrice").val();
-							form.pPrice.value = $("#norpPrice").val();
-							form.p2Price.value = $("#norp2Price").val();
-							form.p3Price.value = $("#norp3Price").val();
-							form.eventStatus.value = 'N';
-							form.eventYn.value = 'N';
-							
-							sendMsgAjax(0,0);
-							
-						}else{
-							
-							alert("문자 전송 중 오류가 발생하였습니다.!!");
-							return false;
-							
-						}
-						
-					}
-					
-					return false;
-				}else{
-					
-					return false;
-					
-				}
-				
-			}else{
-				
-				//발송 Ajax 호출해주기
-				sendMsgAjax(0,0);
-				
-			}
-			
-		}else{
-			
-			//발송 Ajax 호출해주기
-			sendMsgAjax(0,0);
-			
-		}
-		
-	//}
-	
-}
-
 
 //이벤트가 아닌 일반 개별 단가 셋팅해주기
 function getNorEachPrice(evnMsgType){
@@ -1968,9 +1245,9 @@
         <div class="send_top">
             <!-- tab button -->
             <ul class="tabType1">
-                <li class="tab"><button type="button" onclick="javascript:fnMsgDataView(); return false;">단체문자(자동동보문자)</button></li>
+                <li class="tab"><button type="button" onclick="javascript:fnMsgDataView(); return false;">자동동보문자</button></li>
                 <li class="tab active">
-                	<button type="button">20건 문자(수동문자)</button>
+                	<button type="button">20건 수동문자</button>
                 </li>
             </ul><!--// tab button -->
 			<!-- tab content1 -->
 
src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/MsgTWDataView_backup_20260219.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/MsgTWDataView_backup_20260219.jsp
@@ -0,0 +1,2278 @@
+<%@ 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" %>
+<%@ page import="itn.com.cmm.LoginVO" %>
+
+<!-- <script src="/publish/js/content.js"></script> -->
+
+<script type="text/javascript">
+
+var _regExp1 = /(^02.{0}|^01.{1}|^[0-9]{3})-?([0-9]{3,4})-?([0-9]{4})$/;
+
+var imgFilePath = []; // 최종 선택한 이미지 경로 저장 변수
+var imgFileId = []; // 최종 선택한 파일 아이디 저장 변수
+var templateYn = []; // 템플릿 사용 여부 저장 변수
+var tableL = null; //좌측 받는 사람 주소록 Tabulator 변수
+var tableR = null; //우측 주소록 불러오기 Tabulator 변수
+var tableAddr = null; //주소록 불러오기 팝업 Tabulator 변수
+
+var loginVO = '${loginVO}';
+
+var popCustomScrT=0;	// 맞춤제작 요청 JSPark => 2023.02.21 추가
+var msgResendAllFlag = "${msgResendAllFlag}";
+var msgResendAllGroupId = "${msgResendAllGroupId}";
+var msgResendAllAdvertiseYn = "${msgResendAllAdvertiseYn}";
+var msgResendAllReplaceYn = "${msgResendAllReplaceYn}";
+
+var enterSts = false;
+
+$(document).ready(function(){
+	//문자 발송 화면 폼 불러오기
+	listMsgDataView();
+	
+	//최 하단  문자 샘플 탭 리스트 내용 불러오기
+	fnLetterListAjax(1);
+	
+	//최 하단 그림문자 탭 리스트 내용 불러오기
+	fnPhotoListAjax(1);
+	
+	// 내보관함 리스트 로그인이 완료된 경우에만 로드되도록
+	if(loginVO != "" && loginVO != null){
+		//최 하단 내문자함 탭 리스트 내용 불러오기
+		fnMyMsgListAjax(1);
+	}
+	
+	//그림문자 샘플 탭 활성화 시키기
+	TabType2($('.tabType2 li').eq(1), '2');
+	
+	$(".tDep2_cateCode a").each(function(index, item){
+		
+		if($(this).text() == "선거"){
+			$('.tDep2_cateCode').find('.on').removeClass('on');
+			$(this).addClass('on');
+		}
+	})
+	
+	// 맞춤제작 요청 JSPark => 2023.02.21 추가
+	//맞춤제작 등록 Popup 
+	//customPopup();	
+
+});
+
+//문자 그룹정보 => 재전송용
+function getMjMsgGroupInfoByResend() {
+	$.ajax({
+		type: "POST",
+		url: "/web/mjon/msgdata/selectMjMsgGroupInfoByResendAjax.do",
+		data: {"msgResendAllGroupId" : msgResendAllGroupId},
+		dataType:'json',
+		async: false,
+		success: function (data) {
+			//alert(JSON.stringify(data));
+			if(data.isSuccess == true){
+				var msgData = data.resultMsgInfo;
+				var fileData = data.resultMsgAddPhotoInfo;
+				
+				// 발신번호
+				var reCallFrom = $.trim(removeDash($("#callFromList option:selected").val()));
+				if ($.trim(removeDash(msgData.callFrom)) != reCallFrom) {
+					alert("발신번호가 이전에 발송한 번호가 아닙니다.\n발신번호를 확인해주세요.")
+				}
+				
+				var smsTxt = msgData.smsTxt;
+				var subject = msgData.subject;
+				var fileId = "";
+				var filePath = "";
+				var len = fileData.length;
+				
+				// 기존 내용 지워주기
+				//$(".btnReset").trigger("click");
+				$('.delLi').each(function(){
+					$(this).remove();
+				});
+				
+				$('.preBoxF').each(function(){
+					$(this).remove();
+				});
+
+				$('#imgCnt').val(0);
+				
+				// 기존 imgFileId, imgFilePath 배열에 있는 내용 초기화 해주기
+				imgFilePath = [];
+				imgFileId = [];
+
+				// 문자제목
+				if (msgData.subject != null && msgData.subject != "") {
+					$('.msg_title').addClass('active');
+					$("input:radio[name='title_status']:radio[value='Y']").prop('checked', true); // 선택하기
+					$('.textbox').show();
+					$("#mmsSubject").val(subject);	
+				}
+				
+				// 문자내용
+				// 선거 기본정보 제거
+				if (smsTxt.indexOf("(선거운동정보)") == 0) {
+					smsTxt = $.trim(smsTxt.replace("(선거운동정보)", ""));
+					var smsTxtLastIdxCnt = smsTxt.lastIndexOf("후보자전화번호");
+					if (smsTxtLastIdxCnt != -1) {
+						smsTxt = $.trim(smsTxt.substring(0, smsTxtLastIdxCnt));	
+					}
+				}
+				$('#smsTxtArea').val(smsTxt);
+				
+				// 첨부 이미지가 있는경우 이미지 처리해주기
+				if(len > 0) {
+					for(var i=0; i < len; i++) {
+						var num = i + 1;
+						var imgId = fileData[i].atchFileId;
+						var imgSn = fileData[i].fileSn;
+						var fileStreCours = fileData[i].fileStreCours;
+						var streFileNm = fileData[i].streFileNm;
+						var fileExtsn = fileData[i].fileExtsn;
+						
+						/* var imgSrc = fileStreCours + "/" + streFileNm + "." + fileExtsn; */
+						var imgSrc = '/cmm/fms/getImage2.do?atchFileId=' + imgId + '&fileSn=' + imgSn;
+						myMsgImageControl(imgSrc, "edit_n", "Template", imgId);
+					}
+					
+					fnByteString($('#smsTxtArea').val());
+				}
+				else {
+					fnByteString($('#smsTxtArea').val());
+				}
+				
+				// 문자전송 상단으로 이동
+				var sendOfT=$('.send_top').offset().top;
+				$('html,body').stop().animate({'scrollTop':sendOfT-60},250);		
+				
+			} else {
+				//alert("Message : " + msg);
+			}
+		},
+		error: function (e) { 
+			//alert("저장에 실패하였습니다."); 
+			//console.log("ERROR : ", e); 
+		}
+	});
+}
+
+// 문자 상세정보 => 재전송용
+function getMjMsgListByResend() {
+	$.ajax({
+		type: "POST",
+		url: "/web/mjon/msgdata/selectMjMsgListByResendAjax.do",
+		data: {"msgResendAllGroupId" : msgResendAllGroupId},
+		dataType:'json',
+		async: true,
+		success: function (data) {
+			if(data.isSuccess == true){
+				var listCnt = data.resultList.length;
+				
+				//수신자 처리 변수
+				var callToList = [];	//수신자 처리 리스트
+				var tableData = [];		//수신자 tabulator 처리 변수
+				
+				for(var i = 0; i < listCnt; i++){ // 수신자 리스트 Tabulator에 입력해 주기
+					callToList[i] = data.resultList[i].callTo;
+					tableData.push({phone: removeDash(callToList[i])});
+				}
+				
+				if(tableData.length > 0){
+					tableL.addData(dupliPhoneData(tableData)); // 받는사람 목록에 주소 정보 입력하기
+
+					totRows = tableL.getRows().length; 
+					updateTotCnt(totRows); //전체 데이터 갯수 구하기
+					
+					//결제 금액 구하기
+				    totalPriceSum(totRows);		
+				}				
+				
+			} else {
+				//alert("Message : " + msg);
+			}
+		},
+		error: function (e) { 
+			//alert("저장에 실패하였습니다."); 
+			//console.log("ERROR : ", e); 
+		}
+	});
+}
+
+//문자발송 URL Move
+function goMsgUrlMove() {
+	//document.location.href = "/web/mjon/msgcampain/selectMsgTWDataView.do";
+	addTWCallToInfo();
+}
+
+function listMsgDataView(){
+	
+	var sendData = $(document.searchForm).serializeArray() ;
+	$(".contentArea").load("/web/mjon/msgcampain/selectMsgTWDataSMLViewAjax.do", sendData ,function(response, status, xhr){
+		
+		//문자 재전송 처리를 위해 사용
+		$("#msgForm").ready(function(){	//문자 내용 폼이 로드된 후 실행
+			
+			var msgResendFlag = '${reSendMsgVO.msgResendFlag}';
+			var msgSeqList = [];
+			msgSeqList = '${reSendMsgVO.msgSeqList}';
+			if(msgSeqList.length > 0){
+					
+				fnMsgResend(msgResendFlag, msgSeqList);
+				
+			}
+
+			//주소록에서 주소를 전송한 경우 처리
+			var moveAddrFlag = '${addrVO.moveAddrFlag}';
+			var addrIdList = [];
+			addrIdList = '${addrVO.addrIdList}';
+			if(addrIdList.length > 0) {
+				fnAddrSet(moveAddrFlag, addrIdList);
+			}		
+			
+			// 문자 재전송 New
+			if (msgResendAllFlag == "Y") {
+				if (msgResendAllReplaceYn != "Y") {
+					// 문자 그룹정보 => 재전송용
+					getMjMsgGroupInfoByResend();
+				}
+
+				// 문자 상세정보 => 재전송용
+				getMjMsgListByResend();
+			}	
+			
+		});	
+		
+		
+	}).slideDown();
+}
+
+function fnAddrSet(moveAddrFlag, addrIdList){
+	
+	if(moveAddrFlag == 'Y'){ // 주소록에서 넘어오는 경우 
+		
+		var form = document.moveAddrForm;
+		form.addrIdList.value = addrIdList;
+		
+		var data = new FormData(form);
+		url = "/web/mjon/addr/selectAddrDataListAjax.do";
+		
+		$.ajax({
+	        type: "POST",
+	        url: url,
+	        data: data,
+	        dataType:'json',
+	        async: true,
+	        processData: false,
+	        contentType: false,
+	        cache: false,
+	        success: function (returnData, status) {
+				if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+					if("fail"==returnData.result){
+						
+						alert(returnData.message);
+						return false;
+						
+					}else if("loginFail"==returnData.result){
+						
+						alert(returnData.message);
+						return false;
+						
+					}else if(returnData.resultListCnt == '0'){
+						
+						alert("전달된 주소록이 없습니다.");
+						return false;
+						
+					}else{
+						
+						var listCnt = returnData.resultListCnt;
+						
+						//수신자 처리 변수
+						var tableData = [];		//수신자 tabulator 처리 변수
+						
+						for(var i = 0; i < listCnt; i++){ // 수신자 리스트 Tabulator에 입력해 주기
+							
+							tableData.push({
+								name: returnData.resultList[i].addrNm
+								,phone: removeDash(returnData.resultList[i].addrPhoneNo)
+								,rep1: returnData.resultList[i].addrInfo1
+								,rep2: returnData.resultList[i].addrInfo2
+								,rep3: returnData.resultList[i].addrInfo3
+								,rep4: returnData.resultList[i].addrInfo4
+								});
+							
+						}
+
+						tableL.addData(dupliPhoneData(tableData)); // 받는사람 목록에 주소 정보 입력하기
+						
+						totRows = tableL.getRows().length;
+						
+						updateTotCnt(totRows); //전체 데이터 갯수 구하기
+						
+						//결제 금액 구하기
+					    totalPriceSum(totRows);
+						
+						return false;
+						
+					}
+				
+				} else if(status== 'fail'){
+					alert(returnData.message);
+				}
+			},
+	        error: function (e) { 
+	        	alert("주소록 가져오기에 실패하였습니다."); 
+	        	console.log("ERROR : ", e); 
+	        },
+			beforeSend : function(xmlHttpRequest) {
+	        	//로딩창 show
+	        	$('.loading_layer').addClass('active');				
+			},	        	        
+	        complete : function(xhr, textStatus) {
+	        	//로딩창 hide
+	        	$('.loading_layer').removeClass('active');
+			}	      
+	    });
+		
+	}
+	
+}
+
+function fnMsgResend(msgResendFlag, msgSeqList){
+	
+	if(msgResendFlag == 'Y'){ // 문자재전송에서 넘어오는 경우 
+		
+		var form = document.msgResendForm;
+		form.msgSeqList.value = msgSeqList;
+		
+		var data = new FormData(form);
+		url = "/web/mjon/msgcampain/selectReSendMsgDataListAjax.do";
+		
+		$.ajax({
+	        type: "POST",
+	        url: url,
+	        data: data,
+	        dataType:'json',
+	        async: false,
+	        processData: false,
+	        contentType: false,
+	        cache: false,
+	        success: function (returnData, status) {
+				if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+					if("fail"==returnData.result){
+						
+						alert(returnData.message);
+						return false;
+						
+					}else if("loginFail"==returnData.result){
+						
+						alert(returnData.message);
+						return false;
+						
+					}else if(returnData.resultListCnt == '0'){
+						
+						alert("재전송 문자내용이 없습니다.");
+						return false;
+						
+					}else{
+						
+						var data = returnData;
+						var listCnt = returnData.resultListCnt;
+						var photoInfo = returnData.resultMsgPhotoInfo;
+						//수신자 처리 변수
+						var callToList = [];	//수신자 처리 리스트
+						var tableData = [];		//수신자 tabulator 처리 변수
+						
+						//var subject = data.resultList[0].subject;	//제목
+						//var smsTxt = data.resultList[0].smsTxt;		//문자내용
+						//var fileCnt = data.resultList[0].fileCnt;		//그림문자 이미지 갯수
+						//var filePath1 = data.resultList[0].fileType1;	//이미지1 파일 경로
+						//var filePath2 = data.resultList[0].fileType2;	//이미지2 파일 경로
+						//var filePath3 = data.resultList[0].fileType3;	//이미지3 파일 경로
+						var atchFileId1 = photoInfo.atchFileId1;		//이미지1 파일 번호
+						var atchFileId2 = photoInfo.atchFileId2;		//이미지2 파일 번호
+						var atchFileId3 = photoInfo.atchFileId3;		//이미지3 파일 번호
+						
+						/* if(smsTxt != null){
+							
+							$("#smsTxtArea").val(smsTxt);
+							fnByteString(smsTxt);
+							
+						}
+						
+						if(subject != null){
+							
+							$("#mmsSubject").val(subject);
+							
+						}
+						
+						if(fileCnt > 0){ //문자 내용 이미지 처리해주기
+							
+							for(var i=0; i < fileCnt; i++){
+								
+								var imgId = "";
+								var imgSrc = "";
+								
+								if(i == 0){
+									
+									imgSrc = filePath1.replace("/usr/local/tomcat_mjon/webapps/mjon","");
+									imgId = atchFileId1;
+									
+								}else if(i == 1){
+									
+									imgSrc = filePath2.replace("/usr/local/tomcat_mjon/webapps/mjon","");
+									imgId = atchFileId2;
+									
+								}else{
+									
+									imgSrc = filePath3.replace("/usr/local/tomcat_mjon/webapps/mjon","");
+									imgId = atchFileId3;
+									
+								}
+								
+								myMsgImageControl(imgSrc, "edit_n", "Template", imgId);
+								
+							}
+							
+						} */
+						
+						for(var i = 0; i < listCnt; i++){ // 수신자 리스트 Tabulator에 입력해 주기
+							
+							callToList[i] = data.resultList[i].callTo;
+							tableData.push({phone: removeDash(callToList[i])});
+							
+						}
+						
+						if(tableData.length > 0){
+							
+							tableL.addData(dupliPhoneData(tableData)); // 받는사람 목록에 주소 정보 입력하기
+							
+							//totRows = tableL.getRows().length; 
+							//updateTotCnt(totRows); //전체 데이터 갯수 구하기
+							
+							//결제 금액 구하기
+						    //totalPriceSum(totRows); 
+							
+						}
+						
+						return false;
+						
+					}
+				
+				} else if(status== 'fail'){
+					alert(returnData.message);
+				}
+			},
+	        error: function (e) { alert("문자 재전송 번호 등록에 실패하였습니다."); console.log("ERROR : ", e); }
+	    });
+		
+	}
+	
+}
+
+function fnLetterListAjax(index){
+	var form = document.letterForm;
+	
+	if($('.tDep1_letType a').eq(0).hasClass('on')) {
+		form.letterType.value='S';
+	} else if ($('.tDep1_letType a').eq(1).hasClass('on')) {
+		form.letterType.value='L';
+	}
+	
+	//검색자 입력 검색 시 카테고리, 해쉬태그 전체  초기화
+	if(form.searchKeyword.value != '') {
+		form.categoryCode.value = "";
+		form.hashTag.value = "";
+		
+		$('.tDep1_cateCode').find('.on').removeClass('on');
+		$('.tDep1_cateCode').find('.cateAll').addClass('on');
+		$('.tDep1_hashTag').find('.on').removeClass('on');
+		$('.tDep1_hashTag').find('.hashAll').addClass('on');
+	}else{
+		//해시태그가 선택되어 있을 경우 해당 태그 검색어를 전달해줌
+		var strTagTxt = $('.tDep1_hashTag').find('.on').text().replace("#","");
+		if(strTagTxt == "전체"){
+			form.hashTag.value = "";
+		}else{
+			form.hashTag.value = strTagTxt;
+		}
+	}
+	
+	form.pageIndex.value = index;
+	var sendData = $(document.letterForm).serializeArray();
+	//하위 카테고리
+	$("#tDep1_depThrCateCode").load("/web/mjon/msgcampain/selectCateConfThrDptListAjax.do", sendData ,function(response, status, xhr){
+		if(document.letterForm.searchKeyword.value == ''){
+			$('.bottom_content .area_total_count').hide();
+		}
+		if(form.hashTag.value != ''){
+			if($('#letterLoad .nodata_box').length > 0){
+				$('#letterLoad .nodata_box').hide().next('.nodata_box.hashTag').show();
+			}
+		}
+		
+	});
+	$("#letterLoad").load("/web/mjon/msgcampain/selectLetterDataListAjax.do", sendData ,function(response, status, xhr){
+		if(document.letterForm.searchKeyword.value == ''){
+			$('.bottom_content .area_total_count').hide();
+		}
+	});
+	
+}
+
+function fnPhotoListAjax(index){
+	var form = document.letterForm;
+	//검색자 입력 검색 시 카테고리, 해쉬태그 전체  초기화
+	if(form.searchKeyword.value != '') {
+		form.categoryCode.value = "";
+		form.hashTag.value = "";
+		
+		$('.tDep2_cateCode').find('.on').removeClass('on');
+		$('.tDep2_cateCode').find('.cateAll').addClass('on');
+		$('.tDep2_hashTag').find('.on').removeClass('on');
+		$('.tDep2_hashTag').find('.hashAll').addClass('on');
+	}else{
+		//해시태그가 선택되어 있을 경우 해당 태그 검색어를 전달해줌
+		var strTagTxt = $('.tDep2_hashTag').find('.on').text().replace("#","");
+		if(strTagTxt == "전체"){
+			form.hashTag.value = "";
+		}else{
+			form.hashTag.value = strTagTxt;
+		}
+	}
+	
+	form.letterType.value = 'P';
+	form.pageIndex.value = index;
+	var sendData = $(document.letterForm).serializeArray();
+	//하위 카테고리
+	$("#tDep2_depThrCateCode").load("/web/mjon/msgcampain/selectCateConfThrDptListAjax.do", sendData ,function(response, status, xhr){
+		if(document.letterForm.searchKeyword.value == ''){
+			$('.bottom_content .area_total_count').hide();
+		}
+		if(form.hashTag.value != ''){
+			if($('#letterLoad .nodata_box').length > 0){
+				$('#letterLoad .nodata_box').hide().next('.nodata_box.hashTag').show();
+			}
+		}
+		
+	});	
+	$("#photoLoad").load("/web/mjon/msgcampain/selectPhotoDataListAjax.do", sendData ,function(response, status, xhr){
+		photoLayerView();
+		if(document.letterForm.searchKeyword.value == ''){
+			$('.bottom_content .area_total_count').hide();
+		}
+		if(form.hashTag.value != ''){
+			if($('#photoLoad .nodata_box').length > 0){
+				$('#photoLoad .nodata_box').hide().next('.nodata_box.hashTag').show();
+			}
+		}
+	});
+	
+}
+
+function fnMyMsgListAjax(index){
+
+	if(loginVO == "" || loginVO == null){
+		//alert("로그인 후 사용이 가능합니다.");
+		location.href="/web/user/login/login.do";
+		return false;
+	}else{
+		document.myMsgForm.pageIndex.value = index;
+		var sendData = $(document.myMsgForm).serializeArray();
+		$("#myMsgLoad").load("/web/mjon/msgcampain/selectMyMsgDataListAjax.do", sendData ,function(response, status, xhr){
+			/* $(".msg_cont").mCustomScrollbar({
+				axis: 'y',
+				scrollbarPosition: "inside",
+				theme: "dark",
+				autoHideScrollbar: false
+			}); */
+			
+		});
+	}
+}
+
+function fnMyMsgSearchListAjax(index){
+	
+	document.myMsgForm.pageIndex.value = index;
+	var sendData = $(document.myMsgForm).serializeArray();
+	$("#myMsgLoad").load("/web/mjon/msgcampain/selectMyMsgDataListAjax.do", sendData ,function(response, status, xhr){
+		
+		/* $(".msg_cont").mCustomScrollbar({
+			axis: 'y',
+			scrollbarPosition: "inside",
+			theme: "dark",
+			autoHideScrollbar: false
+		}); */
+		
+	});
+	
+}
+
+function fnMsgDataView(){
+	
+	/* var sendData = $(document.searchForm).serializeArray() ;
+	
+	//엑셀 문자 탭 활성화 시키기
+	TabType1($('.tabType1 li').eq(1), '2');
+	
+	$(".contentExcelArea").load("/web/mjon/msgcampain/selectMsgExcelDataViewAjax.do", sendData ,function(response, status, xhr){
+	}); */
+	
+	//location.href="/web/mjon/msgcampain/excel/selectMsgExcelDataView.do";
+	location.href="/web/mjon/msgcampain/selectMsgDataView.do";
+	
+}
+
+function fn_saveMyMsg(){ // 내 문자 보관함 저장
+	
+	var form = document.msgForm;
+	var myImgFileId = [];			//신규 이미지 추가 파일 Id 저장 변수
+	var adverYn = $("input[name='send_adYn']").val(); //광고 체크여부
+	
+	/*
+		이미지 에디터를 사용하여 추가한 경우 이미지 업로드 처리 - 단 에디터에서 템플릿을 선택한 경우는 업로드안함
+		신규 이미지 추가를 한 경우만 이미지 파일 업로드 처리함
+	*/
+	$('.thumb_wrap').find('.thumb_img').each(function(idx, el) {
+		
+		if($("#delLi"+idx).hasClass("Template")){ //이미지 에디터 템플릿 이미지 선택 여부 확인
+			templateYn.push("Y"); 
+		} else {
+			templateYn.push("N"); 
+		}
+		
+		if($(el).hasClass("edit_y")) { //에디터를 사용했고
+			//이미지 변환
+			const imgBase64 = $(el).attr("src");
+			const decodImg = atob(imgBase64.split(',')[1]);  // base64~ 부분을 제외하고 데이터 디코딩
+			
+	
+			let array = [];
+			for (let i = 0; i < decodImg.length; i++) {
+			  array.push(decodImg.charCodeAt(i));
+			}
+
+			const file = new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
+			const fileName = 'canvas_img_' + new Date().getMilliseconds() + '.jpg';
+			let formData = new FormData();
+			formData.append('file', file, fileName);
+			
+			$.ajax({
+				type: 'post',
+				url: '/web/mjon/msgcampain/insertEditImageAjax.do',
+				cache: false,
+				data: formData,
+				dataType:'json',
+				processData: false,
+				contentType: false,
+				async: false,
+				success: function (returnData, status) {
+					if(status == 'success'){
+						// imgFilePath 에 배열로 담아주기(이미지 순서대로)
+						//console.log(imgFilePath);
+						//imgFilePath.push(returnData.filefullPath);
+						myImgFileId.push(returnData.atchFileId);
+						
+					} else if(status== 'fail'){
+						alert(returnData.message);
+					}
+				},
+				error: function (e) { alert("이미지 업로드에 실패하였습니다."); console.log("ERROR : ", e); }
+			});
+			
+		} else {
+			//에디터 안거친 템플릿 이미지면 바로 src 때림
+			imgFilePath.push($(el).attr("src"));
+		}	
+	});
+	
+	if(myImgFileId.length > 0 && imgFileId.length > 0){ //기존 샘플 이미지와 이미지 에디터 둘다 사용한 경우
+		
+		var tempImgId = [];
+		
+		tempImgId.push(myImgFileId);
+		tempImgId.push(imgFileId);
+		form.imgFileId.value = tempImgId; 
+		
+	}else if(myImgFileId.length > 0){	//이미지 에디터에서 신규 등록한 이미지 
+		
+		form.imgFileId.value = myImgFileId; 
+		
+	}else{	//샘플 이미지 선택만 했을경우(이미지 에디터 사용 안했을때)
+		
+		form.imgFileId.value = imgFileId; 
+	}
+	
+	//광고 문자 내용 합쳐주기
+	if(adverYn == 'Y'){
+		
+		var adTxt = $('.ad_txt').text();
+		var denyTxt = $('.deny_txt').text();
+		var smsTxt = form.smsTxtArea.value;
+		
+		//var adverTxt = adTxt + '\n\n' + smsTxt + '\n\n' + denyTxt;
+		var adverTxt = smsTxt;
+		form.smsTxt.value = adverTxt;
+		
+	}else{
+		
+		var smsTxt = form.smsTxtArea.value;
+		form.smsTxt.value = smsTxt;
+		
+	}
+	
+	//문자 종류 설정(S:단문 , L:장문 , P:그림)
+	var photoSts = $('.delLi').length;
+	var conLeng = conByteLeng(form.smsTxt.value); // 내용 문자 입력 바이트 수 계산하기
+	
+	if(photoSts > 0){
+		
+		form.msgType.value = 'P';
+		
+	}else if(conLeng > 90){
+	
+		form.msgType.value = 'L';
+		
+	}else{
+		
+		form.msgType.value = 'S';
+		
+	}
+	
+	if(photoSts == '0' && conLeng == '0'){
+		
+		alert("문자내용을 입력해 주세요.");
+		return false;
+		
+	}
+	
+	var data = new FormData(form);
+	url = "/web/mjon/msgcampain/insertMyMsgDataAjax.do";
+	
+	$.ajax({
+        type: "POST",
+        url: url,
+        data: data,
+        dataType:'json',
+        async: false,
+        processData: false,
+        contentType: false,
+        cache: false,
+        success: function (returnData, status) {
+			if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+				if("fail"==returnData.result){
+					
+					alert(returnData.message);
+					return false;
+					
+				}else{
+					
+					alert("내 문자함에 저장되었습니다.");
+					
+					//내 문자함 탭 활성화 시키기
+					TabType2($('.tabType2 li').eq(3), '4');
+					var offset = $('.tabType2').offset();
+				    $('html, body').animate({scrollTop : offset.top-140}, 400);
+					
+					//최 하단 내문자함 탭 리스트 내용 불러오기
+					var sendData = $(document.myMsgForm).serializeArray();
+					$("#myMsgLoad").load("/web/mjon/msgcampain/selectMyMsgDataListAjax.do", sendData ,function(response, status, xhr){
+					});
+					
+				}
+			
+			} else if(status== 'fail'){
+				alert(returnData.message);
+			}
+		},
+        error: function (e) { alert("문자 저장에 실패하였습니다."); console.log("ERROR : ", e); }
+    });
+	
+}
+
+//내 문자함으로 탭이동
+function fnGoMyMsg(){
+	
+	//내 문자함 탭 활성화 시키기
+	TabType2($('.tabType2 li').eq(3), '4');
+	
+	var offset = $('.tabType2').offset();
+    $('html, body').animate({scrollTop : offset.top-140}, 400);
+	
+}
+
+//MJ_MSG_GROUP_DATA 누락데이터 체크
+function getMsgGroupDataErrorCheck() {
+	var isError = false;
+	
+	$.ajax({
+	    type: "POST",
+	    url: "/web/mjon/msgdata/selectMsgGroupNotExistInfoAjax.do",
+	    data: {},
+	    dataType:'json',
+	    async: false,
+	    success: function (data) {
+			if (data.isSuccess) { 
+				if (data.isError == true) {
+					isError = true;
+				}
+			} 
+		},
+	    error: function (e) {
+	    	
+	    }
+	});	
+
+	return isError;
+}
+
+function checkConf() {
+	var confCheck = false;
+	
+	$.ajax({
+		type: "POST",
+		url: "/web/mjon/conf/selectMjonMsgUseConfAjax.do",
+		data: {},
+		dataType:'json',
+		async: false,
+		success: function (returnData, status) {
+			if(returnData.result == "fail") {
+				console.log(returnData.message);
+			}else if(returnData.result == "success"){
+				confCheck = true;
+			}
+		}
+		,error: function (e) {console.log("ERROR : ", e); }
+	});	
+	
+	return confCheck;
+}
+
+//문자발송 처리 함수
+function fn_sendMsgData(){
+	
+	var candiNm = $("#candidateNm").val();
+	
+	if(candiNm == ""){
+		fn_candidateChk();
+		return false;
+	}
+	
+	
+	if(!checkConf()){	//문자온 conf-check
+		alert("현재 문자 발송하기 기능 점검 중입니다.\n\n1분 후 다시 시도해주세요.");
+		return false;
+	}
+	
+	var form = document.msgForm;
+
+	//회원 보유 잔액 비교
+	var totPriceOnly = stringReplaceAll(form.totPrice.value, ",", "");
+	var userMoneyOnly = stringReplaceAll(form.myPrice.value, ",", "");
+	if(parseFloat(userMoneyOnly) < parseFloat(totPriceOnly)){
+		alert("문자 발송에 필요한 회원님의 보유 잔액이 부족 합니다.");
+		return false;
+	}	
+	
+	var loginVO = '${LoginVO}';
+	var adverYn = $("input[name='send_adYn']").val();
+	var spamStatus = false;
+	var exceptSpamYn = $("#exceptSpamYn").val(); //금지어 필터링 예외 여부 - N 일 경우만 스팸 검사를 진행
+	
+	if(loginVO == "" || loginVO == null){
+		
+		alert("문자발송 서비스는 로그인 후 이용 가능합니다.");
+		return false;
+		
+	}
+	
+	if(form.callFromList.value == ""){
+		
+		alert("발신번호를 입력해 주세요.");
+		return false;
+		
+	}
+	
+	var titleStatus = form.title_status.value;
+	if(titleStatus == 'N'){//장문 제목 사용안함으로 선택시 제목에 있는 데이터 지워주기
+		
+		form.mmsSubject.value = "";
+		
+	}else{//장문 제목에 치환문자 포함된 경우 입력 못하도록 처리.
+		
+		var mmsSubject = form.mmsSubject.value;
+		if(getSpacialStringChk(mmsSubject)){
+			alert("문자 제목에는 치환문자(엑셀 내 *이름*, *1*, *2*, *3*, *4* 등)를 사용하실 수 없습니다.");
+			return false;
+		}
+		
+	}
+	
+	//문자내용 첫글자에 특수기호 포함 여부 체크
+	var strCont = form.smsTxtArea.value;
+	var rtnStr = strChinJpnCheck(strCont);
+	
+	//문자제목에 이모지가 있는지 체크
+	var titleStatusYn = $("input[name='title_status']:checked").val();
+	if(titleStatusYn == 'Y') {
+		if(!emojiCheck(form.mmsSubject.value)) return false;
+	}
+	
+	//문자내용에 이모지가 있는지 체크
+	if(!emojiCheck(strCont)) return false;
+	
+	if(rtnStr.length > 0){
+		
+		alert("입력하신 문구 중 \" " + rtnStr + " \" 는 일부 휴대폰에서 표기되지 않을 수 있습니다.");
+		
+	}
+	
+	if(imgFilePath.length == 0){ // 그림문자일 경우 내용이 없어도 됨 , 장문 문자일 경우만 문자내용 체크함
+		
+		if(form.smsTxtArea.value == ""){
+			
+			alert("문자 내용을 입력해 주세요.");
+			return false;
+			
+		}
+		
+	}
+	
+	//선거 문자 내용 합쳐주기
+	if(adverYn == 'Y'){
+		
+		var adTxt = $('.ad_txt').text();
+		var denyTxt = $('.deny_txt').html();
+		var smsTxt = form.smsTxtArea.value;
+		
+		//선거운동정보 하단 테스트내용 줄바꿈 처리해주기
+		denyTxt = denyTxt.replaceAll("<br>","\n");
+		denyTxt = denyTxt.replaceAll("<br/>","\n");
+		
+		var adverTxt = adTxt + "\n" + smsTxt + "\n" + denyTxt;
+		form.smsTxt.value = adverTxt;
+		
+	}else{
+		
+		var smsTxt = form.smsTxtArea.value;
+		form.smsTxt.value = smsTxt;
+		
+	}
+	
+	var chkCalltoCnt =  $("input[name=chkCallTo]").length;
+	
+	if(Number(chkCalltoCnt) == 0){
+		
+		alert("받는사람을 추가해 주세요.");
+		return false;
+	}
+	
+	
+	//수신번호 리스트 체크하기
+	var numCnt = 0;
+	var nameList = [];		//치환문자 이름
+	var phoneNum = [];	//받는사람
+	var rep1List = [];		//치환문자1
+	var rep2List = [];		//치환문자2
+	var rep3List = [];		//치환문자3
+	var rep4List = [];		//치환문자4
+	
+	var chkSts = $('input:checkbox[name="chkCallTo"]').is(':checked');
+	
+	if(!chkSts){
+		
+		alert("받는사람 연락처를 한 건 이상 선택해주세요.");
+		return false;
+		
+	}
+	
+	//받는사람 목록에서 체크된 연락처만 전달하도록 함.
+	$("input:checkbox[name='chkCallTo']:checked").each(function(){
+		
+		var callToNum = $(this).closest("div").next().text();
+		
+		if(!checkHpNum(callToNum)){
+			alert("선택한 연락처 목록에 잘못된 연락처가 있습니다. 연락처 번호 : " + callToNum + " 입니다.");
+			return false;
+		}else{
+			phoneNum.push(callToNum);
+		}
+		
+	});
+	
+	var reserYn = $("input[name=reserYn]:checked").val(); // 예약 발송 여부 확인
+	
+	if(reserYn == 'Y'){
+		
+		var date = $(".resDate").val();//form.msgResDate.value;
+		var hour = form.msgResHour.value;
+		var min = form.msgResMin.value;
+		
+		if(date == ""){
+			
+			alert("예약전송 날짜를 선택해 주세요.");
+			return false;
+			
+		}else{
+			
+			var now = new Date();
+			var reqDate = date + " " + hour + ":" + min + ":00";
+			var gapDate = getGapDayTime(date, hour, min);
+			
+			if(gapDate < 0){ // 음수이면 이전날짜, 크면 이후 날짜.
+				alert("예약 날짜는 현재 시간 이후의 날짜 및 시간을 선택해 주세요.");
+				return false;
+			}else{
+				form.reqDate.value = reqDate;	//예약일자 파라미터 저장
+			}
+		}
+
+	}else{
+		
+		form.reqDate.value = "";
+		
+	}
+	
+	var fileLinks = document.getElementsByName("fileLinks");
+	
+	var conLeng = conByteLeng($('#smsTxt').val()); // 내용 문자 입력 바이트 수 계산하기
+	
+	if(conLeng > 2000){
+		
+		alert("문자 내용은 2000byte를 넘을 수 없습니다.");
+		return false;
+		
+	}
+	
+	//엔터키로 문자 전송 바로 처리하기 : 엔터키와 엔터키 체크박스 둘다 조건 만족시 메시지 없이 전송처리
+	var enterChk = $("#enterChk").is(':checked');
+	if(!enterChk || !enterSts){
+		
+		if(!confirm("문자를 전송하시겠습니까?")){
+			return false;
+		}
+		
+	}
+	
+	//if(confirm("문자를 전송하시겠습니까?")){
+
+		imgFilePath = [];
+		$('.thumb_wrap').find('.thumb_img').each(function(idx, el) {
+			if($("#delLi"+idx).hasClass("Template")){
+				templateYn.push("Y");
+			} else {
+				templateYn.push("N");
+			}
+			
+			if($(el).hasClass("edit_y")) {
+				//이미지 변환
+				const imgBase64 = $(el).attr("src");
+				const decodImg = atob(imgBase64.split(',')[1]);  // base64~ 부분을 제외하고 데이터 디코딩
+				
+		
+				let array = [];
+				for (let i = 0; i < decodImg.length; i++) {
+				  array.push(decodImg.charCodeAt(i));
+				}
+
+				const file = new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
+				const fileName = 'canvas_img_' + new Date().getMilliseconds() + '.jpg';
+				let formData = new FormData();
+				formData.append('file', file, fileName);
+				
+				$.ajax({
+					type: 'post',
+					url: '/web/mjon/msgcampain/insertEditImageAjax.do',
+					cache: false,
+					data: formData,
+					dataType:'json',
+					processData: false,
+					contentType: false,
+					async: false,
+					success: function (returnData, status) {
+						if(status == 'success'){
+							// imgFilePath 에 배열로 담아주기(이미지 순서대로)
+							//console.log(imgFilePath);
+							imgFilePath.push(returnData.filefullPath);
+							imgFileId.push(returnData.atchFileId);
+							
+						} else if(status== 'fail'){
+							alert(returnData.message);
+						}
+					},
+					error: function (e) { alert("이미지 업로드에 실패하였습니다."); console.log("ERROR : ", e); }
+				});
+				
+			} else {
+
+				if(imgFilePath.length != imgFileId.length){
+					//에디터 안거친 템플릿 이미지면 바로 src 때림
+					imgFilePath.push($(el).attr("src"));
+				}
+				
+			}	
+		});
+		
+		form.imgFilePath.value = imgFilePath; // 저장한 이미지 경로 담아주기
+		form.callToList.value = phoneNum; //수신자번호 리스트 저장해주기
+		form.callFrom.value = removeDash(form.callFromList.value); // 발신번호 대쉬(-) 문자 없애주기
+		form.reserveYn.value = reserYn; // 즉시 / 예약 문자 선택 여부 
+		form.templateYn.value = templateYn;
+		form.imgFileId.value = imgFileId;
+		form.nameList.value = nameList;
+		form.rep1List.value = rep1List;
+		form.rep2List.value = rep2List;
+		form.rep3List.value = rep3List;
+		form.rep4List.value = rep4List;
+		
+		//총 결제금액 천단위 콤마 삭제 후 전송
+		var totPrice = form.totPrice.value;
+		totPrice = totPrice.replace(",","");
+		form.totPrice.value = totPrice;
+		
+		//문자내용이 입력된 경우 스팸 필터링 실행
+		if(!form.smsTxtArea.value == "" && exceptSpamYn == "N"){
+			
+			console.log(smsTxtArea);
+			var spmData = new FormData(form);
+			url = "/web/mjon/msgdata/selectSpamTxtChkAjax.do";
+			
+			$.ajax({
+		        type: "POST",
+		        url: url,
+		        data: spmData,
+		        dataType:'json',
+		        async: false,
+		        processData: false,
+		        contentType: false,
+		        cache: false,
+		        success: function (returnData, status) {
+					if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+						
+						if("fail" == returnData.result){
+							
+							alert(returnData.message);
+							return false;
+							
+						}else if("loginFail" == returnData.result){
+							
+							alert(returnData.message);
+							return false;
+								
+						}else if("spams" == returnData.result){
+							
+// 							var spmFilterTxt = returnData.spmFilterTxt;
+							spamStatus = true;
+							
+// 							form.spamKeyword.value = spmFilterTxt;
+							form.spamStatus.value='Y';
+						}else{
+							form.spamKeyword.value = '';
+							form.spamStatus.value='N';
+							
+						}
+						
+					} else if(status== 'fail'){
+						alert(returnData.message);
+						return false;
+					}
+				},
+		        error: function (e) { alert("문자 발송에 실패하였습니다."); console.log("ERROR : ", e); return false;}
+		    });
+			
+		}
+		
+		
+		//이벤트 진행중 회원의 경우 이벤트 잔여금액 비교 처리 필요.
+		//이벤트 캐시가 부족한 경우 이벤트 캐시로 발송 가능한 만큼만 이벤트 금액으로 발송 처리해줌.
+		//이 후 나머지 발송 건수는 이벤트 캐시가 아닌 일반 단가로 발송 처리를 진행 함.
+		var eventStatus = form.eventStatus.value;
+		
+		if(eventStatus == 'Y'){ //이벤트 진행 대상자이면 문자종류에 이벤트로 구분
+			
+			form.eventYn.value = "Y"; //이벤트문자 종류 설정
+			
+		}
+		
+		var eventRemainCash = parseFloat(form.eventRemainCash.value);
+		
+		if(eventStatus == 'Y'){
+			
+			if(parseFloat(eventRemainCash) < parseFloat(totPriceOnly)){
+				
+				if(confirm("고객님의 이벤트 캐시 잔액(" + eventRemainCash + "원) 부족으로 요청하신 문자("+numberWithCommas(phoneNum.length)+"건)를 모두 발송할 수 없습니다. 이벤트 캐시 초과 건에 대해서는 일반 단가를 적용하여 발송하시겠습니까?")){
+					
+					var smsTxtArea = $('#smsTxtArea').val();
+					var evnMsgType = $("#msgType").val();
+					var evnEachPrice = $("#eachPrice").val();	//form 에 저장된 이벤트 개별 단가 불러오기
+					var evnSendCnt = Math.floor(eventRemainCash / evnEachPrice);
+					var norEachPrice = 0;
+					var imgCnt = $("#imgCnt").val();	//그림 이미지 갯수
+					var txtReplYn = $("#txtReplYn").val();	//치환문자 포함 여부 
+					var evnPhoneNumCnt = Number($("#evnPhoneNumCnt").val());	//치환문자 체크하면서 단/장문 건수 카운팅하면서 이벤트 금액으로 발송가능한 수신자 갯수 정보
+					var myPrice = parseFloat($("#myPrice").val());	//회원보유 잔여 캐시 금액
+					
+					//수신목록 저장 배열 변수 
+					var evnPhoneNum = [];	//이벤트 단가 받는사람
+					var norPhoneNum = [];	//일반 단가 받는 사람
+					
+					//치환문자 포함 문자 저장 배열 변수(이벤트 문자 저장)
+					var evnName = [];
+					var evnRep1 = [];
+					var evnRep2 = [];
+					var evnRep3 = [];
+					var evnRep4 = [];
+					
+					//치환문자 포함 문자 저장 배열 변수(일반 문자 저장)
+					var norName = [];
+					var norRep1 = [];
+					var norRep2 = [];
+					var norRep3 = [];
+					var norRep4 = [];
+					
+					
+					/**
+					Desc:	1. 그림, 치환, 일반 문자에 대해서 각각 이벤트 단가로 전송할 리스트 와 일반단가로 전송할 리스트를 분리 하는 로직
+							2. 그림 및 일반 문자는 단순 이벤트 금액으로 보낼수 있는 건수를 계산하여 리스트[0] 부터 발송 건수만큼 추출하여 evnPhoneNum 배열에 입력 후 이벤트 금액으로 발송 진행
+							3. 이벤트 발송이 완료되면, 이벤트 건수를 제외한 나머지 건수를 norPhoneNum 배열에 입력 후 일반 금액으로 발송 진행
+							4. 일반 발송시에 전송 단가(eachPrice), 전체금액(totPrice) 등 변수 정보 변경
+							=====
+							5. 그림문자가 아닌 치환문자인 경우 치환 처리를 진행하면서 단문, 장문을 구분하고 이때 이벤트 금액에서 단문, 장문 가격을 차감하여 보낼 수량을 카운팅 함.
+							6. 치환 체크가 완료되면 치환시 나온 카운트 갯수만큼 이벤트 배열과 일반 배열에 분리처리 후 전송함.
+					Param Array : evnPhoneNum, norPhoneNum
+					function :  getNorEachPrice - 메세지 타입(msgType)에 따른 단문, 장문, 그림문자 개별 단가 금액 확인
+								sendMsgAjax 	- 문자 발송 요청 Ajax 처리
+					*/
+
+					//그림문자인 경우
+					if(imgCnt > 0){
+						
+						//이벤트 가격으로 전송 할 받는 사람 리스트 저장처리
+						for(var i=0; i< evnSendCnt; i++){
+							evnPhoneNum[i]= phoneNum[i];
+							
+							//그림문자에 치환문자가 포함된 경우
+							if(txtReplYn == 'Y'){
+								
+								evnPhoneNum[i] = phoneNum[i];
+								evnName[i] = nameList[i];
+								evnRep1[i] = rep1List[i];
+								evnRep2[i] = rep2List[i];
+								evnRep3[i] = rep3List[i];
+								evnRep4[i] = rep4List[i];
+								
+							}
+						}
+						
+						//일반 가격으로 전송 할 받는 사람 리스트 저장처리
+						for(var j=0; j < phoneNum.length - evnSendCnt; j++){
+							norPhoneNum[j]= phoneNum[j + evnSendCnt];
+							
+							//그림문자에 치환문자가 포함된 경우
+							if(txtReplYn == 'Y'){
+								
+								norPhoneNum[j]= phoneNum[j + evnSendCnt];
+								norName[j] = nameList[j + evnSendCnt];
+								norRep1[j] = rep1List[j + evnSendCnt];
+								norRep2[j] = rep2List[j + evnSendCnt];
+								norRep3[j] = rep3List[j + evnSendCnt];
+								norRep4[j] = rep4List[j + evnSendCnt];
+								
+							}
+							
+						};
+						
+					}else if(txtReplYn == 'Y'){//치환 문자가 있는 경우 , 그림문자에 치환이 있는 경우 그림문자 가격으로 발송
+						
+						//이벤트 가격으로 전송 할 받는 사람 리스트 저장처리
+						for(var i=0; i< evnPhoneNumCnt; i++){
+							evnPhoneNum[i] = phoneNum[i];
+							evnName[i] = nameList[i];
+							evnRep1[i] = rep1List[i];
+							evnRep2[i] = rep2List[i];
+							evnRep3[i] = rep3List[i];
+							evnRep4[i] = rep4List[i];
+							
+						}
+						
+						//일반 가격으로 전송 할 받는 사람 리스트 저장처리
+						for(var j=0; j < phoneNum.length - evnPhoneNumCnt; j++){
+							norPhoneNum[j]= phoneNum[j + evnPhoneNumCnt];
+							norName[j] = nameList[j + evnPhoneNumCnt];
+							norRep1[j] = rep1List[j + evnPhoneNumCnt];
+							norRep2[j] = rep2List[j + evnPhoneNumCnt];
+							norRep3[j] = rep3List[j + evnPhoneNumCnt];
+							norRep4[j] = rep4List[j + evnPhoneNumCnt];
+							
+						};
+						
+					}else{//치환문자 없는 경우 처리
+						
+						//이벤트 가격으로 전송 할 받는 사람 리스트 저장처리
+						for(var i=0; i< evnSendCnt; i++){
+							evnPhoneNum[i]= phoneNum[i];
+						}
+						
+						//일반 가격으로 전송 할 받는 사람 리스트 저장처리
+						for(var j=0; j < phoneNum.length - evnSendCnt; j++){
+							norPhoneNum[j]= phoneNum[j + evnSendCnt];
+						};
+					}
+						
+					var orgShortMsgCnt = $("#shortMsgCnt").val();	//단문 총 건수 백업
+					var orgLongMsgCnt = $("#longMsgCnt").val();		//장문 총 건수 백업
+					//이벤트 단가 문자 전송 처리 시작
+					if(evnPhoneNum.length > 0){
+						
+						form.callToList.value = evnPhoneNum; //수신자번호 리스트 저장해주기
+						form.totPrice.value = evnEachPrice * evnSendCnt;	//이벤트 단가 총 결제금액 셋팅해주기
+						form.eventStatus.value = 'Y';
+						form.eventYn.value = 'Y';
+						
+						var evnTotPrice = parseFloat(form.totPrice.value); 
+						
+						if(myPrice < evnTotPrice){
+						
+							alert("문자 발송에 필요한 회원님의 보유 잔액이 부족 합니다.");
+							return false;
+							
+						}else{
+							
+							myPrice = myPrice - evnTotPrice;
+							
+						}
+						
+						//치환문자가 있는 경우 변수 정보 담아주기(그림문자 아닌경우)
+						if(txtReplYn == 'Y' &&  imgCnt < 1){
+							
+							var evnShortMsgCnt = $("#evnShortMsgCnt").val();
+							var evnLongMsgCnt = $("#evnLongMsgCnt").val();
+							
+							form.shortMsgCnt.value = evnShortMsgCnt;
+							form.longMsgCnt.value = evnLongMsgCnt;
+							form.nameList.value = evnName;
+							form.rep1List.value = evnRep1;
+							form.rep2List.value = evnRep2;
+							form.rep3List.value = evnRep3;
+							form.rep4List.value = evnRep4;
+							
+						}else if(txtReplYn == 'Y' &&  imgCnt > 0){//치환문자가 있는 경우 변수 정보 담아주기(그림문자인 경우)
+							
+							form.nameList.value = evnName;
+							form.rep1List.value = evnRep1;
+							form.rep2List.value = evnRep2;
+							form.rep3List.value = evnRep3;
+							form.rep4List.value = evnRep4;
+							
+						}
+						
+						//이벤트 발송 실행 해주기
+						var form = document.msgForm;
+						
+						var data = new FormData(form);
+						url = "/web/mjon/msgcampain/sendMsgDataAjax.do";
+						
+						$.ajax({
+					        type: "POST",
+					        url: url,
+					        data: data,
+					        dataType:'json',
+					        async: true,
+					        processData: false,
+					        contentType: false,
+					        cache: false,
+					        success: function (returnData, status) {
+								if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+									if("fail" == returnData.result){
+										
+										alert(returnData.message);
+										return false;
+										
+									}else if("loginFail" == returnData.result){
+										
+										alert(returnData.message);
+										return false;
+											
+									}else if("smsLengFail" == returnData.result){
+										
+										alert(returnData.message);
+										return false;
+											
+									}else if("imgSourceFail" == returnData.result){
+										
+										$('.pop_msg_fails').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+										$('.pop_msg_fails .msg_text').html(returnData.message);
+										$('.mask').addClass('on');
+										
+									}else if("spamKeyWordFail" == returnData.result){//스팸 및 스미싱 단어가 들어간 문자 발송시 회원 이용정지 처리
+										
+										$('.pop_msg_spam').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+										$('.pop_msg_spam .msg_text').html(returnData.message);
+										$('.mask').addClass('on');
+										
+									}else if("statusFail" == returnData.result){
+										
+										alert(returnData.message);
+										//문자발송 URL Move
+										goMsgUrlMove();
+										return false;
+										
+									}else{
+										
+										var smsCnt = returnData.resultSts;
+										var blockCnt = returnData.resultBlockSts;
+										
+										//이벤트 발송 처리가 완료 되면 나머지 일반 캐시로 발송할 문자 처리를 진행해 준다.
+										var norPhoneNumCnt = norPhoneNum.length; 
+										if(norPhoneNumCnt > 0){
+											
+											var norEachPrice = getNorEachPrice(evnMsgType); //일반 개별 단가 금액 셋팅해주기
+											
+											form.callToList.value = norPhoneNum;	//수신자번호 리스트 저장해주기
+											form.eachPrice.value =  norEachPrice;	//일반 개별 단가 금액 셋팅해주기
+											form.totPrice.value = norEachPrice * norPhoneNumCnt;	//일반 단가 총 결제 금액 셋팅해주기
+											form.sPrice.value = $("#norsPrice").val();
+											form.mPrice.value = $("#normPrice").val();
+											form.pPrice.value = $("#norpPrice").val();
+											form.p2Price.value = $("#norp2Price").val();
+											form.p3Price.value = $("#norp3Price").val();
+											form.eventStatus.value = 'N';
+											form.eventYn.value = 'N';
+											
+											var norTotPrice = parseFloat(form.totPrice.value); 
+											
+											if(myPrice < norTotPrice){
+											
+												var failMsg = "이벤트 캐시 잔액으로 발송한 문자("+smsCnt+"건)의 발송이 완료되었으나 일반 문자 발송("+norPhoneNumCnt+"건)에 필요한 회원님의 보유 잔액이 부족 합니다.";
+												
+												$('.loading_layer').removeClass('active');
+
+												$('.pop_msg_fails').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+												$('.pop_msg_fails .msg_text').html(failMsg);
+												$('.mask').addClass('on');
+												
+												return false;
+												
+											}
+											
+											//치환문자가 있는 경우 변수 정보 담아주기(그림문자가 아닌경우)
+											if(txtReplYn == 'Y' &&  imgCnt < 1){
+												
+												//치환문자 단/장문 혼용된 경우 각 타입별 건수를 재 계산해준다.
+												//총 단/장문 각각 건수에서 이벤트로 발송한 건수를 빼준다.
+												var evnShortMsgCnt = $("#evnShortMsgCnt").val();
+												var evnLongMsgCnt = $("#evnLongMsgCnt").val();
+												
+												var shortMsgCnt = Number(orgShortMsgCnt) - Number(evnShortMsgCnt);
+												var longMsgCnt = Number(orgLongMsgCnt) - Number(evnLongMsgCnt);
+												
+												
+												//계산 값이 음수로 나오는 경우 0건으로 간주한다.
+												if(shortMsgCnt <= 0){
+													
+													shortMsgCnt = 0;
+													
+												}
+												
+												if(longMsgCnt <= 0){
+													
+													longMsgCnt = 0;
+													
+												}
+												
+												form.shortMsgCnt.value = shortMsgCnt;
+												form.longMsgCnt.value = longMsgCnt;
+												
+												form.nameList.value = norName;
+												form.rep1List.value = norRep1;
+												form.rep2List.value = norRep2;
+												form.rep3List.value = norRep3;
+												form.rep4List.value = norRep4;
+												
+											}else if(txtReplYn == 'Y' &&  imgCnt > 0){//치환문자가 있는 경우 변수 정보 담아주기(그림문자인 경우)
+												
+												form.nameList.value = norName;
+												form.rep1List.value = norRep1;
+												form.rep2List.value = norRep2;
+												form.rep3List.value = norRep3;
+												form.rep4List.value = norRep4;
+												
+											}
+											
+											
+											sendMsgAjax(smsCnt, blockCnt);
+										}
+										
+									}
+									
+								} else if(status== 'fail'){
+									alert(returnData.message);
+								}
+							},
+							beforeSend : function(xmlHttpRequest) {
+					        	//로딩창 show
+					        	$('.loading_layer').addClass('active');				
+							},	        	        
+					        complete : function(xhr, textStatus) {
+					        	//로딩창 hide
+					        	//$('.loading_layer').removeClass('active');
+							},	      			
+					        error: function (e) { alert("문자 발송에 실패하였습니다."); console.log("ERROR : ", e); }
+					    });
+						
+					}else{
+						
+						//이벤트 건수로 발송 할 수 없는 경우 일반 캐시 단가로 발송처리하기
+						if(norPhoneNum.length > 0){
+							
+							form.callToList.value = norPhoneNum; //수신자번호 리스트 저장해주기
+							form.eachPrice.value = getNorEachPrice(evnMsgType); //일반 개별 단가 금액 셋팅해주기
+							form.sPrice.value = $("#norsPrice").val();
+							form.mPrice.value = $("#normPrice").val();
+							form.pPrice.value = $("#norpPrice").val();
+							form.p2Price.value = $("#norp2Price").val();
+							form.p3Price.value = $("#norp3Price").val();
+							form.eventStatus.value = 'N';
+							form.eventYn.value = 'N';
+							
+							sendMsgAjax(0,0);
+							
+						}else{
+							
+							alert("문자 전송 중 오류가 발생하였습니다.!!");
+							return false;
+							
+						}
+						
+					}
+					
+					return false;
+				}else{
+					
+					return false;
+					
+				}
+				
+			}else{
+				
+				//발송 Ajax 호출해주기
+				sendMsgAjax(0,0);
+				
+			}
+			
+		}else{
+			
+			//발송 Ajax 호출해주기
+			sendMsgAjax(0,0);
+			
+		}
+		
+	//}
+	
+}
+
+
+//이벤트가 아닌 일반 개별 단가 셋팅해주기
+function getNorEachPrice(evnMsgType){
+	
+	var norEachPrice = 0;
+	var evnImgCnt = $("#imgCnt").val();
+	
+	//일반 단가로 변경해주기
+	if(evnMsgType == '4'){
+		
+		norEachPrice = $("#norsPrice").val();
+		console.log("norEachPrice Short::: "+norEachPrice);
+		
+	}else if(evnMsgType == '6'){
+		
+		if(evnImgCnt == 0){//장문 가격
+			
+			norEachPrice = $("#normPrice").val();
+			console.log("norEachPrice Long ::: "+norEachPrice);
+			
+		}else if(evnImgCnt == 1){
+			
+			norEachPrice = $("#norpPrice").val();
+			console.log("norEachPrice p1 ::: "+norEachPrice);
+			
+		}else if(evnImgCnt == 2){
+			
+			norEachPrice = $("#norp2Price").val();
+			console.log("norEachPrice p2 ::: "+norEachPrice);
+			
+		}else if(evnImgCnt == 3){
+			
+			norEachPrice = $("#norp3Price").val();
+			console.log("norEachPrice p3 ::: "+norEachPrice);
+			
+		}
+		
+	}
+	
+	return norEachPrice;
+}
+
+
+function sendMsgAjax(paramSmsCnt, paramBlockCnt){
+	
+	var form = document.msgForm;
+	var reserYn = $("#reserveYn").val();
+	
+	var data = new FormData(form);
+	url = "/web/mjon/msgcampain/sendMsgTWDataAjax.do";
+	
+	$.ajax({
+        type: "POST",
+        url: url,
+        data: data,
+        dataType:'json',
+        async: true,
+        processData: false,
+        contentType: false,
+        cache: false,
+        success: function (returnData, status) {
+			if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
+				if("fail" == returnData.result){
+					
+					alert(returnData.message);
+					return false;
+					
+				}else if("loginFail" == returnData.result){
+					
+					alert(returnData.message);
+					return false;
+						
+				}else if("smsLengFail" == returnData.result){
+					
+					alert(returnData.message);
+					return false;
+						
+				}else if("imgSourceFail" == returnData.result){
+					
+					$('.pop_msg_fails').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+					$('.pop_msg_fails .msg_text').html(returnData.message);
+					$('.mask').addClass('on');
+					
+				}else if("spamKeyWordFail" == returnData.result){//스팸 및 스미싱 단어가 들어간 문자 발송시 회원 이용정지 처리
+					
+					$('.pop_msg_spam').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+					$('.pop_msg_spam .msg_text').html(returnData.message);
+					$('.mask').addClass('on');
+					
+				}else if("statusFail" == returnData.result){
+					
+					alert(returnData.message);
+					//문자발송 URL Move
+					goMsgUrlMove();
+					return false;
+					
+				}else{
+					
+					var smsCnt = Number(returnData.resultSts);
+					var blockCnt = Number(returnData.resultBlockSts);
+					
+					smsCnt = Number(smsCnt) + Number(paramSmsCnt);
+					blockCnt = Number(blockCnt) + Number(paramBlockCnt);
+					
+					if((smsCnt + blockCnt) == 0){
+						
+						$('.pop_msg_spam').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+						$('.pop_msg_spam .msg_text').html("문자 발송(예약)에 실패하였습니다.<br/> 다시 시도해주세요. <br/>* 정상적으로 발송 시도하였으나 실패하신 경우 혹시 문자내용에 사용불가 이모지 <br/>또는 복사-붙여넣기로 인한 보이지 않는 특수문자가 포함되었는지 확인 후 다시 시도해주세요.");
+						$('.mask').addClass('on');
+						
+					}else{
+						
+						/* $('.pop_msg_success').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
+						
+						//예약발송 건의 경우 결과 팝업 문구 변경
+						if(reserYn == 'Y'){
+							$('.pop_msg_success .msg_text').html("예약 성공 : <strong>"+ smsCnt + "</strong>건,수신거부 : <span>" + blockCnt + "</span>건의<br>문자가 예약 되었습니다.");
+						}else{
+							$('.pop_msg_success .msg_text').html("발송 성공 : <strong>"+ smsCnt + "</strong>건,수신거부 : <span>" + blockCnt + "</span>건의<br>문자가 발송 되었습니다.");
+						}
+						
+						$('.mask').addClass('on'); */
+						
+						//문자 예약 및 발송이 완료되면 토스트 메세지 띄워 주기
+						if(reserYn == 'Y'){
+							publishCommon.toastsUtil('문자 예약이 완료되었습니다.','active','success');
+						}else{
+							publishCommon.toastsUtil('문자 발송이 완료되었습니다.','active','success');
+						}
+						
+						//발송이 완료되면 발송 금액 표시를 0으로 변경해 준다.
+						$("#totalPriceTxt").text("0");
+						
+						//받는사람 리스트 새로 갱신해주기
+						document.callToForm.pageIndex.value = 1;
+						addTWCallToInfo();
+						
+					}
+					
+				}
+				
+			} else if(status== 'fail'){
+				alert(returnData.message);
+			}
+		},
+		beforeSend : function(xmlHttpRequest) {
+        	//로딩창 show
+        	$('.loading_layer').addClass('active');				
+		},	        	        
+        complete : function(xhr, textStatus) {
+        	//로딩창 hide
+        	$('.loading_layer').removeClass('active');
+		},	      			
+        error: function (e) { alert("문자 발송에 실패하였습니다."); console.log("ERROR : ", e); }
+    });
+	
+}
+
+
+function linkPage(pageNo){
+	fnLetterListAjax(pageNo);
+}
+
+
+function linkPhoPage(pageNo){
+	fnPhotoListAjax(pageNo);
+}
+
+function myMsgPage(pageNo){
+	fnMyMsgListAjax(pageNo);
+}
+
+function fnMyMsgCheckDelete(){
+	
+	var msgId = [];
+	if($("input:checkbox[name='myMsgDel']").is(":checked")==false){
+		alert("선택된 항목이 없습니다.");
+		return;
+	}
+	
+	$("input:checkbox[name='myMsgDel']:checked").each(function(index){
+		
+		msgId[index] = $(this).val();
+		
+	});
+	
+	if(msgId.length > 0){
+		
+		document.myMsgForm.msgIdList.value = msgId;
+		var sendData =  $(document.myMsgForm).serializeArray();
+		
+		$("#myMsgLoad").load("/web/mjon/msgcampain/deleteMyMsgDataListAjax.do", sendData ,function(response, status, xhr){
+			
+			//문자 내용 스크롤 적용
+			/* $(".msg_cont").mCustomScrollbar({
+				axis: 'y',
+				scrollbarPosition: "inside",
+				theme: "dark",
+				autoHideScrollbar: false
+			}); */
+			
+		});
+		
+	}else{
+		
+		alert("삭제할 문자를 선택해 주세요.");
+		return false;
+		
+	}
+	
+}
+
+//문자 샘플 2줄, 4줄 보기 기능 
+function fnLPageUnit(){
+	
+	var form = document.letterForm;
+	var pageUnit = form.LPageUnit.value;
+	
+	form.pageUnit.value = pageUnit;
+	fnLetterListAjax();
+	
+}
+
+//그림문자 샘플 2줄, 4줄 보기 기능 
+function fnPhPageUnit(){
+	
+	var form = document.letterForm;
+	var pageUnit = form.PhPageUnit.value;
+	
+	form.pageUnit.value = pageUnit;
+	fnPhotoListAjax();
+	
+}
+
+//그림문자 샘플 2줄, 4줄 보기 기능 
+function fnPhPageUnit(){
+	
+	var form = document.letterForm;
+	var pageUnit = form.PhPageUnit.value;
+	
+	form.pageUnit.value = pageUnit;
+	fnPhotoListAjax();
+	
+}
+
+function fnMsgPageUnit(){
+	
+	var form = document.myMsgForm;
+	var pageUnit = form.msgPageUnit.value;
+	
+	form.pageUnit.value = pageUnit;
+	fnMyMsgListAjax();
+	
+}
+
+function fnMyMsgSearchListOrd(){
+	
+	var form = document.myMsgForm;
+	var sortOrd = form.searchSortOrd.value;
+	
+	if(sortOrd == 'desc'){
+		
+		form.searchSortOrd.value = 'asc';
+		$('#sortCnd').text('등록순');
+		
+	}else{
+		
+		form.searchSortOrd.value = 'desc';
+		$('#sortCnd').text('최근순');
+		
+	}
+	
+	//내문자함 내용 검색하기
+	fnMyMsgSearchListAjax(1);
+	
+}
+
+function msgSuccessClose(obj){
+	$(obj).closest('.pop_msg_success').attr('style','');
+	//문자발송 URL Move
+	goMsgUrlMove();
+	//$('html').scrollTop(0);
+}
+
+function msgFailsClose(obj){
+	$(obj).closest('.pop_msg_fails').attr('style','');
+}
+
+function msgSpamClose(obj){
+	$(obj).closest('.pop_msg_spam').attr('style','');
+	//location.href="/web/uat/uia/actionLogout.do";
+}
+
+function msgResultLink(){
+	var reserYn = $("input[name=reserYn]:checked").val(); // 예약 발송 여부 확인
+	if(reserYn == 'Y'){
+		
+		location.href="/web/mjon/reservmsg/selectReservMsgView.do";
+		
+	}else{
+		
+		location.href="/web/mjon/msgsent/selectMsgSentView.do";
+		
+	}
+	
+}
+
+//START
+//맞춤제작 요청 JSPark => 2023.02.21 추가
+//맞춤제작 등록 Popup 
+function customPopup(){
+	$("#customPopup").load("/web/mjon/custom/selectMsgCustomPopupAjax.do", "" ,function(response, status, xhr){
+		popupImgList(1);
+	});
+}
+
+function openMsgCustomPopup() {
+	if(loginVO == "" || loginVO == null){
+		alert("로그인 후 이용이 가능합니다.");
+		return false;
+	} else {
+		$("#customPopupOpen").trigger("click");
+	}
+	$("#customType04").hide();
+	popCustomScrT=$(window).scrollTop();
+	popScrTarget();
+}
+
+$(window).on('load',function(){
+	setTimeout(function(){
+		popScrTarget();
+	},500);
+});
+
+function popScrTarget(){
+	var closeTarget=$('.custom_layer .tooltip-close');
+	closeTarget.attr('onclick','popScrCloseSetting();');
+}
+
+function popScrCloseSetting(){
+	setTimeout(function(){
+		$(window).scrollTop(popCustomScrT);	
+	},1);
+}
+//END
+</script>
+	<div class="tooltip-wrap">
+		<!-- 문자발송 성공 레이어팝업 -->
+		<div class="popup-com pop_msg_success">
+			<div class="popup_heading">
+				<p>문자 전송 결과</p>
+				<button type="button" class="tooltip-close" onclick="msgSuccessClose(this);"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+			</div>
+			<div class="layer_in">
+				<div class="msg_text">발송성공 : <strong>1</strong> 건, 수신거부 : <span>0</span>건의<br>문자가 발송 되었습니다.</div>
+			</div>
+			<div class="popup_btn">
+				<!-- <button type="button" onclick="msgResultLink(); return false;">문자 발송결과 바로가기</button>      -->                 
+				<button type="button" class="tooltip-close" onclick="msgSuccessClose(this);">다음 20건</button>                      
+			</div>
+		</div>
+	</div>
+	<div class="tooltip-wrap">
+		<!-- 문자발송 실패 레이어팝업 -->
+		<div class="popup-com pop_msg_fails">
+			<div class="popup_heading">
+				<p>문자 전송 결과</p>
+				<button type="button" class="tooltip-close" onclick="msgFailsClose(this);"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+			</div>
+			<div class="layer_in">
+				<div class="msg_text">발송성공 : <strong>1</strong> 건, 수신거부 : <span>0</span>건의<br>문자가 발송 되었습니다.</div>
+			</div>
+			<div class="popup_btn">
+				<button type="button" class="tooltip-close" onclick="msgFailsClose(this);">확인</button>                      
+			</div>
+		</div>
+	</div>
+	<div class="tooltip-wrap">
+		<!-- 문자발송 스팸 이용정지 레이어팝업 -->
+		<div class="popup-com pop_msg_spam">
+			<div class="popup_heading">
+				<p>문자 전송 결과</p>
+				<button type="button" class="tooltip-close" onclick="msgSpamClose(this);"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+			</div>
+			<div class="layer_in">
+				<div class="msg_text"></div>
+			</div>
+			<div class="popup_btn">
+				<button type="button" class="tooltip-close" onclick="msgSpamClose(this);">확인</button>                      
+			</div>
+		</div>
+	</div>
+    <div class="inner">
+        <!-- send top -->
+        <div class="send_top">
+            <!-- tab button -->
+            <ul class="tabType1">
+                <li class="tab"><button type="button" onclick="javascript:fnMsgDataView(); return false;">단체문자(자동동보문자)</button></li>
+                <li class="tab active">
+                	<button type="button">20건 문자(수동문자)</button>
+                </li>
+            </ul><!--// tab button -->
+			<!-- tab content1 -->
+			<!-- <span id="contentArea"></span> -->
+			<div class="top_content current election contentArea" id="tab1_1" style="min-height: 555px;"></div>
+			
+			<!-- tab content2 -->
+			<!-- <span id="contentExcelArea"></span> -->
+			<!-- <div class="top_content current get_excel contentExcelArea" id="tab1_2"></div> -->
+		</div><!--// send top -->
+	<!-- send bottom -->
+	<div class="send_bottom">
+		<!-- tab button -->
+		<ul class="tabType2 selectedTab">
+			<li class="tab active"><button type="button" onclick="TabType2(this,'1');">문자 샘플</button></li>
+			<li class="tab"><button type="button" onclick="TabType2(this,'2');">그림문자 샘플</button></li>
+			<li class="tab"><button type="button" onclick="TabType2(this,'3');">지도/약도 추가</button></li>
+			<li class="tab"><button type="button" onclick="TabType2(this,'4');">내 문자함</button></li>
+		</ul>
+		<!--// tab button -->
+		<!-- tab content1 -->
+		<form id="letterForm" name="letterForm" method="post">
+			<input type="hidden" id="letterType" name="letterType" value="<c:out value='${letterVO.letterType}'/>"/>
+			<input type="hidden" id="memberType" name="memberType" value="<c:out value='${letterVO.memberType}'/>"/>
+			<input type="hidden" id="categoryCode" name="categoryCode" value="<c:out value='${letterVO.categoryCode}'/>"/>
+			<input type="hidden" id="hashTag" name="hashTag" value="<c:out value='${letterVO.hashTag}'/>"/>
+			<input type="hidden" id="pageIndex" name="pageIndex" value="<c:out value='${letterVO.pageIndex}' default='1' /> "/>
+			<input type="hidden" id="pageUnit" name="pageUnit" value="<c:out value='${letterVO.pageUnit}'/>"/>
+			<input type="hidden" id="upperCateNo" name="upperCateNo" value=""/>
+			<input type="hidden" id="bestCategory" name="bestCategory" value="<c:out value='${letterVO.bestCategory}'/>"/>
+		
+			<div class="search_sample">
+				<input type="text" id="searchKeyword" name="searchKeyword" value="<c:out value='${letterVO.searchKeyword}'/>" placeholder="문자샘플 검색하기" onfocus="this.placeholder=''" onblur="this.placeholder='문자샘플 검색하기'" maxlength="10">
+				<button class="btnSearchF"><img src="/publish/images/search02.png" alt=""></button>
+			</div>
+			<!-- tab content1 -->
+			<div class="bottom_content current" id="tab2_1">
+				<div class="area_tabs">
+					<div class="top_tab">
+						<!-- <div class="tab_depth1 tDep1_mType">
+							<a href="#none" class="on" value="">전체</a>
+							<a href="#none" value="B">기업</a>
+							<a href="#none" value="P">개인</a>
+							<div class="on_active">전체</div>
+						</div> -->
+						<div class="tab_depth2 tDep1_letType">
+							<a href="#none" class="on" value="S">단문문자</a>
+							<a href="#none" value="L">장문문자</a>
+						</div>
+						<select name="LPageUnit" id="LPageUnit" class="selType2" onChange="fnLPageUnit(); return false;">
+							<option value="10">2줄보기</option>
+							<option value="20">4줄보기</option>
+							<option value="30">6줄보기</option>
+						</select>
+						<div class="customReq">
+							<%-- 맞춤제작 요청 JSPark => 2023.02.21 추가 --%>
+							<%--
+							<input type="hidden" id="customPopupOpen" data-tooltip="popup01">
+							<button type="button" onclick="openMsgCustomPopup(); return false;"><i></i>맞춤제작 요청</button>					
+							--%>	
+							<button type="button" onClick="location.href='/web/mjon/custom/selectMsgCustomView.do'"><i></i>맞춤제작 요청</button>
+						</div>
+					</div>
+					<div class="bottom_tab">
+						<div class="tab_depth3 tDep1_cateCode">
+							<a href="#none" class="on cateAll" value="">All</a>
+							<a href="#none" value="best">BEST</a>
+							<c:forEach var="cateList" items="${cateCodeList}" varStatus="status">
+								<a href="#none" value="<c:out value='${cateList.cateCode}'/>"><c:out value="${cateList.cateNm}"/></a>
+							</c:forEach>
+						</div>
+						<div class="tab_depth4 tDep1_threeCateCode" id="tDep1_depThrCateCode"> <!-- 해쉬태그 삭제 및 하위 카테고리 추가로 인해 class="tDep1_hashTag" 삭제 -->
+							<%-- <a href="#none" class="on hashAll" value="">전체</a>
+							<c:forEach var="hashList" items="${hashTagList}" varStatus="status">
+								<a href="#none" value="${hashList.hashNm}">#<c:out value="${hashList.hashNm}"/></a>
+							</c:forEach> --%>
+						</div>
+					</div>
+				</div>
+				<div id="letterLoad">
+				</div>
+			</div><!--// tab content1 -->
+			<!--// tab content2 -->
+			<div class="bottom_content" id="tab2_2">
+				<div class="area_tabs">
+					<div class="top_tab">
+						<!-- <div class="tab_depth1 tDep2_mType">
+							<a href="#none" class="on" value="">전체</a>
+							<a href="#none" value="B">기업</a>
+							<a href="#none" class="on" value="P">개인</a>
+							<div class="on_active">전체</div>
+						</div> -->
+						<div class="tab_depth2 tDep2_letType">
+							<a href="#none" class="on" value="P">그림문자</a>
+						</div>
+						<select name="PhPageUnit" id="PhPageUnit" class="selType2" onChange="fnPhPageUnit(); return false;">
+							<option value="10">2줄보기</option>
+							<option value="20">4줄보기</option>
+							<option value="30">6줄보기</option>
+						</select>
+						<div class="customReq">
+							<%-- 맞춤제작 요청 JSPark => 2023.02.21 추가 --%>
+							<%--
+							<input type="hidden" id="customPopupOpen" data-tooltip="popup01">
+							<button type="button" onclick="openMsgCustomPopup(); return false;"><i></i>맞춤제작 요청</button>					
+							--%>	
+							<button type="button" onClick="location.href='/web/mjon/custom/selectMsgCustomView.do'"><i></i>맞춤제작 요청</button>
+						</div>
+					</div>
+					<div class="bottom_tab">
+						<div class="tab_depth3 tDep2_cateCode">
+							<a href="#none" class="on cateAll" value="">All</a>
+							<a href="#none" value="best">BEST</a>
+							<c:forEach var="cateList" items="${cateCodeList}" varStatus="status">
+								<a href="#none" value="<c:out value='${cateList.cateCode}'/>"><c:out value="${cateList.cateNm}"/></a>
+							</c:forEach>
+						</div>
+						<div class="tab_depth4 tDep2_threeCateCode" id="tDep2_depThrCateCode"><!-- 해쉬태그 삭제 및 하위 카테고리 추가로 인해 class="tDep2_hashTag" 삭제 -->
+							<!-- 하위 카테고리(3뎁스)로 대체 -->
+							<%-- <a href="#none" class="on hashAll" value="">전체</a>
+							<c:forEach var="hashList" items="${hashTagList}" varStatus="status">
+								<a href="#none" value="${hashList.hashNm}">#<c:out value="${hashList.hashNm}"/></a>
+							</c:forEach> --%>
+						</div>
+					</div>
+				</div>
+				<div id="photoLoad">
+			    </div>
+				<!-- pagination -->
+			</div><!--// tab content2 -->
+		</form>
+		
+		<!--tab content3 -->
+		<div class="bottom_content" id="tab2_3">
+			<div class="map_search">
+				<label for="" class="label"></label>
+				<div class="mapWrap">
+					<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
+					<script type="text/javascript" src="//dapi.kakao.com/v2/maps/sdk.js?appkey=7fc7b80a3e32ac964da92f6aa3d6000d&libraries=services"></script>
+					<input type="text" id="sample5_address" placeholder="도로명 또는 지번을 입력해주세요." onfocus="this.placeholder=''" onblur="this.placeholder='도로명 또는 지번을 입력해주세요.'">
+					<button type="button" class="btnType map_check" onclick="sample5_execDaumPostcode()">확인</button>
+					<button type="button" class="btnType map_add" onclick="insertajax();">약도링크 추가</button>
+					<p><span class="vMiddle">*</span> 지도링크는 입력메시지 끝부분에 추가됩니다.</p>
+					<div id="map" style="width:100%;height:450px; margin-top: 10px;">&nbsp;</div>
+					
+					<div class="mapInfo">
+					</div>
+				</div>
+			</div>
+			<script>
+			    var mapContainer = document.getElementById('map'), // 지도를 표시할 div
+			        mapOption = {
+			            center: new daum.maps.LatLng(37.613898152040385, 127.15319231152851), // 지도의 중심좌표
+			            level: 5 // 지도의 확대 레벨
+			        };
+			
+			    //지도를 미리 생성
+			    var map = new daum.maps.Map(mapContainer, mapOption);
+			    //주소-좌표 변환 객체를 생성
+			    var geocoder = new daum.maps.services.Geocoder();
+			    //마커를 미리 생성
+			    var marker = new daum.maps.Marker({
+			        position: new daum.maps.LatLng(37.613898152040385, 127.15319231152851),
+			        map: map
+			    });
+			    var testcoords = new daum.maps.LatLng(37.613898152040385, 127.15319231152851);
+			    setTimeout(function(){ 
+			    	map.relayout();
+			    	map.setCenter(testcoords);
+			    }, 5000);
+			    
+				//lat 위도 lng 경도
+			    var paramLat;
+			    var paramLng;
+			    
+			    function sample5_execDaumPostcode() {
+			        new daum.Postcode({
+			            oncomplete: function(data) {
+			                var addr = data.address; // 최종 주소 변수
+			
+			                // 주소 정보를 해당 필드에 넣는다.
+			                document.getElementById("sample5_address").value = addr;
+			                // 주소로 상세 정보를 검색
+			                geocoder.addressSearch(data.address, function(results, status) {
+			                    // 정상적으로 검색이 완료됐으면
+			                    if (status === daum.maps.services.Status.OK) {
+			
+			                        var result = results[0]; //첫번째 결과의 값을 활용
+			
+			                        // 해당 주소에 대한 좌표를 받아서
+			                        var coords = new daum.maps.LatLng(result.y, result.x);
+			                        // 지도를 보여준다.
+			                        mapContainer.style.display = "block";
+			                        map.relayout();
+			                        // 지도 중심을 변경한다.
+			                        map.setCenter(coords);
+			                        // 마커를 결과값으로 받은 위치로 옮긴다.
+			                        marker.setPosition(coords)
+			                        paramLat = result.y;
+			                        paramLng = result.x;
+			                        
+			                    }
+			                });
+			            }
+			        }).open({
+			        	q: document.getElementById("sample5_address").value
+			        });
+			    }
+			    
+			    function insertajax(){
+			    	var mapInsertConfirm = confirm('약도를 추가하시겠습니까?');
+			    	
+			    	if(mapInsertConfirm){
+				    	$.ajax({
+				            cache : false,
+				            url : "<c:url value='/MapUrlInsertAjax.do'/>", 
+				            type : 'POST', 
+				            data : {
+				            	"mapLat" : paramLat,
+				            	"mapLng" : paramLng
+				            },
+				            dataType:'json',
+				            success : function(returnData, status){
+				    			if(status == "success") {
+				    				if (returnData.url != 0) {
+				    					var smsTxttmp = $('#smsTxtArea').val();
+				    					
+				    					/* document.getElementById("testarea").value = returnData.url + "/MapUrl.do?seq=" + returnData.seq; */
+				    					$('#smsTxtArea').val(smsTxttmp+returnData.url + "/MapUrl.do?seq=" + returnData.seq);
+				    					
+				    					smsTxttmp = $('#smsTxtArea').val();
+				    					
+				    					fnByteString(smsTxttmp);
+				    				}
+				    			}else{ alert("ERROR!");return;} 
+				    		},
+				    
+				            error : function(request , status, error){
+				    			alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
+				    			
+				            }
+				        });
+			    	}
+			    	else{
+			    		alert("취소되었습니다.");
+			    	}
+			    } 
+			</script>
+		</div><!--// tab content3 -->
+		<!-- tab content4 -->
+		<form id="myMsgForm" name="myMsgForm" method="post">
+			<input name="pageIndex" type="hidden" value="1"/>
+			<input name="msgIdList" type="hidden" value=""/>
+			<input name="pageUnit" type="hidden" value=""/>
+			<input name="searchSortOrd" type="hidden" value="desc"/>
+			<input name="msgKind" type="hidden" value="C"/>
+			<div class="bottom_content" id="tab2_4">
+				<div class="search_wrap clearfix">
+		            <div class="btn_left">
+		                    <span>· 기간</span>
+		                    <div class="calendar_wrap">
+								<input type="text" class="startDate inp calendar" title="검색 시작일" id="startDate" name="myMsgStDt" value="" data-datecontrol="true">
+								<span class="dateEtc">~</span>
+								<input type="text" class="endDate inp calendar" title="검색 종료일" id="endDate" name="myMsgEndDt" value="" data-datecontrol="true">
+							</div>
+		                    <div class="search">
+		                        <label for="searchWord" class="label"></label>
+		                        <input type="text" id="searchWord" name="searchKeyword" placeholder="내 문자함 검색" onfocus="this.placeholder=''" onblur="this.placeholder='내보관함 검색'" maxlength="10">
+		                    <button type="button" class="btnType btnType2" onclick="javascript:fnMyMsgSearchListAjax(1); return false;">검색</button>
+		                </div>
+		            </div>
+		            <div class="btn_right">
+		                <button type="button" id="sortOrd" name="sortOrd" onClick="javascript:fnMyMsgSearchListOrd(); return false;"><span id="sortCnd">최근순</span><i></i></button>
+		                <select name="msgType" id="msgType1" class="selType2" onChange="fnMyMsgSearchListAjax(1); return false;">
+		                    <option value="">전체보기</option>
+		                    <option value="S">단문문자</option>
+		                    <option value="L">장문문자</option>
+		                    <option value="P">그림문자</option>
+		                </select>
+		                <select name="msgPageUnit" id="msgPageUnit" class="selType2" onChange="fnMsgPageUnit(); return false;">
+		                    <option value="10">2줄보기</option>
+		                    <option value="20">4줄보기</option>
+		                    <option value="30">6줄보기</option>
+		                </select>
+		            </div>
+		        </div>
+				<div id="myMsgLoad">
+				</div>
+			</div><!--// tab content4 -->
+		</form>
+	</div><!-- inner close -->
+	
+	<!-- 맞춤제작 요청 레이어 팝업 -->
+	<div class="tooltip-wrap" id="customPopup">
+	</div>
+	<!--// 맞춤제작 요청 레이어 팝업 -->		
+</div>
+<form id="msgResendForm" name="msgResendForm" method="post">
+	<input name="msgResendFlag" type="hidden" value="N"/>
+	<input name="msgSeqList" type="hidden" value=""/>
+</form>
+<form id="moveAddrForm" name="moveAddrForm" method="post">
+	<input name="moveAddrFlag" type="hidden" value="N"/>
+	<input name="addrIdList" type="hidden" value=""/>
+</form>
 
src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/include/msgDataIncludeExcel.jsp (added)
+++ src/main/webapp/WEB-INF/jsp/web/msgcampain/tw/include/msgDataIncludeExcel.jsp
@@ -0,0 +1,775 @@
+<%@ 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; //엑셀입력 탭
+var $tableError = null; //엑셀입력 탭
+$(document).ready(function(){
+	
+	//Tabulator AJAX Data Loading
+	$tableError = new Tabulator("#tabulator_error", {
+		height:"255px",
+		width:"100%",
+	    layout:"fitColumns",
+	    autoColumns:false,
+	    headerHozAlign:"center", 
+	    validationMode:"highlight",
+	    clipboard:false,
+	    clipboardCopySelector:"table",
+	    clipboardPasteAction:"insert", // insert, update, replace
+	    placeholder:"등록 팝업에서 휴대폰을 선택 후 확인해주세요.", //fit columns to width of table (optional)
+	 	columns:[ //Define Table Columns
+		 	{title:"이름", field:"name", hozAlign:"center", headerHozAlign: "center", width:125},
+		 	{title:"휴대폰", field:"phone", hozAlign:"center", headerHozAlign: "center", width:158},
+		 	{title:"미등록 결과", field:"result", hozAlign:"center", headerHozAlign: "center", width:125}
+	 	]
+	});
+	
+
+	//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, headerHozAlign:"center", width:50, hozAlign:"center", headerSort:false, cellClick:function(e, cell){
+	 	        cell.getRow().toggleSelect();
+		 		}
+		 	}, 
+			{formatter:"rownum", align:"center" ,title:"No", hozAlign:"center", headerHozAlign:"center", width:50},
+		 	{title:"A", field:"A", hozAlign:"center", headerHozAlign: "center", validator:["maxLength:100", "string"]},
+		 	{title:"B", field:"B", hozAlign:"center", headerHozAlign: "center", validator:["maxLength:100", "string"]}
+		 	// ,{title:"C", field:"C", hozAlign:"center", headerHozAlign: "center", width:140, validator:["maxLength:100", "string"]},
+		 	// {title:"D", field:"D", hozAlign:"center", headerHozAlign: "center", width:140, validator:["maxLength:100", "string"]},
+		 	// {title:"E", field:"E", hozAlign:"center", headerHozAlign: "center", width:140, validator:["maxLength:100", "string"]},
+		 	// {title:"F", field:"F", hozAlign:"center", headerHozAlign: "center", width:140, validator:["maxLength:100", "string"]}
+	 	],
+	 	validationFailed:function(cell, value, parameters){ // 유효성 체크 함수 
+	        var valid = cell.isValid();
+	 		if(!valid){
+	 			alert("양식에 맞지 않는 정보가 입력되었습니다.");
+	 			
+	 			//해당 셀 데이터 삭제
+	 			cell.setValue("");
+	 		}
+	 		return value % parameters.phone;
+	    },
+	});
+	
+	// 타뷸레이터 width값 변경 시 위에 select width 값 변경
+	var titleArray = ["No","A","B","C","D","E","F"];
+
+	$tableExcel.on("columnWidth",function(column){
+		var titleIndex = titleArray.indexOf(column._column.definition.title);
+		titleIndex += 1;
+		
+		if(titleIndex != 0){
+			$('.select_adr_hd>div').eq(titleIndex).css('width', column._column.width);
+		}else{
+			$('.select_adr_hd>div').eq(0).css('width', column._column.width);
+		}
+	});
+
+	$tableExcel.on("scrollHorizontal",function(left){
+	      $(".adr_excel").scrollLeft(left);
+	})
+
+
+	$(".adr_excel").on("scroll",function(){
+		$(".tabulator-tableholder").scrollLeft($(this).scrollLeft());
+	});
+
+    $("#excelFile").on("change", function(event) {
+    	var fileInfo =  event.target.files;
+        if(fileInfo.length > 0){
+            excelFileChange(fileInfo[0]);
+        } else {
+            fn_loadRemoveActive(); // 파일이 선택되지 않은 경우 로딩 상태 제거
+            setTimeout(() => { $(this).val(''); }, 0);  // 파일 선택 초기화
+        }
+    });
+
+	// 대량등록 팝업닫기
+    $(document).on('click', '#btnAddrMassClose', function() {
+    	setAddrMassClose();
+    });
+	
+    // 대량등록 팝업닫기
+    $(document).on('click', '#closeBtn', function() {
+    	setAddrMassClose();
+    });
+
+ 	// excel 오류정보 테스트
+	$(document).on('click', '#errorExcelBtn', function() {
+		if($tableError.getDataCount()<1){
+			alert('오류 정보가 없습니다.');
+			return false;
+		}
+		$tableError.download("xlsx", "error_data.xlsx");
+	});
+    
+ 	// 엑셀등록 초기화 값 설정
+	function setAddrMassClose() {
+		$tableExcel.clearData();
+		$("#excelRowTotCnt").text(0); //총건수 수정
+		$("#excelRowDupCnt").text(0); //중복건수 수정
+		$("#excelRowErrorCnt").text(0); //중복건수 수정
+		dupliPhoneDataRealList.length = 0;	// 중복 휴대폰번호 초기화
+		addrMassDupliSaveList = null;
+		
+		$('#excelFile').val(''); //첨부파일 값 초기화
+		
+		// popup 영역
+		$tableError.clearData();
+		// 중복 카운트
+		$("#errorPopDupCnt").text(0);
+		// 에러 카운트
+		$("#errorPopErrorCnt").text(0);
+		// 
+		$("#errorPopTotCnt").text(0);
+		// select 선택값 초기화
+		$('.field-selector').each(function() { $(this).val(''); });
+	}
+    
+	//#############################################################################################
+	//파일업로드 드래그앤 드롭
+	//#############################################################################################
+	var objDragAndDrop = $(".upload_area");
+	$(document).on("dragenter",".upload_area",function(e){
+		e.stopPropagation();
+		e.preventDefault();
+	});
+	$(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();
+	});
+	$(document).on('drop', function (e){
+		e.stopPropagation();
+		e.preventDefault();
+	});
+  	//파일 드래그앤드롭 종료
+  
+	//타이틀 select 선택 이벤트
+	 $('.field-selector').on('change', function() {
+		fn_loadAddActive();
+
+		setTimeout(() => { 
+			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();
+
+		}, 0); // 지연 없이 즉시 실행되도록 0ms 지연을 설정
+		
+	});
+	
+	//받는사람 전체삭제 버튼 처리
+	$('#allDel').click(function(){
+		var data = $tableExcel.getRows();	
+		$tableExcel.clearData();
+		$("#excelRowTotCnt").text(0); //총건수 수정
+		$("#excelRowDupCnt").text(0); //중복건수 수정
+		dupliPhoneDataRealList.length = 0;	// 중복 휴대폰번호 초기화
+		
+		// select box 초기화
+		$('.field-selector').each(function() { $(this).val(''); });
+		
+	});
+
+	// 받는사람 선택삭제 버튼 처리해주기
+	$('#in_select_del').click(function(){
+		
+		if($tableExcel == null || $tableExcel == ""){
+			alert("받는사람을 추가해 주세요.");
+			return false;
+		}
+		
+		var selectedData = $tableExcel.getSelectedRows();
+		
+		if(selectedData == "" || selectedData == null){
+			alert("삭제할 연락처를 선택해주세요.");
+			return false;
+		}else{ // 선택한 Row 데이터 삭제하기
+			if(confirm("선택하신 받는 사람을 삭제하시겠습니까?")){
+				// 선택 데이터 삭제
+			    selectedData.forEach(row => row.delete());
+				totRows = $tableExcel.getRows().length;
+			    $("#excelRowTotCnt").text(totRows);
+			}
+		}
+	});
+
+	// 추가버튼
+	$('#btnAddrMassReg').click(function(){
+		
+		if($tableExcel.getData().length < 1){
+			alert("한 개 이상의 연락처를 입력하세요");
+			return false;
+		}
+		
+		
+		// tableExcel 그룹의 select 요소들을 확인
+		var columns = $tableExcel.getColumns();
+		var isAddrPhoneNoSelected = columns.some(column => column.getField() === 'addrPhoneNo');
+
+		if (!isAddrPhoneNoSelected) {
+			alert('휴대폰이 선택되지 않았습니다.');
+			return false;
+		}
+
+		// 새로 추가하려는 데이터 (대시 제거)
+		const addrData = $tableExcel.getData().map(row => ({
+			name: row.addrNm,
+			phone: removeDash(row.addrPhoneNo)
+		}));
+
+		updateTwSmSTable(addrData);
+
+
+
+		
+		setAddrMassClose();
+		$('.field-selector').each(function() { $(this).val(''); });
+		$('#closeBtn').click();
+	});
+});
+
+function excelFileChange(file) {
+	if (file) {
+
+		// 파일 크기 체크 (20MB)
+		const maxSize = 20 * 1024 * 1024; // 20MB in bytes
+		if (file.size > maxSize) {
+			alert('파일 크기는 20MB를 초과할 수 없습니다.');
+			return;
+		}
+		
+		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});
+					// 문제 데이터를 확인하는 함수 호출
+					findInvalidDBCharacters(jsonData);
+					processExcelData(jsonData);
+				} else if (extension === 'xls') {
+					var data = e.target.result;
+					var workbook = XLSX.read(data, { type: 'binary' });
+					var firstSheet = workbook.Sheets[workbook.SheetNames[0]];
+					var jsonData = XLSX.utils.sheet_to_json(firstSheet, { header: 1 });
+
+					// 문제 데이터를 확인하는 함수 호출
+					findInvalidDBCharacters(jsonData);
+
+					
+					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 === 'xls') {
+			reader.readAsBinaryString(file); // xls 파일에 적절한 read 메서드 호출
+		} else if (extension === 'txt') {
+			reader.readAsText(file);
+		}
+	}
+}
+
+//문제 데이터를 확인하는 함수
+function findInvalidDBCharacters(jsonData) {
+	console.log('DB 입력 값 검사 중...');
+	const invalidCharPattern = /[\uD800-\uDBFF][\uDC00-\uDFFF]/; // 4바이트 유니코드 문자 (이모지 등)
+	for (let rowIndex = 0; rowIndex < jsonData.length; rowIndex++) {
+		const row = jsonData[rowIndex];
+		if (Array.isArray(row)) {
+			for (let colIndex = 0; colIndex < row.length; colIndex++) {
+				const cell = row[colIndex];
+				if (typeof cell === 'string' && invalidCharPattern.test(cell)) {
+					console.warn('허용되지 않는 문자: row', rowIndex + 1,', col ', colIndex + 1, ', value:', cell);
+					// 허용되지 않는 문자를 제거 (선택 사항)
+					row[colIndex] = cell.replace(invalidCharPattern, '');
+					console.log('수정된 값:', row[colIndex]);
+				}
+			}
+		}
+	}
+}
+
+
+// 엑셀 데이터 처리 함수
+function processExcelData(data) {
+	var keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
+	var tableData = [];
+	
+	data.slice(0).forEach((row, index) => {
+		var rowData = {};
+		keys.forEach((key, idx) => { // index 변수명 변경 (내부와 외부에서 사용되므로 충돌 방지)
+			rowData[key] = (typeof row[idx] === 'string') ? row[idx].trim() : row[idx];
+		});
+		
+		tableData.push(rowData);
+	});
+	
+	updateTable(tableData);
+}
+
+// 텍스트 데이터 처리 함수
+function processTextData(text) {
+	var lines = text.split('\n'); // 각 줄을 배열로 분리
+	// var keys = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
+	var keys = ['A', 'B'];
+	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([ //Define Table Columns
+ 		{formatter:"rowSelection", titleFormatter:"rowSelection",clipboard:false, headerHozAlign:"center", width:50, hozAlign:"center", headerSort:false, cellClick:function(e, cell){
+ 	        cell.getRow().toggleSelect();
+			}
+	 	},
+		{formatter:"rownum", align:"center" ,title:"No", hozAlign:"center", headerHozAlign:"center", width:50},
+		{title:"A", field:"A", hozAlign:"center", headerHozAlign: "center", validator:["maxLength:100", "string"]},
+		{title:"B", field:"B", hozAlign:"center", headerHozAlign: "center", validator:["maxLength:100", "string"]}
+ 	]);
+
+	$tableExcel.setData(tableData).then(() => {
+		// excelRowTotCnt 업데이트
+		document.getElementById("excelRowTotCnt").innerText = tableData.length;
+	});
+	
+	fn_loadRemoveActive();
+}
+
+
+
+/* 
+* 타이틀 select 선택할때마다 실행해서         
+* 데이터테이블 필드값 수정                  
+*/
+function updateTableFields($objTabul) {
+	var currentData = $objTabul.getData();
+	var columns = [
+		{formatter: "rowSelection", titleFormatter: "rowSelection", clipboard: false, width:50, hozAlign: "center", headerHozAlign: "center", headerSort: false, cellClick: function(e, cell) {
+			cell.getRow().toggleSelect();
+		}}
+		,{formatter:"rownum", align:"center", title:"No", hozAlign:"center", headerHozAlign:"center", width:60}
+	];
+
+	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"
+				, editor: false
+				// , width: 140
+				, validator: ["maxLength:100", "string"]
+			});
+			fieldMapping.push(selectedField);
+		} else {
+			columns.push({
+				title: field
+				, field: field
+				, hozAlign: "center"
+				, headerHozAlign: "center"
+				, editor: false
+// 				, editor: "input"
+// 				, width: 140
+				, 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) {
+	 
+	$tableError.clearData();
+	
+	var data = $objTabul.getData();
+	var phoneNumberChk = false;
+	var existingNumbers = new Set(); // 배열에서 Set으로 변경
+	
+	let errorCount = 0; // 중복 번호 개수를 저장할 변수
+	let duplicateCount = 0; // 중복 번호 개수를 저장할 변수
+	
+	const errors = [];  // 오류 데이터를 저장할 배열
+	const newData = []; // 유효한 데이터만 저장할 새로운 배열
+	
+	data.forEach((row, index) => {
+		
+		const number = row.addrPhoneNo;
+		
+		// number가 null, undefined, 빈 문자열이거나 숫자인 경우 처리
+		if (!number || (typeof number === 'string' && !number.trim())){
+			console.log("number : ", number);
+			 return;
+		}
+		
+		const formattedNumber = formatPhoneNumber(number); // 번호 표준화
+		const cleanedNumber = formattedNumber.replace(/[^0-9]/g, ''); // 숫자만 남김
+		
+		if (!existingNumbers.has(cleanedNumber)) { // 중복 번호 체크
+		    if (isValidPhoneNumber(formattedNumber)) { // 유효성 검사
+		        row.addrPhoneNo = formattedNumber;
+		        existingNumbers.add(cleanedNumber); // 추가된 번호를 기존 목록에 추가
+		        newData.push(row); // 유효한 데이터만 새로운 배열에 추가
+		    } else {
+				// 오류: 유효성 통과 못함
+				errorCount++;
+				
+				errors.push({ 
+					name: row.addrNm, // 이름
+					phone: row.addrPhoneNo, // 폰번호
+					result: "오류" // 결과 메시지 추가
+				});
+		    }
+		} else {
+			// 중복
+			duplicateCount++;
+			
+			errors.push({ 
+				name: row.addrNm, // 이름
+				phone: row.addrPhoneNo, // 폰번호
+				result: "중복" // 결과 메시지 추가
+			});
+		}
+	});
+	
+	// data 배열을 newData 배열로 대체
+	data = newData;
+	
+
+	// 수정된 데이터로 테이블 업데이트
+	$objTabul.setData(data);
+	// 오류 총 카운트
+    $("#excelRowTotCnt").text($objTabul.getDataCount());
+	// 중복 카운트
+	$("#excelRowDupCnt").text(duplicateCount);
+	// 에러 카운트
+	$("#excelRowErrorCnt").text(errorCount);
+	
+	// popup 영역
+	$("#errorPopTotCnt").text($objTabul.getDataCount());
+	// 중복 카운트
+	$("#errorPopDupCnt").text(duplicateCount);
+	// 에러 카운트
+	$("#errorPopErrorCnt").text(errorCount);
+	
+	
+	$tableError.setData(errors);
+	
+	if(errorCount > 0){
+		alert('휴대폰 형식에 맞지 않는 데이터는 삭제 후 업로드 됩니다.\nex) 발송불가 특수문자, 자릿수 오류 등');
+	}
+}
+
+function fn_dupliPopupShow(){
+
+	$("#tableExcelDupliBtn").show();
+}
+
+function makeAddrMassDupliPop(dupliPhoneDataRealList) {
+	var sHtml = "";
+	sHtml += "<div class='' style='overflow-x:auto; height:350px;'>";
+	sHtml += "<table class='tType4'>";
+	sHtml += "		<colgroup>";
+	sHtml += "			<col style='width:auto' />";
+	sHtml += "		</colgroup>";
+	sHtml += "		<thead>";
+	sHtml += "			<tr>";
+	sHtml += "				<th>중복 휴대폰번호 (" + numberWithCommas(dupliPhoneDataRealList.length) + "개)</th>";
+	sHtml += "			</tr>";
+	sHtml += "		</thead>";
+	sHtml += "		<tbody>";
+	for (var i = 0; i < dupliPhoneDataRealList.length; i++) {
+		sHtml += "		<tr>";
+		sHtml += "			<td>" + dupliPhoneDataRealList[i] + "</td>";
+		sHtml += "		</tr>";
+	}
+	sHtml += "		</tbody>";
+	sHtml += "	</table>";
+	sHtml += "	</div>";
+
+	$("#addrMassDupli_layer").html(sHtml);
+	fn_dupliPopupShow();
+	
+}
+
+
+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>
+
+<!-- 중복전화번호 data-tooltip:addrMassDupli_layer -->
+<div class="tooltip-wrap">
+	<div class="popup-com addrMassDupli_layer" tabindex="0" data-tooltip-con="addrMassDupli_layer" data-focus="addrMassDupli_layer" data-focus-prev="addrMassDupli_layer-close" style="width: 270px; height: 500px;">
+		<div class="popup_heading">
+			<p>중복 휴대폰번호</p>
+			<button type="button" class="tooltip-close" data-focus="addrMassDupli_layer-close" onclick="setAddrDupliClose();"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		<div class="layer_in" style="padding:20px 0px;" id="addrMassDupli_layer">
+		</div>
+		
+		<div class="popup_btn_wrap2" style="margin-top: 0px;">
+			<button type="button" class="tooltip-close" data-focus="addrMassDupli_layer-close" data-focus-next="addrMassDupli_layer">닫기</button>
+		</div>		
+	</div>		
+</div>
+
+
+<!-- 주소록 상세 결과 팝업 data-tooltip:adr_popup14 -->
+<div class="tooltip-wrap">
+	<div class="popup-com adr_layer adr_detail_result adr_popup14" tabindex="0" data-tooltip-con="adr_popup14" data-focus="adr_popup14" data-focus-prev="adr_popu14-close" style="width: 450px;z-index:125;">
+		<div class="popup_heading">
+			<p>주소록 상세 결과</p>
+			<button type="button" class="tooltip-close" data-focus="adr_popup14-close"><img src="/publish/images/content/layerPopup_close.png" alt="팝업 닫기"></button>
+		</div>
+		<div class="layer_in" style="padding:30px 20px;">
+			<div class="table_top">
+				<p>
+				총 <span class="c_e40000" id="errorPopTotCnt">0</span>건 
+				/ 중복 <span class="c_002c9a" id="errorPopDupCnt">0</span>건
+				/ 오류 <span class="c_002c9a" id="errorPopErrorCnt">0</span>건</p>
+				<button type="button" class="excel_btn btnType" id="errorExcelBtn"><i class="downroad"></i>엑셀 다운로드</button>
+			</div>
+			<div class="tb_wrap adr_list" id="tabulator_error">
+				<!-- $tableError 참고  -->
+			</div>
+			<ul class="cf_text_ul">
+				<li>*중복번호는 하나의 번호만 등록됩니다.</li>
+				<li>*휴대폰 형식에 맞지 않는 데이터는 삭제 후 업로드 됩니다.</li>
+				<li>ex) 발송불가 특수문자, 자릿수 오류 등</li>
+			</ul>
+			<div class="popup_btn_wrap2">
+				<button type="button" class="tooltip-close" data-focus="adr_popup14-close" data-focus-next="adr_popup14" style="">닫기</button>                      
+			</div>
+		</div>
+	</div>
+</div>
+
+<div class="popup_heading">
+	<p>엑셀 불러오기</p>
+	<button type="button" class="tooltip-close" id="closeBtn" 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="popCont current pop_more_cont" id="popCont_1">
+		<div class="titBox">
+			<p>- 주소록은 한 번에 최대 30만건까지 등록(EXCEL파일, 최대용량 20MB) 가능합니다. </p>
+			<p>- 엑셀 파일에 비밀번호 설정, 제한된 보기, 수식 등이 설정되어 있는 경우 업로드가 불가합니다.</p>
+			<p>- 구분선(|), 역슬래시(\, ₩), 큰따옴표("), 이모지(이모티콘) 등 발송불가 특수문자는 저장되지 않습니다.</p>
+<%--			<p>- 이름 200byte, [*1*]~[*4*] 200byte, 메모 250byte까지 입력 가능합니다.</p>--%>
+			<p>- 주소록 등록이 어려우신 경우에는 <a href="<c:url value='/web/mjon/addragency/selectAddrAgencyList.do'/>" style="font-weight: bold; color: blue;">주소록 입력대행</a> 메뉴를 이용하실 수 있습니다. </p>
+		</div>
+		<div class="pop_more_wrap">
+			<button type="button" class="pop_more" onclick="popMore(this);" style="margin-top:-29px;">더보기<i></i></button>
+		</div>
+	</div>
+	<!--// 엑셀입력 -->
+
+	<!-- 공통 -->
+	<div>
+		<table class="layer_tType1">
+			<caption>엑셀입력 표</caption>
+			<colgroup>
+				<col style="width: 95px">
+				<col style="width: auto">
+			</colgroup>
+			<tbody>
+				<tr>
+					<td colspan="2" style="padding:20px 0;">
+						<div class="file_upload_wrap" style="width:100%;display:flex;">
+							<div class="file_add upload_area">
+								<p><img src="/publish/images/content/file_add.png" alt="파일 붙여넣기">마우스로 엑셀, TXT파일을 여기에 끌어다 놓으세요</p>
+							</div>
+							<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>
+						</div>
+					</td>
+				</tr>
+			</tbody>
+		</table>
+	</div>
+            
+	<div class="excel_middle2">
+		<p>
+			총 <span class="c_e40000 fwBold" id="excelRowTotCnt">0</span>건 
+			/ 중복 <span class="c_002c9a fwBold" id="excelRowDupCnt">0</span>건
+			/ 오류 <span class="c_002c9a fwBold" id="excelRowErrorCnt">0</span>건
+			<button type="button" class="btn_list_detail" data-tooltip="adr_popup14"><img src="/publish/images/search.png"></button>
+		</p>
+	</div>
+	<div class="adr_excel" style="margin-top: 13px; overflow-x:auto;">
+		<!-- thead -->
+		<div class="adr_hd select_adr_hd msg" data-group="tableExcel">
+			<div style="width: 100px;"></div>
+			<div style="width: 100px;"></div>
+			<div style="width: 140px;">
+				<label for="" class="label"></label>
+				<select class="field-selector">
+					<option value="">선택하기</option>
+					<option value="addrNm">이름</option>
+					<option value="addrPhoneNo">휴대폰</option>
+				</select>
+			</div>
+			<div style="width: 140px;">
+				<label for="" class="label"></label>
+				<select class="field-selector">
+					<option value="">선택하기</option>
+					<option value="addrNm">이름</option>
+					<option value="addrPhoneNo">휴대폰</option>
+				</select>
+			</div>
+		</div>
+	</div>					
+	<div class="drag_drop_wrap callList_includ_box" id="tabulator_excel"></div>
+	<div class="excel_middle">
+		<div class="select_btnWrap clearfix">
+			<div>
+				<button type="button" id="allDel"><i class="remove_img"></i>전체삭제</button>
+				<button type="button" id="in_select_del"><i class="remove_img"></i>선택삭제</button>
+			</div>
+
+		</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/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
@@ -3490,7 +3490,7 @@
 	if(Number(totCnt) > 5000){
 		
 		alert("분할전송 건수는 5,000건을 초과할 수 없습니다.");
-		$('#divideCnt').val("20");
+		$('#divideCnt').val("500");
 		return false;
 		
 	}
@@ -4488,7 +4488,7 @@
                            	<div class="rev_bottom">
              		            <input type="checkbox" id="divideChk" name="divideChk">
              		            <label for="divideChk">분할전송</label>
-             		            <input type="text" class="dividType1" id="divideCnt" name="divideCnt" value="20" onkeypress='return checkNumber(event)' maxlength="4"/>
+             		            <input type="text" class="dividType1" id="divideCnt" name="divideCnt" value="500" onkeypress='return checkNumber(event)' maxlength="4"/>
              		            <label for="divideCnt">건씩</label> <!-- 2023 11 17 수정 --> 
              		            <select class="selType1" id="divideTime" name="divideTime">
              		                <option value="1">01분</option>
src/main/webapp/WEB-INF/jsp/web/pop/testSendPop.jsp
--- src/main/webapp/WEB-INF/jsp/web/pop/testSendPop.jsp
+++ src/main/webapp/WEB-INF/jsp/web/pop/testSendPop.jsp
@@ -126,12 +126,13 @@
 			var adTxt = '';
 			var denyTxt = '';
 			var adverYn = opener.document.msgForm.send_adYn.value;
-			
+
+			console.log('adverYn :: ', adverYn);
 			//선거문자 20건 발송에서는 선거 필수문구가 필수가 아니어서 선거문자 필수 문구가 있는지 체크하여 처리함.20231214 추가
 			if(adverYn == 'Y'){
 				adTxt = $('.ad_tit').text();
-				denyTxt = $('.deny_receipt').html();
-				denyTxt = denyTxt.replaceAll("<br>","\n");
+				denyTxt = $('.deny_txt').html();
+				denyTxt.replaceAll("<br>","\n");
 			}
 			
 			form.smsTxt.value = adTxt + '\n' + $(".preview_auto").find("pre").text() + '\n' + denyTxt;
src/main/webapp/js/MJUtill.js
--- src/main/webapp/js/MJUtill.js
+++ src/main/webapp/js/MJUtill.js
@@ -200,8 +200,8 @@
 
 //숫자 천단위 콤마 찍어주기
 function numberWithCommas(x) { 
-    console.log(' + typeof x : ',typeof x);
-    console.log(' + x : ',x);
+    // console.log(' + typeof x : ',typeof x);
+    // console.log(' + x : ',x);
 	return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 
 }
 
@@ -1118,5 +1118,81 @@
 	$('#rowDupCnt').text(cnt)
 }
 
+/**
+ * @Discript : 현재 금액 조회
+ * 				선거에서 사용중
+ * @history : 2026.03.31 : 갱신된 금액 가져오는 ajax
+ * 				2028. 04. 13 : 이벤트도 추가 함
+ */
+function getBeforeCashData(){
 
+	$.ajax({
+		type: 'POST',
+		url: '/web/api/getBeforeCashDataAjax.do',
+		contentType: 'application/json',
+		// data: JSON.stringify(sendData),
+		dataType: 'json',
+		success : function(data) {
+			// alert(data.msg);
+			// console.log(data);
+			if(data.status == 'OK')
+			{
+				// 서버 응답 데이터
+				const result = data.data;
+
+				// 이벤트 정보 (없을 경우 대비)
+				const eventMberInfo = result.eventMberInfo || {};
+
+				// 자주 쓰는 jQuery 객체 캐싱
+				const $eventStatus = $('#eventStatus');
+				const $eventRemainCash = $('#eventRemainCash');
+				const $topEventTag = $('#topEventTag');
+				const $topEventPrice = $('#topEventTag .price');
+
+				// 사용자 보유 금액 표시 (한국식 콤마 포맷)
+				$('#hdUserMoney').text(result.userMoney.toLocaleString('ko-KR'));
+
+				// 이벤트 상태값 (Y: 진행중, E: 종료, N: 미진행)
+				const eventStatus = eventMberInfo.eventStatus;
+
+				// 이벤트 남은 금액 (없을 경우 0 처리 후 포맷)
+				const eventRemainCash = (eventMberInfo.eventRemainCash || 0).toLocaleString('ko-KR');
+
+				// 디버깅 로그
+				console.log('result : ', result);
+				console.log('eventStatus : ', eventStatus);
+				console.log('eventRemainCash : ', eventRemainCash);
+
+				// ===== 이벤트 종료 상태 =====
+				if (eventStatus === 'E') {
+
+					// 이미 종료 처리된 상태가 아닐 때만 실행 (중복 처리 방지)
+					if ($eventStatus.val() !== 'E') {
+						$topEventTag.hide();                 // 이벤트 영역 숨김
+						$eventStatus.val('E');              // 상태값 업데이트
+						$eventRemainCash.val(eventRemainCash); // 남은 금액 저장
+					}
+
+					// ===== 이벤트 진행중 상태 =====
+				} else if (eventStatus === 'Y') {
+					$eventRemainCash.val(eventRemainCash);   // 남은 금액 저장
+					$topEventPrice.text(eventRemainCash);    // 화면 금액 변경
+					// $topEventTag.show();                     // 이벤트 영역 표시
+
+					// ===== 이벤트 미진행 or 기타 상태 =====
+				}
+			}
+			else
+			{
+				// 실패 처리 로직
+			}
+		},
+		error : function(jqXHR, textStatus, errorThrown) {
+			console.error("AJAX Error:", textStatus, errorThrown);
+			console.error("Response:", jqXHR.responseText);
+		}
+	});
+
+
+}
 
src/main/webapp/js/txtSpecialReplace.js
--- src/main/webapp/js/txtSpecialReplace.js
+++ src/main/webapp/js/txtSpecialReplace.js
@@ -36,7 +36,6 @@
 function fnReplCell(){
 	
 	var smsTxtArea = $('#smsTxtArea').val();
-	var imgCnt = $("#imgCnt").val(); // 현재 페이지에 첨부된 이미지 갯수
 	var orgSmsTxt = smsTxtArea;		// 광고문자 뺀 문자내용
 	
 	var adTxt = $('.ad_txt').text();
@@ -46,7 +45,6 @@
 	
 	//이벤트 잔여 캐시 자동 처리 관련 변수
 	var evnRemainCash = parseFloat($("#eventRemainCash").val()); //이벤트 잔여 캐시 금액
-	var evnEachPrice = parseFloat($("#eachPrice").val());
 	var evnShortPrice = parseFloat($("#sPrice").val());
 	var evnLongPrice = parseFloat($("#mPrice").val());
 	var evnPhoneNumCnt = 0;
@@ -80,37 +78,6 @@
 		//일괄변환문자 포함 여부 변경 - 문자내용에 치환변환 문자는 있지만 받는사람 데이터에 치환 데이터를 안넣는 경우 오류가 발생하여 상태값 입력 위치 상단으로 변경함.
 		//치환데이터가 없는 경우 Alert 띄우고 빠져나가기 때문에  치환문자 상태 체크값이 누락되어서 변경함 - 20230407 우영두
 		$('#txtReplYn').val("Y");
-		
-		var nmStatus = false;
-		var rep1Status = false;
-		var rep2Status = false;
-		var rep3Status = false;
-		var rep4Status = false;
-		
-		if(smsTxtArea.indexOf("[*이름*]")  > -1){
-			
-			nmStatus = true;
-		}
-		
-		if(smsTxtArea.indexOf("[*1*]")  > -1){
-			
-			rep1Status = true;
-		}
-		
-		if(smsTxtArea.indexOf("[*2*]")  > -1){
-			
-			rep2Status = true;
-		}
-		
-		if(smsTxtArea.indexOf("[*3*]")  > -1){
-			
-			rep3Status = true;
-		}
-		
-		if(smsTxtArea.indexOf("[*4*]")  > -1){
-			
-			rep4Status = true;
-		}
 
 		
 		//기존 받는사람 리스트를 배열에 미리 담아둔다.
@@ -132,14 +99,7 @@
 					orgSmsTxt = stringReplaceAll(orgSmsTxt, "[*이름*]", name);//광고, 선거 문자인 경우 상하단 문구 제거한 문자내용만 보여주도록 함. 치환문자 있으면 변환해서 보여줌
 					
 					
-				}/*else{
-					
-					if(nmStatus){
-						alert("[*이름*] 치환 문자에 데이터가 없습니다. 받는사람 목록의 치환 데이터를 확인해 주세요.");
-						return false;
-					}
-					
-				}*/
+				}
 				
 				if(typeof recTableData[j].getData().rep1 != 'undefined' && recTableData[j].getData().rep1 != null && recTableData[j].getData().rep1 != ""){
 					
@@ -147,14 +107,7 @@
 					smsTxt = stringReplaceAll(smsTxt, "[*1*]", rep1);
 					orgSmsTxt = stringReplaceAll(orgSmsTxt, "[*1*]", rep1);
 					
-				}/*else{
-					
-					if(rep1Status){
-						alert("[*1*] 치환 문자에 데이터가 없습니다. 받는사람 목록의 치환 데이터를 확인해 주세요.");
-						return false;
-					}
-					
-				}*/
+				}
 				
 				if(typeof recTableData[j].getData().rep2 != 'undefined' && recTableData[j].getData().rep2 != null  && recTableData[j].getData().rep2 != ""){
 					
@@ -162,14 +115,7 @@
 					smsTxt = stringReplaceAll(smsTxt, "[*2*]", rep2);
 					orgSmsTxt = stringReplaceAll(orgSmsTxt, "[*2*]", rep2);
 					
-				}/*else{
-					
-					if(rep2Status){
-						alert("[*2*] 치환 문자에 데이터가 없습니다. 받는사람 목록의 치환 데이터를 확인해 주세요.");
-						return false;
-					}
-					
-				}*/
+				}
 				
 				if(typeof recTableData[j].getData().rep3 != 'undefined' && recTableData[j].getData().rep3 != null  && recTableData[j].getData().rep3 != ""){
 					
@@ -177,14 +123,7 @@
 					smsTxt = stringReplaceAll(smsTxt, "[*3*]", rep3);
 					orgSmsTxt = stringReplaceAll(orgSmsTxt, "[*3*]", rep3);
 					
-				}/*else{
-					
-					if(rep3Status){
-						alert("[*3*] 치환 문자에 데이터가 없습니다. 받는사람 목록의 치환 데이터를 확인해 주세요.");
-						return false;
-					}
-					
-				}*/
+				}
 				
 				if(typeof recTableData[j].getData().rep4 != 'undefined' && recTableData[j].getData().rep4 != null && recTableData[j].getData().rep4 != ""){
 					
@@ -192,14 +131,7 @@
 					smsTxt = stringReplaceAll(smsTxt, "[*4*]", rep4);
 					orgSmsTxt = stringReplaceAll(orgSmsTxt, "[*4*]", rep4);
 					
-				}/*else{
-					
-					if(rep4Status){
-						alert("[*4*] 치환 문자에 데이터가 없습니다. 받는사람 목록의 치환 데이터를 확인해 주세요.");
-						return false;
-					}
-					
-				}*/
+				}
 				
 				
 				var msgLen = conByteLeng(smsTxt);
 
src/main/webapp/js/web/msgcampain/tw/event.js (added)
+++ src/main/webapp/js/web/msgcampain/tw/event.js
@@ -0,0 +1,1131 @@
+/**
+ * 20건 수동문자
+ *
+ * 주요 기능:
+ * 1. 발송 가능 상태(발송전)인 대상자만 선택 가능
+ * 2. 엔터키 롱프레스 연속 선택 (현재 페이지에서만)
+ * 3. 선택해제 시 완전 초기화
+ */
+
+var isSpacePressed = false;
+var isSendLocked = false;
+
+$(document).ready(function(){
+    // 필요 시 초기화 코드
+});
+
+/* ====================== 엔터키 연속 선택 ====================== */
+$(document).on("keydown", function (e) {
+
+    var isSpaceChecked = $("input:checkbox[name='sendBySpace']").is(":checked");
+
+    // Spacebar로 발송 (기존 유지)
+    if (e.keyCode === 32 && isSpaceChecked && !$(".put_text").is(':focus')) {
+        e.preventDefault();
+
+        if (isSpacePressed || isSendLocked) return;
+
+        isSpacePressed = true;
+        // isSendLocked = true;
+
+        var checkedCnt = twSmsTable.getSelectedData().length;
+        if (checkedCnt > 0) {
+            setTimeout(function () {
+                $(".btn_send").click();
+            }, 500);
+        } else {
+            isSendLocked = false;
+            alert("발송할 대상을 선택해 주세요.");
+        }
+        return;
+    }
+    // ==================== 엔터키 연속 선택 ====================
+    if (e.keyCode === 13 && !$(".put_text").is(':focus')) {
+
+        if ($(e.target).is("input, textarea, select, [contenteditable='true']")) {
+            return;
+        }
+
+        e.preventDefault();
+
+        if (isEnterPressed || isSendLocked) return;
+
+        isEnterPressed = true;
+        window.enterSelectCurrentPage = twSmsTable.getPage() || 1;
+
+        // 처음 시작할 때 1개 선택
+        selectRowsFastInCurrentPage(1);
+
+        // 연속 선택 시작
+        enterLongPressTimer = setInterval(function () {
+
+            var selected = selectRowsFastInCurrentPage(3);
+
+            // 현재 페이지에 더 이상 선택할 행이 없으면 → 선택 완료로 판단하고 발송
+            if (!selected) {
+                clearInterval(enterLongPressTimer);
+                enterLongPressTimer = null;
+                window.enterSelectCurrentPage = null;
+
+                if (isSendLocked) return;
+                // isSendLocked = true;
+
+                triggerSend();
+                return;
+            }
+
+            // 페이지가 바뀌었으면 강제 종료
+            if (twSmsTable.getPage() !== window.enterSelectCurrentPage) {
+                clearInterval(enterLongPressTimer);
+                enterLongPressTimer = null;
+                isEnterPressed = false;
+                window.enterSelectCurrentPage = null;
+            }
+
+        }, 120);
+    }
+});
+
+$(document).on("keyup", function (e) {
+
+    if (e.keyCode === 13) {
+        isEnterPressed = false;
+        // isSendLocked = false;
+
+        if (enterLongPressTimer) {
+            clearInterval(enterLongPressTimer);
+            enterLongPressTimer = null;
+        }
+
+        window.enterSelectCurrentPage = null;
+    }
+
+    if (e.keyCode === 32) {
+        isSpacePressed = false;
+        // isSendLocked = false;
+    }
+});
+
+// ====================== 발송 트리거 함수 ======================
+function triggerSend() {
+    var checkedCnt = twSmsTable.getSelectedData().length;
+
+    if (checkedCnt > 0) {
+        // UI 업데이트를 위한 최소한의 딜레이 (0.2초 추천)
+        setTimeout(function () {
+            $(".btn_send").click();
+        }, 200);
+    } else {
+        alert("발송할 대상을 선택해 주세요.");
+    }
+}
+
+/* ====================== 선택 함수 ====================== */
+/**
+ * 현재 페이지에서 빠르게 선택
+ */
+function selectRowsFastInCurrentPage(count) {
+    var rows = getCurrentPageSelectableRows();
+    if (rows.length === 0) return false;
+
+    var selectedCount = 0;
+    var table = twSmsTable;
+
+    table.blockRedraw();
+    try {
+        for (var i = 0; i < rows.length; i++) {
+            var row = rows[i];
+            if (!row.isSelected() && isSelectableStatus(row.getData().status)) {
+                row.select();
+                selectedCount++;
+                if (selectedCount >= count) break;
+            }
+        }
+    } finally {
+        table.restoreRedraw();
+    }
+
+    // 선택 후 현재 페이지에 더 이상 선택 가능한 행이 없으면 false 반환
+    return getCurrentPageSelectableRows().length > 0;
+}
+
+/**
+ * 현재 페이지에 보이는 선택 가능한 행만 반환 (이미 선택된 행은 제외)
+ */
+function getCurrentPageSelectableRows() {
+    var table = twSmsTable;
+    if (!table) return [];
+
+    var visibleRows = table.getRows("visible");
+    var selectableRows = [];
+
+    for (var i = 0; i < visibleRows.length; i++) {
+        var row = visibleRows[i];
+        if (isSelectableStatus(row.getData().status) && !row.isSelected()) {
+            selectableRows.push(row);
+        }
+    }
+    return selectableRows;
+}
+
+/**
+ * 발송전 상태 체크
+ */
+function isSelectableStatus(status) {
+    var text = "";
+
+    if(status === null || status === undefined){
+        text = "";
+    }else{
+        text = String(status).replace(/<[^>]*>/g, "").replace(/\s/g, "");
+    }
+
+    // 선택 가능: 미발송 상태만 허용
+    if(text === "" || text === "N" || text === "발송전"){
+        return true;
+    }
+
+    // 선택 불가: 발송 성공/제외
+    if(text === "Y" || text === "발송성공"){
+        return false;
+    }
+
+    if(text === "F" || text === "발송제외"){
+        return false;
+    }
+
+    return false;
+}
+
+/* ====================== 선택해제 ====================== */
+function clearAllSelection(){
+    if(!window.twSmsTable) return;
+
+    var table = window.twSmsTable;
+
+    table.blockRedraw();
+    try {
+        table.deselectRow();                    // 전체 해제
+        table.getRows().forEach(function(row){
+            row.deselect();
+        });
+    } finally {
+        table.restoreRedraw();
+    }
+
+    // 엔터키 선택 상태 초기화
+    if (enterLongPressTimer) {
+        clearInterval(enterLongPressTimer);
+        enterLongPressTimer = null;
+    }
+    window.enterSelectCurrentPage = null;
+}
+
+/* ====================== 페이지네이션 ====================== */
+$(document).on("click", "#sms-pagination .page-btn", function(){
+    var page = $(this).data("page");
+
+    if($(this).prop("disabled")) return;
+
+    // 엔터키 선택 중이었으면 상태 초기화
+    if (window.enterSelectCurrentPage) {
+        window.enterSelectCurrentPage = null;
+    }
+
+    var table = window.twSmsTable || table;   // window.twSmsTable이 우선
+
+    if(page === "first"){ table.setPage(1); return; }
+    if(page === "prev"){ table.previousPage(); return; }
+    if(page === "next"){ table.nextPage(); return; }
+    if(page === "last"){ table.setPage(table.getPageMax()); return; }
+
+    table.setPage(Number(page));
+});
+
+/* ====================== 기타 기존 함수 ====================== */
+function twUpdateTotCnt(){
+    var totRows = twSmsTable.getRows().length;
+    var twTotalRowCnt = Number(totRows) || 0;
+
+    $('#totCallToCnt').text(twTotalRowCnt);
+
+    if(window.twSmsTable){
+        window.twSmsTable.redraw(true);
+    }
+}
+
+function updateTwSmSTable(addrData){
+    const existingData = twSmsTable.getData();
+    const phoneToItemMap = new Map(existingData.map(item => [item.phone, item]));
+    const newlyAdded = [];
+
+    // 1. 데이터 병합 및 중복 제거 루프 수행
+    for (const item of addrData) {
+        const phone = item.phone;
+        if (phone && !phoneToItemMap.has(phone)) {
+            newlyAdded.push(item);
+            phoneToItemMap.set(phone, item);
+        }
+    }
+
+    // 2. 루프 종료 후 최종 Map의 크기(전체 데이터 건수) 체크
+    const MAX_LIMIT = 300000;
+    console.log('phoneToItemMap.size : ', phoneToItemMap.size);
+    if (phoneToItemMap.size > MAX_LIMIT) {
+        alert(`최대 허용 건수(${MAX_LIMIT.toLocaleString()}건)를 초과했습니다. 현재: ${phoneToItemMap.size.toLocaleString()}건`);
+        console.error("Data limit exceeded after merge.");
+        return; // 테이블 업데이트를 하지 않고 종료
+    }
+    console.log('phoneToItemMap.size!!!!!!!! : ', phoneToItemMap.size);
+
+    twSmsTable.setData(Array.from(phoneToItemMap.values()));
+    twUpdateTotCnt();
+
+
+    var tmpJobId = $('#tmpJobId').val();
+    console.log('tmpJobId : ', tmpJobId);
+
+    console.log('newlyAdded.length  : ', newlyAdded.length );
+    if(newlyAdded.length < 1){
+        alert("중복 제거 후 추가할 데이터가 없습니다.");
+        return false;
+    }
+
+    if(tmpJobId){
+        fn_updateCampainTmpJob(tmpJobId, newlyAdded);
+    }else{
+        fn_insertCampainTmpJob(newlyAdded);
+    }
+
+}
+
+
+
+function fn_udpateCampainJob(p_tmpJobId, p_jobStatus){
+
+    var sendData = {
+        "tmpJobId" : p_tmpJobId,
+        "jobStatus" : p_jobStatus
+    }
+
+    console.log('sendData :: ',sendData);
+    $.ajax({
+        type: 'POST',
+        url: '/web/mjon/msgcampain/updateCampainJobStatus.do',
+        contentType: 'application/json',
+        data: JSON.stringify(sendData),
+        dataType: 'json',
+        success : function(data) {
+            console.log(data);
+            if(data.status == 'OK')
+            {
+                // 성공 후 처리 로직
+            }
+            else
+            {
+                // 실패 처리 로직
+            }
+        },
+        error : function(jqXHR, textStatus, errorThrown) {
+            console.error("AJAX Error:", textStatus, errorThrown);
+            console.error("Response:", jqXHR.responseText);
+        }
+    });
+}
+
+
+function fn_updateCampainTmpJob(tmpJobId, newlyAdded){
+
+    console.log('newlyAdded : ', newlyAdded);
+    var sendData = {
+        "totalCount" : newlyAdded.length
+        ,"tmpJobId" : tmpJobId
+    }
+
+
+    $.ajax({
+        type: 'POST',
+        url: "/web/mjon/msgcampain/updateMjCampainTmpJob.do",
+        contentType: 'application/json',
+        data: JSON.stringify(sendData),
+        dataType: 'json',
+        beforeSend: function() {
+            $('.loading_layer').addClass('active');
+        },
+        complete: function() {
+        },
+        success: function(data) {
+            console.log(data.status);
+            if(data.status == 'OK')
+            {
+                console.log(' data :: '+data.status)
+                console.log(' data :: '+data.status)
+                console.log(' data :: '+data.status)
+                console.log(' data :: '+data.status)
+                console.log(' data :: '+data.status)
+                console.log(' data :: '+data.status)
+                fn_insertCampainTmp(newlyAdded)
+                // 성공 후 처리 로직
+            }
+            else
+            {
+                alert(data.message);
+                return false;
+                // 실패 처리 로직
+            }
+        },
+        error: function(jqXHR, textStatus, errorThrown) {
+            console.error("AJAX Error:", textStatus, errorThrown);
+        }
+    });
+
+}
+
+/**
+ * @discription 수신자 목록 저장
+ * @param newlyAdded
+ */
+function fn_insertCampainTmpJob(newlyAdded){
+    if (newlyAdded.length < 1) return;
+
+    var sendData = {
+        "totalCount" : newlyAdded.length
+    }
+
+    $.ajax({
+        type: 'POST',
+        url: "/web/mjon/msgcampain/insertMjCampainTmpJob.do",
+        contentType: 'application/json',
+        data: JSON.stringify(sendData),
+        dataType: 'json',
+        beforeSend: function() {
+            $('.loading_layer').addClass('active');
+        },
+        complete: function() {
+        },
+        success: function(data) {
+            console.log(data.msg);
+            $('#tmpJobId').val(data.data);
+            fn_insertCampainTmp(newlyAdded)
+        },
+        error: function(jqXHR, textStatus, errorThrown) {
+            console.error("AJAX Error:", textStatus, errorThrown);
+        }
+    });
+}
+
+/**
+ * @discription 수신자 목록 저장
+ * @param newlyAdded
+ */
+function fn_insertCampainTmp(newlyAdded){
+    if (newlyAdded.length < 1) return;
+    var currentTmpJobId = $('#tmpJobId').val();
+
+    var sendList = newlyAdded.map(function(row) {
+        return {
+            callNm: row.name || "",
+            callTo: row.phone || "",
+            tmpJobId: currentTmpJobId
+        };
+    });
+
+    $.ajax({
+        type: 'POST',
+        url: "/web/mjon/msgcampain/insertMyAddrTWCallToAjax_advc.do",
+        contentType: 'application/json',
+        data: JSON.stringify(sendList),
+        dataType: 'json',
+        beforeSend: function() {
+            $('.loading_layer').addClass('active');
+        },
+        complete: function() {
+            $('.loading_layer').removeClass('active');
+            refreshSendCounts();
+            // fn_udpateCampainJob(data.data, 'C');
+        },
+        success: function(data) {
+            console.log(data.msg);
+            // fn_udpateCampainJob(currentTmpJobId, 'C');
+        },
+        error: function(jqXHR, textStatus, errorThrown) {
+            console.error("AJAX Error:", textStatus, errorThrown);
+        }
+    });
+}
+
+// 초기화 버튼
+function fnCallToListReset(){
+    var totalCount = twSmsTable.getData().length;
+    if(totalCount < 1){
+        alert("받는사람 목록이 없습니다.");
+        return false;
+    }
+
+    if(!confirm("기존 받는사람이 모두 초기화되며, 복구할 수 없습니다. 진행하시겠습니까?")){
+        return false;
+    }
+
+
+    var sendData = {
+        "tmpJobId" : $('#tmpJobId').val() ,
+        "jobStatus" : $('#jobStatus').val()
+    }
+
+    $.ajax({
+        type: "POST",
+        url: "/web/mjon/msgcampain/deleteCandidateTWCallToData.do",
+        contentType: 'application/json',
+        data: JSON.stringify(sendData),
+        dataType: 'json',
+        success: function(data) {
+            // if(data.status == 'OK')
+        },
+        error: function (e) { console.log("ERROR : ", e); },
+        beforeSend: function() { $('.loading_layer').addClass('active'); },
+        complete: function() { location.reload() }
+    });
+}
+
+
+
+
+// 발송 event
+
+
+var imgFilePath = []; // 최종 선택한 이미지 경로 저장 변수
+var imgFileId = []; // 최종 선택한 파일 아이디 저장 변수
+var templateYn = []; // 템플릿 사용 여부 저장 변수
+
+//이벤트가 아닌 일반 개별 단가 셋팅해주기
+function getEventEachPrice(evnMsgType){
+
+    var eventEachPrice = 0;
+    var evnImgCnt = $("#imgCnt").val();
+
+    //일반 단가로 변경해주기
+    if(evnMsgType == '4'){
+
+        eventEachPrice = $("#sPrice").val();
+        console.log("eventEachPrice Short::: "+eventEachPrice);
+
+    }else if(evnMsgType == '6'){
+
+        if(evnImgCnt == 0){//장문 가격
+
+            eventEachPrice = $("#mPrice").val();
+            console.log("eventEachPrice Long ::: "+eventEachPrice);
+
+        }else if(evnImgCnt == 1){
+
+            eventEachPrice = $("#pPrice").val();
+            console.log("eventEachPrice p1 ::: "+eventEachPrice);
+
+        }else if(evnImgCnt == 2){
+
+            eventEachPrice = $("#p2Price").val();
+            console.log("eventEachPrice p2 ::: "+eventEachPrice);
+
+        }else if(evnImgCnt == 3){
+
+            eventEachPrice = $("#p3Price").val();
+            console.log("eventEachPrice p3 ::: "+eventEachPrice);
+
+        }
+
+    }
+
+    return eventEachPrice;
+}
+
+//문자발송 처리 함수
+function fn_sendMsgData(e){
+
+    console.log("isTrusted :: ", e?.isTrusted);
+    if (isSendLocked) {
+        console.warn("발송 처리 중입니다. 중복 요청을 무시합니다.");
+        return false;
+    }
+
+    const isUserClick = e && e.isTrusted === true;
+/*    if(e && e.isTrusted){
+        console.log("마우스 클릭 (사용자 직접)");
+    }else{
+        console.log("스크립트/키 이벤트로 실행됨");
+    }*/
+
+    // return false;
+    // 타블레이터 호출
+    var $selectedData = twSmsTable.getSelectedData(); // 데이터 가져오기
+    // console.log('$selectedData : ', $selectedData);
+
+    if(!checkConf()){	//문자온 conf-check
+        alert("현재 문자 발송하기 기능 점검 중입니다.\n\n1분 후 다시 시도해주세요.");
+        return false;
+    }
+
+    var form = document.msgForm;
+    var totPriceOnly = stringReplaceAll(form.totPrice.value, ",", "");
+    var userMoneyOnly = stringReplaceAll(form.myPrice.value, ",", "");
+
+    // test 주석
+    if(parseFloat(userMoneyOnly) < parseFloat(totPriceOnly)){
+        alert("문자 발송에 필요한 회원님의 보유 잔액이 부족 합니다.");
+        return false;
+    }
+
+    // console.log(' 11111 : ');
+    // 폼 유효성 검사
+    if (!validateForm(form)) return false;
+
+    // console.log(' 2222 : ');
+
+    // var blineCodeYn = $("#blineCode").val();
+    // if(blineCodeYn != 'N'){
+    // 	if(!blineSendCheck(blineCodeYn)){	//문자온 conf-check
+    // 		alert("현재 문자 발송하기 기능 점검 중입니다.\n\n잠시 후 다시 시도해주세요.");
+    // 		return false;
+    // 	}
+    // }
+
+    if($selectedData.length > 300000){
+        alert("30만건까지 발송이 가능합니다.\n받는사람 목록을 확인해주세요.");
+        return false;
+    }
+
+    // �� 여기만 조건 추가
+    if(isUserClick){
+        if(!confirm("문자를 전송하시겠습니까?")){
+            return false;
+        }
+    }
+
+
+    var msgType = conTypeCheck($('#smsTxtArea').val());	//입력 문자 길이 체크
+
+    console.log(msgType)
+    console.log(msgType)
+    console.log(msgType)
+    console.log(msgType)
+    console.log(msgType)
+    //금액 소수점 제거 하여 적용 20220623 소수점 버림 처리
+    if(msgType == "P"){//그림문자
+
+        //그림 이미지 갯수에 따른 금액 계산
+        if(imgCnt > 2){//그림 3장일경우
+            price = $('#p3Price').val();
+        }else if(imgCnt > 1){//그림 2장일경우
+            price = $('#p2Price').val();
+        }else{//그림 1장일 경우
+            price = $('#pPrice').val();
+        }
+
+    }else if(msgType == "M"){//장문 문자
+
+        price = $('#mPrice').val();
+
+    }else{//단문문자
+
+        price = $('#sPrice').val();
+
+    }
+    // var msgCnt = userMoney / price;
+    var totPrice = price * $selectedData.length;
+
+    // form.totPrice.value = totPrice.replace(",","");
+
+
+
+    //이벤트 진행중 회원의 경우 이벤트 잔여금액 비교 처리 필요.
+    //이벤트 캐시가 부족한 경우 이벤트 캐시로 발송 가능한 만큼만 이벤트 금액으로 발송 처리해줌.
+    //이 후 나머지 발송 건수는 이벤트 캐시가 아닌 일반 단가로 발송 처리를 진행 함.
+    var eventStatus = form.eventStatus.value;
+
+    if(eventStatus == 'Y'){ //이벤트 진행 대상자이면 문자종류에 이벤트로 구분
+
+        form.eventYn.value = "Y"; //이벤트문자 종류 설정
+
+    }
+
+    var eventRemainCash = parseFloat(form.eventRemainCash.value);
+    console.log('eventStatus : ', eventStatus);
+    console.log('parseFloat(eventRemainCash) : ', parseFloat(eventRemainCash));
+    console.log('parseFloat(totPriceOnly) : ', parseFloat(totPrice));
+    console.log('parseFloat(eventRemainCash) < parseFloat(totPriceOnly) : ', parseFloat(eventRemainCash) < parseFloat(totPriceOnly));
+
+    if(eventStatus == 'Y' && parseFloat(eventRemainCash) < parseFloat(totPrice))
+    {
+
+        // 이벤트 금액 부족 상태 요청하신 모두 발송할 수 없습니다
+        console.log('eventRemainCash : ', eventRemainCash);
+        if(!confirm("고객님의 이벤트 캐시 잔액(" + eventRemainCash + "원) 부족으로 요청하신 문자("+numberWithCommas($selectedData.length)+"건)를 모두 발송할 수 없습니다. 이벤트 캐시 초과 건에 대해서는 일반 단가를 적용하여 발송하시겠습니까?")){
+            return false;
+        }
+
+        // 이벤트 캐시 초과 건에 대해서는 일반 단가를 적용하여 발송하시겠습니까
+
+        var evnMsgType = $("#msgType").val(); 				// 문자전송 타입
+        var norEachPrice = getNorEachPrice(evnMsgType);		// 일반전송 금액
+        var eventEachPrice = getEventEachPrice(evnMsgType);	// 이벤트 전송 금액
+        var eventCount = eventRemainCash/eventEachPrice;	// 이벤트금액으로 전송가능한 수량
+        console.log('eventCount : ', parseInt(eventCount));
+        var norCount = numberWithCommas($selectedData.length)-parseInt(eventCount);	// 일반금액으로 전송수량
+        console.log('norCount : ', parseInt(norCount));
+
+        var norAccount = norCount * norEachPrice;		// 일반금액으로 변경한 발송금액
+        var totAccount = userMoneyOnly - norAccount		//
+        console.log('norAccount : ', norAccount);
+        console.log('userMoneyOnly : ', userMoneyOnly);
+        console.log('totAccount : ', totAccount);
+
+        if(totAccount < 0){
+            alert("고객님의 이벤트 캐시 잔액(" + parseInt(totAccount)*-1 + "원) 부족으로 요청하신 문자("+numberWithCommas($selectedData.length)+"건)를 모두 발송할 수 없습니다.");
+            return false;
+        }
+    }
+
+
+
+    isSendLocked = true;
+
+    // console.log(' !!! imgFilePath : ', imgFilePath);
+
+    // img 처리 영역
+    imgFilePath = [];
+    $('.thumb_wrap').find('.thumb_img').each(function(idx, el) {
+        if($("#delLi"+idx).hasClass("Template")){
+            templateYn.push("Y");
+        } else {
+            templateYn.push("N");
+        }
+
+        if($(el).hasClass("edit_y")) {
+            //이미지 변환
+            const imgBase64 = $(el).attr("src");
+            const decodImg = atob(imgBase64.split(',')[1]);  // base64~ 부분을 제외하고 데이터 디코딩
+
+
+            let array = [];
+            for (let i = 0; i < decodImg.length; i++) {
+                array.push(decodImg.charCodeAt(i));
+            }
+
+            const file = new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
+            const fileName = 'canvas_img_' + new Date().getMilliseconds() + '.jpg';
+            let formData = new FormData();
+            formData.append('file', file, fileName);
+
+            $.ajax({
+                type: 'post',
+                url: '/web/mjon/msgdata/insertEditImageAjax.do',
+                cache: false,
+                data: formData,
+                dataType:'json',
+                processData: false,
+                contentType: false,
+                async: false,
+                success: function (returnData, status) {
+                    if(status == 'success'){
+                        console.log('returnData : ',returnData)
+                        // imgFilePath 에 배열로 담아주기(이미지 순서대로)
+                        //console.log(imgFilePath);
+                        imgFilePath.push(returnData.filefullPath);
+                        imgFileId.push(returnData.atchFileId);
+
+                    } else if(status== 'fail'){
+                        alert(returnData.message);
+                    }
+                },
+                error: function (e) { alert("이미지 업로드에 실패하였습니다."); console.log("ERROR : ", e); }
+            });
+
+        } else {
+            if(imgFilePath.length != imgFileId.length){
+                //에디터 안거친 템플릿 이미지면 바로 src 때림
+                imgFilePath.push($(el).attr("src"));
+            }
+        }
+    });
+
+
+    form.templateYnAdvc.value = templateYn;
+    form.imgFilePathAdvc.value = imgFilePath;
+    form.imgFileIdAdvc.value =  imgFileId;
+    form.callFrom.value = removeDash($('#callFromList').val()); // 발신번호 대쉬(-) 문자 없애주기
+
+    //광고 종류 설정
+
+
+    //발송 Ajax 호출해주기
+    sendMsgAjax_advc();
+}
+
+
+// 기업회원 및 선거후보자 체크
+function deptCandidateChk(){
+
+    var candidateNm = $.trim($("#candidateNmChk").val());
+    var dept = $.trim($("#deptChk").val());
+
+    // 기업회원이면
+    if(dept == 'c'){
+        $('[data-tooltip="alert_layer_popup02"]').trigger('click'); // 기업회원 팝업
+    }else if(!candidateNm){	// 값이 없으면
+        $('[data-tooltip="alert_layer_popup"]').trigger('click'); // 후보자 등록 팝업
+    }
+}
+
+function sendMsgAjax_advc(){
+    // 타블레이터 호출
+    var $selectedData = twSmsTable.getSelectedData(); // 데이터 가져오기
+
+    // 폼 데이터를 배열로 직렬화
+    var form = $('#msgForm');
+    var formDataArray = form.serializeArray();
+
+    // 배열을 객체로 변환
+    var formData = {};
+    $.each(formDataArray, function(index, field) {
+        formData[field.name] = field.value;
+    });
+
+    // 빈 값 제거
+    removeEmptyValues(formData);
+
+    // 선택된 데이터 추가
+    formData["mjonMsgSendVOList"] = $selectedData;
+
+    // JSON 데이터 확인
+    console.log("최종 formData:", JSON.stringify(formData));
+
+    // var url = "/web/mjon/msgdata/sendMsgDataAjax_advc.do";
+    // var url = "/web/mjon/msgcampain/sendMsgDataAjax.do";
+    var url = "/web/mjon/msgcampain/sendMsgDataAjax_advc.do";
+    // 시작 시간
+
+    // 프로그래스파 시간을 위한 계산
+    var estimtedTime = calculateEstimatedTime($selectedData.length);
+
+
+    $.ajax({
+        type: "POST",
+        url: url,
+        data: JSON.stringify(formData),
+        contentType: 'application/json',
+        dataType: 'json',
+        success: function (data) {
+
+
+            console.log('발송 결과 data : ', data);
+            console.log('발송 결과 data : ', data);
+            console.log(' ::data.status:: ');
+
+            if (data.status === "OK") {
+                const resultSts      = Number(data.object.resultSts || 0);
+                const resultBlockSts = Number(data.object.resultBlockSts || 0);
+                const resultBlockList = data.object.resultBlockList || [];
+
+
+                // 선택된 데이터는 선택 해제 전에 미리 복사
+                const $selectedData = twSmsTable.getSelectedData();
+
+                // 1. 테이블 상태 정확히 업데이트
+                updateTableAfterSend(resultSts, resultBlockSts, resultBlockList);
+
+                // 2. DB 실제 SEND_FLAG 업데이트
+                updateDbSendResult(resultBlockList, $selectedData);
+
+                // 자동 페이지 이동 기능
+                const isAutoPageMove = $("#autoPageMove").is(":checked");
+                if (isAutoPageMove) {
+                    // console.log("currentPage :: ", twSmsTable.getPage());
+                    // console.log("pageMax :: ", twSmsTable.getPageMax());
+
+                    const currentPage = Number(twSmsTable.getPage() || 1);
+                    const pageMax = Number(twSmsTable.getPageMax() || 1);
+
+                    // 현재 페이지에서 아직 선택 가능한 행(= 체크박스 살아있는 발송전 상태) 조회
+                    const remainSelectableRows = getCurrentPageSelectableRows();
+
+                    console.log("remainSelectableRows.length :: ", remainSelectableRows.length);
+
+                    // 현재 페이지에 더 이상 선택 가능한 행이 없을 때만 다음 페이지 이동
+                    if (remainSelectableRows.length === 0 && currentPage < pageMax) {
+                        setTimeout(function() {
+                            twSmsTable.setPage(currentPage + 1);
+                        }, 300);
+                    }
+                }
+            }
+            else if (data.status === "BAD_REQUEST") {
+                alert(data.message || "잘못된 요청입니다.");
+            }
+            else if (data.status === "UNAUTHORIZED") {
+                alert(data.message);
+                goMsgUrlMove();
+            }
+            else if("FORBIDDEN" == data.status){ // 정지 회원 처리
+                deptCandidateChk();
+                return false;
+            }
+            else {
+                alert("발송 처리 중 오류가 발생했습니다.");
+            }
+            // 갱신된 금액 이벤트 잔액 불러오기
+            getBeforeCashData();
+        },
+        beforeSend : function(xmlHttpRequest) {
+            // 프로그래스 바 실행
+            progressStart(estimtedTime);
+        },
+        complete : function(xhr, textStatus) {
+
+            // 프로그래스 바 종료
+            progressComplete();
+            // ✅ 여기서 잠금을 해제합니다. 서버 응답이 완전히 끝난 후 다음 발송 허용.
+            isSendLocked = false;
+        },
+        error: function (e) { alert("문자 발송에 실패하였습니다."); console.log("ERROR : ", e); }
+    });
+
+}
+
+// 발송 후 DB SEND_FLAG 업데이트 (20건 기준 단순화)
+function updateDbSendResult(resultBlockList, $selectedData) {
+
+    console.log(' :: updateDbSendResult :: ')
+    // Tabulator에서 현재 선택된 행 데이터 가져오기
+    if ($selectedData.length === 0) return;
+    const blockSet = new Set(resultBlockList || []);
+    const failPhones = [];
+    const successPhones = [];
+
+    // 선택된 데이터 순회하면서 성공/실패 분류
+    $selectedData.forEach(item => {
+        const phone = String(item.phone || "").replace(/[^0-9]/g, '');
+        if (blockSet.has(phone)) {
+            failPhones.push(phone);
+        } else {
+            successPhones.push(phone);
+        }
+    });
+    $.ajax({
+        type: "POST",
+        url: "/web/mjon/msgcampain/updateSendFlagAfterSend.do",
+        contentType: 'application/json',
+        data: JSON.stringify({
+            successPhones: successPhones,
+            failPhones: failPhones
+        }),
+        dataType: 'json',
+        success: function(res) {
+            console.log("DB SEND_FLAG 업데이트 완료", res);
+        },
+        error: function(e) {
+            console.error("DB 업데이트 실패", e);
+        }
+    });
+}
+
+
+//폼 유효성 검사 함수
+function validateForm(form) {
+
+    // 타블레이터 호출
+    var $selectedData = twSmsTable.getSelectedData(); // 데이터 가져오기
+
+    // console.log('$selectedData : ', $selectedData);
+    if($selectedData.length < 1){
+        alert("받는사람 내역을 입력해주세요.");
+        return false;
+    }
+
+
+    if(form.callFromList.value == ""){
+
+        alert("발신번호를 입력해 주세요.");
+        return false;
+
+    }
+
+    if (form.subjectChkYn.value === 'N') {
+        form.mmsSubject.value = "";
+    } else if (getSpacialStringChk(form.mmsSubject.value)) {
+        alert("문자 제목에는 치환문자(엑셀 내 *이름*, *1*, *2*, *3*, *4* 등)를 사용하실 수 없습니다.");
+        return false;
+    }
+
+    //문자제목에 이모지가 있는지 체크
+    var titleStatusYn = $("input[name='subjectChkYn']:checked").val();
+    if(titleStatusYn == 'Y') {
+        if(!emojiCheck(form.mmsSubject.value)) return false;
+    }
+
+    // 문자내용에 이모지가 있는지 체크
+    var strCont = form.smsTxtArea.value;
+    if (!emojiCheck(strCont)) return false;
+
+    var rtnStr = strChinJpnCheck(strCont);
+    if(rtnStr.length > 0){
+        alert("입력하신 문구 중 \" " + rtnStr + " \" 는 일부 휴대폰에서 표기되지 않을 수 있습니다.");
+    }
+
+    if (imgFilePath.length === 0 && !form.smsTxtArea.value) {
+        alert("문자내용을 입력해 주세요.");
+        return false;
+    }
+    return true;
+}
+
+
+
+
+//빈 값이나 null 값을 제거하는 함수
+function removeEmptyValues(obj) {
+    Object.keys(obj).forEach(function(key) {
+        if (obj[key] === null || obj[key] === '') {
+            delete obj[key];
+        }
+    });
+}
+
+
+// 선택된 데이터의 길이에 따라 예상 시간 계산 함수
+function calculateEstimatedTime(selectedCount) {
+    //기준값
+    // const processTimePerBatch = 130; // 130초
+
+
+    // 30만건 기준 10분으로 기준을 잡아서
+    // 시간계산함
+    const processTimePerBatch = 600;
+    const batchSize = 300000;
+
+    // 1건당 처리 시간
+    const timePerRecord = processTimePerBatch / batchSize;
+
+    // 예상 시간 계산
+    const estimatedTimeInSeconds = selectedCount * timePerRecord;
+
+    return estimatedTimeInSeconds.toFixed(2);
+}
+/**
+ * 발송 성공 후 테이블 상태 정확히 업데이트
+ * resultBlockList를 이용해 실제 성공/실패 구분
+ */
+function updateTableAfterSend(resultSts, resultBlockSts, resultBlockList) {
+    const table = window.twSmsTable;
+    if (!table) return;
+
+    // 빠른 조회를 위한 Set (전화번호 기준)
+    const blockSet = new Set(resultBlockList || []);
+
+    table.blockRedraw();          // 성능 최적화 (한 번에 redraw)
+
+    try {
+        const selectedRows = table.getSelectedRows();   // 선택된 행만 처리
+
+        selectedRows.forEach(row => {
+            const data = row.getData();
+            const phone = String(data.phone || "").replace(/[^0-9]/g, ''); // 대시 제거
+
+            console.log("phone :: "+ phone);
+            // 실제 발송 결과 판단
+            if (blockSet.has(phone)) {
+                data.status = "발송제외";     // 또는 "F" (formatter가 처리한다면 F도 OK)
+            } else {
+                data.status = "발송완료";     // 또는 "Y"
+            }
+
+
+            row.update(data);      // 행 업데이트
+            row.deselect();        // 선택 해제
+        });
+
+    } finally {
+        table.restoreRedraw();     // redraw 복구
+    }
+
+    // 좌측 카운트 갱신
+    refreshSendCounts();
+
+    console.log(`✅ 테이블 업데이트 완료: 성공 ${resultSts}건, 제외 ${resultBlockSts}건`);
+}
+
+
+
+function refreshSendCounts() {
+    var table = window.twSmsTable;
+    if (!table) return;
+
+    var allRows = table.getData();   // 전체 데이터 (모든 페이지 포함)
+
+    var totalCnt = allRows.length;
+    var completeCnt = 0;   // 발송완료 (Y)
+    var excludeCnt = 0;    // 발송제외 (F)
+    var remainCnt = 0;     // 잔여 (발송전)
+
+    var hasSent = false;
+    allRows.forEach(function(row) {
+        var status = String(row.status || "").trim();
+
+        if (status === "Y" || status === "발송완료") {
+            completeCnt++;
+            hasSent = true;
+        } else if (status === "F" || status === "발송제외") {
+            excludeCnt++;
+            hasSent = true;
+        } else {
+            remainCnt++;
+        }
+    });
+
+    // 화면에 표시
+    $("#totCallToCnt").text(numberWithCommas(totalCnt));
+    $("#sendCompleteCnt").text(numberWithCommas(completeCnt));
+    $("#excludeSendCnt").text(numberWithCommas(excludeCnt));
+    $("#remainCnt").text(numberWithCommas(remainCnt));
+
+    // 테이블 redraw (필요 시)
+    table.redraw(true);
+
+    if(hasSent){
+        $(".callToBtn").prop("disabled", true);
+    }
+    /*else{
+        $(".callToBtn").prop("disabled", false);
+    }*/
+
+}
+
+
+function moveToFirstSelectablePage(){
+    if(!window.twSmsTable){
+        return;
+    }
+
+    var table = window.twSmsTable;
+    var rows = table.getRows("active");
+    var pageSize = table.getPageSize() || 20;
+
+    if(!rows || !rows.length){
+        table.setPage(1);
+        return;
+    }
+
+    for(var i = 0; i < rows.length; i++){
+        var rowData = rows[i].getData();
+
+        if(isSelectableStatus(rowData.status)){
+            var targetPage = Math.floor(i / pageSize) + 1;
+
+            if((table.getPage() || 1) !== targetPage){
+                table.setPage(targetPage);
+            }
+
+            return;
+        }
+    }
+
+    table.setPage(1);
+}(No newline at end of file)
 
src/main/webapp/js/web/msgcampain/tw/init.js (added)
+++ src/main/webapp/js/web/msgcampain/tw/init.js
@@ -0,0 +1,139 @@
+/**
+ * Tabulator.js 기반의 메시지 발송 대상자 관리 스크립트
+ * 
+ * 주요 기능:
+ * 1. 발송 가능 상태(발송전)인 대상자만 선택 가능하도록 제어
+ * 2. 사용자 정의 페이지네이션 UI 구현
+ * 3. 마우스 드래그를 이용한 행(Row) 범위 선택
+ * 4. 버튼 클릭 및 엔터키 롱프레스를 통한 대량 행 자동 선택 (연속 선택)
+ */
+
+$(document).ready(function(){
+
+
+    fn_chkTmpJobStatus();
+
+    // fn_setTwSmsTable();
+
+});
+
+
+function fn_chkTmpJobStatus(){
+
+    // console.log('=========================fn_setTwSmsTable=========================');
+
+    var url = "/web/mjon/msgcampain/chkTmpJobStatusAjax.do";
+    $.ajax({
+        type: 'POST',
+        url: url,
+        contentType: 'application/json',
+        dataType: 'json'
+        ,beforeSend : function() {
+            //로딩창 show
+            $('.loading_layer').addClass('active');
+        },
+        success : function(data) {
+            console.log(' + fn_chkTmpJobStatus data : ', data);
+            // alert(data.msg);
+            if(data.status == 'OK')
+            {
+                if(data.data == null){
+                    $('.loading_layer').removeClass('active');
+                }else if(data.data.jobStatus == 'P'){
+                    setTimeout(function(){
+                        fn_chkTmpJobStatus();
+                    }, 3000);
+                }else if(data.data.jobStatus == 'C'){
+                    var tmpJobId = data.data.tmpJobId;
+                    $('#tmpJobId').val(tmpJobId);
+                    fn_setTwSmsTable(tmpJobId);
+                }
+            }
+            else
+            {
+                // 실패 처리 로직
+            }
+        }
+        ,error: function(jqXHR, textStatus, errorThrown) {
+            console.error("AJAX 실패:", textStatus, errorThrown);
+            console.error("서버 응답 전체:", jqXHR.responseText.substring(0, 500)); // 앞부분만 출력
+
+            // ★★★ 중요: 실제 받은 내용 확인용 ★★★
+            if (jqXHR.responseText && jqXHR.responseText.includes('<!DOCTYPE')) {
+                console.error("HTML 응답 받음 → 서버에서 JSON 대신 HTML 반환 중 (404/500/로그인 리다이렉트?)");
+            }
+        }
+        ,complete : function(xhr, textStatus) {
+            //로딩창 hide
+            // $('.loading_layer').removeClass('active');
+        }
+    });
+}
+
+
+// 기존에 받는 사람 목록 가져오기
+function fn_setTwSmsTable(tmpJobId){
+
+
+
+
+    var sendData = {
+        "tmpJobId" : tmpJobId
+    }
+    console.log('=========================fn_setTwSmsTable=========================');
+
+    var url = "/web/mjon/msgcampain/selectMsgTWCallToListAjax_advc.do";
+    $.ajax({
+        type: 'POST',
+        url: url,
+        contentType: 'application/json',
+        data: JSON.stringify(sendData),
+        dataType: 'json'
+        ,beforeSend : function() {
+            //로딩창 show
+            // $('.loading_layer').addClass('active');
+        },
+        success : function(data) {
+            console.log(' + fn_setTwSmsTable data : ', data);
+            // alert(data.msg);
+            if(data.status == 'OK')
+            {
+
+                var sendList = data.data.map(function(row) {
+                    // console.log('row.sendFlag : ', rowㄴ.sendFlag);
+                    return {
+                        name: row.callNm  || "",   // 이름 → callNm
+                        phone: row.callTo || "",    // 전화번호 → callTo
+                        status: row.sendFlag || ""    // 전화번호 → callTo
+                        // 필요하면 추가 필드 넣기
+                        // status: row.status,
+                    };
+                });
+                twSmsTable.setData(sendList).then(function(){
+                    refreshSendCounts();
+                    moveToFirstSelectablePage();
+                });
+            }
+            else
+            {
+                // 실패 처리 로직
+            }
+        }
+        ,error: function(jqXHR, textStatus, errorThrown) {
+            console.error("AJAX 실패:", textStatus, errorThrown);
+            console.error("서버 응답 전체:", jqXHR.responseText.substring(0, 500)); // 앞부분만 출력
+
+            // ★★★ 중요: 실제 받은 내용 확인용 ★★★
+            if (jqXHR.responseText && jqXHR.responseText.includes('<!DOCTYPE')) {
+                console.error("HTML 응답 받음 → 서버에서 JSON 대신 HTML 반환 중 (404/500/로그인 리다이렉트?)");
+            }
+        }
+        ,complete : function(xhr, textStatus) {
+            //로딩창 hide
+            $('.loading_layer').removeClass('active');
+        }
+    });
+
+
+
+}(No newline at end of file)
 
src/main/webapp/js/web/msgcampain/tw/tabulator.js (added)
+++ src/main/webapp/js/web/msgcampain/tw/tabulator.js
@@ -0,0 +1,645 @@
+/**
+ * Tabulator.js 기반의 메시지 발송 대상자 관리 스크립트
+ * 
+ * 주요 기능:
+ * 1. 발송 가능 상태(발송전)인 대상자만 선택 가능하도록 제어
+ * 2. 사용자 정의 페이지네이션 UI 구현
+ * 3. 마우스 드래그를 이용한 행(Row) 범위 선택
+ * 4. 버튼 클릭 및 엔터키 롱프레스를 통한 대량 행 자동 선택 (연속 선택)
+ */
+// 버튼(개별선택)을 길게 누를 때 연속 선택 처리를 위한 타이머
+var buttonLongPressTimer = null;
+
+// 엔터키를 길게 누를 때 연속 선택 처리를 위한 타이머
+var enterLongPressTimer = null;
+
+// 현재 엔터키가 눌려 있는 상태인지 여부 (중복 실행 방지)
+var isEnterPressed = false;
+
+// 마우스 드래그를 통해 행을 선택 중인지 여부
+var isDragSelecting = false;
+
+// 마우스 왼쪽 버튼이 행(Row) 위에서 눌려 있는 상태인지 여부
+var isMouseDownOnRow = false;
+
+// 드래그 선택이 시작된 행(Row) 객체
+var dragStartRow = null;
+
+// 드래그가 시작된 행이 선택 가능한 상태(발송전)였는지 여부
+var dragStartedOnSelectableRow = false;
+
+$(document).ready(function(){
+
+
+
+
+    /**
+     * Tabulator 인스턴스 생성 및 설정
+     */
+    var table = new Tabulator("#sms-table", {
+        height:"255px",
+        layout: "fitColumns",
+        selectableRows: true, // 행 선택 기능 활성화
+        
+        // 특정 행이 선택 가능한지 체크하는 함수
+        selectableRowsCheck: function(row){
+            return isSelectableStatus(row.getData().status);
+        },
+
+        // 행이 렌더링될 때의 모양을 정의
+        rowFormatter:function(row){
+            // 선택 불가능한 행은 체크박스를 숨김 처리
+            if(!isSelectableStatus(row.getData().status)){
+                var checkbox = row.getElement().querySelector("input[type='checkbox']");
+                if(checkbox){
+                    checkbox.style.display = "none";
+                }
+            }
+        },
+
+        pagination: "local", // 로컬(클라이언트 측) 페이지네이션 사용
+        paginationSize: 20,  // 한 페이지에 20개씩 표시
+        placeholder: "주소록 또는 엑셀 불러오기를 통해"+
+                     "\n" +"받는사람 명단을 등록해주세요.",
+        columns: [
+            {
+                formatter: "rowSelection", // 선택 체크박스 컬럼
+                hozAlign: "center",
+                headerSort: false,
+                width: 40,
+                cellClick: function(e, cell){
+                    e.stopPropagation(); // 셀 클릭 시 이벤트 전파 차단
+
+                    var row = cell.getRow();
+
+                    // 선택 불가능한 상태면 클릭 무시
+                    if(!isSelectableStatus(row.getData().status)){
+                        return;
+                    }
+
+                    row.toggleSelect(); // 선택 상태 토글
+                }
+            },
+            {
+                title: "No",
+                field: "rowNo",
+                width: 50,
+                hozAlign: "center",
+                headerHozAlign: "center",
+                headerSort: false,
+                formatter: function(cell){
+                    var row = cell.getRow();
+                    var table = cell.getTable();
+                    var page = table.getPage() || 1;
+                    var pageSize = table.getPageSize() || 20;
+                    var position = row.getPosition(true);
+
+                    if(position === false || position === null || position === undefined){
+                        return "";
+                    }
+
+                    return ((page - 1) * pageSize) + position;
+                }
+            },
+            {
+                title: "이름",
+                field: "name",
+                widthGrow: 1,
+                headerSort: true,
+                hozAlign: "center"
+            },
+            {
+                title: "번호",
+                field: "phone",
+                width: 150,
+                widthGrow: 2,
+                headerSort: true,
+                cssClass: "phone-cell",
+                hozAlign: "center"
+            },
+            {
+                title: "발송여부",
+                field: "status",
+                widthGrow: 1,
+                headerSort: true,
+                hozAlign: "center",
+                formatter: function(cell){
+                    var val = cell.getValue();
+
+                    // null, undefined, 빈 문자열 처리
+                    if (val == null || val === "" || String(val).trim() === "") {
+                        return "발송전";
+                    }
+
+                    // N → 발송전, Y → 발송완료, F → 발송제외
+                    switch(val){
+                        case "N": return "발송전";
+                        case "Y": return "발송완료";
+                        case "F": return "발송제외";
+                        default: return val;  // 예상치 못한 값은 그대로
+                    }
+                }
+            }
+        ],
+        // 테이블 렌더링 완료 시 실행 (페이지네이션 UI 생성 및 높이 조정)
+        renderComplete: function(){
+            renderCustomPagination();
+            // fitTableHeightToRows();
+        },
+        // 페이지 변경 완료 시 실행
+        pageLoaded: function(){
+            renderCustomPagination();
+            // setTimeout(function(){
+            //     fitTableHeightToRows();
+            // }, 0);
+        }
+    });
+
+    // 전역에서 테이블 인스턴스에 접근 가능하도록 설정
+    window.twSmsTable = table;
+
+    /**
+     * 사용자 정의 페이지네이션 UI를 렌더링합니다. (숫자 버튼 5개 단위)
+     */
+    function renderCustomPagination(){
+        var currentPage = table.getPage();
+        var maxPage = table.getPageMax();
+        var $pagination = $("#sms-pagination");
+
+        if(!$pagination.length){
+            return;
+        }
+
+        if(!maxPage || maxPage < 1){
+            $pagination.empty();
+            return;
+        }
+
+        var html = "";
+        // 5페이지씩 묶어서 표시 (1~5, 6~10 ...)
+        var startPage = Math.floor((currentPage - 1) / 5) * 5 + 1;
+        var endPage = startPage + 4;
+
+        if(endPage > maxPage){
+            endPage = maxPage;
+        }
+
+        // 처음으로, 이전 버튼
+        html += "<button type='button' class='page-btn' data-page='first' " + (currentPage === 1 ? "disabled" : "") + ">«</button>";
+        html += "<button type='button' class='page-btn' data-page='prev' " + (currentPage === 1 ? "disabled" : "") + ">‹</button>";
+
+        // 숫자 페이지 버튼
+        for(var i = startPage; i <= endPage; i++){
+            html += "<button type='button' class='page-btn " + (i === currentPage ? "active" : "") + "' data-page='" + i + "'>" + i + "</button>";
+        }
+
+        // 다음, 끝으로 버튼
+        html += "<button type='button' class='page-btn' data-page='next' " + (currentPage === maxPage ? "disabled" : "") + ">›</button>";
+        html += "<button type='button' class='page-btn' data-page='last' " + (currentPage === maxPage ? "disabled" : "") + ">»</button>";
+
+        $pagination.html(html);
+    }
+
+    /**
+     * 페이지네이션 버튼 클릭 이벤트 바인딩
+     */
+    $(document).on("click", "#sms-pagination .page-btn", function(){
+        var page = $(this).data("page");
+
+        if($(this).prop("disabled")){
+            return;
+        }
+
+        if(page === "first"){
+            table.setPage(1);
+            return;
+        }
+
+        if(page === "prev"){
+            table.previousPage();
+            return;
+        }
+
+        if(page === "next"){
+            table.nextPage();
+            return;
+        }
+
+        if(page === "last"){
+            table.setPage(table.getPageMax());
+            return;
+        }
+
+        table.setPage(Number(page));
+    });
+
+
+
+    /**
+     * 현재 페이지에서 선택되지 않은 행 하나를 선택합니다.
+     * @returns {boolean} - 선택 성공 여부
+     */
+    function selectOneRowInCurrentPage(){
+        var rows = getCurrentPageSelectableRows();
+
+        for(var i = 0; i < rows.length; i++){
+            var row = rows[i];
+
+            if(!row.isSelected()){
+                row.select();
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * 현재 페이지에서 여러 행을 빠르게 선택합니다. (성능을 위해 blockRedraw 사용)
+     * @param {number} count - 선택할 행의 개수
+     * @returns {boolean} - 하나 이상의 행이 선택되었는지 여부
+     */
+    function selectRowsFastInCurrentPage(count){
+        var rows = getCurrentPageSelectableRows();
+        var selectedCount = 0;
+
+        table.blockRedraw(); // 렌더링 일시 정지 (성능 향상)
+
+        try{
+            for(var i = 0; i < rows.length; i++){
+                var row = rows[i];
+
+                if(!row.isSelected()){
+                    row.select();
+                    selectedCount++;
+
+                    if(selectedCount >= count){
+                        break;
+                    }
+                }
+            }
+        }finally{
+            table.restoreRedraw(); // 렌더링 재개
+        }
+
+        return selectedCount > 0;
+    }
+
+    /**
+     * 드래그 선택 관련 상태를 초기화합니다.
+     */
+    function resetDragState(){
+        isMouseDownOnRow = false;
+        isDragSelecting = false;
+        dragStartRow = null;
+        lastDragRow = null;
+    }
+
+    /**
+     * DOM 엘리먼트로부터 해당 Tabulator Row 컴포넌트를 찾습니다.
+     * @param {HTMLElement} rowEl - 행 엘리먼트
+     * @returns {Object|null} - Row 컴포넌트
+     */
+    function getRowComponentFromElement(rowEl){
+        var rows = table.getRows();
+
+        for(var i = 0; i < rows.length; i++){
+            if(rows[i].getElement() === rowEl){
+                return rows[i];
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 시작 행부터 끝 행까지의 범위를 선택합니다.
+     * @param {Object} startRow - 시작 Row 컴포넌트
+     * @param {Object} endRow - 끝 Row 컴포넌트
+     */
+    function selectRowRange(startRow, endRow){
+        if(!startRow || !endRow){
+            return;
+        }
+
+        var rows = table.getRows("visible");
+        var startIndex = -1;
+        var endIndex = -1;
+
+        // 시작 행과 끝 행의 인덱스 찾기
+        for(var i = 0; i < rows.length; i++){
+            if(rows[i] === startRow){
+                startIndex = i;
+            }
+
+            if(rows[i] === endRow){
+                endIndex = i;
+            }
+        }
+
+        if(startIndex === -1 || endIndex === -1){
+            return;
+        }
+
+        var minIndex = Math.min(startIndex, endIndex);
+        var maxIndex = Math.max(startIndex, endIndex);
+
+        // 범위 내의 선택 가능한 행들을 모두 선택
+        for(var j = minIndex; j <= maxIndex; j++){
+            var row = rows[j];
+
+            if(isSelectableStatus(row.getData().status) && !row.isSelected()){
+                row.select();
+            }
+        }
+    }
+
+    /**
+     * 마우스 좌표가 테이블 영역을 벗어났을 때 가장 가장자리에 있는 행을 반환합니다.
+     * (드래그 중 테이블 밖으로 나갔을 때 처리를 위해 사용)
+     * @param {MouseEvent} e - 마우스 이벤트
+     * @returns {Object|null} - 가장자리 Row 컴포넌트
+     */
+    function getEdgeRowByPointer(e){
+        var $holder = $("#sms-table .tabulator-tableholder");
+
+        if(!$holder.length){
+            return null;
+        }
+
+        var holderEl = $holder[0];
+        var rect = holderEl.getBoundingClientRect();
+        var rows = table.getRows("visible");
+
+        if(!rows.length){
+            return null;
+        }
+
+        if(e.clientY < rect.top){
+            return rows[0]; // 위로 벗어남
+        }
+
+        if(e.clientY > rect.bottom){
+            return rows[rows.length - 1]; // 아래로 벗어남
+        }
+
+        return null;
+    }
+
+    /**
+     * 이벤트 타겟으로부터 행(Row) 컴포넌트를 추출합니다.
+     * @param {HTMLElement} target - 이벤트 타겟
+     * @returns {Object|null} - Row 컴포넌트
+     */
+    function getRowComponentFromTarget(target){
+        var rowEl = $(target).closest(".tabulator-row")[0];
+
+        if(!rowEl){
+            return null;
+        }
+
+        var rows = table.getRows("visible");
+
+        for(var i = 0; i < rows.length; i++){
+            if(rows[i].getElement() === rowEl){
+                return rows[i];
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 행에서 마우스 왼쪽 버튼을 눌렀을 때 (드래그 시작 준비)
+     */
+    $("#sms-table").on("mousedown", ".tabulator-row", function(e){
+        if(e.button !== 0){ // 왼쪽 버튼만 처리
+            return;
+        }
+
+        var row = getRowComponentFromElement(this);
+
+        if(!row){
+            resetDragState();
+            return;
+        }
+
+        isMouseDownOnRow = true;
+        isDragSelecting = false;
+        dragStartRow = row;
+        dragStartedOnSelectableRow = true;
+    });
+
+    /**
+     * 문서 전체에서 마우스가 이동할 때 (드래그 선택 처리)
+     */
+    $(document).on("mousemove", function(e){
+        if(!isMouseDownOnRow || !dragStartRow){
+            return;
+        }
+
+        // 현재 마우스 위치 아래에 있는 행 찾기
+        var target = document.elementFromPoint(e.clientX, e.clientY);
+        var row = getRowComponentFromTarget(target);
+
+        // 행을 못 찾았다면(테이블 밖 등) 가장자리 행 사용
+        if(!row){
+            row = getEdgeRowByPointer(e);
+        }
+
+        if(!row){
+            return;
+        }
+
+        // 시작 행과 다른 행으로 이동했다면 드래그 선택 모드로 진입
+        if(row !== dragStartRow){
+            isDragSelecting = true;
+        }
+
+        if(!isDragSelecting){
+            return;
+        }
+
+        // 동일한 행 위에서의 중복 호출 방지
+        if(lastDragRow === row){
+            return;
+        }
+
+        lastDragRow = row;
+        selectRowRange(dragStartRow, row);
+    });
+
+    /**
+     * 행에서 마우스 버튼을 눌렀을 때 (이벤트 타겟 기반)
+     */
+    $("#sms-table").on("mousedown", ".tabulator-row", function(e){
+        if(e.button !== 0){
+            return;
+        }
+
+        var row = getRowComponentFromTarget(e.target);
+
+        if(!row){
+            resetDragState();
+            return;
+        }
+
+        isMouseDownOnRow = true;
+        isDragSelecting = false;
+        dragStartRow = row;
+        lastDragRow = row;
+    });
+
+    /**
+     * '개별선택' 버튼을 누를 때 (길게 누르면 대량 선택)
+     */
+    $(".btn_check_one").on("mousedown", function(e){
+        e.preventDefault();
+
+        // 엔터키 연속 선택 타이머가 돌고 있다면 정지
+        if(enterLongPressTimer){
+            clearInterval(enterLongPressTimer);
+            enterLongPressTimer = null;
+            isEnterPressed = false;
+        }
+
+        selectRowsFastInCurrentPage(1); // 즉시 1개 선택
+
+        // 120ms 마다 3개씩 연속 선택 시작
+        buttonLongPressTimer = setInterval(function(){
+            var selected = selectRowsFastInCurrentPage(3);
+
+            if(!selected){
+                clearInterval(buttonLongPressTimer);
+                buttonLongPressTimer = null;
+            }
+        }, 120);
+    });
+
+    /**
+     * 마우스 버튼을 뗄 때 연속 선택 및 드래그 타이머 종료
+     */
+    $(document).on("mouseup", function(){
+        resetDragState();
+
+        if(buttonLongPressTimer){
+            clearInterval(buttonLongPressTimer);
+            buttonLongPressTimer = null;
+        }
+    });
+
+    /**
+     * 엔터키(Enter)를 누르고 있을 때 연속 선택 처리
+     */
+ /*   $(document).on("keydown", function(e){
+        if(e.key !== "Enter"){
+            return;
+        }
+
+        if(isEnterPressed){
+            e.preventDefault();
+            return;
+        }
+
+    });*/
+
+    /**
+     * 엔터키에서 손을 뗄 때 타이머 종료
+     */
+    $(document).on("keyup", function(e){
+        if(e.key !== "Enter"){
+            return;
+        }
+
+        isEnterPressed = false;
+
+        if(enterLongPressTimer){
+            clearInterval(enterLongPressTimer);
+            enterLongPressTimer = null;
+        }
+    });
+
+    /**
+     * 마우스가 문서를 벗어날 때 상태 초기화
+     */
+    $(document).on("mouseleave", function(){
+        resetDragState();
+    });
+
+    /**
+     * 창 포커스를 잃을 때 상태 초기화
+     */
+    $(window).on("blur", function(){
+        resetDragState();
+    });
+});
+
+/**
+ * 드래그 선택 중에는 텍스트 선택(하이라이트)을 방지합니다.
+ */
+$(document).on("selectstart", function(e){
+    if(isDragSelecting){
+        e.preventDefault();
+        return false;
+    }
+});
+
+/**
+ * 테이블의 모든 선택 항목을 해제합니다.
+ */
+function clearAllSelection(){
+    if(!window.twSmsTable) return;
+
+    var table = window.twSmsTable;
+
+    table.blockRedraw();
+    try {
+        table.deselectRow();                    // 전체 해제
+        table.getRows("visible").forEach(function(row){
+            row.deselect();                     // visible 행도 강제 해제
+        });
+    } finally {
+        table.restoreRedraw();
+    }
+
+    // 선택 상태 완전 초기화
+    if (typeof table.clearSelectedRows === "function") {
+        table.clearSelectedRows();
+    }
+}
+
+/**
+ * 테이블 내 행의 개수에 따라 테이블 높이를 동적으로 조절합니다.
+ * (스크롤 없이 모든 행을 표시해야 하는 경우 사용)
+ */
+function fitTableHeightToRows(){
+    var $table = $("#sms-table .tabulator");
+    var $header = $("#sms-table .tabulator-header");
+    var $rows = $("#sms-table .tabulator-row");
+    var $footer = $("#sms-table .tabulator-footer");
+
+    if(!$table.length){
+        return;
+    }
+
+    var headerHeight = $header.outerHeight() || 0;
+    var footerHeight = $footer.outerHeight() || 0;
+    var rowCount = $rows.length;
+    var rowHeight = 0;
+
+    if(rowCount > 0){
+        rowHeight = $rows.first().outerHeight() || 0;
+    }
+
+    // 바디 높이 = 행 높이 * 행 개수
+    var bodyHeight = rowHeight * rowCount;
+    // 전체 높이 = 헤더 + 바디 + 푸터 + 오차 보정
+    var totalHeight = headerHeight + bodyHeight + footerHeight + 2;
+
+    $table.css("height", totalHeight + "px");
+    $("#sms-table .tabulator-tableholder").css({
+        "height": bodyHeight + "px",
+        "max-height": "none",
+        "overflow-y": "hidden" // 내부 스크롤 비활성화
+    });
+}(No newline at end of file)
 
src/main/webapp/pb/geo_blocked.html (added)
+++ src/main/webapp/pb/geo_blocked.html
This diff is skipped because there are too many other diffs.
src/main/webapp/publish/css/button.css
--- src/main/webapp/publish/css/button.css
+++ src/main/webapp/publish/css/button.css
This diff is skipped because there are too many other diffs.
src/main/webapp/publish/css/common.css
--- src/main/webapp/publish/css/common.css
+++ src/main/webapp/publish/css/common.css
This diff is skipped because there are too many other diffs.
src/main/webapp/publish/css/content.css
--- src/main/webapp/publish/css/content.css
+++ src/main/webapp/publish/css/content.css
This diff is skipped because there are too many other diffs.
src/main/webapp/publish/css/popupLayer.css
--- src/main/webapp/publish/css/popupLayer.css
+++ src/main/webapp/publish/css/popupLayer.css
This diff is skipped because there are too many other diffs.
 
src/main/webapp/publish/email_form_terms_2026_clause.html (added)
+++ src/main/webapp/publish/email_form_terms_2026_clause.html
This diff is skipped because there are too many other diffs.
src/main/webapp/publish/images/content/cdPop_cont2_7.png (Binary)
--- src/main/webapp/publish/images/content/cdPop_cont2_7.png
+++ src/main/webapp/publish/images/content/cdPop_cont2_7.png
Binary file is not shown
src/main/webapp/publish/images/popup/tw_popup/tw_con_01.jpg (Binary)
--- src/main/webapp/publish/images/popup/tw_popup/tw_con_01.jpg
+++ src/main/webapp/publish/images/popup/tw_popup/tw_con_01.jpg
Binary file is not shown
src/main/webapp/publish/images/popup/tw_popup/tw_con_02.jpg (Binary)
--- src/main/webapp/publish/images/popup/tw_popup/tw_con_02.jpg
+++ src/main/webapp/publish/images/popup/tw_popup/tw_con_02.jpg
Binary file is not shown
src/main/webapp/publish/images/popup/tw_popup/tw_con_03.jpg (Binary)
--- src/main/webapp/publish/images/popup/tw_popup/tw_con_03.jpg
+++ src/main/webapp/publish/images/popup/tw_popup/tw_con_03.jpg
Binary file is not shown
src/main/webapp/publish/images/popup/tw_popup/tw_con_04.jpg (Binary)
--- src/main/webapp/publish/images/popup/tw_popup/tw_con_04.jpg
+++ src/main/webapp/publish/images/popup/tw_popup/tw_con_04.jpg
Binary file is not shown
 
src/main/webapp/publish/sub_election_v2025.html (added)
+++ src/main/webapp/publish/sub_election_v2025.html
This diff is skipped because there are too many other diffs.
Add a comment
List