Browse Source

幸运大转盘页面

zhanghui 7 months ago
parent
commit
5beb593243
42 changed files with 2925 additions and 93 deletions
  1. 4 0
      .hbuilderx/launch.json
  2. 24 0
      .idea/inspectionProfiles/Project_Default.xml
  3. 201 0
      components/@lucky-canvas/uni/LICENSE
  4. 138 0
      components/@lucky-canvas/uni/README.md
  5. 317 0
      components/@lucky-canvas/uni/lucky-grid.vue
  6. 255 0
      components/@lucky-canvas/uni/lucky-wheel.vue
  7. 23 0
      components/@lucky-canvas/uni/package.json
  8. 214 0
      components/@lucky-canvas/uni/slot-machine.vue
  9. 82 0
      components/@lucky-canvas/uni/utils.js
  10. 129 0
      components/WF-scroll/WF-scroll.vue
  11. 201 0
      components/lucky-canvas/LICENSE
  12. 42 0
      components/lucky-canvas/README.md
  13. 15 0
      components/lucky-canvas/dist/index.cjs.js
  14. 0 0
      components/lucky-canvas/dist/index.cjs.js.map
  15. 14 0
      components/lucky-canvas/dist/index.esm.js
  16. 0 0
      components/lucky-canvas/dist/index.esm.js.map
  17. 14 0
      components/lucky-canvas/dist/index.umd.js
  18. 0 0
      components/lucky-canvas/dist/index.umd.js.map
  19. 14 0
      components/lucky-canvas/dist/lucky-canvas.js
  20. 1 0
      components/lucky-canvas/index.js
  21. 66 0
      components/lucky-canvas/package.json
  22. 752 0
      components/lucky-canvas/types/index.d.ts
  23. 12 3
      manifest.json
  24. 15 14
      package.json
  25. 30 4
      pages.json
  26. 71 0
      pages/index/index.rpx.scss
  27. 2 72
      pages/index/index.vue
  28. 23 0
      pages/lotteryRecord/index.rpx.scss
  29. 37 0
      pages/lotteryRecord/lotteryRecord.vue
  30. 12 0
      pages/lotteryRule/index.rpx.scss
  31. 33 0
      pages/lotteryRule/lotteryRule.vue
  32. 58 0
      pages/zhuanpan/index.rpx.scss
  33. 126 0
      pages/zhuanpan/zhuanpan.vue
  34. BIN
      static/img/1712667932387.jpg
  35. BIN
      static/img/1712668343314.jpg
  36. BIN
      static/img/DM_20240409173533_001.png
  37. BIN
      static/img/DM_20240409173533_003.jpg
  38. BIN
      static/img/DM_20240409173533_004.png
  39. BIN
      static/img/DM_20240409173533_005.png
  40. BIN
      static/img/DM_20240409173533_006.png
  41. BIN
      static/img/DM_20240409173533_007.png
  42. BIN
      static/img/zpbg.png

+ 4 - 0
.hbuilderx/launch.json

