merge master into develop - CscListRForm.jsp FAQ 아코디언 버그 수정
This commit is contained in:
487
build/resources/main/static/mobile/js/bnft/lucklott/Lucklott.js
Normal file
487
build/resources/main/static/mobile/js/bnft/lucklott/Lucklott.js
Normal file
@@ -0,0 +1,487 @@
|
||||
/**
|
||||
* 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; // 그리기 상태 초기화
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
Reference in New Issue
Block a user