/**
* Lucklott.js
*
* 행운 복권(스크래치) 기능을 구현한 모듈
* 사용자가 화면을 스크래치하여 당첨 여부를 확인하는 인터랙티브 기능 제공
*
* 주요 기능:
* 1. 스크래치 캔버스 구현 및 관리
* 2. 당첨 결과 확인 및 표시
* 3. 사용자 인터랙션 처리
* 4. 모달 팝업을 통한 결과 안내
*/
$(document).ready(function() {
// 기본 변수 초기화
let canvas = $('.scrachMask')[0]; // 스크래치 마스크 캔버스 요소
let ctx = canvas.getContext('2d'); // 캔버스 컨텍스트
let isDrawing = false; // 그리기 상태 플래그
let totalPixels; // 전체 픽셀 수
let clearedPixels = 0; // 지워진 픽셀 수
let isPopupShown = false; // 팝업 표시 상태
let isPrizeRequested = false; // 당첨 결과 요청 여부 플래그 추가
let prize; // 당첨 결과 저장 변수
let prizeResult = null; // 미리 받아온 당첨 결과
let bnfInnb = $('#bnfInnb').val(); // 혜택 고유 번호
// bnfInnb 값 확인 및 유효성 검사
console.log('bnfInnb value:', bnfInnb);
if (!bnfInnb || bnfInnb === '' || bnfInnb === 'null' || bnfInnb === 'undefined') {
console.error('bnfInnb 값이 올바르지 않습니다:', bnfInnb);
// 에러 모달 표시
$('#modal-1 .microModal__title').html('오류');
$('#modal-1 .modal-icon-present').hide();
$('#modal-1 .sub_tit').html('혜택 정보를 불러올 수 없습니다.');
$('#modal-1 p:last-child').html('페이지를 새로고침 해주세요.');
MicroModal.show('modal-1');
return;
}
// 화면 로딩 시 재고 상태 체크 (추가)
checkStockStatus();
/**
* 화면 로딩시 재고 상태 체크
*/
function checkStockStatus() {
$.ajax({
url: '/sopmal/bnft/checkRemainingGoodsQuantity',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
bnfInnb: bnfInnb
}),
success: function(response) {
console.log('checkStockStatus response:', response);
// 응답 결과 파싱
let result = JSON.parse(response.resBody.result);
// 재고가 없는 경우 처리
if (!result.hasAnyStock && result.totalRewards > 0) {
// 품절 모달 표시
MicroModal.show('modal-sold-out');
return;
}
// 재고가 있는 경우 정상 진행
console.log('재고 상태:', result);
},
error: function() {
console.error('재고 상태 확인 실패');
// 에러 발생 시에도 품절 모달 표시
MicroModal.show('modal-sold-out');
}
});
}
/**
* 캔버스 크기 조정 및 초기화 함수
* 화면 크기에 맞게 캔버스를 조정하고 그라데이션 배경 생성
*/
function resizeCanvas() {
// 캔버스 크기를 컨테이너에 맞게 설정
canvas.width = $('.luckyScrachBox').width();
canvas.height = $('.luckyScrachBox').height();
// 그라데이션 배경 생성
let gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
gradient.addColorStop(0, '#d3d3d3'); // 시작 색상
gradient.addColorStop(0.25, '#e9e9e9'); // 25% 지점 색상
gradient.addColorStop(0.5, '#ddd'); // 50% 지점 색상
gradient.addColorStop(0.75, '#eee'); // 75% 지점 색상
gradient.addColorStop(1, '#ddd'); // 끝 색상
// 그라데이션으로 캔버스 채우기
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// 전체 픽셀 수 계산
totalPixels = canvas.width * canvas.height;
}
/**
* 마우스/터치 위치 계산 함수
* 이벤트 객체에서 캔버스 내 상대 좌표를 계산
* @param {Event} e - 마우스 또는 터치 이벤트 객체
* @return {Object} - x, y 좌표를 포함한 객체
*/
function getOffset(e) {
let offset = $(canvas).offset();
// 마우스 또는 터치 이벤트의 좌표 추출
let x = (e.pageX || e.originalEvent.touches[0].pageX) - offset.left;
let y = (e.pageY || e.originalEvent.touches[0].pageY) - offset.top;
return { x: x, y: y };
}
/**
* 스크래치 진행률 확인 함수
* 캔버스에서 지워진 픽셀의 비율을 계산하고 진행 상태에 따라 처리
*/
function checkClearedPercentage() {
let imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
let pixels = imageData.data;
clearedPixels = 0;
for (let i = 3; i < pixels.length; i += 4) {
if (pixels[i] === 0) {
clearedPixels++;
}
}
let clearedPercentage = (clearedPixels / totalPixels) * 100;
// 80% 이상 지워졌고 팝업이 아직 표시되지 않았다면 실제 참여 처리
if (clearedPercentage > 80 && !isPopupShown && prizeResult) {
isPopupShown = true;
// 실제 참여 처리
confirmParticipation();
}
if (clearedPercentage > 80) {
isDrawing = false;
}
}
/**
* 당첨 결과 확인 함수
* 서버에 API 요청을 보내 당첨 결과를 받아옴
* @return {Promise} - 당첨 결과를 담은 Promise 객체
*/
function determinePrize() {
return new Promise((resolve, reject) => {
$.ajax({
url: '/sopmal/bnft/participateLuckyLottery',
type: 'POST',
data: JSON.stringify({
bnfInnb: bnfInnb
}),
contentType: 'application/json',
success: function(response) {
let result = JSON.parse(response.resBody.result);
if (!result.success) {
reject(new Error(response.message));
return;
}
resolve(result);
},
error: function(error) {
reject(error);
}
});
});
}
/**
* 화면 로딩 시 당첨 결과를 미리 받아와서 이미지 설정 (실제 참여 안함)
*/
function preloadPrizeAndSetImages() {
if (isPrizeRequested) return;
isPrizeRequested = true;
// bnfInnb를 숫자로 변환하여 전송
let bnfInnbNumber = parseInt(bnfInnb);
if (isNaN(bnfInnbNumber)) {
console.error('bnfInnb를 숫자로 변환할 수 없습니다:', bnfInnb);
$('#modal-1 .microModal__title').html('오류');
$('#modal-1 .modal-icon-present').hide();
$('#modal-1 .sub_tit').html('혜택 정보가 올바르지 않습니다.');
$('#modal-1 p:last-child').html('페이지를 새로고침 해주세요.');
MicroModal.show('modal-1');
return;
}
// 미리보기 API 호출 (실제 참여 안함)
$.ajax({
url: '/sopmal/bnft/previewLuckyLotteryResult',
type: 'POST',
data: JSON.stringify({
bnfInnb: bnfInnbNumber // 숫자로 전송
}),
contentType: 'application/json',
success: function(response) {
let result = JSON.parse(response.resBody.result);
if (!result.success) {
// 에러 처리
$('#modal-1 .microModal__title').html('안내');
$('#modal-1 .modal-icon-present').hide();
$('#modal-1 .sub_tit').html(result.message || '참여할 수 없습니다.');
$('#modal-1 p:last-child').html('내일 다시 도전해주세요.');
MicroModal.show('modal-1');
return;
}
// 미리보기 결과 저장
prizeResult = result;
// 당첨 등수에 따른 이미지 설정
let rank = result.rank;
if (rank === 0) {
// 행운상일 때는 기존 이미지 유지 (서로 다른 이미지)
$('.scrachGift').html(`
`);
} else {
// 일반 당첨일 때는 같은 이미지 3개
let imagePath = `/mobile/images/bnft/lucky_award${rank}.svg`;
let altText = rank + '등';
$('.scrachGift').html(`
`);
}
},
error: function(error) {
console.error('Error in preview:', error);
isPrizeRequested = false;
}
});
}
/**
* 당첨 결과 표시 함수
* 당첨 결과에 따라 적절한 모달 팝업을 표시
* @param {string} prize - JSON 형식의 당첨 결과 문자열
*/
function showPrize(prize) {
let result = JSON.parse(prize);
if (result.success) {
let modalTitle, iconText, subTitle, bottomText;
// 행운상 (rank: 0)인 경우 - 응답 데이터에 따라 구분 처리
if (result.rank === 0) {
modalTitle = '축하합니다!
행운상 당첨!';
// 쿠폰 정보가 있는 경우
if (result.couponName && result.couponName.trim() !== '') {
iconText = '쿠폰';
subTitle = result.couponName;
bottomText = 'MY혜택 > 쿠폰에서 확인하세요.';
}
// 마일리지가 있는 경우
else if (result.mileageAmount && result.mileageAmount > 0) {
iconText = '포인트';
subTitle = '마일리지 ' + result.mileageAmount + '점 적립';
bottomText = 'MY혜택 > 포인트에서 확인하세요.';
}
// bnfRwdCateDvCd로 판단
else {
switch (result.bnfRwdCateDvCd) {
case '03010': // 쿠폰
iconText = '쿠폰';
subTitle = result.couponName || '할인 쿠폰';
bottomText = 'MY혜택 > 쿠폰에서 확인하세요.';
break;
case '03020': // 마일리지
iconText = '포인트';
subTitle = result.mileageAmount > 0 ?
'마일리지 ' + result.mileageAmount + '점 적립' : '마일리지 10점 적립';
bottomText = 'MY혜택 > 포인트에서 확인하세요.';
break;
case '03030': // 상품
iconText = '선물';
subTitle = result.couponName || '경품';
bottomText = 'MY혜택에서 확인하세요.';
break;
case '03040': // 쿠폰 (응답의 bnfRwdCateDvCd가 03040인 경우)
iconText = '쿠폰';
subTitle = result.couponName || '할인 쿠폰';
bottomText = 'MY혜택 > 쿠폰에서 확인하세요.';
break;
default:
// 기본값으로 마일리지 처리
iconText = '포인트';
subTitle = '마일리지 10점 적립';
bottomText = 'MY혜택 > 포인트에서 확인하세요.';
break;
}
}
}
// 실제 데이터를 보고 판단 (쿠폰 이름이 있으면 쿠폰으로 처리)
else if (result.couponName && result.couponName.trim() !== '') {
iconText = '쿠폰';
modalTitle = '축하합니다!
' + result.rank + '등 당첨!';
subTitle = result.couponName;
bottomText = 'MY혜택 > 쿠폰에서 확인하세요.';
}
// 마일리지가 있으면 마일리지로 처리
else if (result.mileageAmount && result.mileageAmount > 0) {
iconText = '포인트';
modalTitle = '축하합니다!
' + result.rank + '등 당첨!';
subTitle = '마일리지 ' + result.mileageAmount + '점 적립';
bottomText = 'MY혜택 > 포인트에서 확인하세요.';
}
// bnfRwdCateDvCd 코드를 보고 판단
else {
switch (result.bnfRwdCateDvCd) {
case '03020': // 마일리지
iconText = '포인트';
modalTitle = '축하합니다!
' + result.rank + '등 당첨!';
subTitle = result.mileageAmount > 0 ?
'마일리지 ' + result.mileageAmount + '점 적립' : '마일리지가 적립되었습니다!';
bottomText = 'MY혜택 > 포인트에서 확인하세요.';
break;
case '03010': // 쿠폰
iconText = '쿠폰';
modalTitle = '축하합니다!
' + result.rank + '등 당첨!';
subTitle = result.couponName || '할인 쿠폰';
bottomText = 'MY혜택 > 쿠폰에서 확인하세요.';
break;
case '03030': // 상품
iconText = '선물';
modalTitle = '축하합니다!
' + result.rank + '등 당첨!';
subTitle = result.couponName || '경품';
bottomText = 'MY혜택에서 확인하세요.';
break;
default:
// 기본값으로 마일리지 처리
iconText = '포인트';
modalTitle = '축하합니다!
' + result.rank + '등 당첨!';
subTitle = '마일리지가 적립되었습니다!';
bottomText = 'MY혜택 > 포인트에서 확인하세요.';
break;
}
}
// 모달 내용 설정 및 표시
$('#modal-1 .microModal__title').html(modalTitle);
$('#modal-1 .modal-icon-present').html(iconText);
$('#modal-1 .sub_tit').html(subTitle);
$('#modal-1 p:last-child').html(bottomText);
MicroModal.show('modal-1');
} else {
// 실패 시 기본 모달 표시
MicroModal.show('modal-2');
}
}
/**
* 실제 게임 참여 확정 처리
*/
function confirmParticipation() {
let bnfInnbNumber = parseInt(bnfInnb);
if (isNaN(bnfInnbNumber)) {
console.error('bnfInnb를 숫자로 변환할 수 없습니다:', bnfInnb);
return;
}
$.ajax({
url: '/sopmal/bnft/confirmLuckyLotteryParticipation',
type: 'POST',
data: JSON.stringify({
bnfInnb: bnfInnbNumber, // 숫자로 전송
previewResult: prizeResult
}),
contentType: 'application/json',
success: function(response) {
let result = JSON.parse(response.resBody.result);
if (result.success) {
// 실제 참여 완료 후 결과 표시
showPrize(JSON.stringify(result));
} else {
// 실패 처리
$('#modal-1 .microModal__title').html('안내');
$('#modal-1 .modal-icon-present').hide();
$('#modal-1 .sub_tit').html(result.message || '참여 처리 중 오류가 발생했습니다.');
$('#modal-1 p:last-child').html('다시 시도해주세요.');
MicroModal.show('modal-1');
}
},
error: function(error) {
console.error('Error confirming participation:', error);
// 에러 처리
$('#modal-1 .microModal__title').html('오류');
$('#modal-1 .modal-icon-present').hide();
$('#modal-1 .sub_tit').html('참여 처리 중 오류가 발생했습니다.');
$('#modal-1 p:last-child').html('다시 시도해주세요.');
MicroModal.show('modal-1');
}
});
}
// 윈도우 크기 변경 시 캔버스 크기 조정
$(window).resize(resizeCanvas);
// 초기 캔버스 설정
resizeCanvas();
// 화면 로딩 시 당첨 결과 미리 받아오기
preloadPrizeAndSetImages();
// 품절 모달의 메인 이동 버튼 이벤트 설정
$('#btn-go-main').on('click', function() {
window.location.href = '/sopmal/bnft/bnftMain';
});
/**
* 모달 닫기 버튼 클릭 이벤트 핸들러
* 모달을 닫고 캔버스를 초기화
*/
$('.microModal__btnContainer').click(function() {
MicroModal.close(); // 모달 닫기
isPopupShown = false; // 팝업 상태 초기화
resizeCanvas(); // 캔버스 초기화
isDrawing = false; // 그리기 상태 초기화
});
/**
* 마우스/터치 시작 이벤트 핸들러
* 스크래치 시작 시 그리기 상태 설정
*/
$(canvas).on('mousedown touchstart', function(e) {
// 이미 그리는 중이거나 80% 이상 지워진 경우 무시
if (isDrawing || clearedPixels / totalPixels * 100 > 80) return;
isDrawing = true;
});
/**
* 마우스/터치 이동 이벤트 핸들러
* 스크래치 효과를 구현하고 진행률 확인
*/
$(canvas).on('mousemove touchmove', function(e) {
if (!isDrawing) return;
e.preventDefault();
// 현재 마우스/터치 위치 계산
let pos = getOffset(e);
// 지우기 모드로 설정 (스크래치 효과)
ctx.globalCompositeOperation = 'destination-out';
ctx.beginPath();
// 원형 브러시로 지우기
ctx.arc(pos.x, pos.y, 20, 0, Math.PI * 2, false);
ctx.fill();
// 스크래치 진행률 확인
checkClearedPercentage();
});
/**
* 마우스/터치 종료 이벤트 핸들러
* 그리기 상태 플래그 리셋
*/
$(canvas).on('mouseup touchend', function() {
isDrawing = false;
});
/**
* 모달 닫기 버튼 클릭 이벤트 핸들러
* 모달을 닫고 캔버스를 초기화 (품절 상황이 아닐 때만)
*/
// 기존의 전역 이벤트 핸들러는 제거하고, 필요시에만 등록하도록 변경
function setupNormalModalHandler() {
$('.microModal__btnContainer').off('click').on('click', function() {
MicroModal.close(); // 모달 닫기
isPopupShown = false; // 팝업 상태 초기화
resizeCanvas(); // 캔버스 초기화
isDrawing = false; // 그리기 상태 초기화
});
}
});