@@ -2,6 +2,10 @@
   // launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
     "version": "0.0",
     "configurations": [{
+     	"app-plus" : 
+     	{
+     		"launchtype" : "local"
+     	},
      	"default" : 
      	{
      		"launchtype" : "local"

+ 24 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,24 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="HtmlUnknownTag" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="myValues">
+        <value>
+          <list size="10">
+            <item index="0" class="java.lang.String" itemvalue="nobr" />
+            <item index="1" class="java.lang.String" itemvalue="noembed" />
+            <item index="2" class="java.lang.String" itemvalue="comment" />
+            <item index="3" class="java.lang.String" itemvalue="noscript" />
+            <item index="4" class="java.lang.String" itemvalue="embed" />
+            <item index="5" class="java.lang.String" itemvalue="script" />
+            <item index="6" class="java.lang.String" itemvalue="l-dialer" />
+            <item index="7" class="java.lang.String" itemvalue="q-turntable" />
+            <item index="8" class="java.lang.String" itemvalue="luckywheel" />
+            <item index="9" class="java.lang.String" itemvalue="solt" />
+          </list>
+        </value>
+      </option>
+      <option name="myCustomValuesEnabled" value="true" />
+    </inspection_tool>
+  </profile>
+</component>

+ 201 - 0
components/@lucky-canvas/uni/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [2021] [Li Dong Qi]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 138 - 0
components/@lucky-canvas/uni/README.md

@@ -0,0 +1,138 @@
+<br />
+
+<div align="center">
+  <img src="https://cdn.jsdelivr.net/gh/buuing/cdn/imgs/lucky-canvas.jpg" width="210" alt="logo" />
+  <h1>lucky-canvas 抽奖插件</h1>
+  <p>一个基于 JavaScript 的跨平台 ( 大转盘 / 九宫格 / 老虎机 ) 抽奖插件</p>
+  <p>
+    <a href="https://github.com/buuing/lucky-canvas/stargazers" target="_black">
+      <img src="https://img.shields.io/github/stars/buuing/lucky-canvas?color=%23ffba15&logo=github&style=flat-square" alt="stars" />
+    </a>
+    <a href="https://github.com/buuing/lucky-canvas/network/members" target="_black">
+      <img src="https://img.shields.io/github/forks/buuing/lucky-canvas?color=%23ffba15&logo=github&style=flat-square" alt="forks" />
+    </a>
+    <a href="https://github.com/buuing" target="_black">
+      <img src="https://img.shields.io/badge/Author-%20buuing%20-7289da.svg?&logo=github&style=flat-square" alt="author" />
+    </a>
+    <a href="https://github.com/buuing/lucky-canvas/blob/master/LICENSE" target="_black">
+      <img src="https://img.shields.io/github/license/buuing/lucky-canvas?color=%232dce89&logo=github&style=flat-square" alt="license" />
+    </a>
+  </p>
+</div>
+
+
+|适配框架|npm下载量|CDN使用量|
+| :-: | :-: | :-: |
+|[`JS` / `JQ` 中使用](https://100px.net/usage/js.html)|<a href="https://www.npmjs.com/package/lucky-canvas" target="_black"><img src="https://img.shields.io/npm/dm/lucky-canvas?color=%23ffba15&logo=npm&style=flat-square" alt="downloads" /></a>|<a href="https://www.jsdelivr.com/package/npm/lucky-canvas" target="_black"><img src="https://data.jsdelivr.com/v1/package/npm/lucky-canvas/badge" alt="downloads" /></a>|
+|[`Vue` 中使用](https://100px.net/usage/vue.html)|<a href="https://www.npmjs.com/package/@lucky-canvas/vue" target="_black"><img src="https://img.shields.io/npm/dm/@lucky-canvas/vue?color=%23ffba15&logo=npm&style=flat-square" alt="downloads" /></a>|<a href="https://www.jsdelivr.com/package/npm/@lucky-canvas/vue" target="_black"><img src="https://data.jsdelivr.com/v1/package/npm/@lucky-canvas/vue/badge" alt="downloads" /></a>|
+|[`React` 中使用](https://100px.net/usage/react.html)|<a href="https://www.npmjs.com/package/@lucky-canvas/react" target="_black"><img src="https://img.shields.io/npm/dm/@lucky-canvas/react?color=%23ffba15&logo=npm&style=flat-square" alt="downloads" /></a>|-|
+|[`UniApp` 中使用](https://100px.net/usage/uni.html)|<a href="https://www.npmjs.com/package/@lucky-canvas/uni" target="_black"><img src="https://img.shields.io/npm/dm/@lucky-canvas/uni?color=%23ffba15&logo=npm&style=flat-square" alt="downloads" /></a>|-|
+|[`Taro3.x` 中使用](https://100px.net/usage/taro.html)|<a href="https://www.npmjs.com/package/@lucky-canvas/taro" target="_black"><img src="https://img.shields.io/npm/dm/@lucky-canvas/taro?color=%23ffba15&logo=npm&style=flat-square" alt="downloads" /></a>|-|
+|[`微信小程序` 中使用](https://100px.net/usage/wx.html)|<a href="https://www.npmjs.com/package/@lucky-canvas/mini" target="_black"><img src="https://img.shields.io/npm/dm/@lucky-canvas/mini?color=%23ffba15&logo=npm&style=flat-square" alt="downloads" /></a>|-|
+
+<br />
+
+## 官方文档 & Demo演示
+
+> **中文**:[https://100px.net](https://100px.net)
+
+> **English**:**If anyone can help translate the document, please contact me** `ldq404@qq.com`
+  
+<br />
+
+## 在 uni-app 中使用
+
+### 1. 安装插件
+
+- 你可以选择通过 `HBuilderX` 导入插件: [https://ext.dcloud.net.cn/plugin?id=3499](https://ext.dcloud.net.cn/plugin?id=3499)
+
+- 也可以选择通过 `npm` / `yarn` 安装
+
+```shell
+# npm 安装:
+npm install @lucky-canvas/uni
+
+# yarn 安装:
+yarn add @lucky-canvas/uni
+```
+
+<br />
+
+### 2. 引入并使用
+
+```html
+<view>
+  <!-- 大转盘抽奖 -->
+  <LuckyWheel
+    width="600rpx"
+    height="600rpx"
+    ...你的配置
+  />
+  <!-- 九宫格抽奖 -->
+  <LuckyGrid
+    width="600rpx"
+    height="600rpx"
+    ...你的配置
+  />
+</view>
+```
+
+```js
+// npm 下载会默认到 node_modules 里面,直接引入包名即可
+import LuckyWheel from '@lucky-canvas/uni/lucky-wheel' // 大转盘
+import LuckyGrid from '@lucky-canvas/uni/lucky-grid' // 九宫格
+
+// 如果你是通过 HBuilderX 导入插件,那你需要指定一下路径
+// import LuckyWheel from '@/components/@lucky-canvas/uni/lucky-wheel' // 大转盘
+// import LuckyGrid from '@/components/@lucky-canvas/uni/lucky-grid' // 九宫格
+
+export default {
+  // 注册组件
+  components: { LuckyWheel, LuckyGrid },
+}
+```
+
+<br />
+
+### 3. 我提供了一个最基本的 demo 供你用于尝试
+
+由于 uni-app 渲染 md 的时候会出问题,所以我把 demo 代码放到了文档里
+
+- [https://100px.net/document/uni-app.html](https://100px.net/document/uni-app.html)
+
+<br />
+
+### **4. 补充说明**
+
+- [**如果用着顺手, 可以在 Github 上面点个 <img height="22" align="top" src="https://img.shields.io/github/stars/buuing/lucky-canvas" /> 支持一下(●'◡'●)**](https://github.com/buuing/lucky-canvas)
+
+- 另外: 如果你修复了某些bug或兼容, 欢迎提给我, 我会把你展示到官网的贡献者列表当中
+
+
+<br />
+
+### 5. 常见问题
+
+1. 转盘层级太高了, 我的弹窗盖不住怎么办?
+
+> 答: 因为小程序里canvas是原生组件顶层渲染, 我无法控制canvas的层级, 如果你想盖住它也肯简单, 你可以百度搜索`<cover>`组件
+
+2. 你这些素材, 图片组件从哪下载?
+
+> 答: 官网里的任何图片素材, 所使用到的图片资源均为学习交流使用, 请勿将其用于商业用途, 由此产生的任何商业纠纷我这边概不负责
+
+3. xxx属性怎么使用? xxx方法怎么调用?
+
+> 答: 自己去看文档, 不然难道要我把代码给你写好吗?
+
+4. 这个属性的效果与官网的描述不一致?
+
+> 答: 可能有bug, 你可以去github上的issues去提问 (请认真填写模板)
+
+5. 为什么这个插件不支持app和其他小程序
+
+> 答: 没时间, 但是希望志同道合的同学来一起参与uniapp的兼容开发
+
+---
+
+<font color="blue">作者留言: 为了使我自己保持心情愉悦, 低于5星的提问我用浏览器插件都屏蔽了</font>

+ 317 - 0
components/@lucky-canvas/uni/lucky-grid.vue

@@ -0,0 +1,317 @@
+<template>
+  <view v-if="isShow" class="lucky-box" :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }">
+    <canvas
+      type="2d"
+      id="lucky-grid"
+      canvas-id="lucky-grid"
+      :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }"
+    ></canvas>
+    <image
+      v-if="imgSrc"
+      :src="imgSrc"
+      @load="myLucky.clearCanvas()"
+      :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }"
+    ></image>
+    <!-- #ifdef APP-PLUS -->
+    <view v-if="btnShow">
+      <view class="lucky-grid-btn" v-for="(btn, index) in btns" :key="index" @click="toPlay(btn, index)" :style="{
+        top: btn.top + 'px',
+        left: btn.left + 'px',
+        width: btn.width + 'px',
+        height: btn.height + 'px',
+      }"></view>
+    </view>
+    <!-- #endif -->
+    <!-- #ifndef APP-PLUS -->
+    <view v-if="btnShow">
+      <cover-view class="lucky-grid-btn" v-for="(btn, index) in btns" :key="index" @click="toPlay(btn, index)" :style="{
+        top: btn.top + 'px',
+        left: btn.left + 'px',
+        width: btn.width + 'px',
+        height: btn.height + 'px',
+      }"></cover-view>
+    </view>
+    <!-- #endif -->
+    <!-- #ifndef H5 -->
+    <view v-if="myLucky">
+      <div class="lucky-imgs">
+        <div v-for="(block, index) in blocks" :key="index">
+          <div v-if="block.imgs">
+            <div v-for="(img, i) in block.imgs" :key="i">
+              <image :src="img.src" :data-index="index" :data-i="i" @load="e => imgBindload(e, 'blocks')"></image>
+              <image :src="img.activeSrc" :data-index="index" :data-i="i" @load="e => imgBindloadActive(e, 'blocks')"></image>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="lucky-imgs">
+        <div v-for="(prize, index) in prizes" :key="index">
+          <div v-if="prize.imgs">
+            <div v-for="(img, i) in prize.imgs" :key="i">
+              <image :src="img.src" :data-index="index" :data-i="i" @load="e => imgBindload(e, 'prizes')"></image>
+              <image :src="img.activeSrc" :data-index="index" :data-i="i" @load="e => imgBindloadActive(e, 'prizes')"></image>
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="lucky-imgs">
+        <div v-for="(btn, index) in buttons" :key="index">
+          <div v-if="btn.imgs">
+            <image v-for="(img, i) in btn.imgs" :key="i" :src="img.src" :data-index="index" :data-i="i" @load="e => imgBindload(e, 'buttons')"></image>
+          </div>
+        </div>
+      </div>
+      <div class="lucky-imgs">
+        <span v-if="button && button.imgs">
+          <image v-for="(img, i) in button.imgs" :key="i" :src="img.src" :data-i="i" @load="e => imgBindloadBtn(e, 'button')"></image>
+        </span>
+      </div>
+    </view>
+    <!-- #endif -->
+  </view>
+</template>
+
+<script>
+  import { changeUnits, resolveImage, getImage } from './utils.js'
+  import { LuckyGrid } from '../../lucky-canvas'
+  export default {
+    name: 'lucky-grid',
+    data () {
+      return {
+        imgSrc: '',
+        myLucky: null,
+        canvas: null,
+        isShow: false,
+        boxWidth: 100,
+        boxHeight: 100,
+        dpr: 1,
+        btns: [],
+        btnShow: false,
+      }
+    },
+    props: {
+      width: {
+        type: String,
+        default: '600rpx'
+      },
+      height: {
+        type: String,
+        default: '600rpx'
+      },
+      cols: {
+        type: [String, Number],
+        default: 3,
+      },
+      rows: {
+        type: [String, Number],
+        default: 3,
+      },
+      blocks: {
+        type: Array,
+        default: () => []
+      },
+      prizes: {
+        type: Array,
+        default: () => []
+      },
+      buttons: {
+        type: Array,
+        default: () => []
+      },
+      button: {
+        type: Object,
+        default: undefined
+      },
+      defaultConfig: {
+        type: Object,
+        default: () => ({})
+      },
+      defaultStyle: {
+        type: Object,
+        default: () => ({})
+      },
+      activeStyle: {
+        type: Object,
+        default: () => ({})
+      }
+    },
+    mounted () {
+      // #ifdef APP-PLUS
+      console.error('该抽奖插件的最新版暂不支持app端, 请通过npm安装旧版本【npm i uni-luck-draw@1.3.9】')
+      // #endif
+      // #ifndef APP-PLUS
+      this.initLucky()
+      // #endif
+    },
+    watch: {
+      cols (newData) {
+        this.myLucky && (this.myLucky.cols = newData)
+      },
+      rows (newData) {
+        this.myLucky && (this.myLucky.rows = newData)
+      },
+      blocks (newData) {
+        this.myLucky && (this.myLucky.blocks = newData)
+      },
+      prizes (newData) {
+        this.myLucky && (this.myLucky.prizes = newData)
+      },
+      buttons (newData) {
+        this.myLucky && (this.myLucky.buttons = newData)
+      },
+      button (newData) {
+        this.myLucky && (this.myLucky.button = newData)
+      },
+      defaultStyle (newData) {
+        this.myLucky && (this.myLucky.defaultStyle = newData)
+      },
+      defaultConfig (newData) {
+        this.myLucky && (this.myLucky.defaultConfig = newData)
+      },
+      activeStyle (newData) {
+        this.myLucky && (this.myLucky.activeStyle = newData)
+      },
+    },
+    methods: {
+      async imgBindload (res, name) {
+        const { index, i } = res.currentTarget.dataset
+        const img = this[name][index].imgs[i]
+        resolveImage(img, this.canvas)
+      },
+      async imgBindloadActive (res, name) {
+        const { index, i } = res.currentTarget.dataset
+        const img = this[name][index].imgs[i]
+        resolveImage(img, this.canvas, 'activeSrc', '$activeResolve')
+      },
+      async imgBindloadBtn (res, name) {
+        const { i } = res.currentTarget.dataset
+        const img = this[name].imgs[i]
+        resolveImage(img, this.canvas)
+      },
+      getImage () {
+        return getImage.call(this, 'lucky-grid', this.canvas)
+      },
+      hideCanvas () {
+        // #ifdef MP
+        this.getImage().then(res => {
+          this.imgSrc = res.tempFilePath
+        })
+        // #endif
+      },
+      initLucky () {
+        this.boxWidth = changeUnits(this.width)
+        this.boxHeight = changeUnits(this.height)
+        this.isShow = true
+        // 某些情况下获取不到 canvas
+        this.$nextTick(() => {
+          setTimeout(() => {
+            this.draw()
+          })
+        })
+      },
+      draw () {
+        const _this = this
+        uni.createSelectorQuery().in(this).select('#lucky-grid').fields({
+          node: true, size: true
+        }).exec((res) => {
+          // #ifdef H5
+          res[0].node = document.querySelector('#lucky-grid canvas')
+          // #endif
+          if (!res[0] || !res[0].node) return console.error('lucky-canvas 获取不到 canvas 标签')
+          const { node, width, height } = res[0]
+          const canvas = this.canvas = node
+          const ctx = this.ctx = canvas.getContext('2d')
+          const dpr = this.dpr = uni.getSystemInfoSync().pixelRatio
+          // #ifndef H5
+          canvas.width = width * dpr
+          canvas.height = height * dpr
+          ctx.scale(dpr, dpr)
+          // #endif
+          const myLucky = this.myLucky = new LuckyGrid({
+            // #ifdef H5
+            flag: 'WEB',
+            // #endif
+            // #ifdef MP
+            flag: 'MP-WX',
+            // #endif
+            ctx,
+            dpr,
+            setTimeout,
+            clearTimeout,
+            setInterval,
+            clearInterval,
+            // #ifdef H5
+            rAF: requestAnimationFrame,
+            // #endif
+            unitFunc: (num, unit) => changeUnits(num + unit),
+            afterInit: function () {
+              [..._this.$props.buttons, _this.$props.button].forEach((btn, index) => {
+                if (!btn) return
+                const [left, top, width, height] = this.getGeometricProperty([
+                  btn.x,
+                  btn.y,
+                  btn.col || 1,
+                  btn.row || 1
+                ])
+                _this.btns[index] = { top, left, width, height }
+              })
+              _this.$forceUpdate()
+            },
+            afterStart: () => {
+              this.imgSrc = ''
+            },
+          }, {
+            ...this.$props,
+            width,
+            height,
+            start: (...rest) => {
+              this.$emit('start', ...rest)
+            },
+            end: (...rest) => {
+              this.$emit('end', ...rest)
+              this.hideCanvas()
+            },
+          })
+          this.btnShow = true
+        })
+      },
+      toPlay (btn, index) {
+        this.myLucky.startCallback(btn, this.$props.buttons[index])
+      },
+      init () {
+        this.myLucky.init()
+      },
+      play (...rest) {
+        this.myLucky.play(...rest)
+      },
+      stop (...rest) {
+        this.myLucky.stop(...rest)
+      },
+    },
+  }
+</script>
+
+<style scoped>
+  .lucky-box {
+    position: relative;
+    overflow: hidden;
+    margin: 0 auto;
+  }
+  .lucky-box canvas {
+    position: absolute;
+    pointer-events: none;
+    left: 0;
+    top: 0;
+  }
+  .lucky-grid-btn {
+    position: absolute;
+    background: rgba(0, 0, 0, 0);
+    border-radius: 0;
+    cursor: pointer;
+  }
+  .lucky-imgs {
+    width: 0;
+    height: 0;
+    visibility: hidden;
+  }
+</style>

+ 255 - 0
components/@lucky-canvas/uni/lucky-wheel.vue

@@ -0,0 +1,255 @@
+<template>
+  <view v-if="isShow" class="lucky-box" :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }">
+    <canvas
+      type="2d"
+      id="lucky-wheel"
+      canvas-id="lucky-wheel"
+      :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }"
+    ></canvas>
+    <image
+      v-if="imgSrc"
+      :src="imgSrc"
+      @load="myLucky.clearCanvas()"
+      :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }"
+    ></image>
+    <!-- #ifdef APP-PLUS -->
+    <view class="lucky-wheel-btn" @click="toPlay" :style="{ width: btnWidth + 'px', height: btnHeight + 'px' }"></view>
+    <!-- #endif -->
+    <!-- #ifndef APP-PLUS -->
+    <cover-view class="lucky-wheel-btn" @click="toPlay" :style="{ width: btnWidth + 'px', height: btnHeight + 'px' }"></cover-view>
+    <!-- #endif -->
+    <!-- #ifndef H5 -->
+    <view v-if="myLucky">
+      <div class="lucky-imgs">
+        <div v-for="(block, index) in blocks" :key="index">
+          <div v-if="block.imgs">
+            <image v-for="(img, i) in block.imgs" :key="i" :src="img.src" @load="e => imgBindload(e, 'blocks', index, i)"></image>
+          </div>
+        </div>
+      </div>
+      <div class="lucky-imgs">
+        <div v-for="(prize, index) in prizes" :key="index">
+          <div v-if="prize.imgs">
+            <image v-for="(img, i) in prize.imgs" :key="i" :src="img.src" @load="e => imgBindload(e, 'prizes', index, i)"></image>
+          </div>
+        </div>
+      </div>
+      <div class="lucky-imgs">
+        <div v-for="(btn, index) in buttons" :key="index">
+          <div v-if="btn.imgs">
+            <image v-for="(img, i) in btn.imgs" :key="i" :src="img.src" @load="e => imgBindload(e, 'buttons', index, i)"></image>
+          </div>
+        </div>
+      </div>
+    </view>
+    <!-- #endif -->
+  </view>
+</template>
+
+<script>
+  import { changeUnits, resolveImage, getImage } from './utils.js'
+  import { LuckyWheel } from '../../lucky-canvas'
+  export default {
+    name: 'lucky-wheel',
+    data () {
+      return {
+        imgSrc: '',
+        myLucky: null,
+        canvas: null,
+        isShow: false,
+        boxWidth: 100,
+        boxHeight: 100,
+        btnWidth: 0,
+        btnHeight: 0,
+        dpr: 1,
+      }
+    },
+    props: {
+      width: {
+        type: String,
+        default: '600rpx'
+      },
+      height: {
+        type: String,
+        default: '600rpx'
+      },
+      blocks: {
+        type: Array,
+        default: () => []
+      },
+      prizes: {
+        type: Array,
+        default: () => []
+      },
+      buttons: {
+        type: Array,
+        default: () => []
+      },
+      defaultConfig: {
+        type: Object,
+        default: () => ({})
+      },
+      defaultStyle: {
+        type: Object,
+        default: () => ({})
+      },
+    },
+    mounted () {
+      // #ifdef APP-PLUS
+      console.error('该抽奖插件的最新版暂不支持app端, 请通过npm安装旧版本【npm i uni-luck-draw@1.3.9】')
+      // #endif
+      // #ifndef APP-PLUS
+      this.initLucky()
+      // #endif
+    },
+    watch: {
+      blocks (newData) {
+        this.myLucky && (this.myLucky.blocks = newData)
+      },
+      prizes (newData) {
+        this.myLucky && (this.myLucky.prizes = newData)
+      },
+      buttons (newData) {
+        this.myLucky && (this.myLucky.buttons = newData)
+      },
+      defaultStyle (newData) {
+        this.myLucky && (this.myLucky.defaultStyle = newData)
+      },
+      defaultConfig (newData) {
+        this.myLucky && (this.myLucky.defaultConfig = newData)
+      },
+    },
+    methods: {
+      async imgBindload (res, name, index, i) {
+        const img = this[name][index].imgs[i]
+        resolveImage(img, this.canvas)
+      },
+      getImage () {
+        return getImage.call(this, 'lucky-wheel', this.canvas)
+      },
+      hideCanvas () {
+        // #ifdef MP
+        this.getImage().then(res => {
+          this.imgSrc = res.tempFilePath
+        })
+        // #endif
+      },
+      initLucky () {
+        this.boxWidth = changeUnits(this.width)
+        this.boxHeight = changeUnits(this.height)
+        this.isShow = true
+        // 某些情况下获取不到 canvas
+        this.$nextTick(() => {
+          setTimeout(() => {
+            this.draw()
+          })
+        })
+      },
+      draw () {
+        const _this = this
+        uni.createSelectorQuery().in(this).select('#lucky-wheel').fields({
+          node: true, size: true
+        }).exec((res) => {
+          // #ifdef H5
+          res[0].node = document.querySelector('#lucky-wheel canvas')
+          // #endif
+          if (!res[0] || !res[0].node) return console.error('lucky-canvas 获取不到 canvas 标签')
+          const { node, width, height } = res[0]
+          const canvas = this.canvas = node
+          const ctx = this.ctx = canvas.getContext('2d')
+          const dpr = this.dpr = uni.getSystemInfoSync().pixelRatio
+          // #ifndef H5
+          canvas.width = width * dpr
+          canvas.height = height * dpr
+          ctx.scale(dpr, dpr)
+          // #endif
+          const Radius = Math.min(width, height) / 2
+          const myLucky = this.myLucky = new LuckyWheel({
+            // #ifdef H5
+            flag: 'WEB',
+            // #endif
+            // #ifdef MP
+            flag: 'MP-WX',
+            // #endif
+            ctx,
+            dpr,
+            setTimeout,
+            clearTimeout,
+            setInterval,
+            clearInterval,
+            // #ifdef H5
+            rAF: requestAnimationFrame,
+            // #endif
+            unitFunc: (num, unit) => changeUnits(num + unit),
+            beforeCreate: function () {
+              ctx.translate(Radius, Radius)
+            },
+            beforeResize: function () {
+              ctx.translate(-Radius, -Radius)
+            },
+            afterInit: function () {
+              // 动态设置按钮
+              _this.btnWidth = this.maxBtnRadius * 2
+              _this.btnHeight = this.maxBtnRadius * 2
+              _this.$forceUpdate()
+            },
+            afterStart: () => {
+              this.imgSrc = ''
+            },
+          }, {
+            ...this.$props,
+            width,
+            height,
+            start: (...rest) => {
+              this.$emit('start', ...rest)
+            },
+            end: (...rest) => {
+              this.$emit('end', ...rest)
+              this.hideCanvas()
+            },
+          })
+        })
+      },
+      toPlay (e) {
+        this.myLucky.startCallback()
+      },
+      init () {
+        this.myLucky.init()
+      },
+      play (...rest) {
+        this.myLucky.play(...rest)
+      },
+      stop (...rest) {
+        this.myLucky.stop(...rest)
+      },
+    },
+  }
+</script>
+
+<style scoped>
+  .lucky-box {
+    position: relative;
+    overflow: hidden;
+    margin: 0 auto;
+  }
+  .lucky-box canvas {
+    position: absolute;
+    pointer-events: none;
+    left: 0;
+    top: 0;
+  }
+  .lucky-wheel-btn {
+    position: absolute;
+    left: 50%;
+    top: 50%;
+    transform: translate(-50%, -50%);
+    background: rgba(0, 0, 0, 0);
+    border-radius: 50%;
+    cursor: pointer;
+  }
+  .lucky-imgs {
+    width: 0;
+    height: 0;
+    visibility: hidden;
+  }
+</style>

+ 23 - 0
components/@lucky-canvas/uni/package.json

@@ -0,0 +1,23 @@
+{
+  "name": "@lucky-canvas/uni",
+  "version": "0.0.10",
+  "description": "uni-app【大转盘 / 九宫格 / 老虎机】抽奖插件",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [
+    "uni-app抽奖"
+  ],
+  "files": [
+    "lucky-wheel.vue",
+    "lucky-grid.vue",
+    "slot-machine.vue",
+    "utils.js",
+    "demo.vue"
+  ],
+  "author": "ldq <ldq404@qq.com>",
+  "license": "Apache-2.0",
+  "dependencies": {
+    "lucky-canvas": "~1.7.19"
+  }
+}

+ 214 - 0
components/@lucky-canvas/uni/slot-machine.vue

@@ -0,0 +1,214 @@
+<template>
+  <view v-if="isShow" class="lucky-box" :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }">
+    <canvas
+      type="2d"
+      id="slot-machine"
+      canvas-id="slot-machine"
+      :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }"
+    ></canvas>
+    <image
+      v-if="imgSrc"
+      :src="imgSrc"
+      @load="myLucky.clearCanvas()"
+      :style="{ width: boxWidth + 'px', height: boxHeight + 'px' }"
+    ></image>
+    <!-- #ifndef H5 -->
+    <view v-if="myLucky">
+      <div class="lucky-imgs">
+        <div v-for="(block, index) in blocks" :key="index">
+          <div v-if="block.imgs">
+            <image v-for="(img, i) in block.imgs" :key="i" :src="img.src" @load="e => imgBindload(e, 'blocks', index, i)"></image>
+          </div>
+        </div>
+      </div>
+      <div class="lucky-imgs">
+        <div v-for="(prize, index) in prizes" :key="index">
+          <div v-if="prize.imgs">
+            <image v-for="(img, i) in prize.imgs" :key="i" :src="img.src" @load="e => imgBindload(e, 'prizes', index, i)"></image>
+          </div>
+        </div>
+      </div>
+    </view>
+    <!-- #endif -->
+  </view>
+</template>
+
+<script>
+  import { changeUnits, resolveImage, getImage } from './utils.js'
+  import { SlotMachine } from '../../lucky-canvas'
+  export default {
+    name: 'slot-machine',
+    data () {
+      return {
+        imgSrc: '',
+        myLucky: null,
+        canvas: null,
+        isShow: false,
+        boxWidth: 100,
+        boxHeight: 100,
+        btnWidth: 0,
+        btnHeight: 0,
+        dpr: 1,
+      }
+    },
+    props: {
+      width: {
+        type: String,
+        default: '600rpx'
+      },
+      height: {
+        type: String,
+        default: '600rpx'
+      },
+      blocks: {
+        type: Array,
+        default: () => []
+      },
+      prizes: {
+        type: Array,
+        default: () => []
+      },
+      slots: {
+        type: Array,
+        default: () => []
+      },
+      defaultConfig: {
+        type: Object,
+        default: () => ({})
+      },
+      defaultStyle: {
+        type: Object,
+        default: () => ({})
+      },
+    },
+    mounted () {
+      // #ifndef APP-PLUS
+      this.initLucky()
+      // #endif
+    },
+    watch: {
+      blocks (newData) {
+        this.myLucky && (this.myLucky.blocks = newData)
+      },
+      prizes (newData) {
+        this.myLucky && (this.myLucky.prizes = newData)
+      },
+      slots (newData) {
+        this.myLucky && (this.myLucky.slots = newData)
+      },
+      defaultStyle (newData) {
+        this.myLucky && (this.myLucky.defaultStyle = newData)
+      },
+      defaultConfig (newData) {
+        this.myLucky && (this.myLucky.defaultConfig = newData)
+      },
+    },
+    methods: {
+      async imgBindload (res, name, index, i) {
+        const img = this[name][index].imgs[i]
+        resolveImage(img, this.canvas)
+      },
+      getImage () {
+        return getImage.call(this, 'slot-machine', this.canvas)
+      },
+      hideCanvas () {
+        // #ifdef MP
+        this.getImage().then(res => {
+          this.imgSrc = res.tempFilePath
+        })
+        // #endif
+      },
+      initLucky () {
+        this.boxWidth = changeUnits(this.width)
+        this.boxHeight = changeUnits(this.height)
+        this.isShow = true
+        // 某些情况下获取不到 canvas
+        this.$nextTick(() => {
+          setTimeout(() => {
+            this.draw()
+          })
+        })
+      },
+      draw () {
+        const _this = this
+        uni.createSelectorQuery().in(this).select('#slot-machine').fields({
+          node: true, size: true
+        }).exec((res) => {
+          // #ifdef H5
+          res[0].node = document.querySelector('#slot-machine canvas')
+          // #endif
+          if (!res[0] || !res[0].node) return console.error('lucky-canvas 获取不到 canvas 标签')
+          const { node, width, height } = res[0]
+          const canvas = this.canvas = node
+          const ctx = this.ctx = canvas.getContext('2d')
+          const dpr = this.dpr = uni.getSystemInfoSync().pixelRatio
+          // #ifndef H5
+          canvas.width = width * dpr
+          canvas.height = height * dpr
+          ctx.scale(dpr, dpr)
+          // #endif
+          const myLucky = this.myLucky = new SlotMachine({
+            // #ifdef H5
+            flag: 'WEB',
+            // #endif
+            // #ifdef MP
+            flag: 'MP-WX',
+            // #endif
+            ctx,
+            dpr,
+            // #ifndef H5
+            offscreenCanvas: uni.createOffscreenCanvas({ type: '2d' }),
+            // #endif
+            setTimeout,
+            clearTimeout,
+            setInterval,
+            clearInterval,
+            // #ifdef H5
+            rAF: requestAnimationFrame,
+            // #endif
+            unitFunc: (num, unit) => changeUnits(num + unit),
+            afterStart: () => {
+              this.imgSrc = ''
+            },
+          }, {
+            ...this.$props,
+            width,
+            height,
+            end: (...rest) => {
+              this.$emit('end', ...rest)
+              this.hideCanvas()
+            },
+          })
+        })
+      },
+      init () {
+        this.myLucky.init()
+      },
+      play (...rest) {
+        this.myLucky.play(...rest)
+      },
+      stop (...rest) {
+        this.myLucky.stop(...rest)
+      },
+    },
+  }
+</script>
+
+<style scoped>
+  .lucky-box {
+    position: relative;
+    overflow: hidden;
+    margin: 0 auto;
+  }
+  .lucky-box canvas {
+    position: absolute;
+    pointer-events: none;
+    left: 0;
+    top: 0;
+  }
+  .lucky-imgs {
+    width: 0;
+    height: 0;
+    visibility: hidden;
+  }
+</style>

+ 82 - 0
components/@lucky-canvas/uni/utils.js

@@ -0,0 +1,82 @@
+let windowWidth = uni.getSystemInfoSync().windowWidth
+// uni-app@2.9起, 屏幕最多适配到960, 超出则按375计算
+if (windowWidth > 960) windowWidth = 375
+
+export const rpx2px = (value) => {
+  if (typeof value === 'string') value = Number(value.replace(/[a-z]*/g, ''))
+  return windowWidth / 750 * value
+}
+
+export const changeUnits = (value) => {
+  return Number(value.replace(/^(\-*[0-9.]*)([a-z%]*)$/, (value, num, unit) => {
+    switch (unit) {
+      case 'px':
+        num *= 1
+        break
+      case 'rpx':
+        num = rpx2px(num)
+        break
+      default:
+        num *= 1
+        break
+    }
+    return num
+  }))
+}
+
+export const resolveImage = async (img, canvas, srcName = 'src', resolveName = '$resolve') => {
+  let imgObj
+  // 区分 H5 和小程序
+  if (window) {
+    imgObj = new Image()
+  } else {
+    imgObj = canvas.createImage()
+  }
+  // 成功回调
+  imgObj.onload = () => {
+    img[resolveName](imgObj)
+  }
+  // 失败回调
+  imgObj.onerror = (err) => {
+    console.error(err)
+    // img['$reject']()
+  }
+  // 设置src
+  imgObj.src = img[srcName]
+}
+
+// 旧版canvas引入图片的方法
+// export const resolveImage = async (res, img, imgName = 'src', resolveName = '$resolve') => {
+//   const src = img[imgName]
+//   const $resolve = img[resolveName]
+//   // #ifdef MP
+//   // 如果是base64就调用base64src()方法把图片写入本地, 然后渲染临时路径
+//   if (/^data:image\/([a-z]+);base64,/.test(src)) {
+//     const path = await base64src(src)
+//     $resolve({ ...res.detail, path })
+//     return
+//   }
+//   // #endif
+//   // 如果是本地图片, 直接返回
+//   if (src.indexOf('http') !== 0) {
+//     $resolve({ ...res.detail, path:src })
+//     return
+//   }
+//   // 如果是网络图片, 则通过getImageInfo()方法获取图片宽高
+//   uni.getImageInfo({
+//     src: src,
+//     success: (imgObj) => $resolve(imgObj),
+//     fail: () => console.error('API `uni.getImageInfo` 加载图片失败', src)
+//   })
+// }
+
+export function getImage(canvasId, canvas) {
+  return new Promise((resolve, reject) => {
+    uni.canvasToTempFilePath({
+      canvas,
+      canvasId,
+      success: res => resolve(res),
+      fail: err => reject(err)
+    }, this)
+  })
+}

+ 129 - 0
components/WF-scroll/WF-scroll.vue

@@ -0,0 +1,129 @@
+<template>
+	<div>
+		<scroll-view show-scrollbar="true" :scroll-top="scrollTop" scroll-y="true" @scrolltolower="upper"
+			@scroll="scroll" :style="{'height':scrollHeight+'rpx'}">
+			<div class="content" @touchstart="touchstart" @touchend="touchend">
+				<view class="flex-row justify-between rollItem" v-for="(item,index) in 10">
+					<view>
+						<text class="text1">17365000014</text>
+						<text class="text2">2021年3月29日09:22</text>
+					</view>
+					<view>
+						<text class="text3">一等奖</text>
+						<text class="text2">扫地机器人</text>
+					</view>
+				</view>
+			</div>
+		</scroll-view>
+	</div>
+</template>
+
+<script>
+	/*
+	listAr  循环数组
+	scrollHeight  scroll可视区域高度
+	scrollTimer  是否默认开始滚动
+	*/
+	export default {
+		name: "WF-scroll",
+		props: {
+			listAr: [],
+			scrollHeight: '',
+			scrollTimer:'',
+		},
+		data() {
+			return {
+				scrollTop: 0,
+				scrollType: true, //判断滚动所用为防止滚动到底部多次赋值
+				contentHeight: '', //内容高度
+				touchstartType: false,
+			};
+		},
+		created() {
+			setTimeout(() => {
+				if(this.scrollTimer){
+					this.setTimer()
+				}
+				const query = uni.createSelectorQuery().in(this);
+				query.select('.content').boundingClientRect(data => {
+					this.contentHeight = data.height * 2 - 40
+				}).exec();
+			}, 1000)
+		},
+		methods: {
+			// 手指触摸
+			touchstart() {
+				this.touchstartType = true
+				this.removeTimer()
+			},
+			// 手指离开
+			touchend() {
+				this.touchstartType = false
+				this.setTimer()
+				this.upper()
+			},
+			scroll(e) {
+				if (this.touchstartType) {
+					this.scrollTop = e.detail.scrollTop
+				}
+			},
+			upper() {
+				console.log(this.touchstartType);
+				if (!this.touchstartType) {
+					setTimeout(() => {
+						if (this.scrollType && this.contentHeight > this.scrollHeight) {
+							this.scrollTop = 0
+							this.scrollType = false
+							setTimeout(() => {
+								this.scrollType = true
+							}, 3000)
+						}
+					}, 3000)
+				}
+
+			},
+			removeTimer() {
+				if (this.timer) {
+					clearInterval(this.timer)
+					this.timer = null
+				}
+			},
+			// 这里设置滚动速度时间越短滚动则越快
+			setTimer() {
+				this.removeTimer()
+				this.timer = setInterval(() => {
+					this.scrollTop++
+				}, 44)
+			},
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.content {
+		/*padding-top: 40rpx;*/
+		/*background: #fff;*/
+	}
+	.content_list {
+		overflow: hidden;
+		white-space: nowrap;
+		text-overflow: ellipsis;
+		cursor: pointer;
+		color: #1debffff;
+		font-size: 32rpx;
+		text-align: left;
+		padding: 20rpx 0;
+	}
+	.rollItem{
+		padding: 0 24rpx;
+		font-size: 18rpx;
+		border-bottom: 1px solid #f1f1f1;
+		line-height: 60rpx;
+	}
+	.text2{
+		margin-left: 10rpx;
+	}
+	.text3{
+		color: #F56C6C;
+	}
+</style>

+ 201 - 0
components/lucky-canvas/LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [2021] [Li Dong Qi]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 42 - 0
components/lucky-canvas/README.md

@@ -0,0 +1,42 @@
+
+
+<div align="center">
+  <img src="https://unpkg.com/buuing@0.0.1/imgs/lucky-canvas.png" width="128" alt="logo" />
+  <h1>lucky-canvas 抽奖插件</h1>
+  <p>一个基于 JavaScript 的跨平台 ( 大转盘 / 九宫格 / 老虎机 ) 抽奖插件</p>
+  <p>
+    <a href="https://github.com/buuing/lucky-canvas/stargazers" target="_black">
+      <img src="https://img.shields.io/github/stars/buuing/lucky-canvas?color=%23ffba15&logo=github&style=flat-square" alt="stars" />
+    </a>
+    <a href="https://github.com/buuing/lucky-canvas/network/members" target="_black">
+      <img src="https://img.shields.io/github/forks/buuing/lucky-canvas?color=%23ffba15&logo=github&style=flat-square" alt="forks" />
+    </a>
+    <a href="https://github.com/buuing" target="_black">
+      <img src="https://img.shields.io/badge/Author-%20buuing%20-7289da.svg?&logo=github&style=flat-square" alt="author" />
+    </a>
+    <a href="https://github.com/buuing/lucky-canvas/blob/master/LICENSE" target="_black">
+      <img src="https://img.shields.io/github/license/buuing/lucky-canvas?color=%232dce89&logo=github&style=flat-square" alt="license" />
+    </a>
+  </p>
+</div>
+
+<br />
+
+## 官方文档 & Demo演示
+
+> **中文**:[https://100px.net/usage/js.html](https://100px.net/usage/js.html)  
+
+> **English**:**If anyone can help translate the document, please contact me** `ldq404@qq.com`
+
+
+<br />
+
+## 在 JS / TS 中使用
+
+- [跳转官网 查看详情](https://100px.net/usage/js.html)
+
+<br />
+
+## 🙏🙏🙏 点个Star
+
+**如果您觉得这个项目还不错, 可以在 [Github](https://github.com/buuing/lucky-canvas) 上面帮我点个`star`, 支持一下作者 ☜(゚ヮ゚☜)**

File diff suppressed because it is too large
+ 15 - 0
components/lucky-canvas/dist/index.cjs.js


File diff suppressed because it is too large
+ 0 - 0
components/lucky-canvas/dist/index.cjs.js.map


File diff suppressed because it is too large
+ 14 - 0
components/lucky-canvas/dist/index.esm.js


File diff suppressed because it is too large
+ 0 - 0
components/lucky-canvas/dist/index.esm.js.map


File diff suppressed because it is too large
+ 14 - 0
components/lucky-canvas/dist/index.umd.js


File diff suppressed because it is too large
+ 0 - 0
components/lucky-canvas/dist/index.umd.js.map


File diff suppressed because it is too large
+ 14 - 0
components/lucky-canvas/dist/lucky-canvas.js


+ 1 - 0
components/lucky-canvas/index.js

@@ -0,0 +1 @@
+module.exports = require('./dist/index.umd.js')

+ 66 - 0
components/lucky-canvas/package.json

@@ -0,0 +1,66 @@
+{
+  "name": "lucky-canvas",
+  "version": "1.7.26",
+  "description": "一个基于原生 js 的(大转盘 / 九宫格 / 老虎机)抽奖插件",
+  "main": "dist/index.cjs.js",
+  "module": "dist/index.esm.js",
+  "unpkg": "dist/index.umd.js",
+  "jsdelivr": "dist/index.umd.js",
+  "types": "types/index.d.ts",
+  "scripts": {
+    "dev": "rollup --config rollup.config.dev.js -w",
+    "build": "rollup --config rollup.config.build.js"
+  },
+  "homepage": "https://100px.net",
+  "bugs": "https://github.com/LuckDraw/lucky-canvas/issues",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/LuckDraw/lucky-canvas.git",
+    "directory": "packages/lucky-canvas"
+  },
+  "author": "ldq <ldq404@qq.com>",
+  "license": "Apache-2.0",
+  "files": [
+    "dist",
+    "types",
+    "index.js"
+  ],
+  "keywords": [
+    "大转盘抽奖",
+    "九宫格抽奖",
+    "老虎机抽奖",
+    "抽奖插件",
+    "js抽奖",
+    "移动端抽奖",
+    "canvas抽奖"
+  ],
+  "devDependencies": {
+    "@babel/core": "^7.12.3",
+    "@babel/preset-env": "^7.12.1",
+    "@babel/plugin-transform-runtime": "^7.16.4",
+    "@babel/runtime": "^7.16.3",
+    "core-js": "^3.19.2",
+    "@rollup/plugin-commonjs": "^16.0.0",
+    "@rollup/plugin-eslint": "^8.0.1",
+    "@rollup/plugin-json": "^4.1.0",
+    "@rollup/plugin-node-resolve": "^10.0.0",
+    "@rollup/plugin-typescript": "^6.1.0",
+    "@typescript-eslint/parser": "^4.14.0",
+    "babel-plugin-external-helpers": "^6.22.0",
+    "babel-preset-latest": "^6.24.1",
+    "eslint": "^7.18.0",
+    "eslint-plugin-prettier": "^3.3.1",
+    "prettier": "^2.2.1",
+    "rollup": "^2.33.1",
+    "rollup-plugin-babel": "^4.4.0",
+    "rollup-plugin-livereload": "^2.0.0",
+    "rollup-plugin-serve": "^1.1.0",
+    "rollup-plugin-terser": "^7.0.2",
+    "rollup-plugin-delete": "^2.0.0",
+    "rollup-plugin-dts": "^3.0.2",
+    "rollup-plugin-typescript2": "^0.30.0",
+    "tslib": "^2.3.1",
+    "typescript": "^4.0.5"
+  },
+  "dependencies": {}
+}

+ 752 - 0
components/lucky-canvas/types/index.d.ts

@@ -0,0 +1,752 @@
+declare type FontItemType = {
+    text: string;
+    top?: string | number;
+    left?: string | number;
+    fontColor?: string;
+    fontSize?: string;
+    fontStyle?: string;
+    fontWeight?: string;
+    lineHeight?: string;
+};
+declare type FontExtendType = {
+    wordWrap?: boolean;
+    lengthLimit?: string | number;
+    lineClamp?: number;
+};
+declare type ImgType = HTMLImageElement | HTMLCanvasElement;
+declare type ImgItemType = {
+    src: string;
+    top?: string | number;
+    left?: string | number;
+    width?: string;
+    height?: string;
+    formatter?: (img: ImgType) => ImgType;
+    $resolve?: Function;
+    $reject?: Function;
+};
+declare type BorderRadiusType = string | number;
+declare type BackgroundType = string;
+declare type ShadowType = string;
+declare type ConfigType = {
+    nodeType?: number;
+    flag: 'WEB' | 'MP-WX' | 'UNI-H5' | 'UNI-MP' | 'TARO-H5' | 'TARO-MP';
+    el?: string;
+    divElement?: HTMLDivElement;
+    canvasElement?: HTMLCanvasElement;
+    ctx: CanvasRenderingContext2D;
+    dpr: number;
+    handleCssUnit?: (num: number, unit: string) => number;
+    rAF?: Function;
+    setTimeout: Function;
+    setInterval: Function;
+    clearTimeout: Function;
+    clearInterval: Function;
+    beforeCreate?: Function;
+    beforeResize?: Function;
+    afterResize?: Function;
+    beforeInit?: Function;
+    afterInit?: Function;
+    beforeDraw?: Function;
+    afterDraw?: Function;
+    afterStart?: Function;
+};
+declare type RequireKey = 'width' | 'height';
+declare type UserConfigType = Partial<Omit<ConfigType, RequireKey>> & Required<Pick<ConfigType, RequireKey>>;
+declare type Tuple<T, Len extends number, Res extends T[] = []> = Res['length'] extends Len ? Res : Tuple<T, Len, [...Res, T]>;
+
+interface WatchOptType {
+    handler?: () => Function;
+    immediate?: boolean;
+    deep?: boolean;
+}
+
+declare class Lucky {
+    static version: string;
+    protected readonly version: string;
+    protected readonly config: ConfigType;
+    protected readonly ctx: CanvasRenderingContext2D;
+    protected htmlFontSize: number;
+    protected rAF: Function;
+    protected boxWidth: number;
+    protected boxHeight: number;
+    protected data: {
+        width: string | number;
+        height: string | number;
+    };
+    /**
+     * 公共构造器
+     * @param config
+     */
+    constructor(config: string | HTMLDivElement | UserConfigType, data: {
+        width: string | number;
+        height: string | number;
+    });
+    /**
+     * 初始化组件大小/单位
+     */
+    protected resize(): void;
+    /**
+     * 初始化方法
+     */
+    protected initLucky(): void;
+    /**
+     * 鼠标点击事件
+     * @param e 事件参数
+     */
+    protected handleClick(e: MouseEvent): void;
+    /**
+     * 根标签的字体大小
+     */
+    protected setHTMLFontSize(): void;
+    clearCanvas(): void;
+    /**
+     * 设备像素比
+     * window 环境下自动获取, 其余环境手动传入
+     */
+    protected setDpr(): void;
+    /**
+     * 重置盒子和canvas的宽高
+     */
+    private resetWidthAndHeight;
+    /**
+     * 根据 dpr 缩放 canvas 并处理位移
+     */
+    protected zoomCanvas(): void;
+    /**
+     * 从 window 对象上获取一些方法
+     */
+    private initWindowFunction;
+    isWeb(): boolean;
+    /**
+     * 异步加载图片并返回图片的几何信息
+     * @param src 图片路径
+     * @param info 图片信息
+     */
+    protected loadImg(src: string, info: ImgItemType, resolveName?: string): Promise<ImgType>;
+    /**
+     * 公共绘制图片的方法
+     * @param imgObj 图片对象
+     * @param rectInfo: [x轴位置, y轴位置, 渲染宽度, 渲染高度]
+     */
+    protected drawImage(ctx: CanvasRenderingContext2D, imgObj: ImgType, ...rectInfo: [...Tuple<number, 4>, ...Partial<Tuple<number, 4>>]): void;
+    /**
+     * 计算图片的渲染宽高
+     * @param imgObj 图片标签元素
+     * @param imgInfo 图片信息
+     * @param maxWidth 最大宽度
+     * @param maxHeight 最大高度
+     * @return [渲染宽度, 渲染高度]
+     */
+    protected computedWidthAndHeight(imgObj: ImgType, imgInfo: ImgItemType, maxWidth: number, maxHeight: number): [number, number];
+    /**
+     * 转换单位
+     * @param { string } value 将要转换的值
+     * @param { number } denominator 分子
+     * @return { number } 返回新的字符串
+     */
+    protected changeUnits(value: string, denominator?: number): number;
+    /**
+     * 获取长度
+     * @param length 将要转换的长度
+     * @param maxLength 最大长度
+     * @return 返回长度
+     */
+    protected getLength(length: string | number | undefined, maxLength?: number): number;
+    /**
+     * 获取相对(居中)X坐标
+     * @param width
+     * @param col
+     */
+    protected getOffsetX(width: number, maxWidth?: number): number;
+    protected getOffscreenCanvas(width: number, height: number): {
+        _offscreenCanvas: HTMLCanvasElement;
+        _ctx: CanvasRenderingContext2D;
+    } | void;
+    /**
+     * 添加一个新的响应式数据 (临时)
+     * @param data 数据
+     * @param key 属性
+     * @param value 新值
+     */
+    $set(data: object, key: string | number, value: any): void;
+    /**
+     * 添加一个属性计算 (临时)
+     * @param data 源数据
+     * @param key 属性名
+     * @param callback 回调函数
+     */
+    protected $computed(data: object, key: string, callback: Function): void;
+    /**
+     * 添加一个观察者 create user watcher
+     * @param expr 表达式
+     * @param handler 回调函数
+     * @param watchOpt 配置参数
+     * @return 卸载当前观察者的函数 (暂未返回)
+     */
+    protected $watch(expr: string | Function, handler: Function | WatchOptType, watchOpt?: WatchOptType): Function;
+}
+
+declare type PrizeFontType$2 = FontItemType & FontExtendType;
+declare type ButtonFontType$1 = FontItemType & {};
+declare type BlockImgType$2 = ImgItemType & {
+    rotate?: boolean;
+};
+declare type PrizeImgType$2 = ImgItemType & {};
+declare type ButtonImgType$1 = ImgItemType & {};
+declare type BlockType$2 = {
+    padding?: string;
+    background?: BackgroundType;
+    imgs?: Array<BlockImgType$2>;
+};
+declare type PrizeType$2 = {
+    range?: number;
+    background?: BackgroundType;
+    fonts?: Array<PrizeFontType$2>;
+    imgs?: Array<PrizeImgType$2>;
+};
+declare type ButtonType$1 = {
+    radius?: string;
+    pointer?: boolean;
+    background?: BackgroundType;
+    fonts?: Array<ButtonFontType$1>;
+    imgs?: Array<ButtonImgType$1>;
+};
+declare type DefaultConfigType$2 = {
+    gutter?: string | number;
+    offsetDegree?: number;
+    speed?: number;
+    speedFunction?: string;
+    accelerationTime?: number;
+    decelerationTime?: number;
+    stopRange?: number;
+};
+declare type DefaultStyleType$2 = {
+    background?: BackgroundType;
+    fontColor?: PrizeFontType$2['fontColor'];
+    fontSize?: PrizeFontType$2['fontSize'];
+    fontStyle?: PrizeFontType$2['fontStyle'];
+    fontWeight?: PrizeFontType$2['fontWeight'];
+    lineHeight?: PrizeFontType$2['lineHeight'];
+    wordWrap?: PrizeFontType$2['wordWrap'];
+    lengthLimit?: PrizeFontType$2['lengthLimit'];
+    lineClamp?: PrizeFontType$2['lineClamp'];
+};
+declare type StartCallbackType$1 = (e: MouseEvent) => void;
+declare type EndCallbackType$2 = (prize: object) => void;
+interface LuckyWheelConfig {
+    width: string | number;
+    height: string | number;
+    blocks?: Array<BlockType$2>;
+    prizes?: Array<PrizeType$2>;
+    buttons?: Array<ButtonType$1>;
+    defaultConfig?: DefaultConfigType$2;
+    defaultStyle?: DefaultStyleType$2;
+    start?: StartCallbackType$1;
+    end?: EndCallbackType$2;
+}
+
+declare class LuckyWheel extends Lucky {
+    private blocks;
+    private prizes;
+    private buttons;
+    private defaultConfig;
+    private defaultStyle;
+    private _defaultConfig;
+    private _defaultStyle;
+    private startCallback?;
+    private endCallback?;
+    private Radius;
+    private prizeRadius;
+    private prizeDeg;
+    private prizeAng;
+    private rotateDeg;
+    private maxBtnRadius;
+    private startTime;
+    private endTime;
+    private stopDeg;
+    private endDeg;
+    private FPS;
+    /**
+     * 游戏当前的阶段
+     * step = 0 时, 游戏尚未开始
+     * step = 1 时, 此时处于加速阶段
+     * step = 2 时, 此时处于匀速阶段
+     * step = 3 时, 此时处于减速阶段
+     */
+    private step;
+    /**
+     * 中奖索引
+     * prizeFlag = undefined 时, 处于开始抽奖阶段, 正常旋转
+     * prizeFlag >= 0 时, 说明stop方法被调用, 并且传入了中奖索引
+     * prizeFlag === -1 时, 说明stop方法被调用, 并且传入了负值, 本次抽奖无效
+     */
+    private prizeFlag;
+    private ImageCache;
+    /**
+     * 大转盘构造器
+     * @param config 配置项
+     * @param data 抽奖数据
+     */
+    constructor(config: UserConfigType, data: LuckyWheelConfig);
+    protected resize(): void;
+    protected initLucky(): void;
+    /**
+     * 初始化数据
+     * @param data
+     */
+    private initData;
+    /**
+     * 初始化属性计算
+     */
+    private initComputed;
+    /**
+     * 初始化观察者
+     */
+    private initWatch;
+    /**
+     * 初始化 canvas 抽奖
+     */
+    init(): Promise<void>;
+    private initImageCache;
+    /**
+     * canvas点击事件
+     * @param e 事件参数
+     */
+    protected handleClick(e: MouseEvent): void;
+    /**
+     * 根据索引单独加载指定图片并缓存
+     * @param cellName 模块名称
+     * @param cellIndex 模块索引
+     * @param imgName 模块对应的图片缓存
+     * @param imgIndex 图片索引
+     */
+    private loadAndCacheImg;
+    private drawBlock;
+    /**
+     * 开始绘制
+     */
+    protected draw(): void;
+    /**
+     * 刻舟求剑
+     */
+    private carveOnGunwaleOfAMovingBoat;
+    /**
+     * 对外暴露: 开始抽奖方法
+     */
+    play(): void;
+    /**
+     * 对外暴露: 缓慢停止方法
+     * @param index 中奖索引
+     */
+    stop(index?: number): void;
+    /**
+     * 实际开始执行方法
+     * @param num 记录帧动画执行多少次
+     */
+    private run;
+    /**
+     * 换算渲染坐标
+     * @param x
+     * @param y
+     */
+    protected conversionAxis(x: number, y: number): [number, number];
+}
+
+declare type PrizeFontType$1 = FontItemType & FontExtendType;
+declare type ButtonFontType = FontItemType & FontExtendType;
+declare type BlockImgType$1 = ImgItemType & {};
+declare type PrizeImgType$1 = ImgItemType & {
+    activeSrc?: string;
+};
+declare type ButtonImgType = ImgItemType & {};
+declare type BlockType$1 = {
+    borderRadius?: BorderRadiusType;
+    background?: BackgroundType;
+    padding?: string;
+    paddingTop?: string | number;
+    paddingRight?: string | number;
+    paddingBottom?: string | number;
+    paddingLeft?: string | number;
+    imgs?: Array<BlockImgType$1>;
+};
+declare type CellType<T, U> = {
+    x: number;
+    y: number;
+    col?: number;
+    row?: number;
+    borderRadius?: BorderRadiusType;
+    background?: BackgroundType;
+    shadow?: ShadowType;
+    fonts?: Array<T>;
+    imgs?: Array<U>;
+};
+declare type PrizeType$1 = CellType<PrizeFontType$1, PrizeImgType$1> & {
+    range?: number;
+    disabled?: boolean;
+};
+declare type ButtonType = CellType<ButtonFontType, ButtonImgType> & {
+    callback?: Function;
+};
+declare type DefaultConfigType$1 = {
+    gutter?: number;
+    speed?: number;
+    accelerationTime?: number;
+    decelerationTime?: number;
+};
+declare type DefaultStyleType$1 = {
+    borderRadius?: BorderRadiusType;
+    background?: BackgroundType;
+    shadow?: ShadowType;
+    fontColor?: PrizeFontType$1['fontColor'];
+    fontSize?: PrizeFontType$1['fontSize'];
+    fontStyle?: PrizeFontType$1['fontStyle'];
+    fontWeight?: PrizeFontType$1['fontWeight'];
+    lineHeight?: PrizeFontType$1['lineHeight'];
+    wordWrap?: PrizeFontType$1['wordWrap'];
+    lengthLimit?: PrizeFontType$1['lengthLimit'];
+    lineClamp?: PrizeFontType$1['lineClamp'];
+};
+declare type ActiveStyleType = {
+    background?: BackgroundType;
+    shadow?: ShadowType;
+    fontColor?: PrizeFontType$1['fontColor'];
+    fontSize?: PrizeFontType$1['fontSize'];
+    fontStyle?: PrizeFontType$1['fontStyle'];
+    fontWeight?: PrizeFontType$1['fontWeight'];
+    lineHeight?: PrizeFontType$1['lineHeight'];
+};
+declare type RowsType = number;
+declare type ColsType = number;
+declare type StartCallbackType = (e: MouseEvent, button?: ButtonType) => void;
+declare type EndCallbackType$1 = (prize: object) => void;
+interface LuckyGridConfig {
+    width: string | number;
+    height: string | number;
+    rows?: RowsType;
+    cols?: ColsType;
+    blocks?: Array<BlockType$1>;
+    prizes?: Array<PrizeType$1>;
+    buttons?: Array<ButtonType>;
+    button?: ButtonType;
+    defaultConfig?: DefaultConfigType$1;
+    defaultStyle?: DefaultStyleType$1;
+    activeStyle?: ActiveStyleType;
+    start?: StartCallbackType;
+    end?: EndCallbackType$1;
+}
+
+declare class LuckyGrid extends Lucky {
+    private rows;
+    private cols;
+    private blocks;
+    private prizes;
+    private buttons;
+    private button?;
+    private defaultConfig;
+    private defaultStyle;
+    private activeStyle;
+    private _defaultConfig;
+    private _defaultStyle;
+    private _activeStyle;
+    private startCallback?;
+    private endCallback?;
+    private cellWidth;
+    private cellHeight;
+    private startTime;
+    private endTime;
+    private currIndex;
+    private stopIndex;
+    private endIndex;
+    private demo;
+    private timer;
+    private FPS;
+    /**
+     * 游戏当前的阶段
+     * step = 0 时, 游戏尚未开始
+     * step = 1 时, 此时处于加速阶段
+     * step = 2 时, 此时处于匀速阶段
+     * step = 3 时, 此时处于减速阶段
+     */
+    private step;
+    /**
+     * 中奖索引
+     * prizeFlag = undefined 时, 处于开始抽奖阶段, 正常旋转
+     * prizeFlag >= 0 时, 说明stop方法被调用, 并且传入了中奖索引
+     * prizeFlag === -1 时, 说明stop方法被调用, 并且传入了负值, 本次抽奖无效
+     */
+    private prizeFlag;
+    private cells;
+    private prizeArea;
+    private ImageCache;
+    /**
+     * 九宫格构造器
+     * @param config 配置项
+     * @param data 抽奖数据
+     */
+    constructor(config: UserConfigType, data: LuckyGridConfig);
+    protected resize(): void;
+    protected initLucky(): void;
+    /**
+     * 初始化数据
+     * @param data
+     */
+    private initData;
+    /**
+     * 初始化属性计算
+     */
+    private initComputed;
+    /**
+     * 初始化观察者
+     */
+    private initWatch;
+    /**
+     * 初始化 canvas 抽奖
+     */
+    init(): Promise<void>;
+    private initImageCache;
+    /**
+     * canvas点击事件
+     * @param e 事件参数
+     */
+    protected handleClick(e: MouseEvent): void;
+    /**
+     * 根据索引单独加载指定图片并缓存
+     * @param cellName 模块名称
+     * @param cellIndex 模块索引
+     * @param imgName 模块对应的图片缓存
+     * @param imgIndex 图片索引
+     */
+    private loadAndCacheImg;
+    /**
+     * 绘制九宫格抽奖
+     */
+    protected draw(): void;
+    /**
+     * 处理背景色
+     * @param x
+     * @param y
+     * @param width
+     * @param height
+     * @param background
+     * @param isActive
+     */
+    private handleBackground;
+    /**
+     * 刻舟求剑
+     */
+    private carveOnGunwaleOfAMovingBoat;
+    /**
+     * 对外暴露: 开始抽奖方法
+     */
+    play(): void;
+    /**
+     * 对外暴露: 缓慢停止方法
+     * @param index 中奖索引
+     */
+    stop(index?: number): void;
+    /**
+     * 实际开始执行方法
+     * @param num 记录帧动画执行多少次
+     */
+    private run;
+    /**
+     * 计算奖品格子的几何属性
+     * @param { array } [...矩阵坐标, col, row]
+     * @return { array } [...真实坐标, width, height]
+     */
+    private getGeometricProperty;
+    /**
+     * 换算渲染坐标
+     * @param x
+     * @param y
+     */
+    protected conversionAxis(x: number, y: number): [number, number];
+}
+
+declare type PrizeFontType = FontItemType & FontExtendType;
+declare type BlockImgType = ImgItemType & {};
+declare type PrizeImgType = ImgItemType;
+declare type BlockType = {
+    borderRadius?: BorderRadiusType;
+    background?: BackgroundType;
+    padding?: string;
+    paddingTop?: string | number;
+    paddingRight?: string | number;
+    paddingBottom?: string | number;
+    paddingLeft?: string | number;
+    imgs?: Array<BlockImgType>;
+};
+declare type PrizeType = {
+    borderRadius?: BorderRadiusType;
+    background?: BackgroundType;
+    fonts?: Array<PrizeFontType>;
+    imgs?: Array<PrizeImgType>;
+};
+declare type SlotType = {
+    order?: number[];
+    speed?: number;
+    direction?: 1 | -1;
+};
+declare type DefaultConfigType = {
+    /**
+     * vertical 为纵向旋转
+     * horizontal 为横向旋转
+     */
+    mode?: 'vertical' | 'horizontal';
+    /**
+     * 当排列方向 = `vertical`时
+     *    1 bottom to top
+     *   -1 top to bottom
+     * 当排列方向 = `horizontal`时
+     *    1 right to left
+     *   -1 left to right
+     */
+    direction?: 1 | -1;
+    rowSpacing?: number;
+    colSpacing?: number;
+    speed?: number;
+    accelerationTime?: number;
+    decelerationTime?: number;
+};
+declare type DefaultStyleType = {
+    borderRadius?: BorderRadiusType;
+    background?: BackgroundType;
+    fontColor?: PrizeFontType['fontColor'];
+    fontSize?: PrizeFontType['fontSize'];
+    fontStyle?: PrizeFontType['fontStyle'];
+    fontWeight?: PrizeFontType['fontWeight'];
+    lineHeight?: PrizeFontType['lineHeight'];
+    wordWrap?: PrizeFontType['wordWrap'];
+    lengthLimit?: PrizeFontType['lengthLimit'];
+    lineClamp?: PrizeFontType['lineClamp'];
+};
+declare type EndCallbackType = (prize: PrizeType | undefined) => void;
+interface SlotMachineConfig {
+    width: string | number;
+    height: string | number;
+    blocks?: Array<BlockType>;
+    prizes?: Array<PrizeType>;
+    slots?: Array<SlotType>;
+    defaultConfig?: DefaultConfigType;
+    defaultStyle?: DefaultStyleType;
+    end?: EndCallbackType;
+}
+
+declare class SlotMachine extends Lucky {
+    private blocks;
+    private prizes;
+    private slots;
+    private defaultConfig;
+    private _defaultConfig;
+    private defaultStyle;
+    private _defaultStyle;
+    private endCallback;
+    private _offscreenCanvas?;
+    private cellWidth;
+    private cellHeight;
+    private cellAndSpacing;
+    private widthAndSpacing;
+    private heightAndSpacing;
+    private FPS;
+    private scroll;
+    private stopScroll;
+    private endScroll;
+    private startTime;
+    private endTime;
+    /**
+     * 游戏当前的阶段
+     * step = 0 时, 游戏尚未开始
+     * step = 1 时, 此时处于加速阶段
+     * step = 2 时, 此时处于匀速阶段
+     * step = 3 时, 此时处于减速阶段
+     */
+    private step;
+    /**
+     * 中奖索引
+     * prizeFlag = undefined 时, 处于开始抽奖阶段, 正常旋转
+     * prizeFlag >= 0 时, 说明stop方法被调用, 并且传入了中奖索引
+     * prizeFlag === -1 时, 说明stop方法被调用, 并且传入了负值, 本次抽奖无效
+     */
+    private prizeFlag;
+    private prizeArea?;
+    private ImageCache;
+    /**
+     * 老虎机构造器
+     * @param config 配置项
+     * @param data 抽奖数据
+     */
+    constructor(config: UserConfigType, data: SlotMachineConfig);
+    protected resize(): void;
+    protected initLucky(): void;
+    /**
+     * 初始化数据
+     * @param data
+     */
+    private initData;
+    /**
+     * 初始化属性计算
+     */
+    private initComputed;
+    /**
+     * 初始化观察者
+     */
+    private initWatch;
+    /**
+     * 初始化 canvas 抽奖
+     */
+    init(): Promise<void>;
+    private initImageCache;
+    /**
+     * 根据索引单独加载指定图片并缓存
+     * @param cellName 模块名称
+     * @param cellIndex 模块索引
+     * @param imgName 模块对应的图片缓存
+     * @param imgIndex 图片索引
+     */
+    private loadAndCacheImg;
+    /**
+     * 绘制离屏canvas
+     */
+    protected drawOffscreenCanvas(): void;
+    /**
+     * 绘制背景区域
+     */
+    protected drawBlocks(): SlotMachine['prizeArea'];
+    /**
+     * 绘制老虎机抽奖
+     */
+    protected draw(): void;
+    /**
+     * 刻舟求剑
+     */
+    private carveOnGunwaleOfAMovingBoat;
+    /**
+     * 对外暴露: 开始抽奖方法
+     */
+    play(): void;
+    stop(index: number | number[]): void;
+    /**
+     * 让游戏动起来
+     * @param num 记录帧动画执行多少次
+     */
+    private run;
+    private displacement;
+    private displacementWidthOrHeight;
+}
+
+/**
+ * 切割圆角
+ * @param img 将要裁剪的图片对象
+ * @param radius 裁剪的圆角半径
+ * @returns 返回一个离屏 canvas 用于渲染
+ */
+declare const cutRound: (img: ImgType, radius: number) => ImgType;
+/**
+ * 透明度
+ * @param img 将要处理的图片对象
+ * @param opacity 透明度
+ * @returns 返回一个离屏 canvas 用于渲染
+ */
+declare const opacity: (img: ImgType, opacity: number) => ImgType;
+
+export { LuckyGrid, LuckyWheel, SlotMachine, cutRound, opacity };

+ 12 - 3
manifest.json

@@ -41,9 +41,13 @@
 				]
 			},
 			/* ios打包配置 */
-			"ios": {},
+			"ios": {
+				"dSYMs": false
+			},
 			/* SDK配置 */
-			"sdkConfigs": {}
+			"sdkConfigs": {
+				"ad": {}
+			}
 		}
 	},
 	/* 快应用特有相关 */
@@ -68,5 +72,10 @@
 	"uniStatistics": {
 		"enable": false
 	},
-	"vueVersion": "2"
+	"vueVersion": "2",
+	"h5": {
+		"router": {
+			"base": "zhuche"
+		}
+	}
 }

+ 15 - 14
package.json

@@ -1,15 +1,16 @@
 {
-  "name": "yaojiu",
-  "version": "1.0.0",
-  "description": "",
-  "main": "main.js",
-  "scripts": {
-    "test": "echo \"Error: no test specified\" && exit 1"
-  },
-  "keywords": [],
-  "author": "",
-  "license": "ISC",
-  "dependencies": {
-    "uview-ui": "^2.0.36"
-  }
-}
+    "id": "WF-scroll",
+    "name": "上下滚动样式,考虑到每个人使用的场景不同,所以没写样式,样式可以自己自定义",
+    "displayName": "上下滚动样式,考虑到每个人使用的场景不同,所以没写样式,样式可以自己自定义",
+    "version": "1.1.0",
+    "description": "手机端(小程序,app,H5)上下滚动样式,可自定义滚动内容,可自行设置是否滚动,手指触摸暂停滚动松手自动滚动",
+    "keywords": [
+        "uniapp"
+    ],
+    "dcloudext": {
+        "category": [
+            "前端组件",
+            "通用组件"
+        ]
+    }
+}

+ 30 - 4
pages.json

@@ -7,16 +7,42 @@
 		{
 			"path": "pages/index/index",
 			"style": {
-				"navigationBarTitleText": "uni-app"
+				"navigationBarTitleText": "uni-app",
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/zhuanpan/zhuanpan",
+			"style" :
+			{
+				"navigationBarTitleText" : "",
+				"enablePullDownRefresh" : false,
+				"navigationStyle": "custom"
+			}
+		},
+		{
+			"path" : "pages/lotteryRecord/lotteryRecord",
+			"style" :
+			{
+				"navigationBarTitleText" : "幸运大转盘",
+				"enablePullDownRefresh" : false
+			}
+		},
+		{
+			"path" : "pages/lotteryRule/lotteryRule",
+			"style" :
+			{
+				"navigationBarTitleText" : "幸运大转盘",
+				"enablePullDownRefresh" : false
 			}
 		}
 	],
 	"globalStyle": {
-		"navigationStyle": "custom",
+
 		"navigationBarTextStyle": "black",
 		"navigationBarTitleText": "uni-app",
-		"navigationBarBackgroundColor": "#F8F8F8",
-		"backgroundColor": "#F8F8F8"
+		"navigationBarBackgroundColor": "#fa7b12",
+		"backgroundColor": "#fa7b12"
 	},
 	"uniIdRouter": {}
 }

