File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
/**
* 20건 수동문자
*
* 주요 기능:
* 1. 발송 가능 상태(발송전)인 대상자만 선택 가능
* 2. 엔터키 롱프레스 연속 선택 (현재 페이지에서만)
* 3. 선택해제 시 완전 초기화
*/
var isSpacePressed = false;
var isSendLocked = false;
$(document).ready(function(){
// 필요 시 초기화 코드
});
/* ====================== 엔터키 연속 선택 ====================== */
$(document).on("keydown", function (e) {
var isSpaceChecked = $("input:checkbox[name='sendBySpace']").is(":checked");
// Spacebar로 발송 (기존 유지)
if (e.keyCode === 32 && isSpaceChecked && !$(".put_text").is(':focus')) {
e.preventDefault();
if (isSpacePressed || isSendLocked) return;
isSpacePressed = true;
// isSendLocked = true;
var checkedCnt = twSmsTable.getSelectedData().length;
if (checkedCnt > 0) {
setTimeout(function () {
$(".btn_send").click();
}, 500);
} else {
isSendLocked = false;
alert("발송할 대상을 선택해 주세요.");
}
return;
}
// ==================== 엔터키 연속 선택 ====================
if (e.keyCode === 13 && !$(".put_text").is(':focus')) {
if ($(e.target).is("input, textarea, select, [contenteditable='true']")) {
return;
}
e.preventDefault();
if (isEnterPressed || isSendLocked) return;
isEnterPressed = true;
window.enterSelectCurrentPage = twSmsTable.getPage() || 1;
// 처음 시작할 때 1개 선택
selectRowsFastInCurrentPage(1);
// 연속 선택 시작
enterLongPressTimer = setInterval(function () {
var selected = selectRowsFastInCurrentPage(3);
// 현재 페이지에 더 이상 선택할 행이 없으면 → 선택 완료로 판단하고 발송
if (!selected) {
clearInterval(enterLongPressTimer);
enterLongPressTimer = null;
window.enterSelectCurrentPage = null;
if (isSendLocked) return;
// isSendLocked = true;
triggerSend();
return;
}
// 페이지가 바뀌었으면 강제 종료
if (twSmsTable.getPage() !== window.enterSelectCurrentPage) {
clearInterval(enterLongPressTimer);
enterLongPressTimer = null;
isEnterPressed = false;
window.enterSelectCurrentPage = null;
}
}, 120);
}
});
$(document).on("keyup", function (e) {
if (e.keyCode === 13) {
isEnterPressed = false;
// isSendLocked = false;
if (enterLongPressTimer) {
clearInterval(enterLongPressTimer);
enterLongPressTimer = null;
}
window.enterSelectCurrentPage = null;
}
if (e.keyCode === 32) {
isSpacePressed = false;
// isSendLocked = false;
}
});
// ====================== 발송 트리거 함수 ======================
function triggerSend() {
var checkedCnt = twSmsTable.getSelectedData().length;
if (checkedCnt > 0) {
// UI 업데이트를 위한 최소한의 딜레이 (0.2초 추천)
setTimeout(function () {
$(".btn_send").click();
}, 200);
} else {
alert("발송할 대상을 선택해 주세요.");
}
}
/* ====================== 선택 함수 ====================== */
/**
* 현재 페이지에서 빠르게 선택
*/
function selectRowsFastInCurrentPage(count) {
var rows = getCurrentPageSelectableRows();
if (rows.length === 0) return false;
var selectedCount = 0;
var table = twSmsTable;
table.blockRedraw();
try {
for (var i = 0; i < rows.length; i++) {
var row = rows[i];
if (!row.isSelected() && isSelectableStatus(row.getData().status)) {
row.select();
selectedCount++;
if (selectedCount >= count) break;
}
}
} finally {
table.restoreRedraw();
}
// 선택 후 현재 페이지에 더 이상 선택 가능한 행이 없으면 false 반환
return getCurrentPageSelectableRows().length > 0;
}
/**
* 현재 페이지에 보이는 선택 가능한 행만 반환 (이미 선택된 행은 제외)
*/
function getCurrentPageSelectableRows() {
var table = twSmsTable;
if (!table) return [];
var visibleRows = table.getRows("visible");
var selectableRows = [];
for (var i = 0; i < visibleRows.length; i++) {
var row = visibleRows[i];
if (isSelectableStatus(row.getData().status) && !row.isSelected()) {
selectableRows.push(row);
}
}
return selectableRows;
}
/**
* 발송전 상태 체크
*/
function isSelectableStatus(status) {
var text = "";
if(status === null || status === undefined){
text = "";
}else{
text = String(status).replace(/<[^>]*>/g, "").replace(/\s/g, "");
}
// 선택 가능: 미발송 상태만 허용
if(text === "" || text === "N" || text === "발송전"){
return true;
}
// 선택 불가: 발송 성공/제외
if(text === "Y" || text === "발송성공"){
return false;
}
if(text === "F" || text === "발송제외"){
return false;
}
return false;
}
/* ====================== 선택해제 ====================== */
function clearAllSelection(){
if(!window.twSmsTable) return;
var table = window.twSmsTable;
table.blockRedraw();
try {
table.deselectRow(); // 전체 해제
table.getRows().forEach(function(row){
row.deselect();
});
} finally {
table.restoreRedraw();
}
// 엔터키 선택 상태 초기화
if (enterLongPressTimer) {
clearInterval(enterLongPressTimer);
enterLongPressTimer = null;
}
window.enterSelectCurrentPage = null;
}
/* ====================== 페이지네이션 ====================== */
$(document).on("click", "#sms-pagination .page-btn", function(){
var page = $(this).data("page");
if($(this).prop("disabled")) return;
// 엔터키 선택 중이었으면 상태 초기화
if (window.enterSelectCurrentPage) {
window.enterSelectCurrentPage = null;
}
var table = window.twSmsTable || table; // window.twSmsTable이 우선
if(page === "first"){ table.setPage(1); return; }
if(page === "prev"){ table.previousPage(); return; }
if(page === "next"){ table.nextPage(); return; }
if(page === "last"){ table.setPage(table.getPageMax()); return; }
table.setPage(Number(page));
});
/* ====================== 기타 기존 함수 ====================== */
function twUpdateTotCnt(){
var totRows = twSmsTable.getRows().length;
var twTotalRowCnt = Number(totRows) || 0;
$('#totCallToCnt').text(twTotalRowCnt);
if(window.twSmsTable){
window.twSmsTable.redraw(true);
}
}
function updateTwSmSTable(addrData){
const existingData = twSmsTable.getData();
const phoneToItemMap = new Map(existingData.map(item => [item.phone, item]));
const newlyAdded = [];
// 1. 데이터 병합 및 중복 제거 루프 수행
for (const item of addrData) {
const phone = item.phone;
if (phone && !phoneToItemMap.has(phone)) {
newlyAdded.push(item);
phoneToItemMap.set(phone, item);
}
}
// 2. 루프 종료 후 최종 Map의 크기(전체 데이터 건수) 체크
const MAX_LIMIT = 300000;
console.log('phoneToItemMap.size : ', phoneToItemMap.size);
if (phoneToItemMap.size > MAX_LIMIT) {
alert(`최대 허용 건수(${MAX_LIMIT.toLocaleString()}건)를 초과했습니다. 현재: ${phoneToItemMap.size.toLocaleString()}건`);
console.error("Data limit exceeded after merge.");
return; // 테이블 업데이트를 하지 않고 종료
}
console.log('phoneToItemMap.size!!!!!!!! : ', phoneToItemMap.size);
twSmsTable.setData(Array.from(phoneToItemMap.values()));
twUpdateTotCnt();
var tmpJobId = $('#tmpJobId').val();
console.log('tmpJobId : ', tmpJobId);
console.log('newlyAdded.length : ', newlyAdded.length );
if(newlyAdded.length < 1){
alert("중복 제거 후 추가할 데이터가 없습니다.");
return false;
}
if(tmpJobId){
fn_updateCampainTmpJob(tmpJobId, newlyAdded);
}else{
fn_insertCampainTmpJob(newlyAdded);
}
}
function fn_udpateCampainJob(p_tmpJobId, p_jobStatus){
var sendData = {
"tmpJobId" : p_tmpJobId,
"jobStatus" : p_jobStatus
}
console.log('sendData :: ',sendData);
$.ajax({
type: 'POST',
url: '/web/mjon/msgcampain/updateCampainJobStatus.do',
contentType: 'application/json',
data: JSON.stringify(sendData),
dataType: 'json',
success : function(data) {
console.log(data);
if(data.status == 'OK')
{
// 성공 후 처리 로직
}
else
{
// 실패 처리 로직
}
},
error : function(jqXHR, textStatus, errorThrown) {
console.error("AJAX Error:", textStatus, errorThrown);
console.error("Response:", jqXHR.responseText);
}
});
}
function fn_updateCampainTmpJob(tmpJobId, newlyAdded){
console.log('newlyAdded : ', newlyAdded);
var sendData = {
"totalCount" : newlyAdded.length
,"tmpJobId" : tmpJobId
}
$.ajax({
type: 'POST',
url: "/web/mjon/msgcampain/updateMjCampainTmpJob.do",
contentType: 'application/json',
data: JSON.stringify(sendData),
dataType: 'json',
beforeSend: function() {
$('.loading_layer').addClass('active');
},
complete: function() {
},
success: function(data) {
console.log(data.status);
if(data.status == 'OK')
{
console.log(' data :: '+data.status)
console.log(' data :: '+data.status)
console.log(' data :: '+data.status)
console.log(' data :: '+data.status)
console.log(' data :: '+data.status)
console.log(' data :: '+data.status)
fn_insertCampainTmp(newlyAdded)
// 성공 후 처리 로직
}
else
{
alert(data.message);
return false;
// 실패 처리 로직
}
},
error: function(jqXHR, textStatus, errorThrown) {
console.error("AJAX Error:", textStatus, errorThrown);
}
});
}
/**
* @discription 수신자 목록 저장
* @param newlyAdded
*/
function fn_insertCampainTmpJob(newlyAdded){
if (newlyAdded.length < 1) return;
var sendData = {
"totalCount" : newlyAdded.length
}
$.ajax({
type: 'POST',
url: "/web/mjon/msgcampain/insertMjCampainTmpJob.do",
contentType: 'application/json',
data: JSON.stringify(sendData),
dataType: 'json',
beforeSend: function() {
$('.loading_layer').addClass('active');
},
complete: function() {
},
success: function(data) {
console.log(data.msg);
$('#tmpJobId').val(data.data);
fn_insertCampainTmp(newlyAdded)
},
error: function(jqXHR, textStatus, errorThrown) {
console.error("AJAX Error:", textStatus, errorThrown);
}
});
}
/**
* @discription 수신자 목록 저장
* @param newlyAdded
*/
function fn_insertCampainTmp(newlyAdded){
if (newlyAdded.length < 1) return;
var currentTmpJobId = $('#tmpJobId').val();
var sendList = newlyAdded.map(function(row) {
return {
callNm: row.name || "",
callTo: row.phone || "",
tmpJobId: currentTmpJobId
};
});
$.ajax({
type: 'POST',
url: "/web/mjon/msgcampain/insertMyAddrTWCallToAjax_advc.do",
contentType: 'application/json',
data: JSON.stringify(sendList),
dataType: 'json',
beforeSend: function() {
$('.loading_layer').addClass('active');
},
complete: function() {
$('.loading_layer').removeClass('active');
refreshSendCounts();
// fn_udpateCampainJob(data.data, 'C');
},
success: function(data) {
console.log(data.msg);
// fn_udpateCampainJob(currentTmpJobId, 'C');
},
error: function(jqXHR, textStatus, errorThrown) {
console.error("AJAX Error:", textStatus, errorThrown);
}
});
}
// 초기화 버튼
function fnCallToListReset(){
var totalCount = twSmsTable.getData().length;
if(totalCount < 1){
alert("받는사람 목록이 없습니다.");
return false;
}
if(!confirm("기존 받는사람이 모두 초기화되며, 복구할 수 없습니다. 진행하시겠습니까?")){
return false;
}
var sendData = {
"tmpJobId" : $('#tmpJobId').val() ,
"jobStatus" : $('#jobStatus').val()
}
$.ajax({
type: "POST",
url: "/web/mjon/msgcampain/deleteCandidateTWCallToData.do",
contentType: 'application/json',
data: JSON.stringify(sendData),
dataType: 'json',
success: function(data) {
// if(data.status == 'OK')
},
error: function (e) { console.log("ERROR : ", e); },
beforeSend: function() { $('.loading_layer').addClass('active'); },
complete: function() { location.reload() }
});
}
// 발송 event
var imgFilePath = []; // 최종 선택한 이미지 경로 저장 변수
var imgFileId = []; // 최종 선택한 파일 아이디 저장 변수
var templateYn = []; // 템플릿 사용 여부 저장 변수
//이벤트가 아닌 일반 개별 단가 셋팅해주기
function getEventEachPrice(evnMsgType){
var eventEachPrice = 0;
var evnImgCnt = $("#imgCnt").val();
//일반 단가로 변경해주기
if(evnMsgType == '4'){
eventEachPrice = $("#sPrice").val();
console.log("eventEachPrice Short::: "+eventEachPrice);
}else if(evnMsgType == '6'){
if(evnImgCnt == 0){//장문 가격
eventEachPrice = $("#mPrice").val();
console.log("eventEachPrice Long ::: "+eventEachPrice);
}else if(evnImgCnt == 1){
eventEachPrice = $("#pPrice").val();
console.log("eventEachPrice p1 ::: "+eventEachPrice);
}else if(evnImgCnt == 2){
eventEachPrice = $("#p2Price").val();
console.log("eventEachPrice p2 ::: "+eventEachPrice);
}else if(evnImgCnt == 3){
eventEachPrice = $("#p3Price").val();
console.log("eventEachPrice p3 ::: "+eventEachPrice);
}
}
return eventEachPrice;
}
//문자발송 처리 함수
function fn_sendMsgData(e){
console.log("isTrusted :: ", e?.isTrusted);
if (isSendLocked) {
console.warn("발송 처리 중입니다. 중복 요청을 무시합니다.");
return false;
}
const isUserClick = e && e.isTrusted === true;
/* if(e && e.isTrusted){
console.log("마우스 클릭 (사용자 직접)");
}else{
console.log("스크립트/키 이벤트로 실행됨");
}*/
// return false;
// 타블레이터 호출
var $selectedData = twSmsTable.getSelectedData(); // 데이터 가져오기
// console.log('$selectedData : ', $selectedData);
if(!checkConf()){ //문자온 conf-check
alert("현재 문자 발송하기 기능 점검 중입니다.\n\n1분 후 다시 시도해주세요.");
return false;
}
var form = document.msgForm;
var totPriceOnly = stringReplaceAll(form.totPrice.value, ",", "");
var userMoneyOnly = stringReplaceAll(form.myPrice.value, ",", "");
// test 주석
if(parseFloat(userMoneyOnly) < parseFloat(totPriceOnly)){
alert("문자 발송에 필요한 회원님의 보유 잔액이 부족 합니다.");
return false;
}
// console.log(' 11111 : ');
// 폼 유효성 검사
if (!validateForm(form)) return false;
// console.log(' 2222 : ');
// var blineCodeYn = $("#blineCode").val();
// if(blineCodeYn != 'N'){
// if(!blineSendCheck(blineCodeYn)){ //문자온 conf-check
// alert("현재 문자 발송하기 기능 점검 중입니다.\n\n잠시 후 다시 시도해주세요.");
// return false;
// }
// }
if($selectedData.length > 300000){
alert("30만건까지 발송이 가능합니다.\n받는사람 목록을 확인해주세요.");
return false;
}
// 👇 여기만 조건 추가
if(isUserClick){
if(!confirm("문자를 전송하시겠습니까?")){
return false;
}
}
var msgType = conTypeCheck($('#smsTxtArea').val()); //입력 문자 길이 체크
console.log(msgType)
console.log(msgType)
console.log(msgType)
console.log(msgType)
console.log(msgType)
//금액 소수점 제거 하여 적용 20220623 소수점 버림 처리
if(msgType == "P"){//그림문자
//그림 이미지 갯수에 따른 금액 계산
if(imgCnt > 2){//그림 3장일경우
price = $('#p3Price').val();
}else if(imgCnt > 1){//그림 2장일경우
price = $('#p2Price').val();
}else{//그림 1장일 경우
price = $('#pPrice').val();
}
}else if(msgType == "M"){//장문 문자
price = $('#mPrice').val();
}else{//단문문자
price = $('#sPrice').val();
}
// var msgCnt = userMoney / price;
var totPrice = price * $selectedData.length;
// form.totPrice.value = totPrice.replace(",","");
//이벤트 진행중 회원의 경우 이벤트 잔여금액 비교 처리 필요.
//이벤트 캐시가 부족한 경우 이벤트 캐시로 발송 가능한 만큼만 이벤트 금액으로 발송 처리해줌.
//이 후 나머지 발송 건수는 이벤트 캐시가 아닌 일반 단가로 발송 처리를 진행 함.
var eventStatus = form.eventStatus.value;
if(eventStatus == 'Y'){ //이벤트 진행 대상자이면 문자종류에 이벤트로 구분
form.eventYn.value = "Y"; //이벤트문자 종류 설정
}
var eventRemainCash = parseFloat(form.eventRemainCash.value);
console.log('eventStatus : ', eventStatus);
console.log('parseFloat(eventRemainCash) : ', parseFloat(eventRemainCash));
console.log('parseFloat(totPriceOnly) : ', parseFloat(totPrice));
console.log('parseFloat(eventRemainCash) < parseFloat(totPriceOnly) : ', parseFloat(eventRemainCash) < parseFloat(totPriceOnly));
if(eventStatus == 'Y' && parseFloat(eventRemainCash) < parseFloat(totPrice))
{
// 이벤트 금액 부족 상태 요청하신 모두 발송할 수 없습니다
console.log('eventRemainCash : ', eventRemainCash);
if(!confirm("고객님의 이벤트 캐시 잔액(" + eventRemainCash + "원) 부족으로 요청하신 문자("+numberWithCommas($selectedData.length)+"건)를 모두 발송할 수 없습니다. 이벤트 캐시 초과 건에 대해서는 일반 단가를 적용하여 발송하시겠습니까?")){
return false;
}
// 이벤트 캐시 초과 건에 대해서는 일반 단가를 적용하여 발송하시겠습니까
var evnMsgType = $("#msgType").val(); // 문자전송 타입
var norEachPrice = getNorEachPrice(evnMsgType); // 일반전송 금액
var eventEachPrice = getEventEachPrice(evnMsgType); // 이벤트 전송 금액
var eventCount = eventRemainCash/eventEachPrice; // 이벤트금액으로 전송가능한 수량
console.log('eventCount : ', parseInt(eventCount));
var norCount = numberWithCommas($selectedData.length)-parseInt(eventCount); // 일반금액으로 전송수량
console.log('norCount : ', parseInt(norCount));
var norAccount = norCount * norEachPrice; // 일반금액으로 변경한 발송금액
var totAccount = userMoneyOnly - norAccount //
console.log('norAccount : ', norAccount);
console.log('userMoneyOnly : ', userMoneyOnly);
console.log('totAccount : ', totAccount);
if(totAccount < 0){
alert("고객님의 이벤트 캐시 잔액(" + parseInt(totAccount)*-1 + "원) 부족으로 요청하신 문자("+numberWithCommas($selectedData.length)+"건)를 모두 발송할 수 없습니다.");
return false;
}
}
isSendLocked = true;
// console.log(' !!! imgFilePath : ', imgFilePath);
// img 처리 영역
imgFilePath = [];
$('.thumb_wrap').find('.thumb_img').each(function(idx, el) {
if($("#delLi"+idx).hasClass("Template")){
templateYn.push("Y");
} else {
templateYn.push("N");
}
if($(el).hasClass("edit_y")) {
//이미지 변환
const imgBase64 = $(el).attr("src");
const decodImg = atob(imgBase64.split(',')[1]); // base64~ 부분을 제외하고 데이터 디코딩
let array = [];
for (let i = 0; i < decodImg.length; i++) {
array.push(decodImg.charCodeAt(i));
}
const file = new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
const fileName = 'canvas_img_' + new Date().getMilliseconds() + '.jpg';
let formData = new FormData();
formData.append('file', file, fileName);
$.ajax({
type: 'post',
url: '/web/mjon/msgdata/insertEditImageAjax.do',
cache: false,
data: formData,
dataType:'json',
processData: false,
contentType: false,
async: false,
success: function (returnData, status) {
if(status == 'success'){
console.log('returnData : ',returnData)
// imgFilePath 에 배열로 담아주기(이미지 순서대로)
//console.log(imgFilePath);
imgFilePath.push(returnData.filefullPath);
imgFileId.push(returnData.atchFileId);
} else if(status== 'fail'){
alert(returnData.message);
}
},
error: function (e) { alert("이미지 업로드에 실패하였습니다."); console.log("ERROR : ", e); }
});
} else {
if(imgFilePath.length != imgFileId.length){
//에디터 안거친 템플릿 이미지면 바로 src 때림
imgFilePath.push($(el).attr("src"));
}
}
});
form.templateYnAdvc.value = templateYn;
form.imgFilePathAdvc.value = imgFilePath;
form.imgFileIdAdvc.value = imgFileId;
form.callFrom.value = removeDash($('#callFromList').val()); // 발신번호 대쉬(-) 문자 없애주기
//광고 종류 설정
//발송 Ajax 호출해주기
sendMsgAjax_advc();
}
// 기업회원 및 선거후보자 체크
function deptCandidateChk(){
var candidateNm = $.trim($("#candidateNmChk").val());
var dept = $.trim($("#deptChk").val());
// 기업회원이면
if(dept == 'c'){
$('[data-tooltip="alert_layer_popup02"]').trigger('click'); // 기업회원 팝업
}else if(!candidateNm){ // 값이 없으면
$('[data-tooltip="alert_layer_popup"]').trigger('click'); // 후보자 등록 팝업
}
}
function sendMsgAjax_advc(){
// 타블레이터 호출
var $selectedData = twSmsTable.getSelectedData(); // 데이터 가져오기
// 폼 데이터를 배열로 직렬화
var form = $('#msgForm');
var formDataArray = form.serializeArray();
// 배열을 객체로 변환
var formData = {};
$.each(formDataArray, function(index, field) {
formData[field.name] = field.value;
});
// 빈 값 제거
removeEmptyValues(formData);
// 선택된 데이터 추가
formData["mjonMsgSendVOList"] = $selectedData;
// JSON 데이터 확인
console.log("최종 formData:", JSON.stringify(formData));
// var url = "/web/mjon/msgdata/sendMsgDataAjax_advc.do";
// var url = "/web/mjon/msgcampain/sendMsgDataAjax.do";
var url = "/web/mjon/msgcampain/sendMsgDataAjax_advc.do";
// 시작 시간
// 프로그래스파 시간을 위한 계산
var estimtedTime = calculateEstimatedTime($selectedData.length);
$.ajax({
type: "POST",
url: url,
data: JSON.stringify(formData),
contentType: 'application/json',
dataType: 'json',
success: function (data) {
console.log('발송 결과 data : ', data);
console.log('발송 결과 data : ', data);
console.log(' ::data.status:: ');
if (data.status === "OK") {
const resultSts = Number(data.object.resultSts || 0);
const resultBlockSts = Number(data.object.resultBlockSts || 0);
const resultBlockList = data.object.resultBlockList || [];
// 선택된 데이터는 선택 해제 전에 미리 복사
const $selectedData = twSmsTable.getSelectedData();
// 1. 테이블 상태 정확히 업데이트
updateTableAfterSend(resultSts, resultBlockSts, resultBlockList);
// 2. DB 실제 SEND_FLAG 업데이트
updateDbSendResult(resultBlockList, $selectedData);
// 자동 페이지 이동 기능
const isAutoPageMove = $("#autoPageMove").is(":checked");
if (isAutoPageMove) {
// console.log("currentPage :: ", twSmsTable.getPage());
// console.log("pageMax :: ", twSmsTable.getPageMax());
const currentPage = Number(twSmsTable.getPage() || 1);
const pageMax = Number(twSmsTable.getPageMax() || 1);
// 현재 페이지에서 아직 선택 가능한 행(= 체크박스 살아있는 발송전 상태) 조회
const remainSelectableRows = getCurrentPageSelectableRows();
console.log("remainSelectableRows.length :: ", remainSelectableRows.length);
// 현재 페이지에 더 이상 선택 가능한 행이 없을 때만 다음 페이지 이동
if (remainSelectableRows.length === 0 && currentPage < pageMax) {
setTimeout(function() {
twSmsTable.setPage(currentPage + 1);
}, 300);
}
}
}
else if (data.status === "BAD_REQUEST") {
alert(data.message || "잘못된 요청입니다.");
}
else if (data.status === "UNAUTHORIZED") {
alert(data.message);
goMsgUrlMove();
}
else if("FORBIDDEN" == data.status){ // 정지 회원 처리
deptCandidateChk();
return false;
}
else {
alert("발송 처리 중 오류가 발생했습니다.");
}
// 갱신된 금액 이벤트 잔액 불러오기
getBeforeCashData();
},
beforeSend : function(xmlHttpRequest) {
// 프로그래스 바 실행
progressStart(estimtedTime);
},
complete : function(xhr, textStatus) {
// 프로그래스 바 종료
progressComplete();
// ✅ 여기서 잠금을 해제합니다. 서버 응답이 완전히 끝난 후 다음 발송 허용.
isSendLocked = false;
},
error: function (e) { alert("문자 발송에 실패하였습니다."); console.log("ERROR : ", e); }
});
}
// 발송 후 DB SEND_FLAG 업데이트 (20건 기준 단순화)
function updateDbSendResult(resultBlockList, $selectedData) {
console.log(' :: updateDbSendResult :: ')
// Tabulator에서 현재 선택된 행 데이터 가져오기
if ($selectedData.length === 0) return;
const blockSet = new Set(resultBlockList || []);
const failPhones = [];
const successPhones = [];
// 선택된 데이터 순회하면서 성공/실패 분류
$selectedData.forEach(item => {
const phone = String(item.phone || "").replace(/[^0-9]/g, '');
if (blockSet.has(phone)) {
failPhones.push(phone);
} else {
successPhones.push(phone);
}
});
$.ajax({
type: "POST",
url: "/web/mjon/msgcampain/updateSendFlagAfterSend.do",
contentType: 'application/json',
data: JSON.stringify({
successPhones: successPhones,
failPhones: failPhones
}),
dataType: 'json',
success: function(res) {
console.log("DB SEND_FLAG 업데이트 완료", res);
},
error: function(e) {
console.error("DB 업데이트 실패", e);
}
});
}
//폼 유효성 검사 함수
function validateForm(form) {
// 타블레이터 호출
var $selectedData = twSmsTable.getSelectedData(); // 데이터 가져오기
// console.log('$selectedData : ', $selectedData);
if($selectedData.length < 1){
alert("받는사람 내역을 입력해주세요.");
return false;
}
if(form.callFromList.value == ""){
alert("발신번호를 입력해 주세요.");
return false;
}
if (form.subjectChkYn.value === 'N') {
form.mmsSubject.value = "";
} else if (getSpacialStringChk(form.mmsSubject.value)) {
alert("문자 제목에는 치환문자(엑셀 내 *이름*, *1*, *2*, *3*, *4* 등)를 사용하실 수 없습니다.");
return false;
}
//문자제목에 이모지가 있는지 체크
var titleStatusYn = $("input[name='subjectChkYn']:checked").val();
if(titleStatusYn == 'Y') {
if(!emojiCheck(form.mmsSubject.value)) return false;
}
// 문자내용에 이모지가 있는지 체크
var strCont = form.smsTxtArea.value;
if (!emojiCheck(strCont)) return false;
var rtnStr = strChinJpnCheck(strCont);
if(rtnStr.length > 0){
alert("입력하신 문구 중 \" " + rtnStr + " \" 는 일부 휴대폰에서 표기되지 않을 수 있습니다.");
}
if (imgFilePath.length === 0 && !form.smsTxtArea.value) {
alert("문자내용을 입력해 주세요.");
return false;
}
return true;
}
//빈 값이나 null 값을 제거하는 함수
function removeEmptyValues(obj) {
Object.keys(obj).forEach(function(key) {
if (obj[key] === null || obj[key] === '') {
delete obj[key];
}
});
}
// 선택된 데이터의 길이에 따라 예상 시간 계산 함수
function calculateEstimatedTime(selectedCount) {
//기준값
// const processTimePerBatch = 130; // 130초
// 30만건 기준 10분으로 기준을 잡아서
// 시간계산함
const processTimePerBatch = 600;
const batchSize = 300000;
// 1건당 처리 시간
const timePerRecord = processTimePerBatch / batchSize;
// 예상 시간 계산
const estimatedTimeInSeconds = selectedCount * timePerRecord;
return estimatedTimeInSeconds.toFixed(2);
}
/**
* 발송 성공 후 테이블 상태 정확히 업데이트
* resultBlockList를 이용해 실제 성공/실패 구분
*/
function updateTableAfterSend(resultSts, resultBlockSts, resultBlockList) {
const table = window.twSmsTable;
if (!table) return;
// 빠른 조회를 위한 Set (전화번호 기준)
const blockSet = new Set(resultBlockList || []);
table.blockRedraw(); // 성능 최적화 (한 번에 redraw)
try {
const selectedRows = table.getSelectedRows(); // 선택된 행만 처리
selectedRows.forEach(row => {
const data = row.getData();
const phone = String(data.phone || "").replace(/[^0-9]/g, ''); // 대시 제거
console.log("phone :: "+ phone);
// 실제 발송 결과 판단
if (blockSet.has(phone)) {
data.status = "발송제외"; // 또는 "F" (formatter가 처리한다면 F도 OK)
} else {
data.status = "발송완료"; // 또는 "Y"
}
row.update(data); // 행 업데이트
row.deselect(); // 선택 해제
});
} finally {
table.restoreRedraw(); // redraw 복구
}
// 좌측 카운트 갱신
refreshSendCounts();
console.log(`✅ 테이블 업데이트 완료: 성공 ${resultSts}건, 제외 ${resultBlockSts}건`);
}
function refreshSendCounts() {
var table = window.twSmsTable;
if (!table) return;
var allRows = table.getData(); // 전체 데이터 (모든 페이지 포함)
var totalCnt = allRows.length;
var completeCnt = 0; // 발송완료 (Y)
var excludeCnt = 0; // 발송제외 (F)
var remainCnt = 0; // 잔여 (발송전)
var hasSent = false;
allRows.forEach(function(row) {
var status = String(row.status || "").trim();
if (status === "Y" || status === "발송완료") {
completeCnt++;
hasSent = true;
} else if (status === "F" || status === "발송제외") {
excludeCnt++;
hasSent = true;
} else {
remainCnt++;
}
});
// 화면에 표시
$("#totCallToCnt").text(numberWithCommas(totalCnt));
$("#sendCompleteCnt").text(numberWithCommas(completeCnt));
$("#excludeSendCnt").text(numberWithCommas(excludeCnt));
$("#remainCnt").text(numberWithCommas(remainCnt));
// 테이블 redraw (필요 시)
table.redraw(true);
if(hasSent){
$(".callToBtn").prop("disabled", true);
}
/*else{
$(".callToBtn").prop("disabled", false);
}*/
}
function moveToFirstSelectablePage(){
if(!window.twSmsTable){
return;
}
var table = window.twSmsTable;
var rows = table.getRows("active");
var pageSize = table.getPageSize() || 20;
if(!rows || !rows.length){
table.setPage(1);
return;
}
for(var i = 0; i < rows.length; i++){
var rowData = rows[i].getData();
if(isSelectableStatus(rowData.status)){
var targetPage = Math.floor(i / pageSize) + 1;
if((table.getPage() || 1) !== targetPage){
table.setPage(targetPage);
}
return;
}
}
table.setPage(1);
}