Merge branch '4786' into advc

This commit is contained in:
hehihoho3@gmail.com 2025-03-25 15:19:51 +09:00
commit 10fb1c7542
33 changed files with 3965 additions and 2039 deletions

11
pom.xml
View File

@ -144,11 +144,12 @@
<version>1.1.2</version> <version>1.1.2</version>
</dependency> </dependency>
<dependency> <!-- https://mvnrepository.com/artifact/cglib/cglib -->
<groupId>cglib</groupId> <dependency>
<artifactId>cglib</artifactId> <groupId>cglib</groupId>
<version>3.1</version> <artifactId>cglib</artifactId>
</dependency> <version>3.3.0</version>
</dependency>
<dependency> <dependency>
<groupId>org.antlr</groupId> <groupId>org.antlr</groupId>

View File

@ -23,6 +23,7 @@ import itn.com.cmm.MjonMsgSendVO;
import itn.com.cmm.OptimalMsgResultDTO; import itn.com.cmm.OptimalMsgResultDTO;
import itn.let.mail.service.StatusResponse; import itn.let.mail.service.StatusResponse;
import itn.let.mjo.event.service.MjonEventVO; import itn.let.mjo.event.service.MjonEventVO;
import itn.let.mjo.mjocommon.MjonCommon;
import itn.let.mjo.msg.service.MjonMsgVO; import itn.let.mjo.msg.service.MjonMsgVO;
import itn.let.mjo.msgagent.service.MjonMsgAgentStsVO; import itn.let.mjo.msgagent.service.MjonMsgAgentStsVO;
import itn.let.mjo.spammsg.web.ComGetSpamStringParser; import itn.let.mjo.spammsg.web.ComGetSpamStringParser;
@ -55,26 +56,6 @@ public final class MsgSendUtils {
// 이벤트 최저 잔액 // 이벤트 최저 잔액
public static final double MIN_EVENT_REMAIN_CASH = 7.5; // 이벤트 최소 잔액 public static final double MIN_EVENT_REMAIN_CASH = 7.5; // 이벤트 최소 잔액
/**
* @methodName : getSmsTxtBytes
* @author : 이호영
* @date : 2024.09.23
* @description : sms 텍스트 바이트 계산 return;
* @param smsTxt
* @return
* @throws UnsupportedEncodingException
*/
public static int getSmsTxtBytes(String smsTxt) throws UnsupportedEncodingException { //문자열 길이 체크 해주기
int smsBytes = 0;
//문자 바이트 계산에 필요한 캐릭터 : 한글 2Byte로 계산
String charset = "euc-kr";
if(StringUtils.isNotEmpty(smsTxt)) {
String smsCont = smsTxt.replace("\r\n", "\n");
smsBytes = smsCont.getBytes(charset).length;
}
// log.info(" + smsBytes :: [{}]", smsBytes);
return smsBytes;
}
/** /**
* @methodName : getMsgType * @methodName : getMsgType
@ -96,7 +77,7 @@ public final class MsgSendUtils {
// msgType = "4"; // msgType = "4";
// } // }
int smsTxtByte = getSmsTxtBytes(p_smsTxt); int smsTxtByte = MjonCommon.getSmsTxtBytes(p_smsTxt);
String msgType = SHORT_MSG_TYPE; String msgType = SHORT_MSG_TYPE;
// 1. 2000 Byte 초과는 에러 처리 // 1. 2000 Byte 초과는 에러 처리
@ -648,7 +629,7 @@ public final class MsgSendUtils {
// 가격을 합산 // 가격을 합산
totalPrice += Float.parseFloat(eachPrice); totalPrice += Float.parseFloat(eachPrice);
} }
mjonMsgVO.setTotalPrice(totalPrice);
} }

View File

@ -0,0 +1,144 @@
package itn.com.cmm.util;
import org.apache.commons.lang3.StringUtils;
import itn.let.kakao.kakaoComm.KakaoVO;
import itn.let.mjo.msg.service.MjonMsgVO;
public class SlackMessageFormatUtil {
private static final String PREFIX_SMISHING = "[스미싱의심]";
private static final String PREFIX_RESERVE = "[예약]";
private static final String PREFIX_IMAGE = "그림문자 ";
/**
* 일반 SMS 메시지 텍스트 포맷팅
*/
public static String formatSmsText(MjonMsgVO mjonMsgVO) {
String smsTxt = mjonMsgVO.getSmsTxt();
String reserveYn = safeGetString(mjonMsgVO.getReserveYn());
String delayYn = safeGetString(mjonMsgVO.getDelayYn());
String smishingYn = safeGetString(mjonMsgVO.getSmishingYn());
// 공통 텍스트 포맷팅 로직 적용
smsTxt = formatMessagePrefix(smsTxt, reserveYn,
"Y".equals(smishingYn) || "Y".equals(delayYn));
// 그림 문자 처리 (SMS 전용 로직)
int fileCount = parseIntOrDefault(mjonMsgVO.getFileCnt(), 0);
if ("6".equals(mjonMsgVO.getMsgType()) && fileCount > 0 && StringUtils.isEmpty(smsTxt)) {
smsTxt = "그림문자 " + smsTxt;
}
return smsTxt;
}
/**
* 카카오톡 메시지 텍스트 포맷팅
*/
public static String formatKakaoText(KakaoVO kakaoVO) {
String smsTxt = kakaoVO.getTemplateContent();
String reserveYn = safeGetString(kakaoVO.getReserveYn());
String atDelayYn = safeGetString(kakaoVO.getAtDelayYn());
// 공통 텍스트 포맷팅 로직 적용
return formatMessagePrefix(smsTxt, reserveYn, "Y".equals(atDelayYn));
}
public static String formatSandName(MjonMsgVO mjonMsgVO) {
String userId = mjonMsgVO.getUserId();
String callFrom = mjonMsgVO.getCallFrom();
String msgType = getMessageTypeLabel(mjonMsgVO.getMsgType(), mjonMsgVO.getFileCnt());
return String.format("[%s][%s]%s", userId, callFrom, msgType);
}
/**
* 메시지 접두사 포맷팅 공통 로직 (예약 스미싱 의심 접두사 처리)
*
* @param messageText 원본 메시지 텍스트
* @param reserveYn 예약 여부
* @param isSmishing 스미싱 의심 여부
* @return 포맷팅된 메시지 텍스트
*/
public static String formatMessagePrefix(String messageText, String reserveYn, boolean isSmishing) {
if ("Y".equals(reserveYn)) {
return isSmishing ? PREFIX_SMISHING + PREFIX_RESERVE + messageText : PREFIX_RESERVE + messageText;
} else if (isSmishing) {
return PREFIX_SMISHING + messageText;
}
return messageText;
}
/**
* @카카오톡용 sandName 포맷팅 메서드
*/
public static String formatKakaoSandName(KakaoVO kakaoVO) {
String userId = kakaoVO.getUserId();
String callFrom = kakaoVO.getCallFrom();
String msgType = getKakaoMessageTypeLabel(kakaoVO.getMsgType());
return String.format("[%s][%s]%s", userId, callFrom, msgType);
}
/**
* 메시지 타입 레이블 반환 (SMS 전용)
*
* @param msgType 메시지 타입
* @param fileCnt 파일 개수
* @return 메시지 타입 레이블
*/
public static String getMessageTypeLabel(String msgType, String fileCnt) {
int fileCount = parseIntOrDefault(fileCnt, 0);
switch (msgType) {
case "4":
return "[단문]";
case "6":
return fileCount == 0 ? "[장문]" : "[그림]";
default:
return "";
}
}
/**
* 카카오톡 메시지 타입 레이블 반환
*
* @param msgType 메시지 타입
* @return 메시지 타입 레이블
*/
public static String getKakaoMessageTypeLabel(String msgType) {
switch (msgType) {
case "8":
return "[알림톡]";
case "9":
return "[친구톡]";
default:
return "";
}
}
/**
* 정수로 변환, 변환 실패 기본값 반환
*
* @param value 변환할 문자열
* @param defaultValue 기본값
* @return 변환된 정수 또는 기본값
*/
public static int parseIntOrDefault(String value, int defaultValue) {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return defaultValue;
}
}
/**
* 안전하게 문자열 가져오기 (null 체크)
*
* @param value 원본 문자열
* @return 원본 문자열 또는 문자열
*/
public static String safeGetString(String value) {
return value == null ? "" : value;
}
}

View File

@ -1,5 +1,9 @@
package itn.let.kakao.kakaoComm; package itn.let.kakao.kakaoComm;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/** /**
* @FileName : KakaoButtonVO.java * @FileName : KakaoButtonVO.java
* @Project : mjon * @Project : mjon
@ -8,6 +12,9 @@ package itn.let.kakao.kakaoComm;
* @프로그램 설명 : button, quickReplies 변수 * @프로그램 설명 : button, quickReplies 변수
*/ */
@ToString
@Getter
@Setter
public class KakaoButtonVO { public class KakaoButtonVO {
private String name = ""; // 버튼명 - linkType AC 선택 버튼명은 채널추가 고정 private String name = ""; // 버튼명 - linkType AC 선택 버튼명은 채널추가 고정
@ -18,48 +25,4 @@ public class KakaoButtonVO {
private String linkPc = ""; // PC 링크 주소 (WL 사용시 선택) private String linkPc = ""; // PC 링크 주소 (WL 사용시 선택)
private String pluginId = ""; // 플러그인 ID (P1, P2, P3 사용시 필수) private String pluginId = ""; // 플러그인 ID (P1, P2, P3 사용시 필수)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLinkType() {
return linkType;
}
public void setLinkType(String linkType) {
this.linkType = linkType;
}
public String getLinkAnd() {
return linkAnd;
}
public void setLinkAnd(String linkAnd) {
this.linkAnd = linkAnd;
}
public String getLinkIos() {
return linkIos;
}
public void setLinkIos(String linkIos) {
this.linkIos = linkIos;
}
public String getLinkMo() {
return linkMo;
}
public void setLinkMo(String linkMo) {
this.linkMo = linkMo;
}
public String getLinkPc() {
return linkPc;
}
public void setLinkPc(String linkPc) {
this.linkPc = linkPc;
}
public String getPluginId() {
return pluginId;
}
public void setPluginId(String pluginId) {
this.pluginId = pluginId;
}
} }

View File

