Selaa lähdekoodia

9块9年卡初版

huangxiaojing 2 vuotta sitten
vanhempi
commit
6b7d3eeb23

BIN
assets/image/activity/lottery/alipay.png


BIN
assets/image/activity/lottery/arrow.png


BIN
assets/image/activity/lottery/bg.png


BIN
assets/image/activity/lottery/coupon-1.png


BIN
assets/image/activity/lottery/coupon-2.png


BIN
assets/image/activity/lottery/monthCard.png


BIN
assets/image/activity/lottery/pay-btn.png


BIN
assets/image/activity/lottery/roulette.png


BIN
assets/image/activity/lottery/rule.png


BIN
assets/image/activity/lottery/select-icon.png


BIN
assets/image/activity/lottery/select-round-icon.png


BIN
assets/image/activity/lottery/start-btn.png


BIN
assets/image/activity/lottery/unselect-icon.png


BIN
assets/image/activity/lottery/unselect-round-icon.png


BIN
assets/image/activity/lottery/wx.png


BIN
assets/image/activity/lottery/yearCard.png


+ 2 - 2
nuxt.config.js

@@ -64,7 +64,7 @@ export default {
     // 'normalize.css',
     '@mdi/font/css/materialdesignicons.css',
     '~/assets/style/main.scss',
-    // 'vant/lib/index.css'
+    'vant/lib/index.css'
   ],
 
   // Plugins to run before rendering page: https://go.nuxtjs.dev/config-plugins
@@ -83,7 +83,7 @@ export default {
     { src: '~/plugins/callapp', mode: 'client' },
     '~/plugins/jweixin',
     // '~/plugins/umeng-datasources',
-    // '@/plugins/vant',
+    '@/plugins/vant',
   ],
 
   // Auto import components: https://go.nuxtjs.dev/config-components

+ 145 - 0
pages/activity/lottery/component/roundTurntable.vue

@@ -0,0 +1,145 @@
+<template>
+  <div ref="turntable" class="turntable">
+    <div class="myTurntable" :style="{transform: rotateAngle, transition: rotateTransition}">
+      <canvas id="canvas" ref="canvas">
+        当前浏览器版本过低,请使用其他浏览器尝试
+      </canvas>
+      <div class="prize-container">
+        <div v-for="(item, index) in prizeData" :key="index" class="item" :style="getRotateAngle(index)">
+          <slot name="item" :item="item"></slot>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+ 
+<script>
+export default {
+  name: 'RoundTurntable',
+  props: {
+    prizeData: {
+      required: true,
+      type: Array
+    },
+    rotateCircle: {
+      default: 6,
+      type: Number
+    },
+    turntableStyleOption: {
+      type: Object,
+      default: () => {
+        return {
+          // 背景色
+          prizeBgColors: ['#ffdfd4', '#fffdfe', '#ffdfd4', '#fffdfe', '#ffdfd4', '#fffdfe', '#ffdfd4', '#fffdfe'],
+          // 转盘的外边框颜色
+          borderColor: '#f9dc84'
+        };
+      }
+    },
+    duringTime: {
+      type: Number,
+      default: 4.5
+    }
+  },
+  data() {
+    return {
+      // 开始转动的角度
+      startRotateDegree: 0,
+      rotateAngle: 0,
+      rotateTransition: ''
+    };
+  },
+  mounted() {
+    this.init();
+  },
+  methods: {
+    // 根据index计算每一格要旋转的角度的样式
+    getRotateAngle(index) {
+      const angle = 360 / this.prizeData.length * index + (180 / this.prizeData.length);
+      return {
+        transform: `rotate(${angle}deg)`
+      };
+    },
+    // 初始化圆形转盘canvas
+    init() {
+      // 各种数据
+      const data = this.turntableStyleOption;
+      const prizeNum = this.prizeData.length;
+      const { prizeBgColors, borderColor } = data;
+      // 开始绘画
+      const canvas = this.$refs.canvas;
+      const ctx = canvas.getContext('2d');
+      const canvasW = this.$refs.canvas.width = this.$refs.turntable.clientWidth; // 画板的高度
+      const canvasH = this.$refs.canvas.height = this.$refs.turntable.clientHeight; // 画板的宽度
+      // translate方法重新映射画布上的 (0,0) 位置
+      ctx.translate(0, canvasH);
+      // rotate方法旋转当前的绘图,因为文字适合当前扇形中心线垂直的!
+      ctx.rotate(-90 * Math.PI / 180);
+      // 圆环的外圆的半径
+      const outRadius = canvasW / 2;
+      // 圆环的内圆的半径
+      const innerRadius = 0;
+      const baseAngle = Math.PI * 2 / prizeNum; // 计算每个奖项所占角度数
+      ctx.clearRect(0, 0, canvasW, canvasH); // 去掉背景默认的黑色
+      ctx.strokeStyle = borderColor; // 设置画图线的颜色
+      for (let index = 0; index < prizeNum; index++) {
+        const angle = index * baseAngle;
+        ctx.fillStyle = prizeBgColors[index]; // 设置每个扇形区域的颜色
+        ctx.beginPath(); // 开始绘制
+        // 标准圆弧:arc(x,y,radius,startAngle,endAngle,anticlockwise)
+        ctx.arc(canvasW * 0.5, canvasH * 0.5, outRadius, angle, angle + baseAngle, false);
+        ctx.arc(canvasW * 0.5, canvasH * 0.5, innerRadius, angle + baseAngle, angle, true);
+        ctx.stroke();// 开始链线
+        ctx.fill(); // 填充颜色
+        ctx.save(); // 保存当前环境的状态
+      }
+    },
+    // 转动起来
+    rotate(index) {
+      // 运转时长
+      const duringTime = this.duringTime;
+      const rotateAngle = this.startRotateDegree + this.rotateCircle * 360 + 360 - (180 / this.prizeData.length + 360 / this.prizeData.length * index) - this.startRotateDegree % 360 - 13;
+      this.startRotateDegree = rotateAngle;
+      this.rotateAngle = `rotate(${rotateAngle}deg)`;
+      this.rotateTransition = `transform ${duringTime}s cubic-bezier(0.250, 0.460, 0.455, 0.995)`;
+      setTimeout(() => {
+        this.$emit('endRotation');
+      }, duringTime * 1000 + 500);
+    }
+  }
+};
+</script>
+ 
+<style scoped lang="scss">
+.turntable {
+  /*background-color: red;*/
+  position: absolute;
+  left: 0;
+  top: 0;
+  text-align: center;
+  transform: translateZ(0);
+  .myTurntable {
+    position: absolute;
+    left: 0;
+    top: 0;
+    width: 100%;
+    height: 100%;
+  }
+  .prize-container {
+    position: absolute;
+    left: 25%;
+    top: 0;
+    width: 50%;
+    height: 50%;
+    .item {
+      /*background: pink;*/
+      position: absolute;
+      left: 0;
+      top: 0;
+      width: 100%;
+      height: 100%;
+      transform-origin: center bottom;
+    }
+  }
+}
+</style>

