/** * 만보기 기능 관련 JavaScript */ $(document).ready(function() { // 헤더 뒤로가기 버튼 이벤트 설정 (이벤트 위임 방식) $(document).on('click', '.header__toBack__btn', function(e) { e.preventDefault(); // 기본 동작 방지 location.href = '/sopmal/bnft/bnftMain'; }); // 동의 상태 확인 (가장 먼저) if (!checkUserConsent()) { return; // 동의하지 않은 경우 여기서 중단 } // 다른 UI 초기화 (앱 인터페이스와 무관한 작업) initStepCountChart(); // 깜짝선물과 마일리지 버튼 초기화 initRewardButtons(); // 스탬프 초기화 initStamps(); // 달력 초기화 initCalendar(); // 앱 인터페이스 초기화 확인 및 걸음 수 데이터 요청 initAppInterface(); }); /** * 사용자 동의 상태 확인 */ function checkUserConsent() { const useAt = $('#useAt').val(); // 값이 없거나 'N'인 경우 동의하지 않은 것으로 처리 if (!useAt || useAt === 'N') { // 동의하지 않은 경우 showConsentModal(); disableAllFeatures(); return false; } return true; } /** * 동의 안내 모달 표시 */ function showConsentModal() { MicroModal.show('modal-consent'); } /** * 모든 기능 비활성화 */ function disableAllFeatures() { // 차트 영역 흐리게 처리 $('.stepChart').css({ 'filter': 'blur(3px)', 'pointer-events': 'none', 'opacity': '0.5' }); // 스탬프 영역 흐리게 처리 $('.stepStamp').css({ 'filter': 'blur(3px)', 'pointer-events': 'none', 'opacity': '0.5' }); // 달력 영역 흐리게 처리 $('.stepCalendar').css({ 'filter': 'blur(3px)', 'pointer-events': 'none', 'opacity': '0.5' }); // 모든 버튼 비활성화 $('#giftButton, #mileageButton').prop('disabled', true); // 앱 인터페이스 기능 비활성화 플래그 설정 window.consentRequired = true; } /** * 앱 인터페이스 초기화 확인 및 걸음 수 데이터 요청 */ function initAppInterface() { // 동의가 필요한 경우 앱 인터페이스 초기화 건너뛰기 if (window.consentRequired) { console.log("사용자 동의가 필요하여 앱 인터페이스 초기화를 건너뜁니다."); return; } // 전역 콜백 함수 정의 window.callback_get_walk_count = callback_get_walk_count; // 앱 인터페이스 초기화 확인 if (window.app) { console.log("앱 인터페이스 감지됨, 걸음 수 데이터 요청"); getWalkCountFromApp(); } else { console.log("앱 인터페이스를 기다리는 중..."); let checkCount = 0; const maxChecks = 10; // 최대 5초(500ms * 10)까지 시도 const checkInterval = setInterval(function() { checkCount++; if (window.app) { clearInterval(checkInterval); console.log("앱 인터페이스 초기화 완료, 걸음 수 데이터 요청"); getWalkCountFromApp(); } else if (checkCount >= maxChecks) { clearInterval(checkInterval); console.warn("앱 인터페이스를 찾을 수 없습니다. 최대 시도 횟수 초과."); } }, 500); } } /** * 앱에서 걸음 수 데이터 가져오기 */ function getWalkCountFromApp() { // 날짜 형식 변환 함수 function formatDate(date) { const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); return year + month + day; } // 오늘 날짜 구하기 const today = new Date(); // 현재 월의 첫 날 구하기 const firstDay = new Date(today.getFullYear(), today.getMonth(), 1); // 날짜 형식 변환 const startDate = formatDate(firstDay); const endDate = formatDate(today); // 앱에서 걸음 수 데이터 가져오기 try { window.app.get_walk_count(startDate, endDate); console.log("걸음 수 데이터 요청 성공"); } catch(e) { console.error("걸음 수 데이터 요청 중 오류:", e); showCustomAlert("걸음 수 데이터를 요청하는 중 오류가 발생했습니다."); } } /** * 걸음 수 데이터 콜백 함수 - 앱에서 호출됨 */ function callback_get_walk_count(json_str) { try { console.log("걸음 수 데이터 수신 성공"); const walkData = JSON.parse(json_str); // 콘솔에 데이터 출력 (디버깅용) for(var i = 0; i < walkData.length; i++) { var date = walkData[i].date; var count = walkData[i].count; console.log(date + " | " + count); } // 데이터 저장 및 처리 saveWalkCountData(walkData); } catch(e) { console.error("걸음 수 데이터 처리 실패:", e); showCustomAlert("걸음 수 데이터를 처리하는 중 오류가 발생했습니다."); } } /** * 걸음 수 데이터 저장 및 처리 */ function saveWalkCountData(walkData) { if (!walkData || walkData.length === 0) return; // 오늘 날짜 구하기 const today = new Date(); const todayFormatted = formatDateYYYYMMDD(today); // 오늘의 걸음 수 찾기 const todayData = walkData.find(item => item.date === todayFormatted); if (todayData) { const stepCount = parseInt(todayData.count); // AJAX로 걸음 수 데이터 서버에 저장 $.ajax({ url: '/sopmal/bnft/saveStepCount', type: 'POST', contentType: 'application/json', data: JSON.stringify({ stepCnt: stepCount, bnfInnb: $('#bnfInnb').val() }), success: function(response) { console.log("걸음 수 저장 성공:", response); // 걸음 수 정보 업데이트 updateStepCountInfo(stepCount); // 만보 달성 시 스탬프 정보 업데이트 if (stepCount >= 10000) { updateStampInfo(); } // 데이터 업데이트 후 화면 새로고침 if (response && response.resBody && response.resBody.result) { const resultObj = JSON.parse(response.resBody.result); if (resultObj && resultObj.result === true) { // location.reload(); } } }, error: function(xhr, status, error) { console.error("걸음 수 저장 실패:", error); } }); } // 모든 걸음 수 데이터 저장 (필요하면 활성화) /* walkData.forEach(function(item) { const date = item.date; const count = parseInt(item.count); // AJAX로 각 날짜의 걸음 수 데이터 저장 $.ajax({ url: '/sopmal/bnft/saveStepCountByDate', type: 'POST', contentType: 'application/json', data: JSON.stringify({ stepCnt: count, bnfInnb: $('#bnfInnb').val(), bnfPrtDt: formatDateForServer(date) }), success: function(response) { console.log(date + " 걸음 수 저장 성공:", response); }, error: function(xhr, status, error) { console.error(date + " 걸음 수 저장 실패:", error); } }); }); */ } /** * YYYYMMDD 형식의 문자열을 서버용 날짜 형식으로 변환 */ function formatDateForServer(dateStr) { const year = dateStr.substring(0, 4); const month = dateStr.substring(4, 6); const day = dateStr.substring(6, 8); return year + '-' + month + '-' + day; } /** * 날짜를 YYYYMMDD 형식의 문자열로 변환 */ function formatDateYYYYMMDD(date) { const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); return year + month + day; } /** * 걸음 수 정보 업데이트 */ function updateStepCountInfo(stepCount) { // hidden input 값 업데이트 (추가) $('#currentStepCount').val(stepCount); // 걸음 수 표시 업데이트 $('.cnt_step b').text(stepCount.toLocaleString()); // 거리와 칼로리 계산 const distance = calculateDistance(stepCount); const calories = calculateCalories(stepCount); // 거리와 칼로리 표시 업데이트 $('.cnt_km b').text(distance.toLocaleString(undefined, {minimumFractionDigits: 2, maximumFractionDigits: 2})); $('.cnt_kcal b').text(calories.toLocaleString(undefined, {minimumFractionDigits: 1, maximumFractionDigits: 1})); // 진행률 계산 및 그래프 업데이트 const progressRate = Math.min(100, (stepCount * 100) / 10000); updateStepCountChart(progressRate); // 메시지 업데이트 const message = stepCount >= 10000 ? "와우, 오늘 만보 달성!!" : "조금 더 걸어볼까요?"; $('.tit3').text(message); // 깜짝선물과 마일리지 버튼 상태 업데이트 updateRewardButtons(stepCount); } /** * 알림용 모달 표시 함수 * @param {string} message - 표시할 메시지 * @param {boolean} isHTML - HTML 형식 메시지 여부 */ function showCustomAlert(message, isHTML) { if (isHTML) { $('#modal-alert .microModal__content').html(message); } else { $('#modal-alert .microModal__content p').text(message); } MicroModal.show('modal-alert'); } /** * 걸음 수를 거리(km)로 변환 */ function calculateDistance(steps) { // 1km당 평균 걸음 수 (일반 성인 기준) const STEPS_PER_KM = 1300; return Math.round((steps / STEPS_PER_KM) * 100) / 100; } /** * 걸음 수를 소모 칼로리(kcal)로 변환 */ function calculateCalories(steps) { // 1 걸음당 평균 소모 칼로리 (일반 성인 기준) const CALORIES_PER_STEP = 0.04; return Math.round(steps * CALORIES_PER_STEP * 10) / 10; } /** * 만보기 그래프 초기화 */ function initStepCountChart() { const progressRate = parseFloat($('#progressRate').val() || 0); const ctx = document.getElementById('myChart').getContext('2d'); window.stepChart = new Chart(ctx, { type: 'doughnut', data: { labels: ['완료', '미완료'], datasets: [{ data: [progressRate, 100 - progressRate], backgroundColor: ['#4CAF50', '#f0f0f0'] }] }, options: { cutoutPercentage: 70, animation: { animateRotate: true, animateScale: true }, legend: { display: false }, tooltips: { enabled: false } } }); // 그래프 중앙에 진행률 표시 (이미 HTML에 존재하므로 값만 업데이트) $('#progressRateValue').text(Math.round(progressRate)); } /** * 만보기 그래프 업데이트 */ function updateStepCountChart(progressRate) { if (window.stepChart) { window.stepChart.data.datasets[0].data = [progressRate, 100 - progressRate]; window.stepChart.update(); $('#progressRateValue').text(Math.round(progressRate)); } } /** * 깜짝선물과 마일리지 버튼 초기화 */ function initRewardButtons() { const currentSteps = parseInt($('#currentStepCount').val() || 0); const giftPosition = parseInt($('#todayGiftCondition').val() || 0); const giftReceived = $('#giftReceived').val() === 'Y'; const mileageReceived = $('#mileageReceived').val() === 'Y'; console.log('초기화 상태:', { currentSteps, giftPosition, giftReceived, mileageReceived }); // 다음 목표 계산 const nextTarget = calculateNextTarget(currentSteps); // 깜짝선물 버튼 초기화 if (giftReceived) { // 이미 받은 경우 $('#giftText').hide(); $('#giftButton') .show() .prop('disabled', true) .text('수령완료') .removeClass('btn Att-check') .addClass('btn-disabled') .off('click'); // 이벤트 제거 } else if (currentSteps >= giftPosition) { // 조건 충족하고 아직 안받은 경우 $('#giftText').hide(); $('#giftButton') .show() .prop('disabled', false) .addClass('btn Att-check') .html('선물받기') .css({ 'padding': '10px', 'font-size': '14px', 'height': '36px', 'white-space': 'nowrap' }) .off('click') // 기존 이벤트 제거 .on('click', receiveGift); // 새 이벤트 추가 } else { // 조건 미충족 $('#giftText') .show() .text((giftPosition - currentSteps).toLocaleString() + ' 걸음'); $('#giftButton').hide(); } // 마일리지 버튼 초기화 if (mileageReceived) { // 이미 받은 경우 $('#mileageText').hide(); $('#mileageButton') .show() .prop('disabled', true) .text('수령완료') .removeClass('btn Att-check') .addClass('btn-disabled') .off('click'); // 이벤트 제거 } else if (currentSteps >= nextTarget.targetStep) { // 조건 충족하고 아직 안받은 경우 $('#mileageText').hide(); $('#mileageButton') .show() .prop('disabled', false) .addClass('btn Att-check') .html('마일리지받기') .css({ 'padding': '10px', 'font-size': '14px', 'height': '36px', 'white-space': 'nowrap' }) .off('click') // 기존 이벤트 제거 .on('click', function() { receiveMileage(); // rewardCode는 함수 내부에서 계산 }); } else { // 조건 미충족 $('#mileageText') .show() .text(nextTarget.remainingSteps.toLocaleString() + ' 걸음'); $('#mileageButton').hide(); } } /** * 깜짝선물과 마일리지 버튼 상태 업데이트 */ function updateRewardButtons(stepCount) { const giftPosition = parseInt($('#todayGiftCondition').val() || 0); const achievementCount = parseInt($('#achievementCount').val() || 0); const monthlyRewardReceived = $('#monthlyRewardReceived').val() === 'Y'; const giftReceived = $('#giftReceived').val() === 'Y'; const mileageReceived = $('#mileageReceived').val() === 'Y'; // 다음 목표 계산 const nextTarget = calculateNextTarget(stepCount); // 깜짝선물 버튼 업데이트 (return 제거) if (giftReceived) { // 이미 받은 경우 - 상태 유지 (return 대신 아무것도 안함) } else if (stepCount >= giftPosition) { $('#giftText').hide(); $('#giftButton') .show() .prop('disabled', false) .addClass('btn Att-check') .html('선물받기') .css({ 'padding': '10px', 'font-size': '14px', 'height': '36px', 'white-space': 'nowrap' }) .off('click') .on('click', receiveGift); } else { $('#giftText') .show() .text((giftPosition - stepCount).toLocaleString() + ' 걸음'); $('#giftButton').hide(); } // 마일리지 버튼 업데이트 - 일일 만보 달성 시 (return 제거) if (mileageReceived) { // 이미 받은 경우 - 상태 유지 (return 대신 아무것도 안함) } else if (stepCount >= nextTarget.targetStep && nextTarget.rewardCode === '02010') { $('#mileageText').hide(); $('#mileageButton') .show() .prop('disabled', false) .addClass('btn Att-check') .html('마일리지받기') .css({ 'padding': '10px', 'font-size': '14px', 'height': '36px', 'white-space': 'nowrap' }) .off('click') .on('click', function() { receiveMileage('02010'); // 일일 만보 달성 코드 }); } else if (nextTarget.rewardCode !== '02020') { $('#mileageText') .show() .text(nextTarget.remainingSteps.toLocaleString() + ' 걸음'); $('#mileageButton').hide(); } // 월 누적 10회 달성 마일리지 버튼 업데이트 if (achievementCount >= 10 && !monthlyRewardReceived) { $('#monthlyMileageButton') .show() .off('click') .on('click', function() { receiveMileage('02020'); // 월누적 10회 달성 코드 전달 }) .addClass('btn Att-check') .html('월 10회 달성 보상받기'); } else { $('#monthlyMileageButton').hide(); } } /** * 다음 목표 단계와 남은 걸음 수 계산 */ function calculateNextTarget(currentSteps) { const result = {}; const achievementCount = parseInt($('#achievementCount').val() || 0); // 만보 10회 달성 체크 if (achievementCount >= 10) { // 이미 수령했는지 확인 const monthlyRewardReceived = $('#monthlyRewardReceived').val() === 'Y'; if (!monthlyRewardReceived) { result.targetStep = 10000; result.remainingSteps = 0; result.achieved = true; result.rewardCode = '02020'; // 월누적 10회 달성 코드 return result; } } // 일일 만보 목표 처리 if (currentSteps < 10000) { result.targetStep = 10000; result.remainingSteps = 10000 - currentSteps; result.rewardCode = '02010'; // 일일 만보 달성 코드 } else { result.targetStep = 10000; result.remainingSteps = 0; result.achieved = true; result.rewardCode = '02010'; // 일일 만보 달성 코드 } return result; } /** * 스탬프 초기화 */ function initStamps() { const achievementCount = parseInt($('#achievementCount').val() || 0); const stampList = $('#stampList'); // 이미 스탬프가 있다면 초기화 건너뛰기 if (stampList.children().length > 0) return; stampList.empty(); for (let i = 1; i <= 10; i++) { if (i <= achievementCount) { stampList.append('
축하합니다!
'; // 선물 타입에 따른 메시지 생성 if (rewardInfo.mileageAmount && rewardInfo.mileageAmount > 0) { rewardMessage += `마일리지 ${rewardInfo.mileageAmount.toLocaleString()}원이 지급되었습니다.
`; } if (rewardInfo.couponNo) { rewardMessage += `쿠폰이 발급되었습니다.
`; } // 보상 카테고리에 따른 추가 정보 표시 가능 switch(rewardInfo.rewardCategoryCode) { case '02032': rewardMessage += `깜짝선물 달성 보상입니다.
`; break; // 다른 카테고리에 대한 처리 추가 가능 } // 커스텀 모달로 선물 정보 표시 showCustomAlert(rewardMessage, true); } else { showCustomAlert('깜짝선물을 받았습니다!'); } // 깜짝선물 수령 상태 업데이트 $('#giftReceived').val('Y'); // 깜짝선물 받기 버튼을 수령완료로 변경 $('#giftText').hide(); $('#giftButton') .show() .prop('disabled', true) .text('수령완료') .removeClass('btn Att-check') .addClass('btn-disabled') .off('click'); // 깜짝선물 획득 횟수 화면 업데이트 if (resultObj.surpriseGiftCount !== undefined) { updateSurpriseGiftCount(resultObj.surpriseGiftCount); } } else { showCustomAlert(resultObj.message || '선물 받기에 실패했습니다.'); } } catch (e) { console.error('응답 파싱 오류:', e); showCustomAlert('응답 처리 중 오류가 발생했습니다.'); } } else { showCustomAlert('유효하지 않은 응답 형식입니다.'); } }, error: function() { showCustomAlert('서버 오류가 발생했습니다.'); } }); } /** * 깜짝선물 획득 횟수 화면 업데이트 */ function updateSurpriseGiftCount(surpriseGiftCount) { // ID를 사용하여 더 정확하게 요소 선택 $('#surpriseGiftCountDisplay').text(surpriseGiftCount.toLocaleString()); console.log('깜짝선물 획득 횟수가 ' + surpriseGiftCount + '회로 업데이트되었습니다.'); } /** * 마일리지 받기 */ function receiveMileage(rewardCode) { const currentSteps = parseInt($('#currentStepCount').val() || 0); const nextTarget = calculateNextTarget(currentSteps); // rewardCode가 없으면 nextTarget에서 가져옴 if (!rewardCode) { rewardCode = nextTarget.rewardCode; } $.ajax({ url: '/sopmal/bnft/receiveMileage', type: 'POST', contentType: 'application/json', data: JSON.stringify({ bnfInnb: $('#bnfInnb').val(), bnfRwdCateDvCd: rewardCode }), success: function(response) { // 응답 구조에 맞게 파싱 if (response && response.resBody && response.resBody.result) { try { const resultObj = JSON.parse(response.resBody.result); if (resultObj && resultObj.success) { if (rewardCode === '02020') { showCustomAlert('월 10회 달성 보상을 받았습니다!'); $('#monthlyMileageButton').prop('disabled', true).text('수령완료'); $('#monthlyRewardReceived').val('Y'); } else { showCustomAlert('마일리지를 받았습니다!'); $('#mileageButton').prop('disabled', true).text('수령완료'); } } else { showCustomAlert(resultObj.message || '마일리지 받기에 실패했습니다.'); } } catch (e) { console.error('응답 파싱 오류:', e); showCustomAlert('응답 처리 중 오류가 발생했습니다.'); } } else { showCustomAlert('유효하지 않은 응답 형식입니다.'); } }, error: function() { showCustomAlert('서버 오류가 발생했습니다.'); } }); } /** * 로컬 테스트용 만보기 데이터 모킹 기능 */ function setupTestEnvironment() { // 앱 인터페이스 모킹 window.app = { get_walk_count: function(startDate, endDate) { console.log("모의 걸음수 데이터 요청: " + startDate + " ~ " + endDate); // 현재 월의 테스트 데이터 생성 const testData = generateTestData(startDate, endDate); // 비동기 실행으로 실제 앱 동작 흉내 setTimeout(function() { callback_get_walk_count(JSON.stringify(testData)); }, 500); } }; console.log("테스트 환경이 설정되었습니다."); } /** * 테스트용 걸음수 데이터 생성 */ function generateTestData(startDate, endDate) { const result = []; const start = parseDate(startDate); const end = parseDate(endDate); // 각 날짜별 데이터 생성 for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) { const date = formatDateYYYYMMDD(d); // 오늘 날짜인 경우 더 많은 걸음수 설정 (테스트용) const isToday = date === formatDateYYYYMMDD(new Date()); // 다양한 테스트 케이스 (1,000 ~ 12,000 걸음) let count; if (isToday) { // 오늘은 목표 달성 가능한 단계별 테스트를 위해 조정 // 예: 2400, 4900, 9900 또는 10000 이상 const testCase = Math.floor(Math.random() * 4); switch(testCase) { case 0: count = 2400; break; // 2500 미만 case 1: count = 4900; break; // 5000 미만 case 2: count = 9900; break; // 10000 미만 case 3: count = 11000; break; // 10000 이상 } } else { // 이전 날짜들은 다양한 걸음수 (성공/실패 케이스 혼합) count = Math.floor(Math.random() * 12000) + 1000; } result.push({ date: date, count: count.toString() }); } return result; } /** * YYYYMMDD 문자열을 Date 객체로 파싱 */ function parseDate(dateStr) { const year = parseInt(dateStr.substring(0, 4)); const month = parseInt(dateStr.substring(4, 6)) - 1; const day = parseInt(dateStr.substring(6, 8)); return new Date(year, month, day); } // 콘솔에서 수동으로 특정 걸음수 설정하는 함수 function setTodaySteps(steps) { const today = formatDateYYYYMMDD(new Date()); const testData = [{ date: today, count: steps.toString() }]; callback_get_walk_count(JSON.stringify(testData)); console.log(steps + "걸음으로 설정되었습니다."); } /** * 스탬프 정보 업데이트 */ function updateStampInfo() { // 서버에서 최신 달성 횟수 조회 $.ajax({ url: '/sopmal/bnft/getMonthlySuccessCount', type: 'POST', contentType: 'application/json', data: JSON.stringify({ bnfInnb: $('#bnfInnb').val() }), success: function(response) { if (response && response.resBody && response.resBody.result) { const resultObj = JSON.parse(response.resBody.result); if (resultObj && resultObj.achievementCount !== undefined) { const achievementCount = resultObj.achievementCount; // hidden input 값 업데이트 $('#achievementCount').val(achievementCount); // 스탬프 UI 업데이트 const stampList = $('#stampList'); stampList.empty(); for (let i = 1; i <= 10; i++) { if (i <= achievementCount) { stampList.append('