488 lines
20 KiB
JavaScript
488 lines
20 KiB
JavaScript
/**
|
|
* 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(`
|
|
<li><img src="/mobile/images/bnft/lucky_award1.svg" alt="1등"></li>
|
|
<li><img src="/mobile/images/bnft/lucky_award2.svg" alt="2등"></li>
|
|
<li><img src="/mobile/images/bnft/lucky_award3.svg" alt="3등"></li>
|
|
`);
|
|
} else {
|
|
// 일반 당첨일 때는 같은 이미지 3개
|
|
let imagePath = `/mobile/images/bnft/lucky_award${rank}.svg`;
|
|
let altText = rank + '등';
|
|
|
|
$('.scrachGift').html(`
|
|
<li><img src="${imagePath}" alt="${altText}"></li>
|
|
<li><img src="${imagePath}" alt="${altText}"></li>
|
|
<li><img src="${imagePath}" alt="${altText}"></li>
|
|
`);
|
|
}
|
|
},
|
|
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 = '축하합니다!<br>행운상 당첨!';
|
|
|
|
// 쿠폰 정보가 있는 경우
|
|
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 = '축하합니다!<br>' + result.rank + '등 당첨!';
|
|
subTitle = result.couponName;
|
|
bottomText = 'MY혜택 > 쿠폰에서 확인하세요.';
|
|
}
|
|
// 마일리지가 있으면 마일리지로 처리
|
|
else if (result.mileageAmount && result.mileageAmount > 0) {
|
|
iconText = '포인트';
|
|
modalTitle = '축하합니다!<br>' + result.rank + '등 당첨!';
|
|
subTitle = '마일리지 ' + result.mileageAmount + '점 적립';
|
|
bottomText = 'MY혜택 > 포인트에서 확인하세요.';
|
|
}
|
|
// bnfRwdCateDvCd 코드를 보고 판단
|
|
else {
|
|
switch (result.bnfRwdCateDvCd) {
|
|
case '03020': // 마일리지
|
|
iconText = '포인트';
|
|
modalTitle = '축하합니다!<br>' + result.rank + '등 당첨!';
|
|
subTitle = result.mileageAmount > 0 ?
|
|
'마일리지 ' + result.mileageAmount + '점 적립' : '마일리지가 적립되었습니다!';
|
|
bottomText = 'MY혜택 > 포인트에서 확인하세요.';
|
|
break;
|
|
case '03010': // 쿠폰
|
|
iconText = '쿠폰';
|
|
modalTitle = '축하합니다!<br>' + result.rank + '등 당첨!';
|
|
subTitle = result.couponName || '할인 쿠폰';
|
|
bottomText = 'MY혜택 > 쿠폰에서 확인하세요.';
|
|
break;
|
|
case '03030': // 상품
|
|
iconText = '선물';
|
|
modalTitle = '축하합니다!<br>' + result.rank + '등 당첨!';
|
|
subTitle = result.couponName || '경품';
|
|
bottomText = 'MY혜택에서 확인하세요.';
|
|
break;
|
|
default:
|
|
// 기본값으로 마일리지 처리
|
|
iconText = '포인트';
|
|
modalTitle = '축하합니다!<br>' + 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; // 그리기 상태 초기화
|
|
});
|
|
}
|
|
|
|
});
|