+ 591 - 0
pages/activity/lottery/index.vue

@@ -0,0 +1,591 @@
+<template>
+  <div class="lottery-container">
+    <van-swipe :autoplay="3000" class="lottery-swipe" vertical :show-indicators="false">
+      <van-swipe-item>有23245个用户 购买15.9年卡</van-swipe-item>
+      <van-swipe-item>有23245个用户 购买15.9年卡</van-swipe-item>
+      <van-swipe-item>有23245个用户 购买15.9年卡</van-swipe-item>
+      <van-swipe-item>有23245个用户 购买15.9年卡</van-swipe-item>
+    </van-swipe>
+    <img class="w51h26" src="~/assets/image/activity/lottery/rule.png" alt="" @click="showRule=true">
+    <div class="roulette">
+      <div class="arrow" @click="startRotation"></div>
+      <img class="start-btn" src="~/assets/image/activity/lottery/start-btn.png" alt="" @click="startRotation">
+    </div>
+    <RoundTurntable ref="roundTurntable" :prize-data="prizeData" :rotate-circle="rotateCircle" :during-time="duringTime" :turntable-style-option="turntableStyleOption" class="turntable" @endRotation="endRotation">
+      <template slot="item" slot-scope="scope">
+        <div class="turntable-name"><span class="fs15">¥</span>{{ scope.item.level }}</div>
+        <div class="turntable-img">
+          <img src="~/assets/image/activity/lottery/yearCard.png" />
+        </div>
+      </template>
+    </RoundTurntable>
+    <div class="num">剩余机会{{num}}次</div>
+    <van-popup v-model="showPay" closeable close-icon-position="top-right" round :close-on-click-overlay="false" @closed="closed">
+      <div class="popup-view">
+        <div class="txt1">恭喜你获得{{actualPrice}}年卡</div>
+        <div :class="selMealId===mealId ? 'coupon-1 active' : 'coupon-1'" @click="selMealId=mealId">
+          <img v-if="selMealId===mealId" class="coupon-select-icon" src="~/assets/image/activity/lottery/select-icon.png" alt="">
+          <img v-else class="coupon-select-icon" src="~/assets/image/activity/lottery/unselect-icon.png" alt="">
+          <div class="coupon-title"><span class="txt2">{{actualPrice}}</span><span>会员</span><span class="txt3">({{title}})</span></div>
+          <div class="txt4">年卡(已获得)</div>
+          <img class="w253h73" src="~/assets/image/activity/lottery/coupon-1.png" alt="">
+        </div>
+        <div v-for="item in mealList" :key="item.id" :class="selMealId===item.id ? 'coupon-2 active' : 'coupon-2'" @click="selMealId=item.id">
+          <img v-if="selMealId===item.id" class="coupon-select-icon" src="~/assets/image/activity/lottery/select-icon.png" alt="">
+          <img v-else class="coupon-select-icon" src="~/assets/image/activity/lottery/unselect-icon.png" alt="">
+          <div class="coupon-title"><span class="txt2">{{item.actualPrice}}</span><span>会员</span></div>
+          <div class="txt4">{{item.day === 30 ? '月卡' : '年卡'}}</div>
+          <img class="w111h73" src="~/assets/image/activity/lottery/coupon-2.png" alt="">
+        </div>
+        <div v-for="item in paySupportType" :key="item" class="fnbc" @click="payType = item">
+          <div v-if="item === 'aliPay'" class="fnc">
+            <van-icon class="icon-pay" :name="require('~/assets/image/activity/lottery/alipay.png')" />
+            <span class="txt5">支付宝支付</span>
+          </div>
+          <div v-else class="fnc">
+            <van-icon class="icon-pay" :name="require('~/assets/image/activity/lottery/wx.png')" />
+            <span class="txt5">微信支付</span>
+          </div>
+          <van-icon :name="payType === item ? require('~/assets/image/activity/lottery/select-round-icon.png') : require('~/assets/image/activity/lottery/unselect-round-icon.png')" size="24" />
+        </div>
+        <img class="w304h62" src="~/assets/image/activity/lottery/pay-btn.png" alt="" @click="createOrder">
+        <div class="txt6">开通前阅读并同意<a @click="showRule=true">购买协议</a></div>
+      </div>
+    </van-popup>
+    <van-popup v-model="show" closeable close-icon-position="top-right" round>
+      <div class="popup-view popup-view-leave">
+        <div class="txt1">确定离开吗</div>
+        <div class="txt6">离开后您将失去{{actualPrice}}年卡,24小时付款有效</div>
+        <div class="coupon-1 active">
+          <img class="coupon-select-icon" src="~/assets/image/activity/lottery/select-icon.png" alt="">
+          <div class="coupon-title"><span class="txt2">{{actualPrice}}</span><span>会员</span><span class="txt3">({{title}})</span></div>
+          <div class="txt4">年卡(已获得)</div>
+          <img class="w253h73" src="~/assets/image/activity/lottery/coupon-1.png" alt="">
+        </div>
+        <div class="fnbc">
+          <div class="btn-leave" @click="show=false">狠心离开</div>
+          <div class="btn-pay" @click="createOrder">立即购买</div>
+        </div>
+      </div>
+    </van-popup>
+    <van-popup v-model="showRule" closeable close-icon-position="top-right" round>
+      <div class="popup-view popup-view-leave" style="text-align: left;">
+        <div class="txt1">购买协议</div>
+        <div class="txt7">时长包使用规则</div>
+        <div class="txt6"> 年卡特惠云手机,按需补充时长包</div>
+        <div class="txt6">有效时间:时长用完前一直有效,支持跨月。</div>
+        <div class="txt6">可用范围:可续时长的机型</div>
+        <div class="txt6">生效方式:立即生效</div>
+        <div class="txt6">退订说明:立即生效产品,不支持退订</div>
+        <div class="txt7">产品说明</div>
+        <div class="txt6">1、生效方式:时长补充包订购后立即生效,直至时长用完则失效,用户可重复订购。</div>
+        <div class="txt6">2、时长使用顺序:优先使用年卡特惠包时长,年卡特惠包时长耗尽,自动使用时长包时长。</div>
+        <div class="txt6">3、年卡特惠包合约到期后,如时长补充包仍有时长,年卡特惠包所属云手机可继续使用至时长用尽。</div>
+        <div class="txt7">温馨提示:</div>
+        <div class="txt6">1、请您理解:通过任何不正当手段参与活动,如借助非自然流量/外挂工具;利用技术漏洞,恶意退款,批量注册账号、买号等搅乱平台管理秩序的行为,臂云科技有权限制/取消用户的活动资格,不予发放/撤销相关交易及福利内容。</div>
+        <div class="txt6">2、如有疑问请联系唔即云APP客服咨询。</div>
+      </div>
+    </van-popup>
+  </div>
+</template>
+
+<script>
+import { Toast } from 'vant'
+import RoundTurntable from './component/roundTurntable.vue'
+export default {
+  name: 'Lottery',
+  auth: false,
+  components: {
+    RoundTurntable
+  },
+  data() {
+    return {
+      showRule: false,
+      show: false,
+      showPay: false,
+      // 转盘上的奖品数据
+      prizeData: [
+        {
+          id: 1,
+          level: 29.9
+        },
+        {
+          id: 2,
+          level: 58
+        },
+        {
+          id: 3,
+          level: 9.9
+        },
+        {
+          id: 4,
+          level: 39.9
+        },
+        {
+          id: 5,
+          level: 378
+        },
+        {
+          id: 6,
+          level: 15.9
+        }
+      ],
+      // 转动的圈数
+      rotateCircle: 6,
+      // 转动需要持续的时间(s)
+      duringTime: 4.5,
+      // 转盘样式的选项
+      turntableStyleOption: {
+        // 背景色
+        prizeBgColors: ['#FFF9F8', '#FFECC9', '#FFF9F8', '#FFECC9', '#FFF9F8', '#FFECC9'],
+        // 转盘的外边框颜色
+        borderColor: '#FFD790'
+      },
+      // 中奖的奖品的index
+      prizeIndex: -1,
+      // 用来锁定转盘,避免同时多次点击转动
+      isLocking: false,
+      // 剩余抽奖次数
+      num: 2,
+      token: '',
+      activityId: '',
+      actualPrice: 0,
+      mealId: '',
+      selMealId: '',
+      paySupportType: [],
+      title: '',
+      payType: '',
+      mealList: [],
+      status: 0
+    }
+  },
+  async fetch() {
+    if (this.$userAgent.isAndroid) {
+      this.token = await window.native.getToken();
+    } else {
+      this.token = this.$route.query.token;
+    }
+  },
+  head: {
+    title: '年卡抽奖活动'
+  },
+  created() {
+    this.getLuckDrawActivity()
+    this.getMealInfo()
+  },
+  methods: {
+    async getMealInfo() {
+      const res = await this.$axios.$get('/pay/v2/meal/info?phoneType=SVIP');
+      this.mealList = res.data.list.filter(item => item.day === 30 || item.day === 365)
+    },
+    createOrder() {
+      if (this.$userAgent.isAndroid) {
+        window.native.startPay(1, this.mealId, 1);
+      }
+    },
+    async getLuckDrawActivity() {
+      const res = await this.$axios.$post('/activity/v1/member/luckDrawActivity');
+      this.activityId = res.data.activityId
+      this.status = res.data.status
+    },
+    // 开始抽奖
+    async startRotation() {
+      // 如果还不可以转动
+      if (!this.canBeRotated()) {
+        return false;
+      }
+      // 开始转动
+      // 先上锁
+      this.isLocking = true;
+      // 设置在哪里停下,应该与后台交互,这里随机抽取0~5
+      const res = await this.$axios.$post('/activity/v1/member/luckDraw?activityId=' + this.activityId, {}, { headers: { Authorization: this.token } });
+      if (res.status === 0) {
+        const index = this.prizeData.findIndex(item => item.level === res.data.actualPrice)
+        this.actualPrice = res.data.actualPrice
+        if (Number(localStorage.getItem('year-15-9')) !== 2 && this.actualPrice === 15.9) {
+          localStorage.setItem('year-15-9', 1)
+        }
+        if (Number(localStorage.getItem('year-9-9')) !== 2 && this.actualPrice === 9.9) {
+          localStorage.setItem('year-9-9', 1)
+        }
+        this.mealId = res.data.mealId
+        this.selMealId = res.data.mealId
+        this.paySupportType = res.data.paySupportType
+        this.payType = this.paySupportType[0]
+        this.title = res.data.title
+        this.prizeIndex = index;
+      } else {
+        return
+      }
+      // 成功后次数减少一次
+      this.num--;
+      // 告诉子组件,开始转动了
+      this.$refs.roundTurntable.rotate(this.prizeIndex);
+    },
+    // 已经转动完转盘触发的函数
+    endRotation() {
+      // 提示中奖
+      this.showPay = true
+      // 解锁
+      this.isLocking = false;
+    },
+    // 判断是否可以转动
+    canBeRotated() {
+      if (this.isLocking) {
+        return false;
+      }
+      if (this.status === 0) {
+        Toast({
+          message: '当前活动已过期',
+          position: 'top',
+        });
+        return false;
+      }
+      if (this.status === 2) {
+        Toast({
+          message: '当前活动未开启',
+          position: 'top',
+        });
+        return false;
+      }
+      if (this.status === 3) {
+        Toast({
+          message: '当前活动已结束',
+          position: 'top',
+        });
+        return false;
+      }
+      return true;
+    },
+    closed() {
+      if (Number(localStorage.getItem('year-15-9')) !== 2) {
+        this.show = true
+        localStorage.setItem('year-15-9', 2)
+      }
+      if (Number(localStorage.getItem('year-9-9')) !== 2) {
+        this.show = true
+        localStorage.setItem('year-9-9', 2)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.lottery-container {
+  background-color: #bbe5f2;
+  background-image: url('../../../assets/image/activity/lottery/bg.png');
+  background-size: contain;
+  min-height: 100vh;
+  overflow: hidden;
+  margin: 0 auto;
+}
+.lottery-swipe {
+  width: 188px;
+  height: 25px;
+  background: rgba($color: #000000, $alpha: 0.24);
+  border-radius: 0px 16px 16px 0px;
+  position: absolute;
+  top: 134px;
+  left: 0;
+  z-index: 1;
+}
+.lottery-swipe .van-swipe-item {
+  color: #ffffff;
+  font-size: 13px;
+  line-height: 25px;
+  text-align: center;
+}
+.w51h26 {
+  width: 51px;
+  height: 26px;
+  position: absolute;
+  top: 128px;
+  right: 0;
+  z-index: 2;
+}
+.roulette {
+  width: 372px;
+  height: 442px;
+  background-image: url('../../../assets/image/activity/lottery/roulette.png');
+  background-size: 100% 100%;
+  margin: 127px auto 0;
+  position: relative;
+}
+.arrow {
+  width: 122px;
+  height: 135px;
+  position: absolute;
+  top: 110px;
+  left: 125px;
+  background-image: url('../../../assets/image/activity/lottery/arrow.png');
+  background-size: 100% 100%;
+  z-index: 1;
+}
+.turntable {
+  position: absolute;
+  left: calc(50% - 144px);
+  top: 163px;
+  width: 288px;
+  height: 288px;
+}
+.turntable-name {
+  position: absolute;
+  left: 10px;
+  top: 20px;
+  width: calc(100% - 20px);
+  font-size: 20px;
+  font-weight: 600;
+  text-align: center;
+  color: #b8320d;
+}
+.fs15 {
+  font-size: 15px;
+}
+.turntable-img {
+  position: relative;
+  /*要居中就要50% - 宽度 / 2*/
+  left: calc(50% - 40px / 2);
+  top: 43px;
+  width: 52px;
+  height: 39px;
+  img {
+    display: inline-block;
+    width: 52px;
+    height: 39px;
+  }
+}
+.start-btn {
+  width: 276px;
+  height: 55px;
+  position: absolute;
+  bottom: 16px;
+  left: calc(50% - 138px);
+}
+.num {
+  margin-top: 8px;
+  text-align: center;
+  font-size: 14px;
+  color: #333333;
+  line-height: 20px;
+}
+.popup-view {
+  width: 324px;
+  padding: 20px 10px;
+  box-shadow: 0px 1px 20px 0px rgba(0, 0, 0, 0.1);
+  background: #ffffff;
+  text-align: center;
+}
+.txt1 {
+  font-size: 18px;
+  font-weight: 600;
+  color: #333333;
+  line-height: 25px;
+  text-align: center;
+}
+.coupon-1 {
+  width: 286px;
+  height: 106px;
+  box-sizing: border-box;
+  margin: 11px auto 0;
+  position: relative;
+  border-radius: 13px;
+  border: 2px solid;
+  border-color: #e8e8e8;
+  box-sizing: border-box;
+  &::before,
+  &::after {
+    background-color: white;
+    border-radius: 50%;
+    content: '';
+    width: 20px;
+    height: 20px;
+    position: absolute;
+    top: 43px;
+    z-index: 1;
+  }
+  &::before {
+    border-right: 2px solid;
+    border-color: #e8e8e8;
+    left: -12px;
+    border-radius: 0 10px 10px 0;
+  }
+
+  &::after {
+    border-left: 2px solid;
+    border-color: #e8e8e8;
+    right: -12px;
+    border-radius: 10px 0 0 10px;
+  }
+}
+.coupon-1.active,
+.coupon-2.active {
+  border-left: 2px solid;
+  border-color: #d96a57 !important;
+  &::before {
+    border-right: 2px solid;
+    border-color: #d96a57;
+  }
+
+  &::after {
+    border-left: 2px solid;
+    border-color: #d96a57;
+  }
+}
+.coupon-title {
+  color: #362113;
+  font-size: 12px;
+  text-align: center;
+  z-index: 1;
+  position: absolute;
+  top: 23px;
+  width: 100%;
+}
+.txt2 {
+  font-weight: 600;
+  font-size: 24px;
+}
+.txt3 {
+  color: #db6857;
+}
+.txt4 {
+  position: absolute;
+  top: 68px;
+  width: 100%;
+  text-align: center;
+  font-size: 14px;
+  font-weight: 600;
+  color: #ffffff;
+  line-height: 20px;
+  z-index: 1;
+}
+.coupon-select-icon {
+  width: 34px;
+  height: 20px;
+  position: absolute;
+  top: 0;
+  right: 0;
+  z-index: 2;
+}
+.w253h73 {
+  width: 253px;
+  height: 73px;
+  position: absolute;
+  top: 15px;
+  left: 15px;
+}
+.coupon-2 {
+  display: inline-block;
+  width: 138px;
+  height: 106px;
+  box-sizing: border-box;
+  margin: 11px 4px 0;
+  position: relative;
+  border-radius: 13px;
+  box-sizing: border-box;
+  border: 2px solid;
+  border-color: #e8e8e8;
+  &::before,
+  &::after {
+    background-color: white;
+    border-radius: 50%;
+    content: '';
+    width: 20px;
+    height: 20px;
+    position: absolute;
+    top: 43px;
+    z-index: 1;
+  }
+  &::before {
+    border-right: 2px solid;
+    border-color: #e8e8e8;
+    left: -12px;
+    border-radius: 0 10px 10px 0;
+  }
+
+  &::after {
+    border-left: 2px solid;
+    border-color: #e8e8e8;
+    right: -12px;
+    border-radius: 10px 0 0 10px;
+  }
+}
+.w111h73 {
+  width: 111px;
+  height: 73px;
+  position: absolute;
+  top: 15px;
+  left: 12px;
+}
+.txt5 {
+  font-size: 16px;
+  color: #333333;
+  margin-left: 7px;
+}
+.icon-pay {
+  font-size: 26px;
+  line-height: inherit;
+}
+.fnc {
+  display: flex;
+  align-items: center;
+}
+.fnbc {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  height: 50px;
+  padding: 0 10px;
+}
+.w304h62 {
+  width: 304px;
+  height: 62px;
+  margin: 0 auto;
+}
+.txt6 {
+  color: #333333;
+  font-size: 11px;
+  line-height: 16px;
+  a {
+    color: #ff7656;
+    text-decoration: underline;
+  }
+}
+.popup-view-leave {
+  background: linear-gradient(180deg, #ffffff 0%, #f7f1e3 100%);
+}
+.btn-leave {
+  width: 140px;
+  height: 48px;
+  background: linear-gradient(180deg, #ffdb94 0%, #ff9539 100%);
+  box-shadow: 0px 2px 7px 0px rgba(237, 76, 0, 0.17),
+    inset 0px -5px 0px 0px #ff7700;
+  border-radius: 24px;
+  font-size: 18px;
+  font-weight: 600;
+  color: #ffffff;
+  text-align: center;
+  line-height: 43px;
+  margin-top: 15px;
+}
+.btn-pay {
+  width: 140px;
+  height: 48px;
+  background: linear-gradient(180deg, #ff9278 0%, #ff562f 100%);
+  box-shadow: 0px 2px 7px 0px rgba(237, 76, 0, 0.17),
+    inset 0px -5px 0px 0px #f62e00;
+  border-radius: 24px;
+  border-radius: 24px;
+  font-size: 18px;
+  font-weight: 600;
+  color: #ffffff;
+  text-align: center;
+  line-height: 43px;
+  margin-top: 15px;
+}
+.txt7 {
+  font-size: 14px;
+  line-height: 18px;
+  margin-top: 10px;
+}
+</style>

+ 613 - 0
pages/activity/lottery/pc.vue

@@ -0,0 +1,613 @@
+<template>
+  <div class="lottery-container">
+    <van-swipe :autoplay="3000" class="lottery-swipe" vertical :show-indicators="false">
+      <van-swipe-item>有23245个用户 购买15.9年卡</van-swipe-item>
+      <van-swipe-item>有23245个用户 购买15.9年卡</van-swipe-item>
+      <van-swipe-item>有23245个用户 购买15.9年卡</van-swipe-item>
+      <van-swipe-item>有23245个用户 购买15.9年卡</van-swipe-item>
+    </van-swipe>
+    <img class="w51h26" src="~/assets/image/activity/lottery/rule.png" alt="" @click="showRule=true">
+    <div class="roulette">
+      <div class="arrow" @click="startRotation"></div>
+      <img class="start-btn" src="~/assets/image/activity/lottery/start-btn.png" alt="" @click="startRotation">
+    </div>
+    <RoundTurntable ref="roundTurntable" :prize-data="prizeData" :rotate-circle="rotateCircle" :during-time="duringTime" :turntable-style-option="turntableStyleOption" class="turntable" @endRotation="endRotation">
+      <template slot="item" slot-scope="scope">
+        <div class="turntable-name"><span class="fs15">¥</span>{{ scope.item.level }}</div>
+        <div class="turntable-img">
+          <img src="~/assets/image/activity/lottery/yearCard.png" />
+        </div>
+      </template>
+    </RoundTurntable>
+    <div class="num">剩余机会{{num}}次</div>
+    <van-popup v-model="showPay" closeable close-icon-position="top-right" round :close-on-click-overlay="false" @closed="closed">
+      <div class="popup-view">
+        <div class="txt1">恭喜你获得{{actualPrice}}年卡</div>
+        <div :class="selMealId===mealId ? 'coupon-1 active' : 'coupon-1'" @click="selMealId=mealId">
+          <img v-if="selMealId===mealId" class="coupon-select-icon" src="~/assets/image/activity/lottery/select-icon.png" alt="">
+          <img v-else class="coupon-select-icon" src="~/assets/image/activity/lottery/unselect-icon.png" alt="">
+          <div class="coupon-title"><span class="txt2">{{actualPrice}}</span><span>会员</span><span class="txt3">({{title}})</span></div>
+          <div class="txt4">年卡(已获得)</div>
+          <img class="w253h73" src="~/assets/image/activity/lottery/coupon-1.png" alt="">
+        </div>
+        <div v-for="item in mealList" :key="item.id" :class="selMealId===item.id ? 'coupon-2 active' : 'coupon-2'" @click="selMealId=item.id">
+          <img v-if="selMealId===item.id" class="coupon-select-icon" src="~/assets/image/activity/lottery/select-icon.png" alt="">
+          <img v-else class="coupon-select-icon" src="~/assets/image/activity/lottery/unselect-icon.png" alt="">
+          <div class="coupon-title"><span class="txt2">{{item.actualPrice}}</span><span>会员</span></div>
+          <div class="txt4">{{item.day === 30 ? '月卡' : '年卡'}}</div>
+          <img class="w111h73" src="~/assets/image/activity/lottery/coupon-2.png" alt="">
+        </div>
+        <div v-for="item in paySupportType" :key="item" class="fnbc" @click="payType = item">
+          <div v-if="item === 'aliPay'" class="fnc">
+            <van-icon class="icon-pay" :name="require('~/assets/image/activity/lottery/alipay.png')" />
+            <span class="txt5">支付宝支付</span>
+          </div>
+          <div v-else class="fnc">
+            <van-icon class="icon-pay" :name="require('~/assets/image/activity/lottery/wx.png')" />
+            <span class="txt5">微信支付</span>
+          </div>
+          <van-icon :name="payType === item ? require('~/assets/image/activity/lottery/select-round-icon.png') : require('~/assets/image/activity/lottery/unselect-round-icon.png')" size="24" />
+        </div>
+        <img class="w304h62" src="~/assets/image/activity/lottery/pay-btn.png" alt="" @click="createOrder">
+        <div class="txt6">开通前阅读并同意<a @click="showRule=true">购买协议</a></div>
+      </div>
+    </van-popup>
+    <van-popup v-model="show" closeable close-icon-position="top-right" round>
+      <div class="popup-view popup-view-leave">
+        <div class="txt1">确定离开吗</div>
+        <div class="txt6">离开后您将失去{{actualPrice}}年卡,24小时付款有效</div>
+        <div class="coupon-1 active">
+          <img class="coupon-select-icon" src="~/assets/image/activity/lottery/select-icon.png" alt="">
+          <div class="coupon-title"><span class="txt2">{{actualPrice}}</span><span>会员</span><span class="txt3">({{title}})</span></div>
+          <div class="txt4">年卡(已获得)</div>
+          <img class="w253h73" src="~/assets/image/activity/lottery/coupon-1.png" alt="">
+        </div>
+        <div class="fnbc">
+          <div class="btn-leave" @click="show=false">狠心离开</div>
+          <div class="btn-pay" @click="createOrder">立即购买</div>
+        </div>
+      </div>
+    </van-popup>
+    <van-popup v-model="showRule" closeable close-icon-position="top-right" round>
+      <div class="popup-view popup-view-leave" style="text-align: left;">
+        <div class="txt1">购买协议</div>
+        <div class="txt7">时长包使用规则</div>
+        <div class="txt6"> 年卡特惠云手机,按需补充时长包</div>
+        <div class="txt6">有效时间:时长用完前一直有效,支持跨月。</div>
+        <div class="txt6">可用范围:可续时长的机型</div>
+        <div class="txt6">生效方式:立即生效</div>
+        <div class="txt6">退订说明:立即生效产品,不支持退订</div>
+        <div class="txt7">产品说明</div>
+        <div class="txt6">1、生效方式:时长补充包订购后立即生效,直至时长用完则失效,用户可重复订购。</div>
+        <div class="txt6">2、时长使用顺序:优先使用年卡特惠包时长,年卡特惠包时长耗尽,自动使用时长包时长。</div>
+        <div class="txt6">3、年卡特惠包合约到期后,如时长补充包仍有时长,年卡特惠包所属云手机可继续使用至时长用尽。</div>
+        <div class="txt7">温馨提示:</div>
+        <div class="txt6">1、请您理解:通过任何不正当手段参与活动,如借助非自然流量/外挂工具;利用技术漏洞,恶意退款,批量注册账号、买号等搅乱平台管理秩序的行为,臂云科技有权限制/取消用户的活动资格,不予发放/撤销相关交易及福利内容。</div>
+        <div class="txt6">2、如有疑问请联系唔即云APP客服咨询。</div>
+      </div>
+    </van-popup>
+  </div>
+</template>
+
+<script>
+import { Toast } from 'vant'
+import RoundTurntable from './component/roundTurntable.vue'
+export default {
+  name: 'Lottery',
+  auth: false,
+  components: {
+    RoundTurntable
+  },
+  data() {
+    return {
+      showRule: false,
+      show: false,
+      showPay: false,
+      // 转盘上的奖品数据
+      prizeData: [
+        {
+          id: 1,
+          level: 29.9
+        },
+        {
+          id: 2,
+          level: 58
+        },
+        {
+          id: 3,
+          level: 9.9
+        },
+        {
+          id: 4,
+          level: 39.9
+        },
+        {
+          id: 5,
+          level: 378
+        },
+        {
+          id: 6,
+          level: 15.9
+        }
+      ],
+      // 转动的圈数
+      rotateCircle: 6,
+      // 转动需要持续的时间(s)
+      duringTime: 4.5,
+      // 转盘样式的选项
+      turntableStyleOption: {
+        // 背景色
+        prizeBgColors: ['#FFF9F8', '#FFECC9', '#FFF9F8', '#FFECC9', '#FFF9F8', '#FFECC9'],
+        // 转盘的外边框颜色
+        borderColor: '#FFD790'
+      },
+      // 中奖的奖品的index
+      prizeIndex: -1,
+      // 用来锁定转盘,避免同时多次点击转动
+      isLocking: false,
+      // 剩余抽奖次数
+      num: 2,
+      token: '',
+      activityId: '',
+      actualPrice: 0,
+      mealId: '',
+      selMealId: '',
+      paySupportType: [],
+      title: '',
+      payType: '',
+      mealList: [],
+      status: 0
+    }
+  },
+  async fetch() {
+    if (this.$userAgent.isAndroid) {
+      this.token = await window.native.getToken();
+    } else {
+      this.token = this.$route.query.token;
+    }
+  },
+  head: {
+    title: '年卡抽奖活动'
+  },
+  created() {
+    this.getLuckDrawActivity()
+    this.getMealInfo()
+  },
+  methods: {
+    async getMealInfo() {
+      const res = await this.$axios.$get('/pay/v2/meal/info?phoneType=SVIP');
+      this.mealList = res.data.list.filter(item => item.day === 30 || item.day === 365)
+    },
+    createOrder() {
+      if (this.$userAgent.isAndroid) {
+        window.native.startPay(1, this.mealId, 1);
+      }
+    },
+    async getLuckDrawActivity() {
+      const res = await this.$axios.$post('/activity/v1/member/luckDrawActivity');
+      this.activityId = res.data.activityId
+      this.status = res.data.status
+    },
+    // 开始抽奖
+    async startRotation() {
+      // 如果还不可以转动
+      if (!this.canBeRotated()) {
+        return false;
+      }
+      // 开始转动
+      // 先上锁
+      this.isLocking = true;
+      // 设置在哪里停下,应该与后台交互,这里随机抽取0~5
+      const res = await this.$axios.$post('/activity/v1/member/luckDraw?activityId=' + this.activityId, {}, { headers: { Authorization: this.token } });
+      if (res.status === 0) {
+        const index = this.prizeData.findIndex(item => item.level === res.data.actualPrice)
+        this.actualPrice = res.data.actualPrice
+        if (Number(localStorage.getItem('year-15-9')) !== 2 && this.actualPrice === 15.9) {
+          localStorage.setItem('year-15-9', 1)
+        }
+        if (Number(localStorage.getItem('year-9-9')) !== 2 && this.actualPrice === 9.9) {
+          localStorage.setItem('year-9-9', 1)
+        }
+        this.mealId = res.data.mealId
+        this.selMealId = res.data.mealId
+        this.paySupportType = res.data.paySupportType
+        this.payType = this.paySupportType[0]
+        this.title = res.data.title
+        this.prizeIndex = index;
+      } else {
+        return
+      }
+      // 成功后次数减少一次
+      this.num--;
+      // 告诉子组件,开始转动了
+      this.$refs.roundTurntable.rotate(this.prizeIndex);
+    },
+    // 已经转动完转盘触发的函数
+    endRotation() {
+      // 提示中奖
+      this.showPay = true
+      // 解锁
+      this.isLocking = false;
+    },
+    // 判断是否可以转动
+    canBeRotated() {
+      if (this.isLocking) {
+        return false;
+      }
+      if (this.status === 0) {
+        Toast({
+          message: '当前活动已过期',
+          position: 'top',
+          className: 'lottery-container-toast'
+        });
+        return false;
+      }
+      if (this.status === 2) {
+        Toast({
+          message: '当前活动未开启',
+          position: 'top',
+          className: 'lottery-container-toast'
+        });
+        return false;
+      }
+      if (this.status === 3) {
+        Toast({
+          message: '当前活动已结束',
+          position: 'top',
+          className: 'lottery-container-toast'
+        });
+        return false;
+      }
+      return true;
+    },
+    closed() {
+      if (Number(localStorage.getItem('year-15-9')) !== 2) {
+        this.show = true
+        localStorage.setItem('year-15-9', 2)
+      }
+      if (Number(localStorage.getItem('year-9-9')) !== 2) {
+        this.show = true
+        localStorage.setItem('year-9-9', 2)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+@media (min-width: 0px) {
+  .lottery-container-toast {
+    &.van-toast--text {
+      min-width: 94px;
+      padding: 8px 12px;
+    }
+    &.van-toast {
+      font-size: 13px;
+      line-height: 21px;
+    }
+  }
+}
+</style>
+
+<style lang="scss" scoped>
+@media (min-width: 0px) {
+  .lottery-container {
+    background-color: #bbe5f2;
+    background-image: url('../../../assets/image/activity/lottery/bg.png');
+    background-size: contain;
+    min-height: 100vh;
+    overflow: hidden;
+    max-width: 500px;
+    margin: 0 auto;
+    position: relative;
+  }
+  .lottery-swipe {
+    width: 188px;
+    height: 25px;
+    background: rgba($color: #000000, $alpha: 0.24);
+    border-radius: 0px 16px 16px 0px;
+    position: absolute;
+    top: 134px;
+    left: 0;
+    z-index: 1;
+  }
+  .lottery-swipe .van-swipe-item {
+    color: #ffffff;
+    font-size: 13px;
+    line-height: 25px;
+    text-align: center;
+  }
+  .w51h26 {
+    width: 51px;
+    height: 26px;
+    position: absolute;
+    top: 128px;
+    right: 0;
+    z-index: 2;
+  }
+  .roulette {
+    width: 372px;
+    height: 442px;
+    background-image: url('../../../assets/image/activity/lottery/roulette.png');
+    background-size: 100% 100%;
+    margin: 127px auto 0;
+    position: relative;
+  }
+  .arrow {
+    width: 122px;
+    height: 135px;
+    position: absolute;
+    top: 110px;
+    left: 125px;
+    background-image: url('../../../assets/image/activity/lottery/arrow.png');
+    background-size: 100% 100%;
+    z-index: 1;
+  }
+  .turntable {
+    position: absolute;
+    left: calc(50% - 144px);
+    top: 163px;
+    width: 288px;
+    height: 288px;
+  }
+  .turntable-name {
+    position: absolute;
+    left: 10px;
+    top: 20px;
+    width: calc(100% - 20px);
+    font-size: 20px;
+    font-weight: 600;
+    text-align: center;
+    color: #b8320d;
+  }
+  .fs15 {
+    font-size: 15px;
+  }
+  .turntable-img {
+    position: relative;
+    /*要居中就要50% - 宽度 / 2*/
+    left: calc(50% - 40px / 2);
+    top: 43px;
+    width: 52px;
+    height: 39px;
+    img {
+      display: inline-block;
+      width: 52px;
+      height: 39px;
+    }
+  }
+  .start-btn {
+    width: 276px;
+    height: 55px;
+    position: absolute;
+    bottom: 16px;
+    left: calc(50% - 138px);
+  }
+  .num {
+    margin-top: 8px;
+    text-align: center;
+    font-size: 14px;
+    color: #333333;
+    line-height: 20px;
+  }
+  .popup-view {
+    width: 324px;
+    padding: 20px 10px;
+    box-shadow: 0px 1px 20px 0px rgba(0, 0, 0, 0.1);
+    background: #ffffff;
+    text-align: center;
+  }
+  .txt1 {
+    font-size: 18px;
+    font-weight: 600;
+    color: #333333;
+    line-height: 25px;
+    text-align: center;
+  }
+  .coupon-1 {
+    width: 286px;
+    height: 106px;
+    box-sizing: border-box;
+    margin: 11px auto 0;
+    position: relative;
+    border-radius: 13px;
+    border: 2px solid;
+    border-color: #e8e8e8;
+    box-sizing: border-box;
+    &::before,
+    &::after {
+      background-color: white;
+      border-radius: 50%;
+      content: '';
+      width: 20px;
+      height: 20px;
+      position: absolute;
+      top: 43px;
+      z-index: 1;
+    }
+    &::before {
+      border-right: 2px solid;
+      border-color: #e8e8e8;
+      left: -12px;
+      border-radius: 0 10px 10px 0;
+    }
+
+    &::after {
+      border-left: 2px solid;
+      border-color: #e8e8e8;
+      right: -12px;
+      border-radius: 10px 0 0 10px;
+    }
+  }
+  .coupon-1.active,
+  .coupon-2.active {
+    border-left: 2px solid;
+    border-color: #d96a57 !important;
+    &::before {
+      border-right: 2px solid;
+      border-color: #d96a57;
+    }
+
+    &::after {
+      border-left: 2px solid;
+      border-color: #d96a57;
+    }
+  }
+  .coupon-title {
+    color: #362113;
+    font-size: 12px;
+    text-align: center;
+    z-index: 1;
+    position: absolute;
+    top: 23px;
+    width: 100%;
+  }
+  .txt2 {
+    font-weight: 600;
+    font-size: 24px;
+  }
+  .txt3 {
+    color: #db6857;
+  }
+  .txt4 {
+    position: absolute;
+    top: 68px;
+    width: 100%;
+    text-align: center;
+    font-size: 14px;
+    font-weight: 600;
+    color: #ffffff;
+    line-height: 20px;
+    z-index: 1;
+  }
+  .coupon-select-icon {
+    width: 34px;
+    height: 20px;
+    position: absolute;
+    top: 0;
+    right: 0;
+    z-index: 2;
+  }
+  .w253h73 {
+    width: 253px;
+    height: 73px;
+    position: absolute;
+    top: 15px;
+    left: 15px;
+  }
+  .coupon-2 {
+    display: inline-block;
+    width: 138px;
+    height: 106px;
+    box-sizing: border-box;
+    margin: 11px 4px 0;
+    position: relative;
+    border-radius: 13px;
+    box-sizing: border-box;
+    border: 2px solid;
+    border-color: #e8e8e8;
+    &::before,
+    &::after {
+      background-color: white;
+      border-radius: 50%;
+      content: '';
+      width: 20px;
+      height: 20px;
+      position: absolute;
+      top: 43px;
+      z-index: 1;
+    }
+    &::before {
+      border-right: 2px solid;
+      border-color: #e8e8e8;
+      left: -12px;
+      border-radius: 0 10px 10px 0;
+    }
+
+    &::after {
+      border-left: 2px solid;
+      border-color: #e8e8e8;
+      right: -12px;
+      border-radius: 10px 0 0 10px;
+    }
+  }
+  .w111h73 {
+    width: 111px;
+    height: 73px;
+    position: absolute;
+    top: 15px;
+    left: 12px;
+  }
+  .txt5 {
+    font-size: 16px;
+    color: #333333;
+    margin-left: 7px;
+  }
+  .icon-pay {
+    font-size: 26px;
+    line-height: inherit;
+  }
+  .fnc {
+    display: flex;
+    align-items: center;
+  }
+  .fnbc {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: 50px;
+    padding: 0 10px;
+  }
+  .w304h62 {
+    width: 304px;
+    height: 62px;
+    margin: 0 auto;
+  }
+  .txt6 {
+    color: #333333;
+    font-size: 11px;
+    line-height: 16px;
+    a {
+      color: #ff7656;
+      text-decoration: underline;
+    }
+  }
+  .popup-view-leave {
+    background: linear-gradient(180deg, #ffffff 0%, #f7f1e3 100%);
+  }
+  .btn-leave {
+    width: 140px;
+    height: 48px;
+    background: linear-gradient(180deg, #ffdb94 0%, #ff9539 100%);
+    box-shadow: 0px 2px 7px 0px rgba(237, 76, 0, 0.17),
+      inset 0px -5px 0px 0px #ff7700;
+    border-radius: 24px;
+    font-size: 18px;
+    font-weight: 600;
+    color: #ffffff;
+    text-align: center;
+    line-height: 43px;
+    margin-top: 15px;
+  }
+  .btn-pay {
+    width: 140px;
+    height: 48px;
+    background: linear-gradient(180deg, #ff9278 0%, #ff562f 100%);
+    box-shadow: 0px 2px 7px 0px rgba(237, 76, 0, 0.17),
+      inset 0px -5px 0px 0px #f62e00;
+    border-radius: 24px;
+    border-radius: 24px;
+    font-size: 18px;
+    font-weight: 600;
+    color: #ffffff;
+    text-align: center;
+    line-height: 43px;
+    margin-top: 15px;
+  }
+  .txt7 {
+    font-size: 14px;
+    line-height: 18px;
+    margin-top: 10px;
+  }
+}
+</style>

+ 3 - 0
plugins/vant.js

@@ -0,0 +1,3 @@
+import Vue from "vue";
+import Vant from "vant";
+Vue.use(Vant);