|
@@ -1,700 +0,0 @@
|
|
|
-<template>
|
|
|
|
|
- <div class="roulette--container--wrappers">
|
|
|
|
|
- <div class="roulette--wrapper">
|
|
|
|
|
- <div class="title">
|
|
|
|
|
- <div>미리 포인트로 즐기는 행운의 찬스!</div>
|
|
|
|
|
- <div class="main-title"><span>룰렛</span><span>을 돌려라!</span></div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="roulette-container-wrap">
|
|
|
|
|
- <div class="roulette-container">
|
|
|
|
|
- <div class="pointer"></div>
|
|
|
|
|
- <div ref="wheelRef" class="wheel"></div>
|
|
|
|
|
- <div ref="textLayerRef" class="text-layer"></div>
|
|
|
|
|
-
|
|
|
|
|
- <button
|
|
|
|
|
- id="agreeButton"
|
|
|
|
|
- type="button"
|
|
|
|
|
- class="center-button"
|
|
|
|
|
- @click="activeLayer(1)"
|
|
|
|
|
- ></button>
|
|
|
|
|
-
|
|
|
|
|
- <!-- <button
|
|
|
|
|
- id="spinButton"
|
|
|
|
|
- type="button"
|
|
|
|
|
- class="center-button"
|
|
|
|
|
- @click="trySpinRoulette"
|
|
|
|
|
- ></button> -->
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="bottom-text">100% 당첨! 룰렛 돌리기</div>
|
|
|
|
|
- <div class="sub-text">미리톡에서 추후 시 500P 사용하면 보너 2개!</div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="buttons">
|
|
|
|
|
- <button type="button" class="button secondary">응모권 확인하기</button>
|
|
|
|
|
- <button type="button" class="button primary">나의 포인트 전환</button>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="probability-display">
|
|
|
|
|
- <div>당첨 확률: <span id="probabilityDisplay">0.2</span>%</div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <!-- 레이어 입력 폼 -->
|
|
|
|
|
- <div
|
|
|
|
|
- id="randomBoxAuth-layer01"
|
|
|
|
|
- class="layer-popup bottom-sheet-wrap event"
|
|
|
|
|
- role="dialog"
|
|
|
|
|
- aria-hidden="false"
|
|
|
|
|
- tabindex="0"
|
|
|
|
|
- style="z-index: 101"
|
|
|
|
|
- :class="{ show: activeLayer1 }"
|
|
|
|
|
- >
|
|
|
|
|
- <div class="layer-popup-item evt-reservation jan-roulette-pop">
|
|
|
|
|
- <div class="popup-header">
|
|
|
|
|
- <strong class="txt-main">룰렛 이벤트 신청</strong>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="popup-body">
|
|
|
|
|
- <div class="page-desc">
|
|
|
|
|
- <h2>
|
|
|
|
|
- 이벤트 신청을 위해서 본인 인증이 필요합니다.<br />본인 인증을 진행해 주세요.
|
|
|
|
|
- </h2>
|
|
|
|
|
- <!-- <p>이벤트 기간 내 가입한 010 신규가입자도 룰렛 이벤트에 참여 가능합니다.</p>-->
|
|
|
|
|
- </div>
|
|
|
|
|
- <!-- <div class="box-btn">-->
|
|
|
|
|
- <!-- <button class="btns md-ripples ripples-light gtm-tracking" type="button" data-gtm-tracking-category="랜덤박스 팝업_PC" data-gtm-tracking-action="본인인증 시도_PC" data-gtm-tracking-label="인증하기 버튼" id="randomBoxAuthBtn">본인 인증 하기</button>-->
|
|
|
|
|
- <!-- <button id="randomBoxChkBtn" class="btns md-ripples ripples-light" type="button" disabled="" style="display: none;">인증 완료</button>-->
|
|
|
|
|
- <!-- </div>-->
|
|
|
|
|
- <div class="phone-certification mt45">
|
|
|
|
|
- <h2>신청자 정보</h2>
|
|
|
|
|
- <div class="box-input mt--45">
|
|
|
|
|
- <label for="userName" class="input-label">이름</label>
|
|
|
|
|
- <div class="input-wrap">
|
|
|
|
|
- <input
|
|
|
|
|
- id="userName"
|
|
|
|
|
- type="text"
|
|
|
|
|
- placeholder="이름을 입력해주세요."
|
|
|
|
|
- class="input-default is-delete"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="box-input mt45">
|
|
|
|
|
- <label for="userPhone" class="input-label">휴대폰 번호</label>
|
|
|
|
|
- <div class="input-wrap">
|
|
|
|
|
- <input
|
|
|
|
|
- id="userPhone"
|
|
|
|
|
- type="text"
|
|
|
|
|
- placeholder="휴대폰 번호를 입력해주세요."
|
|
|
|
|
- class="input-default is-delete"
|
|
|
|
|
- />
|
|
|
|
|
- </div>
|
|
|
|
|
- <input id="randomBoxInput3" type="hidden" disabled="" value="" />
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div class="rq-form">
|
|
|
|
|
- <div class="agree-wrap">
|
|
|
|
|
- <!-- 전체 동의 -->
|
|
|
|
|
- <div class="btn-box btn-check btn-text-line">
|
|
|
|
|
- <input
|
|
|
|
|
- type="checkbox"
|
|
|
|
|
- id="agreeAll"
|
|
|
|
|
- v-model="agreeAll"
|
|
|
|
|
- @change="onAgreeAllChange"
|
|
|
|
|
- />
|
|
|
|
|
- <label for="agreeAll">
|
|
|
|
|
- <span class="ico-check"></span>전체 동의 (필수)
|
|
|
|
|
- </label>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="agree-group">
|
|
|
|
|
- <div class="btn-box btn-check">
|
|
|
|
|
- <input
|
|
|
|
|
- type="checkbox"
|
|
|
|
|
- class="agreeReq"
|
|
|
|
|
- id="randomBoxAgree1"
|
|
|
|
|
- v-model="agree1"
|
|
|
|
|
- @change="onAgreeChange"
|
|
|
|
|
- />
|
|
|
|
|
- <label for="randomBoxAgree1">
|
|
|
|
|
- <span class="ico-check"></span>이벤트 참여 및 전화 상담을 위한
|
|
|
|
|
- 개인정보 수집 및 이용 동의 (필수)
|
|
|
|
|
- </label>
|
|
|
|
|
- <a @click="activeLayer(2)" class="ico-arrow-right agreeActions"
|
|
|
|
|
- >더보기</a
|
|
|
|
|
- >
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="btn-box btn-check">
|
|
|
|
|
- <input
|
|
|
|
|
- type="checkbox"
|
|
|
|
|
- class="agreeReq"
|
|
|
|
|
- id="randomBoxAgree2"
|
|
|
|
|
- v-model="agree2"
|
|
|
|
|
- @change="onAgreeChange"
|
|
|
|
|
- />
|
|
|
|
|
- <label for="randomBoxAgree2">
|
|
|
|
|
- <span class="ico-check"></span>고객 혜택 정보 및 광고 수신 동의
|
|
|
|
|
- (필수)
|
|
|
|
|
- </label>
|
|
|
|
|
- <a @click="activeLayer(2)" class="ico-arrow-right agreeActions"
|
|
|
|
|
- >더보기</a
|
|
|
|
|
- >
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="popup-footer">
|
|
|
|
|
- <div class="btn-group">
|
|
|
|
|
- <button
|
|
|
|
|
- class="btns w-sm lightgray md-ripples ripples-dark popup-close"
|
|
|
|
|
- type="button"
|
|
|
|
|
- >
|
|
|
|
|
- 취소
|
|
|
|
|
- </button>
|
|
|
|
|
- <button
|
|
|
|
|
- id="randomBoxAplyBtn"
|
|
|
|
|
- class="btns w-sm md-ripples ripples-light gtm-tracking"
|
|
|
|
|
- data-gtm-tracking-category="랜덤박스 팝업_PC"
|
|
|
|
|
- data-gtm-tracking-action="랜덤박스 열기_PC"
|
|
|
|
|
- data-gtm-tracking-label="박스열기 버튼"
|
|
|
|
|
- type="button"
|
|
|
|
|
- @click="trySpinRoulette(useSeq)"
|
|
|
|
|
- >
|
|
|
|
|
- 룰렛 돌리기
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
- <button
|
|
|
|
|
- @click="activeLayer1 = !activeLayer1"
|
|
|
|
|
- type="button"
|
|
|
|
|
- id="layer-close01"
|
|
|
|
|
- class="btn-close-x popup-close"
|
|
|
|
|
- >
|
|
|
|
|
- <svg
|
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
- width="37.657"
|
|
|
|
|
- height="37.657"
|
|
|
|
|
- viewBox="0 0 37.657 37.657"
|
|
|
|
|
- >
|
|
|
|
|
- <path
|
|
|
|
|
- data-name="선 392"
|
|
|
|
|
- transform="translate(2.828 2.828)"
|
|
|
|
|
- style="fill: none; stroke: #000; stroke-linecap: round; stroke-width: 4px"
|
|
|
|
|
- d="m0 0 32 32"
|
|
|
|
|
- />
|
|
|
|
|
- <path
|
|
|
|
|
- data-name="선 393"
|
|
|
|
|
- transform="translate(2.828 2.828)"
|
|
|
|
|
- style="fill: none; stroke: #000; stroke-linecap: round; stroke-width: 4px"
|
|
|
|
|
- d="M32 0 0 32"
|
|
|
|
|
- />
|
|
|
|
|
- </svg>
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-
|
|
|
|
|
- <div
|
|
|
|
|
- id="randomBoxAgree-layer02"
|
|
|
|
|
- class="layer-popup bottom-sheet-wrap terms"
|
|
|
|
|
- role="dialog"
|
|
|
|
|
- aria-hidden="false"
|
|
|
|
|
- tabindex="0"
|
|
|
|
|
- style="z-index: 101"
|
|
|
|
|
- :class="{ show: activeLayer2 }"
|
|
|
|
|
- >
|
|
|
|
|
- <div class="layer-popup-item">
|
|
|
|
|
- <div class="popup-header">
|
|
|
|
|
- <strong class="txt-main">약관 및 동의 내용 보기</strong>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="popup-body">
|
|
|
|
|
- <div class="agree-cont">
|
|
|
|
|
- <div class="agree-box">
|
|
|
|
|
- <p>
|
|
|
|
|
- 귀사가 고객 혜택정보 및 광고 수신동의(필수) 항목에서 수집한 개인정보,
|
|
|
|
|
- 고객세분화정보,<br />
|
|
|
|
|
- 선호도 및 라이프스타일 정보, 전산조회이력정보 및 상담이력정보, 고객 간
|
|
|
|
|
- 관계에 관한 예측 정보 및 이 정보들에 대한 통계·분석데이터를 해지 시까지
|
|
|
|
|
- 수집·이용·분석하여 각종 서비스<br />
|
|
|
|
|
- ·상품(주)미디어로그가 제공하는 이동통신, 금융서비스, 결합·제휴상품,
|
|
|
|
|
- 스토리지 등<br />
|
|
|
|
|
- 데이터·콘텐츠서비스, 부가서비스, 전자상거래서비스, 위치정보서비스,
|
|
|
|
|
- it솔루션, Smart health서비스, 신규서비스·상품 포함), 제휴사와 결합된
|
|
|
|
|
- 서비스 및 제휴사의 서비스에 대하여 홍보, 가입권유, 프로모션, 생활정보,
|
|
|
|
|
- 멤버십정보, 이벤트, 해외로밍 안내(공항 또는 항만 위치 시 로밍 이용방법,
|
|
|
|
|
- 진행중인 이벤트 등 안내) 및 설문조사 목적으로 수집·이용·활용하는 것,
|
|
|
|
|
- 본인에게 혜택정보, 광고정보를 각종 통신방식[전화, SMS, LMS, MMS, WAP
|
|
|
|
|
- Push,이메일, 우편, APP안내 및 팝업, APP PUSH]으로 전송하는 것에
|
|
|
|
|
- 동의합니다.
|
|
|
|
|
- </p>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- <div class="popup-footer">
|
|
|
|
|
- <!-- <div class="btn-group">
|
|
|
|
|
- <button
|
|
|
|
|
- class="btns w-sm lightgray md-ripples ripples-dark popup-close"
|
|
|
|
|
- type="button"
|
|
|
|
|
- >
|
|
|
|
|
- 취소
|
|
|
|
|
- </button>
|
|
|
|
|
- <button class="btns w-sm md-ripples ripples-light popup-close" type="button">
|
|
|
|
|
- 확인
|
|
|
|
|
- </button>
|
|
|
|
|
- </div> -->
|
|
|
|
|
- <button
|
|
|
|
|
- @click="activeLayer2 = !activeLayer2"
|
|
|
|
|
- class="btn-close-x popup-close"
|
|
|
|
|
- id="layer-close02"
|
|
|
|
|
- type="button"
|
|
|
|
|
- >
|
|
|
|
|
- <svg
|
|
|
|
|
- xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
- width="37.657"
|
|
|
|
|
- height="37.657"
|
|
|
|
|
- viewBox="0 0 37.657 37.657"
|
|
|
|
|
- >
|
|
|
|
|
- <path
|
|
|
|
|
- data-name="선 392"
|
|
|
|
|
- transform="translate(2.828 2.828)"
|
|
|
|
|
- style="fill: none; stroke: #000; stroke-linecap: round; stroke-width: 4px"
|
|
|
|
|
- d="m0 0 32 32"
|
|
|
|
|
- />
|
|
|
|
|
- <path
|
|
|
|
|
- data-name="선 393"
|
|
|
|
|
- transform="translate(2.828 2.828)"
|
|
|
|
|
- style="fill: none; stroke: #000; stroke-linecap: round; stroke-width: 4px"
|
|
|
|
|
- d="M32 0 0 32"
|
|
|
|
|
- />
|
|
|
|
|
- </svg>
|
|
|
|
|
- </button>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
- </div>
|
|
|
|
|
-</template>
|
|
|
|
|
-
|
|
|
|
|
-<script setup>
|
|
|
|
|
- import { ref, onMounted, nextTick } from "vue";
|
|
|
|
|
- import { useRoute } from "vue-router";
|
|
|
|
|
-
|
|
|
|
|
- definePageMeta({
|
|
|
|
|
- layout: "roulette",
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- /************************************************************************
|
|
|
|
|
-| 전역
|
|
|
|
|
-************************************************************************/
|
|
|
|
|
-
|
|
|
|
|
- const pageId = ref("ROULETTE");
|
|
|
|
|
- const { $eventBus } = useNuxtApp();
|
|
|
|
|
- const winProbability = ref(100.0);
|
|
|
|
|
- const savedName = ref("");
|
|
|
|
|
- const savedPhone = ref("");
|
|
|
|
|
- const isSpinning = ref(false);
|
|
|
|
|
- const activeLayer1 = ref(false);
|
|
|
|
|
- const activeLayer2 = ref(false);
|
|
|
|
|
-
|
|
|
|
|
- const wheelRef = ref(null);
|
|
|
|
|
- const textLayerRef = ref(null);
|
|
|
|
|
-
|
|
|
|
|
- const agreeAll = ref(false);
|
|
|
|
|
- const agree1 = ref(false);
|
|
|
|
|
- const agree2 = ref(false);
|
|
|
|
|
-
|
|
|
|
|
- const route = useRoute();
|
|
|
|
|
- const useSeq = ref(route.query.seq || route.params.seq || ""); // 쿼리 또는 params에서 seq 추출
|
|
|
|
|
- const compId = ref(route.query.id || route.params.id || ""); // 쿼리 또는 params에서 id 추출
|
|
|
|
|
- /************************************************************************
|
|
|
|
|
-| 스토어
|
|
|
|
|
-************************************************************************/
|
|
|
|
|
- const useDtStore = useDetailStore();
|
|
|
|
|
-
|
|
|
|
|
- /************************************************************************
|
|
|
|
|
-| 함수
|
|
|
|
|
-************************************************************************/
|
|
|
|
|
- const setWinProbability = (probability) => {
|
|
|
|
|
- winProbability.value = Math.max(0, Math.min(100, parseFloat(probability)));
|
|
|
|
|
- return winProbability.value;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const activeLayer = (idx) => {
|
|
|
|
|
- if (idx === 1) {
|
|
|
|
|
- activeLayer1.value = !activeLayer1.value;
|
|
|
|
|
- } else if (idx === 2) {
|
|
|
|
|
- activeLayer2.value = !activeLayer2.value;
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const createRoulette = (numSections, itemName) => {
|
|
|
|
|
- nextTick(() => {
|
|
|
|
|
- const $wheel = wheelRef.value;
|
|
|
|
|
- const $textLayer = textLayerRef.value;
|
|
|
|
|
- if (!$wheel || !$textLayer) return;
|
|
|
|
|
-
|
|
|
|
|
- // 초기화
|
|
|
|
|
- $wheel.style.background = "";
|
|
|
|
|
- $textLayer.innerHTML = "";
|
|
|
|
|
- const items = ["당첨", "꽝", "꽝", "꽝", "꽝", "꽝", "꽝", "꽝"];
|
|
|
|
|
- const sectionCount = numSections;
|
|
|
|
|
- const sectionAngle = 360 / sectionCount;
|
|
|
|
|
- const colors = ["#f5c4c3", "#fdf195", "#F0FFF0"];
|
|
|
|
|
-
|
|
|
|
|
- // conic-gradient
|
|
|
|
|
- let conicGradient = "conic-gradient(";
|
|
|
|
|
- for (let i = 0; i < sectionCount; i++) {
|
|
|
|
|
- const startAngle = i * sectionAngle;
|
|
|
|
|
- const endAngle = (i + 1) * sectionAngle;
|
|
|
|
|
- const color = colors[i % 3];
|
|
|
|
|
- conicGradient += `${color} ${startAngle}deg ${endAngle}deg`;
|
|
|
|
|
- if (i < sectionCount - 1) conicGradient += ", ";
|
|
|
|
|
- }
|
|
|
|
|
- conicGradient += ")";
|
|
|
|
|
- $wheel.style.background = conicGradient;
|
|
|
|
|
-
|
|
|
|
|
- // 룰렛 크기 계산
|
|
|
|
|
- const wheelRect = $wheel.getBoundingClientRect();
|
|
|
|
|
- const radius = wheelRect.width / 2;
|
|
|
|
|
-
|
|
|
|
|
- for (let i = 0; i < sectionCount; i++) {
|
|
|
|
|
- const textDiv = document.createElement("div");
|
|
|
|
|
- textDiv.className = "section-text";
|
|
|
|
|
- textDiv.innerText = items[i % items.length];
|
|
|
|
|
- const angle = i * sectionAngle + sectionAngle / 2;
|
|
|
|
|
- const distance = radius * 0.75;
|
|
|
|
|
- const radians = angle * (Math.PI / 180);
|
|
|
|
|
- const centerX = radius;
|
|
|
|
|
- const centerY = radius;
|
|
|
|
|
- const x = centerX + Math.sin(radians) * distance;
|
|
|
|
|
- const y = centerY - Math.cos(radians) * distance;
|
|
|
|
|
- textDiv.style.position = "absolute";
|
|
|
|
|
- textDiv.style.left = `${x}px`;
|
|
|
|
|
- textDiv.style.top = `${y}px`;
|
|
|
|
|
- textDiv.style.transform = `rotate(${angle}deg)`;
|
|
|
|
|
- $textLayer.appendChild(textDiv);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 당첨 섹션 강조
|
|
|
|
|
- const winSectionIndex = 4;
|
|
|
|
|
- const $winText = $textLayer.children[winSectionIndex];
|
|
|
|
|
- if ($winText) {
|
|
|
|
|
- $winText.style.color = "#E91E63";
|
|
|
|
|
- $winText.style.fontWeight = "bolder";
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const handleWin = (name, phone, EVT_SEQ) => {
|
|
|
|
|
- //참여자 정보
|
|
|
|
|
- let __req = {
|
|
|
|
|
- name: name,
|
|
|
|
|
- phone: phone,
|
|
|
|
|
- seq: EVT_SEQ,
|
|
|
|
|
- ignore_auth: 1,
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- useAxios()
|
|
|
|
|
- .post("/winner/reg", __req)
|
|
|
|
|
- .then((res) => {
|
|
|
|
|
- if (res.data.rank > 0) {
|
|
|
|
|
- let param = {
|
|
|
|
|
- id: pageId,
|
|
|
|
|
- title: "시스템 메시지",
|
|
|
|
|
- content: `축하합니다.<br/>${res.data.rank}등에 당첨되었습니다!`,
|
|
|
|
|
- yes: {
|
|
|
|
|
- text: "확인",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- no: {
|
|
|
|
|
- text: "취소",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- reload: true,
|
|
|
|
|
- };
|
|
|
|
|
- $eventBus.emit("OPEN_CONFIRM_POP_UP", param);
|
|
|
|
|
- } else {
|
|
|
|
|
- let param = {
|
|
|
|
|
- id: pageId,
|
|
|
|
|
- title: "시스템 메시지",
|
|
|
|
|
- content: `당첨에 실패하였습니다.<br/>다음 기회에 도전해보세요!`,
|
|
|
|
|
- yes: {
|
|
|
|
|
- text: "확인",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- no: {
|
|
|
|
|
- text: "취소",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- reload: true,
|
|
|
|
|
- };
|
|
|
|
|
- $eventBus.emit("OPEN_CONFIRM_POP_UP", param);
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- .catch((error) => {})
|
|
|
|
|
- .finally(() => {});
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const spinRoulette = (name, phone, EVT_SEQ) => {
|
|
|
|
|
- if (isSpinning.value) return;
|
|
|
|
|
- isSpinning.value = true;
|
|
|
|
|
-
|
|
|
|
|
- const spinDuration = 5000;
|
|
|
|
|
- const spinRounds = 5; // 룰렛 회전 횟수
|
|
|
|
|
- const sectionCount = 8; // 룰렛 섹션 개수
|
|
|
|
|
- const sectionAngle = 360 / sectionCount;
|
|
|
|
|
- const winSectionIndex = 0; //당첨 섹션 인덱스 : crateRoulette()에서 설정한 인덱스와 동일해야 함
|
|
|
|
|
- const winSectionStart = winSectionIndex * sectionAngle; // 당첨 섹션 시작 각도
|
|
|
|
|
- const winSectionEnd = (winSectionIndex + 1) * sectionAngle; // 당첨 섹션 끝 각도
|
|
|
|
|
-
|
|
|
|
|
- const isWin = Math.random() * 100 < winProbability.value;
|
|
|
|
|
- let stopAngle;
|
|
|
|
|
- if (isWin) {
|
|
|
|
|
- stopAngle = winSectionStart + Math.random() * (winSectionEnd - winSectionStart);
|
|
|
|
|
- } else {
|
|
|
|
|
- const loseSections = [];
|
|
|
|
|
- for (let i = 0; i < sectionCount; i++) {
|
|
|
|
|
- if (i !== winSectionIndex) loseSections.push(i);
|
|
|
|
|
- }
|
|
|
|
|
- const loseIndex = loseSections[Math.floor(Math.random() * loseSections.length)];
|
|
|
|
|
- const loseStart = loseIndex * sectionAngle;
|
|
|
|
|
- const loseEnd = (loseIndex + 1) * sectionAngle;
|
|
|
|
|
- stopAngle = loseStart + Math.random() * (loseEnd - loseStart);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const rotationAmount = spinRounds * 360 + (360 - stopAngle);
|
|
|
|
|
-
|
|
|
|
|
- nextTick(() => {
|
|
|
|
|
- const $wheel = wheelRef.value;
|
|
|
|
|
- const $textLayer = textLayerRef.value;
|
|
|
|
|
- if (!$wheel || !$textLayer) return;
|
|
|
|
|
-
|
|
|
|
|
- $wheel.style.transition = "none";
|
|
|
|
|
- $wheel.style.transform = "rotate(0deg)";
|
|
|
|
|
- $textLayer.style.transition = "none";
|
|
|
|
|
- $textLayer.style.transform = "rotate(0deg)";
|
|
|
|
|
- void $wheel.offsetWidth;
|
|
|
|
|
- $wheel.style.transition = `transform ${spinDuration}ms cubic-bezier(0.2, 0.8, 0.3, 0.9)`;
|
|
|
|
|
- $wheel.style.transform = `rotate(${rotationAmount}deg)`;
|
|
|
|
|
- $textLayer.style.transition = `transform ${spinDuration}ms cubic-bezier(0.2, 0.8, 0.3, 0.9)`;
|
|
|
|
|
- $textLayer.style.transform = `rotate(${rotationAmount}deg)`;
|
|
|
|
|
-
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- isSpinning.value = false;
|
|
|
|
|
- const finalAngle = (360 - (rotationAmount % 360)) % 360;
|
|
|
|
|
- const sectionIndex = Math.floor(finalAngle / sectionAngle);
|
|
|
|
|
-
|
|
|
|
|
- //console.log(sectionIndex, winSectionIndex);
|
|
|
|
|
- if (sectionIndex === winSectionIndex) {
|
|
|
|
|
- handleWin(name, phone, EVT_SEQ);
|
|
|
|
|
- } else {
|
|
|
|
|
- handleWin(name, phone, EVT_SEQ);
|
|
|
|
|
- }
|
|
|
|
|
- }, spinDuration);
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const trySpinRoulette = async (EVT_SEQ) => {
|
|
|
|
|
- const name = document.getElementById("userName").value.trim();
|
|
|
|
|
- const phone = document.getElementById("userPhone").value.trim();
|
|
|
|
|
-
|
|
|
|
|
- if (!name) {
|
|
|
|
|
- let param = {
|
|
|
|
|
- id: pageId,
|
|
|
|
|
- title: "시스템 메시지",
|
|
|
|
|
- content: "이름을 입력하세요.",
|
|
|
|
|
- yes: {
|
|
|
|
|
- text: "확인",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- no: {
|
|
|
|
|
- text: "취소",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
- $eventBus.emit("OPEN_CONFIRM_POP_UP", param);
|
|
|
|
|
- document.getElementById("userName").focus();
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- if (!phone) {
|
|
|
|
|
- let param = {
|
|
|
|
|
- id: pageId,
|
|
|
|
|
- title: "시스템 메시지",
|
|
|
|
|
- content: "휴대폰 번호를 입력하세요.",
|
|
|
|
|
- yes: {
|
|
|
|
|
- text: "확인",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- no: {
|
|
|
|
|
- text: "취소",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
- $eventBus.emit("OPEN_CONFIRM_POP_UP", param);
|
|
|
|
|
- document.getElementById("userPhone").focus();
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const phoneRegex = /^010-\d{4}-\d{4}$/;
|
|
|
|
|
- if (!phoneRegex.test(phone)) {
|
|
|
|
|
- let param = {
|
|
|
|
|
- id: pageId,
|
|
|
|
|
- title: "시스템 메시지",
|
|
|
|
|
- content: "휴대폰 번호를 형식에 맞게 입력하세요. 예시: 010-1234-5678",
|
|
|
|
|
- yes: {
|
|
|
|
|
- text: "확인",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- no: {
|
|
|
|
|
- text: "취소",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
- $eventBus.emit("OPEN_CONFIRM_POP_UP", param);
|
|
|
|
|
- document.getElementById("userPhone").focus();
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (!agreeAll.value) {
|
|
|
|
|
- let param = {
|
|
|
|
|
- id: pageId,
|
|
|
|
|
- title: "시스템 메시지",
|
|
|
|
|
- content:
|
|
|
|
|
- "이벤트 참여 및 전화 상담을 위한 개인정보 수집 및\n이용 동의 (필수) 에 동의해주세요.",
|
|
|
|
|
- yes: {
|
|
|
|
|
- text: "확인",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- no: {
|
|
|
|
|
- text: "취소",
|
|
|
|
|
- isProc: false,
|
|
|
|
|
- },
|
|
|
|
|
- };
|
|
|
|
|
- $eventBus.emit("OPEN_CONFIRM_POP_UP", param);
|
|
|
|
|
-
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- savedName.value = name;
|
|
|
|
|
- savedPhone.value = phone;
|
|
|
|
|
-
|
|
|
|
|
- activeLayer1.value = !activeLayer1.value;
|
|
|
|
|
-
|
|
|
|
|
- const isMatched = await matchedUser(savedName.value, savedPhone.value, EVT_SEQ);
|
|
|
|
|
- if (!isMatched) {
|
|
|
|
|
- spinRoulette(savedName.value, savedPhone.value, EVT_SEQ);
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const rouletteCnt = (EVT_SEQ) => {
|
|
|
|
|
- let __req = {
|
|
|
|
|
- seq: EVT_SEQ,
|
|
|
|
|
- ignore_auth: 1,
|
|
|
|
|
- };
|
|
|
|
|
- useAxios()
|
|
|
|
|
- .post("/winner/itemcount", __req)
|
|
|
|
|
- .then((res) => {
|
|
|
|
|
- //createRoulette(res.data.count, res.data.items);
|
|
|
|
|
- /*
|
|
|
|
|
- TODO :
|
|
|
|
|
- 룰렛 생성 어떤 형태로 진행할지 기획 조율 필요
|
|
|
|
|
- */
|
|
|
|
|
- createRoulette(8, res.data.items);
|
|
|
|
|
- })
|
|
|
|
|
- .catch((error) => {})
|
|
|
|
|
- .finally(() => {});
|
|
|
|
|
- };
|
|
|
|
|
- // 전체 동의 체크 시 하위 동의도 같이 변경
|
|
|
|
|
- const onAgreeAllChange = () => {
|
|
|
|
|
- agree1.value = agreeAll.value;
|
|
|
|
|
- agree2.value = agreeAll.value;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- // 하위 동의 체크 시 전체 동의 상태도 동기화
|
|
|
|
|
- const onAgreeChange = () => {
|
|
|
|
|
- agreeAll.value = agree1.value && agree2.value;
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const winnerCheck = (EVT_SEQ) => {
|
|
|
|
|
- let params = {
|
|
|
|
|
- seq: EVT_SEQ,
|
|
|
|
|
- ignore_auth: 1,
|
|
|
|
|
- };
|
|
|
|
|
- useAxios()
|
|
|
|
|
- .post("/winner/winnerchk", params)
|
|
|
|
|
- .then((res) => {
|
|
|
|
|
- //console.log(res.data.status);
|
|
|
|
|
- rouletteCnt(EVT_SEQ);
|
|
|
|
|
- if (res.data.status == "closed") {
|
|
|
|
|
- setWinProbability(0);
|
|
|
|
|
- } else {
|
|
|
|
|
- setWinProbability(100); // 당첨 확률 몇 퍼센트로 할지 관리자 설정값으로 진행할지 여부 확인 필요
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- .catch((error) => {
|
|
|
|
|
- //$log.debug("[equipMgmtReg][fnGetTenantList][error]");
|
|
|
|
|
- //useErrorHandler().fnSetCommErrorHandle(error, fnGetTenantList);
|
|
|
|
|
- })
|
|
|
|
|
- .finally(() => {
|
|
|
|
|
- //$log.debug("[equipMgmtReg][fnGetTenantList][finished]");
|
|
|
|
|
- //objSlt.value.tenantNameList = _cloneDeep(temp);
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- const matchedUser = async (name, phone, EVT_SEQ) => {
|
|
|
|
|
- let __req = {
|
|
|
|
|
- name,
|
|
|
|
|
- phone,
|
|
|
|
|
- seq: EVT_SEQ,
|
|
|
|
|
- ignore_auth: 1,
|
|
|
|
|
- };
|
|
|
|
|
- try {
|
|
|
|
|
- const res = await useAxios().post("/winner/matcheduser", __req);
|
|
|
|
|
- if (res.data.result == "matched") {
|
|
|
|
|
- let param = {
|
|
|
|
|
- id: pageId,
|
|
|
|
|
- title: "시스템 메시지",
|
|
|
|
|
- content: `이미 참여하신 사용자입니다.<br/>다음 기회에 도전해보세요!`,
|
|
|
|
|
- yes: { text: "확인", isProc: false },
|
|
|
|
|
- no: { text: "취소", isProc: false },
|
|
|
|
|
- reload: true,
|
|
|
|
|
- };
|
|
|
|
|
- $eventBus.emit("OPEN_CONFIRM_POP_UP", param);
|
|
|
|
|
- return true; // 이미 참여자
|
|
|
|
|
- } else if (res.data.result == "phonesame") {
|
|
|
|
|
- let param = {
|
|
|
|
|
- id: pageId,
|
|
|
|
|
- title: "시스템 메시지",
|
|
|
|
|
- content: `이미 참여한 사용자의 휴대폰 번호와 동일합니다.<br/>다음 기회에 도전해보세요!`,
|
|
|
|
|
- yes: { text: "확인", isProc: false },
|
|
|
|
|
- no: { text: "취소", isProc: false },
|
|
|
|
|
- reload: true,
|
|
|
|
|
- };
|
|
|
|
|
- $eventBus.emit("OPEN_CONFIRM_POP_UP", param);
|
|
|
|
|
- return true; // 이미 참여자
|
|
|
|
|
- }
|
|
|
|
|
- return false; // 참여자 아님
|
|
|
|
|
- } catch (e) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- /************************************************************************
|
|
|
|
|
-| 라이프 사이클
|
|
|
|
|
-************************************************************************/
|
|
|
|
|
- onMounted(() => {
|
|
|
|
|
- // useSeq.value가 비어있지 않을 때만 winnerCheck 호출
|
|
|
|
|
- if (!useSeq.value || !compId.value) {
|
|
|
|
|
- $eventBus.emit("OPEN_CONFIRM_POP_UP", {
|
|
|
|
|
- id: "ROULETTE",
|
|
|
|
|
- title: "시스템 메시지",
|
|
|
|
|
- content: "이벤트 식별값(id/seq)이 없습니다.",
|
|
|
|
|
- yes: { text: "확인", isProc: false },
|
|
|
|
|
- no: { text: "취소", isProc: false },
|
|
|
|
|
- });
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- winnerCheck(useSeq.value);
|
|
|
|
|
- /*
|
|
|
|
|
- TODO :
|
|
|
|
|
- */
|
|
|
|
|
- });
|
|
|
|
|
-</script>
|
|
|