+ 71 - 0
pages/index/index.rpx.scss

@@ -0,0 +1,71 @@
+.page {
+  width: 100vw;
+  height: 100vh;
+  position: relative;
+}
+
+.bg {
+  width: 100%;
+  height: 100%;
+}
+
+.content {
+  width: 100vw;
+  position: absolute;
+  bottom: 100rpx;
+  left: 0;
+}
+
+
+.inputView {
+  width: 646rpx;
+  min-height: 50rpx;
+  background: white;
+  margin-top: 20rpx;
+  margin-left: 32rpx;
+  border-radius: 15rpx;
+  overflow: hidden;
+  padding: 10rpx 20rpx;
+}
+.inputView1 {
+  background-color: rgba(255, 255, 255, 0.5)
+}
+
+.tips {
+  color: #b63a3a;
+
+
+}
+.zcbtn{
+  background: #fed09e;
+  width: 686rpx;
+  height: 80rpx;
+  border-radius: 40rpx;
+  text-align: center;
+  color: #bc372b;
+  line-height: 80rpx;
+  font-size: 36rpx;
+  margin-top: 20rpx;
+  margin-left: 32rpx;
+}
+.read{
+  color: white;
+  font-size: 22rpx;
+  margin-top: 20rpx;
+}
+.icon{
+  margin-top: 5rpx;
+}
+.xiazai{
+  width: 686rpx;
+  margin-top: 20rpx;
+  margin-left: 32rpx;
+  font-size: 26rpx;
+}
+.agree{
+  width: 686rpx;
+  height: 80vh;
+  border-radius: 15rpx;
+  background: white;
+  overflow: auto;
+}

