|
|
@@ -0,0 +1,521 @@
|
|
|
+<!DOCTYPE html>
|
|
|
+<html lang="en">
|
|
|
+
|
|
|
+<head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
+ <title>转盘抽奖</title>
|
|
|
+ <style>
|
|
|
+ .el-overlay {
|
|
|
+ background-color: rgba(0, 0, 0, 0.8);
|
|
|
+ }
|
|
|
+
|
|
|
+ ::-webkit-scrollbar {
|
|
|
+ width: 6px;
|
|
|
+ height: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::-webkit-scrollbar-track {
|
|
|
+ width: 3px;
|
|
|
+ background: rgba(#101F1C, 0.1);
|
|
|
+ -webkit-border-radius: 2em;
|
|
|
+ -moz-border-radius: 2em;
|
|
|
+ border-radius: 2em;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::-webkit-scrollbar-thumb {
|
|
|
+ background-color: rgba(144, 147, 153, .5);
|
|
|
+ background-clip: padding-box;
|
|
|
+ min-height: 28px;
|
|
|
+ -webkit-border-radius: 2em;
|
|
|
+ -moz-border-radius: 2em;
|
|
|
+ border-radius: 2em;
|
|
|
+ transition: background-color .3s;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::-webkit-scrollbar-thumb:hover {
|
|
|
+ background-color: rgba(144, 147, 153, .3);
|
|
|
+ }
|
|
|
+
|
|
|
+ * {
|
|
|
+ margin: 0;
|
|
|
+ padding: 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ #app {
|
|
|
+ /* background: url('https://xiaoyou.dgtis.com/images/image/2025/01/16/9nr68awt17tzoa20d7bo.jpg') no-repeat; */
|
|
|
+ background: url('https://xiaoyou.dgtis.com/images/image/2025/01/16/h1xp8b04dwbqs4m6qzrd.jpg') no-repeat;
|
|
|
+ background-size: 100% 100%;
|
|
|
+ width: 375px;
|
|
|
+ height: 680px;
|
|
|
+ margin: 0 auto;
|
|
|
+ margin-top: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-dialog__body {
|
|
|
+ padding-top: 0px !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ [v-cloak] {
|
|
|
+ display: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ .rules {
|
|
|
+ cursor: pointer;
|
|
|
+ position: absolute;
|
|
|
+ width: 50px;
|
|
|
+ height: 50px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ left: 25%;
|
|
|
+ top: 25%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .recordBtn {
|
|
|
+ cursor: pointer;
|
|
|
+ position: absolute;
|
|
|
+ width: 50px;
|
|
|
+ height: 50px;
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 600;
|
|
|
+ right: 10%;
|
|
|
+ bottom: 7%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .recordBtn>img {
|
|
|
+ width: 75px;
|
|
|
+ height: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .container {
|
|
|
+ overflow: hidden;
|
|
|
+ width: 350px;
|
|
|
+ height: 350px;
|
|
|
+ margin: 0 auto;
|
|
|
+ position: relative;
|
|
|
+ top: 30%;
|
|
|
+ }
|
|
|
+
|
|
|
+ .prize-list {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ border-radius: 50%;
|
|
|
+ border: 10px solid #ffc227;
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+
|
|
|
+ .prize-item {
|
|
|
+ /*border: 2px solid red;*/
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ top: -10px;
|
|
|
+ margin: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .prize-item img {
|
|
|
+ width: 25%;
|
|
|
+ /* height: 25%; */
|
|
|
+ margin: 35px auto 10px;
|
|
|
+ display: block;
|
|
|
+ }
|
|
|
+
|
|
|
+ .prize-item p {
|
|
|
+ color: #fff;
|
|
|
+ font-size: 12px;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 20px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn {
|
|
|
+ width: 80px;
|
|
|
+ height: 110px;
|
|
|
+ background: url('https://xiaoyou.dgtis.com/images/image/2023/09/12/xvtwunkntyc65fngc9pb.png') no-repeat center / 100% 100%;
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ top: -5%;
|
|
|
+ bottom: 0;
|
|
|
+ margin: auto;
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* .btn::before {
|
|
|
+ content: "";
|
|
|
+ width: 41px;
|
|
|
+ height: 39px;
|
|
|
+ background: url('https://xiaoyou.dgtis.com/images/image/2023/08/15/2vac6uuqd3gpbl35l8e1.png') no-repeat center / 100% 100%;
|
|
|
+ position: absolute;
|
|
|
+ left: 0;
|
|
|
+ right: 0;
|
|
|
+ top: -30px;
|
|
|
+ margin: auto;
|
|
|
+ -webkit-transform: rotate(-5deg);
|
|
|
+ transform: rotate(-5deg);
|
|
|
+ } */
|
|
|
+ .recordListBox {
|
|
|
+ max-height: 300px;
|
|
|
+ overflow: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title {
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ .recordItem {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-around;
|
|
|
+ align-items: center;
|
|
|
+ margin: 10px 0;
|
|
|
+ }
|
|
|
+ </style>
|
|
|
+</head>
|
|
|
+
|
|
|
+<body>
|
|
|
+ <div id="app" v-cloak class="app">
|
|
|
+ <div class="rules" @click="showRules">
|
|
|
+ 抽奖<br>规则
|
|
|
+ </div>
|
|
|
+ <div class="recordBtn" @click="showRecordList">
|
|
|
+ <!-- <img src="https://xiaoyou.dgtis.com/images/image/2023/09/06/lt1vbg426idwq725ysdm.png" alt="抽奖记录"> -->
|
|
|
+ <!-- <img src="https://xiaoyou.dgtis.com/images/image/2024/11/28/9p4ts0l94ngnz9rac48b.png" alt="十连抽奖"> -->
|
|
|
+ </div>
|
|
|
+ <div class="container">
|
|
|
+ <div class="prize-list" ref="prizeWrap" :style="bgColor">
|
|
|
+ <div class="prize-item" v-for="(item, index) in prizeList" :style="prizeStyle(index)">
|
|
|
+ <img :src="item.imgUrl" alt="">
|
|
|
+ <p>{{ item.prizeName }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="btn" @click="start"></div>
|
|
|
+ </div>
|
|
|
+ <el-dialog v-model="dialogVisible" title="抽奖规则" width="50%" center>
|
|
|
+ <div style="max-height: 400px;overflow: auto;" v-html="rule"></div>
|
|
|
+ </el-dialog>
|
|
|
+ <el-dialog v-model="dialogRecordList" title="中奖记录" width="40%" center>
|
|
|
+ <div class="recordListBox">
|
|
|
+ <div class="recordItem" v-for="item in recordList">
|
|
|
+ <div style="width: 100%;text-align: center;">{{item}}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+
|
|
|
+</body>
|
|
|
+<script src="./js/crypto-js.min.js"></script>
|
|
|
+<script src="./js/vue.global.js"></script>
|
|
|
+<link href="./css/index.css" rel="stylesheet">
|
|
|
+<script src="./js/index.full.min.js"></script>
|
|
|
+<script src="./js/jquery.js"></script>
|
|
|
+<script>
|
|
|
+ const {
|
|
|
+ createApp,
|
|
|
+ onBeforeMount,
|
|
|
+ onMounted,
|
|
|
+ onUnmounted,
|
|
|
+ ref,
|
|
|
+ reactive,
|
|
|
+ toRefs,
|
|
|
+ computed,
|
|
|
+ nextTick
|
|
|
+ } = Vue
|
|
|
+ createApp({
|
|
|
+ setup() {
|
|
|
+ const state = reactive({
|
|
|
+ recordList: [],
|
|
|
+ dialogRecordList: false,
|
|
|
+ dialogVisible: false,
|
|
|
+ rule: '',
|
|
|
+ token: '',
|
|
|
+ actId: '',
|
|
|
+ keyStr: 'qwerasdfzxcvtyui',
|
|
|
+ prizeList: [
|
|
|
+ ], // 后台配置的奖品数据
|
|
|
+ isRunning: false, // 是否正在抽奖
|
|
|
+ baseRunAngle: 360 * 5, // 总共转动角度 至少5圈
|
|
|
+ prizeId: 0, // 中奖id
|
|
|
+ })
|
|
|
+ const prizeWrap = ref(null)
|
|
|
+
|
|
|
+
|
|
|
+ // 平均每个奖品角度
|
|
|
+ const rotateAngle = computed(() => {
|
|
|
+ const _degree = 360 / state.prizeList.length
|
|
|
+ return _degree
|
|
|
+ })
|
|
|
+
|
|
|
+ // 要执行总角度数
|
|
|
+ const totalRunAngle = computed(() => {
|
|
|
+ return state.baseRunAngle + 360 - state.prizeId * rotateAngle.value - rotateAngle.value / 2
|
|
|
+ })
|
|
|
+
|
|
|
+ // 计算绘制转盘背景
|
|
|
+ const bgColor = computed(() => {
|
|
|
+ const _len = state.prizeList.length
|
|
|
+ const colorList = ['#e32c1a', '#ff5544']
|
|
|
+ let colorVal = ''
|
|
|
+ for (let i = 0; i < _len; i++) {
|
|
|
+ colorVal += `${colorList[i % 2]} ${rotateAngle.value * i}deg ${rotateAngle.value * (i + 1)}deg,`
|
|
|
+ }
|
|
|
+ return `
|
|
|
+ background: conic-gradient(${colorVal.slice(0, -1)});
|
|
|
+ `
|
|
|
+ })
|
|
|
+ // 每个奖品布局
|
|
|
+ const prizeStyle = computed(() => {
|
|
|
+ const _degree = rotateAngle.value
|
|
|
+ return (i) => {
|
|
|
+ return `
|
|
|
+ width: ${2 * 185 * Math.sin(_degree / 2 * Math.PI / 180)}px;
|
|
|
+ height: 185px;
|
|
|
+ transform: rotate(${_degree * i + _degree / 2}deg);
|
|
|
+ transform-origin: 50% 100%;
|
|
|
+ `
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ onBeforeMount(() => {
|
|
|
+ window.addEventListener('message', function (e) {
|
|
|
+ // console.log("接收值:", e.data)
|
|
|
+ state.token = e.data.token;
|
|
|
+ state.actId = e.data.actId;
|
|
|
+ ElementPlus.ElLoading.service();
|
|
|
+ getTurntableInfo();
|
|
|
+ ElementPlus.ElLoading.service().close();
|
|
|
+ })
|
|
|
+ })
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+
|
|
|
+ prizeWrap.value.style = `${bgColor.value} transform: rotate(-${rotateAngle.value / 2}deg)`;
|
|
|
+ })
|
|
|
+
|
|
|
+ onUnmounted(() => {
|
|
|
+ prizeWrap.value.removeEventListener('transitionend', stopRun)
|
|
|
+ })
|
|
|
+
|
|
|
+ // 获取大转盘信息
|
|
|
+ async function getTurntableInfo() {
|
|
|
+ const postData = {
|
|
|
+ actId: state.actId,
|
|
|
+ };
|
|
|
+ let res = await httpAjax('get', '/mall-prize/prize/info', postData)
|
|
|
+ if (res.errno === 0) {
|
|
|
+ // console.log('获取大转盘信息',res.data);
|
|
|
+ state.prizeList = res.data.pool;
|
|
|
+ state.rule = res.data.content;
|
|
|
+ } else {
|
|
|
+ ElementPlus.ElMessage({
|
|
|
+ showClose: true,
|
|
|
+ message: res.errmsg,
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ };
|
|
|
+ function encryptECB(word) {
|
|
|
+ var keyHex = CryptoJS.enc.Utf8.parse(state.keyStr)
|
|
|
+ var plaintText = word
|
|
|
+ var encryptedData = CryptoJS.AES.encrypt(
|
|
|
+ plaintText,
|
|
|
+ keyHex,
|
|
|
+ {
|
|
|
+ mode: CryptoJS.mode.ECB,
|
|
|
+ padding: CryptoJS.pad.Pkcs7
|
|
|
+ })
|
|
|
+ return encryptedData.toString();
|
|
|
+ };
|
|
|
+ // 大转盘抽奖按钮
|
|
|
+ async function starDraw() {
|
|
|
+ let postData = {
|
|
|
+ actId: state.actId,
|
|
|
+ };
|
|
|
+ postData = JSON.stringify(postData)
|
|
|
+ postData = encryptECB(postData)
|
|
|
+ postData = postData.replace(/[\t\r\f\n\s]*/g, '');
|
|
|
+ // let res = await httpAjax('post', '/mall-prize/prize', getFormData(postData));
|
|
|
+ let res = await httpAjax('post', '/mall-prize/prize', postData);
|
|
|
+ if (res.errno === 0) {
|
|
|
+ // console.log('抽奖',res.data);
|
|
|
+ state.prizeId = res.data.index;
|
|
|
+ startRun();
|
|
|
+ } else {
|
|
|
+ state.isRunning = false;
|
|
|
+ ElementPlus.ElMessage({
|
|
|
+ showClose: true,
|
|
|
+ message: res.errmsg,
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ //中奖记录
|
|
|
+ async function getRecordList() {
|
|
|
+ let postData = {
|
|
|
+ actId: state.actId,
|
|
|
+ };
|
|
|
+ postData = JSON.stringify(postData)
|
|
|
+ postData = encryptECB(postData)
|
|
|
+ postData = postData.replace(/[\t\r\f\n\s]*/g, '');
|
|
|
+ ElementPlus.ElLoading.service();
|
|
|
+ let res = await httpAjax('post', '/mall-prize/continuousClicks', postData);
|
|
|
+ ElementPlus.ElLoading.service().close();
|
|
|
+ window.parent.getUserInfo();
|
|
|
+ if (res.errno === 0) {
|
|
|
+ state.recordList = res.data;
|
|
|
+ state.dialogRecordList = true;
|
|
|
+ } else {
|
|
|
+ ElementPlus.ElMessage({
|
|
|
+ showClose: true,
|
|
|
+ message: res.errmsg,
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ };
|
|
|
+
|
|
|
+ // 简单封装ajax
|
|
|
+ const httpAjax = (type, url, data) => {
|
|
|
+ ajaxHeaders = {
|
|
|
+ "Authorization": state.token,
|
|
|
+ 'Content-Type':'application/json'
|
|
|
+ }
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ $.ajax({
|
|
|
+ type: type,
|
|
|
+ // url: 'http://192.168.100.208:9083/admin' + url, //本地
|
|
|
+ // url: "http://47.103.79.143:9085/admin" + url,//测试环境
|
|
|
+ url:"https://xiaoyou.dgtis.com/admin"+ url,//正式环境
|
|
|
+ data: data,
|
|
|
+ contentType: type === 'post' ? false : true,
|
|
|
+ processData: type === 'post' ? false : true,
|
|
|
+ headers: ajaxHeaders,
|
|
|
+ success: function (res) {
|
|
|
+ if (res.errno == 503) {
|
|
|
+ window.location.href = 'https://dgt.dgtis.com/oneportal/login'
|
|
|
+ } else {
|
|
|
+ resolve(res);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ error: function (error) {
|
|
|
+ reject(error);
|
|
|
+ ElementPlus.ElMessage({
|
|
|
+ showClose: true,
|
|
|
+ message: '网络错误,请稍后再试!',
|
|
|
+ type: 'error',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理formData数据格式
|
|
|
+ const getFormData = (datas) => {
|
|
|
+ let formData = new FormData();
|
|
|
+ for (let key in datas) {
|
|
|
+ formData.append(key, datas[key]);
|
|
|
+ }
|
|
|
+ return formData;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取随机数
|
|
|
+ const getRandomNum = () => {
|
|
|
+ const num = Math.floor(Math.random() * state.prizeList.length)
|
|
|
+ return num
|
|
|
+ }
|
|
|
+ const showRules = () => {
|
|
|
+ state.dialogVisible = true;
|
|
|
+ }
|
|
|
+ const showRecordList = () => {
|
|
|
+ getRecordList();
|
|
|
+ }
|
|
|
+ const start = () => {
|
|
|
+ // ElementPlus.ElMessage({
|
|
|
+ // showClose: true,
|
|
|
+ // message: '已无抽奖次数!',
|
|
|
+ // type: 'warning',
|
|
|
+ // })
|
|
|
+ // return
|
|
|
+ if (!state.isRunning) {
|
|
|
+ state.isRunning = true;
|
|
|
+ starDraw();
|
|
|
+ // console.log('开始抽奖,后台请求中奖奖品')
|
|
|
+ // // 请求返回的奖品编号 这里使用随机数
|
|
|
+ // const prizeId = getRandomNum()
|
|
|
+ // console.log('中奖ID>>>', prizeId, state.prizeList[prizeId])
|
|
|
+ // state.prizeId = prizeId
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const startRun = () => {
|
|
|
+ // console.log(state.isRunning, totalRunAngle.value)
|
|
|
+ // 设置动效
|
|
|
+ prizeWrap.value.style = `
|
|
|
+ ${bgColor.value}
|
|
|
+ transform: rotate(${totalRunAngle.value}deg);
|
|
|
+ transition: all 4s ease;
|
|
|
+ `
|
|
|
+ // 监听transition动效停止事件
|
|
|
+ prizeWrap.value.addEventListener('transitionend', stopRun)
|
|
|
+ }
|
|
|
+
|
|
|
+ const stopRun = (e) => {
|
|
|
+ // console.log(e)
|
|
|
+ state.isRunning = false
|
|
|
+ prizeWrap.value.style = `
|
|
|
+ ${bgColor.value}
|
|
|
+ transform: rotate(${totalRunAngle.value - state.baseRunAngle}deg);
|
|
|
+ `
|
|
|
+ if (state.prizeList[state.prizeId].prizeType == '10') {
|
|
|
+ ElementPlus.ElMessageBox.alert("恭喜,您中了" + state.prizeList[state.prizeId].prizeName + "," + "可在“个人中心”我的礼品券中查看,在礼品兑换中兑换相应物品。", {
|
|
|
+ showClose: false,
|
|
|
+ center: true,
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ })
|
|
|
+ window.parent.getUserInfo();
|
|
|
+ } else if (state.prizeList[state.prizeId].prizeType == '20') {
|
|
|
+ ElementPlus.ElMessageBox.alert("恭喜,您中了" + state.prizeList[state.prizeId].prizeName + "!", {
|
|
|
+ showClose: false,
|
|
|
+ center: true,
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ })
|
|
|
+ window.parent.getUserInfo();
|
|
|
+ } else {
|
|
|
+ ElementPlus.ElMessageBox.alert("很遗憾,您未中奖。", {
|
|
|
+ showClose: false,
|
|
|
+ center: true,
|
|
|
+ confirmButtonText: '确认',
|
|
|
+ })
|
|
|
+ window.parent.getUserInfo();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...toRefs(state),
|
|
|
+ bgColor,
|
|
|
+ prizeStyle,
|
|
|
+ prizeWrap,
|
|
|
+ start,
|
|
|
+ showRules,
|
|
|
+ showRecordList
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }).use(ElementPlus).mount('#app')
|
|
|
+</script>
|
|
|
+
|
|
|
+</html>
|