@ -3,6 +3,10 @@ package itn.let.kakao.kakaoComm;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/** /**
* @FileName : KakaoCommentVO.java * @FileName : KakaoCommentVO.java
* @Project : mjon * @Project : mjon
@ -11,6 +15,9 @@ import java.util.List;
* @프로그램 설명 : comment 변수 * @프로그램 설명 : comment 변수
*/ */
@ToString
@Getter
@Setter
public class KakaoCommentVO { public class KakaoCommentVO {
private String content = ""; // 댓글 본분 private String content = ""; // 댓글 본분
@ -26,60 +33,4 @@ public class KakaoCommentVO {
private String originalFileName = ""; private String originalFileName = "";
private String filePath = ""; private String filePath = "";
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getOriginalFileName() {
return originalFileName;
}
public void setOriginalFileName(String originalFileName) {
this.originalFileName = originalFileName;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public List<KakaoCommentVO> getAttachFileList() {
return attachFileList;
}
public void setAttachFileList(List<KakaoCommentVO> attachFileList) {
this.attachFileList = attachFileList;
}
} }

View File

@ -4,6 +4,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import itn.com.cmm.ComDefaultVO; import itn.com.cmm.ComDefaultVO;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
/** /**
* @FileName : KakaoReturnVO.java * @FileName : KakaoReturnVO.java
@ -13,6 +16,9 @@ import itn.com.cmm.ComDefaultVO;
* @프로그램 설명 : 카카오톡 리턴 변수 목록 * @프로그램 설명 : 카카오톡 리턴 변수 목록
*/ */
@Getter
@Setter
@ToString
public class KakaoReturnVO extends ComDefaultVO{ public class KakaoReturnVO extends ComDefaultVO{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -130,415 +136,4 @@ public class KakaoReturnVO extends ComDefaultVO{
private String businessType = ""; //카카오톡 채널 비즈니스 인증 타입 private String businessType = ""; //카카오톡 채널 비즈니스 인증 타입
public static long getSerialversionuid() {
return serialVersionUID;
}
public String getBizReturnMsg() {
return bizReturnMsg;
}
public void setBizReturnMsg(String bizReturnMsg) {
this.bizReturnMsg = bizReturnMsg;
}
public String getBizReturnCode() {
return bizReturnCode;
}
public void setBizReturnCode(String bizReturnCode) {
this.bizReturnCode = bizReturnCode;
}
public String getProfileId() {
return profileId;
}
public void setProfileId(String profileId) {
this.profileId = profileId;
}
public String getTotalCount() {
return totalCount;
}
public void setTotalCount(String totalCount) {
this.totalCount = totalCount;
}
public String getTotalPage() {
return totalPage;
}
public void setTotalPage(String totalPage) {
this.totalPage = totalPage;
}
public String getCurrentPage() {
return currentPage;
}
public void setCurrentPage(String currentPage) {
this.currentPage = currentPage;
}
public String getSenderKey() {
return senderKey;
}
public void setSenderKey(String senderKey) {
this.senderKey = senderKey;
}
public String getSenderKeyType() {
return senderKeyType;
}
public void setSenderKeyType(String senderKeyType) {
this.senderKeyType = senderKeyType;
}
public String getTemplateCode() {
return templateCode;
}
public void setTemplateCode(String templateCode) {
this.templateCode = templateCode;
}
public String getTemplateName() {
return templateName;
}
public void setTemplateName(String templateName) {
this.templateName = templateName;
}
public String getCategoryCode() {
return categoryCode;
}
public void setCategoryCode(String categoryCode) {
this.categoryCode = categoryCode;
}
public String getCreatedAt() {
return createdAt;
}
public void setCreatedAt(String createdAt) {
this.createdAt = createdAt;
}
public String getModifiedAt() {
return modifiedAt;
}
public void setModifiedAt(String modifiedAt) {
this.modifiedAt = modifiedAt;
}
public String getServiceStatus() {
return serviceStatus;
}
public void setServiceStatus(String serviceStatus) {
this.serviceStatus = serviceStatus;
}
public List<KakaoReturnVO> getTemplatList() {
return templatList;
}
public void setTemplatList(List<KakaoReturnVO> templatList) {
this.templatList = templatList;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public boolean isBlock() {
return block;
}
public void setBlock(boolean block) {
this.block = block;
}
public boolean isDormant() {
return dormant;
}
public void setDormant(boolean dormant) {
this.dormant = dormant;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getListTitle() {
return listTitle;
}
public void setListTitle(String listTitle) {
this.listTitle = listTitle;
}
public String getListDescription() {
return listDescription;
}
public void setListDescription(String listDescription) {
this.listDescription = listDescription;
}
public String getSumTitle() {
return sumTitle;
}
public void setSumTitle(String sumTitle) {
this.sumTitle = sumTitle;
}
public String getSumDescription() {
return sumDescription;
}
public void setSumDescription(String sumDescription) {
this.sumDescription = sumDescription;
}
public String getProfileStatus() {
return profileStatus;
}
public void setProfileStatus(String profileStatus) {
this.profileStatus = profileStatus;
}
public boolean isAlimtalk() {
return alimtalk;
}
public void setAlimtalk(boolean alimtalk) {
this.alimtalk = alimtalk;
}
public boolean isBizchat() {
return bizchat;
}
public void setBizchat(boolean bizchat) {
this.bizchat = bizchat;
}
public boolean isBrandtalk() {
return brandtalk;
}
public void setBrandtalk(boolean brandtalk) {
this.brandtalk = brandtalk;
}
public String getCommittalCompanyName() {
return committalCompanyName;
}
public void setCommittalCompanyName(String committalCompanyName) {
this.committalCompanyName = committalCompanyName;
}
public String getChannelKey() {
return channelKey;
}
public void setChannelKey(String channelKey) {
this.channelKey = channelKey;
}
public boolean isBusinessProfile() {
return businessProfile;
}
public void setBusinessProfile(boolean businessProfile) {
this.businessProfile = businessProfile;
}
public String getBusinessType() {
return businessType;
}
public void setBusinessType(String businessType) {
this.businessType = businessType;
}
public String getTemplateMessageType() {
return templateMessageType;
}
public void setTemplateMessageType(String templateMessageType) {
this.templateMessageType = templateMessageType;
}
public String getTemplateEmphasizeType() {
return templateEmphasizeType;
}
public void setTemplateEmphasizeType(String templateEmphasizeType) {
this.templateEmphasizeType = templateEmphasizeType;
}
public String getTemplateContent() {
return templateContent;
}
public void setTemplateContent(String templateContent) {
this.templateContent = templateContent;
}
public String getTemplateExtra() {
return templateExtra;
}
public void setTemplateExtra(String templateExtra) {
this.templateExtra = templateExtra;
}
public String getTemplateAd() {
return templateAd;
}
public void setTemplateAd(String templateAd) {
this.templateAd = templateAd;
}
public String getTemplateImageName() {
return templateImageName;
}
public void setTemplateImageName(String templateImageName) {
this.templateImageName = templateImageName;
}
public String getTemplateImageUrl() {
return templateImageUrl;
}
public void setTemplateImageUrl(String templateImageUrl) {
this.templateImageUrl = templateImageUrl;
}
public String getTemplateTitle() {
return templateTitle;
}
public void setTemplateTitle(String templateTitle) {
this.templateTitle = templateTitle;
}
public String getTemplateSubtitle() {
return templateSubtitle;
}
public void setTemplateSubtitle(String templateSubtitle) {
this.templateSubtitle = templateSubtitle;
}
public String getTemplateHeader() {
return templateHeader;
}
public void setTemplateHeader(String templateHeader) {
this.templateHeader = templateHeader;
}
public Boolean getSecurityFlag() {
return securityFlag;
}
public void setSecurityFlag(Boolean securityFlag) {
this.securityFlag = securityFlag;
}
public String getInspectionStatus() {
return inspectionStatus;
}
public void setInspectionStatus(String inspectionStatus) {
this.inspectionStatus = inspectionStatus;
}
public List<KakaoButtonVO> getButtonList() {
return buttonList;
}
public void setButtonList(List<KakaoButtonVO> buttonList) {
this.buttonList = buttonList;
}
public List<KakaoButtonVO> getQuickReplyList() {
return quickReplyList;
}
public void setQuickReplyList(List<KakaoButtonVO> quickReplyList) {
this.quickReplyList = quickReplyList;
}
public List<KakaoCommentVO> getCommentList() {
return commentList;
}
public void setCommentList(List<KakaoCommentVO> commentList) {
this.commentList = commentList;
}
public List<KakaoItemVO> getItemList() {
return itemList;
}
public void setItemList(List<KakaoItemVO> itemList) {
this.itemList = itemList;
}
} }

View File

@ -0,0 +1,116 @@
package itn.let.kakao.kakaoComm;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
/**
* @FileName : KakaoSendVO.java
* @Project : mjon
* @Date : 2025. 3. 25.
* @작성자 : 이호영
* @프로그램 설명 : 문자온 발송부분만 ADVC
*/
@Getter
@Setter
public class KakaoSendAdvcVO implements Serializable {
/**
*
*/
private static final long serialVersionUID = 343099046833205405L;
// =====
// Insert 데이터
private String msgId; // 문자ID
private String msgGroupId; // 전송그룹ID
private String msgGroupCnt; // 전송그룹ID
private String userId; // 사용자ID
private String agentCode; // 전송사코드
private String senderKey; // 발신프로필
private String templateCode; // 템플릿 코드
private String callTo; // 수신번호
private String callFrom; // 발신번호
private String msgType; // 메시지 타입
private String templateContent; // 템플릿 내용
private String templateTitle; // 템플릿 제목
List<KakaoButtonVO> buttonList; // 템플릿 버튼 리스트
private String subMsgSendYn; // 대체문자 전송 여부
private String subMsgTxt; // 대체문자 내용
private String subMsgType; // 대체문자 타입
private String reqDate; // 예약일시
private String jsonStr; // jsonStr
// =====
// =====
private String eachPrice; // sms 단가
private String smsPrice; // sms 단가
private String mmsPrice; // mms 단가
private String totPrice; // mms 단가
private String befCash; // mms 단가
private String befPoint; // mms 단가
private String kakaoAtPrice; // 카카오 알림톡 단가
private String bizJsonName; // 카카오 알림톡 단가
private String reserveYn; // 카카오 알림톡 단가
private String atDelayYn; // 카카오 알림톡 단가
private String bizKakaoResendOrgnlTxt; // 카카오 알림톡 단가
private String bizKakaoResendType; // 카카오 알림톡 단가
@Override
public String toString() {
return "MsgSendVO[" +
"\n msgId=[" + msgId + "]" +
"\n , msgGroupId=[" + msgGroupId + "]" +
"\n , msgGroupCnt=[" + msgGroupCnt + "]" +
"\n , userId=[" + userId + "]" +
"\n , agentCode=[" + agentCode + "]" +
"\n , senderKey=[" + senderKey + "]" +
"\n , templateCode=[" + templateCode + "]" +
"\n , callTo=[" + callTo + "]" +
"\n , callFrom=[" + callFrom + "]" +
"\n , msgType=[" + msgType + "]" +
"\n , templateContent=[" + templateContent + "]" +
"\n , templateTitle=[" + templateTitle + "]" +
"\n , buttonList=[" + buttonList.toString() + "]" +
"\n , subMsgSendYn=[" + subMsgSendYn + "]" +
"\n , subMsgTxt=[" + subMsgTxt + "]" +
"\n , subMsgType=[" + subMsgType + "]" +
"\n , reqDate=[" + reqDate + "]" +
"\n , jsonStr=[" + jsonStr + "]" +
"\n , ==== MJ_MSG_DATA INSERT DATA END =======" +
"\n " +
"\n , eachPrice=[" + eachPrice + "]" +
"\n , smsPrice=[" + smsPrice + "]" +
"\n , mmsPrice=[" + mmsPrice + "]" +
"\n , totPrice=[" + totPrice + "]" +
"\n , befCash=[" + befCash + "]" +
"\n , befPoint=[" + befPoint + "]" +
"\n , kakaoAtPrice=[" + kakaoAtPrice + "]" +
"\n , bizJsonName=[" + bizJsonName + "]" +
"\n , reserveYn=[" + reserveYn + "]" +
"\n , atDelayYn=[" + atDelayYn + "]" +
"\n , bizKakaoResendOrgnlTxt=[" + bizKakaoResendOrgnlTxt + "]" +
"\n , bizKakaoResendType=[" + bizKakaoResendType + "]" +
"\n ]";
}
}

View File

@ -1,21 +1,38 @@
package itn.let.kakao.kakaoComm; package itn.let.kakao.kakaoComm;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import egovframework.rte.fdl.idgnr.EgovIdGnrService;
import itn.com.cmm.util.StringUtil; import itn.com.cmm.util.StringUtil;
import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiJsonSave; import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiJsonSave;
import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiTemplate;
import itn.let.mail.service.StatusResponse;
import itn.let.mjo.mjocommon.MjonCommon;
import itn.let.mjo.msg.service.MjonMsgVO; import itn.let.mjo.msg.service.MjonMsgVO;
import itn.let.mjo.msgdata.service.MjonMsgDataService; import itn.let.mjo.msgdata.service.MjonMsgDataService;
import itn.let.mjo.spammsg.web.ComGetSpamStringParser; import itn.let.mjo.spammsg.web.ComGetSpamStringParser;
import itn.let.module.base.PriceAndPoint;
import itn.let.sym.site.service.JoinSettingVO; import itn.let.sym.site.service.JoinSettingVO;
import itn.let.uss.umt.service.MberManageVO; import itn.let.uss.umt.service.MberManageVO;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component @Component
public class KakaoSendUtil { public class KakaoSendUtil {
@ -25,6 +42,374 @@ public class KakaoSendUtil {
@Resource(name = "MjonMsgDataService") @Resource(name = "MjonMsgDataService")
private MjonMsgDataService mjonMsgDataService; private MjonMsgDataService mjonMsgDataService;
@Autowired
KakaoApiTemplate kakaoApiTemplate;
@Autowired
private PriceAndPoint priceAndPoint;
@Autowired
private MjonCommon mjonCommon;
// 클래스 수준에서 정적 Pattern 정의 (성능 최적화)
private static final Pattern REPLACEMENT_PATTERN = Pattern.compile("#\\{[^}]+\\}");
private static final SimpleDateFormat DATE_FORMATTER = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
// 단문 메세지 타입
public static final String SHORT_MSG_TYPE = "SMS";
// 장문 메세지 타입
public static final String LONG_MSG_TYPE = "MMS";
/**
* @methodName : populateSendLists _advc
* @author : 이호영
* @date : 2025. 3. 7.
* @description : 기존 kakaoSendPrice 개선
* @return : KakaoVO
* @param kakaoVO
* @param statusResponse
* @return
* @throws Exception
*
*/
public List<KakaoSendAdvcVO> populateSendLists(KakaoVO kakaoVO, boolean isNotified, StatusResponse statusResponse) throws Exception {
//사용자 현재 보유 금액 불러오기(문자 발송 금액 차감 이전 금액)
// String befCash = kakaoVO.getBefCash();
log.info(" +kakaoVO.getVarListMap().size() :: [{}]", kakaoVO.getVarListMap().size());
List<KakaoSendAdvcVO> kakaoSendAdvcListVO = new ArrayList<>();
Calendar calendar = setupBaseDate(kakaoVO, isNotified);
KakaoReturnVO templateDetail = kakaoApiTemplate.selectKakaoApiTemplateDetail(kakaoVO);
String templateContent = templateDetail.getTemplateContent(); // 알림톡 템플릿
kakaoVO.setTemplateContent(templateContent);
String templateTitle = templateDetail.getTemplateTitle();
// log.info(" + templateDetail :: [{}]", templateDetail);
// templateDetail.getButtonList().forEach(t->log.info(" + ButtonList :: [{}]", t.toString()));
Boolean hasContentReplacement = this.replBooleanStrChecker(templateContent);
Boolean hasTitleReplacement = this.replBooleanStrChecker(templateTitle);
Boolean hasButtonReplacement = this.needsButtonReplacement(templateDetail.getButtonList());
/** @jsonStr 필요유무 */
boolean hasTitleOrButtons = StringUtils.isNotEmpty(templateTitle)
|| CollectionUtils.isNotEmpty(templateDetail.getButtonList());
/** @jsonStr 반복유무 */
boolean needsJsonReplacement = hasTitleReplacement || hasButtonReplacement;
String sharedJsonStr = null;
String subMsgTxt = kakaoVO.getSubMsgTxt(); // 실패 대체 문자
// 시스템 기본 단가 정보 불러오기
JoinSettingVO sysJoinSetVO = mjonMsgDataService.selectJoinSettingInfo();
// 사용자 개인 단가 정보 불러오기
MberManageVO mberManageVO = mjonMsgDataService.selectMberManageInfo(kakaoVO.getUserId());
/** @MSGID KEY값 */
List<String> idList = mjonCommon.getNextCustomMsgCId(kakaoVO.getVarListMap().size());
// for (int i = 0; i < kakaoSendAdvcListVO.size(); i++) {
// kakaoSendAdvcListVO.get(i).setMsgId(idList.get(i));
// kakaoSendAdvcListVO.get(i).setBizJsonName(idList.get(i));
// }
// 분할 건수 카운터
int counter = 0;
/** @Map에 총 갯수가 수신자 갯수와 동일함 */
List<Map<String, String>> varList = kakaoVO.getVarListMap();
for (int i = 0; i < varList.size(); i++) {
// for(Map<String, String> variables : kakaoVO.getVarListMap()) {
// 치환 데이터
Map<String, String> variables = varList.get(i);
/** @공통 기본값 */
KakaoSendAdvcVO sendVO = createSendVO(kakaoVO);
String msgId = idList.get(i);
sendVO.setMsgId(msgId);
// step1
// Step 1-1: 치환 수신번호 셋팅
// Step 1-2: 수신자 정보 설정 (callToList는 항상 설정).
if (variables.containsKey("callToList")) {
sendVO.setCallTo(variables.get("callToList"));
variables.remove("callToList"); // 사용 제거.
}
/** @Step1-3: 템플릿 치환데이터 설정 */
if (hasContentReplacement) {
templateContent = mjonCommon.ATReplaceTemplateVariables(templateContent, variables);
if(hasTitleReplacement) {
templateTitle = mjonCommon.ATReplaceTemplateVariables(templateTitle, variables);
}
}
/** @버튼 치환 */ // 버튼 리스트가 있으면 치환 수행, 항상 sendVO에 설정
List<KakaoButtonVO> buttonList = templateDetail.getButtonList();
if(hasButtonReplacement) {
buttonList = replaceButtonLinks(buttonList, variables);
}
sendVO.setButtonList(buttonList);
sendVO.setTemplateTitle(templateTitle);
sendVO.setTemplateContent(templateContent);
// Step 1-4: 실패 대체 문자 치환데이터 설정
if("Y".equals(kakaoVO.getSubMsgSendYn())) { // 대체문자가 있나?
if ("Y".equals(kakaoVO.getSubMsgTxtReplYn())) { // 치환데이터가 있나?
subMsgTxt = mjonCommon.ATReplaceTemplateVariables(subMsgTxt, variables);
}
sendVO.setSubMsgTxt(subMsgTxt);// 실패
}
sendVO.setSubMsgSendYn(kakaoVO.getSubMsgSendYn());
/*
log.info("kakaoSendAdvcVO Details: [callTo={}\n, templateContent=\n{}\n, subMsgTxt=\n{}]\n\n\n\n",
kakaoSendAdvcVO.getCallTo(),
kakaoSendAdvcVO.getTemplateContent(),
kakaoSendAdvcVO.getSubMsgTxt()
);
*/
// Step1 END
// step3
// 바이트 체크 금액설정
Float kakaoAtPrice = mberManageVO.getKakaoAtPrice();
// 유효한 단가 계산
float shortPrice = getValidPrice(mberManageVO.getShortPrice(), sysJoinSetVO.getShortPrice());
float longPrice = getValidPrice(mberManageVO.getLongPrice(), sysJoinSetVO.getLongPrice());
String shortPStr = Float.toString(shortPrice);
String mmsPStr = Float.toString(longPrice);
// 공통 가격 설정
sendVO.setSmsPrice(shortPStr);
sendVO.setMmsPrice(mmsPStr);
if("Y".equals(kakaoVO.getSubMsgSendYn())) {
int smsTxtByte = mjonCommon.getSmsTxtBytes(sendVO.getSubMsgTxt());
String sendType = getMsgType(smsTxtByte);
sendVO.setSubMsgType(sendType);
if ("INVALID".equals(sendType)) {
statusResponseSet(statusResponse, HttpStatus.BAD_REQUEST, "전송 문자 길이를 초과하였습니다.");return kakaoSendAdvcListVO;
}
boolean isMms = "MMS".equals(sendType);
sendVO.setEachPrice(isMms ? mmsPStr : shortPStr);
} else {
kakaoAtPrice = getValidPrice(mberManageVO.getKakaoAtPrice(), sysJoinSetVO.getKakaoAtPrice());
sendVO.setEachPrice( Float.toString(kakaoAtPrice) );
}
// step4
// 예약 시간 설정 분할 데이터 설정
if ("Y".equalsIgnoreCase(kakaoVO.getReserveYn())
&& "Y".equalsIgnoreCase(kakaoVO.getDivideChk())
&& counter == Integer.parseInt(kakaoVO.getDivideCnt()))
{
counter = 0;
calendar.add(Calendar.MINUTE, Integer.parseInt(kakaoVO.getDivideTime()));
}
counter++;
// 즉시 발송인경우 현재 시간
// 예약인 경우 위에 설정한 시간 입력
sendVO.setReqDate(DATE_FORMATTER.format(calendar.getTime()));
/** @step5 전송 메세지 설정 json파일 만들기*/
// 타이틀과 버튼이 있고
if(hasTitleOrButtons) {
// 버튼과 타이틀에 치환데이터가 있으면 json String을 계속 생성
if(needsJsonReplacement) {
sharedJsonStr = kakaoApiJsonSave.kakaoApiJsonSave_advc(sendVO, templateDetail);
sendVO.setBizJsonName(msgId);
sendVO.setJsonStr(sharedJsonStr);
} else if (StringUtils.isEmpty(sharedJsonStr)) {
// 치환 데이터가 없고 아직 생성되지 않았으면 번만 생성
sharedJsonStr = kakaoApiJsonSave.kakaoApiJsonSave_advc(sendVO, templateDetail);
sendVO.setBizJsonName(idList.get(0));
sendVO.setJsonStr(sharedJsonStr);
}else {
sendVO.setBizJsonName(idList.get(0));
}
}
kakaoSendAdvcListVO.add(sendVO);
}
return kakaoSendAdvcListVO;
}
private Calendar setupBaseDate(KakaoVO kakaoVO, boolean isNotified) throws ParseException {
// 예약 시간 기본값 설정
Date now = new Date();
// ReqDate가 비어 있으면 현재 시간으로 설정, 그렇지 않으면 ReqDate로 설정
// 화면에서 예약문자면 예약시간을 regDate로 설정한다.
Date baseDate;
if (StringUtils.isEmpty(kakaoVO.getReqDate())) {
kakaoVO.setReqDate(DATE_FORMATTER.format(now)); // ReqDate에 현재 시간 설정
baseDate = now;
} else {
baseDate = DATE_FORMATTER.parse(kakaoVO.getReqDate()); // ReqDate를 baseDate로 설정
}
// 시간 성정
Calendar calendar = Calendar.getInstance();
calendar.setTime(baseDate); // calendar에 baseDate 설정
// 지연 여부 처리
// 알림톡 스미싱의심 + 공휴일알림 조건이 맞으면 30분 delay
if ( "Y".equalsIgnoreCase(kakaoVO.getAtSmishingYn())
&& isNotified) {
calendar.add(Calendar.MINUTE, 30); // 모든 시간을 30분 뒤로 미룸
}
return calendar;
}
/**
* @methodName : createSendVO
* @author : 이호영
* @date : 2025. 3. 19.
* @description : populateSendLists 반복에 필요한 공통생성 부분
* @return : KakaoSendAdvcVO
* @param kakaoVO
* @return
*
*/
private KakaoSendAdvcVO createSendVO(KakaoVO kakaoVO) {
KakaoSendAdvcVO sendVO = new KakaoSendAdvcVO();
sendVO.setMsgType("8");
sendVO.setSenderKey(kakaoVO.getSenderKey());
sendVO.setTemplateCode(kakaoVO.getTemplateCode());
sendVO.setUserId(kakaoVO.getUserId());
sendVO.setCallFrom(kakaoVO.getCallFrom());
sendVO.setAgentCode("04");
return sendVO;
}
private List<KakaoButtonVO> replaceButtonLinks(List<KakaoButtonVO> buttonList,
Map<String, String> variables) {
if (buttonList != null) {
for (KakaoButtonVO button : buttonList) {
// 링크 필드에 대해 치환 수행
if (button.getLinkAnd() != null) {
button.setLinkAnd(mjonCommon.ATReplaceTemplateVariables(button.getLinkAnd(), variables));
}
if (button.getLinkIos() != null) {
button.setLinkIos(mjonCommon.ATReplaceTemplateVariables(button.getLinkIos(), variables));
}
if (button.getLinkMo() != null) {
button.setLinkMo(mjonCommon.ATReplaceTemplateVariables(button.getLinkMo(), variables));
}
if (button.getLinkPc() != null) {
button.setLinkPc(mjonCommon.ATReplaceTemplateVariables(button.getLinkPc(), variables));
}
}
// 치환된 버튼 리스트를 sendVO에 반영
// sendVO.setButtonList(buttonList); // KakaoSendAdvcVO에 setButtonList가 있다고 가정
}
return buttonList;
}
/**
* 버튼 리스트에 치환 패턴(#{...}) 있는지 확인합니다.
* @param buttonList 버튼 리스트 (null 가능)
* @return 치환 패턴이 있으면 true, 없으면 false
*/
private boolean needsButtonReplacement(List<KakaoButtonVO> buttonList) {
if (buttonList == null) {
return false;
}
return buttonList.stream().anyMatch(button ->
replBooleanStrChecker(button.getLinkAnd()) ||
replBooleanStrChecker(button.getLinkIos()) ||
replBooleanStrChecker(button.getLinkMo()) ||
replBooleanStrChecker(button.getLinkPc())
);
}
/**
* 입력 문자열에 치환 패턴(#{...}) 있는지 확인합니다.
* @param input 확인할 문자열 (null 가능)
* @return 치환 패턴이 있으면 true, 없으면 false
*/
private boolean replBooleanStrChecker(String input) {
// #{...} 패턴을 확인하는 정규 표현식
if (input == null) {
return false;
}
Matcher matcher = REPLACEMENT_PATTERN.matcher(input);
return matcher.find();
}
public Float getValidPrice(Float personalPrice, Float defaultPrice) {
return (personalPrice != null && personalPrice > 0) ? personalPrice : defaultPrice;
}
/**
* @methodName : getMsgType
* @author : 이호영
* @date : 2025. 3. 12.
* @description : 메세지 타입 구하기
* @return : String
* @param smsTxtByte
* @return
*
*/
private String getMsgType(int smsTxtByte) {
// TODO Auto-generated method stub
String msgType = SHORT_MSG_TYPE;
// 1. 2000 Byte 초과는 에러 처리
if (smsTxtByte > 2000) {
return "INVALID";
}
// 2. 문자 길이에 따라 메시지 타입 설정 (90 Byte 초과는 장문)
if (smsTxtByte > 90) {
msgType = LONG_MSG_TYPE;
}
return msgType;
}
/** /**
* @Method Name : kakaoSendPrice * @Method Name : kakaoSendPrice
@ -34,13 +419,11 @@ public class KakaoSendUtil {
*/ */
public KakaoVO kakaoSendPrice(KakaoVO kakaoVO) throws Exception { public KakaoVO kakaoSendPrice(KakaoVO kakaoVO) throws Exception {
//사용자 현재 보유 금액 불러오기(문자 발송 금액 차감 이전 금액) System.out.println(" :: kakaoSendPrice :: ");
String befCash = kakaoVO.getBefCash();
//사용자 현재 보유 금액 불러오기(문자 발송 금액 차감 이전 금액)
// String befCash = kakaoVO.getBefCash();
//VO에서 현재 보유금액이 없으면 디비에서 조회해서 불러옴
if("".equals(befCash) || befCash == null) {
}
MjonMsgVO mjonMsgVO = new MjonMsgVO(); MjonMsgVO mjonMsgVO = new MjonMsgVO();
mjonMsgVO.setUserId(kakaoVO.getUserId()); mjonMsgVO.setUserId(kakaoVO.getUserId());
String userMoney = mjonMsgDataService.selectBeforeCashData(mjonMsgVO); String userMoney = mjonMsgDataService.selectBeforeCashData(mjonMsgVO);
@ -55,6 +438,7 @@ public class KakaoSendUtil {
/** 대체문자 여부 체크(있으면 대체문자 가격으로 없으면 카카오톡 가격으로) */ /** 대체문자 여부 체크(있으면 대체문자 가격으로 없으면 카카오톡 가격으로) */
//대체문자 발송 여부 확인 //대체문자 발송 여부 확인
System.out.println(" :: kakaoVO.getSubMsgSendYn() :: "+ kakaoVO.getSubMsgSendYn());
if(kakaoVO.getSubMsgSendYn().equals("Y")) { if(kakaoVO.getSubMsgSendYn().equals("Y")) {
@ -401,6 +785,107 @@ public class KakaoSendUtil {
varValInfo = kakaoVO.getVarValList().get(count); varValInfo = kakaoVO.getVarValList().get(count);
} }
String jsonFileName = kakaoApiJsonSave.kakaoApiJsonSave(kakaoVO, varValInfo); String jsonFileName = kakaoApiJsonSave.kakaoApiJsonSave(kakaoVO, varValInfo);
setSendMsgVO.setBizJsonName(jsonFileName); //json 파일명
}
kakaoSendList.add(setSendMsgVO);
}
kakaoVO.setKakaoSendList(kakaoSendList);
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
}
return kakaoVO;
}
/**
* @methodName : kakaoSendMsg_advc
* @author : 이호영
* @date : 2025. 3. 13.
* @description : kakaoSendMsg 개선
* @return : KakaoVO
* @param kakaoVO
* @return
* @throws Exception
*
*/
public KakaoVO kakaoSendMsg_advc(KakaoVO kakaoVO) throws Exception {
List<KakaoVO> kakaoSendList = new ArrayList<KakaoVO>();
//전체 받는사람 수량만큼 반복 확인
int callToCnt = kakaoVO.getCallToList().length;
try {
for(int count =0; count < callToCnt; count++) {
KakaoVO setSendMsgVO = new KakaoVO();
setSendMsgVO.setDestPhone(kakaoVO.getCallToList()[count]); // 수신 번호
// 카카오 전송내용 설정
// 변환문자 포함(Y), 미포함(N)
if(kakaoVO.getTxtReplYn().equals("Y")) {
String templateContent = kakaoSubMagTxtRepl(kakaoVO.getTemplateContent(), kakaoVO, count);
setSendMsgVO.setTemplateContent(templateContent);
if(kakaoVO.getTemplateEmphasizeType().equals("TEXT")) {
String title = kakaoSubMagTxtRepl(kakaoVO.getTemplateTitle(), kakaoVO, count);
String subTitle = kakaoVO.getTemplateSubtitle();
// title = title +"§§"+ subTitle;
setSendMsgVO.setTemplateEmphasizeType(kakaoVO.getTemplateEmphasizeType());
setSendMsgVO.setTemplateTitle(title);
}
}else {
if(kakaoVO.getTemplateEmphasizeType().equals("TEXT")) {
String title = kakaoSubMagTxtRepl(kakaoVO.getTemplateTitle(), kakaoVO, count);
String subTitle = kakaoVO.getTemplateSubtitle();
// title = title +"§§"+ subTitle;
setSendMsgVO.setTemplateEmphasizeType(kakaoVO.getTemplateEmphasizeType());
setSendMsgVO.setTemplateTitle(title);
}
// 템플릿 내용 설정
setSendMsgVO.setTemplateContent(kakaoVO.getTemplateContent());
}
//대체문자 포함(Y), 미포함(N)
if(kakaoVO.getSubMsgSendYn().equals("Y")) {
String charset = "euc-kr"; //문자 바이트 계산에 필요한 캐릭터 : 한글 2Byte로 계산
String tempSubMagTxt = kakaoVO.getSubMsgTxt().replace("\r\n", "\n");
kakaoVO.setKakaoSubMagOrgnlTxt(tempSubMagTxt);
if(kakaoVO.getSubMsgTxtReplYn().equals("Y")) {
tempSubMagTxt = kakaoSubMagTxtRepl(tempSubMagTxt, kakaoVO, count);
}
System.out.println("@@ 대체문자내용 : " + tempSubMagTxt);
setSendMsgVO.setSubMsgTxt(tempSubMagTxt);
int FrBytes = tempSubMagTxt.getBytes(charset).length;
System.out.println("@@ 대체문자길이 : " + FrBytes);
//메세지 길이가 90Byte가 초과시 MMS
if(FrBytes > 90) {
setSendMsgVO.setSubMsgType("MMS");
}else {// 아니면 SMS
setSendMsgVO.setSubMsgType("SMS");
}
System.out.println("@@ 대체문자타입 : " + setSendMsgVO.getSubMsgType());
}
if(kakaoVO.getBizJsonYn().equals("Y")) {
kakaoVO.setDestPhone(kakaoVO.getCallToList()[count]); // 수신 번호
String[] varValInfo = null;
if( kakaoVO.getVarValList().size() != 0) {
varValInfo = kakaoVO.getVarValList().get(count);
}
String jsonFileName = kakaoApiJsonSave.kakaoApiJsonSave(kakaoVO, varValInfo);
// String jsonFileName = kakaoApiJsonSave.kakaoApiJsonSave_advc(kakaoVO, varValInfo);
// String jsonFileName = kakaoApiJsonSave.kakaoApiJsonSave(kakaoVO, kakaoVO.getVarValList().get(count)); // String jsonFileName = kakaoApiJsonSave.kakaoApiJsonSave(kakaoVO, kakaoVO.getVarValList().get(count));
setSendMsgVO.setBizJsonName(jsonFileName); //json 파일명 setSendMsgVO.setBizJsonName(jsonFileName); //json 파일명
} }
@ -509,6 +994,7 @@ public class KakaoSendUtil {
public String kakaoSubMagTxtRepl(String tempSubMagTxt, KakaoVO kakaoVO, int count) { public String kakaoSubMagTxtRepl(String tempSubMagTxt, KakaoVO kakaoVO, int count) {
System.out.println("tempSubMagTxt : "+ tempSubMagTxt);
// String tempSubMagTxt = kakaoVO.getSubMsgTxt().replace("\r\n", "\n"); // String tempSubMagTxt = kakaoVO.getSubMsgTxt().replace("\r\n", "\n");
// String tempSubMagTxt = msgTxt; // String tempSubMagTxt = msgTxt;
@ -551,6 +1037,7 @@ public class KakaoSendUtil {
return tempSubMagTxt; return tempSubMagTxt;
} }
public String kakaoFTSubMagTxtRepl(String tempSubMagTxt, KakaoVO kakaoVO, int count) throws Exception{ public String kakaoFTSubMagTxtRepl(String tempSubMagTxt, KakaoVO kakaoVO, int count) throws Exception{
List<String[]> varValList = kakaoVO.getVarValList(); List<String[]> varValList = kakaoVO.getVarValList();
@ -704,5 +1191,10 @@ public class KakaoSendUtil {
//} //}
return ""; return "";
} }
public static void statusResponseSet (StatusResponse statusResponse, HttpStatus httpStatus, String msg ) {
statusResponse.setStatus(httpStatus);
statusResponse.setMessage(msg);
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@ import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import org.json.simple.JSONArray; import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
@ -18,6 +19,7 @@ import org.springframework.stereotype.Component;
import itn.com.cmm.util.StringUtil; import itn.com.cmm.util.StringUtil;
import itn.let.kakao.kakaoComm.KakaoButtonVO; import itn.let.kakao.kakaoComm.KakaoButtonVO;
import itn.let.kakao.kakaoComm.KakaoReturnVO; import itn.let.kakao.kakaoComm.KakaoReturnVO;
import itn.let.kakao.kakaoComm.KakaoSendAdvcVO;
import itn.let.kakao.kakaoComm.KakaoVO; import itn.let.kakao.kakaoComm.KakaoVO;
@Component @Component
@ -32,7 +34,57 @@ public class KakaoApiJsonSave {
static String json; static String json;
@SuppressWarnings("unchecked") public String kakaoApiJsonSave_advc(KakaoSendAdvcVO sendVO, KakaoReturnVO templateDetail) {
// 버튼리스트 JSON 생성
JSONArray buttonList = new JSONArray();
for(KakaoButtonVO buttonInfoVO : sendVO.getButtonList()) {
JSONObject buttonInfo = new JSONObject();
buttonInfo.put("name", buttonInfoVO.getName());
buttonInfo.put("type", buttonInfoVO.getLinkType());
if(buttonInfoVO.getLinkType().equals("WL")) {
buttonInfo.put("url_mobile", buttonInfoVO.getLinkMo());
buttonInfo.put("url_pc", buttonInfoVO.getLinkPc());
}else if(buttonInfoVO.getLinkType().equals("AL")) {
buttonInfo.put("scheme_ios", buttonInfoVO.getLinkIos());
buttonInfo.put("scheme_android", buttonInfoVO.getLinkAnd());
}else if(buttonInfoVO.getLinkType().equals("BC")) {
// 상담톡 진행시 등록해야함
}else if(buttonInfoVO.getLinkType().equals("BT")) {
// 전환 전달
}
buttonList.add(buttonInfo);
}
// 강조유형 JSON 생성
JSONObject templateDetailInfo = new JSONObject();
String emphasizeType = templateDetail.getTemplateEmphasizeType();
if(emphasizeType.equals("TEXT")) {
templateDetailInfo.put("title", sendVO.getTemplateTitle());
}else if(emphasizeType.equals("IMAGE")) {
templateDetailInfo.put("msg_type", "ai");
}
JSONObject jo = new JSONObject();
if(buttonList.size() != 0) {
jo.put("button", buttonList);
}
if(templateDetailInfo.size() != 0) {
jo.put("extra", templateDetailInfo);
}
// 입력 json 데이터를 파일로 변경
String jsonStr = jo.toString();
return jsonStr;
}
public String kakaoApiJsonSave(KakaoVO kakaoVO, String[] varValInfo) { public String kakaoApiJsonSave(KakaoVO kakaoVO, String[] varValInfo) {
// json파일 저장 // json파일 저장
@ -109,12 +161,12 @@ public class KakaoApiJsonSave {
for(int i=0; i < varNm.length; i++) { for(int i=0; i < varNm.length; i++) {
for(int j=0; j < varValInfo.length; j++) { for(int j=0; j < varValInfo.length; j++) {
if (templateTitle.indexOf(varNm[i]) > -1) { if (templateTitle.indexOf(varNm[i]) > -1) {
if(varValInfo[j] != null) { if(varValInfo[j] != null) {
templateTitle = templateTitle.replaceAll(varNm[i] , StringUtil.getString(varValInfo[j])); templateTitle = templateTitle.replaceAll(varNm[i] , StringUtil.getString(varValInfo[j]));
}else { }else {
templateTitle = templateTitle.replaceAll(varNm[i] , ""); templateTitle = templateTitle.replaceAll(varNm[i] , "");
} }
} }
} }
} }
@ -140,8 +192,8 @@ public class KakaoApiJsonSave {
// 입력 json 데이터를 파일로 변경 // 입력 json 데이터를 파일로 변경
String jsonStr = jo.toString(); String jsonStr = jo.toString();
System.out.println("jsonFileName : "+jsonFileName); // System.out.println("jsonFileName : "+jsonFileName);
File outPut = new File(jsonFileName); File outPut = new File(jsonFileName);
outPut.createNewFile(); outPut.createNewFile();

View File

@ -2,7 +2,11 @@ package itn.let.kakao.user.kakaoAt.service;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletRequest;
import itn.let.kakao.kakaoComm.KakaoSendAdvcVO;
import itn.let.kakao.kakaoComm.KakaoVO; import itn.let.kakao.kakaoComm.KakaoVO;
import itn.let.mail.service.StatusResponse;
import itn.let.mjo.msgdata.service.MjonMsgReturnVO; import itn.let.mjo.msgdata.service.MjonMsgReturnVO;
public interface KakaoAlimTalkService { public interface KakaoAlimTalkService {
@ -24,5 +28,7 @@ public interface KakaoAlimTalkService {
//카카오 친구톡 전송 실패 환불리스트 조회 //카카오 친구톡 전송 실패 환불리스트 조회
public void selectKakaoFtSentRefundList() throws Exception; public void selectKakaoFtSentRefundList() throws Exception;
StatusResponse insertKakaoAtSandAjax_advc(KakaoVO kakaoVO, HttpServletRequest request) throws Exception;
} }

View File

@ -6,6 +6,7 @@ import java.util.List;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import egovframework.rte.psl.dataaccess.EgovAbstractDAO; import egovframework.rte.psl.dataaccess.EgovAbstractDAO;
import itn.let.kakao.kakaoComm.KakaoSendAdvcVO;
import itn.let.kakao.kakaoComm.KakaoVO; import itn.let.kakao.kakaoComm.KakaoVO;
@Repository("kakaoAlimTalkDAO") @Repository("kakaoAlimTalkDAO")
@ -43,15 +44,6 @@ public class KakaoAlimTalkDAO extends EgovAbstractDAO {
return result; return result;
} }
public int insertKakaoAtDataInfo(List<KakaoVO> kakaoAtSandList) throws Exception{
int result = 0;
result = update("kakaoAlimTalkDAO.insertKakaoAtDataInfo", kakaoAtSandList);
return result;
}
public void insertKakaoSendPrice(KakaoVO kakaoVO) throws Exception{ public void insertKakaoSendPrice(KakaoVO kakaoVO) throws Exception{
insert("kakaoAlimTalkDAO.insertKakaoSendPrice",kakaoVO); insert("kakaoAlimTalkDAO.insertKakaoSendPrice",kakaoVO);
} }
@ -94,4 +86,26 @@ public class KakaoAlimTalkDAO extends EgovAbstractDAO {
public void updateKakaoFtNotSend(KakaoVO kakaoVO) { public void updateKakaoFtNotSend(KakaoVO kakaoVO) {
select("kakaoAlimTalkDAO.updateKakaoFtNotSend", kakaoVO); select("kakaoAlimTalkDAO.updateKakaoFtNotSend", kakaoVO);
} }
public int insertKakaoAtDataInfo(List<KakaoVO> kakaoAtSandList) throws Exception{
int result = 0;
result = update("kakaoAlimTalkDAO.insertKakaoAtDataInfo", kakaoAtSandList);
return result;
}
public int insertKakaoAtDataInfo_advc(List<KakaoSendAdvcVO> kakaoSendAdvcVOList) {
return update("kakaoAlimTalkDAO.insertKakaoAtDataInfo_advc", kakaoSendAdvcVOList);
}
public void insertKakaoAtDataJsonInfo_advc(List<KakaoSendAdvcVO> kakaoSendAdvcVOList) {
insert("kakaoAlimTalkDAO.insertKakaoAtDataJsonInfo_advc", kakaoSendAdvcVOList);
}
public void insertKakaoGroupDataTb_advc(KakaoSendAdvcVO sendVO) {
insert("kakaoAlimTalkDAO.insertKakaoGroupDataTb_advc", sendVO);
}
} }

View File

@ -1,19 +1,40 @@
package itn.let.kakao.user.kakaoAt.service.impl; package itn.let.kakao.user.kakaoAt.service.impl;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl; import egovframework.rte.fdl.cmmn.EgovAbstractServiceImpl;
import egovframework.rte.fdl.idgnr.EgovIdGnrService; import egovframework.rte.fdl.idgnr.EgovIdGnrService;
import egovframework.rte.fdl.security.userdetails.util.EgovUserDetailsHelper;
import itn.com.cmm.LoginVO;
import itn.com.cmm.MjonMsgSendVO;
import itn.com.utl.fcc.service.EgovStringUtil;
import itn.let.kakao.kakaoComm.KakaoSendAdvcVO;
import itn.let.kakao.kakaoComm.KakaoSendUtil;
import itn.let.kakao.kakaoComm.KakaoVO; import itn.let.kakao.kakaoComm.KakaoVO;
import itn.let.kakao.user.kakaoAt.service.KakaoAlimTalkService; import itn.let.kakao.user.kakaoAt.service.KakaoAlimTalkService;
import itn.let.mail.service.StatusResponse;
import itn.let.mjo.mjocommon.MjonCommon;
import itn.let.mjo.mjocommon.MjonHolidayApi; import itn.let.mjo.mjocommon.MjonHolidayApi;
import itn.let.mjo.msg.service.MjonMsgVO; import itn.let.mjo.msg.service.MjonMsgVO;
import itn.let.mjo.msg.service.impl.MjonMsgDAO; import itn.let.mjo.msg.service.impl.MjonMsgDAO;
@ -24,9 +45,14 @@ import itn.let.mjo.msgholiday.service.MsgHolidayVO;
import itn.let.mjo.msgholiday.service.impl.MsgHolidayDAO; import itn.let.mjo.msgholiday.service.impl.MsgHolidayDAO;
import itn.let.mjo.pay.service.MjonPayService; import itn.let.mjo.pay.service.MjonPayService;
import itn.let.mjo.pay.service.MjonPayVO; import itn.let.mjo.pay.service.MjonPayVO;
import itn.let.module.base.PriceAndPoint;
import itn.let.sym.site.service.JoinSettingVO; import itn.let.sym.site.service.JoinSettingVO;
import itn.let.sym.site.service.impl.SiteManagerDAO; import itn.let.sym.site.service.impl.SiteManagerDAO;
import itn.let.uss.umt.service.EgovUserManageService;
import itn.let.uss.umt.service.UserManageVO;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Service("kakaoAlimTalkService") @Service("kakaoAlimTalkService")
public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements KakaoAlimTalkService{ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements KakaoAlimTalkService{
@ -47,12 +73,28 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements
@Resource(name = "egovMjonMsgIdGnrService") @Resource(name = "egovMjonMsgIdGnrService")
private EgovIdGnrService idgenMsgId; private EgovIdGnrService idgenMsgId;
@Resource(name = "egovMjonMsgGroupIdGnrService")
private EgovIdGnrService idgenMjonMsgGroupId;
@Resource(name = "mjonPayService") @Resource(name = "mjonPayService")
private MjonPayService mjonPayService; private MjonPayService mjonPayService;
@Resource(name = "egovMjonCashIdGnrService") @Resource(name = "egovMjonCashIdGnrService")
private EgovIdGnrService idgenMjonCashId; private EgovIdGnrService idgenMjonCashId;
/** userManageService */
@Resource(name = "userManageService")
private EgovUserManageService userManageService;
@Autowired
KakaoSendUtil kakaoSendUtil;
@Autowired
private MjonCommon mjonCommon;
@Autowired
private PriceAndPoint priceAndPoint;
//발신프로필 상태값 변경(삭제/복구 기능) //발신프로필 상태값 변경(삭제/복구 기능)
@Override @Override
@ -816,4 +858,341 @@ public class KakaoAlimTalkServiceImpl extends EgovAbstractServiceImpl implements
} }
} }
} }
@Override
public StatusResponse insertKakaoAtSandAjax_advc(KakaoVO kakaoVO, HttpServletRequest request) throws Exception {
log.info(" :: [{}]", kakaoVO.toString());
// 측정할 메소드 호출 시간 기록
Instant start = Instant.now();
// KakaoSendAdvcVO
Map<String, Object> returnMap = new HashMap<>();
LoginVO loginVO = EgovUserDetailsHelper.isAuthenticated()
? (LoginVO) EgovUserDetailsHelper.getAuthenticatedUser()
: null;
String userId = loginVO == null ? "" : EgovStringUtil.isNullToString(loginVO.getId());
if (userId.equals("")) {
return new StatusResponse(HttpStatus.BAD_REQUEST, "로그인 후 이용이 가능합니다.");
}
kakaoVO.setUserId(userId);
/**
* 회원 정지된 상태이면 문자 발송이 안되도록 처리함 현재 로그인 세션도 만료 처리함
*/
boolean mberSttus = userManageService.selectUserStatusInfo(userId);
if (!mberSttus) {
request.getSession().invalidate();
// UNAUTHORIZED : 인증되지 않은 사용자가 접근하려고
return new StatusResponse(HttpStatus.UNAUTHORIZED,
"현재 고객님께서는 문자온 서비스 이용이 정지된 상태로 알림톡을 발송하실 수 없습니다. 이용정지 해제를 원하시면 고객센터로 연락주시기 바랍니다.");
}
StatusResponse statusResponse = new StatusResponse();
/** @isHolidayNotified
* @false : 알림 X
* @true : 알림 O */
boolean isNotified = mjonCommon.processUserAndCheckAT(kakaoVO);
/** @LETTNGNRLMBER 사용자 정보 -> 스미싱의심 여부 */
UserManageVO userManageVO = mjonCommon.getUserManageInfo(userId);
kakaoVO.setAtSmishingYn(userManageVO.getAtSmishingYn());
/** @카카오톡 전송 list 셋팅 -------------------------------------------*/
List<KakaoSendAdvcVO> kakaoSendAdvcListVO = kakaoSendUtil.populateSendLists(kakaoVO, isNotified, statusResponse);
if (statusResponse.getStatus() != null && !statusResponse.getStatus().equals(HttpStatus.OK)) {
log.error(" + populateSendLists 처리 중 오류 발생: {}", statusResponse.getMessage());
return statusResponse;
}
/** @전송금액 확인 --------------------------------------------------*/
if (!isCashSufficient(userId, kakaoSendAdvcListVO)) {
log.error("Insufficient balance for message sending.");
return new StatusResponse(HttpStatus.BAD_REQUEST, "문자 발송에 필요한 보유 잔액이 부족 합니다.");
}
Map<String, List<KakaoSendAdvcVO>> priceGroupedMessages = kakaoSendAdvcListVO.stream()
.collect(Collectors.groupingBy(KakaoSendAdvcVO::getEachPrice));
// instTotalCnt : 화면에서 보여줄 발송건수
int instTotalCnt = 0;
// 임시
List<String> nextMsgGroupIdA = new ArrayList<>();
// 대안: entrySet() 직접 사용
for (Map.Entry<String, List<KakaoSendAdvcVO>> entry : priceGroupedMessages.entrySet()) {
// entry 사용
List<KakaoSendAdvcVO> groupedMsgList = entry.getValue(); // 해당 가격의 메시지 리스트
String nextMsgGroupId = idgenMjonMsgGroupId.getNextStringId();
groupedMsgList.forEach(t -> t.setMsgGroupId(nextMsgGroupId));
// 발송 데이터 삽입
int instCnt = this.insertKakaoData_advc(groupedMsgList);
// int instCnt = 6;
if(instCnt > 0) {
instTotalCnt += instCnt;
KakaoSendAdvcVO sendVO = groupedMsgList.get(0);
/** @groupData 테이블 insert */
this.insertKakaoGroupDataTb_advc(instCnt, kakaoVO, sendVO);
/** @biz_kakao_price에 insert (대체문자 환불관련 테이블)*/
kakaoVO.setMsgGroupId(sendVO.getMsgGroupId());
kakaoVO.setKakaoAtPrice(Float.parseFloat(sendVO.getEachPrice()));
kakaoVO.setSmsPrice(Float.parseFloat(sendVO.getSmsPrice()));
kakaoVO.setMmsPrice(Float.parseFloat(sendVO.getMmsPrice()));
kakaoAlimTalkDAO.insertKakaoSendPrice(kakaoVO);
priceAndPoint.insertCashAndPoint(kakaoVO.getUserId()
, -Float.parseFloat(sendVO.getTotPrice())
, "카카오 알림톡 총 "+groupedMsgList.size()+"건 중 " + instCnt + "건 발송"
, nextMsgGroupId
);
/** @SLACK발송 */
/** @발송조건이되면 발송 */
if(isNotified) {
mjonCommon.getAdminKakaoAtSendSlack(kakaoVO);
}else if("Y".equals(kakaoVO.getAtSmishingYn())){
/** @발송조건이 안되면 DB INSERT */
mjonMsgDAO.insertSpamPassMsgData(MjonMsgVO.builder()
.msgGroupId(nextMsgGroupId)
.userId(kakaoVO.getUserId())
.reqDate(kakaoVO.getReqDate())
.smsTxt(groupedMsgList.get(0).getTemplateContent())
.totalCallCnt(instCnt)
.callFrom(kakaoVO.getCallFrom())
.msgType("8")
.reserveYn(kakaoVO.getReserveYn())
.build()
);
}
nextMsgGroupIdA.add(nextMsgGroupId);
}
}
returnMap.put("resultSts", instTotalCnt);
returnMap.put("reserYn", kakaoVO.getReserveYn());
returnMap.put("groupIds", nextMsgGroupIdA);
// 측정할 메소드 호출 시간 기록
Instant end = Instant.now();
log.info(" + start :: [{}]", start);
// 실행 시간 계산 (나노초, 밀리초, )
long seconds = Duration.between(start, end).getSeconds();
System.out.println("메소드 실행 시간 (초): " + seconds + " s");
double minutes = seconds / 60.0; // 소수점 포함을 위해 60.0으로 나눔
returnMap.put("second", seconds+" s");
returnMap.put("minutes", minutes+" min");
// System.out.println("메소드 실행 시간 (분): " + minutes + " min");
// priceAndPoint.getBefCash(userId);
statusResponse.setStatus(HttpStatus.OK);
statusResponse.setObject(returnMap);
return statusResponse;
}
private void insertKakaoGroupDataTb_advc(int instCnt, KakaoVO kakaoVO, KakaoSendAdvcVO sendVO) throws Exception {
// TODO Auto-generated method stub
// log.info(" + insertKakaoGroupDataTb_advc kakaoVO :: \n[{}]", kakaoVO.toString());;
// log.info(" + insertKakaoGroupDataTb_advc kakaoSendAdvcVOList :: \n[{}]", sendVO.toString());
sendVO.setMsgGroupCnt(Integer.toString(instCnt));
sendVO.setReserveYn(kakaoVO.getReserveYn());
sendVO.setBefCash(priceAndPoint.getBefCash(sendVO.getUserId()));
sendVO.setBefPoint(priceAndPoint.getBefPoint(sendVO.getUserId()));
Float eachPrice = Float.parseFloat(sendVO.getEachPrice());
Float totPrice = eachPrice * instCnt;
sendVO.setTotPrice(String.format("%.1f", totPrice));
sendVO.setAtDelayYn(kakaoVO.getAtSmishingYn());
sendVO.setBizKakaoResendOrgnlTxt(kakaoVO.getSubMsgTxt());
sendVO.setBizKakaoResendType(sendVO.getSubMsgType());
kakaoAlimTalkDAO.insertKakaoGroupDataTb_advc(sendVO);
}
/**
* @methodName : insertKakaoData_advc
* @author : 이호영
* @date : 2025. 3. 20.
* @description : 카카오 batch 발송 => mj_msg_data
* @return : int
* @param kakaoSendAdvcVOList
* @param parentLoopCount
* @param isJsonNotEmpty
* @param isJsonNameAllSame
* @return
*
*/
private int insertKakaoData_advc(List<KakaoSendAdvcVO> kakaoSendAdvcVOList) {
// 시작 시간 측정
long totalStartTime = System.currentTimeMillis();
int totalSize = kakaoSendAdvcVOList.size(); // 데이터 개수
// Batch 크기 설정 (고정값)
// int batchSize = 10000; 465
int batchSize = 50000; // 9분 18초
log.info("총 데이터 개수 :: [{}] ", totalSize);
log.info("설정된 Batch 크기 :: [{}] ", batchSize);
// insert 카운트
int instCnt = 0;
int batchCount = 0;
// 배치별 실행 시간 기록
List<Double> batchExecutionTimes = new ArrayList<>();
// 번째 배치에서만 삽입했는지 추적하는 플래그
for (int i = 0; i < totalSize; i += batchSize) {
// Batch 시작 시간 측정
long batchStartTime = System.currentTimeMillis();
// Batch 리스트 생성
List<KakaoSendAdvcVO> batchList = kakaoSendAdvcVOList.subList(i, Math.min(i + batchSize, totalSize));
System.out.println("Batch 시작 인덱스: " + i);
// mj_msg_data 테이블 insert
int insertedCount = kakaoAlimTalkDAO.insertKakaoAtDataInfo_advc(batchList);
/** @kakaoSendUtil.populateSendLists
* 하단에서
* getJsonStr 데이터 처리 활용
* */
batchList.removeIf(t -> StringUtils.isBlank(t.getJsonStr()));
if(batchList.size() > 0) {
kakaoAlimTalkDAO.insertKakaoAtDataJsonInfo_advc(batchList);
}
instCnt += insertedCount;
// Batch 종료 시간 측정 실행 시간 계산
long batchEndTime = System.currentTimeMillis();
double batchExecutionTimeInSeconds = (batchEndTime - batchStartTime) / 1000.0;
// 실행 시간 기록
batchExecutionTimes.add(batchExecutionTimeInSeconds);
batchCount++;
}
// 종료 시간 측정
long totalEndTime = System.currentTimeMillis();
// 실행 시간 계산 (밀리초 -> 초로 변환)
double totalExecutionTimeInSeconds = (totalEndTime - totalStartTime) / 1000.0;
// 실행 시간 출력
log.info("총 배치 실행 횟수 :: [{}] ", batchCount);
log.info("batchSize :: [{}] ", batchSize);
log.info("총 실행 시간 :: [{}] ", totalExecutionTimeInSeconds + "");
log.info("총 삽입 건수 :: [{}] ", instCnt);
// 배치별 실행 시간 출력
for (int k = 0; k < batchExecutionTimes.size(); k++) {
System.out.println("배치 " + (k + 1) + " 실행 시간 :: " + batchExecutionTimes.get(k) + "");
}
return instCnt;
}
// 보유 금액이 충분한지 확인하는 메서드
private boolean isCashSufficient(String userId, List<KakaoSendAdvcVO> kakaoSendAdvcListVO) throws Exception {
String userMoney = priceAndPoint.getBefCash(userId);
// 쉼표 제거
userMoney = userMoney.replace(",", "");
// 사용자 보유 금액 BigDecimal 변환 (HALF_EVEN 적용)
BigDecimal befCash = new BigDecimal(userMoney).setScale(2, RoundingMode.HALF_EVEN);
// 메시지 금액 계산 (HALF_EVEN 적용)
BigDecimal totalEachPrice = kakaoSendAdvcListVO.stream()
.map(msg -> new BigDecimal(String.valueOf(msg.getEachPrice()))) // 변환 오류 방지
.reduce(BigDecimal.ZERO, BigDecimal::add)
.setScale(2, RoundingMode.HALF_EVEN); // 일관성 유지
// 비교 수행
return befCash.compareTo(totalEachPrice) >= 0;
}
} }

View File

@ -35,9 +35,11 @@ import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap; import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.ModelAttribute; 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.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
@ -59,6 +61,7 @@ import itn.com.cmm.util.MJUtil;
import itn.com.cmm.util.StringUtil; import itn.com.cmm.util.StringUtil;
import itn.com.utl.fcc.service.EgovStringUtil; import itn.com.utl.fcc.service.EgovStringUtil;
import itn.let.kakao.kakaoComm.KakaoReturnVO; import itn.let.kakao.kakaoComm.KakaoReturnVO;
import itn.let.kakao.kakaoComm.KakaoSendAdvcVO;
import itn.let.kakao.kakaoComm.KakaoSendUtil; import itn.let.kakao.kakaoComm.KakaoSendUtil;
import itn.let.kakao.kakaoComm.KakaoVO; import itn.let.kakao.kakaoComm.KakaoVO;
import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiJsonSave; import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiJsonSave;
@ -67,6 +70,7 @@ import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiProfileCategory;
import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiTemplate; import itn.let.kakao.kakaoComm.kakaoApi.KakaoApiTemplate;
import itn.let.kakao.kakaoComm.kakaoApi.service.KakaoApiService; import itn.let.kakao.kakaoComm.kakaoApi.service.KakaoApiService;
import itn.let.kakao.user.kakaoAt.service.KakaoAlimTalkService; import itn.let.kakao.user.kakaoAt.service.KakaoAlimTalkService;
import itn.let.mail.service.StatusResponse;
import itn.let.mjo.mjocommon.MjonCommon; import itn.let.mjo.mjocommon.MjonCommon;
import itn.let.mjo.mjocommon.MjonHolidayApi; import itn.let.mjo.mjocommon.MjonHolidayApi;
import itn.let.mjo.msgdata.service.MjonMsgDataService; import itn.let.mjo.msgdata.service.MjonMsgDataService;
@ -239,6 +243,8 @@ public class KakaoAlimTalkSendController {
return "web/kakao/msgdata/at/KakaoAlimtalkMsgDataView"; return "web/kakao/msgdata/at/KakaoAlimtalkMsgDataView";
// return "web/kakao/msgdata/at/KakaoAlimtalkMsgDataView_advcbackup_20250310";
} }
@ -1079,6 +1085,16 @@ public class KakaoAlimTalkSendController {
return modelAndView; return modelAndView;
} }
@RequestMapping(value= {"/web/mjon/kakao/alimtalk/kakaoAlimTalkMsgSendAjax_advc.do"}, method = RequestMethod.POST)
public ResponseEntity<StatusResponse> kakaoAlimTalkMsgSendAjax_advc(
@RequestBody KakaoVO kakaoVO,
HttpServletRequest request
) throws Exception {
System.out.println(" + kakaoAlimTalkMsgSendAjax_advc + ");
return ResponseEntity.ok().body(kakaoAlimTalkService.insertKakaoAtSandAjax_advc(kakaoVO, request)) ;
}
@RequestMapping(value= {"/web/mjon/kakao/alimtalk/kakaoAlimTalkMsgSendAjax.do"}, method = RequestMethod.POST) @RequestMapping(value= {"/web/mjon/kakao/alimtalk/kakaoAlimTalkMsgSendAjax.do"}, method = RequestMethod.POST)
// @ResponseBody // @ResponseBody
public ModelAndView kakaoAlimTalkMsgSendAjax( public ModelAndView kakaoAlimTalkMsgSendAjax(
@ -1086,6 +1102,10 @@ public class KakaoAlimTalkSendController {
HttpServletRequest request, HttpServletRequest request,
@ModelAttribute("kakaoVO") KakaoVO kakaoVO @ModelAttribute("kakaoVO") KakaoVO kakaoVO
) throws Exception { ) throws Exception {
// 시작 시간
long startTime = System.currentTimeMillis();
System.out.println(" :: kakaoAlimTalkMsgSendAjax :: ");
ModelAndView modelAndView = new ModelAndView(); ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("jsonView"); modelAndView.setViewName("jsonView");
@ -1410,7 +1430,7 @@ public class KakaoAlimTalkSendController {
if(!smishingAlarmPassSts) {//평일,주말, 공휴일 알림설정 시간에 포함되지 않는 경우 슬랙 알림 발송 if(!smishingAlarmPassSts) {//평일,주말, 공휴일 알림설정 시간에 포함되지 않는 경우 슬랙 알림 발송
mjonCommon.getAdminKakaoAtSandSlack(kakaoVO); mjonCommon.getAdminKakaoAtSendSlack(kakaoVO);
} }
@ -1422,6 +1442,17 @@ public class KakaoAlimTalkSendController {
} catch (Exception e) { } catch (Exception e) {
throw new Exception("++++++++++++++++++++++ getAdminPhoneSendMsgData Error !!! " + e); throw new Exception("++++++++++++++++++++++ getAdminPhoneSendMsgData Error !!! " + e);
} }
// 종료 시간
long endTime = System.currentTimeMillis();
// 실행 시간 계산 ( 단위)
double executionTimeSeconds = (endTime - startTime) / 1000.0;
System.out.println("실행 시간: " + String.format("%.3f", executionTimeSeconds) + "");
String returnTxt = String.format("%.3f", executionTimeSeconds) + "";
modelAndView.addObject("seconds", returnTxt);
return modelAndView; return modelAndView;
} }

View File

@ -663,7 +663,7 @@ public class KakaoFriendsTalkSendController {
if(!smishingAlarmPassSts) {//평일,주말, 공휴일 알림설정 시간에 포함되지 않는 경우 슬랙 알림 발송 if(!smishingAlarmPassSts) {//평일,주말, 공휴일 알림설정 시간에 포함되지 않는 경우 슬랙 알림 발송
MjonCommon comm = new MjonCommon(); MjonCommon comm = new MjonCommon();
comm.getAdminKakaoAtSandSlack(kakaoVO); comm.getAdminKakaoAtSendSlack(kakaoVO);
} }

View File

@ -1,10 +1,12 @@
package itn.let.mjo.mjocommon; package itn.let.mjo.mjocommon;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import javax.annotation.Resource; import javax.annotation.Resource;
@ -14,13 +16,17 @@ import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PostMethod;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.mysql.jdbc.StringUtils; import com.mysql.jdbc.StringUtils;
import egovframework.com.idgen.CustomIdGnrService;
import egovframework.rte.fdl.cmmn.exception.FdlException;
import itn.com.cmm.MjonMsgSendVO; import itn.com.cmm.MjonMsgSendVO;
import itn.com.cmm.OptimalMsgResultDTO; import itn.com.cmm.OptimalMsgResultDTO;
import itn.com.cmm.util.MsgSendUtils; import itn.com.cmm.util.MsgSendUtils;
import itn.com.cmm.util.SlackMessageFormatUtil;
import itn.let.kakao.kakaoComm.KakaoVO; import itn.let.kakao.kakaoComm.KakaoVO;
import itn.let.mail.service.StatusResponse; import itn.let.mail.service.StatusResponse;
import itn.let.mjo.event.service.MjonEventService; import itn.let.mjo.event.service.MjonEventService;
@ -36,7 +42,7 @@ import itn.let.uss.umt.service.UserManageVO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
@Service("MjonCommon") @Component
public class MjonCommon { public class MjonCommon {
@ -60,11 +66,14 @@ public class MjonCommon {
/** xpedite 솔루션 ID*/ /** xpedite 솔루션 ID*/
@Value("#{globalSettings['Globals.slack.channel.name']}") @Value("#{globalSettings['Globals.slack.channel.name']}")
private String SLACK_CHANNEL; private String SLACK_CHANNEL;
@Resource(name = "egovMjonMsgIdCGnrService")
private CustomIdGnrService idgenMsgCId;
/** /**
* @methodName : getAdminMsgSandSlack * @methodName : getAdminSandSlack
* @author : 이호영 * @author : 이호영
* @date : 2024.12.04 * @date : 2024.12.04
* @description : 기존 메소드 리펙토링 * @description : 기존 메소드 리펙토링
@ -120,8 +129,8 @@ public class MjonCommon {
try { try {
// 메시지 내용 설정 // 메시지 내용 설정
String smsTxt = formatSmsText(mjonMsgVO); String smsTxt = SlackMessageFormatUtil.formatSmsText(mjonMsgVO);
String sandName = formatSandName(mjonMsgVO); String sandName = SlackMessageFormatUtil.formatSandName(mjonMsgVO);
// Slack 메시지 생성 // Slack 메시지 생성
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
@ -150,94 +159,49 @@ public class MjonCommon {
} }
} }
/** public void getAdminKakaoAtSendSlack(KakaoVO kakaoVO) {
* @throws Exception
* @Method Name : getAdminSlackSand
* @작성일 : 2022. 12. 6.
* @작성자 : WYH
* @Method 설명 : slack 메시지 전송
*/
/*public void getAdminMsgSandSlack(MjonMsgVO mjonMsgVO) {
HttpClient client = new HttpClient(); HttpClient client = new HttpClient();
PostMethod post = new PostMethod(url); PostMethod post = new PostMethod(SLACK_URL);
JSONObject json = new JSONObject();
try { try {
// 메시지 내용 설정
String reserveYn = mjonMsgVO.getReserveYn(); String smsTxt = SlackMessageFormatUtil.formatKakaoText(kakaoVO);
String delayYn = mjonMsgVO.getDelayYn(); String sandName = SlackMessageFormatUtil.formatKakaoSandName(kakaoVO);
String smsTxt = mjonMsgVO.getSmsTxt();
String smishingYn = mjonMsgVO.getSmishingYn();
String reservSmsTxt = "";
String smisingSmsTxt = "";
//예약문자를 발송하는 경우 문자 내용 앞에 "[예약]" 표시되도록 처리
if(reserveYn.equals("Y")) { // Slack 메시지 생성
JSONObject json = new JSONObject();
if(smishingYn.equals("Y") || delayYn.equals("Y")) { json.put("channel", SLACK_CHANNEL);
reservSmsTxt = "[스미싱의심][예약]" + smsTxt;
}else {
reservSmsTxt = "[예약]" + smsTxt;
}
smsTxt = reservSmsTxt;
System.out.println("smishingYn : "+ smishingYn);
System.out.println("delayYn : "+ delayYn);
}else if(smishingYn.equals("Y") || delayYn.equals("Y")) {
smisingSmsTxt = "[스미싱의심]" + smsTxt;
smsTxt = smisingSmsTxt;
}
String sandName = mjonMsgVO.getCallFrom();
String userId = mjonMsgVO.getUserId();
String msgType = "";
int fileCount = Integer.parseInt(mjonMsgVO.getFileCnt());//그림 이미지 갯수
if(mjonMsgVO.getMsgType().equals("4")) { //단문 금액
msgType = "[단문]";
}else if(mjonMsgVO.getMsgType().equals("6")){
if(fileCount == 0) {
msgType = "[장문]";
}else {
msgType = "[그림]";
// 2022.12.21 JSP => 텍스트없는 그림문자만 발송시 슬랙알림 안됨
if (StringUtils.isNullOrEmpty(smsTxt)) {
smsTxt = "그림문자 " + smsTxt;
}
}
}
// sandName = "[" + userId + "]" + "[" + sandName + "]" + msgType;
sandName = "[개발테스트]"+"[" + userId + "]" + "[" + sandName + "]" + msgType;
json.put("channel", "mjon메시지");
json.put("text", smsTxt); json.put("text", smsTxt);
json.put("username", sandName); json.put("username", sandName);
// Slack 요청
post.addParameter("payload", json.toString()); post.addParameter("payload", json.toString());
// 처음에 utf-8로 content-type안넣어주니까 한글은 깨져서 content-type넣어줌
post.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); post.setRequestHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
// Slack 응답 처리
int responseCode = client.executeMethod(post); int responseCode = client.executeMethod(post);
String response = post.getResponseBodyAsString(); if (responseCode != HttpStatus.SC_OK) {
if (responseCode != HttpStatus.SC_OK) { log.warn("Slack 메시지 전송 실패. Response: {}", post.getResponseBodyAsString());
System.out.println("Response: " + response);
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
System.out.println("IllegalArgumentException posting to Slack " + e); log.error("Slack 메시지 전송 중 IllegalArgumentException 발생", e);
} } catch (IOException e) {
catch (IOException e) { log.error("Slack 메시지 전송 중 IOException 발생", e);
System.out.println("IOException posting to Slack " + e); } catch (Exception e) {
} log.error("Slack 메시지 전송 중 Exception 발생", e);
catch (Exception e) {
System.out.println("Exception posting to Slack " + e);
e.printStackTrace();
} finally { } finally {
post.releaseConnection(); post.releaseConnection();
} }
}
}*/
private String formatKakaoSandName(KakaoVO kakaoVO) {
// TODO Auto-generated method stub
return null;
}
/** /**
* @Method Name : sendSimpleSlackMsg * @Method Name : sendSimpleSlackMsg
* @작성일 : 2022. 12. 9 * @작성일 : 2022. 12. 9
@ -384,7 +348,7 @@ public class MjonCommon {
return mjonMsgVO; return mjonMsgVO;
} }
/*
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public void getAdminKakaoAtSandSlack(KakaoVO kakaoVO) { public void getAdminKakaoAtSandSlack(KakaoVO kakaoVO) {
@ -448,7 +412,7 @@ public class MjonCommon {
} }
} }
*/
public String getCreateMsgUserIdgen(String subUserId, String lastId) throws Exception{ public String getCreateMsgUserIdgen(String subUserId, String lastId) throws Exception{
@ -485,27 +449,6 @@ public class MjonCommon {
private String formatSmsText(MjonMsgVO mjonMsgVO) {
String smsTxt = mjonMsgVO.getSmsTxt();
String reserveYn = safeGetString(mjonMsgVO.getReserveYn());
String delayYn = safeGetString(mjonMsgVO.getDelayYn());
String smishingYn = safeGetString(mjonMsgVO.getSmishingYn());
// 예약 문자와 스미싱 의심 처리
if ("Y".equals(reserveYn)) {
smsTxt = ("Y".equals(smishingYn) || "Y".equals(delayYn)) ? "[스미싱의심][예약]" + smsTxt : "[예약]" + smsTxt;
} else if ("Y".equals(smishingYn) || "Y".equals(delayYn)) {
smsTxt = "[스미싱의심]" + smsTxt;
}
// 그림 문자 처리
int fileCount = parseIntOrDefault(mjonMsgVO.getFileCnt(), 0);
if ("6".equals(mjonMsgVO.getMsgType()) && fileCount > 0 && StringUtils.isNullOrEmpty(smsTxt)) {
smsTxt = "그림문자 " + smsTxt;
}
return smsTxt;
}
private String formatSandName(MjonMsgVO mjonMsgVO) { private String formatSandName(MjonMsgVO mjonMsgVO) {
String userId = mjonMsgVO.getUserId(); String userId = mjonMsgVO.getUserId();
@ -542,7 +485,18 @@ private int parseIntOrDefault(String value, int defaultValue) {
// 전체 로직 처리 ( 번에 모든 필요한 정보 반환) /**
* @methodName : processUserAndCheckSms
* @author : 이호영
* @date : 2025. 3. 25.
* @description : SMS 알림 전체 로직 처리 ( 번에 모든 필요한 정보 반환)
* @return : boolean
* @param mjonMsgVO
* @param userId
* @return
* @throws Exception
*
*/
public boolean processUserAndCheckSms(MjonMsgVO mjonMsgVO, String userId) throws Exception { public boolean processUserAndCheckSms(MjonMsgVO mjonMsgVO, String userId) throws Exception {
UserManageVO userManageVO = getUserManageInfo(userId); UserManageVO userManageVO = getUserManageInfo(userId);
@ -556,11 +510,41 @@ private int parseIntOrDefault(String value, int defaultValue) {
mjonMsgVO.setSmishingYn(smishingYn); // MjonMsgVO에 스미싱 정보 설정 mjonMsgVO.setSmishingYn(smishingYn); // MjonMsgVO에 스미싱 정보 설정
// 스미싱 알림 처리 // 스미싱 알림 처리
return handleSmishingAlert(mjonMsgVO); // 알림 처리 결과 반환 return handleSmishingAlert(); // 알림 처리 결과 반환
} }
return false; // 알림 처리되지 않음 return false; // 알림 처리되지 않음
} }
/**
* @methodName : processUserAndCheckAT
* @author : 이호영
* @date : 2025. 3. 25.
* @description : SMS 알림 전체 로직 처리 ( 번에 모든 필요한 정보 반환)
* @return : boolean
* @param mjonMsgVO
* @param userId
* @return
* @throws Exception
*
*/
public boolean processUserAndCheckAT(KakaoVO kakaoVO) throws Exception {
UserManageVO userManageVO = getUserManageInfo(kakaoVO.getUserId());
// 기본값 처리된 사용자 정보와 문자 상태
String adminSmsNoticeYn = userManageVO.getAdminSmsNoticeYn();
String atSmishingYn = userManageVO.getAtSmishingYn();
// 조건 체크
if ("Y".equals(adminSmsNoticeYn) || "Y".equals(atSmishingYn)) {
kakaoVO.setAtSmishingYn(atSmishingYn); // MjonMsgVO에 스미싱 정보 설정
// 스미싱 알림 처리
return handleSmishingAlert(); // 알림 처리 결과 반환
}
return false; // 알림 처리되지 않음
}
// 사용자 정보 조회 기본값 처리 // 사용자 정보 조회 기본값 처리
public UserManageVO getUserManageInfo(String userId) throws Exception { public UserManageVO getUserManageInfo(String userId) throws Exception {
@ -572,18 +556,28 @@ private int parseIntOrDefault(String value, int defaultValue) {
} }
// 스미싱 알림 처리 // 스미싱 알림 처리
public boolean handleSmishingAlert(MjonMsgVO mjonMsgVO) throws Exception { public boolean handleSmishingAlert() throws Exception {
/**
* MJ_MBER_SETTING => 기본 시스템 알림 여부
* 슬랙 Y
* 야간스미싱알림 Y
* 등등
*
*/
JoinSettingVO joinSettingVO = egovSiteManagerService.selectAdminNotiDetail(); JoinSettingVO joinSettingVO = egovSiteManagerService.selectAdminNotiDetail();
/** @시스템 설정에 야간스미싱 알림 || 슬랙알림이 N이면 false*/
if (joinSettingVO == null || !"Y".equals(joinSettingVO.getHoliSmishingNoti()) || if (joinSettingVO == null || !"Y".equals(joinSettingVO.getHoliSmishingNoti()) ||
!"Y".equals(joinSettingVO.getSlackNoti())) { !"Y".equals(joinSettingVO.getSlackNoti())) {
return false; // 알림 조건 미충족 return false; // 알림 조건 미충족
} }
// 알림 조건 충족 추가 작업 /** @MJ_SPAMPASS_ALARM : 현재 활성화된 알림 SELECT */
List<MsgAlarmSetVO> alarmList = getAlarmSettings(); List<MsgAlarmSetVO> alarmList = getAlarmSettings();
/** @MJ_HOLIDAY 시스템에 등록된 공휴일 설정 */
List<MsgHolidayVO> holidayList = getHolidayList(); List<MsgHolidayVO> holidayList = getHolidayList();
boolean isNotificationAllowed = new MjonHolidayApi().getHolidaySmishingPassStatus(alarmList, holidayList); /** @MJ_HOLIDAY 시스템에 등록된 공휴일 설정 */
boolean isNotificationAllowed = new MjonHolidayApi().getHolidaySmishingPassStatus_advc(alarmList, holidayList);
return !isNotificationAllowed; // 알림 발송 조건 미충족 return !isNotificationAllowed; // 알림 발송 조건 미충족
} }
@ -699,9 +693,55 @@ private int parseIntOrDefault(String value, int defaultValue) {
public List<String> getNextCustomMsgCId (int cnt) throws FdlException {
List<String> idList = idgenMsgCId.getNextStringId(cnt);
return idList;
}
/**
* @methodName : getSmsTxtBytes
* @author : 이호영
* @date : 2024.09.23
* @description : sms 텍스트 바이트 계산 return;
* @param smsTxt
* @return
* @throws UnsupportedEncodingException
*/
public static int getSmsTxtBytes(String smsTxt) throws UnsupportedEncodingException { //문자열 길이 체크 해주기
int smsBytes = 0;
//문자 바이트 계산에 필요한 캐릭터 : 한글 2Byte로 계산
String charset = "euc-kr";
if(org.apache.commons.lang3.StringUtils.isNotEmpty(smsTxt)) {
String smsCont = smsTxt.replace("\r\n", "\n");
smsBytes = smsCont.getBytes(charset).length;
}
// log.info(" + smsBytes :: [{}]", smsBytes);
return smsBytes;
}
/**
* @methodName : replaceTemplateVariables
* @author : 이호영
* @date : 2025. 3. 12.
* @description : 헬퍼 메서드: 템플릿 변수 치환
* @return : String
* @param content
* @param variables
* @return
*/
public static String ATReplaceTemplateVariables(String content, Map<String, String> variables) {
String result = content;
for (Map.Entry<String, String> entry : variables.entrySet()) {
String placeholder = entry.getKey();
String value = entry.getValue();
result = result.replace(placeholder, value);
}
return result;
}

View File

@ -231,4 +231,71 @@ public class MjonHolidayApi {
return smishingAlarmPassSts; return smishingAlarmPassSts;
} }
/**
* @methodName : getHolidaySmishingPassStatus_advc
* @author : 이호영
* @date : 2025. 3. 19.
* @description : getHolidaySmishingPassStatus 개선 버전
* @return : boolean
* @param resultAlarmList
* @param resultHolidayList
* @return
* @throws Exception
*
*/
public boolean getHolidaySmishingPassStatus_advc(List<MsgAlarmSetVO> alarmList, List<MsgHolidayVO> holidayList) throws Exception{
Date now = new Date(); // 현재 시스템 시간
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); // 날짜-시간 포맷 (: 2025-03-18 14:30)
// 현재 날짜와 요일 계산
Calendar cal = Calendar.getInstance();
cal.setTime(now);
int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK); // 1(일요일) ~ 7(토요일)
// 오늘 날짜를 "yyyy-MM-dd" 형식으로 포맷팅 (mj_holiday.HOLIDAY_DATE와 비교용)
String today = String.format("%d-%02d-%02d",
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH) + 1, // Calendar.MONTH는 0부터 시작하므로 +1
cal.get(Calendar.DATE));
// 공휴일 여부 확인
// mj_holiday 테이블의 HOLIDAY_DATE와 오늘 날짜가 일치하는지 체크
// HOLIDAY_DATE는 'yyyy-MM-dd' 형식으로 저장됨 (: '2025-01-01')
boolean isHoliday = holidayList.stream()
.anyMatch(holiday -> today.equals(holiday.getHolidayDate()));
// 알람 설정 순회
// alarmList는 MsgAlarmSetVO 객체의 리스트로, 알람 타입과 시작/종료 시간을 포함
for (MsgAlarmSetVO alarm : alarmList) {
String alarmType = alarm.getAlarmType(); // 알람 유형: 'W'(평일), 'E'(주말), 'H'(공휴일)
// 오늘 날짜에 알람 시작/종료 시간을 붙여 Date 객체로 변환
Date start = sdf.parse(today + " " + alarm.getAlarmStart()); // : "2025-03-18 09:00"
Date end = sdf.parse(today + " " + alarm.getAlarmEnd()); // : "2025-03-18 18:00"
// 현재 시간이 알람 시작~종료 시간 범위 내에 있는지 확인
boolean isWithinTime = now.after(start) && now.before(end);
if (!isWithinTime) continue; // 시간 범위 밖이면 다음 알람으로
// 평일 체크 (~: dayOfWeek 2~6)
// alarmType 'W' 평일에만 적용
if (dayOfWeek > 1 && dayOfWeek < 7 && alarmType.equals("W")) {
return true; // 평일이고, 시간이 맞고, 타입이 'W' 스미싱 알람 통과
}
// 주말 체크 (:1, :7)
// alarmType 'E' 주말에만 적용
else if ((dayOfWeek == 1 || dayOfWeek == 7) && alarmType.equals("E")) {
return true; // 주말이고, 시간이 맞고, 타입이 'E' 스미싱 알람 통과
}
// 공휴일 체크
// alarmType 'H' mj_holiday에 등록된 공휴일에 적용
// HOLIDAY_TYPE(1:법정, 2:임시, 3:기타) 관계없이 날짜만 확인
else if (isHoliday && alarmType.equals("H")) {
return true; // 공휴일이고, 시간이 맞고, 타입이 'H' 스미싱 알람 통과
}
}
// 모든 조건에 부합하지 않으면 false 반환 (스미싱 알람 비활성화)
return false;
}
} }

View File

@ -7,12 +7,18 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import itn.com.cmm.ComDefaultVO; import itn.com.cmm.ComDefaultVO;
import itn.com.cmm.MjonMsgSendVO; import itn.com.cmm.MjonMsgSendVO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter; import lombok.Setter;
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
@Getter @Getter
@Setter @Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class MjonMsgVO extends ComDefaultVO{ public class MjonMsgVO extends ComDefaultVO{
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

View File

@ -4061,7 +4061,7 @@ public class MjonMsgDataServiceImpl extends EgovAbstractServiceImpl implements M
System.out.println("================================"); System.out.println("================================");
// 스팸 스미싱 의심이면 slack 알림 // 스팸 스미싱 의심이면 slack 알림
boolean isHolidayNotified = mjonCommon.handleSmishingAlert(mjonMsgVO); boolean isHolidayNotified = mjonCommon.handleSmishingAlert();
// 스팸관련 키워드 select // 스팸관련 키워드 select
@ -4095,7 +4095,9 @@ public class MjonMsgDataServiceImpl extends EgovAbstractServiceImpl implements M
MsgSendUtils.setPriceforVO(mjonMsgVO, mjonMsgSendVOList, sysJoinSetVO, mberManageVO); MsgSendUtils.setPriceforVO(mjonMsgVO, mjonMsgSendVOList, sysJoinSetVO, mberManageVO);
// msg_id 대량 생성 // msg_id 대량 생성
List<String> idList = idgenMsgCId.getNextStringId(mjonMsgSendVOList.size());
// List<String> idList = idgenMsgCId.getNextStringId(mjonMsgSendVOList.size());
List<String> idList = mjonCommon.getNextCustomMsgCId(mjonMsgSendVOList.size());
for (int i = 0; i < mjonMsgSendVOList.size(); i++) { for (int i = 0; i < mjonMsgSendVOList.size(); i++) {
mjonMsgSendVOList.get(i).setMsgId(idList.get(i)); mjonMsgSendVOList.get(i).setMsgId(idList.get(i));
} }
@ -4136,7 +4138,6 @@ public class MjonMsgDataServiceImpl extends EgovAbstractServiceImpl implements M
int instTotalCnt = 0; int instTotalCnt = 0;
// Step 2: 그룹화 데이터를 그룹별로 insert 처리 // Step 2: 그룹화 데이터를 그룹별로 insert 처리
for (Map.Entry<String, List<MjonMsgSendVO>> entry : priceGroupedMessages.entrySet()) { for (Map.Entry<String, List<MjonMsgSendVO>> entry : priceGroupedMessages.entrySet()) {
String price = entry.getKey(); // 가격 (String)
List<MjonMsgSendVO> groupedMsgList = entry.getValue(); // 해당 가격의 메시지 리스트 List<MjonMsgSendVO> groupedMsgList = entry.getValue(); // 해당 가격의 메시지 리스트
// msgGroupId 생성 // msgGroupId 생성
@ -4172,7 +4173,7 @@ public class MjonMsgDataServiceImpl extends EgovAbstractServiceImpl implements M
// 수신거부 목록 업데이트 // 수신거부 목록 업데이트
// returnMap.put("resultSts", instCnt); // returnMap.put("resultSts", instCnt);
log.debug("가격 [{}]의 총 갯수: [{}]", price, groupedMsgList.size()); log.debug("가격 [{}]의 총 갯수: [{}]", entry.getKey(), groupedMsgList.size());
} }

View File

@ -2090,16 +2090,8 @@ public class MjonMsgDataController {
} }
long startTime = System.currentTimeMillis(); // 시작 시간 측정
List<AddrVO> resultAddrList = mjonMsgDataService.selectMsgAddrListAjax(addrVO); List<AddrVO> resultAddrList = mjonMsgDataService.selectMsgAddrListAjax(addrVO);
long endTime = System.currentTimeMillis(); // 종료 시간 측정
long elapsedTime = endTime - startTime; // 소요 시간 계산
System.out.println("소요 시간: " + elapsedTime + " 밀리초");
modelAndView.addObject("resultAddrList", resultAddrList); modelAndView.addObject("resultAddrList", resultAddrList);
modelAndView.addObject("result", "success"); modelAndView.addObject("result", "success");

View File

@ -4,9 +4,10 @@
========= ======= ================================================= ========= ======= =================================================
2023.02.02 우영두 2023.02.02 우영두
--> -->
<!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="kakaoAlimTalk"> <sqlMap namespace="kakaoAlimTalk">
<typeAlias alias="kakaoVO" type="itn.let.kakao.kakaoComm.KakaoVO"/> <typeAlias alias="kakaoVO" type="itn.let.kakao.kakaoComm.KakaoVO"/>
<typeAlias alias="kakaoSendAdvcVO" type="itn.let.kakao.kakaoComm.KakaoSendAdvcVO"/>
<insert id="kakaoAlimTalkDAO.insertKakaoAtDataInfo" parameterClass="java.util.List"> <insert id="kakaoAlimTalkDAO.insertKakaoAtDataInfo" parameterClass="java.util.List">
INSERT INTO MJ_MSG_DATA INSERT INTO MJ_MSG_DATA
@ -54,6 +55,119 @@
</iterate> </iterate>
</insert> </insert>
<insert id="kakaoAlimTalkDAO.insertKakaoAtDataInfo_advc" parameterClass="java.util.List">
INSERT INTO MJ_MSG_DATA
(
MSG_ID
, MSG_GROUP_ID
, USER_ID
, AGENT_CODE
, CUR_STATE
, MSG_NOTICETALK_SENDER_KEY
, MSG_NOTICETALK_TMP_KEY
, CALL_TO
, CALL_FROM
, MSG_TYPE
, SMS_TXT
, BIZ_KAKAO_TITLE
, BIZ_KAKAO_RESEND_YN
, BIZ_KAKAO_RESEND_DATA
, BIZ_KAKAO_RESEND_TYPE
, BIZ_KAKAO_JSON_FILE
, REQ_DATE
)VALUES
<iterate conjunction=",">
(
#[].msgId#
, #[].msgGroupId#
, #[].userId#
, #[].agentCode#
, 0
, #[].senderKey#
, #[].templateCode#
, #[].callTo#
, #[].callFrom#
, #[].msgType#
, #[].templateContent#
, #[].templateTitle#
, #[].subMsgSendYn#
, #[].subMsgTxt#
, #[].subMsgType#
, #[].bizJsonName#
, #[].reqDate#
)
</iterate>
</insert>
<insert id="kakaoAlimTalkDAO.insertKakaoAtDataJsonInfo_advc" parameterClass="java.util.List">
INSERT INTO BIZ_ATTACHMENTS
(
MSG_KEY
, TYPE
, CONTENTS
)VALUES
<iterate conjunction=",">
(
#[].msgId#
, 'JSON'
, #[].jsonStr#
)
</iterate>
</insert>
<insert id="kakaoAlimTalkDAO.insertKakaoGroupDataTb_advc" parameterClass="kakaoSendAdvcVO">
INSERT INTO MJ_MSG_GROUP_DATA
(
MSG_GROUP_ID,
USER_ID,
CALL_FROM,
SMS_TXT,
REQ_DATE,
MSG_GROUP_CNT,
MSG_TYPE,
AGENT_CODE,
EACH_PRICE,
RESERVE_YN,
BEF_CASH,
BEF_POINT,
TOT_PRICE,
AT_DELAY_YN,
BIZ_KAKAO_RESEND_ORGNL_TXT,
BIZ_KAKAO_RESEND_TYPE
)VALUES
(
#msgGroupId#,
#userId#,
#callFrom#,
#templateContent#,
#reqDate#,
#msgGroupCnt#,
#msgType#,
#agentCode#,
#eachPrice#,
#reserveYn#,
#befCash#,
#befPoint#,
#totPrice#,
#atDelayYn#,
#bizKakaoResendOrgnlTxt#,
#bizKakaoResendType#
)
</insert>
<insert id="kakaoAlimTalkDAO.insertKakaoSendPrice" parameterClass="kakaoVO"> <insert id="kakaoAlimTalkDAO.insertKakaoSendPrice" parameterClass="kakaoVO">
INSERT INTO BIZ_KAKAO_PRICE INSERT INTO BIZ_KAKAO_PRICE
( (

View File

@ -1315,6 +1315,7 @@
ADMIN_SMS_NOTICE_YN AS adminSmsNoticeYn ADMIN_SMS_NOTICE_YN AS adminSmsNoticeYn
,PRE_PAYMENT_YN AS prePaymentYn ,PRE_PAYMENT_YN AS prePaymentYn
,SMISHING_YN AS smishingYn ,SMISHING_YN AS smishingYn
,AT_SMISHING_YN AS atSmishingYn
,AUTO_CASH AS autoCash ,AUTO_CASH AS autoCash
,IFNULL(BLINE_CODE, 'N') AS blineCode ,IFNULL(BLINE_CODE, 'N') AS blineCode
,IFNULL(RECOMMEND_ID, '') AS recommendId ,IFNULL(RECOMMEND_ID, '') AS recommendId

View File

@ -7,6 +7,8 @@
<!-- <script src="/publish/js/content.js"></script> --> <!-- <script src="/publish/js/content.js"></script> -->
<!-- 주소록관련 js --> <!-- 주소록관련 js -->
<script type="text/javascript" defer src="<c:out value='/js/kakao/at/init.js' />"></script> <script type="text/javascript" defer src="<c:out value='/js/kakao/at/init.js' />"></script>
<script type="text/javascript" src="<c:out value='/js/kakao/at/tabulator.js' />"></script> <script type="text/javascript" src="<c:out value='/js/kakao/at/tabulator.js' />"></script>
<script type="text/javascript" src="<c:out value='/js/kakao/at/addr.js' />"></script> <script type="text/javascript" src="<c:out value='/js/kakao/at/addr.js' />"></script>
@ -15,7 +17,6 @@
<script type="text/javascript" src="<c:out value='/js/common/popup.js' />"></script> <script type="text/javascript" src="<c:out value='/js/common/popup.js' />"></script>
<script type="text/javascript"> <script type="text/javascript">
var loginVO = '${loginVO}'; var loginVO = '${loginVO}';
// 체크박스 동적 바인딩 // 체크박스 동적 바인딩
$(document).on('click','.wrap01C', function(){ $(document).on('click','.wrap01C', function(){
var total = $(".wrap01C").length; var total = $(".wrap01C").length;
@ -87,28 +88,52 @@ $(document).ready(function(){
//선택삭제 버튼 클릭 이벤트 //선택삭제 버튼 클릭 이벤트
$("#select_del").on('click', function(){ $("#select_del").on('click', function(){
if($('.wrap01C:checkbox:checked').length < 1)
{ if(tableL == null || tableL == ""){
alert("삭제할 연락처를 선택해주세요.!!");
alert("받는사람을 추가해 주세요.");
return false; return false;
}
var selectedData = tableL.getSelectedRows();
if(selectedData == "" || selectedData == null){
alert("삭제할 연락처를 선택해주세요.");
return false;
// 선택한 Row 데이터 삭제하기
}else if(confirm("선택하신 받는 사람을 삭제하시겠습니까?")){
// 선택 데이터 삭제
selectedData.forEach(row => row.delete());
totRows = tableL.getRows().length;
updateTotCnt(totRows);
var smsTxtArea = $('#smsTxtArea').val();
//일괄변환 문구 결제금액 처리
} }
$('.wrap01C').each(function(index, item){
if($(item).is(':checked'))
$(item).parent().parent().remove();
});
updateTotCnt();
}); });
//선택삭제 버튼 클릭 이벤트 //선택삭제 버튼 클릭 이벤트
$("#all_del").on('click', function(){ $("#all_del").on('click', function(){
if(!confirm("받는사람 목록을 모두 삭제하시겠습니까?")) if(!confirm("받는사람 목록을 모두 삭제하시겠습니까?"))
return false; return false;
$('#wrap01_body .list_body').remove(); $('#wrap01_body .list_body').remove();
tableL.clearData();
$('#rowTotCnt').text(0); $('#rowTotCnt').text(0);
$('#rowDupCnt').text(0); $('#rowDupCnt').text(0);
}); });
@ -509,19 +534,13 @@ function sendTemplateInfo(){
return false; return false;
} }
//수신자 목록 체크
if($('.phoneArea').length < 1)
{
alert('받는 사람 입력 후 발송해 주세요');
return false;
}
//수신자 목록 체크 //수신자 목록 체크
if($('.phoneArea').length > 500) /* if($('.phoneArea').length > 500)
{ {
alert("최대 발송 건수는 500건 입니다."); alert("최대 발송 건수는 500건 입니다.");
return false; return false;
} } */
if($('#errorChk').val() === 'N' if($('#errorChk').val() === 'N'
@ -550,7 +569,7 @@ function sendTemplateInfo(){
// 초기화 // 초기화
$('.varValList').remove(); $('.varValList').remove();
$('#bizForm #varNmList').val(''); // $('#bizForm #varNmList').val('');
// 대체문자 전송 확인 // 대체문자 전송 확인
@ -613,133 +632,227 @@ function sendTemplateInfo(){
}else{ }else{
$('#bizForm #reqDate').val(""); $('#bizForm #reqDate').val("");
} }
var dataList = [];
// 치환문자 있는 데이터 파씽 // 치환문자 있는 데이터 파씽
if($('#bizForm #txtReplYn').val() === 'Y'){ if($('#bizForm #txtReplYn').val() === 'Y'){
fn_excelDataTransParsing(); // fn_excelDataTransParsing();
// 치환문자 있는 수신자 리스트 // 치환문자 있는 수신자 리스트
fn_transCallToListParsing(); dataList = fn_transCallToListParsing();
}else{ }else{
// 치환문자 없는 수신자 리스트 // 치환문자 없는 수신자 리스트
fn_callToListParsing(); dataList = fn_callToListParsing();
} }
$('#bizForm #senderKey').val($('#selectKakaoProfileList').val());
$('#bizForm #templateCode').val($('#selectTemplateList').val());
//수신자 목록 체크
if(dataList.length < 1)
{
alert('받는 사람 입력 후 발송해 주세요');
return false;
}
// 채널 ID
$('#bizForm #senderKey').val($('#selectKakaoProfileList').val());
// 채널 > 템플릿
$('#bizForm #templateCode').val($('#selectTemplateList').val());
// 발신번호 // 발신번호
$('#bizForm #callFrom').val(removeDash($('#callFromList option:selected').val())); $('#bizForm #callFrom').val(removeDash($('#callFromList option:selected').val()));
if(confirm("알림톡을 발송하시겠습니까?")){ // 폼 데이터를 배열로 직렬화
var spamChk = true; var form = $('#bizForm');
//2023.09.06 알림톡 스팸체크 기능 제거요청으로 인한 주석처리 var formDataArray = form.serializeArray();
/*var spamChk = false;
var spmData = new FormData(document.bizForm); // 배열을 객체로 변환
$.ajax({ var formData = {};
type: "POST" $.each(formDataArray, function(index, field) {
, url: "/web/mjon/alimtalk/selectSpamKakaoAlimtalkMsgChkAjax.do" formData[field.name] = field.value;
, data: spmData });
, dataType:'json'
, async: false // 빈 값 제거 (참고 코드 기반)
, processData: false for (var key in formData) {
, contentType: false if (formData[key] === '' || formData[key] === null || formData[key] === undefined) {
, cache: false delete formData[key];
, 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){
alert("전송 내용에 스팸문구가 포함되어 있습니다.")
return false;
}else{
spamChk = true;
return false;
}
} else if(status== 'fail'){
alert(returnData.message);
return false;
}
}
, error: function (e) {
alert("문자 발송에 실패하였습니다.");
console.log("ERROR : ", e);
return false;
}
}); */
if(spamChk){
var data = new FormData(document.bizForm);
$.ajax({
type: "POST"
, url: "/web/mjon/kakao/alimtalk/kakaoAlimTalkMsgSendAjax.do"
, data: data
, dataType: 'json'
, async: true
, processData: false
, contentType: false
, cache: false
, success: function (returnData, status) {
if(status == 'success'){
if("loginFail" == returnData.result){
alert(returnData.message);
return false;
}else if('fail' == returnData.result){
alert(returnData.message);
return false;
}else if('authFail' == returnData.result){
alert(returnData.message);
location.reload();
} else if(status == 'success'){
var kakaoSendCnt = returnData.resultSts;
$('.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>"+ kakaoSendCnt + "</strong>건의<br>알림톡이 예약 되었습니다.");
}else{
$('.pop_msg_success .msg_text').html("발송 성공 : <strong>"+ kakaoSendCnt + "</strong>건의<br>알림톡이 발송 되었습니다.");
}
$('.mask').addClass('on');
}
}
}
,beforeSend : function(xmlHttpRequest) {
//로딩창 show
$('.loading_layer').addClass('active');
}
,complete : function(xhr, textStatus) {
//로딩창 hide
$('.loading_layer').removeClass('active');
}
,error: function (e) {
console.log("ERROR : ", e);
alert("카카오 알림톡 전송에 실패하였습니다.");
}
});
} }
} }
// delete formData['varNmList'];
// 선택된 데이터 추가 (varListMap)
formData["varListMap"] = dataList;
console.log('formData : ', formData);
if(confirm("알림톡을 발송하시겠습니까?")){
// 프로그래스파 시간을 위한 계산
var estimtedTime = calculateEstimatedTime(dataList.length);
$.ajax({
type: "POST",
url: "/web/mjon/kakao/alimtalk/kakaoAlimTalkMsgSendAjax_advc.do",
data: JSON.stringify(formData),
contentType: 'application/json',
dataType: 'json',
success: function (data) {
console.log('data : ', data);
var status = data.status;
if("OK" == status){
var resultSts = data.object.resultSts;
var reserYn = data.object.reserYn;
var resText = (reserYn === 'Y') ? '예약' : '발송';
$('.pop_msg_success').css({'display':'block','opacity':'1','left':'50%','top':'50%','transform':'translate(-50%,-50%)'});
$('.pop_msg_success .msg_text').html(resText+" 성공 : <strong>"+ resultSts + "</strong>건의<br>알림톡이 " + resText + " 되었습니다.");
}else if("UNAUTHORIZED" == status){
alert(data.message);
location.reload();
}else{
alert(data.message);
return false;
}
// if(data == 'success'){
/* if("loginFail" == returnData.result){
alert(returnData.message);
return false;
}else if('fail' == returnData.result){
alert(returnData.message);
return false;
}else if('authFail' == returnData.result){
alert(returnData.message);
location.reload();
} else if(status == 'success'){
var kakaoSendCnt = returnData.resultSts;
$('.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>"+ kakaoSendCnt + "</strong>건의<br>알림톡이 예약 되었습니다.");
}else{
$('.pop_msg_success .msg_text').html("발송 성공 : <strong>"+ kakaoSendCnt + "</strong>건의<br>알림톡이 발송 되었습니다.");
}
$('.mask').addClass('on');
} */
// }
}
,beforeSend : function(xmlHttpRequest) {
//로딩창 show
// $('.loading_layer').addClass('active');
// 프로그래스 바 실행
progressStart(estimtedTime);
}
,complete : function(xhr, textStatus) {
//로딩창 hide
// $('.loading_layer').removeClass('active');
// 프로그래스 바 종료
progressComplete();;
}
,error: function (e) {
console.log("ERROR : ", e);
alert("카카오 알림톡 전송에 실패하였습니다.");
}
});
}
}
//선택된 데이터의 길이에 따라 예상 시간 계산 함수
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);
}
//프로그레스바
var start, change;
var progressInterval = null; // 전역 변수로 타이머 ID 관리
function progressStart(time) {
// 기존 타이머 정지 및 초기화
if (progressInterval !== null) {
clearInterval(progressInterval); // 이전 타이머 정지
progressInterval = null; // 타이머 ID 초기화
}
resetProgressBar(); // 프로그레스바 초기화
// 프로그레스바 보이기
$(".progress_bar_wrap").css("display", "flex");
// 프로그레스바 요소 가져오기
var timeText = document.querySelector(".time_text");
var bar = document.querySelector(".change_bar");
// 초기 상태 설정
var width = 1;
var totalTime = time * 1000; // 총 실행 시간 (밀리초)
var cmpWid = totalTime / 100; // width 증가 간격 (밀리초)
// 새 타이머 시작
progressInterval = setInterval(changeWidth, cmpWid);
function changeWidth() {
if (width >= 100) {
// 프로그레스바 100% 도달
clearInterval(progressInterval); // 타이머 종료
progressInterval = null; // 타이머 ID 초기화
timeText.innerHTML = "100%";
setTimeout(function () {
// 100% 표시 후 "잠시만 기다려주세요" 변경
timeText.innerHTML = "잠시만 기다려주세요...";
$(".time_text").addClass("animation");
}, 1000);
} else {
// 프로그레스바 진행
width++;
bar.style.width = width + "%";
timeText.innerHTML = width + "%";
}
}
}
//프로그레스바 완료
function progressComplete() {
// var width = parseInt($(".time_text").text().replace('%', '')) || 0; // 현재 width 가져오기
$(".progress_bar_wrap").hide();
} }
/* /*
* 치환문자 있는 수신자 목록 파씽 * 치환문자 있는 수신자 목록 파씽
*/ */
function fn_transCallToListParsing(){ function fn_transCallToListParsing(){
var callToList = []; /* var callToList = [];
// excel body // excel body
$('.excelBody').each(function(indexBody, itemBody){ $('.excelBody').each(function(indexBody, itemBody){
$(itemBody).find('.list_table_name').each(function(indexRow, itemRow){ $(itemBody).find('.list_table_name').each(function(indexRow, itemRow){
@ -750,7 +863,31 @@ function fn_transCallToListParsing(){
}); });
}); });
$('#bizForm #callToList').val(callToList); $('#bizForm #callToList').val(callToList);
*/
var dataList = [];
var headers = [];
$('#excelHead .list_table_name').each(function() {
headers.push($(this).text().trim());
});
$('.excelBody').each(function() {
var row = {};
$(this).find('.list_table_name').each(function(index) {
var key = headers[index];
var value = $(this).text().trim();
if (index === 0) {
row["callToList"] = value; // 수신번호는 별도로 처리
} else {
row[key] = value; //
}
});
console.log(row)
dataList.push(row);
});
return dataList;
} }
/* /*
@ -758,13 +895,28 @@ function fn_transCallToListParsing(){
*/ */
function fn_callToListParsing(){ function fn_callToListParsing(){
var callToList = []; var dataList = [];
// excel body
$('.phoneArea').each(function(index, item){ /* $('.phoneArea').each(function(index, item){
callToList.push($(item).text().replaceAll('\\t', '')); var row = {};
var value = $(item).text().replaceAll('\\t', '')
row["callToList"] = value; // 수신번호는 별도로 처리
dataList.push(row);
});
*/
// Tabulator 테이블의 데이터 가져오기
var tableData = tableL.getData();
tableData.forEach(function(row){
var dataRow = {};
dataRow["callToList"] = row.phone; // phone 필드 값을 callToList로 저장
dataList.push(dataRow);
}); });
$('#bizForm #callToList').val(callToList); return dataList;
} }
@ -777,9 +929,8 @@ function fn_excelDataTransParsing(){
// title 배열 // title 배열
var varHead = []; var varHead = [];
// 값 배열 // 값 배열
var varVal = []; // var varVal = [];
var inputTag = '<input type="hidden" class="varValList" name="varValList[$INDEX$]" value="$VAL$">';
// excel title // excel title
$('#excelHead').find('div').each(function(index, item){ $('#excelHead').find('div').each(function(index, item){
@ -803,7 +954,7 @@ function fn_excelDataTransParsing(){
$("#bizForm").append(inputTag.replace('$VAL$',varValTemp ).replace('$INDEX$',index )); $("#bizForm").append(inputTag.replace('$VAL$',varValTemp ).replace('$INDEX$',index ));
}); */ }); */
$('.excelBody').each(function(index, item){ /* $('.excelBody').each(function(index, item){
var valLeng = $('#excelHead').find('.list_table_name').length-1; var valLeng = $('#excelHead').find('.list_table_name').length-1;
varValTemp = ''; varValTemp = '';
@ -821,7 +972,7 @@ function fn_excelDataTransParsing(){
console.log('varValTemp : ',varValTemp); console.log('varValTemp : ',varValTemp);
varVal.push(varValTemp); varVal.push(varValTemp);
}); });
$('#bizForm #varValList').val(varVal); $('#bizForm #varValList').val(varVal); */
} }
@ -881,9 +1032,9 @@ function thisFnByteString(contents){
$('#smsLen').val(conLeng); $('#smsLen').val(conLeng);
$('#msgLeng').html(conLeng + " / ");
if(conLeng > 90){ if(conLeng > 90){
$('#msgLeng').html(conLeng + " / ");
$('#limitLeng').html("2000"); $('#limitLeng').html("2000");
$('.msg_com').html("장문"); $('.msg_com').html("장문");
$('#msgType').val("6"); // 메세지 타입 설정 $('#msgType').val("6"); // 메세지 타입 설정
@ -897,7 +1048,6 @@ function thisFnByteString(contents){
}else{ }else{
$('#msgLeng').html(conLeng + " / ");
$('#limitLeng').html("90"); $('#limitLeng').html("90");
$('.msg_com').html("단문"); $('.msg_com').html("단문");
$('#msgType').val("4"); // 메세지 타입 설정 $('#msgType').val("4"); // 메세지 타입 설정
@ -910,7 +1060,7 @@ function thisFnByteString(contents){
} }
//수신목록 전체 데이터 갯수 구하기 //수신목록 전체 데이터 갯수 구하기
updateTotCnt(totRows); //updateTotCnt(totRows);
} }
/** /**
@ -1141,6 +1291,17 @@ $(window).on('load', function() {
</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>
<!-- 기업회원 이동 팝업 --> <!-- 기업회원 이동 팝업 -->
<div class="tooltip-wrap cvt_member_popup_wrap"> <div class="tooltip-wrap cvt_member_popup_wrap">
<div class="popup-com cvt_member_layer" tabindex="0" data-tooltip-con="cvt_member_layer" data-focus="cvt_member_layer" data-focus-prev="cvt_member_layer-close"> <div class="popup-com cvt_member_layer" tabindex="0" data-tooltip-con="cvt_member_layer" data-focus="cvt_member_layer" data-focus-prev="cvt_member_layer-close">
@ -1192,8 +1353,8 @@ $(window).on('load', function() {
<input type="hidden" id="divideTime" name="divideTime" value=""> <!--전송일자--> <input type="hidden" id="divideTime" name="divideTime" value=""> <!--전송일자-->
<input type="hidden" id="callFrom" name="callFrom" value=""> <!--완 보내는사람 --> <input type="hidden" id="callFrom" name="callFrom" value=""> <!--완 보내는사람 -->
<input type="hidden" id="callToList" name="callToList" value=""> <!--완 받는사람 리스트--> <!-- <input type="hidden" id="callToList" name="callToList" value=""> 완 받는사람 리스트 -->
<input type="hidden" id="varNmList" name="varNmList" value=""> <!--완 변수 이름 리스트--> <!-- <input type="hidden" id="varNmList" name="varNmList" value=""> 완 변수 이름 리스트 -->
<input type="hidden" id="varValList" name="varValList" value=""> <!--완 변수 리스트--> <input type="hidden" id="varValList" name="varValList" value=""> <!--완 변수 리스트-->
<input type="hidden" id="atSmishingYn" name="atSmishingYn" value="${atSmishingYn}"> <!--알림톡 스미싱 여부--> <input type="hidden" id="atSmishingYn" name="atSmishingYn" value="${atSmishingYn}"> <!--알림톡 스미싱 여부-->
@ -1354,25 +1515,25 @@ $(window).on('load', function() {
</span> </span>
</div> </div>
<div class="receipt_num_midde"> <div class="receipt_num_midde">
<div class="listType list01" > <div class="listType list01 callList_box_P">
<div class="list_table list_head"> <!-- <div class="list_table list_head">
<div class="cb_wrap"> <div class="cb_wrap">
<label for="select_all" class="label"></label> <label for="select_all" class="label"></label>
<input type="checkbox" id="select_all"> <input type="checkbox" id="select_all">
</div> </div>
<div class="list_table_num"> <div class="list_table_num">
<p>휴대폰</p> <p>휴대폰</p>
<!-- <img src="/publish/images/sortUp.png"> --> <img src="/publish/images/sortUp.png">
<!-- <img src="/publish/images/sortDown.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 class="list_table_name"> -->
<!-- <p>이름</p> -->
<!-- <img src="/publish/images/sortUp.png"> -->
<!-- <img src="/publish/images/sortDown.png"> -->
<!-- </div> -->
</div> </div>
<div class="list_body_wrap" id="wrap01_body"> <div class="list_body_wrap" id="wrap01_body">
</div> </div> -->
</div> </div>
<div class="put_right"> <div class="put_right">
<div class="btn_popup_wrap spc_wrap"> <div class="btn_popup_wrap spc_wrap">
@ -1684,7 +1845,9 @@ $(window).on('load', function() {
<!--// table --> <!--// table -->
</div> </div>
<div class="popup_btn_wrap2"> <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> <button type="button" onClick="javascript:addrClose(); return false;">닫기</button>
</div> </div>
<%-- 주소록 레이어 팝업 닫기 실행 코드 --%> <%-- 주소록 레이어 팝업 닫기 실행 코드 --%>
@ -1773,6 +1936,7 @@ $(window).on('load', function() {
<!-- 엑셀 불러오기 --> <!-- 엑셀 불러오기 -->
<form id="excelToolTipForm" name="excelToolTipForm" method="post"> <form id="excelToolTipForm" name="excelToolTipForm" method="post">
<div class="tooltip-wrap"> <div class="tooltip-wrap">

View File

@ -18,8 +18,6 @@
$(document).ready(function(){ $(document).ready(function(){
console.log(": MsgDataSMLView :");
// console.log(' + $(#tabDision).val() : ',$('#tabDision').val()) // console.log(' + $(#tabDision).val() : ',$('#tabDision').val())
// if($('#tabDision').val() == 'tab02'){ // if($('#tabDision').val() == 'tab02'){

View File

@ -71,8 +71,6 @@ $(document).ready(function(){
</div> </div>
</div> </div>
<div class="btn_wrap"> <div class="btn_wrap">
<!-- <button type="button" class="btnType btnType2" style="margin:50px 0;" onclick="progressStart(10,'완료되었습니다.');">시작</button>
<button type="button" class="btnType btnType2" style="margin:50px 0;" onclick="progressComplete('완료되었습니다.');return false;">멈춤</button> -->
</div> </div>
</div> </div>

View File

@ -200,6 +200,8 @@ function XSSChange(str) {
//숫자 천단위 콤마 찍어주기 //숫자 천단위 콤마 찍어주기
function numberWithCommas(x) { function numberWithCommas(x) {
console.log(' + typeof x : ',typeof x);
console.log(' + x : ',x);
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} }
@ -1030,6 +1032,17 @@ function removeDuplicatesAndCount(array, key) {
} }
function setAllCntData(result){
console.log('result :: ', result);
// 합쳐진 데이터를 tableL에 설정합니다.
tableL.setData(result.uniqueArray);
// 중복데이터 건수 입력
setRowDupCnt(result.duplicateCount);
$('#rowTotCnt').text(result.uniqueCount)
}
function validateRowLimit(totalRows, limit = 300000) { function validateRowLimit(totalRows, limit = 300000) {
// 값과 타입 확인 // 값과 타입 확인

View File

@ -101,6 +101,7 @@ function addrClose(){
} }
//주소록 불러오기에서 수신자 리스트 추가해 주기 //주소록 불러오기에서 수신자 리스트 추가해 주기
/*
function addrToList(){ function addrToList(){
var selectedData = tableAddr.getSelectedRows(); var selectedData = tableAddr.getSelectedRows();
@ -114,10 +115,10 @@ function addrToList(){
}else{ // 선택한 Row 데이터 저장해주기 }else{ // 선택한 Row 데이터 저장해주기
// 선택한 Row 데이터 저장해주기 // 선택한 Row 데이터 저장해주기
if(selectedData.length > 500){ // if(selectedData.length > 500){
alert("최대 발송 건수는 500 입니다."); // alert("최대 발송 건수는 500 입니다.");
return false; // return false;
}else{ // }else{
for(var i=0; i < selectedData.length; i++){ for(var i=0; i < selectedData.length; i++){
//좌측 받는사람 리스트를 담아둔 배열에 데이터를 추가해 준다. //좌측 받는사람 리스트를 담아둔 배열에 데이터를 추가해 준다.
@ -137,10 +138,68 @@ function addrToList(){
//주소록 레이어 팝업의 Tabulator 데이터 지워주기 //주소록 레이어 팝업의 Tabulator 데이터 지워주기
tableAddr.clearData(); tableAddr.clearData();
} // }
} }
} }
*/
//주소록 불러오기에서 수신자 리스트 추가해 주기
function addrToList_advc(type){
// 선택된 데이터 또는 전체 데이터 변수 초기화
let selectedData = type === 'select' ? tableAddr.getSelectedRows() : tableAddr.getData();
// 데이터가 비어있으면 경고 후 종료
if (!selectedData || selectedData.length < 1) {
if(tableAddr.getDataCount() < 1){
alert("주소록을 선택해 주세요.");
}else{
alert("전화번호를 선택해 주세요.");
}
return false;
}
// 데이터 변환 로직
const addrData = selectedData.map(row => {
const rowData = type === 'select' ? row.getData() : row; // 'select'는 행 객체에서 데이터 추출
return {
phone: removeDash(rowData.phone),
};
})
.filter(row => checkHpNum(row.phone)); // 유효한 번호만 필터링;
// 기존 tableL의 데이터를 가져옵니다.
var existingData = tableL.getData();
// 기존 데이터와 새로운 데이터를 합칩니다.
var combinedData = existingData.concat(addrData);
// @ phone을 기준으로 중복 제거 및 갯수 계산
const result = removeDuplicatesAndCount(combinedData, 'phone');
// 총 30만건이 넘으면 false
if (!validateRowLimit(result.uniqueCount)) {
return false;
}
setAllCntData(result);
// 미리보기 버튼 활성화
$(".closeAddr").trigger("click");
//주소록 레이어 팝업의 Tabulator 데이터 지워주기
tableAddr.clearData();
fn_priceClclt();
}
function loadAddrList(){ function loadAddrList(){
console.log(' loadAddrList() '); console.log(' loadAddrList() ');
@ -150,7 +209,8 @@ function loadAddrList(){
*/ */
var data = $("#searchAddrGrpForm").serialize(); var data = $("#searchAddrGrpForm").serialize();
var url = "/web/mjon/msgdata/selectMsgAddrListAjax.do"; // var url = "/web/mjon/msgdata/selectMsgAddrListAjax.do";
var url = "/web/mjon/msgdata/selectMsgAddrListAjax_advc.do";
$.ajax({ $.ajax({
type: "POST", type: "POST",
@ -159,43 +219,36 @@ function loadAddrList(){
dataType:'json', dataType:'json',
async: false, async: false,
cache: false, cache: false,
success: function (returnData, status) { success: function (data) {
console.log('returnData : ', returnData); console.log('data : ', data);
if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나 if(data.status == "OK"){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
if(returnData.result == "success"){
var addrList = data.object;
var addrList = returnData.resultAddrList;
var tableData = []; if(addrList.length == 0){
if(addrList.length == 0){ alert("주소록 정보가 없습니다.");
// tableAddr.setData([]);
alert("주소록 정보가 없습니다."); return false;
tableAddr.setData(tableData); }
return false; tableAddr.setData(addrList);
} }
else
//받는사람 리스트를 담아둔 배열에 신규 추가 데이터를 추가해 준다. {
for(var i=0; i < addrList.length; i++){ alert("주소록 불러오기에 실패하였습니다. !!");
}
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}); },
error: function (e) {
} alert("주소록 불러오기에 실패하였습니다."); console.log("ERROR : ", e);
}
//우측 주소록 리스트 Tabulator에 입력해주기 , beforeSend : function(xmlHttpRequest) {
tableAddr.setData(tableData); //로딩창 show
$('.loading_layer').addClass('active');
}else{ }
, complete : function(xhr, textStatus) {
alert(returnData.message); //로딩창 hide
return false; $('.loading_layer').removeClass('active');
}
}
} else if(status== 'fail'){
alert("주소록 불러오기에 실패하였습니다. !!");
}
},
error: function (e) { alert("주소록 불러오기에 실패하였습니다."); console.log("ERROR : ", e); }
}); });
} }

View File

@ -198,6 +198,7 @@ function excelAddAjax(){
* *
* */ * */
function excelExportVarAjax(){ function excelExportVarAjax(){
console.log(' :: excelExportVarAjax ::')
var data = document.getElementById('excelFile').files; var data = document.getElementById('excelFile').files;
@ -245,7 +246,7 @@ function excelAddVarAjax(){
//timeout: 600000, //timeout: 600000,
success: function (returnData, status) { success: function (returnData, status) {
if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나 if(status == 'success'){ // status 확인 필요한가. 석세스 안뜨면 에러 가지 않나
console.log('returnData : ', returnData);
if(returnData.success){ if(returnData.success){
var data = returnData.data; var data = returnData.data;
@ -290,10 +291,10 @@ function excelAddVarAjax(){
var totalDuplCnt = $('#rowDupCnt').text();//중복 건수 정보 var totalDuplCnt = $('#rowDupCnt').text();//중복 건수 정보
var $excelBody = $('#excelBody02'); var $excelBody = $('#excelBody02');
var bodyData;
var addDiv = ""; var addDiv = "";
var phoneNum; var phoneNum;
var msgCnt = 0;
//입력데이터를 역정렬해준다. //입력데이터를 역정렬해준다.
data.reverse(); data.reverse();
@ -337,6 +338,7 @@ function excelAddVarAjax(){
if(lengthCheck){ if(lengthCheck){
addDiv += excelBody; addDiv += excelBody;
msgCnt++;
} }
} }
@ -359,6 +361,9 @@ function excelAddVarAjax(){
//화면에 수신번호 및 변수 데이터 추가해 주기 //화면에 수신번호 및 변수 데이터 추가해 주기
$excelBody.append(addDiv); $excelBody.append(addDiv);
// 총 금액 계산
fn_priceClclt(msgCnt);
} }

View File

@ -12,6 +12,8 @@
* *
* *
*/ */
$(document).ready(function(){ $(document).ready(function(){

View File

@ -70,8 +70,6 @@ $(document).ready(function(){
fn_priceClclt(); fn_priceClclt();
}); });
// 대상 노드에 감시자 전달 // 대상 노드에 감시자 전달
observer_wrap01.observe(target01, option); observer_wrap01.observe(target01, option);
@ -85,18 +83,24 @@ $(document).ready(function(){
/** /**
* @description 금액 계산 function * @description 금액 계산 function
*/ */
function fn_priceClclt(){ function fn_priceClclt(phoneSu = 0){
// 미리보기 텍스트 console.log(":: at fn_priceClclt :: ");
var templateHtml = $('#smsTxtArea').val(); // 미리보기 텍스트
// var templateHtml = $('.template_text').html(); var templateHtml = $('#smsTxtArea').val();
// var templateHtml = $('.template_text').html();
// 수신 번호 개수
var phoneSu = $('.phoneArea').length; // 치환문자 여부 확인
var txtReplYn = $('#txtReplYn').val()
console.log('txtReplYn : ', txtReplYn);
// 수신 번호 개수
if(phoneSu == 0 && txtReplYn == 'Y')
phoneSu = $('.phoneArea').length;
if(phoneSu == 0 && txtReplYn == 'N')
phoneSu = tableL.getData().length;
// 대체문자 있는지 확인 // 대체문자 있는지 확인
var isSendFailChecked = $("#send_fail_check").is(":checked"); var isSendFailChecked = $("#send_fail_check").is(":checked");
// 치환문자 여부 확인
var txtReplYn = $('#txtReplYn').val()
// 대체문자 하위에 장문 / 단문 select // 대체문자 하위에 장문 / 단문 select
var msgTypeText = $('.msg_com').text().trim(); var msgTypeText = $('.msg_com').text().trim();
@ -212,8 +216,8 @@ function fn_writePriceText(msgTypeText, phoneSu){
if(msgTypeText == '단문') price = SHORT_PRICE * phoneSu; if(msgTypeText == '단문') price = SHORT_PRICE * phoneSu;
else if(msgTypeText == '장문') price = LONG_PRICE * phoneSu; else if(msgTypeText == '장문') price = LONG_PRICE * phoneSu;
else price = KAKAO_AT_PRICE * phoneSu; // 카카오 else price = KAKAO_AT_PRICE * phoneSu; // 카카오
$('#totalPriceTxt').text((price).toFixed(1)); $('#totalPriceTxt').text(numberWithCommas((price).toFixed(1)));
} }

View File

@ -12,83 +12,41 @@
* *
* *
*/ */
var tableL = null;
$(document).ready(function (){ $(document).ready(function (){
/**
//받는사람 연락처 내용 처리 //받는사람 연락처 내용 처리
//Tabulator AJAX Data Loading //Tabulator AJAX Data Loading
tableL = new Tabulator(".callList_box", { tableL = new Tabulator(".callList_box_P", {
height:"255px", height:"255px",
layout:"fitColumns", layout:"fitColumns",
//data:tabledata, headerHozAlign:"center",
//autoColumns:true, validationMode:"highlight",
headerHozAlign:"center", headerHozAlign:"center",
validationMode:"highlight", validationMode:"highlight",
//clipboard:false,
//clipboardCopySelector:"table",
//clipboardPasteAction:"insert", // insert, update, replace
placeholder:"복사(Ctrl+C)한 내용을 여기에 붙여넣기(Ctrl+V) 해주세요.", //fit columns to width of table (optional) placeholder:"복사(Ctrl+C)한 내용을 여기에 붙여넣기(Ctrl+V) 해주세요.", //fit columns to width of table (optional)
resizableColumns:false, resizableColumns:false,
columnDefaults:{ // 공통설정
hozAlign: "center",
headerHozAlign: "center",
editor: "input",
editor: false
},
columns:[ //Define Table Columns columns:[ //Define Table Columns
{formatter:"rowSelection", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", headerSort:false, cellClick:function(e, cell){ {formatter:"rowSelection", titleFormatter:"rowSelection", width:60, clipboard:false, hozAlign:"center", headerSort:false, cellClick:function(e, cell){
cell.getRow().toggleSelect(); cell.getRow().toggleSelect();
}}, }},
{title:"이름", hozAlign:"center", field:"name", editor:"input", validator:["maxLength:12"], cellEdited:function(cell){ // {title:"이름", hozAlign:"center", field:"name", editor:"input", validator:["maxLength:12"], cellEdited:function(cell){
//cell - cell component // //cell - cell component
fnReplCell(); // fnReplCell();
}}, // }},
{title:"휴대폰", hozAlign:"center", field:"phone", editor:"input", width:100, validator:["required","minLength:10", "maxLength:12"], cellEdited:function(cell){ {title:"휴대폰", hozAlign:"center", field:"phone", editor:"input", validator:["required","minLength:10", "maxLength:12"], cellEdited:function(cell){
//cell - cell component //cell - cell component
fnDuplPhone(); fnDuplPhone();
}}, }},
{title:"[*1*]", hozAlign:"center", field:"rep1", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){ ]
//cell - cell component
fnReplCell();
}},
{title:"[*2*]", hozAlign:"center", field:"rep2", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
//cell - cell component
fnReplCell();
}},
{title:"[*3*]", hozAlign:"center", field:"rep3", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
//cell - cell component
fnReplCell();
}},
{title:"[*4*]", hozAlign:"center", field:"rep4", editor:"input", minWidth:60, validator:["maxLength:40"], cellEdited:function(cell){
//cell - cell component
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();
}
//해당 셀 데이터 삭제
//cell.setValue("");
}
return value % parameters.phone;
},
}); });
*/
//주소록 불러오기 팝업 내용 //주소록 불러오기 팝업 내용
//Tabulator AJAX Data Loading //Tabulator AJAX Data Loading
tableAddr = new Tabulator(".callAddr_box", { tableAddr = new Tabulator(".callAddr_box", {
@ -99,13 +57,13 @@ $(document).ready(function (){
placeholder:"주소록 그룹을 선택해 주세요.", //fit columns to width of table (optional) placeholder:"주소록 그룹을 선택해 주세요.", //fit columns to width of table (optional)
resizableColumns:false, resizableColumns:false,
columns:[ //Define Table Columns columns:[ //Define Table Columns
{formatter:"rowSelection", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", headerSort:false, cellClick:function(e, cell){ {formatter:"rowSelection", titleFormatter:"rowSelection",clipboard:false, hozAlign:"center", headerSort:false, width: 50, cellClick:function(e, cell){
cell.getRow().toggleSelect(); cell.getRow().toggleSelect();
} }
}, },
{title:"그룹명", hozAlign:"center", field:"addrGroupNm", editor:"input", width:120, validator:["required","minLength:2", "maxLength:40"]}, {title:"그룹명", hozAlign:"center", field:"addrGroupNm", widthGrow: 3, editor:"input", validator:["required","minLength:2", "maxLength:40"]},
{title:"이름", hozAlign:"center", field:"addrName", editor:"input", width:120, validator:["maxLength:12"]}, {title:"이름", hozAlign:"center", field:"name", widthGrow: 2, editor:"input", validator:["maxLength:12"]},
{title:"휴대폰번호", hozAlign:"center", field:"addrPhone", editor:"input", width:120, validator:["required","minLength:10", "maxLength:11"]}, {title:"휴대폰번호", hozAlign:"center", field:"phone", widthGrow: 3, editor:"input", validator:["required","minLength:10", "maxLength:11"]},
], ],
validationFailed:function(cell, value, parameters){ // 유효성 체크 함수 - 아직 잘 모르겠음 validationFailed:function(cell, value, parameters){ // 유효성 체크 함수 - 아직 잘 모르겠음
@ -132,53 +90,32 @@ $(document).ready(function (){
//받는사람 번호 버튼 클릭시 Tabulator에 데이터 넣어주기 //받는사람 번호 버튼 클릭시 Tabulator에 데이터 넣어주기
$('.addCallToF').click(function(){ $('.addCallToF').click(function(){
var callToNum = $('#callTo').val(); // checkHpNum(callToNum)
if(callToNum == null || callToNum == ""){
alert("받는사람 번호를 입력해 주세요.");
return false;
}else if(!checkHpNum(callToNum)){
alert("올바른 전화번호를 입력해 주세요.");
$('#callTo').val("");
return false;
}
//핸드폰 번호에 '-' 문자 제거하기
callToNum = removeDash(callToNum);
var dpCnt = 0; var textarea = $('#callTo');
$(".phoneArea p").each(function(index, item){ const numbers = textarea.val().split('\n')
if(this.textContent == callToNum){ .map(num => removeDash(num.trim()))
.filter(num => num !== "")
dpCnt++; .filter(num => checkHpNum(num)); // 유효한 번호만 필터링;
alert("받는사람 리스트에 동일한 연락처가 있습니다.");
$('#callTo').val("");
return false; const formattedData = numbers.map(num => ({phone: num}));
}
}); // 기존 tableL의 데이터를 가져옵니다.
var existingData = tableL.getData();
if(dpCnt > 0){ // 기존 데이터와 새로운 데이터를 합칩니다.
alert("받는사람 리스트에 동일한 연락처가 있습니다."); var combinedData = existingData.concat(formattedData);
$('#callTo').val("");
return false; // @ phone을 기준으로 중복 제거 및 갯수 계산
}else{ const result = removeDuplicatesAndCount(combinedData, 'phone');
// fn_displayJsonToHtmlTable 재사용을 위한
// 파라미터 형변환 setAllCntData(result);
var data =[];
data.push({ phone: callToNum, name: ''}); textarea.val('');
fn_displayJsonToHtmlTable(data); fn_priceClclt();
/*
* 토탈 카운트 화면에 노출
*/
updateTotCnt();
// 번호 추가란 초기화
$('#callTo').val('');
}
}); });
@ -442,9 +379,9 @@ var totRows = 0; // 좌측 받는사람 총 갯수
* 토탈 카운트 화면에 노출 * 토탈 카운트 화면에 노출
* 변수 없는 리스트만 체크 * 변수 없는 리스트만 체크
*/ */
function updateTotCnt(){ function updateTotCnt(cnt){
$("#rowTotCnt").text($('#wrap01_body .list_body').length); $("#rowTotCnt").text(cnt);
} }
@ -456,10 +393,10 @@ function addPhoneInfo(taData){
return; return;
} }
if(taData.length > 500){ // if(taData.length > 500){
alert("최대 발송 건수는 500건 입니다."); // alert("최대 발송 건수는 500건 입니다.");
return; // return;
} // }
/* /*

View File

@ -1269,8 +1269,6 @@ function sendMsgAjax_advc(){
var url = "/web/mjon/msgdata/sendMsgDataAjax_advc.do"; var url = "/web/mjon/msgdata/sendMsgDataAjax_advc.do";
// 시작 시간 // 시작 시간
const startTime = new Date();
// 프로그래스파 시간을 위한 계산 // 프로그래스파 시간을 위한 계산
var estimtedTime = calculateEstimatedTime($selectedData.length); var estimtedTime = calculateEstimatedTime($selectedData.length);