+ 2 - 72
pages/index/index.vue

@@ -210,77 +210,7 @@
     }
 </script>
 
-<style>
-    .page {
-        width: 100vw;
-        height: 100vh;
-        position: relative;
-    }
-
-    .bg {
-        width: 100%;
-        height: 100%;
-    }
-
-    .content {
-        width: 100vw;
-        position: absolute;
-        bottom: 100rpx;
-        left: 0;
-    }
-
-
-    .inputView {
-        width: 646rpx;
-        min-height: 50rpx;
-        background: white;
-        margin-top: 20rpx;
-        margin-left: 32rpx;
-        border-radius: 15rpx;
-        overflow: hidden;
-        padding: 10rpx 20rpx;
-    }
-    .inputView1 {
-        background-color: rgba(255, 255, 255, 0.5)
-    }
-
-    .tips {
-        color: #b63a3a;
-
-
-    }
-	.zcbtn{
-		background: #fed09e;
-		width: 686rpx;
-		height: 80rpx;
-		border-radius: 40rpx;
-		text-align: center;
-		color: #bc372b;
-		line-height: 80rpx;
-		font-size: 36rpx;
-        margin-top: 20rpx;
-		margin-left: 32rpx;
-	}
-    .read{
-        color: white;
-        font-size: 22rpx;
-        margin-top: 20rpx;
-    }
-    .icon{
-        margin-top: 5rpx;
-    }
-    .xiazai{
-        width: 686rpx;
-        margin-top: 20rpx;
-        margin-left: 32rpx;
-        font-size: 26rpx;
-    }
-    .agree{
-        width: 686rpx;
-        height: 80vh;
-        border-radius: 15rpx;
-        background: white;
-        overflow: auto;
-    }
+<style scoped lang="scss">
+    @import './index.rpx.scss';
 </style>
 

