reel.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. <template>
  2. <view>
  3. <scroll-view
  4. class="scroll-wrapper"
  5. :style="{ top: top + 'px' }"
  6. scroll-y
  7. @scrolltolower="loadMore"
  8. >
  9. <view class="notice marginX22">
  10. 重要通知:魔天轮将于7月26日24:00下线,请各位魔主及时使用门票,届时门票将清零!
  11. </view>
  12. <view class="paddingX22 flex-align-between paddingY10">
  13. <image
  14. :src="resource.weal_reel_rule_btn"
  15. webp
  16. style="width: 188rpx; height: 68rpx"
  17. @click="$refs.rule.show()"
  18. />
  19. <view class="relative" style="width: 176rpx; height: 56rpx">
  20. <image
  21. :src="resource.weal_reel_ticket"
  22. webp
  23. style="width: 176rpx; height: 56rpx"
  24. />
  25. <view class="ticket translateY">{{ tickets }}</view>
  26. </view>
  27. </view>
  28. <view class="paddingX32 flex-align-end paddingB10">
  29. <view class="color-white font4 underline relative">
  30. 进群领门票
  31. <cell
  32. class="group-btn"
  33. url="https://work.weixin.qq.com/gm/140cdeace2d2c03b35d693b1b755b815"
  34. />
  35. </view>
  36. </view>
  37. <view class="reel-wrapper" v-if="data">
  38. <image :src="resource.weal_bg_reel_bottom" class="bottom translateX" />
  39. <image v-if="titleImg" :src="titleImg" class="title translateX" mode="heightFix" />
  40. <view class="top flex-align-center">
  41. <image :src="resource.weal_bg_reel_top2" webp class="bg" />
  42. <view class="inner-wrapper" :animation="animationData">
  43. <image
  44. :src="resource.weal_bg_reel_inner_right"
  45. webp
  46. class="inner translateXY"
  47. />
  48. <view class="relative width100 height100">
  49. <view
  50. v-for="(item, index) in data"
  51. :key="item.spuId"
  52. :class="[`award_${index + 1}`]"
  53. class="award flex-align-center"
  54. >
  55. <image
  56. :src="item.spu.cover"
  57. mode="aspectFit"
  58. style="width: 49px; height: 49px"
  59. />
  60. </view>
  61. </view>
  62. </view>
  63. <image
  64. :src="resource.weal_reel_pointer"
  65. webp
  66. class="point translateXY"
  67. @click="start"
  68. />
  69. </view>
  70. </view>
  71. <view class="paddingT25">
  72. <view class="flex-align-center marginB15">
  73. <image :src="resource.weal_reel_record" style="width: 372rpx; height: 30rpx" />
  74. </view>
  75. <view v-for="(item, index) in tableData" class="cell flex-align" :key="index">
  76. <image :src="item.avatar || resource.defaultAvatar" class="icon" />
  77. <view class="font2 color-white marginL12 flex1">{{ item.nickname }}</view>
  78. <view class="marginL20 font2 color-white line-ellipsis" style="width: 40%">
  79. {{ item.name }}
  80. </view>
  81. <image :src="item.cover" class="image marginL20" />
  82. </view>
  83. </view>
  84. </scroll-view>
  85. <reel-result ref="result" />
  86. <reel-rule ref="rule" />
  87. </view>
  88. </template>
  89. <script>
  90. import pageMixin from './../../mixin/page'
  91. import resource from '@/utils/resource'
  92. import reelResult from './reel_result'
  93. import reelRule from './reel_rule'
  94. export default {
  95. mixins: [pageMixin],
  96. components: { reelResult, reelRule },
  97. props: {
  98. statusBarHeight: Number
  99. },
  100. data() {
  101. return {
  102. resource,
  103. requesting: false,
  104. reelRequesting: false,
  105. isRefreshClear: false,
  106. animationData: null,
  107. data: null,
  108. titleImg: '',
  109. tickets: 0
  110. }
  111. },
  112. computed: {
  113. top() {
  114. return this.statusBarHeight + uni.upx2px(72) + 45
  115. }
  116. },
  117. mounted() {
  118. this.init(true)
  119. this.animation = wx.createAnimation({
  120. timingFunction: 'ease'
  121. })
  122. },
  123. methods: {
  124. init(loading) {
  125. this.getTicker()
  126. this.getDetail()
  127. this.refresh()
  128. },
  129. async getTicker() {
  130. const res = await this.$service.wallet.info('LUCK_WHEEL_TICKET')
  131. res && (this.tickets = res.balance)
  132. },
  133. async getDetail() {
  134. const res = await this.$service.weal.reelDetail(1)
  135. if (res) {
  136. this.titleImg = res.cover
  137. if (res.luckWheelGoodsList && res.luckWheelGoodsList.length > 0) {
  138. this.data = res.luckWheelGoodsList
  139. } else {
  140. this.data = null
  141. }
  142. }
  143. },
  144. async start() {
  145. if (!this.$common.checkLogin()) return
  146. if (!this.tickets || this.tickets <= 0) {
  147. this.$message.warn('您的门票不足')
  148. return
  149. }
  150. if (this.reelRequesting) {
  151. this.$message.warn('请不要重复点击')
  152. return
  153. }
  154. this.reelRequesting = true
  155. const res = await this.$service.weal.reelJoin(1)
  156. this.getTicker()
  157. if (res.success) {
  158. let index = this.getIndex(res.data.spuId)
  159. if (index === -1) {
  160. this.$message.error('系统异常,请联系客服处理')
  161. this.reelRequesting = false
  162. return
  163. }
  164. this.startAnimal(index)
  165. setTimeout(() => {
  166. this.reelRequesting = false
  167. this.refresh()
  168. this.$refs.result.show(this.data[index - 1].spu)
  169. setTimeout(() => {
  170. this.rotateNormal()
  171. }, 200)
  172. }, 4100)
  173. } else {
  174. this.$message.error(res.msg)
  175. this.reelRequesting = false
  176. }
  177. },
  178. getIndex(spuId) {
  179. for (let i = 0; i < this.data.length; i++) {
  180. if (this.data[i].spuId === spuId) {
  181. return i + 1
  182. }
  183. }
  184. return -1
  185. },
  186. rotateNormal() {
  187. this.animation.rotate(0).step({
  188. duration: 0
  189. })
  190. this.animationData = this.animation.export()
  191. },
  192. startAnimal(number) {
  193. this.rotateNormal()
  194. let offset = -Math.floor(Math.random() * 40 + 5)
  195. setTimeout(() => {
  196. this.animation.rotate(360 * 3 + (-60 * (number - 1) + offset)).step({
  197. duration: 4000
  198. })
  199. this.animationData = this.animation.export()
  200. }, 50)
  201. },
  202. async loadData(loading = false) {
  203. this.requesting = true
  204. const res = await this.$service.weal.reelList(1, this.pageNum, this.pageSize)
  205. setTimeout(() => {
  206. this.requesting = false
  207. }, 1000)
  208. return res
  209. }
  210. }
  211. }
  212. </script>
  213. <style lang="scss" scoped>
  214. .scroll-wrapper {
  215. position: fixed;
  216. left: 0;
  217. right: 0;
  218. bottom: 0;
  219. }
  220. .notice {
  221. height: 106rpx;
  222. background: rgba(0, 0, 0, 0.3);
  223. color: red;
  224. font-size: 32rpx;
  225. border-radius: 32rpx;
  226. padding: 10rpx 22rpx 0;
  227. }
  228. .ticket {
  229. position: absolute;
  230. right: 26rpx;
  231. color: #fff;
  232. font-size: 32rpx;
  233. font-weight: bold;
  234. }
  235. .reel-wrapper {
  236. margin: 0 auto;
  237. position: relative;
  238. width: 284px;
  239. height: 350px;
  240. .top {
  241. width: 284px;
  242. height: 284px;
  243. position: relative;
  244. .bg {
  245. position: absolute;
  246. left: 0;
  247. top: 0;
  248. width: 284px;
  249. height: 284px;
  250. }
  251. .inner-wrapper {
  252. position: relative;
  253. width: 233px;
  254. height: 233px;
  255. .inner {
  256. position: absolute;
  257. width: 233px;
  258. height: 233px;
  259. }
  260. .award {
  261. position: absolute;
  262. left: 50%;
  263. top: 50%;
  264. width: 54px;
  265. height: 54px;
  266. margin-top: -27px;
  267. margin-left: -27px;
  268. &.award_1 {
  269. transform: translate(40px, -72px) rotateZ(30deg);
  270. }
  271. &.award_2 {
  272. transform: translateX(80px) rotateZ(90deg);
  273. }
  274. &.award_3 {
  275. transform: translate(40px, 72px) rotateZ(150deg);
  276. }
  277. &.award_4 {
  278. transform: translate(-40px, 72px) rotateZ(210deg);
  279. }
  280. &.award_5 {
  281. transform: translateX(-80px) rotateZ(270deg);
  282. }
  283. &.award_6 {
  284. transform: translate(-40px, -72px) rotateZ(330deg);
  285. }
  286. }
  287. }
  288. .point {
  289. position: absolute;
  290. width: 124px;
  291. height: 124px;
  292. }
  293. }
  294. .bottom {
  295. width: 227px;
  296. height: 156px;
  297. position: absolute;
  298. bottom: 0;
  299. }
  300. .title {
  301. position: absolute;
  302. bottom: 13px;
  303. height: 22px;
  304. width: 0;
  305. }
  306. }
  307. .cell {
  308. padding: 0 16rpx 0 40rpx;
  309. margin: 0 28rpx 20rpx 28rpx;
  310. height: 116rpx;
  311. border-radius: 8rpx;
  312. background: rgba(34, 35, 53, 0.6);
  313. border: 1px solid rgba(255, 255, 255, 0.1);
  314. .icon {
  315. width: 52rpx;
  316. height: 52rpx;
  317. border-radius: 20rpx;
  318. }
  319. .image {
  320. width: 84rpx;
  321. height: 84rpx;
  322. border-radius: 8rpx;
  323. }
  324. }
  325. .group-btn {
  326. position: absolute;
  327. left: 0;
  328. top: 0;
  329. right: 0;
  330. bottom: 0;
  331. opacity: 0;
  332. }
  333. </style>