+ 23 - 0
pages/lotteryRecord/index.rpx.scss

@@ -0,0 +1,23 @@
+.page {
+  background-image: linear-gradient(180deg, #fa7b12,#ed4f39);
+  padding: 0 32rpx;
+}
+.content{
+  background: #fff7e4;
+  border-radius: 30rpx;
+}
+.titlePhoto{
+  width: 350rpx;
+}
+.record{
+  overflow: auto;
+}
+.recordItem{
+  padding: 0 24rpx;
+  line-height: 70rpx;
+  border-bottom: 1px solid #f1f1f1;
+  font-size: 30rpx;
+}
+.text1{
+  color: #F56C6C;
+}

+ 37 - 0
pages/lotteryRecord/lotteryRecord.vue

@@ -0,0 +1,37 @@
+<template>
+	<view class="page"  :style="{height:windowHeight + 'px'}">
+
+		<view class="content" :style="{height:windowHeight *0.95  +'px'}">
+			<view class="flex-row justify-center">
+				<image  :src="'/static/img/1712668343314.jpg'" mode="widthFix" class="titlePhoto"></image>
+			</view>
+			<view class="flex-col record" :style="{height:windowHeight * 0.95 - 60 +'px'}">
+				<view class="flex-row justify-between recordItem" v-for="(item,index) in 100">
+					<text>2021年3月29日09:22</text>
+					<text class="text1">扫地机器人</text>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				windowHeight:'',
+			}
+		},
+		onLoad(){
+			let sysinfo = uni.getSystemInfoSync()
+			this.windowHeight = sysinfo.windowHeight
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	@import './index.rpx.scss';
+</style>

+ 12 - 0
pages/lotteryRule/index.rpx.scss

@@ -0,0 +1,12 @@
+.page {
+  background-image: linear-gradient(180deg, #fa7b12,#ed4f39);
+  padding: 0 32rpx;
+}
+.content{
+  background: #fff7e4;
+  border-radius: 30rpx;
+}
+.titlePhoto{
+  width: 500rpx;
+}
+

+ 33 - 0
pages/lotteryRule/lotteryRule.vue

@@ -0,0 +1,33 @@
+<template>
+	<view class="page" :style="{height:windowHeight + 'px'}">
+
+		<view class="content">
+			<view class="flex-row justify-center" :style="{height:windowHeight * 0.95 + 'px'}">
+				<image  :src="'/static/img/1712667932387.jpg'" mode="widthFix" class="titlePhoto"></image>
+			</view>
+
+		</view>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				windowHeight:''
+			}
+		},
+		onLoad(){
+			let sysinfo = uni.getSystemInfoSync()
+			this.windowHeight = sysinfo.windowHeight
+		},
+		methods: {
+
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	@import './index.rpx.scss';
+</style>

+ 58 - 0
pages/zhuanpan/index.rpx.scss

@@ -0,0 +1,58 @@
+.page{
+  width: 100vw;
+  height: 100vh;
+  position: relative;
+}
+.bg {
+  width: 100%;
+  height: 100%;
+}
+.content{
+  width: 686rpx;
+  height: 75vh;
+  position: absolute;
+  left: 32rpx;
+  bottom: 2vh;
+  background: #FFFFFF;
+  border-radius: 30rpx;
+}
+.record{
+  color: #ff6f91;
+  padding: 20rpx;
+  font-size: 35rpx;
+}
+.record-left{
+  margin-right: 20rpx;
+}
+.count{
+  background-image: linear-gradient(45deg, #fa7b12,#ed4f39);
+  width: 500rpx;
+  height: 80rpx;
+  border-radius: 40rpx;
+  line-height: 80rpx;
+  text-align: center;
+  margin-left: 93rpx;
+  margin-top: 20rpx;
+  color: white;
+}
+.roll{
+  flex: 1;
+  margin-top: 20rpx;
+}
+
+.rule{
+  width: 140rpx;
+  height: 80rpx;
+  border-top-right-radius: 40rpx;
+  border-bottom-right-radius: 40rpx;
+  position: fixed;
+  top: 28vh;
+  background: #ffc000;
+  z-index: 100;
+  line-height: 80rpx;
+  text-align: center;
+  font-size: 35rpx;
+  font-weight: 500;
+  color: white;
+}
+

+ 126 - 0
pages/zhuanpan/zhuanpan.vue

@@ -0,0 +1,126 @@
+<template>
+	<view class="page">
+		<image class="bg" :src="'/static/img/DM_20240409173533_003.jpg'"></image>
+		<view class="rule" @click="goRule">
+			<text>规则</text>
+		</view>
+		<view class="flex-col content">
+			<view class="flex-row justify-end">
+				<view class="flex-row justify-end record"  @click="goRecord">
+					<text class="record-left">中奖记录</text>
+					<u-icon name="/static/img/DM_20240409173533_004.png" size="45rpx"></u-icon>
+				</view>
+			</view>
+
+			<view>
+				<LuckyWheel ref="myLucky" width="550rpx" height="550rpx"
+							:blocks="blocks" :prizes="prizes" :buttons="buttons"
+							@start="startCallBack" @end="endCallBack"/>
+			</view>
+
+			<view class="count">
+				<text>您有0次抽奖机会</text>
+			</view>
+			<view id="rollId" class="roll">
+				<wfScroll :scrollHeight="scrollHeight" :scrollTimer="true">
+					<view class="flex-row justify-between rollItem" v-for="(item,index) in 10">
+						<view>
+							<text class="text1">17365000014</text>
+							<text class="text2">2021年3月29日09:22</text>
+						</view>
+						<view>
+							<text class="text3">一等奖</text>
+							<text class="text2">扫地机器人</text>
+						</view>
+					</view>
+				</wfScroll>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import wfScroll from "../../components/WF-scroll/WF-scroll";
+	import LuckyWheel from "../../components/@lucky-canvas/uni/lucky-wheel";
+	export default {
+		components: {LuckyWheel,wfScroll},
+		data() {
+			return {
+				scrollHeight:0,
+
+				blocks: [
+						{ padding: '55rpx'},
+					{imgs:[{src:'static/img/zpbg.png',width:'550rpx',height:'550rpx',top:'-55rpx',rotate:true}]}
+				],
+				prizes: [
+					{ fonts: [{ text: '一等奖', top: '10%',fontSize:'25rpx' }],imgs:[{src:'static/img/DM_20240409173533_004.png',top:'40%'}], background: '#fff9d9' },
+					{ fonts: [{ text: '小米手机', top: '10%',fontSize:'25rpx' }], background: '#f6ecb4' },
+					{ fonts: [{ text: '大彩电', top: '10%',fontSize:'25rpx' }], background: '#fff9d9' },
+					{ fonts: [{ text: '小踩点', top: '10%',fontSize:'25rpx' }], background: '#f6ecb4' },
+					{ fonts: [{ text: '耳机', top: '10%',fontSize:'25rpx' }], background: '#fff9d9' },
+					{ fonts: [{ text: '收音机', top: '10%',fontSize:'25rpx' }], background: '#f6ecb4' },
+				],
+				buttons: [
+					{ radius: '90rpx', background: '#fddc6a'},
+					// {
+					// 	radius: '40px', background: '#fddc6a',
+					// 	pointer: true,
+					// 	fonts: [{ text: '开始\n抽奖', top: '-30px',fontColor:'#fa4445',fontWeight:'700',fontSize:'40rpx',lineHeight:'50rpx' }]
+					// },
+
+					{
+						imgs: [{src:'static/img/DM_20240409173533_001.png',width:'200rpx',height:'240rpx',top:'-140rpx'}],
+					},
+				],
+			}
+		},
+
+		mounted(){
+			this.getScrollHeight();
+		},
+		methods: {
+
+			goRecord(){
+				uni.navigateTo({
+					url:'/pages/lotteryRecord/lotteryRecord'
+				})
+			},
+			goRule(){
+				uni.navigateTo({
+					url:'/pages/lotteryRule/lotteryRule'
+				})
+			},
+
+			getScrollHeight(){
+				const query = uni.createSelectorQuery().in(this);
+				query.select('#rollId').boundingClientRect(data => {
+					let sysinfo = uni.getSystemInfoSync()
+					this.scrollHeight = (sysinfo.screenWidth/750) * data.height
+					console.log('元素的高度:', this.scrollHeight);
+				}).exec();
+			},
+
+			// 点击抽奖按钮触发回调
+			startCallBack () {
+				// 先开始旋转
+				this.$refs.myLucky.play()
+				// 使用定时器来模拟请求接口
+				setTimeout(() => {
+					// 假设后端返回的中奖索引是0
+					const index = 3
+					// 调用stop停止旋转并传递中奖索引
+					this.$refs.myLucky.stop(index)
+				}, 3000)
+			},
+			// 抽奖结束触发回调
+			endCallBack (prize) {
+				// 奖品详情
+				console.log(prize)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import './index.rpx.scss';
+</style>

BIN
static/img/1712667932387.jpg


BIN
static/img/1712668343314.jpg


BIN
static/img/DM_20240409173533_001.png


BIN
static/img/DM_20240409173533_003.jpg


BIN
static/img/DM_20240409173533_004.png


BIN
static/img/DM_20240409173533_005.png


BIN
static/img/DM_20240409173533_006.png


BIN
static/img/DM_20240409173533_007.png


BIN
static/img/zpbg.png


Some files were not shown because too many files changed in this diff