Bladeren bron

12.10-12.11 修改:投票列表、投票详情、分享海报、地图页

yfso 2 jaren geleden
commit
121846c27f
100 gewijzigde bestanden met toevoegingen van 20069 en 0 verwijderingen
  1. 4 0
      .gitignore
  2. 31 0
      App.vue
  3. 143 0
      README.md
  4. 52 0
      api/active/active.js
  5. 12 0
      api/category/category.js
  6. 27 0
      api/document/document.js
  7. 83 0
      api/episode.js
  8. 29 0
      api/hotel/hotel.js
  9. 37 0
      api/index.js
  10. 22 0
      api/integral/integral.js
  11. 30 0
      api/lottery/lottery.js
  12. 102 0
      api/my/my.js
  13. 46 0
      api/orders/orders.js
  14. 11 0
      api/pay.js
  15. 22 0
      api/product/product.js
  16. 39 0
      api/setting.js
  17. 35 0
      api/share/index.js
  18. 16 0
      api/share/order.js
  19. 16 0
      api/share/team.js
  20. 24 0
      api/share/withdraw.js
  21. 26 0
      api/sign.js
  22. 37 0
      api/user/collect.js
  23. 16 0
      api/user/consume.js
  24. 50 0
      api/user/episode.js
  25. 29 0
      api/user/favorite.js
  26. 83 0
      api/user/index.js
  27. 24 0
      api/user/recharge.js
  28. 23 0
      api/user/vip.js
  29. 30 0
      components/CheckLogin/index.vue
  30. 147 0
      components/Episode/index.vue
  31. 104 0
      components/NavBar/index.vue
  32. 353 0
      components/Recharge/index.vue
  33. 119 0
      components/SwiperBox/index.vue
  34. 185 0
      components/TabBar/tabbar.vue
  35. 55 0
      components/bottombtn/bottombtn.vue
  36. 281 0
      components/hch-position/hch-position.vue
  37. 78 0
      components/lime-painter/canvas.js
  38. 686 0
      components/lime-painter/draw.js
  39. 107 0
      components/lime-painter/gradient.js
  40. 286 0
      components/lime-painter/index.vue
  41. 372 0
      components/lime-painter/layout.js
  42. 1 0
      components/lime-painter/qrcode.js
  43. 437 0
      components/lime-painter/utils.js
  44. 116 0
      components/my-nav/my-nav.vue
  45. 114 0
      components/q-turntable/q-turntable.vue
  46. 142 0
      components/waterfall/waterfall-item.vue
  47. 239 0
      components/waterfall/waterfall-list.vue
  48. 20 0
      index.html
  49. 33 0
      main.js
  50. 86 0
      manifest.json
  51. 31 0
      package-lock.json
  52. 15 0
      package.json
  53. 330 0
      pages.json
  54. 825 0
      pages/goods/goods-detail/index.vue
  55. 213 0
      pages/goods/goods-hotel/index.vue
  56. 468 0
      pages/goods/goods-lucky/index.vue
  57. 376 0
      pages/goods/goods.vue
  58. 971 0
      pages/index/active-detail/index.vue
  59. 339 0
      pages/index/active-list/index.vue
  60. 1125 0
      pages/index/index.vue
  61. 908 0
      pages/index/vote-detail/index.vue
  62. 261 0
      pages/index/vote-detail/poster.vue
  63. 294 0
      pages/login/login.vue
  64. 457 0
      pages/login/youyue.vue
  65. 366 0
      pages/map/hotel-book/index.vue
  66. 664 0
      pages/map/map - 副本.vue
  67. 1021 0
      pages/map/map.vue
  68. 236 0
      pages/msg/msg.vue
  69. 182 0
      pages/my/Kudos/Kudos.vue
  70. 323 0
      pages/my/PersonalData/personalData.vue
  71. 363 0
      pages/my/integral/integral.vue
  72. 188 0
      pages/my/integral/integralExchange.vue
  73. 558 0
      pages/my/integral/integralOrder.vue
  74. 271 0
      pages/my/integral/integralRecord.vue
  75. 62 0
      pages/my/integral/integralRule.vue
  76. 568 0
      pages/my/my.vue
  77. 371 0
      pages/my/myorders/orderDetail.vue
  78. 604 0
      pages/my/myorders/orders.vue
  79. 182 0
      pages/my/prize/exchangeDetail.vue
  80. 259 0
      pages/my/prize/exchangePrize.vue
  81. 374 0
      pages/my/prize/prize.vue
  82. 76 0
      pages/my/protocol/PrivacyPolicy.vue
  83. 74 0
      pages/my/protocol/UserAgreement.vue
  84. 168 0
      pages/my/setting/setting.vue
  85. 271 0
      pages/my/verification/orderVerification.vue
  86. 376 0
      pages/my/verification/verification.vue
  87. 297 0
      pages/my/verification/verificationDetail.vue
  88. 36 0
      pages/webview/webview.vue
  89. 16 0
      setting.js
  90. 29 0
      static/css/common.scss
  91. 266 0
      static/css/flex.scss
  92. 3 0
      static/css/iconfont.css
  93. 12 0
      static/css/mixin.scss
  94. 172 0
      static/css/store-buy.scss
  95. 8 0
      static/css/variable.scss
  96. BIN
      static/icon/Kudos(1).png
  97. BIN
      static/icon/Kudos.png
  98. BIN
      static/icon/Receipt.png
  99. BIN
      static/icon/add01.png
  100. BIN
      static/icon/address01.png

+ 4 - 0
.gitignore

xqd
@@ -0,0 +1,4 @@
+/node_modules
+/unpackage
+/.hbuilderx
+/.idea

+ 31 - 0
App.vue

xqd
@@ -0,0 +1,31 @@
+<script>
+	export default {
+		onLaunch: function() {
+			console.log('App Launch')
+		},
+		onShow: function() {
+			console.log('App Show')
+			uni.hideTabBar()
+		},
+		onHide: function() {
+			console.log('App Hide')
+		}
+	}
+</script>
+
+<style lang="scss">
+	/*每个页面公共css */
+	@import "uview-ui/index.scss";
+	@import '@/static/css/flex.scss';
+	@import '@/static/css/common.scss';
+	@import '@/static/css/iconfont.css';
+
+	page{
+		height: 100%;
+	}
+
+	
+	
+	
+
+</style>

+ 143 - 0
README.md

xqd
@@ -0,0 +1,143 @@
+## 一、支持平台
+
+| App    | H5  | 微信小程序 | 支付宝小程序 | 百度小程序 | 字节跳动小程序 | QQ 小程序 |
+| ------ | --- | ---------- | ------------ | ---------- | -------------- | --------- |
+| 未测试 | √   | √          | √            | √          | √              | √         |
+
+## 二、效果演示
+
+<table>
+<tr>
+    <th>兼容不同屏幕大小</th>
+    <th>绘制图形,图片,文本等展示</th>
+  </tr>
+  <tr>
+    <td><img src="https://huangchunhongzz.gitee.io/imgs/poster/poster_gif.gif" height = '400' /></td>
+    <td><img src="https://huangchunhongzz.gitee.io/imgs/poster/poster_gif_20210730.gif" height = '400'  /></td>
+  </tr>
+</table>
+
+## 三、注意事项
+
+### 1、小程序下获取网络图片信息需先配置 downloadFile 域名白名单才能生效。否则会报错(downloadFile 合法域名校验失败),并且绘制海报失败
+
+流程:开发平台->服务器域名->uploadFile 合法域名要添加上 https://huangchunhongzz.gitee.io 否则没办法下载成功图片
+
+### 2、hch-poster 海报模板,主要按照苹果 375\*667 比例,其他型号手机等比例缩放绘制海报,以达到兼容不同屏幕大小的效果
+
+### 3、微信小程序要在基础库 2.16.0 及以下,否则会报(Uncaught TypeError: Cannot delete property 'WeixinJSBridge' of #<Window>)页面空白现象
+
+### 4、H5 需要注意使用的图片要支持跨域(插件例子的图片目前是不支持跨域的,可以自行替换成支持跨域的图片,已测试可行性)
+
+## 四、海报模板使用方法(主要看 pages/hch-poster 页面的例子里面有详细说明)
+
+```js
+
+<hch-poster ref="hchPoster" @cancel="handleCancel" :posterData.sync="posterData" @previewImage='previewImage' />
+
+import HchPoster from "../../components/hch-poster/hch-poster.vue"
+
+export default {
+  components: {
+    HchPoster
+  },
+  data() {
+    return {
+      // 海报模板数据
+      posterData: {
+        poster: {
+          //根据屏幕大小自动生成海报背景大小
+          url: "https://huangchunhongzz.gitee.io/imgs/poster/poster_bg_3.png",//图片地址
+          r: 10, //圆角半径
+          w: 300, //海报宽度
+          h: 480, //海报高度
+          p: 20 //海报内边距padding
+        },
+        mainImg: {
+          //海报主商品图
+          url: "https://huangchunhongzz.gitee.io/imgs/poster/product.png",//图片地址
+          r: 10, //圆角半径
+          w: 250, //宽度
+          h: 200 //高度
+        },
+        title: {
+          //商品标题
+          text: "今日上新水果,牛奶草莓,颗粒饱满,每盒 200g",//文本
+          fontSize: 16, //字体大小
+          color: "#000", //颜色
+          lineHeight: 25, //行高
+          mt: 20 //margin-top
+        },
+        codeImg: {
+          //小程序码
+          url: "https://huangchunhongzz.gitee.io/imgs/poster/code.png",//图片地址
+          w: 100, //宽度
+          h: 100, //高度
+          mt: 20, //margin-top
+          r: 50 //圆角半径
+        },
+        tips: [
+          //提示信息
+          {
+            text: "记忆之王",//文本
+            fontSize: 14,//字体大小
+            color: "#2f1709",//字体颜色
+            align: "center",//对齐方式
+            lineHeight: 25,//行高
+            mt: 20//margin-top
+          },
+          {
+            text: "长按/扫描识别查看商品",//文本
+            fontSize: 12,//字体大小
+            color: "#2f1709",//字体颜色
+            align: "center",//对齐方式
+            lineHeight: 25,//行高
+            mt: 20//margin-top
+          }
+        ]
+      }
+    }
+  }
+}
+
+```
+
+## 五、API
+
+### 生成海报的方法调用如
+
+```js
+this.$refs.hchPoster.posterShow()
+```
+
+### 取消海报
+
+```js
+//有$emit方法
+this.$emit('cancel', true)
+// 所以在组件中用@cancel绑定方法适用
+// <hch-poster ref="hchPoster" @cancel="handleCancel" :posterData.sync="posterData" @previewImage='previewImage' />
+```
+
+### 海报预览(H5 端才有的方法)
+
+```js
+//有$emit方法
+this.$emit('previewImage', base64)
+// 所以在组件中用@previewImage绑定方法适用
+// <hch-poster ref="hchPoster" @cancel="handleCancel" :posterData.sync="posterData" @previewImage='previewImage' />
+```
+
+## 六、props
+
+| name | 描述 | 默认值 | 类型 |
+| --- | --- | --- | --- |
+| posterData | 海报的属性(修改海报的属性值就可以生成自己的海报) | (具体数据参考上方,posterData:{}) | Object |
+
+## 七、开源不易,喜欢的请 star
+
+### 喜欢这个海报,觉得好用的,可以支持打赏下哦
+
+<table>
+<img src="https://gitee.com/huangchunhongzZ/imgs/raw/master/poster/weixin.jpg" height = '200' style='height:400px;'  />
+</table>

+ 52 - 0
api/active/active.js

xqd
@@ -0,0 +1,52 @@
+const request = uni.$u.http
+
+// 获取活动列表
+export function getActiveList(data){
+	return request.post(
+		`v1/activity/activityList`,
+		data
+	)
+}
+// 获取活动详情
+export function getActiveDetail(data){
+	return request.post(
+		`v1/activity/activityDetail`,
+		data
+	)
+}
+// 点赞
+export function kudos(data){
+	return request.post(
+		`v1/activity/activityLike`,
+		data
+	)
+}
+// 获取活动项目列表
+export function getActiveProjectList(data){
+	return request.post(
+		`v1/activity/activityProjectList`,
+		data
+	)
+}
+// 获取活动项目详情
+export function getActiveProjectDetail(data){
+	return request.post(
+		`v1/activity/activityProjectDetail`,
+		data
+	)
+}
+// 投票
+export function vote(data){
+	return request.post(
+		`v1/activity/vote`,
+		data
+	)
+}
+export default {
+  getActiveDetail,
+  getActiveList,
+  kudos,
+  getActiveProjectList,
+  getActiveProjectDetail,
+  vote
+}

+ 12 - 0
api/category/category.js

xqd
@@ -0,0 +1,12 @@
+const request = uni.$u.http
+
+// 分类列表
+export function getCategoryList(data) {
+	return request.post(
+		`v1/setting/categoryList`,
+		data
+	)
+}
+export default {
+	getCategoryList
+}

+ 27 - 0
api/document/document.js

xqd
@@ -0,0 +1,27 @@
+const request = uni.$u.http
+
+// 隐私协议
+export function privacy(){
+	return request.get(
+		`privacy`
+	)
+}
+// 用户协议
+export function agreement(){
+	return request.get(
+		`agreement`
+	)
+}
+
+//配置数据
+export function allSet(){
+	return request.get(
+		`index/get_all_settings`
+	)
+}
+
+export default {
+  privacy,
+  agreement,
+  allSet
+}

+ 83 - 0
api/episode.js

xqd
@@ -0,0 +1,83 @@
+const request = uni.$u.http
+
+export function recommend() {
+  return request.get(
+    'episode/recommend'
+  )
+}
+
+export function news() {
+  return request.get(
+    'episode/news'
+  )
+}
+
+export function rank() {
+  return request.get(
+    'episode/rank'
+  )
+}
+
+export function todayRecommend() {
+  return request.get(
+    'episode/today/recommend'
+  )
+}
+
+export function detail(id) {
+  return request.get(
+    `episode/${id}/detail`
+  )
+}
+
+export function trace() {
+  return request.get(
+    'episode/trace'
+  )
+}
+
+export function list(params) {
+  return request.get(
+    'episode/list',
+    { params }
+  )
+}
+
+export function shared(id) {
+  return request.post(
+    `episode/shared/${id}`
+  )
+}
+
+export function search(params) {
+  return request.get(
+    `episode/search`,
+    { params }
+  )
+}
+
+export function vipFree(params) {
+  return request.get(
+    `episode/vip/free`,
+    { params }
+  )
+}
+
+export function listBuyNum(list_id) {
+  return request.get(
+    `episode/list/${list_id}/buyNum`
+  )
+}
+
+export default {
+  recommend,
+  news,
+  rank,
+  todayRecommend,
+  detail,
+  trace,
+  list,
+  search,
+  vipFree,
+  listBuyNum
+}

+ 29 - 0
api/hotel/hotel.js

xqd
@@ -0,0 +1,29 @@
+const request = uni.$u.http
+
+// 酒店列表
+export function getHotelList(data){
+	return request.post(
+		`v1/hotel/hotelList`,
+		data
+	)
+}
+// 酒店分类列表
+export function getHotelCategory(data){
+	return request.post(
+		`v1/hotel/categoryList`,
+		data
+	)
+}
+// 酒店详情
+export function getHotelDetail(data){
+	return request.post(
+		`v1/hotel/hotelDetail`,
+		data
+	)
+}
+
+export default {
+  getHotelList,
+  getHotelCategory,
+  getHotelDetail
+}

+ 37 - 0
api/index.js

xqd
@@ -0,0 +1,37 @@
+import user from './user/index'
+import setting from './setting'
+import episode from './episode'
+import sign from './sign'
+import pay from './pay'
+import share from './share'
+// 酒店
+import document from './document/document.js'
+import my from './my/my.js'
+import hotel from './hotel/hotel.js'
+import active from './active/active.js'
+import category from './category/category.js'
+import integral from './integral/integral.js'
+import product from './product/product.js'
+import lottery from './lottery/lottery.js'
+import orders from './orders/orders.js'
+
+const api = {
+	user,
+	setting,
+	episode,
+	sign,
+	pay,
+	share,
+
+	category,
+	document,
+	my,
+	hotel,
+	active,
+	integral,
+	product,
+	lottery,
+	orders
+}
+
+export default api

+ 22 - 0
api/integral/integral.js

xqd
@@ -0,0 +1,22 @@
+const request = uni.$u.http
+
+// 获取积分日志
+export function getIntegralLog(data){
+	return request.post(
+		`v1/integral/integralLog`,
+		data
+	)
+}
+// 积分兑换
+export function integralExchange(data){
+	return request.post(
+		`v1/integral/integralExchange`,
+		data
+	)
+}
+
+
+export default {
+  getIntegralLog,
+  integralExchange
+}

+ 30 - 0
api/lottery/lottery.js

xqd
@@ -0,0 +1,30 @@
+const request = uni.$u.http
+
+// 抽奖
+export function luckyDraw(data){
+	return request.post(
+		`v1/draw/luckyDraw`,
+		data
+	)
+}
+
+// 抽奖详情
+export function getDrawInfo(data){
+	return request.post(
+		`v1/draw/drawInfo`,
+		data
+	)
+}
+// 中奖记录
+export function getDrawRecord(data){
+	return request.post(
+		`v1/draw/drawRecord`,
+		data
+	)
+}
+
+export default {
+  luckyDraw,
+  getDrawInfo,
+  getDrawRecord
+}

+ 102 - 0
api/my/my.js

xqd
@@ -0,0 +1,102 @@
+const request = uni.$u.http
+
+//获取地区{{host}}/api/index/all_region
+export function allRegion(params) {
+	return request.get(
+		`index/all_region`, {
+			params
+		}
+	)
+}
+
+
+// 隐私协议
+export function myLogin(data) {
+	return request.post(
+		`auth/mnplogin`,
+		data
+	)
+}
+
+export function joinVip(data) {
+	return request.post(
+		`v1/user/userJoinVip`,
+		data
+	)
+}
+
+export function update(data) {
+	return request.post(
+		`users/1/update_avatar_nickname`,
+		data
+	)
+}
+
+//用户加入会员{{host}}/api/v1/user/
+export function userJoinVip(data) {
+	return request.post(
+		`v1/user/userJoinVip`,
+		data
+	)
+}
+
+//消息获取
+export function messageList(data) {
+	return request.post(
+		`/v1/message/messageList`,
+		data
+	)
+}
+
+//更新用户信息
+export function refreshPersonData(data) {
+	return request.post(
+		`v1/user/updateUser`,
+		data
+	)
+}
+
+//用户信息
+export function userInfo(data) {
+	return request.post(
+		`v1/user/userInfo`,
+		data
+	)
+}
+//新增用户数据
+export function userMemberAdd(data) {
+	return request.post(
+		`users/member_add`,
+		data
+	)
+}
+
+//上传图片
+export function UserUploadFile(data) {
+	return request.post(
+		`v1/user/uploadFile`,
+		data
+	)
+}
+
+//删除信息
+export function delMessage(data) {
+	return request.post(
+		`v1/message/delMessage`,
+		data
+	)
+}
+
+export default {
+	allRegion,
+	myLogin,
+	update,
+	joinVip,
+	userJoinVip,
+	messageList,
+	refreshPersonData,
+	userInfo,
+	userMemberAdd,
+	UserUploadFile,
+	delMessage
+}

+ 46 - 0
api/orders/orders.js

xqd
@@ -0,0 +1,46 @@
+const request = uni.$u.http
+
+// 订单列表
+export function getOrderList(data){
+	return request.post(
+		`v1/order/orderList`,
+		data
+	)
+}
+
+// 我的订单详情
+export function getOrderDetail(data){
+	return request.post(
+		`v1/order/orderDetail`,
+		data
+	)
+}
+
+// 订单兑换
+export function orderExchange(data){
+	return request.post(
+		`v1/order/orderExchange`,
+		data
+	)
+}
+// 核销订单
+export function confirmOrder(data){
+	return request.post(
+		`v1/order/confirmOrder`,
+		data
+	)
+}
+// 核销订单详情
+export function confirmOrderDetail(data){
+	return request.post(
+		`v1/order/confirmOrderDetail`,
+		data
+	)
+}
+export default {
+ getOrderList,
+ getOrderDetail,
+ orderExchange,
+ confirmOrder,
+ confirmOrderDetail
+}

+ 11 - 0
api/pay.js

xqd
@@ -0,0 +1,11 @@
+const request = uni.$u.http
+
+export function query(pay_id) {
+  return request.get(
+    `pay/${pay_id}/query`
+  )
+}
+
+export default {
+  query
+}

+ 22 - 0
api/product/product.js

xqd
@@ -0,0 +1,22 @@
+const request = uni.$u.http
+
+// 获取产品列表
+export function getProducts(data){
+	return request.post(
+		`v1/product/productList`,
+		data
+	)
+}
+
+// 获取产品详情
+export function getProductDetail(data){
+	return request.post(
+		`v1/product/productDetail`,
+		data
+	)
+}
+
+export default {
+  getProducts,
+  getProductDetail
+}

+ 39 - 0
api/setting.js

xqd
@@ -0,0 +1,39 @@
+const request = uni.$u.http
+
+export function tabBar() {
+  return request.get(
+    'setting/tabBar'
+  )
+}
+
+export function navBar() {
+  return request.get(
+    'setting/navBar'
+  )
+}
+
+export function banner() {
+  return request.get(
+    'setting/banner'
+  )
+}
+
+export function rechargeCombo() {
+  return request.get(
+    'setting/rechargeCombo'
+  )
+}
+
+export function homeColumn() {
+  return request.get(
+    'setting/homeColumn'
+  )
+}
+
+export default {
+  tabBar,
+  navBar,
+  banner,
+  rechargeCombo,
+  homeColumn
+}

+ 35 - 0
api/share/index.js

xqd
@@ -0,0 +1,35 @@
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/8/14.
+ */
+const request = uni.$u.http
+
+import order from './order'
+import team from './team'
+import withdraw from './withdraw'
+
+export function income() {
+  return request.get(
+    'share/income'
+  )
+}
+
+export function tips() {
+  return request.get(
+    'share/tips'
+  )
+}
+
+export function setting() {
+  return request.get(
+    'share/setting'
+  )
+}
+
+export default {
+  order,
+  withdraw,
+  team,
+  income,
+  tips,
+  setting
+}

+ 16 - 0
api/share/order.js

xqd
@@ -0,0 +1,16 @@
+
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/11/5.
+ */
+const request = uni.$u.http
+
+export function lists(params) {
+  return request.get(
+    'share/order/lists',
+    { params }
+  )
+}
+
+export default {
+  lists
+}

+ 16 - 0
api/share/team.js

xqd
@@ -0,0 +1,16 @@
+
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/11/5.
+ */
+const request = uni.$u.http
+
+export function lists(params) {
+  return request.get(
+    'share/team/lists',
+    { params }
+  )
+}
+
+export default {
+  lists
+}

+ 24 - 0
api/share/withdraw.js

xqd
@@ -0,0 +1,24 @@
+
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/8/22.
+ */
+const request = uni.$u.http
+
+export function lists(params) {
+  return request.get(
+    `share/withdraw/lists`,
+    { params }
+  )
+}
+
+export function create(data) {
+  return request.post(
+    `share/withdraw/create`,
+    data
+  )
+}
+
+export default {
+  lists,
+  create
+}

+ 26 - 0
api/sign.js

xqd
@@ -0,0 +1,26 @@
+const request = uni.$u.http
+
+export function setting() {
+  return request.get(
+    'user/sign/setting'
+  )
+}
+
+export function handle() {
+  return request.post(
+    `user/sign/handle`
+  )
+}
+
+export function agreement() {
+  return request.get(
+   `agreement`
+  )
+}
+
+
+export default {
+  setting,
+  handle,
+  agreement
+}

+ 37 - 0
api/user/collect.js

xqd
@@ -0,0 +1,37 @@
+
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/8/22.
+ */
+const request = uni.$u.http
+
+export function record(params) {
+  return request.get(
+    `user/collect/record`,
+    { params }
+  )
+}
+
+export function check(id) {
+  return request.post(
+    `user/collect/${id}/check`
+  )
+}
+
+export function add(id) {
+  return request.post(
+    `user/collect/${id}/add`
+  )
+}
+
+export function destroy(id) {
+  return request.post(
+    `user/collect/${id}/destroy`
+  )
+}
+
+export default {
+  record,
+  check,
+  add,
+  destroy
+}

+ 16 - 0
api/user/consume.js

xqd
@@ -0,0 +1,16 @@
+
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/8/22.
+ */
+const request = uni.$u.http
+
+export function record(params) {
+  return request.get(
+    'user/consume/record',
+    { params }
+  )
+}
+
+export default {
+  record
+}

+ 50 - 0
api/user/episode.js

xqd
@@ -0,0 +1,50 @@
+
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/8/22.
+ */
+const request = uni.$u.http
+
+export function record(params) {
+  return request.get(
+    'user/watch/record',
+    { params }
+  )
+}
+export function deleteRecord(id) {
+  return request.post(
+    `user/watch/${id}/destroy`
+  )
+}
+
+export function recent() {
+  return request.get(
+    'user/watch/recent'
+  )
+}
+
+export function watched(id, list_id) {
+  return request.post(
+    'user/watch/episode',
+    { id, list_id }
+  )
+}
+
+export async function buyRecord(episode_id) {
+  return request.get(
+    `user/episode/buy/${episode_id}/record`
+  )
+}
+
+export async function buyHandle(episode_id, list_id) {
+  return request.post(
+    `user/episode/${episode_id}/${list_id}/buy`
+  )
+}
+export default {
+  recent,
+  record,
+  deleteRecord,
+  watched,
+  buyRecord,
+  buyHandle
+}

+ 29 - 0
api/user/favorite.js

xqd
@@ -0,0 +1,29 @@
+
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/8/22.
+ */
+const request = uni.$u.http
+
+export function check(id) {
+  return request.post(
+    `user/favorite/${id}/check`
+  )
+}
+
+export function add(id) {
+  return request.post(
+    `user/favorite/${id}/add`
+  )
+}
+
+export function destroy(id) {
+  return request.post(
+    `user/favorite/${id}/destroy`
+  )
+}
+
+export default {
+  check,
+  add,
+  destroy
+}

+ 83 - 0
api/user/index.js

xqd
@@ -0,0 +1,83 @@
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/8/14.
+ */
+import { getToken } from '../../utils/auth'
+
+const request = uni.$u.http
+
+import episode from './episode'
+import consume from './consume'
+import recharge from './recharge'
+import collect from './collect'
+import favorite from './favorite'
+import vip from './vip'
+
+export async function login() {
+  console.log('-->data', 1)
+  return new Promise(resolve => {
+    uni.showLoading({
+      title: '数据加载中...',
+      mask: true
+    })
+    uni.login({
+      provider: uni.$u.platform,
+      success: loginRes => {
+        console.log('-->data', loginRes)
+        uni.hideLoading()
+        // #ifdef  MP-KUAISHOU
+        const url = '/auth/kuaishou'
+        // #endif
+        // #ifdef  MP-TOUTIAO
+        const url = '/auth/bytedance'
+        // #endif
+        // #ifdef  MP-WEIXIN
+        const url = '/auth/wechat'
+        // #endif
+
+        return request.post(
+          url,
+          { code: loginRes.code, anonymousCode: loginRes.anonymousCode }
+        ).then(res => {
+          resolve(res)
+        })
+      }
+    })
+  })
+}
+
+export function update(data) {
+  return request.post(
+    'user/update',
+    data
+  )
+}
+
+export async function info() {
+  return request.get(
+    'user/info'
+  )
+}
+
+export async function bind(id) {
+  return request.post(
+    `user/${id}/bind`
+  )
+}
+
+export function isLogin() {
+  return !!getToken()
+}
+
+export default {
+  login,
+  update,
+  bind,
+  info,
+  isLogin,
+  episode,
+  consume,
+  recharge,
+  collect,
+  favorite,
+  vip
+}

+ 24 - 0
api/user/recharge.js

xqd
@@ -0,0 +1,24 @@
+
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/8/22.
+ */
+const request = uni.$u.http
+
+export function record(params) {
+  return request.get(
+    'user/recharge/record',
+    { params }
+  )
+}
+
+export function create(data) {
+  return request.post(
+    'user/recharge/create/order',
+    data
+  )
+}
+
+export default {
+  record,
+  create
+}

+ 23 - 0
api/user/vip.js

xqd
@@ -0,0 +1,23 @@
+
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/8/22.
+ */
+const request = uni.$u.http
+
+export function setting() {
+  return request.get(
+    'user/vip/setting'
+  )
+}
+
+export function create(data) {
+  return request.post(
+    'user/vip/create/order',
+    data
+  )
+}
+
+export default {
+  setting,
+  create
+}

+ 30 - 0
components/CheckLogin/index.vue

xqd
@@ -0,0 +1,30 @@
+<template>
+  <view class="check-login">
+    <u-loading-page
+      :loading="!isLogin"
+      :bg-color="$colors.bgColor"
+      :color="$colors.primaryColor"
+      :loading-color="$colors.primaryColor"
+    />
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'CheckLogin',
+  data() {
+    return {}
+  },
+  computed: {
+    isLogin() {
+      return this.$api.user.isLogin()
+    }
+  },
+  methods: {}
+}
+</script>
+
+<style lang="scss" scoped>
+    .check-login {
+    }
+</style>

+ 147 - 0
components/Episode/index.vue

xqd
@@ -0,0 +1,147 @@
+<template>
+  <view class="episode" :style="[customStyle]" @click="handlePlay">
+    <view class="cover-image" :style="[imageStyle]">
+      <view v-if="rank" class="rank" :class="{first: rank === 1}">
+        <text>{{ rank }}</text>
+      </view>
+      <image :src="episode.cover_img" :style="[imageStyle]" />
+      <view v-if="recent" class="special">最近播放 </view>
+      <view v-if="guess" class="special guess">猜你喜欢 </view>
+    </view>
+    <u-text
+      :text="episode.name"
+      :lines="1"
+      size="32rpx"
+      margin="20rpx 0 10rpx"
+      :color="$colors.defaultColor"
+    />
+    <view class="status-box dir-left-nowrap">
+      <u-text
+        :text="episode.status_text"
+        :lines="1"
+        size="24rpx"
+        :custom-style="{flex: 'unset'}"
+        :color="$colors.primaryColor"
+      />
+      <u-text
+        :text="`共${episode.total}集`"
+        :lines="1"
+        size="24rpx"
+        margin="0 0 0 10rpx"
+        :color="$colors.infoColor"
+      />
+    </view>
+  </view></template>
+
+<script>
+import UText from '../../uni_modules/uview-ui/components/u--text/u--text'
+export default {
+  name: 'Episode',
+  components: { UText },
+  props: {
+    episode: {
+      type: Object,
+      required: true
+    },
+    customStyle: {
+      type: Object,
+      default() {
+        return {}
+      }
+    },
+    imageStyle: {
+      type: Object,
+      default() {
+        return {}
+      }
+    },
+    recent: {
+      type: Boolean,
+      default: false
+    },
+    guess: {
+      type: Boolean,
+      default: false
+    },
+    rank: {
+      type: Number,
+      default: 0
+    },
+    redirect: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {}
+  },
+  computed: {},
+  methods: {
+    handlePlay() {
+      if (!this.redirect) return
+      this.$u.route({
+        url: '/pages/episode/play',
+        params: {
+          id: this.episode.id
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+    .episode {
+      width: calc((#{750rpx} - #{80rpx}) / 3);
+      margin-bottom: 30rpx;
+      overflow: hidden;
+      .cover-image{
+        position: relative;
+        height: 330rpx;
+        image{
+          width: 100%;
+          height: inherit;
+          border-radius: 20rpx;
+        }
+        .special{
+          background: rgba(48, 98, 97, 0.65);
+          text-align: center;
+          color: #fff;
+          padding: 10rpx 0;
+          position: absolute;
+          bottom: 0;
+          width: 100%;
+          font-size: 26rpx;
+          border-bottom-left-radius: 20rpx;
+          border-bottom-right-radius: 20rpx;
+          &.guess{
+            background: rgba(124, 78, 112, 0.65);
+          }
+        }
+        .rank{
+          position: absolute;
+          top: -35rpx;
+          left: -35rpx;
+          width: 70rpx;
+          height: 70rpx;
+          transform: rotate(45deg);
+          background: rgba(251, 54, 81, 0.6);
+          color: #fff;
+          font-size: 26rpx;
+          z-index: 99;
+          &.first{
+            background: #FE3552;
+          }
+          text{
+            position: absolute;
+            right: 5px;
+            top: 10px;
+            transform: rotate(-45deg);
+          }
+        }
+      }
+      .status-box{
+
+      }
+    }
+</style>

+ 104 - 0
components/NavBar/index.vue

xqd
@@ -0,0 +1,104 @@
+<template>
+  <view class="nav-bar main-center cross-center">
+    <view
+      v-for="(item,index) in navItem"
+      :key="index"
+      class="item dir-top-wrap cross-center"
+      @click="handleRedirect(item)"
+    >
+      <view
+        class="icon"
+        :class="item.class"
+        :style="{
+          backgroundImage: `url(${item.icon})`
+        }"
+      />
+      <text>{{ item.name }}</text>
+    </view>
+    <!--充值-->
+    <recharge :show.sync="recharge.show" />
+  </view>
+</template>
+
+<script>
+
+import Recharge from '../Recharge/index'
+export default {
+  name: 'NavBar',
+  components: { Recharge },
+  data() {
+    return {
+      types: {
+        1: { href: '/pages/index/rank', class: 'rank' },
+        2: { href: '/pages/index/news', class: 'news' },
+        3: { href: '/pages/member/index', class: 'member' },
+        4: { href: '/pages/sign/index', class: 'sign' },
+        5: { type: 'recharge', class: 'recharge' }
+      },
+      navItem: [
+        { icon: '', name: '排行榜', href: '/pages/index/rank', class: 'rank' },
+        { icon: '', name: '最新', href: '/pages/index/news', class: 'news' },
+        { icon: '', name: '会员', href: '/pages/member/index', class: 'member' },
+        { icon: '', name: '签到', href: '/pages/sign/index', class: 'sign' },
+        { icon: '', name: '充值', type: 'recharge', class: 'recharge' }
+      ],
+      recharge: { show: false }
+    }
+  },
+  computed: {},
+  created() {
+    this.getData()
+  },
+  methods: {
+    handleRedirect(item) {
+      if (item.type === 'recharge') {
+        this.recharge.show = true
+      } else if (item.href) {
+        this.$u.route(item.href)
+      }
+    },
+    getData() {
+      /**
+       * type 1 -排行榜 2 -最新  3 -会员 4 -签到 5 -充值
+       */
+      this.$api.setting.navBar().then(res => {
+        const data = res.data
+        data.forEach(obj => {
+          Object.assign(obj, this.types[obj.type])
+        })
+        this.navItem = data
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .nav-bar {
+    .item{
+      flex: 1;
+      font-size: 32rpx;
+      .icon{
+        width: 90rpx;
+        height: 90rpx;
+        background-repeat: no-repeat;
+        background-size: 100%;
+        background-position: center;
+        &.rank{}
+        &.news{
+          width: 80rpx;
+        }
+        &.member{
+          width: 82rpx;
+        }
+        &.sign{}
+        &.recharge{
+          width: 70rpx;
+        }
+      }
+      text{
+        color: #fff;
+      }
+    }
+  }
+</style>

+ 353 - 0
components/Recharge/index.vue

xqd
@@ -0,0 +1,353 @@
+<template>
+  <view class="recharge">
+    <u-popup
+      :show="show"
+      :mode="mode"
+      round="20rpx"
+      :close-on-click-overlay="false"
+      @close="close"
+    >
+      <view class="container" :class="{bottom: mode === 'bottom'}">
+        <template v-if="type === 'play'">
+          <view class="play-container">
+            <view class="header main-between cross-center">
+              <text>感谢您的支持,本集解锁后可继续观看</text>
+              <u-icon name="arrow-down" size="28rpx" @click="close" />
+            </view>
+            <view class="episode main-between cross-center">
+              <view class="detail">
+                <view class="name">{{ episode.name }} 第{{ list.sort }}集</view>
+                <view class="sale-box main-left cross-center">
+                  <view class="sale-price cross-center">专享价{{ list.sale_price }}金币</view>
+                  <view v-if="list.origin_price" class="origin-price cross-center">原价{{ list.origin_price }}金币</view>
+                </view>
+              </view>
+              <view class="buy-num">{{ buyNum }}人购买</view>
+            </view>
+          </view>
+          <view class="static-text main-between cross-center">
+            <text>充值金币</text>
+            <view class="overage">账户余额:<text>{{ userInfo.info.integral }}金币</text></view>
+          </view>
+        </template>
+        <template v-else>
+          <view class="static-text main-between cross-center">
+            <text>充值金币</text>
+            <u-icon name="close-circle" size="52rpx" color="#BEBDBB" @click="close" />
+          </view>
+          <view class="overage">账户余额:<text>{{ userInfo.info.integral }}金币</text></view>
+        </template>
+
+        <scroll-view
+          class="recharge-group-view dir-left-wrap"
+          scroll-y
+          scroll-with-animation
+          :enable-flex="true"
+        >
+          <view class="recharge-group dir-left-wrap">
+            <view
+              v-for="(combo,index) in combos"
+              :key="index"
+              class="recharge-item dir-top-wrap main-center cross-center"
+              :class="{active: rechargeActive === index}"
+              @click="rechargeActive = index"
+            >
+              <text class="price">{{ combo.price }}元</text>
+              <text class="gold">{{ combo.gold }}+{{ combo.gift }}金币</text>
+              <text class="gift">多送{{ combo.gift }}金币</text>
+            </view>
+          </view>
+        </scroll-view>
+
+        <view class="btn" @click="handleRecharge">充值</view>
+      </view>
+    </u-popup>
+  </view>
+</template>
+
+<script>
+import { mapState } from 'vuex'
+export default {
+  name: 'Recharge',
+  props: {
+    show: {
+      type: Boolean,
+      default: false
+    },
+    mode: {
+      type: String,
+      default: 'center'
+    },
+    type: {
+      type: String,
+      default: 'normal'
+    },
+    episode: {
+      type: Object,
+      default() {
+        return {}
+      }
+    },
+    list: {
+      type: Object,
+      default() {
+        return {}
+      }
+    }
+  },
+  data() {
+    return {
+      modal: {
+        show: false
+      },
+      combos: [],
+      rechargeActive: 0,
+      buyNum: 0,
+      payId: 0
+    }
+  },
+  computed: {
+    ...mapState({
+      userInfo: seate => seate.user.info
+    })
+  },
+  watch: {
+    show(val) {
+      this.modal.show = val
+      if (val) {
+        this.getCombo()
+        this.getBuyNum()
+      }
+    }
+  },
+  created() {
+    // this.getCombo()
+    // this.getBuyNum()
+  },
+  methods: {
+    getCombo() {
+      this.$api.setting.rechargeCombo().then(res => {
+        this.combos = res.data
+      })
+    },
+    close() {
+      this.$emit('update:show', false)
+    },
+    getBuyNum() {
+      if (this.type === 'play') {
+        this.$api.episode.listBuyNum(this.list.id).then(res => {
+          this.buyNum = res.data
+        })
+      }
+    },
+    handleRecharge() {
+      // IOS 不允许购买
+      // #ifdef MP-TOUTIAO | MP-WEIXIN
+      if (!this.$util.checkOS()) return
+      // #endif
+      const item = this.combos[this.rechargeActive]
+      this.$loading('请稍后...')
+      this.$api.user.recharge.create({ id: item.id }).then(res => {
+        this.payId = res.pay_id
+        delete res.pay_id
+        console.log('-->data', res)
+        // #ifdef MP-TOUTIAO
+        tt.pay({
+          service: 5,
+          orderInfo: {
+            order_id: res.data.order_id,
+            order_token: res.data.order_token
+          },
+          success: payRes => {
+            if (payRes.code === 0) {
+              this.$loading('支付结果查询中...')
+              this.query()
+            } else {
+              this.$u.toast('支付失败')
+            }
+          },
+          fail: err => {
+            console.log('-->data', err)
+            clearInterval(this.interval)
+            // 调起收银台失败处理逻辑
+          }
+        })
+        // #endif
+        // #ifdef MP-KUAISHOU
+        ks.pay({
+          serviceId: '1',
+          orderInfo: {
+            order_no: res.data.order_id,
+            order_info_token: res.data.order_token
+          },
+          success: payRes => {
+            this.$loading('支付结果查询中...')
+            this.query()
+          },
+          fail: err => {
+            console.log('-->data', err)
+            clearInterval(this.interval)
+            // 调起收银台失败处理逻辑
+          }
+        })
+        // #endif
+        // #ifdef MP-WEIXIN
+        uni.requestPayment({
+          ...res.data,
+          provider: 'wxpay',
+          success: res => {
+            console.log('success:' + JSON.stringify(res))
+            // _this.$u.toast("支付成功")
+            this.$loading('支付结果查询中...')
+            this.query()
+          },
+          fail: err => {
+            console.log('fail:' + JSON.stringify(err))
+            // _this.$u.toast("支付失败")
+            clearInterval(this.interval)
+          }
+        })
+        // #endif
+        this.$hideLoading()
+      }).catch(() => {
+        this.$hideLoading()
+      })
+    },
+    query() {
+      if (this.interval) return
+      this.interval = setInterval(() => {
+        this.$api.pay.query(this.payId).then(res => {
+          this.$hideLoading()
+          this.$u.toast('支付成功')
+          clearInterval(this.interval)
+          // 获取用户信息
+          this.$api.user.info().then(res => {
+            this.$store.dispatch('user/info', res.data)
+          })
+        }).catch(err => {
+          this.$hideLoading()
+        })
+      }, 1000)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+    .recharge {
+      font-size: 28rpx;
+      .container{
+        width: 700rpx;
+        border: 2rpx solid;
+        padding: 30rpx;
+        &.bottom{
+          width: 750rpx;
+          border: unset;
+          .recharge-group{
+            .recharge-item{
+              width: calc(#{670rpx} / 2) !important;
+            }
+          }
+        }
+        .static-text{
+          font-size: 36rpx;
+          font-weight: 600;
+          margin-bottom: 40rpx;
+          .overage{
+            font-size: 28rpx;
+            color: $info-color;
+          }
+        }
+        .overage{
+          color: $info-color;
+          text{
+            color: #FB3651 ;
+          }
+        }
+        // 播放充值
+        .play-container{
+          .episode{
+            margin: 40rpx 0 ;
+            background: linear-gradient(270deg, #6EEBE8, #FF74B9);
+            border-radius: 20rpx;
+            height: 180rpx;
+            padding: 20rpx;
+            .detail{
+              .name{
+                color: $default-color;
+                font-weight: 600;
+              }
+              .sale-box{
+                margin-top: 40rpx;
+                .sale-price{
+                  color: $primary-color;
+                  font-size: 28rpx;
+                }
+                .origin-price{
+                  color: $default-color;
+                  font-size: 24rpx;
+                  margin-left: 20rpx;
+                  text-decoration: line-through;
+                  opacity: .6;
+                  margin-top: 6rpx;
+                }
+              }
+            }
+            .buy-num{
+              color: $default-color;
+              min-width: 80px;
+              text-align: center;
+            }
+          }
+        }
+        // 充值套餐
+        .recharge-group-view{
+          .recharge-group{
+            margin-top: 30rpx;
+            height: 50vh;
+            display: flex;
+            .recharge-item{
+              border: 4rpx solid $primary-color;
+              width: calc(#{600rpx} / 2);
+              margin-right: 20rpx;
+              margin-bottom: 20rpx;
+              border-radius: 20rpx;
+              padding: 40rpx 20rpx;
+              transition: .3s;
+              &:nth-child(2n){
+                margin-right: 0;
+              }
+              &.active{
+                background: #1b1e32;
+                border: 4rpx solid #1b1e32;
+                .price{
+                  color: $default-color;
+                }
+              }
+              .price{
+                margin-bottom: 40rpx;
+                font-size: 38rpx;
+              }
+              .gold{
+                color: $primary-color;
+                margin-bottom: 10rpx;
+              }
+              .gift{
+                color: $info-color;
+              }
+            }
+          }
+        }
+        .btn{
+          background: linear-gradient(270deg, #6EEBE8 0%, #FF74B9 100%);
+          width: 90%;
+          margin: 40rpx auto;
+          padding: 20rpx 0;
+          text-align: center;
+          border-radius: 40rpx;
+          color: $default-color;
+          letter-spacing: .1rem;
+        }
+      }
+    }
+</style>

+ 119 - 0
components/SwiperBox/index.vue

xqd
@@ -0,0 +1,119 @@
+<template>
+  <view
+    class="swiper-box "
+    :class="{
+      loading:loading,
+      'main-center':loading,
+      'cross-center': loading
+    }"
+    :style="{height: height}"
+  >
+    <u-loading-icon :show="loading" vertical />
+    <u-swiper
+      v-if="list.length"
+      :list="list"
+      :height="height"
+      :radius="radius"
+      style="width: 100%;"
+      :bg-color="$colors.bgColor"
+      :indicator="true"
+      :show-title="true"
+      indicator-mode="dot"
+      :indicator-style="{bottom: '24rpx'}"
+      img-mode=""
+      @click="handleClick"
+      @change="handleChange"
+    >
+      <view
+        slot="indicator"
+        class="indicator"
+      >
+        <view
+          v-for="(item, index) in list"
+          :key="index"
+          class="indicator__dot"
+          :class="[index === currentNum && 'indicator__dot--active']"
+        />
+      </view>
+    </u-swiper>
+  </view>
+</template>
+
+<script>
+
+export default {
+  name: 'SwiperBox',
+  props: {
+    height: {
+      type: [Number, String],
+      default: '386rpx'
+    },
+    radius: {
+      type: [Number, String],
+      default: '0rpx'
+    }
+  },
+  data() {
+    return {
+      loading: true,
+      // list: [require('../../static/icon/swiper01.png'),require('../../static/icon/swiper01.png')],
+      currentNum: 0
+    }
+  },
+  computed: {
+  },
+  created() {
+    // this.getSwiper()
+  },
+  methods: {
+    handleClick(index) {
+      const item = this.list[index]
+      console.log('-->data', item)
+    },
+    handleChange(e) {
+      this.currentNum = e.current
+    },
+    getSwiper() {
+      this.$api.setting.banner().then(res => {
+        this.loading = false
+        res.data.forEach(obj => {
+          this.list.push(obj.image)
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+	::v-deep .u-swiper{
+		width:100% !important;
+	}
+	
+	
+  .swiper-box{
+    // margin: 20rpx 0;
+    // border-radius: 8rpx;
+    &.loading{
+      background-color: #1B203C;
+    }
+    .indicator {
+      display: flex;
+      flex-direction: row;
+      justify-content: center;
+
+      &__dot {
+        height: 20rpx;
+        width: 20rpx;
+        border-radius: 50%;
+        background-color: rgba(255, 255, 255, 0.35);
+        margin: 0 10px;
+        transition: background-color 0.3s;
+
+        &--active {
+          background-color: #6EEBE8;
+        }
+      }
+    }
+  }
+</style>

+ 185 - 0
components/TabBar/tabbar.vue

xqd
@@ -0,0 +1,185 @@
+<template>
+	<view class="tab-bar" :style="{'--padding-bottom':`${wagesheight}`+'rpx'}">
+		<view class="content main-between cross-center">
+			<view v-for="(item,index) in list" :key="index" class="tab-item dir-top-wrap cross-center main-center"
+				:class="{active: active === index}" @click="handleSwitch(index)">
+				<view class="icon">
+					<image
+						:src="active === index ? (item.selected_icon ? item.selected_icon : item.selectedIconPath) : (item.icon ? item.icon : item.iconPath)"
+						mode="aspectFit" />
+				</view>
+				<text>{{ item.text }}</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import {
+		mapState
+	} from 'vuex'
+
+	export default {
+		name: 'TabBar',
+		data() {
+			return {
+				wagesheight: '',
+				color: '#CBC8C7',
+				selectedColor: '#FF6200',
+				// types: {
+				// 	1: {
+				// 		'pagePath': '/pages/index/index',
+				// 		'iconPath': '/static/icon/home2.png',
+				// 		'selectedIconPath': '/static/icon/home1.png'
+				// 	},
+				// 	2: {
+				// 		'pagePath': '/pages/map/map',
+				// 		'iconPath': '/static/icon/map02.png',
+				// 		'selectedIconPath': '/static/icon/map01.png'
+				// 	},
+				// 	3: {
+				// 		'pagePath': '/pages/msg/msg',
+				// 		'iconPath': '/static/icon/msg02.png',
+				// 		'selectedIconPath': '/static/icon/msg01.png'
+				// 	},
+				// 	4: {
+				// 		'pagePath': '/pages/my/my',
+				// 		'iconPath': '/static/icon/my02.png',
+				// 		'selectedIconPath': '/static/icon/my01.png'
+				// 	}
+				// },
+				list: [{
+						'pagePath': '/pages/index/index',
+						'iconPath': '/static/icon/home02.png',
+						'selectedIconPath': '/static/icon/home01.png',
+						'text': '首页'
+					},
+					{
+						'pagePath': '/pages/map/map',
+						'iconPath': '/static/icon/map02.png',
+						'selectedIconPath': '/static/icon/map01.png',
+						'text': 'IHG地图'
+					},
+					{
+						'pagePath': '/pages/msg/msg',
+						'iconPath': '/static/icon/msg02.png',
+						'selectedIconPath': '/static/icon/msg01.png',
+						'text': '消息'
+					},
+					{
+						'pagePath': '/pages/my/my',
+						'iconPath': '/static/icon/my02.png',
+						'selectedIconPath': '/static/icon/my01.png',
+						'text': '我的'
+					}
+				]
+			}
+		},
+		computed: {
+			...mapState({
+				active: seate => seate.tab.index
+			})
+		},
+		created() {
+			this.calc()
+			uni.hideTabBar()
+			// this.getData()
+		},
+		mounted() {
+			let _this = this
+			uni.getSystemInfo({
+				success: function(res) {
+					let bottom = res.safeArea.bottom
+					let height = res.safeArea.height
+					let cacl = bottom - height
+					_this.wagesheight = cacl
+				}
+			})
+		},
+		methods: {
+			handleSwitch(index) {
+				if (index === this.active) {
+					return
+				}
+				this.$store.dispatch('tab/index', index)
+				const item = this.list[index]
+				uni.switchTab({
+					url: item.pagePath
+				})
+			},
+			calc() {
+				let active = 1
+				const page = uni.$u.page().replace('//', '/')
+				this.list.forEach((obj, index) => {
+					if (obj.pagePath === page) {
+						active = index
+					}
+				})
+				if (active !== this.active) {
+					this.$store.dispatch('tab/index', active)
+				}
+			},
+			// getData() {
+			// 	this.$api.setting.tabBar().then(res => {
+			// 		const data = res.data
+			// 		data.forEach(obj => {
+			// 			Object.assign(obj, this.types[obj.type])
+			// 		})
+			// 		console.log('-->data', data)
+			// 		this.list = data
+			// 	})
+			// }
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.tab-bar {
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		background-color: #fff;
+		width: 100%;
+		z-index: 999 !important;
+
+		.content {
+			background-color: #fff;
+			box-shadow: 0px -2rpx 20rpx 0px rgba(0, 0, 0, 0.05);
+			position: absolute;
+			bottom: 0;
+			width: 100%;
+			height: 120rpx;
+			background-size: 110% 100%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			// padding-bottom: var(--padding-bottom);
+
+			.tab-item {
+				flex: 1;
+				color: #CBC8C7;
+				transition: .3s;
+				font-size: 24rpx;
+				position: relative;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				justify-content: center;
+
+				&.active {
+					color: #FF6200;
+				}
+
+				.icon {
+					width: 42rpx;
+					height: 42rpx;
+
+					image {
+						height: 100%;
+						width: 100%;
+					}
+				}
+			}
+		}
+	}
+</style>

+ 55 - 0
components/bottombtn/bottombtn.vue

xqd
@@ -0,0 +1,55 @@
+<template>
+	<view class="bottombtn" @click="goExDetail">
+		<view class="btnitem" >
+			<text>{{btnName}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default{
+		name:'bottombtn',
+		props:['text'],
+		data(){
+			return{
+				btnName:''
+			}
+		},
+		created() {
+			this.btnName=this.text
+		},
+		methods:{
+			goExDetail(){
+				this.$emit('goExDetail')
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+	
+	.bottombtn{
+		width: 690rpx;
+		height: 92rpx;
+		background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);	
+		border-radius: 12rpx;
+		margin-left: 30rpx;
+		position: fixed;
+		bottom: 72rpx;
+		@include flexlayout();
+		.btnitem{
+			@include flexlayout();
+			text{
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #FFFFFF;
+			}
+		}
+	}
+</style>

+ 281 - 0
components/hch-position/hch-position.vue

xqd
@@ -0,0 +1,281 @@
+<template>
+	<view>
+		<view class="page-body">
+			<view class="page-section page-section-gap">
+				<map  scale="10"  ubkey='CQIBZ-P2MR5-PM3IB-QRKTX-SEVJE-GYF34' :showScale="false" :showLocation="true"  :showCompass="false" enableZoom="true" enableScroll="true" enableBuilding="true" enable3D="true" id="myMap" style="width: 100%; height: 600px;"
+					:latitude="latitude" 
+					:longitude="longitude"
+					:markers="markersIn" 
+					:layerStyle="mapStyle"  
+					@markertap='markertap'
+					@anchorpointtap='anchorpointtap'
+				>
+				</map>
+			</view>
+			
+			<lPainter
+				style="position: fixed;left:0px;top: -500px;"
+				isRenderImage
+				:board="painter.base"
+				@success="(e)=>{painter.path = e; painter.wait=0}"
+			/>
+		</view>
+	</view>
+</template>
+
+<script>
+	import lPainter from '@/components/lime-painter/index.vue'
+	
+	export default {
+		components:{
+			lPainter
+		},
+		props: {
+			
+			markers: {
+				type: Array,
+				default: [{
+						id: 1,
+						latitude: 30.6034799,
+						longitude: 104.1132550,
+						// iconPath: "../../static/hch-position/门店.png",
+						width: '38rpx',
+						height: '40rpx',
+						joinCluster: true, // 指定了该参数才会参与聚合
+						callout: {
+							content: "门店1号店",
+							borderRadius: 10,
+							padding: 5,
+							display: "ALWAYS",
+							transform: "tranlateY(20px)"
+						}
+					},
+				]
+			}
+		},
+		data() {
+			return {
+				latitude: 30.6034799,
+				longitude: 104.1132550,
+				mapStyle: 1, //个性化地图
+				markersIn: [],
+				isUpdate: false,
+				painter:{
+					wait: 0,
+					base:{
+						width: '94rpx',
+						height: '110rpx',
+						radius: "100rpx",
+						views:[
+							{
+								type: 'image',
+								src: '../../static/icon/late02.png',
+								css: {
+									left: '0rpx',
+									top: '0rpx',
+									width: '90rpx',
+									height: '100rpx',
+								}
+							},
+							{
+								type: 'image',
+								src: '',
+								css: {
+									left: '10rpx',
+									top: '8rpx',
+									width: '70rpx',
+									height: '70rpx',
+									borderRadius: '30rpx'
+								}
+							}
+						]
+					},
+					path:""
+				},
+			}
+		},
+
+		onReady() {
+			this._mapContext = uni.createMapContext("map", this);
+
+			// 仅调用初始化,才会触发 on.("markerClusterCreate", (e) => {})
+			this._mapContext.initMarkerCluster({
+				enableDefaultStyle: false,
+				zoomOnClick: true,
+				gridSize: 60,
+				complete(res) {
+					console.log('initMarkerCluster', res)
+				}
+			});
+			this._mapContext.on("markerClusterCreate", (e) => {
+				console.log("markerClusterCreate", e);
+			});
+			// this.addMarkers();
+		},
+		methods: {
+			goLocation(la,lo){
+				this.latitude = la
+				this.longitude = lo
+			},
+			//生成图片
+			generateImg(imgUrl){
+				if(this.painter.wait != 0) return new Promise();
+				this.painter.show = false;
+				this.painter.base.views[1].src = imgUrl;
+				this.painter.show = true;
+				this.painter.wait = 1;
+				
+				return new Promise(resolve=>{
+					let timer = setInterval(()=>{
+						if(this.painter.wait === 0){
+							clearInterval(timer);
+							resolve(this.painter.path);
+						}else if(this.painter.wait <= 3000){
+							this.painter.wait += 10
+						}else{
+							clearInterval(timer);
+							this.painter.wait = 0;
+							resolve(this.painter.path);
+						}
+					}, 10);
+				})
+			},
+			//	点击标记点时触发,e.detail = {markerId}
+			markertap(e) {
+				this.markersIn.forEach((item,index) => {			
+					if(e.markerId === item.id){		
+						this.generateImg(item.active.iconPath).then(()=>{
+							item.width = item.active.width;
+							item.height = item.active.height;
+							item.iconPath = this.painter.path;
+							item.isActive = true;
+							console.log(item.latitude,item.longitude)
+							this.latitude = item.latitude
+							this.longitude = item.longitude
+							this.$set(this.markersIn, index, item);
+							this.addMarkers()
+						})
+						return;
+					}else if(item.isActive){
+						item.width = item.noActive.width;
+						item.height = item.noActive.height;
+						item.iconPath = item.noActive.iconPath;
+						item.isActive = false;
+						this.$set(this.markersIn, index, item);
+						this.addMarkers()
+					}
+				})				
+				
+				this.isUpdate = false
+				this.$emit('moveToMarkId',e.markerId)
+			},
+			//点击定位标时触发,e.detail = {longitude, latitude}
+			anchorpointtap(e) {
+				console.log('---->定位点', e.detail);
+			},
+			addMarkers() {
+				this._mapContext.addMarkers({
+					markers: this.markersIn,
+					clear: false,
+					complete(res) {
+						console.log('addMarkers', res)
+					}
+				})
+			},
+		},
+
+		onShow() {
+			this.markersIn = this.markers;
+		},
+		watch:{
+			'markers': {
+				handler(val,oldVal) {
+					this.markersIn = this.markers;
+				},
+				// immediate: true
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.content {
+		text-align: center;
+		height: 400rpx;
+	}
+
+	.page-section {
+		z-index: 0;
+	}
+
+	.store-tips {
+		width: 600rpx;
+		height: 100rpx;
+		margin: 10rpx auto;
+		border-radius: 10rpx;
+		position: absolute;
+		top: 10rpx;
+		left: 50%;
+		transform: translate(-50%, 0);
+		z-index: 2;
+		overflow: hidden;
+
+		.store-des-box {
+			background: #fff;
+		}
+
+		.store-img {
+			width: 80rpx;
+			height: 80rpx;
+			border-radius: 10rpx;
+			margin: 10rpx;
+			float: left;
+		}
+
+		.store-des {
+			padding-top: 8rpx;
+			float: left;
+			line-height: 1;
+			font-size: 22rpx;
+			color: #666;
+			padding-left: 20rpx;
+
+			.store-name {
+				font-weight: 600;
+				color: deeppink;
+			}
+		}
+
+		.store-clear {
+			width: 30rpx;
+			height: 30rpx;
+			position: absolute;
+			top: 7rpx;
+			right: 7rpx;
+			margin: 30rpx;
+		}
+	}
+
+	.address-icon {
+		width: 38rpx;
+		height: 40rpx;
+		position: absolute;
+		top: 22%;
+		left: 50%;
+		z-index: 2;
+		margin-bottom: -20rpx;
+		margin-left: -20rpx;
+	}
+
+	.near-num {
+		padding: 10rpx 20rpx;
+		border-radius: 10rpx;
+		position: absolute;
+		top: 17%;
+		left: 50%;
+		z-index: 2;
+		font-size: 24rpx;
+		background: #fff;
+		transform: translate(-50%, 0);
+	}
+</style>

+ 78 - 0
components/lime-painter/canvas.js

xqd
@@ -0,0 +1,78 @@
+import { CHAR_WIDTH_SCALE_MAP } from './utils'
+const _expand = ctx => {
+	// #ifndef APP-PLUS
+	ctx._measureText = ctx.measureText
+	// #endif
+	return {
+		setFonts({fontFamily: ff = 'sans-serif', fontSize: fs = 14, fontWeight: fw = 'normal' , textStyle: ts = 'normal'}) {
+			// let ctx = this.ctx
+			// 设置属性
+			// #ifndef MP-TOUTIAO
+			// fw = fw == 'bold' ? 'bold' : 'normal'
+			// ts = ts == 'italic' ? 'italic' : 'normal'
+			// #endif
+			// #ifdef MP-TOUTIAO
+			fw = fw == 'bold' ? 'bold' : ''
+			ts =  ts == 'italic' ? 'italic' : ''
+			// #endif
+			ctx.font = `${ts} ${fw} ${fs}px ${ff}`;
+		},
+		// #ifndef APP-PLUS
+		measureText(text, fontSize) {
+			// app measureText为0需要累加计算0
+			return {
+				width: text.split("").reduce((widthScaleSum, char) => {
+				let code = char.charCodeAt(0);
+				let widthScale = CHAR_WIDTH_SCALE_MAP[code - 0x20] || 1;
+				return widthScaleSum + widthScale;
+			  }, 0) * fontSize
+			};
+		},
+		// #endif
+	}
+};
+export function expand(ctx) {
+	return Object.assign(ctx, _expand(ctx))
+}
+export function adaptor(ctx) {
+	return Object.assign(ctx, _expand(ctx), {
+		setStrokeStyle(val) {
+			ctx.strokeStyle = val;
+		},
+		setLineWidth(val) {
+			ctx.lineWidth = val;
+		},
+		setLineCap(val) {
+			ctx.lineCap = val;
+		},
+		setFillStyle(val) {
+			ctx.fillStyle = val;
+		},
+		setFontSize(val) {
+			ctx.font = String(val);
+		},
+		setGlobalAlpha(val) {
+			ctx.globalAlpha = val;
+		},
+		setLineJoin(val) {
+			ctx.lineJoin = val;
+		},
+		setTextAlign(val) {
+			ctx.textAlign = val;
+		},
+		setMiterLimit(val) {
+			ctx.miterLimit = val;
+		},
+		setShadow(offsetX, offsetY, blur, color) {
+			ctx.shadowOffsetX = offsetX;
+			ctx.shadowOffsetY = offsetY;
+			ctx.shadowBlur = blur;
+			ctx.shadowColor = color;
+		},
+		setTextBaseline(val) {
+			ctx.textBaseline = val;
+		},
+		createCircularGradient() {},
+		draw() {},
+	});
+}

+ 686 - 0
components/lime-painter/draw.js

xqd
@@ -0,0 +1,686 @@
+import { toPx, isNumber, getImageInfo  } from './utils'
+import { GD } from './gradient'
+import QR from './qrcode'
+
+export class Draw {
+	constructor(context, canvas, use2dCanvas = false, isH5PathToBase64 = false, sleep) {
+		this.ctx = context
+		this.canvas = canvas || null
+		this.use2dCanvas = use2dCanvas
+		this.isH5PathToBase64 = isH5PathToBase64
+		this.sleep = sleep
+	}
+	roundRect(x, y, w, h, r, fill = false, stroke = false, ) {
+		if (r < 0) return
+		const {ctx} = this
+		ctx.beginPath()
+		if(!r) {
+			ctx.rect(x, y, w, h)
+		} else if(typeof r === 'number' && [0,1,-1].includes(w - r * 2) &&  [0, 1, -1].includes(h - r * 2)) {
+			ctx.arc(x + w - r, y + h - r, r, 0, Math.PI * 2)
+		} else {
+			let {
+				borderTopLeftRadius: tl = r || 0,
+				borderTopRightRadius: tr = r || 0,
+				borderBottomRightRadius: br = r || 0,
+				borderBottomLeftRadius: bl = r || 0
+			} = r || {r,r,r,r}
+			// 右下角
+			ctx.arc(x + w - br, y + h - br, br, 0, Math.PI * 0.5)
+			ctx.lineTo(x + bl, y + h)
+			// 左下角
+			ctx.arc(x + bl, y + h - bl, bl, Math.PI * 0.5, Math.PI)
+			ctx.lineTo(x, y + tl)
+			// 左上角
+			ctx.arc(x + tl, y + tl, tl, Math.PI, Math.PI * 1.5)
+			ctx.lineTo(x + w - tr, y)
+			// 右上角
+			ctx.arc(x + w - tr, y + tr, tr, Math.PI * 1.5, Math.PI * 2)
+			ctx.lineTo(x + w, y + h - br)
+		}
+		ctx.closePath()
+		if (stroke) ctx.stroke()
+		if (fill) ctx.fill()
+	}
+	setTransform(box, {transform}) {
+		const {ctx} = this
+		let {
+			scaleX = 1,
+			scaleY = 1,
+			translateX = 0,
+			translateY = 0,
+			rotate = 0,
+			skewX = 0,
+			skewY = 0
+		} = transform || {}
+		let {
+			left: x,
+			top: y,
+			width: w,
+			height: h
+		} = box
+		translateX = toPx(translateX, w) || 0
+		translateY = toPx(translateY, h) || 0
+		ctx.scale(scaleX, scaleY)
+		ctx.translate(
+			w * (scaleX > 0 ? 1 : -1) / 2 + (x + translateX) / scaleX,  
+			h * (scaleY > 0 ? 1 : -1) / 2 + (y + translateY) / scaleY) 
+		
+		if(rotate) {
+			ctx.rotate(rotate * Math.PI / 180)
+		}
+		if(skewX || skewY) {
+			ctx.transform(1, Math.tan(skewY * Math.PI/180), Math.tan(skewX * Math.PI/180), 1 , 0, 0)
+		}
+	}
+	setBackground(bg , w, h) {
+		const {ctx} = this
+		if (!bg) {
+			// #ifndef MP-TOUTIAO || MP-BAIDU
+			ctx.setFillStyle('transparent')
+			// #endif
+			// #ifdef MP-TOUTIAO || MP-BAIDU
+			ctx.setFillStyle('rgba(0,0,0,0)')
+			// #endif
+		} else if(GD.isGradient(bg)) {
+			GD.doGradient(bg, w, h, ctx);
+		} else {
+			ctx.setFillStyle(bg)
+		}
+	}
+	setShadow({boxShadow: bs = []}) {
+		const {ctx} = this
+		if (bs.length) {
+			const [x, y, b, c] = bs
+			ctx.setShadow(x, y, b, c)
+		}
+	}
+	setBorder(box, style) {
+		const {ctx} = this
+		let {
+			left: x,
+			top: y,
+			width: w,
+			height: h
+		} = box
+		const {border, borderBottom, borderTop, borderRight, borderLeft, borderRadius: r, opacity = 1} = style;
+		const {
+			borderWidth : bw = 0,
+			borderStyle : bs,
+			borderColor : bc,
+		} = border || {}
+		const {
+			borderBottomWidth : bbw = bw,
+			borderBottomStyle : bbs = bs,
+			borderBottomColor : bbc= bc,
+		} = borderBottom || {}
+		const {
+			borderTopWidth: btw = bw,
+			borderTopStyle: bts = bs,
+			borderTopColor: btc = bc,
+		} = borderTop || {}
+		const {
+			borderRightWidth: brw = bw,
+			borderRightStyle: brs = bs,
+			borderRightColor: brc = bc,
+		} = borderRight || {}
+		const {
+			borderLeftWidth: blw = bw,
+			borderLeftStyle: bls = bs,
+			borderLeftColor: blc  = bc,
+		} = borderLeft || {}
+		
+		let {
+			borderTopLeftRadius: tl = r || 0,
+			borderTopRightRadius: tr = r || 0,
+			borderBottomRightRadius: br = r || 0,
+			borderBottomLeftRadius: bl = r || 0
+		} = r || {r,r,r,r}
+		if(!borderBottom && !borderLeft && !borderTop && !borderRight && !border) return;
+		const _borderType = (w, s, c) => {
+			// #ifndef APP-NVUE
+			if (s == 'dashed') {
+				// #ifdef MP
+				ctx.setLineDash([Math.ceil(w * 4 / 3), Math.ceil(w * 4 / 3)])
+				// #endif
+				// #ifndef MP
+				ctx.setLineDash([Math.ceil(w * 6), Math.ceil(w * 6)])
+				// #endif
+			} else if (s == 'dotted') {
+				ctx.setLineDash([w, w])
+			}
+			// #endif
+			ctx.setStrokeStyle(c)
+		}
+		const _setBorder = (x1, y1, x2, y2, x3, y3, r1, r2, p1, p2, p3,  bw, bs, bc) => {
+			ctx.save()
+			this.setOpacity(style)
+			this.setTransform(box, style)
+			ctx.setLineWidth(bw)
+			_borderType(bw, bs, bc)
+			ctx.beginPath()
+			ctx.arc(x1, y1, r1, Math.PI * p1, Math.PI * p2)
+			ctx.lineTo(x2, y2)
+			ctx.arc(x3, y3, r2, Math.PI * p2, Math.PI * p3)
+			ctx.stroke()
+			ctx.restore()
+		}
+	
+		if(border) {
+			ctx.save()
+			this.setOpacity(style)
+			this.setTransform(box, style)
+			ctx.setLineWidth(bw)
+			_borderType(bw, bs, bc)
+			this.roundRect(-w/2, -h/2, w, h, r, false, bc ? true : false)
+			ctx.restore()
+		}
+		x = -w/2
+		y = -h/2
+		if(borderBottom) {
+			_setBorder(x + w - br, y + h - br, x + bl, y + h, x + bl, y + h - bl, br, bl, 0.25, 0.5, 0.75, bbw, bbs, bbc)
+		}
+		if(borderLeft) {
+			// 左下角
+			_setBorder(x + bl, y + h - bl, x, y + tl, x + tl, y + tl, bl, tl, 0.75, 1, 1.25, blw, bls, blc)
+		}
+		if(borderTop) {
+			// 左上角
+			_setBorder(x + tl, y + tl, x + w - tr, y, x + w - tr, y + tr, tl, tr, 1.25, 1.5, 1.75, btw, bts, btc)
+		}
+		if(borderRight) {
+			// 右上角
+			_setBorder(x + w - tr, y + tr, x + w, y + h - br, x + w - br, y + h - br, tr, br, 1.75, 2, 0.25, btw, bts, btc)
+		}
+	}
+	setOpacity({opacity = 1}) {
+		this.ctx.setGlobalAlpha(opacity)
+	}
+	drawView(box, style) {
+		const {ctx} = this
+		const {
+			left: x,
+			top: y,
+			width: w,
+			height: h
+		} = box
+		let {
+			borderRadius = 0,
+			border,
+			borderTop,
+			borderBottom,
+			borderLeft,
+			borderRight,
+			color = '#000000',
+			backgroundColor: bg,
+			rotate,
+			shadow
+		} = style || {}
+		ctx.save()
+		this.setOpacity(style)
+		this.setTransform(box, style)
+		this.setShadow(style)
+		this.setBackground(bg, w, h)
+		this.roundRect(-w/2, -h/2, w, h, borderRadius, true, false)
+		ctx.restore()
+		this.setBorder(box, style)
+	}
+	async drawImage(img, box = {}, style = {}, custom = true) {
+		await new Promise(async (resolve, reject) => {
+			const {ctx} = this
+			const canvas = this.canvas
+			let {
+				borderRadius = 0,
+				mode,
+				padding = {},
+				backgroundColor: bg,
+			} = style
+			const {paddingTop: pt = 0, paddingLeft: pl= 0, paddingRight: pr= 0, paddingBottom: pb = 0} = padding
+			let {
+				left: x,
+				top: y,
+				width: w,
+				height: h
+			} = box
+			ctx.save()
+			if(!custom) {
+				this.setOpacity(style)
+				this.setTransform(box, style)
+				if(bg) {
+					this.setBackground(bg, w, h)
+				}
+				this.setShadow(style)
+				x = -w/2
+				y = -h/2
+				this.roundRect(x, y, w, h, borderRadius, borderRadius ? true : false, false)
+			}
+			ctx.clip()
+			const _modeImage = (img) => {
+				x += pl
+				y += pt
+				w = w - pl - pr
+				h = h - pt - pb
+				// 获得图片原始大小
+				let rWidth = img.width
+				let rHeight = img.height
+				let startX = 0
+				let startY = 0
+				// 绘画区域比例
+				const cp = w / h
+				// 原图比例
+				const op = rWidth / rHeight
+				if(!img.width) {
+					mode = 'scaleToFill'
+				}
+				switch(mode) {
+					case 'scaleToFill': 
+						ctx.drawImage(img.src, x, y, w, h);
+						break;
+					case 'aspectFit': 	
+						if(cp >= op) {
+							rWidth = h * op;
+							rHeight = h
+							startX = x + Math.round(w - rWidth) / 2 
+							startY = y
+						} else {
+							rWidth = w
+							rHeight = w / op;
+							startX = x
+							startY = y + Math.round(h - rHeight) / 2 
+						}
+						ctx.drawImage(img.src, startX, startY, rWidth, rHeight);
+						break;
+					case 'aspectFill': 
+						if (cp >= op) {
+							rHeight = rWidth / cp;
+							// startY = Math.round((h - rHeight) / 2)
+						} else {
+							rWidth = rHeight * cp;
+							startX = Math.round(((img.width || w) - rWidth) / 2)
+						}
+						// 百度小程序 开发工具 顺序有问题 暂不知晓真机
+						// #ifdef MP-BAIDU
+						ctx.drawImage(img.src, x, y, w, h, startX, startY, rWidth, rHeight)
+						// #endif
+						// #ifndef MP-BAIDU
+						ctx.drawImage(img.src, startX, startY, rWidth, rHeight, x, y, w, h)
+						// #endif
+						 break;
+					default: 
+						ctx.drawImage(img.src, x, y, w, h);
+				}
+			}
+			const _restore = () => {
+				ctx.restore()
+				this.setBorder(box, style)
+				setTimeout(() => {
+					resolve(true)
+				}, this.sleep)
+			}
+			const _drawImage = (img) => {
+				if (this.use2dCanvas) {
+					const Image = canvas.createImage()
+					Image.onload = () => {
+						img.src = Image
+						_modeImage(img)
+						_restore()
+					}
+					Image.onerror = () => {
+						console.error(`createImage fail: ${JSON.stringify(img)}`)
+						reject(new Error(`createImage fail: ${JSON.stringify(img)}`))
+					}
+					Image.src = img.src
+				} else {
+					_modeImage(img)
+					_restore()
+				}
+			}
+			
+			if(typeof img === 'string') {
+				const {path: src, width, height} = await getImageInfo(img, this.isH5PathToBase64)
+				_drawImage({src, width, height})
+			} else {
+				_drawImage(img)
+			}
+		})
+	}
+	drawText(text, box, style, rules) {
+		const {ctx} = this
+		let {
+			left: x,
+			top: y,
+			width: w,
+			height: h,
+			offsetLeft: ol = 0
+		} = box
+		let {
+			color = '#000000',
+			lineHeight = '1.4em',
+			fontSize = 14,
+			fontWeight,
+			fontFamily,
+			textStyle,
+			textAlign = 'left',
+			verticalAlign: va = 'top',
+			backgroundColor: bg,
+			maxLines,
+			display,
+			padding = {},
+			borderRadius = 0,
+			textDecoration: td
+		} = style
+		const {paddingTop: pt = 0, paddingLeft: pl = 0} = padding
+		lineHeight = toPx(lineHeight, fontSize)
+		if (!text) return
+		ctx.save()
+		this.setOpacity(style)
+		this.setTransform(box, style)
+		x = -w/2
+		y = -h/2
+		ctx.setTextBaseline(va)
+		ctx.setFonts({fontFamily, fontSize, fontWeight, textStyle})
+		ctx.setTextAlign(textAlign)
+		
+		if(bg) {
+			this.setBackground(bg, w, h)
+			this.roundRect(x, y, w, h, borderRadius, 1, 0)
+		 }
+		 if(display && display.includes('lock')) {
+			x += pl
+			y += pt 
+		 }
+		this.setShadow(style)
+		ctx.setFillStyle(color)
+		let rulesObj = {};
+		if(rules) {
+			if (rules.word.length > 0) {
+				for (let i = 0; i < rules.word.length; i++) {
+					let startIndex = 0,
+						index;
+					while ((index = text.indexOf(rules.word[i], startIndex)) > -1) {
+						rulesObj[index] = { 
+							reset: true
+						};
+						for (let j = 0; j < rules.word[i].length; j++) {
+							rulesObj[index + j] = { 
+								reset: true
+							};
+						}
+						startIndex = index + 1;
+					}
+				}
+			}
+		}
+		// 水平布局
+		switch (textAlign) {
+			case 'left':
+				break
+			case 'center':
+				x += 0.5 * w
+				break
+			case 'right':
+				x += w
+				break
+			default:
+				break
+		}
+		const textWidth = ctx.measureText(text, fontSize).width
+		const actualHeight = Math.ceil(textWidth / w) * lineHeight
+		let paddingTop = Math.ceil((h - actualHeight) / 2)
+		if (paddingTop < 0) paddingTop = 0
+		// 垂直布局
+		switch (va) {
+			case 'top':
+				break
+			case 'middle':
+				y += fontSize / 2
+				break
+			case 'bottom':
+				y += fontSize 
+				break
+			default:
+				break
+		}
+		
+		// 绘线
+		const _drawLine = (x, y, textWidth) => {
+			const { system } = uni.getSystemInfoSync()
+			if(/win|mac/.test(system)){
+				y += (fontSize / 3)
+			}
+			// 垂直布局
+			switch (va) {
+				case 'top':
+					break
+				case 'middle':
+					y -= fontSize / 2 
+					break
+				case 'bottom':
+					y -= fontSize
+					break
+				default:
+					break
+			}
+			let to = x
+			switch (textAlign) {
+				case 'left':
+					x = x
+					to+= textWidth
+					break
+				case 'center':
+					x = x - textWidth / 2
+					to = x + textWidth
+					break
+				case 'right':
+					to = x
+					x = x - textWidth
+					break
+				default:
+					break
+			}
+			
+			if(td) {
+				ctx.setLineWidth(fontSize / 13);
+				ctx.beginPath();
+				
+				if (/\bunderline\b/.test(td)) {
+					y -= inlinePaddingTop * 0.8
+					ctx.moveTo(x, y);
+					ctx.lineTo(to, y);
+				}
+				
+				if (/\boverline\b/.test(td)) {
+					y += inlinePaddingTop
+					ctx.moveTo(x, y - lineHeight);
+					ctx.lineTo(to, y - lineHeight);
+				}
+				if (/\bline-through\b/.test(td)) {
+					ctx.moveTo(x , y - lineHeight / 2 );
+					ctx.lineTo(to, y - lineHeight /2 );
+				}
+				ctx.closePath();
+				ctx.setStrokeStyle(color);
+				ctx.stroke();
+			}
+		}
+		const _reset = (text, x, y) => {
+			const rs = Object.keys(rulesObj)
+			for (let i = 0; i < rs.length; i++) {
+				const item = rulesObj[rs[i]]
+				// ctx.globalCompositeOperation = "destination-out";
+				ctx.save();
+				ctx.setFillStyle(rules.color);
+				if(item.char) {
+					ctx.fillText(item.char, item.x , item.y)
+				}
+				ctx.restore();
+			}
+		}
+		const _setText = (isReset, char) => {
+			if(isReset) {
+				const t1 = Math.round(ctx.measureText('\u0020', fontSize).width)
+				const t2 = Math.round(ctx.measureText('\u3000', fontSize).width)
+				const width = Math.round(ctx.measureText(char, fontSize).width)
+				let _char = ''
+				let _num = 1
+				if(width == t2){
+					_char ='\u3000'
+					_num = 1
+				} else {
+					_char = '\u0020'
+					_num = Math.ceil(width / t1)
+				}
+				return {char: new Array(_num).fill(_char).join(''), width}
+			} else {
+				return {char}
+			}
+		}
+		const _setRulesObj = (text, index, x, y) => {
+			rulesObj[index].x = x
+			rulesObj[index].y = y
+			rulesObj[index].char = text
+		}
+		const _setRules = (x, rs, text, textWidth, {startIndex = 0, endIndex}) => {
+			let clonetext = text
+			if(/·/.test(text)) {
+				clonetext = clonetext.replace(/·/g, '.')
+				textWidth = ctx.measureText(clonetext, fontSize).width
+			}
+			let _text = text.split('')
+			let _x = x
+			let first = true
+			for (let i = 0; i < rs.length; i++) {
+				const index = rs[i]
+				const key = index - startIndex
+				const t = _text[key]
+				if(t) {
+					let {char, width} = _setText(rulesObj[index], t)
+					_text[key] = char
+					if(first) {
+						first = false
+						let dot = 0
+						let dot2 = 0
+						let num = 0
+						if(textAlign == 'center') {
+							_x = x - 0.5 * (textWidth - width - (dot2 - dot) * num)
+						}
+						if(textAlign == 'right') {
+							 _x = x - textWidth + width + (dot2 - dot) * num
+						}
+					}
+					_setRulesObj(t, index, _x  + ctx.measureText(clonetext.substring(0, key), fontSize).width, y + inlinePaddingTop)
+				} else {
+					continue
+				}
+				
+			}
+			return _text
+		}
+		const inlinePaddingTop = Math.ceil((lineHeight - fontSize) / 2)
+		// 不超过一行
+		if (textWidth + ol <= w && !text.includes('\n')) {
+			x = x + ol
+			const rs = Object.keys(rulesObj)
+			let _text = ''
+			if(rs) {
+				_text = _setRules(x, rs, text, textWidth, {})
+				_reset()
+			}
+			ctx.fillText(_text.join(''), x, y + inlinePaddingTop)
+			y += lineHeight
+			_drawLine(x, y, textWidth)
+			ctx.restore()
+			this.setBorder(box, style)
+			return
+		}
+		// 多行文本
+		const chars = text.split('')
+		const _y = y
+		let _x = x
+		// 逐行绘制
+		let line = ''
+		let lineIndex = 0
+		let startIndex = 0
+		for(let index = 0 ; index <= chars.length; index++){
+			let ch = chars[index] || ''
+			const isLine = ch === '\n'
+			const isRight = ch == ''// index == chars.length
+			ch = isLine ? '' : ch;
+			let textline = line + ch
+			let textWidth = ctx.measureText(textline, fontSize).width
+			// 绘制行数大于最大行数,则直接跳出循环
+			if (lineIndex >= maxLines) {
+				break;
+			}
+			if(lineIndex == 0) {
+				textWidth = textWidth + ol
+				_x = x + ol
+			} else {
+				textWidth = textWidth
+				_x = x
+			}
+			
+			if (textWidth > w || isLine || isRight) {
+				let endIndex = index
+				lineIndex++
+				line = isRight && textWidth <= w ? textline : line
+				if(lineIndex === maxLines && textWidth > w) {
+					while( ctx.measureText(`${line}...`, fontSize).width > w) {
+						if (line.length <= 1) {
+							// 如果只有一个字符时,直接跳出循环
+							break;
+						}
+						line = line.substring(0, line.length - 1);
+					}
+					line += '...'
+				}
+				const rs = Object.keys(rulesObj)
+				let _text = ''
+				if(rs) {
+					_text = _setRules(x, rs, line, textWidth, {startIndex, endIndex})
+					_reset()
+				}
+				ctx.fillText(_text.join(''), _x, y + inlinePaddingTop)
+				y += lineHeight
+				_drawLine(_x, y, textWidth)
+				line = ch
+				startIndex = endIndex + (isLine ? 1 : 0)
+				if ((y + lineHeight) > (_y + h)) break
+			} else {
+				line = textline
+			}
+		}
+		// const rs = Object.keys(rulesObj)
+		// if(rs) {
+		// 	_reset()
+		// }
+		ctx.restore()
+		this.setBorder(box, style)
+	}
+	async drawNode(element) {
+		const {
+			layoutBox,
+			computedStyle,
+			name,
+			rules
+		} = element
+		const {
+			src,
+			text
+		} = element.attributes
+		if (name === 'view') {
+			this.drawView(layoutBox, computedStyle)
+		} else if (name === 'image' && src) {
+			await this.drawImage(element.attributes, layoutBox, computedStyle, false)
+		} else if (name === 'text') {
+			this.drawText(text, layoutBox, computedStyle, rules)
+		} else if (name === 'qrcode') {
+			QR.api.draw(text, this, layoutBox, computedStyle)
+		}
+		if (!element.children) return
+		const childs = Object.values ? Object.values(element.children) : Object.keys(element.children).map((key) => element.children[key]);
+		for (const child of childs) {
+			await this.drawNode(child)
+		}
+	}
+}

+ 107 - 0
components/lime-painter/gradient.js

xqd
@@ -0,0 +1,107 @@
+/* eslint-disable */
+
+export const GD = {
+	isGradient(bg) {
+		if (bg && (bg.startsWith('linear') || bg.startsWith('radial'))) {
+			return true;
+		}
+		return false;
+	},
+	doGradient(bg, width, height, ctx) {
+		if (bg.startsWith('linear')) {
+			linearEffect(width, height, bg, ctx);
+		} else if (bg.startsWith('radial')) {
+			radialEffect(width, height, bg, ctx);
+		}
+	},
+}
+
+function analizeGrad(string) {
+	const colorPercents = string.substring(0, string.length - 1).split("%,");
+	const colors = [];
+	const percents = [];
+	for (let colorPercent of colorPercents) {
+		colors.push(colorPercent.substring(0, colorPercent.lastIndexOf(" ")).trim());
+		percents.push(colorPercent.substring(colorPercent.lastIndexOf(" "), colorPercent.length) / 100);
+	}
+	return {
+		colors: colors,
+		percents: percents
+	};
+}
+
+function radialEffect(width, height, bg, ctx) {
+	const colorPer = analizeGrad(bg.match(/radial-gradient\((.+)\)/)[1]);
+	const grd = ctx.createCircularGradient(0, 0, width < height ? height / 2 : width / 2);
+	for (let i = 0; i < colorPer.colors.length; i++) {
+		grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
+	}
+	ctx.setFillStyle(grd);
+}
+
+function analizeLinear(bg, width, height) {
+	const direction = bg.match(/([-]?\d{1,3})deg/);
+	const dir = direction && direction[1] ? parseFloat(direction[1]) : 0;
+	let coordinate;
+	switch (dir) {
+		case 0:
+			coordinate = [0, -height / 2, 0, height / 2];
+			break;
+		case 90:
+			coordinate = [width / 2, 0, -width / 2, 0];
+			break;
+		case -90:
+			coordinate = [-width / 2, 0, width / 2, 0];
+			break;
+		case 180:
+			coordinate = [0, height / 2, 0, -height / 2];
+			break;
+		case -180:
+			coordinate = [0, -height / 2, 0, height / 2];
+			break;
+		default:
+			let x1 = 0;
+			let y1 = 0;
+			let x2 = 0;
+			let y2 = 0;
+			if (direction[1] > 0 && direction[1] < 90) {
+				x1 = (width / 2) - ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (
+					90 - direction[1]) * Math.PI * 2 / 360) / 2;
+				y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
+				x2 = -x1;
+				y1 = -y2;
+			} else if (direction[1] > -180 && direction[1] < -90) {
+				x1 = -(width / 2) + ((width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (
+					90 - direction[1]) * Math.PI * 2 / 360) / 2;
+				y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
+				x2 = -x1;
+				y1 = -y2;
+			} else if (direction[1] > 90 && direction[1] < 180) {
+				x1 = (width / 2) + (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 * (
+					90 - direction[1]) * Math.PI * 2 / 360) / 2;
+				y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
+				x2 = -x1;
+				y1 = -y2;
+			} else {
+				x1 = -(width / 2) - (-(width / 2) * Math.tan((90 - direction[1]) * Math.PI * 2 / 360) - height / 2) * Math.sin(2 *
+					(90 - direction[1]) * Math.PI * 2 / 360) / 2;
+				y2 = Math.tan((90 - direction[1]) * Math.PI * 2 / 360) * x1;
+				x2 = -x1;
+				y1 = -y2;
+			}
+			coordinate = [x1, y1, x2, y2];
+			break;
+	}
+	return coordinate;
+}
+
+function linearEffect(width, height, bg, ctx) {
+	const param = analizeLinear(bg, width, height);
+	const grd = ctx.createLinearGradient(param[0], param[1], param[2], param[3]);
+	const content = bg.match(/linear-gradient\((.+)\)/)[1];
+	const colorPer = analizeGrad(content.substring(content.indexOf(',') + 1));
+	for (let i = 0; i < colorPer.colors.length; i++) {
+		grd.addColorStop(colorPer.percents[i], colorPer.colors[i]);
+	}
+	ctx.setFillStyle(grd);
+}

+ 286 - 0
components/lime-painter/index.vue

xqd
@@ -0,0 +1,286 @@
+<template>
+	<canvas 
+		v-if="use2dCanvas" 
+		:id="canvasId" 
+		type="2d" 
+		:style="style"
+		>
+	</canvas>
+	<canvas
+		v-else 
+		:canvas-id="canvasId" 
+		:style="style" 
+		:id="canvasId" 
+		:width="boardWidth * dpr" 
+		:height="boardHeight * dpr"
+		>
+	</canvas>
+</template>
+
+<script>
+import { toPx, base64ToPath, compareVersion} from './utils';
+import { Draw } from './draw';
+import { Layout } from './layout';
+import { adaptor, expand } from './canvas';
+export default {
+	// version: '1.5.9.7',
+	name: 'l-painter',
+	props: {
+		board: Object,
+		fileType: {
+			type: String,
+			default: 'png'
+		},
+		quality: {
+			type: Number,
+			default: 1
+		},
+		width: [Number, String],
+		height: [Number, String],
+		pixelRatio: Number,
+		customStyle: String,
+		isRenderImage: Boolean,
+		isBase64ToPath: Boolean,
+		isH5PathToBase64: Boolean,
+		sleep: {
+			type: Number,
+			default: 1000/30
+		},
+		// #ifdef MP-WEIXIN
+		type: {
+			type: String,
+			default: '2d',
+		},
+		// #endif
+		
+	},
+	data() {
+		return {
+			// #ifndef MP-WEIXIN || MP-QQ || MP-BAIDU
+			canvasId: `l-painter${this._uid}`,
+			// #endif
+			// #ifdef MP-WEIXIN || MP-QQ || MP-BAIDU
+			canvasId: `l-painter`,
+			// #endif
+			// #ifdef MP-WEIXIN
+			use2dCanvas: true,
+			// #endif
+			// #ifndef MP-WEIXIN
+			use2dCanvas: false,
+			// #endif
+			draw: null,
+			ctx: null,
+			layout: new Layout()
+		};
+	},
+	computed: {
+		newboard() {
+			return this.board && JSON.parse(JSON.stringify(this.board))
+		},
+		style() {
+			return `width:${this.boardWidth}px; height: ${this.boardHeight}px; ${this.customStyle}`;
+		},
+		dpr() {
+			return this.pixelRatio || uni.getSystemInfoSync().pixelRatio;
+		},
+		boardWidth() {
+			const { width = 200 } = this.board || {};
+			return toPx(this.width || width);
+		},
+		boardHeight() {
+			const { height = 200 } = this.board || {};
+			return toPx(this.height || height);
+		}
+	},
+	watch: {
+		style() {
+			// #ifdef MP-WEIXIN
+			if(this.use2dCanvas) {
+				this.inited = false;
+			}
+			// #endif
+			// #ifdef MP-ALIPAY
+			this.inited = false;
+			// #endif
+		}
+	},
+	mounted() {
+		// #ifdef MP-WEIXIN
+		const {SDKVersion, version, platform} = wx.getSystemInfoSync()
+		// ios wx7.0.20 createImage bug
+		this.use2dCanvas = (this.type === '2d' && compareVersion(SDKVersion, '2.9.2') >= 0) && !(/ios/.test(platform) && /7.0.20/.test(version));
+		// #endif
+		this.$watch('board', async (val, old) => {
+			if (JSON.stringify(val) === '{}' || !val) return;
+			this.render();
+		}, {
+			deep: true, 
+			immediate: true,
+			})
+	},
+	methods: {
+		async render(args = {}, single = false) {
+			const isArgsNoEmpty = JSON.stringify(args) != '{}'
+			const ctx = await this.getContext()
+			const { use2dCanvas, boardWidth, boardHeight, board, canvas, isBase64ToPath, isH5PathToBase64, sleep } = this;
+			if (use2dCanvas && !canvas) {
+				return Promise.reject(new Error('render: fail canvas has not been created'));
+			}
+			this.boundary = {
+			  top: 0,
+			  left: 0,
+			  width: boardWidth,
+			  height: boardHeight,
+			}
+			if(!single) {
+				ctx.clearRect(0, 0, boardWidth, boardHeight);
+			}
+			if(!this.draw || isArgsNoEmpty) {
+				this.draw = new Draw(ctx, canvas, use2dCanvas, isH5PathToBase64, sleep);
+			} 
+			this.layout.init(ctx, this.boundary, this.isH5PathToBase64)
+			if(isArgsNoEmpty || board && JSON.stringify(board) != '{}') {
+				this.node = await this.layout.calcNode(isArgsNoEmpty ? args : board)
+			}
+			if(this.node) {
+				await this.draw.drawNode(this.node);
+			}
+			await new Promise(resolve => this.$nextTick(resolve)) 
+			if (!use2dCanvas && !single) {
+				await this.canvasDraw(ctx);
+			}
+			this.$emit('done')
+			if(this.isRenderImage && !single) {
+				this.canvasToTempFilePath()
+				.then(async res => {
+					if(/^data:image\/(\w+);base64/.test(res.tempFilePath) && isBase64ToPath) {
+						const img = await base64ToPath(res.tempFilePath)
+						this.$emit('success', img)
+					} else {
+						this.$emit('success', res.tempFilePath)
+					}
+				})
+				.catch(err => {
+					this.$emit('fail', err)
+					new Error(JSON.stringify(err))
+					console.error(JSON.stringify(err))
+				})
+			}
+			return Promise.resolve({ctx, draw: this.draw});
+		},
+		async custom(cb) {
+			const {ctx, draw} = await this.render({}, true)
+			ctx.save()
+			await cb(ctx, draw)
+			ctx.restore()
+			return Promise.resolve(true);
+		},
+		async single(args = {}) {
+			await this.render(args, true)
+			return Promise.resolve(true);
+		},
+		canvasDraw(flag = false) {
+			const {ctx} = this
+			return new Promise(resolve => {
+				ctx.draw(flag, () => {
+					resolve(true);
+				});
+			});
+		},
+		async getContext() {
+			if(this.ctx && this.inited) {
+				return Promise.resolve(this.ctx)
+			};
+			const { type, use2dCanvas, dpr, boardWidth, boardHeight } = this;
+			await new Promise(resolve => this.$nextTick(resolve)) 
+			const _getContext = () => {
+				return new Promise(resolve => {
+				uni.createSelectorQuery()
+					.in(this)
+					.select('#' + this.canvasId)
+					.boundingClientRect()
+					.exec(res => {
+						if(res) {
+							const ctx = uni.createCanvasContext(this.canvasId, this);
+							if (!this.inited) {
+								this.inited = true;
+								this.use2dCanvas = false;
+								this.canvas = res
+							}
+							// #ifdef MP-ALIPAY
+							ctx.scale(dpr, dpr);
+							// #endif
+							this.ctx = expand(ctx)
+							resolve(this.ctx);
+						}
+					})
+				})
+			}
+			// #ifndef MP-WEIXIN 
+			return _getContext()
+			// #endif
+			
+			if(!use2dCanvas) {
+				return _getContext()
+			}
+			return new Promise(resolve => {
+				uni.createSelectorQuery()
+					.in(this)
+					.select('#l-painter')
+					.node()
+					.exec(res => {
+						const canvas = res[0].node;
+						if(!canvas) {
+							this.use2dCanvas = false;
+							return this.getContext()
+						}
+						const ctx = canvas.getContext(type);
+						if (!this.inited) {
+							this.inited = true;
+							canvas.width = boardWidth * dpr;
+							canvas.height = boardHeight * dpr;
+							this.use2dCanvas = true;
+							this.canvas = canvas
+							ctx.scale(dpr, dpr);
+						}
+						this.ctx = adaptor(ctx)
+						resolve(this.ctx);
+					});
+				
+			});
+		},
+		canvasToTempFilePath(args = {}) {
+		  const {use2dCanvas, canvasId} = this
+		  return new Promise((resolve, reject) => {
+		    let { top: y = 0, left: x = 0, width, height } = this.boundary || this
+			let destWidth = width * this.dpr
+			let destHeight = height * this.dpr
+			// #ifdef MP-ALIPAY
+			width = width * this.dpr
+			height = height * this.dpr
+			// #endif
+		    const copyArgs = {
+		      x,
+		      y,
+		      width,
+		      height,
+		      destWidth,
+		      destHeight,
+		      canvasId,
+		      fileType: args.fileType || this.fileType,
+		      quality: /\d/.test(args.quality) ? args.quality : this.quality,
+		      success: resolve,
+		      fail: reject
+		    }
+		    if (use2dCanvas) {
+		      delete copyArgs.canvasId
+		      copyArgs.canvas = this.canvas
+		    }
+		    uni.canvasToTempFilePath(copyArgs, this)
+		  })
+		}
+	}
+};
+</script>
+
+<style></style>

+ 372 - 0
components/lime-painter/layout.js

xqd
@@ -0,0 +1,372 @@
+import { toPx, isNumber, getImageInfo  } from './utils'
+let uuid = 0;
+export class Layout {
+	constructor(context, root, isH5PathToBase64) {
+		this.ctx = context
+		this.root = root
+		this.isH5PathToBase64 = isH5PathToBase64
+	}
+	init(context, root, isH5PathToBase64) {
+		this.ctx = context
+		this.root = root
+		this.isH5PathToBase64 = isH5PathToBase64
+	}
+	async getNodeTree(element, parent = {}, index = 0, siblings = [], source) {
+		let computedStyle = Object.assign({}, this.getComputedStyle(element, parent, index));
+		let attributes = await this.getAttributes(element)
+		let node = {
+			id: uuid++,
+			parent,
+			computedStyle,
+			rules: element.rules,
+			attributes: Object.assign({}, attributes),
+			name: element?.type || 'view',
+		}
+		if(JSON.stringify(parent) === '{}' && !element.type) {
+			const {left = 0, top = 0, width = 0, height = 0 } = computedStyle
+			node.layoutBox = {left, top, width, height }
+		} else {
+			node.layoutBox = Object.assign({left: 0, top: 0}, this.getLayoutBox(node, parent, index, siblings, source))
+		}
+		if (element?.views) {
+			let childrens = []
+			node.children = []
+			for (let i = 0; i < element.views.length; i++) {
+				let v = element.views[i]
+				childrens.push(await this.getNodeTree(v, node, i, childrens, element))
+			}
+			 node.children = childrens
+		}
+		return node
+	}
+	getComputedStyle(element, parent = {}, index = 0) {
+		const style = {}
+		const name = element.name || element.type
+		const node = JSON.stringify(parent) == '{}' && !name ? element :  element.css;
+		
+		if(!node) return style
+		const inheritProps = ['color', 'fontSize', 'lineHeight', 'verticalAlign', 'fontWeight', 'textAlign']
+		if(parent.computedStyle) {
+			inheritProps.forEach(prop => {
+				if(node[prop] || parent.computedStyle[prop]) {
+					node[prop] = node[prop] || parent.computedStyle[prop]
+				}
+			})
+		}
+		for (let value of Object.keys(node)) {
+			const item = node[value]
+			if(value == 'views') {continue}
+			if (/^(box)?shadow$/i.test(value)) {
+				let shadows = item.split(' ').map(v => /^\d/.test(v) ? toPx(v) : v)
+				style.boxShadow = shadows
+				continue
+			}
+			if (/^border(?!radius)/i.test(value)) {
+				const prefix = value.match(/^border([BTRLa-z]+)?/)[0]
+				const type = value.match(/[W|S|C][a-z]+/)
+				let v = item.split(' ').map(v => /^\d/.test(v) ? toPx(v) : v)
+				
+				if(v.length > 1) {
+					style[prefix] = {
+						[prefix + 'Width'] : v[0] || 1,
+						[prefix + 'Style'] : v[1] || 'solid',
+						[prefix + 'Color'] : v[2] || 'black'
+					}
+				} else {
+					style[prefix] = {
+						[prefix + 'Width'] :  1,
+						[prefix + 'Style'] : 'solid',
+						[prefix + 'Color'] : 'black'
+					}
+					style[prefix][prefix + type[0]] = v[0]
+				}
+				continue
+			}
+			if (/^background(Color)?$/i.test(value)) {
+				style['backgroundColor'] = item
+				continue
+			}
+			if(/padding|margin|radius/i.test(value)) {
+				let isRadius = value.includes('adius')
+				let prefix = isRadius ? 'borderRadius' : value.match(/[a-z]+/)[0]
+				let pre = [0,0,0,0].map((item, i) => isRadius ? ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius'][i] : [prefix + 'Top', prefix + 'Right', prefix + 'Bottom', prefix + 'Left'][i] )
+				if(value === 'padding' || value === 'margin' || value === 'radius' || value === 'borderRadius') {
+					let v = item?.split(' ').map((item) => /^\d/.test(item) && toPx(item, node['width']), []) ||[0];
+					let type = isRadius ? 'borderRadius' : value;
+					if(v.length == 1) {
+						style[type] = v[0]
+					} else {
+						let [t, r, b, l] = v
+						style[type] = {
+							[pre[0]]: t,
+							[pre[1]]: isNumber(r) ? r : t,
+							[pre[2]]: isNumber(b) ? b : t,
+							[pre[3]]: isNumber(l) ? l : r
+						}
+					}
+				} else {
+					if(typeof style[prefix] === 'object') {
+						style[prefix][value] = toPx(item, node['width'])
+					} else {
+						style[prefix] = {
+							[pre[0]]: style[prefix] || 0,
+							[pre[1]]: style[prefix] || 0,
+							[pre[2]]: style[prefix] || 0,
+							[pre[3]]: style[prefix] || 0
+						}
+						style[prefix][value] = toPx(item, node['width'])
+					}
+				}
+				continue
+			}
+			 if(/^(width|height)$/i.test(value)) {
+				if(/%$/.test(item)) {
+					style[value] = toPx(item, parent.layoutBox[value])
+				} else {
+					style[value] = /px|rpx$/.test(item) ? toPx(item) : item
+				}
+				continue
+			}
+			if(/^transform$/i.test(value)) {
+				style[value]= {}
+				item.replace(/([a-zA-Z]+)\(([0-9,-\.%rpxdeg\s]+)\)/g, (g1, g2, g3) => {
+					const v = g3.split(',').map(k => k.replace(/(^\s*)|(\s*$)/g,''))
+					const transform = (v, r) => {
+						return v.includes('deg') ? v * 1 : r && !/%$/.test(r) ? toPx(v, r) : v
+					}
+					if(g2.includes('matrix')) {
+						style[value][g2] = v.map(v => v * 1)
+					} else if(g2.includes('rotate')) {
+						style[value][g2] = g3.match(/\d+/)[0] * 1
+					}else if(/[X, Y]/.test(g2)) {
+						style[value][g2] = /[X]/.test(g2) ? transform(v[0], node['width']) : transform(v[0], node['height'])
+					} else {
+						style[value][g2+'X'] = transform(v[0], node['width'] )
+						style[value][g2+'Y'] = transform(v[1] || v[0], node['height'])
+					}
+				})
+				continue
+			}
+			if(/%/.test(item)) {
+				const {width: pw, height: ph, left: pl, top: pt} = parent.layoutBox;
+				const {width: rw, height: rh} = this.root;
+				const isR = style.position == 'relative'
+				
+				if(value == 'width') {
+					style[value] = toPx(item, pw || rw)
+				}else if(value == 'height') {
+					style[value] = toPx(item, ph || rh)
+				}else if(value == 'left') {
+					style[value] = item // isR ? toPx(item, pw) + pl : toPx(item, rw)
+				}else if(value == 'top') {
+					style[value] = item // isR ? toPx(item, ph) + pt : toPx(item, rh)
+				} else {
+					style[value] = toPx(item, node['width'])
+				}
+			} else {
+				style[value] = /px|rpx$/.test(item) ? toPx(item) : /em$/.test(item) && name == 'text'? toPx(item, node['fontSize']) : item
+			}
+		}
+		if(/image/.test(element.name||element.type ) && !style.mode) {
+			style.mode = element.mode || 'scaleToFill' 
+			if((!node.width || node.width == 'auto') && (!node.height || node.width == 'auto') ) {
+				style.mode = ''
+			} 
+		}
+		return style
+	}
+	getLayoutBox(element, parent = {}, index = 0, siblings = [], source = {}) {
+		let box = {}
+		let {name, computedStyle: cstyle, layoutBox, attributes} = element || {}
+		if(!name) return box
+		const {ctx} = this
+		const pbox = parent.layoutBox || this.root
+		const pstyle = parent.computedStyle
+		let { 
+			verticalAlign: v, 
+			left: x, 
+			top: y,
+			width: w,
+			height: h,
+			fontSize = 14,
+			lineHeight = '1.4em',
+			maxLines,
+			fontWeight,
+			fontFamily,
+			textStyle,
+			position,
+			display
+			}  = cstyle;
+		const p = cstyle.padding
+		const m = cstyle.margin
+		const { paddingTop: pt = 0, paddingRight: pr = 0, paddingBottom: pb = 0, paddingLeft: pl = 0, } = cstyle.padding || {p,p,p,p}
+		const { marginTop: mt = 0, marginRight: mr = 0, marginBottom: mb = 0, marginLeft: ml = 0, } = cstyle.margin || {m,m,m,m}
+		const {layoutBox: lbox, computedStyle: ls, name: lname} = siblings[index - 1] || {}
+		const {layoutBox: rbox, computedStyle: rs, name: rname} = siblings[index + 1] || {}
+		
+		const lmb = ls?.margin?.marginBottom || 0
+		const lmr = ls?.margin?.marginRight || 0
+		
+		if(/%$/.test(x)) {
+			x = toPx(x, pbox.width)
+		}
+		if(/%$/.test(y)) {
+			y = toPx(y, pbox.height)
+		}
+		if(position == 'relative') {
+			x += pbox.left
+			y += pbox.top
+		}
+		if(name === 'text') {
+			const text = attributes.text ||''
+			lineHeight = toPx(lineHeight, fontSize)
+			ctx.save()
+			ctx.setFonts({fontFamily, fontSize, fontWeight, textStyle})
+			const isLeft = index == 0 
+			const islineBlock = display === 'inlineBlock'
+			const isblock = display === 'block' || ls?.display === 'block' 
+			const isOnly = isLeft && !rbox || !parent?.id
+			const lboxR = isLeft || isblock ? 0 : lbox.offsetRight || 0
+			let texts = text.split('\n')
+			let lineIndex = 1
+			let line = ''
+			const textIndent = cstyle.textIndent || 0
+			if(!isOnly && !islineBlock) {
+				texts.map((t, i) => {
+					lineIndex += i
+					const chars = t.split('')
+					for (let j = 0; j < chars.length; j++) {
+						let ch = chars[j]
+						let textline = line + ch
+						let textWidth = ctx.measureText(textline, fontSize).width
+						if(lineIndex == 1) {
+							textWidth = textWidth + (isblock ? 0 : lboxR) +  textIndent
+						}
+						if(textWidth > pbox.width) {
+							lineIndex++
+							line = ch
+						} else {
+							line = textline
+						}
+					}
+				})
+			} else {
+				line = text
+				lineIndex = Math.max(texts.length, Math.ceil(ctx.measureText(text, fontSize).width / ((w || pbox.width) - ctx.measureText('!', fontSize).width / 2)))
+			}
+			if(!islineBlock) {
+				box.offsetLeft =  (isNumber(x) || isblock || isOnly ? textIndent : lboxR) +  pl + ml;
+			}
+			
+			// 剩下的字宽度
+			const remain = ctx.measureText(line, fontSize).width
+			let width =  lineIndex > 1 ? pbox.width : remain + (box?.offsetLeft || 0);
+			if(!islineBlock) {
+				box.offsetRight = (x || 0) + box.offsetLeft + (w ? w : (isblock ? pbox.width : remain)) + pr + mr;
+			}
+			const lboxOffset = lbox ? lbox.left + lbox.width : 0;
+			const _getLeft = () => {
+				if(islineBlock) {
+					return (lboxOffset +  width > pbox.width || isLeft ? pbox.left : lboxOffset + lmr ) + ml
+				}
+				return (x || pbox.left)
+			}
+			const _getWidth = () => {
+				if(islineBlock) {
+					return width + pl + pr 
+				}
+				return w || (!isOnly || isblock ? pbox.width : (width > pbox.width - box.left || lineIndex > 1 ?  pbox.width - box.left : width))
+			}
+			const _getHeight = () => {
+				if(h) {
+					return h
+				} else if(lineIndex > 1 ) {
+					return (maxLines || lineIndex) * lineHeight + pt + pb 
+				} else {
+					return lineHeight + pt + pb 
+				}
+			}
+			const _getTop = () => {
+				let _y = y
+				if(_y) {
+					// return _y + pt + mt
+				} else if(isLeft) {
+					_y = pbox.top
+				} else if((lineIndex == 1 && width < pbox.width && lname === 'text' && !isblock && !islineBlock) || lbox.width < pbox.width && !(islineBlock && (lboxOffset +  width > pbox.width))) {
+					_y = lbox.top
+				} else {
+					_y = lbox.top + lbox.height - (ls?.lineHeight || 0)
+				}
+				if (v === 'bottom') {
+					_y = pbox.top + (pbox.height - box.height || 0)
+				}
+				if (v === 'middle') {
+					_y = pbox.top + (pbox.height ? (pbox.height - box.height || 0) / 2 : 0)
+				}
+				return _y + mt + (isblock && ls?.lineHeight || 0 ) + (lboxOffset +  width > pbox.width ? lmb : 0)
+			}
+			box.left = _getLeft() 
+			box.width = _getWidth() 
+			box.height = _getHeight()
+			box.top = _getTop()
+			if(pstyle && !pstyle.height) {
+				pbox.height = box.top - pbox.top + box.height
+			}
+			ctx.restore()
+		} else if(['view', 'qrcode'].includes(name)) {
+			box.left = ( x || pbox.left) + ml - mr
+			box.width = (w || pbox?.width) - pl - pr
+			box.height = (h || 0 ) 
+			if(isNumber(y)) {
+				box.top = y + mt
+			} else {
+				box.top = (lbox && (lbox.top + lbox.height) || pbox.top) + mt + lmb
+			}
+			
+		} else if(name === 'image') {
+			const {
+				width: rWidth,
+				height: rHeight
+			} = attributes
+			const limageOffset = lbox && (lbox.left + lbox.width)
+			if(isNumber(x)) {
+				box.left = x + ml - mr
+			} else {
+				box.left = (lbox && (limageOffset < pbox.width ? limageOffset : pbox.left) || pbox.left) + ml - mr
+			}
+			if(isNumber(w)) {
+				box.width = w // - pl - pr 
+			} else {
+				box.width = Math.round(isNumber(h) ? rWidth * h / rHeight : pbox?.width) // - pl - pr
+			}
+			if(isNumber(h)) {
+				box.height = h
+			} else {
+				const cH = Math.round(box.width * rHeight / rWidth )
+				box.height = Math.min(cH, pbox?.height)
+			}
+			if(isNumber(y)) {
+				box.top = y + mt
+			} else {
+				box.top = (lbox && (limageOffset < pbox.width ? limageOffset : (lbox.top + lbox.height)) || pbox.top) + mt + lmb
+			}
+		}
+		return box
+	}
+	async getAttributes(element) {
+		let arr = { }
+		if(element?.url || element?.src) {
+			arr.src = element.url || element?.src;
+			const {width = 0, height = 0, path: src, url} = await getImageInfo(arr.src, this.isH5PathToBase64) || {}
+			arr = Object.assign({}, arr, {width, height, src, url})
+		}
+		if(element?.text) {
+			arr.text = element.text
+		}
+		return arr
+	}
+	async calcNode(element) {
+		const node = element || this.element
+		return await this.getNodeTree(node)
+	}
+}

+ 1 - 0
components/lime-painter/qrcode.js

xqd
@@ -0,0 +1 @@
+// 请去下载覆盖:https://gitee.com/liangei/lime-painter/blob/master/qrcode.js

+ 437 - 0
components/lime-painter/utils.js

xqd
@@ -0,0 +1,437 @@
+const screen = uni.getSystemInfoSync().windowWidth / 750;
+// 缓存图片
+let cache = {}
+export function isNumber(value) {
+	return /^-?\d+(\.\d+)?$/.test(value);
+}
+export function toPx(value, baseSize) {
+	// 如果是数字
+	if (typeof value === 'number') {
+		return value
+	}
+	// 如果是字符串数字
+	if (isNumber(value)) {
+		return value * 1
+	}
+	// 如果有单位
+	if (typeof value === 'string') {
+		const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g
+		const results = reg.exec(value);
+		if (!value || !results) {
+			return 0;
+		}
+		const unit = results[3];
+		value = parseFloat(value);
+		let res = 0;
+		if (unit === 'rpx') {
+			res = Math.floor(value * (screen || 0.5) * 1);
+		} else if (unit === 'px') {
+			res = Math.floor(value * 1);
+		} else if (unit === '%') {
+			res = Math.floor(value * toPx(baseSize) / 100);
+		} else if (unit === 'em') {
+			res = Math.ceil(value * toPx(baseSize || 14));
+		}
+		return res;
+	}
+}
+
+// 计算版本
+export function compareVersion(v1, v2) {
+  v1 = v1.split('.')
+  v2 = v2.split('.')
+  const len = Math.max(v1.length, v2.length)
+  while (v1.length < len) {
+    v1.push('0')
+  }
+  while (v2.length < len) {
+    v2.push('0')
+  }
+  for (let i = 0; i < len; i++) {
+    const num1 = parseInt(v1[i], 10)
+    const num2 = parseInt(v2[i], 10)
+
+    if (num1 > num2) {
+      return 1
+    } else if (num1 < num2) {
+      return -1
+    }
+  }
+  return 0
+}
+
+/** 从 0x20 开始到 0x80 的字符宽度数据 */
+export const CHAR_WIDTH_SCALE_MAP = [0.296, 0.313, 0.436, 0.638, 0.586, 0.89, 0.87, 0.256, 0.334, 0.334, 0.455, 0.742,
+	0.241, 0.433, 0.241, 0.427, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.586, 0.241, 0.241, 0.742,
+	0.742, 0.742, 0.483, 1.031, 0.704, 0.627, 0.669, 0.762, 0.55, 0.531, 0.744, 0.773, 0.294, 0.396, 0.635, 0.513, 0.977,
+	0.813, 0.815, 0.612, 0.815, 0.653, 0.577, 0.573, 0.747, 0.676, 1.018, 0.645, 0.604, 0.62, 0.334, 0.416, 0.334, 0.742,
+	0.448, 0.295, 0.553, 0.639, 0.501, 0.64, 0.567, 0.347, 0.64, 0.616, 0.266, 0.267, 0.544, 0.266, 0.937, 0.616, 0.636,
+	0.639, 0.64, 0.382, 0.463, 0.373, 0.616, 0.525, 0.79, 0.507, 0.529, 0.492, 0.334, 0.269, 0.334, 0.742, 0.296
+];
+// #ifdef MP
+const prefix = () => {
+	// #ifdef MP-TOUTIAO
+	return tt
+	// #endif
+	// #ifdef MP-WEIXIN
+	return wx
+	// #endif
+	// #ifdef MP-BAIDU
+	return swan
+	// #endif
+	// #ifdef MP-ALIPAY
+	return my
+	// #endif
+	// #ifdef MP-QQ
+	return qq
+	// #endif
+	// #ifdef MP-360
+	return qh
+	// #endif
+}
+
+const base64ToArrayBuffer = (data) => {
+	/**
+	 * base64ToArrayBuffer
+	 * Base64Binary.decode(base64_string);  
+	 * Base64Binary.decodeArrayBuffer(base64_string); 
+	 */
+	const Base64Binary = {
+	  _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
+	  
+	  /* will return a  Uint8Array type */
+	  decodeArrayBuffer(input) {
+	    const bytes = (input.length/4) * 3;
+	    const ab = new ArrayBuffer(bytes);
+	    this.decode(input, ab);
+	    return ab;
+	  },
+	 
+	  removePaddingChars(input) {
+	    const lkey = this._keyStr.indexOf(input.charAt(input.length - 1));
+	    if(lkey == 64){
+	      return input.substring(0,input.length - 1);
+	    }
+	    return input;
+	  },
+	 
+	  decode(input, arrayBuffer) {
+	    //get last chars to see if are valid
+	    input = this.removePaddingChars(input);
+	    input = this.removePaddingChars(input);
+	 
+	    const bytes = parseInt((input.length / 4) * 3, 10);
+	    
+	    let uarray;
+	    let chr1, chr2, chr3;
+	    let enc1, enc2, enc3, enc4;
+	    let i = 0;
+	    let j = 0;
+	    
+	    if (arrayBuffer)
+	      uarray = new Uint8Array(arrayBuffer);
+	    else
+	      uarray = new Uint8Array(bytes);
+	    
+	    input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
+	    
+	    for (i=0; i<bytes; i+=3) {  
+	      //get the 3 octects in 4 ascii chars
+	      enc1 = this._keyStr.indexOf(input.charAt(j++));
+	      enc2 = this._keyStr.indexOf(input.charAt(j++));
+	      enc3 = this._keyStr.indexOf(input.charAt(j++));
+	      enc4 = this._keyStr.indexOf(input.charAt(j++));
+	  
+	      chr1 = (enc1 << 2) | (enc2 >> 4);
+	      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
+	      chr3 = ((enc3 & 3) << 6) | enc4;
+	  
+	      uarray[i] = chr1;      
+	      if (enc3 != 64) uarray[i+1] = chr2;
+	      if (enc4 != 64) uarray[i+2] = chr3;
+	    }
+	    return uarray;  
+	  }
+	 }
+	return (uni.base64ToArrayBuffer && uni.base64ToArrayBuffer(data)) || Base64Binary.decodeArrayBuffer(data)
+}
+// #endif
+
+/**
+ * base64转路径
+ * @param {Object} base64
+ */
+export function base64ToPath(base64) {
+	const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
+	
+	return new Promise((resolve, reject) => {
+		// #ifdef MP
+		const fs = uni.getFileSystemManager()
+		
+		//自定义文件名
+		if (!format) {
+			console.error('ERROR_BASE64SRC_PARSE')
+			reject(new Error('ERROR_BASE64SRC_PARSE'))
+		}
+		const time = new Date().getTime();
+		let pre = prefix()
+		const filePath = `${pre.env.USER_DATA_PATH}/${time}.${format}`
+		let buffer = base64ToArrayBuffer(bodyData)
+		fs.writeFile({
+			filePath,
+			data: buffer,
+			encoding: 'binary',
+			success() {
+				resolve(filePath)
+			},
+			fail(err) {
+				console.error('获取base64图片失败', JSON.stringify(err))
+				reject(err)
+			}
+		})
+		// #endif
+		
+		// #ifdef H5
+		// mime类型
+		let mimeString = base64.split(',')[0].split(':')[1].split(';')[0]; 
+		//base64 解码
+		let byteString = atob(base64.split(',')[1]); 
+		//创建缓冲数组
+		let arrayBuffer = new ArrayBuffer(byteString.length);
+		//创建视图
+		let intArray = new Uint8Array(arrayBuffer); 
+		for (let i = 0; i < byteString.length; i++) {
+			intArray[i] = byteString.charCodeAt(i);
+		}
+		resolve(URL.createObjectURL(new Blob([intArray], { type: mimeString })))
+		// #endif
+		
+		// #ifdef APP-PLUS
+		const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
+		bitmap.loadBase64Data(base64, () => {
+			if (!format) {
+				console.error('ERROR_BASE64SRC_PARSE')
+				reject(new Error('ERROR_BASE64SRC_PARSE'))
+			}
+			const time = new Date().getTime();
+			const filePath = `_doc/uniapp_temp/${time}.${format}`
+			
+			bitmap.save(filePath, {}, 
+				() => {
+					bitmap.clear()
+					resolve(filePath)
+				}, 
+				(error) => {
+					bitmap.clear()
+					console.error(`${JSON.stringify(error)}`)
+					reject(error)
+				})
+		}, (error) => {
+			bitmap.clear()
+			console.error(`${JSON.stringify(error)}`)
+			reject(error)
+		})
+		// #endif
+	})
+}
+
+/**
+ * 路径转base64
+ * @param {Object} string
+ */
+
+export function pathToBase64(path) {
+	return new Promise((resolve, reject) => {
+		// #ifdef H5
+		const _canvas = ()=> {
+			let image = new Image();
+			image.onload = function() {
+				let canvas = document.createElement('canvas');
+				// 获取图片原始宽高
+				canvas.width = this.naturalWidth;
+				canvas.height = this.naturalHeight;
+				// 将图片插入画布并开始绘制
+				canvas.getContext('2d').drawImage(image, 0, 0);
+				let result = canvas.toDataURL('image/png')
+				resolve(result);
+				canvas.height = canvas.width = 0
+			}
+			image.src = path
+			image.setAttribute("crossOrigin",'Anonymous');
+			image.src = path;
+			image.onerror = (error) => {
+				console.error(`urlToBase64 error: ${path}`, JSON.stringify(error))
+			    reject(new Error('urlToBase64 error'));
+			};
+		}
+		const _fileReader = (blob) => {
+			const fileReader = new FileReader();
+			fileReader.onload = (e) => {
+			    resolve(e.target.result);
+			};
+			fileReader.readAsDataURL(blob);
+			fileReader.onerror = (error) => {
+				console.error('blobToBase64 error:', JSON.stringify(error))
+			    reject(new Error('blobToBase64 error'));
+			};
+		}
+		const isFileReader = typeof FileReader === 'function'
+		if(/^(http|\/\/)/.test(path) && isFileReader ) {
+			window.URL = window.URL || window.webkitURL;
+			const xhr = new XMLHttpRequest();
+			xhr.open("get", path, true);
+			xhr.timeout = 2000;
+			xhr.responseType = "blob";
+			xhr.onload = function() {
+				if(this.status == 200) {
+					_fileReader(this.response)
+				} else {
+					_canvas()
+				}
+			}
+			xhr.onreadystatechange = function() {
+				if(this.status === 0) {
+					console.error('图片跨域了,得后端处理咯')
+				}
+			}
+			xhr.send();
+		} else if(/^blob/.test(path) && isFileReader){
+			_fileReader(path)
+		} else {
+			_canvas()
+		}
+		// #endif
+		
+		// #ifdef MP
+		if(uni.canIUse('getFileSystemManager')) {
+			uni.getFileSystemManager().readFile({
+			    filePath: path,
+			    encoding: 'base64',
+			    success: (res) => {
+			        resolve('data:image/png;base64,' + res.data)
+			    },
+			    fail: (error) => {
+					console.error('urlToBase64 error:', JSON.stringify(error))
+			        reject(error)
+			    }
+			})
+		}
+		// #endif
+		
+		// #ifdef APP-PLUS
+		plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), (entry) => {
+		    entry.file((file) => {
+		        const fileReader = new plus.io.FileReader()
+		        fileReader.onload = (data) => {
+		            resolve(data.target.result)
+		        }
+		        fileReader.onerror = (error) => {
+					console.error('pathToBase64 error:', JSON.stringify(error))
+		            reject(error)
+		        }
+		        fileReader.readAsDataURL(file)
+		    }, (error) => {
+				console.error('pathToBase64 error:', JSON.stringify(error))
+		        reject(error)
+		    })
+		}, (error) => {
+			console.error('pathToBase64 error:', JSON.stringify(error))
+		    reject(error)
+		})
+		// #endif
+	})
+}
+
+// #ifdef APP-PLUS
+const getLocalFilePath = (path)=> {
+    if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
+        return path
+    }
+    if (path.indexOf('file://') === 0) {
+        return path
+    }
+    if (path.indexOf('/storage/emulated/0/') === 0) {
+        return path
+    }
+    if (path.indexOf('/') === 0) {
+        const localFilePath = plus.io.convertAbsoluteFileSystem(path)
+        if (localFilePath !== path) {
+            return localFilePath
+        } else {
+            path = path.substr(1)
+        }
+    }
+    return '_www/' + path
+}
+// #endif
+
+export function getImageInfo(img, isH5PathToBase64) {
+	return new Promise(async (resolve, reject) => {
+		const base64Reg = /^data:image\/(\w+);base64/
+		const localReg = /^\.|^\/(?=[^\/])/;
+		const networkReg = /^(http|\/\/)/
+		// #ifdef H5
+		if(networkReg.test(img) && isH5PathToBase64) {
+			img = await pathToBase64(img)
+		}
+		// #endif
+		// #ifndef MP-ALIPAY 
+		if(base64Reg.test(img)) {
+			if(!cache[img]) {
+				const imgName = img
+				img = await base64ToPath(img)
+				cache[imgName] = img
+			} else {
+				img = cache[img]
+			}
+		}
+		// #endif
+		if(cache[img] && cache[img].errMsg) {
+			resolve(cache[img])
+		} else {
+			uni.getImageInfo({
+				src: img,
+				success: (image) => {
+					// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
+					image.path = localReg.test(img) ?  `/${image.path}` : image.path;
+					// #endif
+					// image.path = /^(http|\/\/|\/|wxfile|data:image\/(\w+);base64|file|bdfile|ttfile|blob)/.test(image.path) ? image.path : `/${image.path}`;
+					image.url = img
+					cache[img] = image
+					resolve(cache[img])
+				},
+				fail(err) {
+					resolve({path: img})
+					console.error(`getImageInfo:fail ${img} failed ${JSON.stringify(err)}`);
+				}
+			})
+		}
+	})
+}
+	
+	
+	
+export class DataUtil {
+  /**
+   * 设置差异数据
+   * @param component
+   * @param data
+   */
+  setDiffData(component, data) {
+	const diffData = {};
+
+	// 遍历获取到有差异的数据
+	Object.keys(data).forEach(key => {
+	  if (component[key] !== data[key]) {
+		diffData[key] = data[key];
+	  }
+	});
+
+	// 设置数据
+	if (Object.keys(diffData).length) {
+	  // component.setData(diffData);
+	}
+  }
+}
+// const dataUtil = new DataUtil;
+// export dataUtil;

+ 116 - 0
components/my-nav/my-nav.vue

xqd
@@ -0,0 +1,116 @@
+<template>
+	<view>
+		<view class="nav-box" :style="{'height':height+'px','background':bgColor}">
+			<!-- 自定义导航栏 -->
+			<view class="status_bar" :style="{'height':statusBarHeight+'px'}">
+				<!-- uni-ui这里是状态栏 -->
+			</view>
+			<!-- 胶囊位置信息 -->
+			<view class="nav-main flex align-center justify-center" :style="{height: navBarHeight+'px'}">
+				<view class="nav-main-back" @click="back" v-if="backIcon">
+					<uni-icons type="back" size="26" color="#fff"></uni-icons>
+				</view>
+				<text class="nav-main-title">{{title}}</text>
+			</view>
+		</view>
+		<view :style="{'height':height+'px','background':bgColor}" style="background-color: #fff;">
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props: {
+			bgColor: {
+				type: String,
+				default: "#FFF"
+			},
+			backIcon: {
+				type: Boolean,
+				default: true
+			},
+			title: {
+				type: String,
+				default: ""
+			}
+		},
+		data() {
+			return {
+				//总高度
+				height: 0,
+				//胶囊位置信息
+				menuButtonRect: {},
+				//状态栏的高度
+				statusBarHeight: 0,
+				//导航栏的高度
+				navBarHeight: 0
+			}
+		},
+		created() {
+			// this.height = wx.getStorageSync('navBarHeight')
+			this.getHeight();
+		},
+		methods: {
+			//获取屏幕导航栏高度
+			getHeight() {
+				if (wx.canIUse('getMenuButtonBoundingClientRect')) {
+					let sysInfo = wx.getSystemInfoSync(); //状态栏的高度
+					this.statusBarHeight = sysInfo.statusBarHeight;
+					// 胶囊位置信息
+					let rect = wx.getMenuButtonBoundingClientRect();
+					this.menuButtonRect = JSON.parse(JSON.stringify(rect));
+					// 导航栏高度
+					let navBarHeight = (rect.top - sysInfo.statusBarHeight) * 2 + rect.height;
+					this.navBarHeight = navBarHeight;
+					// 自定义导航栏的高度
+					this.height = sysInfo.statusBarHeight + navBarHeight;
+				} else {
+					wx.showToast({
+						title: '您的微信版本过低,界面可能会显示不正常',
+						icon: 'none',
+						duration: 4000
+					});
+				}
+			},
+			//返回
+			back() {
+				uni.navigateBack({
+					delta: 1
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.nav-box{
+		width: 100%;
+		background-color: #fff;
+		position: fixed;
+		top: 0;
+		z-index: 9999;
+		overflow: hidden;
+	}
+	.status_bar {
+		// height: var(--status-bar-height);
+		width: 100%;
+		// background:#ff0;
+	}
+
+	.nav-main {
+		position: relative;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		// background:#f00;
+		.nav-main-back {
+			position: absolute;
+			left: 10rpx;
+		}
+
+		.nav-main-title {
+			color: #333;
+			font-size: 16px;
+		}
+	}
+</style>

+ 114 - 0
components/q-turntable/q-turntable.vue

xqd
@@ -0,0 +1,114 @@
+<template>
+	<view>
+		<view class="turntable_wp sol-class">
+			<image
+				src="http://t9.9026.com/imgs/banner03.png"
+				:style="'-webkit-transform:rotate(' + deg + 'deg) translateZ(0);transform:rotate(' + deg + 'deg) translateZ(0)'"
+			></image>
+			<view class="turntable_pointer" @tap="start"><image src="http://t9.9026.com/imgs/banner04.png"></image></view>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			deg: 0,
+			singleAngle: '',
+			// 每片扇形的角度
+			isStart: false
+		};
+	},
+
+	components: {},
+	props: {
+		// 划分区域
+		areaNumber: {
+			type: Number,
+			default: 6
+		},
+		// 速度
+		speed: {
+			type: Number,
+			default: 16
+		}
+	},
+
+	beforeMount() {
+		this.init();
+	},
+
+	methods: {
+		init() {
+			let { areaNumber } = this;
+			const singleAngle = 360 / areaNumber;
+			this.singleAngle = singleAngle;
+		},
+
+		// 点击开始抽奖
+		start() {
+			this.$emit('start');
+		},
+
+		begin(awardNumer) {
+			var deg = this.deg;
+			var singleAngle = this.singleAngle;
+			var speed = this.speed;
+			var isStart = this.isStart;
+			if (isStart) return;
+			this.isStart = true;
+			let endAddAngle = 0;
+			endAddAngle = 360 - ((awardNumer - 1) * singleAngle + singleAngle / 2); // 中奖角度
+			
+
+			const rangeAngle = (Math.floor(Math.random() * 4) + 4) * 360; // 随机旋转几圈再停止
+
+			console.log(endAddAngle);
+			let cAngle;
+			deg = 0;
+			this.timer = setInterval(() => {
+				if (deg < rangeAngle) {
+					deg += speed;
+				} else {
+					cAngle = (endAddAngle + rangeAngle - deg) / speed;
+					cAngle = cAngle > speed ? speed : cAngle < 1 ? 1 : cAngle;
+					deg += cAngle;
+
+					if (deg >= endAddAngle + rangeAngle) {
+						deg = endAddAngle + rangeAngle;
+						this.isStart = false;
+						clearInterval(this.timer);
+						this.$emit('success');
+					}
+				}
+
+				this.deg = deg;
+			}, 1000 / 60);
+		}
+	}
+};
+</script>
+<style>
+
+.turntable_wp {
+	width: 538rpx;
+	height: 548rpx;
+	position: relative;
+	margin: 0 auto;
+}
+.turntable_wp image {
+	display: block;
+	width: 100%;
+	height: 100%;
+}
+.turntable_wp .turntable_pointer {
+	position: absolute;
+	width: 132rpx;
+	height: 150rpx;
+	top: 50%;
+	left: 50%;
+	margin: -93rpx 0 0 -70rpx;
+}
+
+</style>

+ 142 - 0
components/waterfall/waterfall-item.vue

xqd
@@ -0,0 +1,142 @@
+<template>
+	<view class="waterfall-item-container">
+		
+		<!-- <view class="waterfall-item" @tap="onTap">
+			<image :src="params.url" mode="widthFix" @load="emitHeight" @error="emitHeight"></image>
+			<view class="content">
+				<view>{{params.title}}</view>
+				<view class="money">{{params.money}}元</view>
+				<view style="margin: 0 0 8rpx 0;">
+					<text class="label">{{params.label}}</text>
+				</view>
+				<view class="shop-name">{{params.shop}}</view>
+			</view>
+		</view> -->
+		
+		<view class="waterfall-item-container" >
+			<view class="contentItem" @tap="onTap(params.money)">
+				<image  :src="params.url" mode="widthFix" @load="emitHeight" @error="emitHeight"></image>
+				<view class="itemName">{{params.label}}</view>
+				<view class="itemPrice">{{params.money}}积分</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name:"helangWaterfallItem",
+		options:{
+			virtualHost: true
+		},
+		props:{
+			params:{
+				type: Object,
+				default(){
+					return {}
+				}
+			},
+			tag:{
+				type:String | Number,
+				default:''
+			},
+			index:{
+				type:Number,
+				default:-1
+			}
+		},
+		data() {
+			return {
+				
+			};
+		},
+		methods:{
+			// 发出组件高度信息,在此处可以区分正确和错误的加载,给予错误的提示图片
+			emitHeight(e){
+				const query = uni.createSelectorQuery().in(this);
+				query.select('.waterfall-item-container').boundingClientRect(data => {
+					let height = Math.floor(data.height);
+					this.$emit("height",height,this.$props.tag);
+				}).exec();
+			},
+			onTap(id){
+				this.$emit("click",this.$props.index,this.$props.tag);
+				console.log(id)
+				uni.navigateTo({
+					url:'/pages/my/integral/integralOrder'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+// .waterfall-item{
+// 	padding: 16rpx;
+// 	background-color: #fff;
+// 	border-radius: 4px;
+// 	font-size: 28rpx;
+// 	color: #666;
+	
+// 	image{
+// 		display: block;
+// 		width: 100%;
+// 		// 默认设置一个图片的大约值
+// 		height: 350rpx;
+// 	}
+	
+// 	.content{
+// 		margin-top: 16rpx;
+		
+// 		.money{
+// 			color: #fa3534;
+// 			margin-top: 8rpx;
+// 		}
+		
+// 		.label{
+// 			background-color: #fa3534;
+// 			color: #fff;
+// 			font-size: 20rpx;
+// 			padding: 4rpx 16rpx;
+// 			border-radius: 20rpx;
+// 		}
+		
+// 		.shop-name{
+// 			font-size: 20rpx;
+// 			color: #999;
+// 		}
+// 	}
+// }
+.waterfall-item-container{
+			display: flex;
+			flex-wrap: wrap;
+			box-sizing: border-box;
+			.contentItem{
+				width: 332rpx;
+				// height: 100%;
+				background: #FFFFFF;
+				box-sizing: border-box;
+				box-shadow: 0px 4rpx 8rpx 0px rgba(0,0,0,0.04);
+				border-radius: 12rpx;
+				image{
+					width: 100%;
+					height: 100%;
+				}
+				.itemName{
+					margin:0 18rpx 10rpx 22rpx ;
+					font-size: 28rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: bold;
+					color: #333333;
+				}
+				.itemPrice{
+					margin-left: 22rpx;
+					font-size: 28rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: bold;
+					color: #FF6200;
+				}
+			}
+			
+		}
+</style>

+ 239 - 0
components/waterfall/waterfall-list.vue

xqd
@@ -0,0 +1,239 @@
+<template>
+	<view>
+		<view class="waterfall-box h-flex-x h-flex-2" v-if="showList">
+			<view>
+				<view v-for="(item,index) in leftList" :key="item._render_id" 
+					class="list-item" 
+					:class="{'show': showPage > item._current_page }"
+				>
+					<helang-waterfall-item
+						:params="item" 
+						tag="left"
+						:index="index"
+						@height="onHeight"
+						@click="onClick"
+					></helang-waterfall-item>
+				</view>
+			</view>
+			<view>
+				<view v-for="(item,index) in rightList" :key="item._render_id" 
+					class="list-item"
+					:class="{'show': showPage > item._current_page }"
+				>
+					<helang-waterfall-item
+						:params="item" 
+						@height="onHeight"
+						@click="onClick"
+						tag="right"
+						:index="index"
+					></helang-waterfall-item>
+				</view>
+			</view>
+		</view>
+		
+		<slot name="default"></slot>
+	</view>
+</template>
+
+<script>
+	import helangWaterfallItem from "./waterfall-item.vue"
+		
+	export default {
+		name:"helangWaterfallList",
+		options:{
+			virtualHost: true
+		},
+		components: {
+			"helang-waterfall-item": helangWaterfallItem
+		},
+		props:{
+			// 组件状态
+			status:{
+				type: String,
+				default:''
+			},
+			// 待渲染的数据
+			list:{
+				type: Array,
+				default(){
+					return [];
+				}
+			},
+			// 重置列表,设置为 true 时,瀑布流会自动重新渲染列表
+			reset:{
+				type: Boolean,
+				default:false
+			},
+		},
+		watch:{
+			"$props.status"(newValue,oldValue){
+				// 状态变更为 加载成功 时,执行瀑布流数据渲染	
+				if(newValue == 'success'){
+					this.startRender();
+				}else if(!this.showList){
+					this.resetData();
+				}
+			}
+		},
+		computed:{
+			showList(){
+				return !["fail","empty"].includes(this.$props.status);
+			}
+		},
+		data() {
+			return {
+				// 左侧列表高度
+				leftHeight: 0,
+				// 右侧列表高度
+				rightHeight: 0,
+				// 左侧列表数据
+				leftList: [],
+				// 右侧列表数据
+				rightList: [],
+				// 待渲染列表
+				awaitRenderList:[],
+				// 当前展示页码数据
+				showPage:1
+			}
+		},
+		mounted() {
+			if(this.$props.status == 'success'){
+				this.startRender();
+			}
+		},
+		methods: {
+			// 监听高度变化
+			onHeight(height, tag) {
+				/**
+				 * 这个为实际渲染后 CSS 中 margin-buttom 的值,本示例默认为20rpx
+				 * 用于解决实际渲染后因为数据条数关系,高度差计算偏差的问题
+				 * */
+				let marginBottom = uni.upx2px(10);
+				
+				// console.log(`左高:${this.leftHeight},右高:${this.rightHeight},当前高:${height},插入方向:${tag}`)
+				
+				if (tag == 'left') {
+					this.leftHeight += (height + marginBottom);
+				} else {
+					this.rightHeight += (height + marginBottom);
+				}
+				this.renderList();
+			},
+			// 组件点击事件
+			onClick(index, tag){
+				// 对应的数据
+				if(tag == 'left'){
+					this.$emit("click",this.leftList[index],index,tag);
+				}else{
+					this.$emit("click",this.rightList[index],index,tag);
+				}
+			},
+			// 渲染列表,这里实现瀑布流的左右分栏
+			renderList() {
+				// 待渲染长度为 0 时表示已渲染完成
+				if(this.awaitRenderList.length < 1){
+					this.showPage++;
+					this.$emit("done");
+					
+					// 为防止 js 数值类型最大值溢出,当高度值大于 1亿时重置高度
+					if(this.leftHeight > 100000000){
+						if(this.leftHeight > this.rightHeight){
+							this.leftHeight = 2;
+							this.rightHeight = 1;
+						}else{
+							this.leftHeight = 1;
+							this.rightHeight = 2;
+						}
+					}
+					return;
+				}
+				let item = {
+					...this.awaitRenderList.splice(0,1)[0],
+					// 当前数据添加当前页面标识
+					_current_page:this.showPage,
+					// 当前数据添加一个渲染id,解决 v-for 重复会出现不执行 load 的 BUG
+					_render_id:new Date().getTime()
+				};
+				
+				if(this.leftHeight > this.rightHeight){
+					this.rightList.push(item);
+				}else{
+					this.leftList.push(item);
+				}
+			},
+			// 重置数据
+			resetData(){
+				this.leftHeight = 0;
+				this.rightHeight = 0;
+				this.leftList = [];
+				this.rightList = [];
+				this.awaitRenderList = [];
+				// 当前展示页码数据
+				this.showPage = 1;
+			},
+			// 启动渲染
+			startRender(){
+				if(!this.showList){
+					this.resetData();
+					return;
+				}
+				
+				if(!this.$props.list || this.$props.list.length < 1){
+					console.log('河浪瀑布流插件提示:当前数据为空,不会触发列表渲染');
+					return;
+				}
+				
+				// 若本次渲染为 重置 则先恢复组件的默认参数
+				if(this.$props.reset){
+					this.resetData();
+				}
+				
+				this.awaitRenderList = [...this.$props.list];
+				this.renderList();
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.waterfall-box {
+		padding: 20rpx 10rpx;
+		box-sizing: border-box;
+
+		>view {
+			padding: 0 10rpx;
+		}
+		
+		.list-item{
+			margin-bottom: 0;
+			// 设置透明,默认是可视的
+			opacity: 0;
+			box-shadow: 0px 4rpx 8rpx 0px rgba(0,0,0,0.04);
+			// 默认超出隐藏,不影响加载中的文字显示效果
+			overflow: hidden;
+			height: 0;
+			
+			&.show{
+				margin-bottom: 20rpx;
+				opacity: 1;
+				// overflow: auto;
+				height: auto;
+			}
+		}
+	}
+
+	.h-flex-x {
+		display: flex;
+		flex-direction: row;
+		flex-wrap: nowrap;
+		justify-content: flex-start;
+		align-items: flex-start;
+		align-content: flex-start;
+
+		&.h-flex-2 {
+			>view {
+				width: 50%;
+			}
+		}
+	}
+</style>

+ 20 - 0
index.html

xqd
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <script>
+      var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
+        CSS.supports('top: constant(a)'))
+      document.write(
+        '<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
+        (coverSupport ? ', viewport-fit=cover' : '') + '" />')
+    </script>
+    <title></title>
+    <!--preload-links-->
+    <!--app-context-->
+  </head>
+  <body>
+    <div id="app"><!--app-html--></div>
+    <script type="module" src="/main.js"></script>
+  </body>
+</html>

+ 33 - 0
main.js

xqd
@@ -0,0 +1,33 @@
+import App from './App'
+
+// #ifndef VUE3
+import Vue from 'vue'
+import uView from "uview-ui";
+// vuex store
+import store from './store'
+import mixin from './utils/mixin'
+let mpShare = require('uview-ui/libs/mixin/mpShare.js');
+Vue.mixin(mpShare)
+// Vue.prototype.$store = store
+Vue.use(uView);
+Vue.mixin(mixin)
+
+Vue.config.productionTip = false
+App.mpType = 'app'
+const app = new Vue({
+	store,
+    ...App
+})
+require('utils/request/index')(app)
+app.$mount()
+// #endif
+
+// #ifdef VUE3
+import { createSSRApp } from 'vue'
+export function createApp() {
+  const app = createSSRApp(App)
+  return {
+    app
+  }
+}
+// #endif

+ 86 - 0
manifest.json

xqd
@@ -0,0 +1,86 @@
+{
+    "name" : "hotel_uni",
+    "appid" : "__UNI__89DEB06",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueStyleCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {},
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {
+                "maps" : {
+                    "amap" : {
+                        "appkey_ios" : "",
+                        "appkey_android" : ""
+                    }
+                }
+            }
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "wx0f8eba0a55baa7fc",
+        "setting" : {
+            "urlCheck" : false,
+            "minified" : true
+        },
+        "usingComponents" : true,
+        "permission" : {
+            "scope.userLocation" : {
+                "desc" : "获取位置,推荐精彩信息"
+            }
+        },
+        "requiredPrivateInfos" : [ "getLocation", "chooseLocation" ]
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    },
+    "vueVersion" : "2"
+}

+ 31 - 0
package-lock.json

xqd
@@ -0,0 +1,31 @@
+{
+  "name": "hotel_uni",
+  "version": "1.0.0",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "hotel_uni",
+      "version": "1.0.0",
+      "license": "ISC",
+      "dependencies": {
+        "uview-ui": "^2.0.31"
+      }
+    },
+    "node_modules/uview-ui": {
+      "version": "2.0.31",
+      "resolved": "https://registry.npmmirror.com/uview-ui/-/uview-ui-2.0.31.tgz",
+      "integrity": "sha512-I/0fGuvtiKHH/mBb864SGYk+SJ7WaF32tsBgYgeBOsxlUp+Th+Ac2tgz2cTvsQJl6eZYWsKZ3ixiSXCAcxZ8Sw==",
+      "engines": {
+        "HBuilderX": "^3.1.0"
+      }
+    }
+  },
+  "dependencies": {
+    "uview-ui": {
+      "version": "2.0.31",
+      "resolved": "https://registry.npmmirror.com/uview-ui/-/uview-ui-2.0.31.tgz",
+      "integrity": "sha512-I/0fGuvtiKHH/mBb864SGYk+SJ7WaF32tsBgYgeBOsxlUp+Th+Ac2tgz2cTvsQJl6eZYWsKZ3ixiSXCAcxZ8Sw=="
+    }
+  }
+}

+ 15 - 0
package.json

xqd
@@ -0,0 +1,15 @@
+{
+  "name": "hotel_uni",
+  "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.31"
+  }
+}

+ 330 - 0
pages.json

xqd
@@ -0,0 +1,330 @@
+{
+	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+
+
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTitleText": "首页",
+				"enablePullDownRefresh": true,
+				"navigationStyle": "custom" // 隐藏系统导航栏
+			}
+		},
+		{
+			"path": "pages/index/active-list/index",
+			"style": {
+				"navigationBarTitleText": "活动列表",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/index/active-detail/index",
+			"style": {
+				"navigationBarTitleText": "IHG最受欢迎酒店",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom" // 隐藏系统导航栏
+			}
+
+		},
+		{
+			"path": "pages/index/vote-detail/index",
+			"style": {
+				"navigationBarTitleText": "投票详情",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/goods/goods",
+			"style": {
+				"navigationBarTitleText": "产品活动列表",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/goods/goods-detail/index",
+			"style": {
+				"navigationBarTitleText": "产品详情",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/goods/goods-hotel/index",
+			"style": {
+				"navigationBarTitleText": "酒店列表",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/goods/goods-lucky/index",
+			"style": {
+				"navigationBarTitleText": "大转盘抽奖活动专区",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/map/map",
+			"style": {
+				"navigationBarTitleText": "IHG地图",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom" // 隐藏系统导航栏
+			}
+
+		},
+		{
+			"path": "pages/map/hotel-book/index",
+			"style": {
+				"navigationBarTitleText": "IHG | 洲际酒店集团中国西区",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom" // 隐藏系统导航栏
+			}
+
+		},
+		{
+			"path": "pages/msg/msg",
+			"style": {
+				"navigationBarTitleText": "消息",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom" // 隐藏系统导航栏
+			}
+
+		},
+		{
+
+			"path": "pages/my/my",
+			"style": {
+				"navigationBarTitleText": "我的",
+				"enablePullDownRefresh": false,
+				"navigationStyle": "custom" // 隐藏系统导航栏
+			}
+
+		},
+
+		{
+			"path": "pages/webview/webview",
+			"style": {
+				"navigationBarTitleText": "webview",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/login/login",
+			"style": {
+				"navigationBarTitleText": "登录账号",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/login/youyue",
+			"style": {
+				"navigationBarTitleText": "登录账号",
+				"enablePullDownRefresh": false
+			}
+
+		},
+
+		{
+			"path": "pages/my/PersonalData/personalData",
+			"style": {
+				"navigationBarTitleText": "个人信息",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/setting/setting",
+			"style": {
+				"navigationBarTitleText": "系统设置",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/myorders/orders",
+			"style": {
+				"navigationBarTitleText": "我的订单",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/myorders/orderDetail",
+			"style": {
+				"navigationBarTitleText": "订单详情",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/protocol/PrivacyPolicy",
+			"style": {
+				"navigationBarTitleText": "隐私协议",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/protocol/UserAgreement",
+			"style": {
+				"navigationBarTitleText": "用户协议",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/verification/verification",
+			"style": {
+				"navigationBarTitleText": "核销中心",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/verification/orderVerification",
+			"style": {
+				"navigationBarTitleText": "订单核销",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/verification/verificationDetail",
+			"style": {
+				"navigationBarTitleText": "核销详情",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/integral/integral",
+			"style": {
+				"navigationBarTitleText": "积分",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/integral/integralRule",
+			"style": {
+				"navigationBarTitleText": "积分规则",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/integral/integralRecord",
+			"style": {
+				"navigationBarTitleText": "积分记录",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/integral/integralOrder",
+			"style": {
+				"navigationBarTitleText": "积分兑换",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/integral/integralExchange",
+			"style": {
+				"navigationBarTitleText": "兑换详情",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/prize/prize",
+			"style": {
+				"navigationBarTitleText": "奖品",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/prize/exchangePrize",
+			"style": {
+				"navigationBarTitleText": "奖品兑换",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/prize/exchangeDetail",
+			"style": {
+				"navigationBarTitleText": "兑换详情",
+				"enablePullDownRefresh": false
+			}
+
+		},
+		{
+			"path": "pages/my/Kudos/Kudos",
+			"style": {
+				"navigationBarTitleText": "点赞",
+				"enablePullDownRefresh": false
+			}
+
+		}
+	],
+
+	"globalStyle": {
+		"navigationBarTextStyle": "black", // black or white
+		"navigationBarTitleText": "",
+		"navigationBarBackgroundColor": "#FFF",
+		"navigationStyle": "default"
+	},
+	"easycom": {
+		"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue",
+		"layout": "@/layout/index.vue"
+	},
+	"tabBar": {
+		"custom": true,
+		"color": "#CBC8C7",
+		"selectedColor": "#FF6200",
+		"backgroundColor": "#fff",
+		"borderStyle": "black",
+		"display": "none",
+		"list": [{
+				"pagePath": "pages/index/index",
+				"iconPath": "static/icon/home02.png",
+				"selectedIconPath": "static/icon/home01.png",
+				"text": "首页"
+			},
+			{
+				"pagePath": "pages/map/map",
+				"iconPath": "static/icon/map02.png",
+				"selectedIconPath": "static/icon/map01.png",
+				"text": "IHG地图"
+			},
+			{
+				"pagePath": "pages/msg/msg",
+				"iconPath": "static/icon/msg02.png",
+				"selectedIconPath": "static/icon/msg01.png",
+				"text": "消息"
+			},
+			{
+				"pagePath": "pages/my/my",
+				"iconPath": "static/icon/my02.png",
+				"selectedIconPath": "static/icon/my01.png",
+				"text": "我的"
+			}
+		]
+	},
+	"condition": { //模式配置,仅开发期间生效
+		"current": 0, //当前激活的模式(list 的索引项)
+		"list": [{
+			"name": "", //模式名称
+			"path": "", //启动页面,必选
+			"query": "" //启动参数,在页面的onLoad函数里面得到
+		}]
+	}
+}

+ 825 - 0
pages/goods/goods-detail/index.vue

xqd
@@ -0,0 +1,825 @@
+<template>
+	<view class="goods-detail">
+		<!-- swiper -->
+		<view class="home-swiper">
+			<!-- <uni-swiper-dot :info="info" :current="current1" :mode="mode" :dots-styles="dotsStyles">
+				<swiper class="swiper-box" @change="change1" circular>
+					<swiper-item v-for="(item ,index) in info" :key="index">
+						<view class="swiper-item" >
+							<image style="width: 100%;height:576rpx;" :src="item.img" mode="aspectFill"></image>
+						</view>
+					</swiper-item>
+				</swiper>
+			</uni-swiper-dot> -->
+			<uni-swiper-dot :mode="mode" :info="info" :current="current1" :dots-styles="dotsStyles">
+				<swiper class="swiper-box" @change="change1" circular>
+					<swiper-item v-for="(item ,index) in info" :key="index"  v-if="resource_type == 1 ">
+						<view class="swiper-item">
+							<image style="width: 100%;height:576rpx;" :src="item.img" mode="aspectFill"></image>
+						</view>
+					</swiper-item>
+					<swiper-item  v-if="resource_type == 2 ">
+						<view class="swiper-item">
+							<video class="baner-video" id="myVideo" ref="myVideo" style="width: 100%; height: 564rpx;"
+								:src="video_url" controls :enable-progress-gesture="false">
+							</video>
+						</view>
+					</swiper-item>
+				</swiper>
+			</uni-swiper-dot>
+		</view>
+
+		<view style="background-color: #f9f9f9;">
+			<!-- 价格 -->
+			<view class="price">
+				<view class="price-top" v-if="produceType == 1">
+					<text>¥</text>
+					<text>{{productDetail.price}}</text>
+				</view>
+				<view class="price-top" v-if="produceType == 2">
+					<text>{{productDetail.integral}}</text>
+					<text>积分</text>
+				</view>	
+				<text class="price-text">{{productDetail.name}}</text>
+				<view @click="goOther" class="price-banner" :style="{backgroundImage:'url('+backImageUrl+')'}">
+					<text>加入IHG优悦会会员享受更多福利</text>
+					<image style="width: 12rpx;height: 20rpx;" src="/static/icon/right02.png" mode=""></image>
+				</view>
+				<!--规格-->
+				<view class="price-specs" @click="Recipientopen()">
+					<view class="price-specs-left">
+						<text>选择</text>
+					</view>
+					<view class="price-specs-main" @click="Recipientopen()">
+						<text>{{specsText||'请选择规格'}}</text>
+					</view>
+					<view @click="Recipientopen()">
+						<image style="width: 12rpx;height: 20rpx;" src="/static/icon/right03.png" mode=""></image>
+					</view>
+				</view>
+			</view>
+
+			<!--酒店信息  -->
+			<view class="about">
+				<text class="about-title">可购买酒店信息</text>
+				<text class="about-name">{{hotelDetail.name}}</text>
+				<view class="about-address">
+					<text style="margin-right:20rpx ;">地址:</text>
+					<text>{{hotelDetail.address}}</text>
+				</view>
+				<view class="about-phone">
+					<text style="margin-right:20rpx ;">电话:</text>
+					<text>{{hotelDetail.phone}}</text>
+				</view>
+				<view class="about-all">
+					<text @click="goGoodsHotel(product_id)" style="margin-right: 16rpx;">全部酒店</text>
+					<image @click="goGoodsHotel(product_id)" style="width: 12rpx;height: 20rpx;" src="/static/icon/right04.png"
+						mode=""></image>
+				</view>
+
+			</view>
+
+			<!-- 产品介绍 -->
+			<view class="produce">
+				<view class="produce-title">
+					<text>产品简介</text>
+				</view>
+				<view class="produce-text" v-html="productDetail.details"></view>
+			</view>
+		</view>
+
+		<view class="buy-btn">
+			<view class="buy-btn-left" @click="goHome">
+				<image style="width: 40rpx;height: 42rpx;" src="/static/icon/home01.png" mode=""></image>
+				<text>首页</text>
+			</view>
+			<view class="buy-btn-right" @click="$refs.codePurchase.open()" v-if="produceType==1">
+				<text>立即购买</text>
+			</view>
+			<view v-if="produceType==2" class="buy-btn-right" @click="goIntegralOrder(product_id)">
+				<text>立即兑换</text>
+			</view>
+		</view>
+		<view style="height: 90px;background-color: #f9f9f9;"></view>
+
+		<!-- 选择规格 -->
+		<uni-popup ref="Recipient" type="bottom" mask-background-color=" rgba(0,0,0,0.3);">
+			<view class="pop">
+				<view class="pop-price">
+					<view class="pop-price-left">
+						<image style="width: 180rpx;height: 136rpx; border-radius:12rpx ;"
+							src="http://t9.9026.com/imgs/special01.png" mode="" ></image>
+						<view class="pop-price-left-money" v-if="produceType == 1">
+							<text>¥</text>
+							<text>{{productDetail.price}}</text>
+						</view>
+						<view class="pop-price-left-money" v-if="produceType == 2">
+							<text>{{productDetail.integral}}</text>
+							<text>积分</text>
+						</view>
+					</view>
+					<image style="width: 52rpx;height: 52rpx;" src="/static/icon/close01.png" mode=""  @click="Recipientclose"></image>
+				</view>
+
+				<view class="pop-flavor">
+					<text>口味</text>
+					<view class="tab_flavor">
+						<view class="flavorTitle-item" :class="{'flavorTitle-item-active':flavorIsActive === index}"  v-for="(item,index) in flavorList" :key="index"
+							@click="flavorchecked(index,item.attr_name)">
+							<view :class="{'active-flavor':flavorIsActive === index}">
+								{{item.attr_name}}
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="pop-flavor" style="margin-top: 44rpx;">
+					<text>重量</text>
+					<view class="tab_flavor">
+						<view class="flavorTitle-item" :class="{'flavorTitle-item-active':weightIsActive === index}" v-for="(item,index) in weightList" :key="index"
+							@click="weightchecked(index,item.attr_name)">
+							<view :class="{'active-flavor':weightIsActive === index}">
+								{{item.attr_name}}
+							</view>
+						</view>
+					</view>
+				</view>
+				<view class="pop-flavor" style="margin-top: 44rpx;">
+					<text>包装</text>
+					<view class="tab_flavor">
+						<view class="flavorTitle-item" :class="{'flavorTitle-item-active':packIsActive === index}" v-for="(item,index) in packList" :key="index"
+							@click="packchecked(index,item.title)">
+							<view :class="{'active-flavor':packIsActive === index}">
+								{{item.title}}
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="purchase" v-if="produceType == 1" @click="goIntegralOrder(product_id)">
+				<view class="purchase-btn">立即购买</view>
+			</view>
+			<view class="purchase" v-if="produceType == 2"  @click="selectSpecs">
+				<!-- <view class="purchase-btn">立即兑换</view> -->
+				<view class="purchase-btn">确认</view>
+			</view>
+
+		</uni-popup>
+
+		<!-- 二维码购买 -->
+		<uni-popup ref="codePurchase" type="center">
+			<view class="code-purchase">
+				<view class="title"><text>识别下方二维码即可购买</text></view>
+				<view style="margin-left:30rpx;width: 580rpx;height: 2rpx;background: #F0F0F0;"></view>
+				<view class="img">
+					<image src="http://t9.9026.com/imgs/Kudosbg.png"></image>
+				</view>
+				<view class="btn">
+					<view class="cancel" @click="dialogClose"><text>取消</text></view>
+					<view class="download" @click="dialogConfirm"><text>保存图片</text></view>
+				</view>
+			</view>
+		</uni-popup>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				jump_type: '',
+				jump_config: '',
+				resource_type: '',
+				//1:第三方产品2:积分兑换产品
+				produceType:'',
+				// 规格
+				specsText:'',
+				specs:{
+					pack:'',
+					weight:'',
+					flavor:'',
+				},
+				// 产品详情
+				productDetail:'',
+				// 酒店详情
+				hotelDetail:'',
+				// 产品id
+				product_id:'',
+				packList: [{
+						title: '礼盒'
+					},
+					{
+						title: '普通'
+					}
+				],
+				weightList: [{
+					attr_name: '50g'
+				}, {
+					attr_name: '100g'
+				}, {
+					attr_name: '150g'
+				}],
+				flavorList: [{
+					attr_name: '五仁'
+				}, {
+					attr_name: '豆沙'
+				}, {
+					attr_name: '水果'
+				}],
+				//激活指定table菜单
+				isActive: 0,
+				flavorIsActive:0,
+				weightIsActive:0,
+				packIsActive:0,
+				
+				backImageUrl: require('../../../static/icon/add01.png'),
+
+				//轮播图
+				info: [{
+					img: 'http://t9.9026.com/imgs/swiper01.png',
+					name: '酒店预订'
+				}, ],
+				dotsStyles: {
+					backgroundColor: 'rgba(255, 255, 255, .3)',
+					border: '1px rgba(255, 255, 255, .3) solid',
+					color: '#fff',
+					selectedBackgroundColor: 'rgba(255, 255, 255, 1)',
+					selectedBorder: '1px rgba(255, 255, 255, 1) solid'
+				},
+				//指示点显示位置
+				current1: 0,
+				//指示点模式
+				mode: 'dot',
+			}
+		},
+		onReady: function(res) {
+			this.videoContext = uni.createVideoContext('myVideo')
+		},
+		onLoad(op) {
+			this.admin = this.$store.getters.userInfo
+			console.log(this.admin);
+			this.product_id=op.id
+			this.produceType = op.type
+			console.log(this.product_id,this.produceType,"产品id")
+			this.getProductDetail(op.id)
+			
+		},
+		methods: {
+			//获取当前页面路径
+			getPageUrl() {
+				const pages = getCurrentPages();
+				if(pages.length==1){
+					const currentPage = pages[0];
+					console.log(currentPage.options,'--------->currentPage.options')
+					let pageUrl = `/${currentPage.route}?type=${currentPage.options.type}`;
+					return pageUrl
+					console.log('当前页面url:', pageUrl);
+				}else{
+					const currentPage = pages[pages.length - 1];
+					console.log(currentPage.options,'--------->currentPage.options')
+					let pageUrl = `/${currentPage.route}?type=${currentPage.options.type}`;
+					return pageUrl
+					console.log('当前页面url:', pageUrl);
+				}
+			},
+			// 跳转其他小程序
+			goOther() {
+				let _this = this
+				wx.navigateToMiniProgram({
+					appId: 'wx255b58f0992b3c53', //appid
+					path: 'newUIMain/enrollment/enrollment', //path
+					extraData: { //参数
+						foo: 'bar'
+					},
+					// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+					success(res) {
+						let page = _this.getPageUrl()
+						let user_id = ''
+						 if(_this.admin != null ){
+							 user_id = _this.admin.id
+						 }else{
+							 user_id = 0
+						 }
+						console.log('成功',page)
+						_this.$api.my.userMemberAdd({
+							user_id,
+							page,
+						}).then(res=>{
+							console.log(res.data);
+						})
+						// 打开成功
+					},
+					fail(e) {
+						console.log(e, '失败')
+					}
+				})
+			},
+			
+			//视频自动播放
+			openVideoPlay() {
+				this.videoContext.play()
+			},
+			// 获取商品详情
+			getProductDetail(id){
+				this.$api.product.getProductDetail({
+					product_id:id
+				}).then(res=>{
+					console.log(res,"产品详情")
+					// console.log(res.data.attr_group,"产品规格")
+					if(res.code==0){
+						this.productDetail=res.data
+						this.info = JSON.parse(res.data.img_urls).map(item => {
+							return {
+								img: item
+							}
+						})
+						//跳转h5和小程序
+						this.jump_type = res.data.jump_type,
+							this.jump_config = res.data.jump_config
+						//banner展示视频或者图片
+						this.resource_type = res.data.resource_type
+						this.video_url = res.data.video_url
+						console.log(this.video_url, '--->this.video_url');
+						//视频自动播放
+						this.openVideoPlay()
+						// 口味
+						// this.flavorList=JSON.parse(res.data.attr_group)[0].attr_list
+						// 重量
+						// this.weightList=JSON.parse(res.data.attr_group)[1].attr_list
+						this.getHotelDetail(res.data.hotel_id)
+					}
+				})
+			},
+			// 获取酒店详情
+			getHotelDetail(id){
+				this.$api.hotel.getHotelDetail({
+					hotel_id:id
+				}).then(res=>{
+					console.log(res,"酒店详情")
+					this.hotelDetail=res.data
+				})
+			},
+			//跳转酒店列表
+			goGoodsHotel(id) {
+				uni.navigateTo({
+					url: '/pages/goods/goods-hotel/index?product_id='+id
+				})
+			},
+			//首页
+			goHome() {
+				uni.switchTab({
+					url: '/pages/index/index'
+				})
+			},
+			//二维码购买确认按钮
+			dialogConfirm() {
+				console.log('确认');
+				this.codePurchaseClose()
+			},
+			//二维码购买取消按钮
+			dialogClose() {
+				console.log('取消');
+				this.codePurchaseClose()
+			},
+			//菜单index切换
+			checked(index) {
+				this.isActive = index
+			},
+			// 口味切换
+			flavorchecked(index,name) {
+				this.flavorIsActive = index
+				this.specs.flavor=name
+			},
+			// 重量切换
+			weightchecked(index,name) {
+				this.weightIsActive = index
+				this.specs.weight=name
+			},
+			// 包装切换
+			packchecked(index,name) {
+				this.packIsActive = index
+				this.specs.pack=name
+			},
+			// 选择规格
+			selectSpecs(){
+				this.specs.flavor='五仁'
+				this.specs.weight='50g'
+				this.specs.pack='礼盒'
+				console.log(this.specs)
+				this.specsText=this.specs.flavor+'--'+this.specs.weight+'--'+this.specs.pack
+				this.Recipientclose()
+			},
+			Recipientopen() {
+				this.$refs.Recipient.open('bottom')
+			},
+			Recipientclose() {
+				this.$refs.Recipient.close()
+			},
+			codePurchaseClose(){
+				this.$refs.codePurchase.close()
+			},
+			// 切换轮播图指示点
+			change1(e) {
+				this.current1 = e.detail.current;
+			},
+			// 跳转积分兑换
+			goIntegralOrder(id){
+				uni.navigateTo({
+					url:'/pages/my/integral/integralOrder?product_id='+id
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	page {
+		height: 100% !important;
+		background: #F9F9F9 !important;
+	}
+
+	.code-purchase {
+		width: 640rpx;
+		height: 764rpx;
+		background: $bgColor;
+		border-radius: 20rpx;
+		padding-top: 64rpx;
+		box-sizing: border-box;
+
+		.title {
+			@include flexlayout();
+			margin-bottom: 24rpx;
+
+			text {
+				font-size: 34rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #333333;
+			}
+		}
+
+		.img {
+			margin-top: 10rpx;
+			margin-left: 48rpx;
+			width: 544rpx;
+			height: 468rpx;
+			background: $bgColor;
+			border-radius: 2rpx;
+			@include flexlayout();
+
+			image {
+				width: 392rpx;
+				height: 390rpx;
+			}
+		}
+
+		.btn {
+			margin-top: 40rpx;
+			width: 100%;
+			height: 110rpx;
+			display: flex;
+			align-items: center;
+
+			.cancel {
+				@include flexlayout();
+				width: 50%;
+				height: 100%;
+				border-top: #E5E5E5 solid 1rpx;
+				border-right: #E5E5E5 solid 1rpx;
+
+				text {
+					font-size: 32rpx;
+					font-family: PingFangSC-Medium, PingFang SC;
+					font-weight: 500;
+					color: #666666;
+				}
+			}
+
+			.download {
+				border-top: #E5E5E5 solid 1rpx;
+				// border-left:#E5E5E5 solid 0.3rpx;
+				@include flexlayout();
+				height: 100%;
+				width: 50%;
+
+				text {
+					font-size: 32rpx;
+					font-family: PingFangSC-Medium, PingFang SC;
+					font-weight: 500;
+					color: #FF7119;
+				}
+			}
+		}
+	}
+
+
+
+	.purchase {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		height: 148rpx;
+		background: #FFFFFF;
+		box-shadow: 0px -4px 8px 0px rgba(0, 0, 0, 0.05);
+		padding: 0 30rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+
+		.purchase-btn {
+			width: 100%;
+			height: 92rpx;
+			background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+			border-radius: 12rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			font-weight: bold;
+			color: #FFFFFF;
+			font-size: 30rpx;
+		}
+	}
+
+	.pop {
+		padding: 32rpx 30rpx 80rpx;
+		width: 100%;
+		height: 914rpx;
+		background: #FFFFFF;
+		border-radius: 22rpx 22rpx 0px 0px;
+		overflow-y: scroll;
+		position: relative;
+
+		.pop-price {
+			display: flex;
+			align-items: flex-start;
+			justify-content: space-between;
+
+			.pop-price-left {
+				flex: 1;
+				display: flex;
+				align-items: center;
+				justify-content: flex-start;
+
+				.pop-price-left-money {
+					font-weight: 800;
+					color: #FF6200;
+					font-size: 48rpx;
+					margin-left: 20rpx;
+				}
+			}
+		}
+
+		.pop-flavor {
+			width: 100%;
+			margin-top: 64rpx;
+			font-weight: bold;
+			color: #333333;
+			font-size: 32rpx;
+		}
+	}
+
+	//口味切换
+	.tab_flavor {
+		margin-top: 14rpx;
+		width: 100%;
+		display: flex;
+		justify-content: flex-start;
+		align-items: center;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		flex-wrap: wrap;
+	}
+
+	.tab_flavor .flavorTitle-item {
+		width: 220rpx;
+		height: 60rpx;
+		background-color: #FFF;
+		border: 2rpx solid #CCCCCC;
+		border-radius: 30rpx;
+		font-size: 30rpx;
+		color: #999;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		margin-right: 15rpx;
+		font-weight: normal;
+		margin-top: 16rpx;
+
+		&:nth-child(3n) {
+			margin-right: 0;
+		}
+	}
+	
+	.flavorTitle-item-active{
+		border: none !important;
+	}
+	
+	.active-flavor {
+		width: 220rpx;
+		height: 60rpx;
+		border-radius: 30rpx;
+		background-color: #FF6200;
+		border: none;
+		color: #fff;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.buy-btn {
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		padding: 0 30rpx 0 58rpx;
+		height: 148rpx;
+		background: #FFFFFF;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.buy-btn-left {
+			flex: none;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+			color: #FF6200;
+			font-size: 22rpx;
+		}
+
+		.buy-btn-right {
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			margin-left: 40rpx;
+			flex: 1;
+			height: 92rpx;
+			background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+			border-radius: 12rpx;
+			font-weight: bold;
+			color: #FFFFFF;
+			font-size: 30rpx;
+		}
+	}
+
+
+	.goods-detail {
+		height: 100%;
+		background: #F9F9F9;
+	}
+
+	.produce {
+		margin-top: 24rpx;
+		padding: 40rpx 30rpx 36rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.02);
+		border-radius: 16rpx;
+
+		.produce-title {
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+
+		.produce-text {
+			margin-top: 26rpx;
+			font-size: 30rpx;
+			color: #333333;
+			line-height: 48rpx;
+		}
+	}
+
+	.about {
+		padding: 40rpx 30rpx 40rpx;
+		width: 100%;
+		// height: 350rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.02);
+		border-radius: 16rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: flex-start;
+		justify-content: flex-start;
+
+		.about-title {
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+
+		.about-name {
+			margin: 30rpx 0 20rpx;
+			font-size: 30rpx;
+			color: #333333;
+		}
+
+		.about-address {
+			font-size: 30rpx;
+			color: #333333;
+		}
+
+		.about-phone {
+			margin: 20rpx 0 48rpx;
+			font-size: 30rpx;
+			color: #333333;
+		}
+
+		.about-all {
+			width: 100%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			font-size: 32rpx;
+			color: #FF6200;
+		}
+	}
+
+
+
+	.home-swiper {
+		height: 576rpx;
+
+		.swiper-box {
+			height: 576rpx;
+		}
+	}
+
+	::v-deep .uni-swiper__dots-box {
+		bottom: 48rpx !important;
+	}
+
+	.price {
+		padding: 32rpx 30rpx 0rpx;
+		position: relative;
+		top: -20rpx;
+		// height: 406rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.02);
+		border-radius: 16rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: flex-start;
+		justify-content: flex-start;
+
+		.price-top {
+			font-size: 48rpx;
+			font-weight: 800;
+			color: #FF6200;
+		}
+
+		.price-text {
+			margin: 30rpx 0 26rpx;
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+
+		.price-banner {
+			padding: 0 24rpx;
+			width: 100%;
+			height: 80rpx;
+			background-repeat: no-repeat;
+			background-size: cover;
+			background-position: center;
+			font-size: 32rpx;
+			color: #FFFFFF;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+		}
+
+		.price-specs {
+			margin-top: 48rpx;
+			width: 100%;
+			height: 110rpx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			border-top: 2rpx solid #F0F0F0;
+
+			.price-specs-left {
+				flex: none;
+				font-size: 32rpx;
+				font-weight: bold;
+				color: #333333;
+			}
+
+			.price-specs-main {
+				flex: 1;
+				margin-left: 28rpx;
+				font-size: 30rpx;
+				color: #666666;
+			}
+
+		}
+	}
+</style>

+ 213 - 0
pages/goods/goods-hotel/index.vue

xqd
@@ -0,0 +1,213 @@
+<template>
+	<view class="goods-hotel">
+		<view class="search">
+			<u-input placeholder="搜索" border='none' v-model="search" @input="searchText">
+				<template slot="suffix" style='margin-right:40rpx;'>
+					<u-image :showLoading="true" :showError='true' src="/static/icon/search.png" width="40rpx"
+						height="32rpx"></u-image>
+				</template>
+			</u-input>
+		</view>
+
+		<view class="content">
+			<view class="content-item" v-for="item in 2">
+				<image style="flex: none;width: 112rpx;height: 112rpx;border-radius: 50%;" src="/static/icon/youyue.png"
+					mode=""></image>
+				<view class="content-item-main">
+					<text class="content-item-main-text">成都环球中心天堂洲际大饭店</text>
+					<view class="content-item-main-call" style="margin: 20rpx 0 12rpx;">
+						<image style="width: 26rpx;height: 26rpx; margin-right: 8rpx;" src="/static/icon/phone02.png"
+							mode=""></image>
+						<text>028-129320</text>
+					</view>
+					<view class="content-item-main-call">
+						<image style="width: 24rpx;height: 28rpx; margin-right: 8rpx; " src="/static/icon/address01.png"
+							mode=""></image>
+						<text>1.2km</text>
+					</view>
+				</view>
+				<view class="content-item-right">
+					<image style="width: 50rpx;height: 48rpx;" src="/static/icon/navigation.png" mode=""></image>
+					<text class="content-item-right-text">去这里</text>
+				</view>
+			</view>
+		</view>
+		<!-- 触底 -->
+		<view class="home-bottom">
+			<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText" />
+		</view>
+
+	</view>
+</template>
+
+<script>
+	import util from '../../../utils/util.js'
+	export default {
+		data() {
+			return {
+				// 搜索
+				search:'',
+				// 组价uni-load-more
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				// 酒店列表
+				hotelList:[],
+				// 产品id
+				product_id:'',
+			}
+		},
+		onLoad(op) {
+			this.product_id=op.product_id
+			if(op.product_id!=''){
+				this.getHotelList(op.product_id)
+			}
+		},
+		methods: {
+			// 获取酒店列表
+			getHotelList(id){
+				this.$api.hotel.getHotelList({
+					page:1,
+					product_id:id
+				}).then(res=>{
+					console.log(res,"酒店列表")
+					if(res.code==0){
+						this.hotelList=res.data.data
+					}
+				})
+			},
+			// 搜索防抖
+			searchText:util.debounce(function(){
+				this.goSearch()
+			},1000),
+			// 搜索
+			goSearch(){
+				this.$api.hotel.getHotelList({
+					page:1,
+					name:this.search,
+					product_id:this.product_id
+				}).then(res=>{
+					console.log(res,'搜索酒店列表')
+					if(res.code==0){
+						this.hotelList=res.data.data
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	page {
+		height: 100% !important;
+		background: #F9F9F9 !important;
+	}
+
+	.goods-hotel {
+		height: 100%;
+		background: #F9F9F9;
+	}
+
+	.home-bottom {
+		background-color: #f9f9f9;
+	}
+
+	.content {
+		width: 100%;
+		padding: 24rpx 30rpx;
+		padding-bottom: 30rpx;
+		background-color: #F9F9F9;
+
+		.content-item {
+			margin-bottom: 24rpx;
+			padding: 0 24rpx;
+			padding-top: 20rpx;
+			padding-bottom: 20rpx;
+			height: 204rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 24rpx -10rpx rgba(101, 95, 90, 0.3);
+			border-radius: 12rpx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.content-item-main {
+				flex: 1;
+				display: flex;
+				flex-direction: column;
+				align-items: flex-start;
+				justify-content: center;
+				margin-left: 20rpx;
+				margin-top: 12rpx;
+
+				.content-item-main-text {
+					font-weight: 500;
+					color: #333333;
+					font-size: 30rpx;
+				}
+
+				.content-item-main-call {
+					font-weight: 500;
+					color: #666666;
+					font-size: 26rpx;
+					display: flex;
+					align-items: center;
+					justify-content: flex-start;
+				}
+			}
+
+			.content-item-right {
+				flex: none;
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				justify-content: center;
+
+				.content-item-right-text {
+					font-weight: bold;
+					color: #FF6201;
+					font-size: 24rpx;
+					margin-top: 16rpx;
+				}
+			}
+		}
+	}
+
+	.search {
+		padding: 0 30rpx;
+		height: 124rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.04);
+		display: flex;
+		align-items: center;
+		justify-content: center;
+
+		::v-deep .u-input {
+			width: 690rpx !important;
+			height: 68rpx !important;
+			background: #F1F1F1;
+			border-radius: 74rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper {
+			padding-left: 36rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper__field {
+			color: #999999 !important;
+			font-size: 28rpx !important;
+		}
+	}
+</style>

+ 468 - 0
pages/goods/goods-lucky/index.vue

xqd
@@ -0,0 +1,468 @@
+<template>
+	<view class="goods-lucky">
+		<!-- 转盘 -->
+		<view class="spinning" :style="{backgroundImage:'url('+backImageUrl+')'}">
+			<view class="spinning-title">
+				<text>幸运大转盘</text>
+			</view>
+			<q-turntable ref="turntable" :areaNumber='9' @start="turntableStart" @success="turntableSuccess">
+			</q-turntable>
+		</view>
+
+		<view style="background-color: #f9f9f9; padding-bottom: 136rpx;">
+			<!-- 产品信息 -->
+			<view class="produce">
+				<view class="produce-title">产品信息</view>
+				<view class="produce-main" v-for="item in 6">
+					<image style="width: 132rpx;height: 132rpx;border-radius: 10rpx;" src="/static/icon/banner02.png"
+						mode=""></image>
+					<view class="produce-main-text">
+						<text class="produce-main-text-top">一等奖</text>
+						<text class="produce-main-text-bom">HUAWEI MateBook X Pro</text>
+					</view>
+				</view>
+			</view>
+
+			<!-- 活动规则 -->
+			<view class="rule">
+				<view class="rule-title">
+					活动规则
+				</view>
+				<view class="rule-content">
+					<view class="introduce-top">
+						<text class="introduce-top-rule1"></text>
+						<text style="margin: 0 8rpx;">活动规则</text>
+						<text class="introduce-top-rule2"></text>
+					</view>
+					<view class="introduce-text">
+						<text>活动奖品分为线上和线下两种类型活动奖品分为线上和线下两种类型奖品活动奖品分为线上和线下两种类型奖品奖品,线上活动奖品分为线上和线下两种类型奖品,线上活动奖品分为线上和线下两种类型奖品,线上</text>
+					</view>
+				</view>
+			</view>
+
+			<!-- 我的奖品 -->
+			<view class="prize">
+				<view class="prize-title">
+					我的奖品
+				</view>
+				<view class="prize-main" v-for="item in 3">
+					<view class="prize-main-left">
+						<text class="prize-main-left-top">HUAWEI MateBook X Pro</text>
+						<text class="prize-main-left-bom">2022-02-10</text>
+					</view>
+					<view :class="isexchange ? 'prize-main-rightSelect' : 'prize-main-right' ">
+						<text v-if="isexchange">立即兑换</text>
+						<text v-if="!isexchange">已兑换</text>
+					</view>
+				</view>
+			</view>
+		</view>
+		
+		
+		<!-- 中奖弹窗 -->
+		<uni-popup ref="codePurchase" type="center">
+			<view class="code-purchase">
+				<view class="img">
+					<image style="width: 80rpx;height: 82rpx" src="/static/icon/gift01.png"></image>
+					<view class="text">
+						<text>恭喜您抽中了<text>{{prizeLevel}}</text></text>
+						<text>请尽快去奖品中心兑奖</text>
+					</view>
+				</view>
+				<view class="btn">
+					<view class="cancel" @click="dialogClose"><text>待会儿</text></view>
+					<view class="download" @click="dialogConfirm"><text>去兑奖</text></view>
+				</view>
+			</view>
+		</uni-popup>
+		<!-- 未中奖弹窗 -->
+		<uni-popup ref="codePurchaseNone" type="center">
+			<view class="code-purchase">
+				<view class="img">
+					<image style="width: 108rpx;height: 68rpx" src="/static/icon/gift02.png"></image>
+					<view class="text">
+						<text>很遗憾您没有抽中奖品</text>
+						<text>下次再来哟</text>
+					</view>
+				</view>
+				<view class="btn">
+					<view class="know" @click="dialogClose"><text>知道了</text></view>
+				</view>
+			</view>
+		</uni-popup>
+
+
+
+	</view>
+</template>
+
+<script>
+	import QTurntable from '@/components/q-turntable/q-turntable.vue'
+	export default {
+		components: {
+			QTurntable
+		},
+		data() {
+			return {
+				//中奖等级
+				prizeLevel:'',
+				isexchange: true,
+				backImageUrl: 'http://t9.9026.com/imgs/banner02.png',
+				award: 1,
+				awardList: [{
+						title: '一等奖'
+					},
+					{
+						title: '四等奖'
+					},
+					{
+						title: '谢谢参与'
+					},
+					{
+						title: '一等奖'
+					},
+					{
+						title: '谢谢参与'
+					},
+					{
+						title: '三等奖'
+					},
+					{
+						title: '三等奖'
+					},
+					{
+						title: '二等奖'
+					},
+					{
+						title: '一等奖'
+					}
+				] // 顺时针对应每个奖项 
+			}
+		},
+		methods: {
+			
+			//中奖去兑换按钮
+			dialogConfirm() {
+				console.log('确认');
+			},
+			//中奖待会按钮
+			dialogClose() {
+				console.log('取消');
+			},
+
+			// 用户点击开始抽奖
+			turntableStart() {
+				let index = Math.floor(Math.random() * 6 + 1) //前端随机数,这里应该后台返回中奖结果
+				// this.award = index
+				this.award = 2
+				this.$refs.turntable.begin(this.award);
+			},
+
+			// 抽奖完成后操作
+			turntableSuccess() {
+				const index = this.award - 1;
+				console.log('bind:success', this.awardList[index]);
+				if(this.awardList[index].title == '谢谢参与'){
+					this.$refs.codePurchaseNone.open()
+				}else{
+					let o =  this.awardList[index].title
+					console.log(this.awardList[index].title);
+					this.prizeLevel = o 
+					this.$refs.codePurchase.open()
+				}
+	
+				// uni.showToast({
+				// 	title: `恭喜你获得${this.awardList[index].title}`,
+				// 	icon: 'none'
+				// });
+			},
+
+
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	page {
+		height: 100% !important;
+		background: #F9F9F9 !important;
+	}
+
+	.goods-lucky {
+		height: 100%;
+		background: #F9F9F9;
+	}
+
+	.code-purchase {
+		width: 620rpx;
+		// height: 357rpx;
+		background: #fff;
+		border-radius: 20rpx;
+		padding-top: 44rpx;
+		box-sizing: border-box;
+		.img {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+		}
+		.text{
+			margin-top: 26rpx;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+			font-weight: 400;
+			color: #333333;
+			font-size: 32rpx;
+			line-height: 44rpx;
+		}
+
+		.btn {
+			margin-top: 26rpx;
+			width: 100%;
+			height: 90rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			border-top:2rpx solid #E5E5E5;
+			.cancel{
+				flex: 1;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-weight: 400;
+				color: #333333;
+				font-size: 32rpx;
+			}
+			.download{
+				flex: 1;
+				height: 90rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				border-left:2rpx solid #E5E5E5;
+				font-weight: 400;
+				color: #FF6200;
+				font-size: 32rpx;
+			}
+			.know{
+				font-weight: 400;
+				color: #FF6200;
+				font-size: 32rpx;
+			}
+		}
+	}
+
+
+
+
+	.prize {
+		margin-top: 24rpx;
+		background: #FFFFFF;
+		border-radius: 16rpx;
+		padding: 40rpx 30rpx 40rpx;
+
+		.prize-title {
+			font-weight: bold;
+			color: #080F18;
+			font-size: 30rpx;
+		}
+
+		.prize-main {
+			margin-top: 40rpx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			border-bottom: 2rpx solid #F0F0F0;
+			padding-bottom: 40rpx;
+
+			&:last-child {
+				border-bottom: none;
+				padding-bottom: 0rpx;
+			}
+
+			.prize-main-left {
+				display: flex;
+				flex-direction: column;
+				align-items: flex-start;
+				justify-content: center;
+
+				.prize-main-left-top {
+					font-size: 32rpx;
+					font-weight: bold;
+					color: #333333;
+				}
+
+				.prize-main-left-bom {
+					font-weight: 500;
+					color: #999999;
+					font-size: 24rpx;
+					margin-top: 24rpx;
+				}
+
+			}
+
+			.prize-main-right {
+				flex: none;
+				width: 148rpx;
+				height: 60rpx;
+				background: #FFFFFF;
+				border-radius: 30rpx;
+				border: 2rpx solid #D0D0D0;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				color: #D0D0D0;
+				font-size: 26rpx;
+			}
+
+			.prize-main-rightSelect {
+				flex: none;
+				width: 148rpx;
+				height: 60rpx;
+				background: #FFFFFF;
+				border-radius: 30rpx;
+				border: 2rpx solid #FF6200;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				color: #FF6200;
+				font-size: 26rpx;
+			}
+		}
+	}
+
+	.rule {
+		margin-top: 24rpx;
+		background: #FFFFFF;
+		border-radius: 16rpx;
+		padding: 40rpx 30rpx 32rpx;
+
+		.rule-title {
+			font-weight: bold;
+			color: #080F18;
+			font-size: 30rpx;
+		}
+
+		.rule-content {
+			margin-top: 32rpx;
+			background: #FFFFFF;
+			border-radius: 4rpx;
+			border: 2rpx solid #999999;
+			padding: 48rpx 20rpx 34rpx;
+
+			.introduce-top {
+				height: 32rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-size: 32rpx;
+				font-weight: bold;
+				letter-spacing: 2rpx;
+
+				.introduce-top-rule1 {
+					width: 56rpx;
+					height: 4rpx;
+					background: linear-gradient(90deg, #FFFFFF 0%, #D9A94D 100%);
+				}
+
+				.introduce-top-rule2 {
+					width: 56rpx;
+					height: 4rpx;
+					background: linear-gradient(-90deg, #FFFFFF 0%, #D9A94D 100%);
+				}
+			}
+
+			.introduce-text {
+				margin-top: 72rpx;
+				font-weight: bold;
+				color: #333333;
+				font-size: 28rpx;
+				line-height: 56rpx;
+			}
+		}
+	}
+
+
+
+	.produce {
+		position: relative;
+		top: -10rpx;
+		background: #FFFFFF;
+		border-radius: 16rpx;
+		padding: 48rpx 30rpx 0rpx;
+
+		.produce-title {
+			font-weight: bold;
+			color: #080F18;
+			font-size: 30rpx;
+			margin-bottom: 40rpx;
+		}
+
+		.produce-main {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			border-bottom: 2rpx solid #F0F0F0;
+			padding-bottom: 32rpx;
+			margin-bottom: 32rpx;
+
+			&:last-child {
+				border: none;
+				margin-bottom: 0;
+			}
+
+			.produce-main-text {
+				margin-left: 24rpx;
+				flex: 1;
+				display: flex;
+				flex-direction: column;
+				align-items: flex-start;
+				justify-content: center;
+
+				.produce-main-text-top {
+					font-weight: 500;
+					color: #080F18;
+					font-size: 28rpx;
+				}
+
+				.produce-main-text-bom {
+					font-weight: 500;
+					color: #666666;
+					font-size: 24rpx;
+					margin-top: 14rpx;
+				}
+			}
+		}
+
+	}
+
+	.spinning {
+		padding-top: 64rpx;
+		width: 100%;
+		height: 790rpx;
+		background-repeat: no-repeat;
+		background-size: cover;
+
+		.spinning-title {
+			margin-bottom: 40rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			font-weight: bold;
+			color: #FFFFFF;
+			font-size: 64rpx;
+		}
+
+	}
+</style>

+ 376 - 0
pages/goods/goods.vue

xqd
@@ -0,0 +1,376 @@
+<template>
+	<view class="goods">
+		<scroll-view class="scroll-y" @scroll="handleScroll" :scroll-into-view="topItem" scroll-with-animation
+			scroll-y="true">
+			<view id="top"></view>
+			<!-- 背景图 -->
+			<view class="goods-img">
+				<image v-if="bannerImg" style="width: 100%; height: 450rpx;" :src="bannerImg" mode=""></image>
+			</view>
+			<!-- 内容 -->
+			<view class="main">
+				<view class="search">
+					<u-input placeholder="搜索" border='none'  v-model="search" @input="searchText">
+						<template slot="suffix" style='margin-right:40rpx;'>
+							<u-image :showLoading="true" :showError='true' src="/static/icon/search.png" width="40rpx"
+								height="32rpx"></u-image>
+						</template>
+					</u-input>
+				</view>
+				<view class="tab_nav">
+					<view class="navTitle" v-for="(item,index) in items" :key="index">
+						<view class="navTitle-item">
+							<view :class="{'active':isActive === index}" @click="checked(index,item.id)">
+								{{item.name}}
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="content">
+
+				<view class="home-hotel-img-content">
+
+					<view @click="goGoodsDetail(item.id)" class="home-hotel-img-content-item" v-for="(item,index) in goodsList" :key="index"
+						:style="{marginTop:item.marginTop || 0 }">
+						<image class="home-hotel-img-content-item-img"
+							:class="item.short?'home-hotel-img-content-item-img': 'home-hotel-img-content-item-img-long' "
+							:src="item.cover_img" mode=""></image>
+						<view class="text">
+							<text class="text-top">{{item.name}}</text>
+							<text class="text-main">{{item.hotel.name}}</text>
+						</view>
+					</view>
+
+				</view>
+				<!-- 触底 -->
+				<view class="home-bottom">
+					<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText" />
+				</view>
+				<!-- <text @click="goGoodsDetail">商品</text>
+			<text @click="goGoodsDetailImg">转盘</text> -->
+			</view>
+		</scroll-view>
+		<view class="return-btn" v-if="isShow" @click="handleBackTop">
+			<image style="width: 128rpx;height: 128rpx;" src="/static/icon/returntop.png" mode=""></image>
+		</view>
+	</view>
+</template>
+
+<script>
+	import util from '@/utils/util.js'
+	export default {
+
+		data() {
+			return {
+				//搜索
+				search:'',
+				//背景图
+				bannerImg:'',
+				// 返回的按钮是否显示
+				isShow: false,
+				topItem: '', //返回顶部的标记点
+				goodsList: [{
+						img: 'http://t9.9026.com/imgs/goodsimg01.png',
+						text: '中秋佳节五仁月饼,惊喜特供,限时抢购',
+						title: '环球洲际',
+						short: '',
+					}],
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				//分段器
+				items: [],
+				//激活指定table菜单
+				isActive: 0,
+				//第三方产品分类categoryId
+				categoryId:'',
+			};
+		},
+		onLoad() {
+			this.shortLong()
+			this.getCategoryList()
+			
+			//获取产品活动列表背景图
+			this.bannerImg = this.$store.getters.allset.activity_page.value.cover
+			
+		},
+		methods: {
+			// 获取分类列表
+			getCategoryList(){
+				this.$api.category.getCategoryList({
+					page:1,
+					type:2
+				}).then(res=>{
+					if(res.code==0){
+						this.items=res.data.data
+						this.categoryId = this.items[0].id
+						console.log(this.categoryId,'--->this.categoryId');
+						this.getGoodsList(this.categoryId)
+					}
+				})
+			},
+			//菜单index切换
+			checked(index,id) {
+				this.isActive = index
+				this.getGoodsList(id)
+			},
+			
+			//产品列表type:1,第三方购买产品
+			getGoodsList(category_id) {
+				this.$api.product.getProducts({
+					type: 1,
+					page: 0,
+					keyword:'',
+					category_id:`${category_id}`
+				}).then(res => {
+					this.goodsList = res.data.data
+					this.shortLong()
+					console.log(this.goodsList,'------>产品图');
+				})
+			},
+
+			handleScroll(e) {
+				//只有scrollTop有用,先拿scrollTop
+				let {
+					scrollTop
+				} = e.detail
+				//滑动大于500让按钮显示
+				this.isShow = scrollTop > 500
+				//因为点第二次不行,这里记得重置清空一下
+				this.topItem = ''
+			},
+			handleBackTop() {
+				this.topItem = 'top'
+			},
+			shortLong() {
+				this.goodsList.forEach((item, index, arr) => {
+					if (index % 4 === 0) {
+						item.short = true
+					}
+					if (index % 4 === 1) {
+						item.long = true
+					}
+					if (index % 4 === 2) {
+						item.long = true
+						item.marginTop = -68 + "rpx"
+					}
+					if (index % 4 === 3) {
+						item.short = true
+					}
+				})
+				console.log(this.goodsList);
+			},
+			// //去大转盘
+			// goGoodsDetailImg() {
+			// 	uni.navigateTo({
+			// 		url: '/pages/goods/goods-lucky/index'
+			// 	})
+			// },
+
+			//去产品详情
+			goGoodsDetail(id) {
+				uni.navigateTo({
+					url:`/pages/goods/goods-detail/index?id=${id}&type=1`
+				})
+			},
+			// 搜索防抖
+			searchText:util.debounce(function(){
+				if(this.search !=''){
+					this.goSearch()
+				}else{
+					this.getGoodsList(this.categoryId)
+				}
+			},1000),
+			//搜索
+			goSearch(){
+				uni.showLoading({
+					title:'加载中'
+				})
+				this.$api.product.getProducts({
+					type: 1,
+					page: 0,
+					name:this.search,
+					category_id:''
+				}).then(res=>{
+					if(res.code==0){
+						uni.hideLoading()
+						this.goodsList=res.data.data
+					}
+				})
+			},
+			
+		}
+
+	}
+</script>
+
+<style lang="scss" scoped>
+	.goods {
+		height: 100%;
+	}
+
+	.tab_nav {
+		width: 100%;
+		height: 100rpx;
+		display: flex;
+		align-items: center;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		overflow-x: scroll;
+
+	}
+
+
+	.scroll-y {
+		height: 100vh;
+	}
+
+
+
+	.content {
+		background-color: #FFF;
+		padding: 20rpx 30rpx;
+
+		.home-hotel-img-content {
+			display: flex;
+			align-items: flex-start;
+			justify-content: space-between;
+			flex-wrap: wrap;
+
+			.home-hotel-img-content-item {
+				width: 332rpx;
+				background: #FFFFFF;
+				box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.04);
+				border-radius: 12rpx;
+				margin-bottom: 26rpx;
+
+				.home-hotel-img-content-item-img {
+					width: 332rpx;
+					height: 332rpx;
+					object-fit: cover;
+					object-position: center;
+				}
+
+				.home-hotel-img-content-item-img-long {
+					width: 332rpx;
+					height: 400rpx;
+					object-fit: cover;
+					object-position: center;
+				}
+
+				.text {
+					display: flex;
+					flex-direction: column;
+					align-items: flex-start;
+					justify-content: center;
+					padding: 18rpx 22rpx 32rpx;
+
+					.text-top {
+						font-size: 28rpx;
+						font-weight: bold;
+						color: #333;
+					}
+
+					.text-main {
+						margin-top: 20rpx;
+						font-size: 24rpx;
+						color: #999999;
+					}
+				}
+			}
+		}
+	}
+
+	.return-btn {
+		position: fixed;
+		bottom: 140rpx;
+		right: 14rpx;
+
+	}
+
+
+
+	.home-bottom {
+		background-color: #FFF;
+		padding-bottom: 84rpx;
+	}
+
+	.tab_nav .navTitle {
+		width: 154rpx;
+		flex: none;
+		height: 28rpx;
+		font-size: 32rpx;
+		color: #666;
+		position: relative;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		margin-right: 16rpx;
+	}
+
+	.navTitle-item {
+		width: 154rpx;
+		flex: none;
+		height: 28rpx;
+		font-size: 32rpx;
+		color: #666;
+		position: relative;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.active {
+		color: #D9A94D;
+		font-weight: bold;
+
+		&::after {
+			display: inline-block;
+			content: '';
+			width: 48rpx;
+			height: 12rpx;
+			background: linear-gradient(90deg, #F3D69F 0%, #D9A94D 100%);
+			border-radius: 6px;
+			position: absolute;
+			bottom: -32rpx;
+			left: 51rpx;
+		}
+	}
+
+	.search {
+		::v-deep .u-input {
+			width: 690rpx !important;
+			height: 68rpx !important;
+			background: #F1F1F1;
+			border-radius: 74rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper {
+			padding-left: 36rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper__field {
+			color: #999999 !important;
+			font-size: 28rpx !important;
+		}
+	}
+
+
+	.goods-img {
+		width: 100%;
+		height: 450rpx;
+	}
+
+	.main {
+		position: relative;
+		top: -36rpx;
+		padding: 48rpx 30rpx 0;
+		border-radius: 16rpx 16rpx 0px 0px;
+		height: 238rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.04);
+	}
+</style>

+ 971 - 0
pages/index/active-detail/index.vue

xqd
@@ -0,0 +1,971 @@
+<template>
+	<view class="active-detail">
+					
+		<!-- 自定义导航栏 -->
+		<u-navbar :leftText='title'  fixed safeAreaInsetTop :placeholder='true'  :bgColor="bgColor" @leftClick='back'>
+		</u-navbar>
+
+		<!-- 背景图 -->
+		<view class="active-detail-img">
+			<image style="width: 100%; height: 720rpx;" :src="activeDeatil.banners" mode=""></image>
+		</view>
+
+		<!--投票数  -->
+		<view class="vote">
+			<view class="vote-detail">
+				<!-- 原版
+				<view class="vote-detail-top">
+					<text style="width: 80rpx; height: 2rpx; background-color: rgba(204, 204, 204, .7); "></text>
+					<view class="vote-detail-top-main">
+						<text>
+							距活动结束:
+						</text>
+						<view class="time">
+							<text>还剩</text>
+							<view class="shijian">{{countdownh}}</view>
+							<text>时</text>
+							<view class="shijian">{{countdownm}}</view>
+							<text>分</text>
+							<view class="shijian">{{countdowns}}</view>
+							<text>秒</text>							
+						</view>
+					</view>
+					<text style="width: 80rpx; height: 2rpx; background-color: rgba(204, 204, 204, .7); "></text>
+				</view>
+				-->
+				<!-- 改版 -->
+				<view class="vote-detail-top-main1">
+					<view>
+						距活动结束
+						<text v-if="countdownh>0">{{countdownd}}</text>
+						<text>{{countdownh}}</text>
+						<text>{{countdownm}}</text>
+						<text>{{countdowns}}</text>
+					</view>
+				</view>
+
+				<view class="vote-detail-btn">
+					<view class="vote-detail-btn-item">
+						<text class="vote-detail-btn-item-num">{{activeDeatil.project_num}}</text>
+						<text class="vote-detail-btn-item-text">投票项</text>
+					</view>
+					<view style="width: 2rpx;height: 52rpx;background-color: #ccc;"></view>
+					<view class="vote-detail-btn-item">
+						<text class="vote-detail-btn-item-num">{{activeDeatil.vote_num}}</text>
+						<text class="vote-detail-btn-item-text">累计投票</text>
+					</view>
+					<view style="width: 2rpx;height: 52rpx;background-color: #ccc;"></view>
+					<view class="vote-detail-btn-item">
+						<text class="vote-detail-btn-item-num">{{activeDeatil.view_num}}</text>
+						<text class="vote-detail-btn-item-text">访问量</text>
+					</view>
+				</view>
+
+			</view>
+
+		</view>
+		<!-- 分段栏 -->
+		<view style="width: 100%;height: 16rpx;background-color:#F0F0F0 ;"></view>
+
+		<!-- 排行榜 -->
+		<view class="rank">
+			<view class="tab_nav">
+				<view class="navTitle" v-for="(item,index) in rankList" :key="index">
+					<view class="navTitle-item">
+						<view :class="{'active':isActive === index}" @click="checked(index)">
+							{{item.title}}
+						</view>
+					</view>
+				</view>
+			</view>
+			<view class="rank-search" v-if="isActive==0">
+				<u-input placeholder="输入IHG酒店名称或编号" border='none' v-model="search" @input='searchText'>
+					<template slot="suffix" style='margin-right:40rpx;'>
+						<u-image :showLoading="true" :showError='true' src="/static/icon/search.png" width="40rpx"
+							height="32rpx"></u-image>
+					</template>
+				</u-input>
+			</view>
+
+			<!-- 地区分类 -->
+			<view class="tab_area" v-if="isActive==0">
+				<view class="areaTitle" v-for="(item,index) in areaList" :key="index"
+					@click="checkedArea(index,item.id)">
+					<view class="areaTitle-item">
+						<view :class="{'active-area':isActiveArea === index}">
+							{{item.name}}
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<!-- 查询结果 -->
+		<view class="List" v-if="isActive==0">
+			<view class="ListItem" v-for="(item,index) in voteList" :key="index" @click="goVoteDetail(item.id)">
+				<image :src="item.cover_img" style="width: 640rpx;height:420rpx;border-radius: 12rpx; "></image>
+				<view class="kudosicon" :style="{backgroundImage:'url('+hotelImageUrl+')'}">
+					<text
+						style="width: 36rpx;height: 52rpx; display: flex;align-items: center;justify-content: center;color: #FFF;font-size: 24rpx;font-weight: bold; ">{{item.sort}}</text>
+				</view>
+				<view class="nav">
+					<view class="events">
+						<text>{{item.project_name}}</text>
+					</view>
+					<view class="voteStatus">
+						<text v-if="item.ticket_num>=0">{{item.ticket_num + item.virtual_ticket_num }}票</text>
+					</view>
+				</view>
+				<view class="foot" @click.stop="goVoteDetail(item.id)">
+					<text>{{activeDeatil.vote_name}}</text>
+				</view>
+			</view>
+		</view>
+
+		<view class="rank-detail" :style="{backgroundImage:'url('+backImageUrl+')'}" v-if="isActive==1">
+			<view class="rank-detail-rank" v-if="rankItemList[0].logo">
+				<image style="width: 92rpx; height: 92rpx; border-radius: 50%; " :src="rankItemList[0].logo" mode="">
+				</image>
+				<text class="rank-detail-rank-text">{{rankItemList[0].project_name}}</text>
+				<view class="rank-detail-rank-data">
+					<image style="width: 26rpx;height: 24rpx; margin-right: 10rpx; " src="/static/icon/votes01.png"
+						mode=""></image>
+					<text>{{rankItemList[0].ticket_num + rankItemList[0].virtual_ticket_num }}</text>
+				</view>
+			</view>
+			<view class="rank-detail-rank rank-detail-rankS" v-if="rankItemList[1].logo">
+				<image style="width: 92rpx; height: 92rpx; border-radius: 50%; " :src="rankItemList[1].logo" mode="">
+				</image>
+				<text class="rank-detail-rank-text">{{rankItemList[1].project_name}}</text>
+				<view class="rank-detail-rank-data">
+					<image style="width: 26rpx;height: 24rpx; margin-right: 10rpx; " src="/static/icon/votes01.png"
+						mode=""></image>
+					<text>{{rankItemList[1].ticket_num + rankItemList[1].virtual_ticket_num }}</text>
+				</view>
+			</view>
+			<view class="rank-detail-rank rank-detail-rankT" v-if="rankItemList[2].logo">
+				<image style="width: 92rpx; height: 92rpx; border-radius: 50%; " :src="rankItemList[2].logo" mode="">
+				</image>
+				<text class="rank-detail-rank-text">{{rankItemList[2].project_name}}</text>
+				<view class="rank-detail-rank-data">
+					<image style="width: 26rpx;height: 24rpx; margin-right: 10rpx; " src="/static/icon/votes01.png"
+						mode=""></image>
+					<text>{{rankItemList[2].ticket_num + rankItemList[2].virtual_ticket_num }}</text>
+				</view>
+			</view>
+		</view>
+		<!-- 具体排名(4-10) -->
+		<view class="rank-other" v-if="isActive==1">
+			<view class="rank-other-item" v-for="(item,index) in rankItemList" v-if="index>2" :key="index">
+				<view class="rank-other-item-left">
+					<text>{{index+1}}</text>
+				</view>
+				<view class="rank-other-item-main">
+					<image
+						style="width: 112rpx;height: 112rpx;margin-left: 24rpx; margin-right: 16rpx;border-radius: 50%; "
+						:src="item.logo" mode=""></image>
+					<text class="rank-other-item-main-text">{{item.project_name}}</text>
+				</view>
+				<view class="rank-other-item-right">
+					<image style="width: 26rpx;height: 24rpx; margin-right: 8rpx; " src="/static/icon/votes02.png"
+						mode=""></image>
+					<text>{{item.ticket_num + item.virtual_ticket_num }}</text>
+				</view>
+			</view>
+		</view>
+
+		<view class="introduce" v-if="isActive==2">
+
+			<view class="introduce-top">
+				<text class="introduce-top-rule1"></text>
+				<text style="margin-right:  8rpx; margin-left: 12rpx; ">活动规则</text>
+				<text class="introduce-top-rule2"></text>
+			</view>
+			<view class="introduce-main">
+				<view v-html="activeDeatil.rule"></view>
+			</view>
+
+			<!-- 分割线 -->
+			<view
+				style="width: 94%; height: 2rpx; background-color:rgba(240, 240, 240, .7);margin: 64rpx auto 80rpx;  ">
+			</view>
+			<view class=" introduce-top">
+				<text class="introduce-top-rule1"></text>
+				<text style="margin-right:  8rpx; margin-left: 12rpx; ">活动介绍</text>
+				<text class="introduce-top-rule2"></text>
+			</view>
+			<view class="introduce-btn-text">
+				<view v-html="activeDeatil.details"></view>
+			</view>
+			<!-- 分割线 -->
+			<view
+				style="width: 94%; height: 2rpx; background-color:rgba(240, 240, 240, .7);margin: 64rpx auto 80rpx;  ">
+			</view>
+			<view class=" introduce-top">
+				<text class="introduce-top-rule1"></text>
+				<text style="margin-right:  8rpx; margin-left: 12rpx; ">活动声明</text>
+				<text class="introduce-top-rule2"></text>
+			</view>
+			<!-- 声明 -->
+			<view class="introduce-btn">
+				<view v-html="activeDeatil.statement"></view>
+			</view>
+
+		</view>
+		<!-- 触底 -->
+		<view class="home-bottom" v-if="isActive==0">
+			<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText" />
+		</view>
+	</view>
+</template>
+
+<script>
+	import util from './../../../utils/util.js'
+	export default {
+		data() {
+			return {
+				//自定义导航栏
+				bgColor: '#fff',
+				title: '',
+				//排行榜
+				rankItemList: [],
+
+				//活动结束倒计时
+				endTime: '',
+				countdownd:"",
+				countdownh: '',
+				countdownm: '',
+				countdowns: '',
+				timer: null, //重复执行
+
+				// 搜索
+				search: '',
+				// 活动id
+				id: '',
+				// 活动详情
+				activeDeatil: '',
+				// 投票列表
+				voteList: [],
+				//酒店排名背景图片
+				hotelImageUrl: require('../../../static/icon/tip01.png'),
+				//排行榜背景图片
+				backImageUrl: 'http://t9.9026.com/imgs/rank01.png',
+				rankList: [{
+						title: '投票'
+					},
+					{
+						title: '排行榜'
+					}, {
+						title: '活动介绍'
+					}
+				],
+				areaList: [],
+				//激活指定table菜单
+				isActive: 0,
+				isActiveArea: 0,
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+			}
+		},
+
+		onShow() {
+			this.admin = this.$store.getters.userInfo
+			console.log(this.admin);
+		},
+		onLoad(o) {
+			this.id = o.id
+			this.getList(o.id)
+			this.getActiveDetail(o.id)
+			this.getCategoryList(o.id)
+		},
+		onUnload(){
+			clearInterval(this.timer)
+		},
+		methods: {
+			//返回上一级
+			back() {
+				uni.navigateBack()
+			},
+
+			showtime(time) {
+				let nowtime = new Date(), //获取当前时间
+					// endtime = new Date("2021/12/10"); //定义结束时间
+					endtime = new Date(time); //定义结束时间
+				// let lefttime = endtime.getTime() - nowtime.getTime(), //距离结束时间的毫秒数
+				// 	leftd = Math.floor(lefttime / (1000 * 60 * 60 * 24)), //计算天数
+				// 	lefth = Math.floor((lefttime / (1000 * 60 * 60) % 24) + leftd * 24) < 10 ? "0" + Math.floor((lefttime /
+				// 		(1000 * 60 * 60) % 24) + leftd * 24) : Math.floor((lefttime / (1000 * 60 * 60) % 24) + leftd *
+				// 		24), //计算小时数
+				// 	leftm = Math.floor(lefttime / (1000 * 60) % 60) < 10 ? "0" + Math.floor(lefttime / (1000 * 60) % 60) :
+				// 	Math.floor(lefttime / (1000 * 60) % 60), //计算分钟数
+				// 	lefts = Math.floor(lefttime / 1000 % 60) < 10 ? "0" + Math.floor(lefttime / 1000 % 60) : Math.floor(
+				// 		lefttime / 1000 % 60); //计算秒数
+				
+				const lefttime = (endtime.getTime() - nowtime.getTime()) / 1000;
+				const leftd =  Math.floor(lefttime / (60 * 60 * 24));
+				const lefth = Math.floor((lefttime - leftd * 86400) / (60 * 60));
+				const leftm = Math.floor((lefttime - leftd * 86400 - lefth * 3600) / 60);
+				const lefts =  Math.floor(lefttime - leftd * 86400 - lefth * 3600 - leftm*60);
+				
+				this.countdownd = leftd 
+				this.countdownh = lefth //返回倒计时的字符串
+				this.countdownm = leftm //返回倒计时的字符串
+				this.countdowns = lefts //返回倒计时的字符串
+				// 倒计时结束时,显示00:00:00
+				if (lefttime < 0) {
+					this.countdownh = this.countdownm = this.countdowns = "00"
+				}
+
+			},
+			// 获取活动项目列表
+			getList(id) {
+				this.$api.active.getActiveProjectList({
+					activity_id: id,
+					page: 0,
+				}).then(res => {
+					console.log(res, "活动项目列表")
+					if (res.code == 0) {
+						this.voteList = JSON.parse(JSON.stringify(res.data.data))
+						this.rankItemList = res.data.data.sort((a, b) => {
+							return (b.ticket_num + b.virtual_ticket_num) - (a.ticket_num + a
+								.virtual_ticket_num)
+						})
+						console.log(this.rankItemList, '--->rankItemList');
+					}
+				})
+			},
+			// 获取活动详情
+			getActiveDetail(id) {
+				this.$api.active.getActiveDetail({
+					activity_id: id
+				}).then(res => {
+					console.log(res, "活动详情")
+					if (res.code == 0) {
+						this.title = res.data.title
+						this.activeDeatil = res.data
+						
+						// this.endTime = res.data.end_time
+						this.endTime = (()=>{
+							const endT = res.data?.end_time ? res.data.end_time : "";
+							return endT.replace(/-/g, "/");
+						})()
+						
+						this.timer = setInterval(() => {
+							this.showtime(this.endTime)
+						}, 100);
+					}
+				})
+			},
+			// 获取活动投票项分类
+			getCategoryList(id) {
+				this.$api.category.getCategoryList({
+					page: 1,
+					type: 3,
+					activity_id: id
+				}).then(res => {
+					console.log(res, "活动投票项分类")
+					if (res.code == 0) {
+						this.areaList = res.data.data
+						console.log(this.areaList, '---->this.areaList');
+						this.areaList.unshift({
+							name: '全部'
+						})
+					}
+				})
+			},
+			//获取地区的投票项
+			getAreaList(category_id) {
+				this.$api.active.getActiveProjectList({
+					activity_id: this.id,
+					category_id,
+					page: 0,
+				}).then(res => {
+					if (res.code == 0) {
+						this.voteList = res.data.data
+					}
+				})
+			},
+
+
+			//购票详情
+			goVoteDetail(id) {
+				if (this.admin == undefined) {
+					uni.navigateTo({
+						url: '/pages/login/login'
+					})
+				} else {
+					uni.navigateTo({
+						url: '/pages/index/vote-detail/index?id=' + id
+					})
+				}
+
+			},
+			// 搜索防抖
+			searchText: util.debounce(function() {
+				this.goSearch()
+			}, 1000),
+			// 搜索
+			goSearch() {
+				this.$api.active.getActiveProjectList({
+					activity_id: this.id,
+					page: 0,
+					keyword: this.search
+				}).then(res => {
+					console.log(res, "搜索活动项目列表")
+					if (res.code == 0) {
+						this.voteList = res.data.data
+						//回到地区分类全部
+						this.isActiveArea = 0
+					}
+				})
+			},
+			//投票/排行榜/活动介绍切换
+			checked(index) {
+				this.isActive = index
+			},
+			//地区分类切换
+			checkedArea(index, id) {
+				this.isActiveArea = index
+				if (index == 0) {
+					this.getList(this.id)
+				} else {
+					this.getAreaList(id)
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.active-detail {
+		height: 100%;
+		background: #F9F9F9;
+	}
+
+	.home-bottom {
+		background-color: #fff;
+		padding-bottom: 84rpx;
+	}
+
+	.rank-search {
+		margin-top: 80rpx;
+
+		::v-deep .u-input {
+			width: 690rpx !important;
+			height: 68rpx !important;
+			background: #F1F1F1;
+			border-radius: 74rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper {
+			padding-left: 36rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper__field {
+			color: #999999 !important;
+			font-size: 28rpx !important;
+		}
+	}
+
+
+	.introduce {
+		width: 100%;
+		background-color: #fff;
+		position: relative;
+		top: -176rpx;
+		padding-bottom: 50rpx;
+		position: relative;
+
+		.introduce-top {
+			height: 32rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			font-size: 32rpx;
+			font-weight: bold;
+			letter-spacing: 2rpx;
+
+			.introduce-top-rule1 {
+				width: 56rpx;
+				height: 4rpx;
+				background: linear-gradient(90deg, #FFFFFF 0%, #D9A94D 100%);
+			}
+
+			.introduce-top-rule2 {
+				width: 56rpx;
+				height: 4rpx;
+				background: linear-gradient(-90deg, #FFFFFF 0%, #D9A94D 100%);
+			}
+		}
+
+		.introduce-main {
+			margin-top: 46rpx;
+			padding: 0 30rpx;
+			font-size: 28rpx;
+			font-weight: bold;
+			color: #333;
+
+			.introduce-main-start {
+				margin-bottom: 24rpx;
+			}
+
+			.introduce-main-rule {
+				display: flex;
+				align-items: flex-start;
+				justify-content: flex-start;
+
+				.introduce-main-rule-left {
+					display: flex;
+					flex-direction: column;
+					align-items: flex-start;
+					justify-content: flex-start;
+					margin-left: 75rpx;
+				}
+			}
+		}
+
+		.introduce-btn-text {
+			padding: 0 30rpx;
+			margin-top: 40rpx;
+			// text-indent: 2em;
+			font-size: 28rpx;
+			color: #333;
+			font-weight: bold;
+			line-height: 56rpx;
+		}
+
+		.introduce-btn {
+			margin-top: 40rpx;
+			padding: 0 30rpx;
+			padding-bottom: 80rpx;
+			width: 100%;
+			display: flex;
+			font-size: 28rpx;
+			color: #333;
+			font-weight: bold;
+		}
+	}
+
+
+	//地区切换
+	.tab_area {
+		margin-top: 48rpx;
+		width: 100%;
+		display: flex;
+		justify-content: flex-start;
+		align-items: center;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		overflow-x: scroll;
+	}
+
+	.area_nav .areaTitle {
+		width: 140rpx;
+		height: 52rpx;
+		background-color: #F1F1F1;
+		border-radius: 26rpx;
+		flex: none;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+
+	}
+
+	.areaTitle-item {
+		width: 140rpx;
+		height: 52rpx;
+		background-color: #F1F1F1;
+		border-radius: 26rpx;
+		font-size: 24rpx;
+		color: #999;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		margin-right: 16rpx;
+
+	}
+
+	.active-area {
+		width: 100%;
+		height: 52rpx;
+		border-radius: 26rpx;
+		background-color: #FF6200;
+		color: #fff;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+
+
+	.rank {
+		height: 340rpx;
+		background-color: #fff;
+		padding: 40rpx 30rpx 0;
+
+		//菜单切换
+		.tab_nav {
+			width: 100%;
+			display: flex;
+			justify-content: space-around;
+			align-items: center;
+			font-family: PingFang-SC-Heavy, PingFang-SC;
+		}
+
+		.tab_nav .navTitle {
+			width: 30%;
+			flex: none;
+			font-size: 32rpx;
+			color: #666;
+			position: relative;
+			display: flex;
+			justify-content: center;
+			align-items: center;
+		}
+
+		.navTitle-item {
+			height: 40rpx;
+		}
+
+		.active {
+			color: #333333;
+			font-weight: bold;
+			font-size: 40rpx;
+
+			&::after {
+				display: inline-block;
+				content: '';
+				width: 156rpx;
+				height: 24rpx;
+				background: linear-gradient(180deg, rgba(249, 231, 219, 0) 0%, #F3C063 100%);
+				border-radius: 12rpx;
+				position: absolute;
+				bottom: -22rpx;
+				left: 25rpx;
+			}
+		}
+	}
+
+	.vote {
+		height: 322rpx;
+		background-color: #fcfcfd;
+
+		.vote-detail {
+			position: relative;
+			top: -40rpx;
+			margin: 0 auto;
+			width: 690rpx;
+			height: 310rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 20rpx 40rpx 0px rgba(220, 222, 229, 0.4);
+			border-radius: 16rpx;
+			padding: 40rpx 26rpx 0;
+
+			.vote-detail-top {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+
+				.vote-detail-top-main {
+					flex: 1;
+					margin-left: 20rpx;
+					color: #333;
+					font-size: 28rpx;
+					display: flex;
+					align-items: center;
+					justify-content: flex-start;
+
+					.time {
+						display: flex;
+						align-items: center;
+						justify-content: flex-start;
+					}
+				}
+			}
+
+			.vote-detail-btn {
+				margin-top: 75rpx;
+				padding: 0 38rpx;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+
+				.vote-detail-btn-item {
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+					justify-content: space-between;
+					font-size: 28rpx;
+					color: #333;
+
+					.vote-detail-btn-item-num {
+						font-size: 44rpx;
+						font-weight: bold;
+					}
+
+					.vote-detail-btn-item-text {
+						margin-top: 20rpx;
+					}
+				}
+			}
+		}
+	}
+
+	.active-detail-img {
+		width: 100%;
+		height: 720rpx;
+	}
+
+	.rank-detail {
+		width: 100%;
+		height: 592rpx;
+		position: relative;
+		top: -176rpx;
+		background-repeat: no-repeat;
+		background-position: center;
+		background-size: cover;
+
+		.rank-detail-rank {
+			position: relative;
+			top: 80rpx;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+
+			.rank-detail-rank-text {
+				width: 182rpx;
+				height: 76rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				text-align: center;
+				font-size: 26rpx;
+				color: #333;
+				margin: 16rpx 0 52rpx;
+			}
+
+			.rank-detail-rank-data {
+				width: 136rpx;
+				height: 56rpx;
+				background: #141414;
+				border-radius: 8rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-size: 24rpx;
+				font-weight: bold;
+				color: #fff;
+			}
+		}
+
+		.rank-detail-rankS {
+			position: relative;
+			top: -155rpx;
+			left: -230rpx;
+		}
+
+		.rank-detail-rankT {
+			position: relative;
+			top: -390rpx;
+			left: 230rpx;
+		}
+	}
+
+	.rank-other {
+		position: relative;
+		top: -204rpx;
+		width: 100%;
+		padding: 48rpx 30rpx 80rpx;
+		background-color: #fff;
+		border-radius: 32rpx 32rpx 0px 0px;
+
+		.rank-other-item {
+			margin-bottom: 24rpx;
+			padding: 0 24rpx;
+			height: 176rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 4rpx 24rpx -10rpx rgba(101, 95, 90, 0.3);
+			border-radius: 16rpx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.rank-other-item-left {
+				width: 48rpx;
+				height: 48rpx;
+				border: 3rpx solid #E6E6E6;
+				border-radius: 50%;
+				font-size: 24rpx;
+				color: #858494;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+
+			.rank-other-item-main {
+				flex: 1;
+				display: flex;
+				align-items: center;
+				justify-content: flex-start;
+
+				.rank-other-item-main-text {
+					width: 282rpx;
+					height: 80rpx;
+					font-size: 28rpx;
+					color: #333;
+					line-height: 40rpx;
+					margin-top: 40rpx;
+				}
+			}
+
+			.rank-other-item-right {
+				width: 132rpx;
+				height: 48rpx;
+				background: rgba(255, 98, 0, 0.22);
+				border-radius: 24rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-size: 24rpx;
+				color: #FF6200;
+				font-weight: bold;
+			}
+		}
+	}
+
+
+
+
+	.List {
+		padding: 0 30rpx;
+		padding-top: 20rpx;
+		padding-bottom: 32rpx;
+
+		.ListItem {
+			position: relative;
+			margin-bottom: 40rpx;
+			width: 100%;
+			height: 665rpx;
+			background: $bgColor;
+			box-shadow: 0rpx 12rpx 40rpx 0rpx rgba(220, 222, 229, 0.4);
+			border-radius: 24rpx;
+			padding: 20rpx 26rpx 26rpx 24rpx;
+
+			.kudosicon {
+				background-repeat: no-repeat;
+				background-size: 36rpx 52rpx;
+				position: absolute;
+				top: 20rpx;
+				left: 60rpx;
+
+				@include flexlayout() image {
+					width: 32rpx;
+					height: 28rpx;
+				}
+			}
+
+			.nav {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+
+				.events {
+					text {
+						margin-top: 10rpx;
+						font-size: 30rpx;
+						font-family: PingFang-SC-Bold, PingFang-SC;
+						font-weight: bold;
+						color: #333333;
+					}
+				}
+
+				.voteStatus {
+					width: 126rpx;
+					height: 48rpx;
+					background: #FFFFFF;
+					border-radius: 6rpx;
+					border: 2rpx solid #A18353;
+					font-size: 30rpx;
+					color: #A18353;
+					margin-top: 20rpx;
+					display: flex;
+					align-items: center;
+					justify-content: center;
+				}
+			}
+
+			.foot {
+				margin-top: 24rpx;
+				width: 100%;
+				height: 84rpx;
+				background: linear-gradient(338deg, #FF6200 0%, #FF9D4F 100%);
+				border-radius: 12rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-weight: bold;
+				color: #fff;
+			}
+
+		}
+	}
+	
+	.vote-detail-top-main1{
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+		height:22px;
+		line-height: 22px;
+		
+		&::before,&::after{
+			content: " ";
+			height: 0.5px;
+			width: 80rpx;
+			background-color: rgba(0,0,0,0.2);
+		}
+		
+		>view{
+			width: 250px;
+			font-size: 30rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			
+			text{
+				width: 22px;
+				margin-left: 15px;
+				height:inherit;
+				line-height: inherit;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				border-radius: 3px;
+				background-color: #000;
+				color: #fff;
+				
+				&::before{
+					content: ":";
+					width: 0px;
+					line-height: inherit;
+					background-color: transparent;
+					color: rgba(0,0,0,0.7);
+					transform: translateX(-11px);
+				}
+			}
+		}
+		
+		
+	}
+</style>

+ 339 - 0
pages/index/active-list/index.vue

xqd
@@ -0,0 +1,339 @@
+<template>
+	<view class="active-list">
+		<!-- 活动查询 -->
+		<view class="active-list-search">
+			<!-- 搜索框 -->
+			<view class="search">
+				<u-input placeholder="输入活动名称或参赛项目" border='none' v-model="search" @input="searchText">
+					<template slot="suffix" style='margin-right:40rpx;'>
+						<u-image :showLoading="true" :showError='true' src="/static/icon/search.png" width="40rpx"
+							height="32rpx"></u-image>
+					</template>
+				</u-input>
+			</view>
+			<view class="tab_nav">
+				<view class="navTitle" v-for="(item,index) in items" :key="index">
+					<view :class="{'active':isActive === index}" @click="checked(index,item.id)">
+						{{item.name}}
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="List">
+			<view class="ListItem" v-for="(item,index) in List" :key="index"  @click="activeDetail(item.id)">
+				<image :src="item.banners?item.cover_img:'http://t9.9026.com/imgs/Kudosbg.png'" style="width: 640rpx;height:420rpx;border-radius: 12rpx;"></image>
+				<view class="kudosicon" @click.stop="kudosActive(item.id,index)">
+					<image src="/static/icon/Kudos.png" v-if="item.is_like==0"></image>
+					<image src="/static/icon/Kudos(1).png" v-if="item.is_like==1"></image>
+				</view>
+				<view class="nav">
+					<view class="events">
+						<text>{{item.title}}</text>
+					</view>
+					<view class="voteStatus" style="width: 100rpx;">
+						<text style="font-size: 30rpx;color: #999;" v-if="item.activity_status==1">未开始</text>
+						<text style="font-size: 30rpx;color: #FF6503;" v-if="item.activity_status==2">进行中</text>
+						<text style="font-size: 30rpx;color: #999;" v-if="item.activity_status==3">已结束</text>
+					</view>
+				</view>
+				<view class="foot">
+					<image src="/static/icon/data.png"></image>
+					<text>{{item.end_time}} 结束</text>
+				</view>
+			</view>
+		</view>
+
+		<!-- 触底 -->
+		<view class="home-bottom">
+			<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText"/>
+		</view>
+	</view>
+</template>
+
+<script>
+	import util from '@/utils/util.js'
+	export default {
+		data() {
+			return {
+				//活动分类categoryId
+				categoryId:'',
+				// 搜索
+				search:'',
+				//分段器
+				items: [{
+						name: '热门活动'
+					},
+					{
+						name: '西区活动'
+					}, {
+						name: '酒店评选'
+					},
+					{
+						name: '旅游推选'
+					}
+				],
+				//激活指定table菜单
+				isActive: 0,
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				// 活动列表
+				List:[],
+			}
+		},
+		onLoad() {
+			// this.getList()
+			this.getCategoryList()
+			console.log(util,"until")
+		},
+		methods: {
+			// 获取活动列表
+			getList(category_id){
+				this.$api.active.getActiveList({
+					page:0,
+					keyword:'',
+					category_id:`${category_id}`
+				}).then(res=>{
+					console.log(res,'活动列表')
+					if(res.code==0){
+						this.List=res.data.data
+						console.log(this.List,'--->this.List');
+					}
+				})
+			},
+			// 获取分类列表
+			getCategoryList(){
+				this.$api.category.getCategoryList({
+					page:1,
+					type:1
+				}).then(res=>{
+					console.log(res,"活动分类列表")
+					if(res.code==0){
+						this.items=res.data.data
+						this.categoryId = this.items[0].id
+						console.log(this.categoryId,'--->this.categoryId');
+						this.getList(this.categoryId)
+					}
+				})
+			},
+			// 点赞活动
+			kudosActive(id,index){
+				let beforeLike=this.List[index].is_like
+				this.$api.active.kudos({
+					activity_id:id
+				}).then(res=>{
+					console.log(res,'点赞')
+					if(res.code==0){
+						if(beforeLike==1){
+							this.List[index].is_like=0
+						}else{
+							this.List[index].is_like=1
+						}
+					}
+				})
+			},
+			//菜单index切换
+			checked(index,id) {
+				this.isActive = index
+				this.getList(id)
+				console.log(this.isActive,'---->this.isActive');
+			},
+			// 活动详情页
+			activeDetail(id){
+				uni.navigateTo({
+					url:'/pages/index/active-detail/index?id='+id
+				})
+			},
+			// 搜索防抖
+			searchText:util.debounce(function(){
+				if(this.search !=''){
+					this.goSearch()
+				}else{
+					this.getList(this.categoryId)
+				}
+			},1000),
+			//搜索
+			goSearch(){
+				uni.showLoading({
+					title:'加载中'
+				})
+				this.$api.active.getActiveList({
+					page:1,
+					keyword:this.search,
+					category_id:''
+				}).then(res=>{
+					if(res.code==0){
+						uni.hideLoading()
+						this.List=res.data.data
+						console.log(this.List,'--->this.list');
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.active-list {
+		height: 100%;
+		background: #F9F9F9;
+	}
+	
+	.home-bottom {
+		background-color: #f9f9f9;
+		padding-bottom: 84rpx;
+	}
+
+	.active-list-search {
+		padding: 24rpx 30rpx 32rpx;
+		height: 222rpx;
+		background-color: #FFFFFF;
+		width: 100%;
+		position: fixed;
+		top: 0;
+		z-index: 99;
+
+		// 搜索
+		.search {
+			::v-deep .u-input {
+				width: 690rpx !important;
+				height: 68rpx !important;
+				background: #F1F1F1;
+				border-radius: 74rpx;
+			}
+
+			::v-deep .u-input__content__field-wrapper {
+				padding-left: 36rpx;
+			}
+			::v-deep .u-input__content__field-wrapper__field{
+				color:#999999 !important;
+				font-size: 28rpx !important;
+			}
+		}
+
+		//菜单切换
+		.tab_nav {
+			width: 100%;
+			margin-top: 32rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			font-family: PingFang-SC-Heavy, PingFang-SC;
+			
+		}
+
+		.tab_nav .navTitle {
+			width: 150rpx;
+			flex: none;
+			height: 28rpx;
+			font-size: 32rpx;
+			color: #666;
+			position: relative;
+		}
+		.active {
+			color: #D9A94D;
+			font-weight: bold;
+			&::after {
+				display: inline-block;
+				content: '';
+				width: 48rpx;
+				height: 12rpx;
+				background: linear-gradient(90deg, #F3D69F 0%, #D9A94D 100%);
+				border-radius: 6px;
+				position: absolute;
+				bottom:-40rpx;
+				left:40rpx;
+			}
+		}
+
+	}
+
+	.List {
+		padding: 0 30rpx;
+		box-sizing: border-box;
+		padding-top: 20rpx;
+		padding-bottom:88rpx ;
+		background-color: #F9F9F9;
+		margin-top: 222rpx; 
+
+		.ListItem {
+			position: relative;
+			margin-bottom: 24rpx;
+			width: 100%;
+			height: 562rpx;
+			background: #F9F9F9;
+			box-shadow: 0rpx 12rpx 40rpx 0rpx rgba(220, 222, 229, 0.4);
+			border-radius: 24rpx;
+			padding: 20rpx 26rpx 26rpx 24rpx;
+			.kudosicon {
+				width: 48rpx;
+				height: 48rpx;
+				position: absolute;
+				top: 52rpx;
+				right: 58rpx;
+				border-radius: 50%;
+				background: #FFFFFF;
+				opacity: 0.84;
+				@include flexlayout() image {
+					width: 32rpx;
+					height: 28rpx;
+				}
+			}
+
+			.nav {
+				display: flex;
+				align-items: flex-start;
+				justify-content: space-between;
+
+				.events {
+					text {
+						font-size: 30rpx;
+						font-family: PingFang-SC-Bold, PingFang-SC;
+						font-weight: bold;
+						color: #333333;
+					}
+				}
+
+				.voteStatus {
+					font-size: 30rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #999999;
+				}
+			}
+
+			.foot {
+				margin-top: 10rpx;
+				display: flex;
+				align-items: center;
+
+				image {
+					width: 28rpx;
+					height: 28rpx;
+					margin-right: 8rpx;
+				}
+
+				text {
+					font-size: 24rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #999999;
+					display: block;
+				}
+			}
+
+		}
+	}
+</style>

+ 1125 - 0
pages/index/index.vue

xqd
@@ -0,0 +1,1125 @@
+<template>
+	<view class="home">
+		<MyNav title="洲际酒店集团中国西区" bgColor="" :backIcon="false"></MyNav>
+		<!-- swiper -->
+		<view class="home-swiper">
+			<uni-swiper-dot :info="infoList" :current="current1" :mode="mode" :dots-styles="dotsStyles">
+				<swiper class="swiper-box" @change="change1" circular>
+					<swiper-item v-for="(item ,index) in infoList" :key="index">
+						<view class="swiper-item" v-if="item.resource_type == 1"
+							@click="goSwiperSmall(item.jump_type,item.jump_config)">
+							<image style="width: 100%;height:592rpx;" :src="item.img" mode="aspectFill"></image>
+						</view>
+						<view class="swiper-item" v-if="item.resource_type == 2">
+							<video id="swiperVideo" ref="swiperVideo" style="width: 100%; height: 592rpx;"
+								:src="item.video_url" controls :enable-progress-gesture="false">
+							</video>
+						</view>
+					</swiper-item>
+				</swiper>
+			</uni-swiper-dot>
+		</view>
+
+		<!-- 金刚图 -->
+		<view class="home-nav">
+			<view class="home-nav-item" v-for="(item,index) in navList" :key="index"
+				@click="goOther(index,item.jump_type,item.jump_config)">
+				<image style="width: 101.96rpx;height: 103.96rpx;" :src="item.img" mode=""></image>
+				<text style="color: #333;font-size: 24rpx;margin-top: 18rpx; ">{{item.title}}</text>
+			</view>
+		</view>
+
+		<!-- 活动专区 -->
+		<view class="home-special-area">
+			<view class="home-special-area-left">
+				<text>非凡西区</text>
+				<view class="text-shadow"></view>
+				<image style="width:16rpx;height: 16rpx;margin-left: 14rpx;" src="/static/icon/symbol.png" mode="">
+				</image>
+			</view>
+			<view @click="goSpecialList" class="home-special-area-right">
+				<text>全部</text>
+				<image style="width: 12rpx; height: 20rpx;margin-left: 8rpx;" src="/static/icon/right01.png" mode="">
+				</image>
+			</view>
+		</view>
+
+		<!-- 活动图片 -->
+		<view class="home-special-img">
+			<view class="ListItem" v-for="(item,index) in specialList" :key="index" @click="activeDetail(item.id)">
+				<image style="width: 312rpx;height: 200rpx; border-radius: 12rpx; "
+					:src="item.banners?item.cover_img:'http://t9.9026.com/imgs/Kudosbg.png'" mode=""></image>
+				<view class="kudosicon" @click.stop="kudosActive(item.id,index)">
+					<image style="width:24rpx;height: 24rpx;" src="/static/icon/Kudos.png" v-if="item.is_like==0">
+					</image>
+					<image style="width:24rpx;height: 24rpx;" src="/static/icon/Kudos(1).png" v-if="item.is_like==1">
+					</image>
+				</view>
+				<text style="color: #333;font-weight: bold;font-size: 28rpx;">{{item.title}}</text>
+			</view>
+		</view>
+
+		<!-- 广告图 -->
+		<view class="home-banner" v-if="!isShowAdver">
+			<view class="home-banner-img" v-if="in_page==1 && type == 1 ">
+				<image style="width: 100%; height: 576rpx; border-radius: 12rpx;" :src="advertisImg" mode=""></image>
+				<image @click="cleanCoverImg" class="img-clean" style="width: 20rpx; height: 20rpx; "
+					src="/static/icon/clean.png" mode="">
+				</image>
+			</view>
+			<view class="home-banner-img" v-if="in_page==1 && type == 2">
+				<image class="banner-img" v-if="!isOpenVideo" @click="openVideoPlay"
+					style="width: 100%; height: 576rpx; border-radius: 12rpx;" :src="videoCoverImg" mode=""></image>
+				<image @click="cleanCoverImg" class="img-clean" style="width: 20rpx; height: 20rpx; "
+					src="/static/icon/clean.png" mode="">
+				</image>
+				<video class="baner-video" id="myVideo" ref="myVideo"
+					style="width: 100%; height: 576rpx;border-radius: 12rpx; " :src="videoSrc" controls
+					:enable-progress-gesture="false">
+				</video>
+			</view>
+		</view>
+
+		<movable-area class="movableArea">
+			<movable-view class="movableView" direction="all" x="630rpx" y="700rpx">
+				<view class="img-IHg" @click="goJoin">
+					<image style="width: 64rpx; height: 58rpx; " src="/static/icon/vip.png" mode=""></image>
+				</view>
+			</movable-view>
+		</movable-area>
+
+		<!-- 广告的附图 -->
+		<view class="home-attach" @click="goH5">
+			<image style="width: 690rpx;height: 156rpx;border-radius: 79rpx;" :src="advertisInsetImg" mode=""></image>
+		</view>
+		<!-- 酒店推荐 -->
+		<view class="home-hotel home-special-area">
+			<view class="home-special-area-left">
+				<text>西区优品</text>
+				<view class="text-shadow"></view>
+				<image style="width:16rpx;height: 16rpx;margin-left: 14rpx;" src="/static/icon/symbol.png" mode="">
+				</image>
+			</view>
+		</view>
+
+		<!-- 酒店推荐图片 -->
+		<view class="home-hotel-img">
+			<view class="home-hotel-img-content">
+				<view class="home-hotel-img-content-item" v-for="(item,index) in goodsList" :key="index"
+					:style="{marginTop:item.marginTop || 0 }">
+					<image class="home-hotel-img-content-item-img"
+						:class="item.short?'home-hotel-img-content-item-img': 'home-hotel-img-content-item-img-long' "
+						:src="item.img" mode=""></image>
+					<view class="text">
+						<text class="text-top">{{item.text}}</text>
+						<text class="text-main">{{item.title}}</text>
+					</view>
+				</view>
+			</view>
+			<view class="home-hotel-img-more" @click="goProduceList">
+				<text>查看更多商品</text>
+			</view>
+		</view>
+		<!-- 酒店品牌 -->
+		<view class="home-brand home-special-area">
+			<view class="home-special-area-left">
+				<text>洲际酒店集团品牌</text>
+				<view class="text-shadow"></view>
+				<image style="width:16rpx;height: 16rpx;margin-left: 14rpx;" src="/static/icon/symbol.png" mode="">
+				</image>
+			</view>
+		</view>
+		<!-- 酒店品牌图片 -->
+		<view class="home-brand-img">
+			<uni-swiper-dot :info="info" mode="default" :current="current2" :dots-styles="dotsStylesBand">
+				<swiper class="swiper-box" circular @change="change2">
+					<swiper-item v-for="(items ,index) in info" :key="index">
+						<view v-for="(item ,j) in items" :key="j" class="swiper-item"
+							@click="goGoodsDetail(item.jump_type,item.jump_config)">
+							<image style="width:144rpx;height:142rpx;" :src="item.img" mode="aspectFill"></image>
+						</view>
+					</swiper-item>
+				</swiper>
+			</uni-swiper-dot>
+		</view>
+		<!-- 触底 -->
+		<view class="home-bottom">
+			<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText" />
+		</view>
+
+		<!-- 弹窗广告 -->
+		<uni-popup ref="popup" type="center">
+			<view class="popup-banner">
+				<image @click="goPopup" style="width: 656rpx;height: 916rpx;border-radius: 12rpx;" :src="popupImg">
+				</image>
+				<view class="popup-banner-clean" @click='closePopupBanner'>
+					<image style="width: 20rpx; height: 20rpx; " src="/static/icon/clean.png" mode="">
+				</view>
+			</view>
+
+		</uni-popup>
+		<view style="height:168rpx; background-color: #f9f9f9; "></view>
+		<tab-bar></tab-bar>
+	</view>
+
+</template>
+
+<script>
+	import TabBar from '../../components/TabBar/tabbar.vue'
+	import SwiperBox from '../../components/SwiperBox/index.vue'
+	import MyNav from "@/components/my-nav/my-nav.vue"
+	export default {
+		components: {
+			TabBar,
+			SwiperBox,
+			MyNav
+		},
+		data() {
+			return {
+				//用户个人信息,判断是否登录
+				admin: '',
+				//获取token
+				data: {},
+				//录播图是展示视频1:图片2:视频
+				resource_type: '',
+				//广告弹框跳转
+				jup_type: '',
+				jump_config: '',
+				//广告弹框图
+				popupImg: '',
+				//弹窗的类型 1只弹一次首次  2就是每次都弹啊
+				times_type:'',
+				//弹窗的显示0不显示 1显示
+				popupImgStatus:'',
+				//视频封面图
+				isOpenVideo: false,
+				videoCoverImg: '',
+				videoSrc: '',
+				in_page: '',
+				type: '',
+				//隐藏广告图
+				isShowAdver: false,
+				//广告图
+				advertis: '',
+				//广告附图展示图片
+				advertisInsetImg: '',
+				//广告图展示图片:
+				advertisImg: '',
+				//广告图展示视频
+				goodsList: [{
+						img: 'http://t9.9026.com/imgs/goodsimg01.png',
+						text: '中秋佳节五仁月饼,惊喜特供,限时抢购',
+						title: '环球洲际',
+						short: '',
+					},
+					{
+						img: 'http://t9.9026.com/imgs/goodsimg02.png',
+						text: '中秋佳节五仁月饼,惊喜特供,限时抢购',
+						title: '环球洲际'
+					},
+					{
+						img: 'http://t9.9026.com/imgs/goodsimg02.png',
+						text: '中秋佳节五仁月饼,惊喜特供,限时抢购',
+						title: '环球洲际'
+					},
+					{
+						img: 'http://t9.9026.com/imgs/goodsimg01.png',
+						text: '中秋佳节五仁月饼,惊喜特供,限时抢购',
+						title: '环球洲际',
+					},
+
+				],
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				infoList: [],
+				//轮播图
+				info: [],
+				dotsStyles: {
+					bottom: 24,
+					backgroundColor: 'rgba(255, 255, 255, .3)',
+					border: '1px rgba(255, 255, 255, .3) solid',
+					color: '#fff',
+					selectedBackgroundColor: 'rgba(255, 255, 255, 1)',
+					selectedBorder: '1px rgba(255, 255, 255, 1) solid'
+				},
+				dotsStylesBand: {
+					bottom: -24,
+					backgroundColor: 'rgba(198, 198, 198, 1)',
+					border: '1px rgba(0, 0, 0, .3) solid',
+					color: '#fff',
+					selectedBackgroundColor: 'rgba(151, 151, 151, 1)',
+					selectedBorder: '1px rgba(0, 0, 0, .9) solid'
+				},
+				//指示点显示位置
+				current1: 0,
+				current2: 0,
+				//指示点模式
+				mode: 'dot',
+				// 金刚图
+				navList: [],
+				//活动专区
+				specialList: []
+			}
+		},
+		// 下拉刷新
+		onPullDownRefresh() {
+			let _this = this
+			setTimeout(function() {
+				uni.stopPullDownRefresh();
+				_this.$store.dispatch('user/allset', null)
+				_this.getAllSet()
+				_this.getList()
+			}, 1000);
+		},
+		onReady: function(res) {
+			this.videoContext = uni.createVideoContext('myVideo')
+		},
+		onShow() {
+			//获取token
+			this.getmsg()
+			this.admin = this.$store.getters.userInfo
+			console.log(this.admin);
+		},
+		onLoad() {
+			
+			this.shortLong()
+			this.getAllSet()
+
+		},
+		methods: {
+			//合同伙伴跳转h5和小程序
+			goGoodsDetail(id, urls) {
+				console.log(urls, '----->url');
+				if (id == 1) {
+					const url = urls; // 跳转的外链
+					const navtitle = 'H5'; // 这个标题是你自己可以设置的
+					uni.navigateTo({
+						// 跳转到webview页面
+						url: `/pages/webview/webview?url=${url}&nav=${navtitle}`,
+						success: () => {
+							console.log('成功')
+						},
+						fail: (e) => {
+							console.log(e, "失败")
+						}
+					});
+				} else if (id == 2) {
+					let obj = JSON.parse(urls);
+					wx.navigateToMiniProgram({
+						appId: `${obj.appid}`, //appid
+						path: `${obj.path}`, //path
+						extraData: { //参数
+							foo: 'bar'
+						},
+						// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+						success(res) {
+							console.log('成功')
+							// 打开成功
+						},
+						fail(e) {
+							console.log(e, '失败')
+						}
+					})
+				}
+			},
+
+			//弹窗广告跳转小程序/h5/内部其他页面
+			goPopup() {
+				//跳转h5
+				if (this.jump_type == 1) {
+					const url = this.jump_config; // 跳转的外链
+					const navtitle = 'H5'; // 这个标题是你自己可以设置的
+					uni.navigateTo({
+						// 跳转到webview页面
+						url: `/pages/webview/webview?url=${url}&nav=${navtitle}`,
+						success: () => {
+							console.log('成功')
+						},
+						fail: (e) => {
+							console.log(e, "失败")
+						}
+					});
+				} else if (this.jump_type == 2) {
+					let obj = JSON.parse(this.jump_config);
+					wx.navigateToMiniProgram({
+						appId: `${obj.appid}`, //appid
+						path: `${obj.path}`, //path
+						extraData: { //参数
+							foo: 'bar'
+						},
+						// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+						success(res) {
+							console.log('成功')
+							// 打开成功
+						},
+						fail(e) {
+							console.log(e, '失败')
+						}
+					})
+				}
+			},
+
+			//关闭弹框
+			closePopupBanner() {
+				this.$refs.popup.close()
+			},
+			//打开弹框
+			open() {
+				console.log(this.popupImgStatus,this.times_type);
+				// 从本地缓存中同步获取指定 key 对应的内容,用于判断是否是第一次打开应用
+				if(this.popupImgStatus == 1){
+					if(this.times_type == 1){
+						//首次进入弹窗
+						const value = uni.getStorageSync('launchFlag');
+						if (value) {
+							console.log('首次弹窗')
+						} else {
+							// 没有值,跳到引导页,并存储,下次打开就不会进去引导页
+							uni.setStorage({
+								key: 'launchFlag',
+								data: true
+							});
+							this.$refs.popup.open('center')
+						}
+					}else{
+						this.$refs.popup.open('center')//每次都弹
+					}	
+				}else{
+					this.$refs.popup.close()//不显示广告弹框
+				}
+			},
+			//点击视频封面图片,播放视频
+			openVideoPlay() {
+				console.log('播放');
+				this.isOpenVideo = !this.isOpenVideo
+				this.videoContext.play()
+			},
+
+
+			//轮播图跳转h5或者小程序
+			goSwiperSmall(type, config) {
+				//跳转h5
+				if (type == 1) {
+					const url = config; // 跳转的外链
+					const navtitle = 'H5'; // 这个标题是你自己可以设置的
+					uni.navigateTo({
+						// 跳转到webview页面
+						url: `/pages/webview/webview?url=${url}&nav=${navtitle}`,
+						success: () => {
+							console.log('成功')
+						},
+						fail: (e) => {
+							console.log(e, "失败")
+						}
+					});
+				} else if (type == 2) {
+					let obj = JSON.parse(config);
+					wx.navigateToMiniProgram({
+						appId: `${obj.appid}`, //appid
+						path: `${obj.path}`, //path
+						extraData: { //参数
+							foo: 'bar'
+						},
+						// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+						success(res) {
+							console.log('成功')
+							// 打开成功
+						},
+						fail(e) {
+							console.log(e, '失败')
+						}
+					})
+				}
+			},
+
+
+			//隐藏图片
+			cleanCoverImg() {
+				this.isShowAdver = !this.isShowAdver
+			},
+
+			// 活动详情页
+			activeDetail(id) {
+				uni.navigateTo({
+					url: '/pages/index/active-detail/index?id=' + id
+				})
+			},
+			// 点赞活动
+			kudosActive(id, index) {
+				let beforeLike = this.specialList[index].is_like
+				this.$api.active.kudos({
+					activity_id: id
+				}).then(res => {
+					console.log(res, '点赞')
+					if (res.code == 0) {
+						if (beforeLike == 1) {
+							this.specialList[index].is_like = 0
+							uni.showToast({
+								icon: 'none',
+								title: '取消点赞'
+							})
+
+						} else {
+							this.specialList[index].is_like = 1
+							uni.showToast({
+								icon: 'none',
+								title: '点赞成功'
+							})
+						}
+					}
+				})
+			},
+			// 获取活动列表
+			getList() {
+				this.$api.active.getActiveList({
+					page: 0,
+					keyword: '',
+					category_id: ''
+				}).then(res => {
+					console.log(res, '活动列表')
+					if (res.code == 0) {
+						this.specialList = res.data.data
+						console.log(this.specialList, '--->this.specialList');
+					}
+				})
+			},
+
+
+			//获取配置数据
+			getAllSet() {
+				this.$api.document.allSet().then(res => {
+					this.$store.dispatch('user/allset', res.data)
+					this.infoList = this.$store.getters.allset.banners
+					this.navList = this.$store.getters.allset.nav_icon
+					this.info = this.$store.getters.allset.partner
+
+					//广告图
+					this.advertis = this.$store.getters.allset.advertises.filter(item => {
+						return item.in_page == 1
+					})
+					if (this.advertis[0].type == 1) {
+						this.in_page = 1
+						this.type = 1
+						this.advertisImg = this.advertis[0].img
+					} else if (this.advertis[0].type == 2) {
+						this.in_page = 1
+						this.type = 2
+						this.videoCoverImg = this.advertis[0].video_cover
+						this.videoSrc = this.advertis[0].video
+					}
+					//胶囊图
+					this.advertisInset = this.$store.getters.allset.advertises.filter(item => {
+						return item.in_page == 2
+					})
+					this.advertisInsetImg = this.advertisInset[0].img
+					//广告弹框图
+					this.popupImg = this.$store.getters.allset.popup_ads[0].img
+					//弹窗是否展示
+					this.popupImgStatus =  this.$store.getters.allset.popup_ads[0].status
+					this.times_type =  this.$store.getters.allset.popup_ads[0].times_type
+					//广告弹框跳转h5和小程序和内部
+					this.jump_type = this.$store.getters.allset.popup_ads[0].jump_type,
+						this.jump_config = this.$store.getters.allset.popup_ads[0].jump_config
+					console.log(this.jump_type, this.jump_config, '----->this.advertis');
+					this.open()
+				})
+			},
+			shortLong() {
+				this.goodsList.forEach((item, index, arr) => {
+					if (index % 4 === 0) {
+						item.short = true
+					}
+					if (index % 4 === 1) {
+						item.long = true
+					}
+					if (index % 4 === 2) {
+						item.long = true
+						item.marginTop = -68 + "rpx"
+					}
+					if (index % 4 === 3) {
+						item.short = true
+					}
+				})
+				console.log(this.goodsList);
+			},
+
+			//跳转方法
+			jumpHAppID(id, urls) {
+				if (id == 1) {
+					const url = urls; // 跳转的外链
+					const navtitle = 'H5'; // 这个标题是你自己可以设置的
+					uni.navigateTo({
+						// 跳转到webview页面
+						url: `/pages/webview/webview?url=${url}&nav=${navtitle}`,
+						success: () => {
+							console.log('成功')
+						},
+						fail: (e) => {
+							console.log(e, "失败")
+						}
+					});
+				} else if (id == 2) {
+					let obj = JSON.parse(urls);
+					wx.navigateToMiniProgram({
+						appId: `${obj.appid}`, //appid
+						path: `${obj.path}`, //path
+						extraData: { //参数
+							foo: 'bar'
+						},
+						// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+						success(res) {
+							console.log('成功')
+							// 打开成功
+						},
+						fail(e) {
+							console.log(e, '失败')
+						}
+					})
+				} else if (id == 3) {
+					let obj = urls;
+					console.log(obj, '------>obj');
+					uni.redirectTo({
+						url: `${obj}`
+					})
+				}
+			},
+
+
+			// 金刚图跳转
+			goOther(index, jumpType, jumpConfig) {
+				if (this.admin == undefined) {
+					uni.navigateTo({
+						url: '/pages/login/login'
+					})
+				} else {
+					switch (index) {
+						case 0:
+							console.log(index, jumpType, jumpConfig, '------>index')
+							this.jumpHAppID(jumpType, jumpConfig)
+							break;
+						case 1:
+							this.jumpHAppID(jumpType, jumpConfig)
+							break;
+						case 2:
+							this.jumpHAppID(jumpType, jumpConfig)
+							break;
+						case 3:
+							this.jumpHAppID(jumpType, jumpConfig)
+							break;
+						case 4:
+							this.jumpHAppID(jumpType, jumpConfig)
+							break;
+						default:
+							console.log(index)
+					}
+				}
+			},
+			// 跳转其他小程序
+			goJoin() {
+				wx.navigateToMiniProgram({
+					appId: 'wx255b58f0992b3c53', //appid
+					path: 'newUIMain/enrollment/enrollment', //path
+					extraData: { //参数
+						foo: 'bar'
+					},
+					// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+					success(res) {
+						console.log('成功')
+						// 打开成功
+					},
+					fail(e) {
+						console.log(e, '失败')
+					}
+				})
+			},
+			// 跳转到h5页面
+			goH5() {
+				let inset = this.advertisInset[0].jump_type
+				let inserPath = this.advertisInset[0].jump_config
+				//跳转h5
+				if (inset == 1) {
+					const url = inserPath; // 跳转的外链
+					const navtitle = 'H5'; // 这个标题是你自己可以设置的
+					uni.navigateTo({
+						// 跳转到webview页面
+						url: `/pages/webview/webview?url=${url}&nav=${navtitle}`,
+						success: () => {
+							console.log('成功')
+						},
+						fail: (e) => {
+							console.log(e, "失败")
+						}
+					});
+				} else if (inset == 2) {
+					let obj = JSON.parse(inserPath);
+					wx.navigateToMiniProgram({
+						appId: `${obj.appid}`, //appid
+						path: `${obj.path}`, //path
+						extraData: { //参数
+							foo: 'bar'
+						},
+						// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+						success(res) {
+							console.log('成功')
+							// 打开成功
+						},
+						fail(e) {
+							console.log(e, '失败')
+						}
+					})
+				}
+			},
+
+			//产品列表
+			goProduceList() {
+				uni.navigateTo({
+					url: '/pages/goods/goods'
+				})
+			},
+
+			//活动列表
+			goSpecialList() {
+				uni.navigateTo({
+					url: '/pages/index/active-list/index'
+				})
+			},
+			// 切换轮播图指示点
+			change1(e) {
+				this.current1 = e.detail.current;
+			},
+			change2(e) {
+				this.current2 = e.detail.current;
+			},
+			getCode() {
+				return new Promise((resolve, reject) => {
+					uni.getUserInfo({
+						success: loginRes => {
+							console.log(loginRes);
+							this.data.encryptData = loginRes.encryptedData,
+								this.data.iv = loginRes.iv
+							resolve(this.data)
+						}
+					})
+				})
+			},
+			//获取微信登录的code码
+			getmsg() {
+				uni.login({
+					provider: uni.$u.platform,
+					success: res => {
+						console.log(res, '------->res');
+						this.getCode().then((data) => {
+							console.log(this.data, '------>data');
+							const params = {
+								code: res.code,
+								iv: data.iv,
+								encryptData: data.encryptData
+							}
+							console.log(params);
+							this.$api.my.myLogin(params).then(res => {
+								let {
+									token
+								} = res.data
+								this.$store.dispatch('user/token', token)
+								// 获取活动列表
+								this.getList()
+							})
+						})
+					}
+				})
+			}
+
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+	page {
+		height: 100%;
+		background-color: #f9f9f9;
+	}
+
+	.home {
+		height: 100%;
+		background-color: #f9f9f9;
+	}
+
+	//首页广告弹框
+	.popup-banner {
+		position: relative;
+
+		.popup-banner-clean {
+			position: absolute;
+			top: 32rpx;
+			right: 32rpx;
+			width: 48rpx;
+			height: 48rpx;
+			background: #000000;
+			opacity: 0.2;
+			border-radius: 50%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+		}
+
+	}
+
+
+
+
+	.movableArea {
+		position: fixed;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+		z-index: 999;
+		pointer-events: none; //设置area元素不可点击,则事件便会下移至页面下层元素
+
+		.movableView {
+			pointer-events: auto; //可以点击
+			width: 84rpx;
+			height: 84rpx;
+			padding: 0 30rpx;
+
+			.img-IHg {
+				width: 84rpx;
+				height: 84rpx;
+				background-color: #fff;
+				box-shadow: 0px 8rpx 24rpx 0px rgba(220, 222, 229, 0.4);
+				border-radius: 50%;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+		}
+	}
+
+
+
+	.slot-wrap {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		flex: 1;
+	}
+
+	.home-swiper {
+		width: 100%;
+		height: 592rpx;
+
+		.swiper-box {
+			width: 100%;
+			height: 592rpx;
+			;
+
+			::v-deep .swiper-item {
+				width: 100%;
+				height: 592rpx;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+			}
+
+		}
+	}
+
+	.home-nav {
+		position: relative;
+		top: -18rpx;
+		padding-top: 60rpx;
+		border-radius: 24rpx 24rpx 0px 0px;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		background-color: #f9f9f9;
+
+		.home-nav-item {
+			width: 20%;
+			flex: none;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+		}
+	}
+
+	.home-special-area {
+		height: 146rpx;
+		padding: 0 30rpx;
+		// background-color: deeppink;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.home-special-area-left {
+			display: flex;
+			align-items: center;
+			justify-content: flex-start;
+			color: #333;
+			font-size: 36rpx;
+			font-weight: 800;
+			position: relative;
+
+			.text-shadow {
+				position: absolute;
+				bottom: 0;
+				left: 0;
+				width: 200rpx;
+				height: 16rpx;
+				background: linear-gradient(270deg, rgba(249, 231, 219, 0) 0%, #F9E7DB 100%);
+				border-radius: 200rpx 0px 0px 200rpx;
+			}
+
+			&::before {
+				content: '';
+				display: inline-block;
+				width: 6rpx;
+				height: 34rpx;
+				background: linear-gradient(180deg, #FF6200 0%, #FF4C00 100%);
+				border-radius: 3rpx;
+				margin-right: 8rpx;
+				margin-top: 2rpx;
+			}
+		}
+
+		.home-special-area-right {
+			display: flex;
+			align-items: center;
+			justify-content: flex-end;
+			font-size: 30rpx;
+			color: #999;
+		}
+	}
+
+	.home-special-img {
+		// height: 260rpx;
+		padding: 0 30rpx;
+		// background-color: #fff;
+		display: flex;
+		align-items: flex-start;
+		justify-content: space-between;
+		overflow-x: scroll;
+		overflow-y: hidden;
+
+		.ListItem {
+			width: 312rpx;
+			position: relative;
+			margin-right: 24rpx;
+
+			.kudosicon {
+				width: 40rpx;
+				height: 40rpx;
+				position: absolute;
+				right: 28rpx;
+				top: 16rpx;
+				border-radius: 50%;
+				background: #FFFFFF;
+				opacity: 0.84;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+		}
+
+		.ListItem:last-child {
+			margin-right: 0;
+		}
+	}
+
+	.home-banner {
+		height: 640rpx;
+		padding: 0 30rpx;
+		padding-top: 64rpx;
+
+		.home-banner-img {
+			position: relative;
+			width: 100%;
+
+			// height: 100%;
+			.baner-video {
+				position: absolute;
+				top: 0;
+				left: 0;
+			}
+
+			.banner-img {
+				position: absolute;
+				top: 0;
+				left: 0;
+				z-index: 9;
+			}
+
+			.img-clean {
+				position: absolute;
+				right: 28rpx;
+				top: 30rpx;
+				z-index: 99;
+			}
+
+			.img-IHg {
+				width: 84rpx;
+				height: 84rpx;
+				background-color: #fff;
+				box-shadow: 0px 8rpx 24rpx 0px rgba(220, 222, 229, 0.4);
+				border-radius: 50%;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				position: fixed;
+				top: 1030rpx;
+				right: 30rpx;
+				z-index: 99;
+
+			}
+		}
+	}
+
+	.home-attach {
+		background-color: #f9f9f9;
+		padding: 40rpx 30rpx 5rpx;
+	}
+
+	.home-hotel {
+		height: 124rpx;
+		background-color: #f9f9f9;
+	}
+
+	.home-hotel-img {
+		background-color: #F9f9f9;
+		padding: 20rpx 30rpx;
+
+		.home-hotel-img-content {
+			display: flex;
+			align-items: flex-start;
+			justify-content: space-between;
+			flex-wrap: wrap;
+
+			.home-hotel-img-content-item {
+				width: 332rpx;
+				background: #FFFFFF;
+				box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.04);
+				border-radius: 12rpx;
+				margin-bottom: 26rpx;
+				// &:nth-child(2n+1){
+				// 	// position: relative;
+				// 	top: -33px;
+				// }
+				// &:nth-child(1){
+				// 	// position: relative;
+				// 	top: 0;
+				// }
+
+				.home-hotel-img-content-item-img {
+					width: 332rpx;
+					height: 332rpx;
+					object-fit: cover;
+					object-position: center;
+				}
+
+				.home-hotel-img-content-item-img-long {
+					width: 332rpx;
+					height: 400rpx;
+					object-fit: cover;
+					object-position: center;
+				}
+
+				.text {
+					display: flex;
+					flex-direction: column;
+					align-items: flex-start;
+					justify-content: center;
+					padding: 18rpx 22rpx 32rpx;
+
+					.text-top {
+						font-size: 28rpx;
+						font-weight: bold;
+						color: #333;
+					}
+
+					.text-main {
+						display: none;
+						margin-top: 20rpx;
+						font-size: 24rpx;
+						color: #999999;
+					}
+				}
+			}
+		}
+
+
+		.home-hotel-img-more {
+			height: 70rpx;
+			background-color: #fff;
+			border-radius: 10rpx;
+			border: 2rpx solid #ddd;
+			font-size: 28rpx;
+			color: #5A5A5A;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			margin-top: 50rpx;
+		}
+	}
+
+	.home-brand {
+		height: 124rpx;
+		background-color: #f9f9f9;
+	}
+
+	.home-brand-img {
+		padding: 0 30rpx;
+		background-color: #f9f9f9;
+
+		zhe::v-deep .uni-swiper__dots-item {
+			width: 22rpx !important;
+			height: 2rpx !important;
+		}
+
+		::v-deep .uni-swiper__dots-bar {
+			width: 22rpx !important;
+			height: 2rpx !important;
+		}
+
+		::v-deep .uni-swiper__warp {
+			overflow: unset !important;
+		}
+
+		.swiper-box {
+			background-color: #f9f9f9;
+			height: 200rpx;
+
+			::v-deep swiper-item {
+				width: 100%;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+
+				view {
+					width: 164rpx;
+					height: 162rpx;
+					background: #FFFFFF;
+					box-shadow: 0px 4rpx 8rpx 0rpx rgba(220, 222, 229, 0.4);
+					border-radius: 32rpx;
+					display: flex;
+					align-items: center;
+					justify-content: center;
+
+					image {
+						border-radius: 32rpx;
+					}
+				}
+
+			}
+		}
+	}
+
+	.home-bottom {
+		background-color: #f9f9f9;
+		padding-top: 120rpx;
+	}
+</style>

+ 908 - 0
pages/index/vote-detail/index.vue

xqd
@@ -0,0 +1,908 @@
+<template>
+	<view class="vote-detail">
+		<!-- 分享海报 -->
+		<!-- <hch-poster ref="hchPoster" @cancel="handleCancel" :posterData.sync="posterData" @previewImage='previewImage' /> -->
+		<!-- 活动查询 -->
+		<view class="title">
+			<image style="width: 158rpx;height: 158rpx;border-radius: 50%; " :src="voteDetail.logo" mode="">
+			</image>
+			<text class="title-text">{{voteDetail.project_name}}</text>
+			<text class="title-btn">{{voteDetail.activity.title}}</text>
+		</view>
+		<!-- 分割线 -->
+		<view style="width: 92%; height: 2rpx; background-color:#F0F0F0;margin: 40rpx auto;  "></view>
+		<!-- 排名 -->
+		<view class="rank">
+			<view class="vote-detail-btn">
+				<view class="vote-detail-btn-item">
+					<text class="vote-detail-btn-item-num">{{voteDetail.project_no}}</text>
+					<text class="vote-detail-btn-item-text">编号</text>
+				</view>
+				<view style="width: 2rpx;height: 52rpx;background-color: #ccc;"></view>
+				<view class="vote-detail-btn-item">
+					<text class="vote-detail-btn-item-num"
+						v-if="voteDetail.ticket_num>=0">{{voteDetail.ticket_num + voteDetail.virtual_ticket_num}}</text>
+					<text class="vote-detail-btn-item-text">票数</text>
+				</view>
+				<view style="width: 2rpx;height: 52rpx;background-color: #ccc;"></view>
+				<view class="vote-detail-btn-item">
+					<text class="vote-detail-btn-item-num">{{voteDetail.rank}}</text>
+					<text class="vote-detail-btn-item-text">排名</text>
+				</view>
+				<view style="width: 2rpx;height: 52rpx;background-color: #ccc;"></view>
+				<view class="vote-detail-btn-item">
+					<text class="vote-detail-btn-item-num">{{voteDetail.next_rank_ticket_num}}</text>
+					<text class="vote-detail-btn-item-text">距上名</text>
+				</view>
+			</view>
+		</view>
+		<!-- 轮播图 -->
+		<view style="background-color: #f9f9f9;">
+			<view class="swiper">
+				<view class="home-swiper">
+					<uni-swiper-dot :mode="mode" :info="info" :current="current1" :dots-styles="dotsStyles">
+						<swiper class="swiper-box" @change="change1" circular>
+							<swiper-item v-for="(item ,index) in info" :key="index" v-if="resource_type == 1 ">
+								<view class="swiper-item">
+									<image style="width: 100%;height:576rpx; border-radius: 12rpx; " :src="item.img"
+										mode="aspectFill"></image>
+								</view>
+							</swiper-item>
+							<swiper-item v-if="resource_type == 2 ">
+								<view class="swiper-item">
+									<video id="myVideo" ref="myVideo"
+										style="width: 100%; height: 576rpx;border-radius: 12rpx; " :src="video_url"
+										controls :enable-progress-gesture="false">
+									</video>
+								</view>
+							</swiper-item>
+						</swiper>
+					</uni-swiper-dot>
+				</view>
+			</view>
+			<!-- 投票 -->
+			<view class="btn" @click="goVote(activity_project_id)">
+				<view v-if="spending || isStart" class="btn-vote"
+					:class="spending?'btn-vote': isStart?'btn-vote-fasle' :'' ">
+					<text>投票</text>
+				</view>
+				<view class="btn-vote-fasle" v-if="isEnd">
+					<text>投票结束</text>
+				</view>
+			</view>
+			<!-- 帮我拉票 -->
+			<view class="help">
+				<!-- <view class="help-btn" @click="getPoster">
+					<text>帮我拉票</text>
+				</view> -->
+				<view class="help-btn" @click="showPoster">
+					<text>帮我拉票</text>
+				</view>
+
+			</view>
+
+			<movable-area class="movableArea">
+				<movable-view class="movableView" direction="all" x="630rpx" y="700rpx">
+					<view class="img-IHg" @click="goJoin">
+						<image style="width: 64rpx; height: 58rpx; " src="/static/icon/vip.png" mode=""></image>
+					</view>
+				</movable-view>
+			</movable-area>
+
+
+			<!-- 分割线 -->
+			<view style="width: 92%; height: 2rpx; background-color:#F0F0F0;margin: 64rpx auto;  "></view>
+			<!-- 介绍 -->
+			<view class="introduce">
+				<view class="introduce-title">
+					<text>参赛介绍</text>
+				</view>
+				<view class="introduce-text" v-html="voteDetail.intro"></view>
+			</view>
+
+			<!-- 预约 -->
+			<view class="reserve">
+				<view class="reserve-left" @click="goSwiperSmall">
+					<image style="width: 36rpx;height: 36rpx; margin-right: 10rpx;" src="/static/icon/reserve02.png"
+						mode=""></image>
+					<text>预约</text>
+				</view>
+				<view class="reserve-right" @click="goJoin">
+					<image style="width: 60rpx;height: 56rpx; margin-right: 4rpx; " src="/static/icon/reserve01.png"
+						mode=""></image>
+					<text>加入IHG会员</text>
+				</view>
+			</view>
+		</view>
+
+		<!-- 弹出层 -->
+		<uni-popup ref="popup" type="center">
+			<view class="pop">
+				<view class="title"><text>投票成功</text></view>
+				<view class="img" v-if="is_prize==0">
+					<image :src="voteDetail.activity.success_img"></image>
+				</view>
+				<view class="img" v-if="is_prize==1">
+					<image :src="voteDetail.activity.success_img"></image>
+				</view>
+				<view class="textfont">
+					<text v-if="!isVoteNum && is_prize==0">今日投票数已用完
+						点击 加入IHG会员 可享受额外{{vipRewardTicketNum}}票数</text>
+					<text v-if="isVoteNum && is_prize==0 ">今日投票数还有 {{userCanVoteNum}} 次
+						点击再次投票可再次为本项目投票也可为其他项目投票</text>
+					<text v-if="is_prize==1">恭喜你中奖了!
+						获得了{{prizeProduct}}的奖品,请尽快领取</text>
+				</view>
+				<view class="btn">
+					<view v-if="is_prize==0" class="cancel"
+						@click="isVoteNum?voteAgain(activity_project_id):closeVote()">
+						<text>{{isVoteNum?'再次投票':'关闭'}}</text>
+					</view>
+					<view v-if="is_prize==0" class="download" @click="isVoteNum?goOtherItem():goJoin()">
+						<text>{{isVoteNum?'其他项目':'加入IHG会员'}}</text>
+					</view>
+
+					<view v-if="is_prize==1" class="cancel" @click="closeVote">
+						<text>关闭</text>
+					</view>
+					<view v-if="is_prize==1" class="download" @click="goConvert">
+						<text>去兑换</text>
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+
+
+		<!-- <canvas :style="{height: pupopHeight + 'px',width: pupopWidth + 'px'}" canvas-id="myCanvas"></canvas>
+		<uni-popup ref="popup" type="center">
+			<view class="popup-wrap">
+				<view class="popup-head">
+					生成海报
+					<view @click="close_popup()" class="close_icon"></view>
+				</view>
+				<image :src="posterImg" mode=""></image>
+				<view class="popup-footer">
+					<button class="save-btn" @click="saveToLocal()" type="default">保存到相册</button>
+					<view class="tips">保存图片到相册,你就可以分享啦!</view>
+				</view>
+			</view>
+		</uni-popup>
+ -->
+		
+		<Poster ref="poster" :name="voteDetail.project_name" :title="voteDetail.activity.title"/>
+		
+	</view>
+</template>
+
+<script>
+	// import HchPoster from "@/components/hch-poster/hch-poster.vue"
+	import Poster from "./poster.vue";
+	
+	export default {
+		components:{Poster},
+		data() {
+			return {
+				pageControl:{
+					isPosterShow:false,
+				},
+				pupopWidth: 590,
+				pupopHeight: 788,
+				//一定要注意像素密度的问题,这里使用的固定数值
+				pixelRatio: 3, //屏幕像数密度
+				inviteQR: '', //动态二维码
+				posterImg: '', //最后生成的海报
+				//二维码
+				codeImg: '',
+				//投票是否中奖,1中奖,0未中奖
+				is_prize: '',
+				//中奖礼物
+				prizeProduct: '',
+				//banner视频路径
+				video_url: '',
+				//banner图展示视频或者图片
+				resource_type: '',
+				//跳转h5和小程序
+				jump_type: '',
+				jump_config: '',
+				//跳转vip小程序获得投票数
+				vipRewardTicketNum: '',
+				//活动id
+				sourceId: '',
+				//活动可以使用的投票数
+				userCanVoteNum: '',
+				isVoteNum: false,
+				//判断活动是否正在进行中
+				spending: false,
+				//判断活动是否开始
+				isStart: false,
+				//判断活动是否结束
+				isEnd: false,
+				//活动开始时间
+				startTime: '',
+				//活动结束时间
+				endTime: "",
+				// 活动项目id
+				activity_project_id: '',
+				// 活动项目详情
+				voteDetail: '',
+				//轮播图
+				info: [],
+				dotsStyles: {
+					backgroundColor: 'rgba(255, 255, 255, .3)',
+					border: '1px rgba(255, 255, 255, .3) solid',
+					color: '#fff',
+					selectedBackgroundColor: 'rgba(255, 255, 255, 1)',
+					selectedBorder: '1px rgba(255, 255, 255, 1) solid'
+				},
+				//指示点显示位置
+				current1: 0,
+				mode: 'dot'
+
+			}
+		},
+		onReady: function(res) {
+			this.videoContext = uni.createVideoContext('myVideo')
+		},
+		onLoad(op) {
+			this.activity_project_id = op.id
+			this.getDetail(op.id)
+			this.admin = this.$store.getters.userInfo
+			console.log(this.admin);
+			// //海报
+			// this.pupopWidth = this.pupopWidth * this.pixelRatio
+			// this.pupopHeight = this.pupopHeight * this.pixelRatio
+
+
+		},
+		watch: {
+			vipRewardTicketNum: {
+				handler(newName, oldName) {
+					console.log(newName, '--->监听')
+				},
+				immediate: true,
+				deep: true
+			}
+		},
+		methods: {
+			shareing() {
+				uni.showLoading({
+					title: "海报生成中...",
+					mask: true
+				})
+				// this.inviteQR = this.codeImg
+				// this.createPoster();
+			},
+
+			//去兑换页面
+			goConvert() {
+				uni.navigateTo({
+					url: '/pages/my/prize/prize',
+					fail:(err)=>{
+						console.log(err)
+					}
+				})
+			},
+
+			//视频自动播放
+			openVideoPlay() {
+				this.videoContext.play()
+			},
+			//隐藏
+			handleCancel() {
+				console.log('取消审生成海报');
+			},
+			//生产海报
+			getPoster() {
+				this.$refs.hchPoster.posterShow()
+			},
+			// 切换轮播图指示点
+			change1(e) {
+				this.current1 = e.detail.current;
+			},
+			getDetail(id) {
+				this.$api.active.getActiveProjectDetail({
+					activity_project_id: id
+				}).then(res => {
+					console.log(res, "detail")
+					if (res.code == 0) {
+						this.voteDetail = res.data
+						console.log(this.voteDetail)
+						this.startTime = res.data.activity.start_time.replace(/-/g, "/")
+						// “yyyy-MM-dd-hh-mm-ss”.replace(/-/g,"/")
+						this.endTime = res.data.activity.end_time.replace(/-/g, "/")
+						console.log(this.startTime, this.endTime);
+						this.cancelTime(this.startTime, this.endTime)
+						//活动可以使用的投票数
+						this.userCanVoteNum = res.data.user_can_vote_num
+						if (this.userCanVoteNum > 0) {
+							this.isVoteNum = true
+						} else {
+							this.isVoteNum = false
+						}
+						this.sourceId = res.data.id
+						//跳转vip小程序获得投票数
+						this.vipRewardTicketNum = res.data.activity.vip_reward_ticket_num
+						// this.info =JSON.parse( res.data.img_urls)
+						this.info = JSON.parse(res.data.img_urls).map(item => {
+							return {
+								img: item
+							}
+						})
+						//跳转h5和小程序
+						this.jump_type = res.data.jump_type,
+							this.jump_config = res.data.jump_config
+						//banner展示视频或者图片
+						this.resource_type = res.data.resource_type
+						this.video_url = res.data.video_url
+						console.log(this.resource_type, this.video_url, '--->this.video_url');
+						//视频自动播放
+						this.openVideoPlay()
+						//海报图片
+						// this.posterData.mainImg = res.data.share_img
+						// this.codeImg = res.data.qrcode_url
+
+					}
+				})
+			},
+
+			//轮播图跳转h5或者小程序和内部页面
+			goSwiperSmall() {
+				//跳转h5
+				if (this.jump_type == 1) {
+					const url = this.jump_config; // 跳转的外链
+					const navtitle = 'H5'; // 这个标题是你自己可以设置的
+					uni.navigateTo({
+						// 跳转到webview页面
+						url: `/pages/webview/webview?url=${url}&nav=${navtitle}`,
+						success: () => {
+							console.log('成功')
+						},
+						fail: (e) => {
+							console.log(e, "失败")
+						}
+					});
+				} else if (this.jump_type == 2) {
+					let obj = JSON.parse(this.jump_config);
+					wx.navigateToMiniProgram({
+						appId: `${obj.appid}`, //appid
+						path: `${obj.path}`, //path
+						extraData: { //参数
+							foo: 'bar'
+						},
+						// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+						success(res) {
+							console.log('成功')
+							// 打开成功
+						},
+						fail(e) {
+							console.log(e, '失败')
+						}
+					})
+				} else if (this.jump_type == 4) {
+					let obj = this.jump_config
+					uni.switchTab({
+						url: `${obj}`,
+						success: function(e) { //跳转成功后刷新页面
+							var page = getCurrentPages().pop();
+							if (page == undefined || page == null) return;
+							page.onLoad();
+						}
+					})
+				}
+			},
+			cancelTime(i, j) {
+				let nowtime = new Date() //获取当前时间
+				let startime = new Date(i) //活动开始时间
+				let endtime = new Date(j); //活动结束时间
+				let lefttime = endtime.getTime() - nowtime.getTime() //距离结束时间的毫秒数
+				let spendtime = nowtime.getTime() - startime.getTime() //距离结束时间的毫秒数
+				console.log(lefttime, '---->lefttime');
+				console.log(spendtime, '---->spendtime');
+				if (lefttime > 0 && spendtime > 0) {
+					//活动进行中
+					this.spending = true
+				} else if (lefttime < 0) {
+					//活动结束
+					this.isEnd = true
+				} else if (spendtime < 0) {
+					//活动未开始
+					this.isStart = true
+				}
+
+			},
+			// 打开弹出层
+			openVote() {
+				this.$refs.popup.open()
+			},
+			// 关闭弹出层
+			closeVote() {
+				this.$refs.popup.close()
+			},
+			//再次投票
+			voteAgain(id) {
+				this.goVote(id)
+			},
+
+			//跳转其他项目
+			goOtherItem() {
+				uni.navigateBack()
+			},
+
+			//获取当前页面路径
+			getPageUrl() {
+				const pages = getCurrentPages();
+				console.log(pages, '--------->pages')
+				if (pages.length == 1) {
+					const currentPage = pages[0];
+					let pageUrl = `/${currentPage.route}`;
+					return pageUrl
+					console.log('当前页面url:', pageUrl);
+				} else {
+					const currentPage = pages[pages.length - 1];
+					let pageUrl = `/${currentPage.route}`;
+					return pageUrl
+					console.log('当前页面url:', pageUrl);
+				}
+			},
+
+			// 跳转其他小程序
+			goJoin() {
+				let _this = this
+				wx.navigateToMiniProgram({
+					appId: 'wx255b58f0992b3c53', //appid
+					path: 'newUIMain/enrollment/enrollment', //path
+					extraData: { //参数
+						foo: 'bar'
+					},
+					// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+					success(res) {
+						let page = _this.getPageUrl()
+						let user_id = ''
+						if (_this.admin != null) {
+							user_id = _this.admin.id
+						} else {
+							user_id = 0
+						}
+						console.log('成功', page)
+						_this.$api.my.userMemberAdd({
+							user_id,
+							page,
+						}).then(res => {
+							console.log(res.data);
+						})
+						
+						//增加票数
+						_this.$api.my.userJoinVip({
+							source_type: 1,
+							source_id: _this.sourceId
+						}).then(res => {
+							console.log('-->res', res)
+						})
+						// 打开成功
+					},
+					fail(e) {
+						console.log(e, '失败')
+					}
+				})
+			},
+			// 投票
+			goVote(id) {
+				this.$api.active.vote({
+					activity_project_id: id
+				}).then(res => {
+					console.log(res, '投票')
+					if (res.code == 0) {
+						
+						/**
+						 * 中奖用例
+						 * 数据由接口文档提供
+						 *
+						 * 
+						res = {
+							data: {
+								"is_prize": 1,
+								"integral": 0,
+								"product": {
+									"id": 1,
+									"type": 1,
+									"hotel_id": 1,
+									"cover_img": "",
+									"banners": "",
+									"name": "测试产品",
+									"category_id": 1,
+									"details": "测试产品",
+									"price": 10,
+									"integral": 0,
+									"stock": 0,
+									"attr_group": "[{\"attr_group_id\":1,\"attr_group_name\":\"口味\",\"attr_list\":[{\"attr_id\":1,\"attr_name\":\"五仁\",\"icon\":\"url1\"},{\"attr_id\":2,\"attr_name\":\"豆沙\",\"icon\":\"url2\"}]},{\"attr_group_id\":2,\"attr_group_name\":\"重量\",\"attr_list\":[{\"attr_id\":3,\"attr_name\":\"100g\",\"icon\":\"url3\"},{\"attr_id\":4,\"attr_name\":\"200g\",\"icon\":\"url4\"}]}]",
+									"created_at": "2022-11-23 18:09:06",
+									"updated_at": "2022-11-23 23:35:26"
+								}
+							}
+						}
+						 */
+					   
+						this.is_prize = res.data.is_prize
+						if (this.is_prize == 1) {
+							this.prizeProduct = res.data.product.name
+						}
+						this.openVote()
+						this.getDetail(this.activity_project_id)
+					} else {
+						if (res.msg.length > 7) {
+							uni.showToast({
+								icon: 'none',
+								title: res.msg
+							})
+						} else {
+							uni.showToast({
+								icon: 'error',
+								title: res.msg
+							})
+						}
+
+					}
+				}).catch(err => {
+					console.log(err)
+					uni.showToast({
+						icon: 'none',
+						title: '投票失败'
+					})
+				})
+			},
+			
+			//帮我拉票
+			showPoster(){
+				/**
+				 * 注意这里的图片接口好像有问题 .activity.cover_img信息
+				 * 报错内容:{"errMsg":"getImageInfo:fail invalid"}
+				 * 可能是图片域名不在微信开发者白名单
+				 * 添加不校验规则依然报错
+				 * 核实后取消下方注释即可
+				 */
+				this.$refs.poster.show({
+					name: this.voteDetail.project_name,
+					title: this.voteDetail.activity.title,
+					imgUrl: this.voteDetail.share_img,
+					qrcodeUrl: this.voteDetail.qrcode_url,
+				})
+				console.log(this.voteDetail)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	page {
+		height: 100% !important;
+		background: #F9F9F9 !important;
+	}
+
+	.vote-detail {
+		height: 100%;
+		background: #F9F9F9;
+	}
+
+	.reserve {
+		// position: fixed;
+		// bottom: 0;
+		width: 100%;
+		height: 148rpx;
+		padding: 0 30rpx;
+		background-color: #fff;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		font-size: 30rpx;
+		color: #fff;
+		font-weight: bold;
+
+		.reserve-left {
+			width: 204rpx;
+			height: 92rpx;
+			background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+			border-radius: 12rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+		}
+
+		.reserve-right {
+			width: 466rpx;
+			height: 92rpx;
+			background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+			border-radius: 12rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+		}
+
+	}
+
+
+
+	.introduce {
+		padding: 0 30rpx;
+		margin-bottom: 102rpx;
+
+		.introduce-title {
+			font-size: 32rpx;
+			font-weight: bold;
+			color: #333;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+		}
+
+		.introduce-text {
+			margin-top: 44rpx;
+			// line-height: 40rpx;
+			color: #333333;
+			// font-size: 28rpx;
+		}
+	}
+
+
+	.help {
+		padding: 0 30rpx;
+		margin-top: 30rpx;
+		position: relative;
+
+		.help-btn {
+			height: 108rpx;
+			background: #F9F9F9;
+			border-radius: 14rpx;
+			border: 2rpx solid #FF6200;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			color: #FF6200;
+			font-weight: bold;
+			font-size: 30rpx;
+		}
+
+		.img-IHg {
+			width: 84rpx;
+			height: 84rpx;
+			background-color: #fff;
+			box-shadow: 0px 8rpx 24rpx 0px rgba(220, 222, 229, 0.4);
+			border-radius: 50%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			position: fixed;
+			// top: -28rpx;
+			// right: 14rpx;
+			top: 1030rpx;
+			right: 30rpx;
+			z-index: 99;
+
+		}
+	}
+
+
+
+	.btn {
+		padding: 0 30rpx;
+		margin-top: 48rpx;
+
+		.btn-vote {
+			height: 108rpx;
+			background: linear-gradient(338deg, #FF6200 0%, #FF9D4F 100%);
+			border-radius: 12rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			color: #FFFFFF;
+			font-size: 30rpx;
+			font-weight: bold;
+		}
+
+		.btn-vote-fasle {
+			height: 108rpx;
+			background: #CCCCCC;
+			border-radius: 12rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			color: #FFFFFF;
+			font-size: 30rpx;
+			font-weight: bold;
+		}
+	}
+
+
+
+
+	.swiper {
+		padding: 0 30rpx;
+		margin-top: 64rpx;
+	}
+
+	.home-swiper {
+		height: 576rpx;
+
+		.swiper-box {
+			height: 576rpx;
+		}
+	}
+
+	.title {
+		padding-top: 30rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+
+		.title-text {
+			margin: 32rpx 0 16rpx;
+			font-size: 40rpx;
+			font-weight: bold;
+			color: #333;
+		}
+
+		.title-btn {
+			color: #FF6200;
+			font-size: 28rpx;
+		}
+	}
+
+	.rank {
+		padding: 0 30rpx;
+	}
+
+	.vote-detail-btn {
+		height: 190rpx;
+		background-color: #fff;
+		box-shadow: 0px 20rpx 40rpx 0px rgba(220, 222, 229, 0.4);
+		border-radius: 16rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+
+		.vote-detail-btn-item {
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: space-between;
+			font-size: 28rpx;
+			color: #333;
+
+			.vote-detail-btn-item-num {
+				font-size: 44rpx;
+				font-weight: bold;
+			}
+
+			.vote-detail-btn-item-text {
+				margin-top: 20rpx;
+			}
+		}
+	}
+
+	.pop {
+		width: 640rpx;
+		height: 740rpx;
+		background: #FFFFFF;
+		border-radius: 20rpx;
+		padding-top: 32rpx;
+		box-sizing: border-box;
+
+		.title {
+			@include flexlayout();
+			margin-bottom: 32rpx;
+
+			text {
+				font-size: 34rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #FF7119;
+			}
+		}
+
+		.img {
+			margin-left: 48rpx;
+			width: 544rpx;
+			height: 306rpx;
+			background: $bgColor;
+			border-radius: 12rpx;
+			@include flexlayout();
+			margin-bottom: 32rpx;
+
+			image {
+				width: 544rpx;
+				height: 306rpx;
+				border-radius: 12rpx;
+			}
+		}
+
+		.textfont {
+			margin-left: 30rpx;
+			margin-bottom: 40rpx;
+			@include flexlayout();
+			width: 572rpx;
+			height: 106rpx;
+
+			text {
+				text-align: center;
+				font-size: 34rpx;
+				font-weight: 400;
+				color: #828282;
+			}
+		}
+
+		.btn {
+			width: 100%;
+			height: 110rpx;
+			display: flex;
+			align-items: center;
+
+			.cancel {
+				@include flexlayout();
+				width: 50%;
+				height: 100%;
+				border-top: #E5E5E5 solid 1rpx;
+				border-right: #E5E5E5 solid 1rpx;
+
+				text {
+					font-size: 32rpx;
+					font-family: PingFangSC-Medium, PingFang SC;
+					font-weight: 500;
+					color: #666666;
+				}
+			}
+
+			.download {
+				border-top: #E5E5E5 solid 1rpx;
+				// border-left:#E5E5E5 solid 0.3rpx;
+				@include flexlayout();
+				height: 100%;
+				width: 50%;
+
+				text {
+					font-size: 32rpx;
+					font-family: PingFangSC-Medium, PingFang SC;
+					font-weight: 500;
+					color: #FF7119;
+				}
+			}
+		}
+	}
+
+	.movableArea {
+		position: fixed;
+		top: 0;
+		left: 0;
+		width: 100%;
+		height: 100%;
+		pointer-events: none; //设置area元素不可点击,则事件便会下移至页面下层元素
+
+		.movableView {
+			pointer-events: auto; //可以点击
+			width: 84rpx;
+			height: 84rpx;
+			padding: 0 30rpx;
+
+			.img-IHg {
+				width: 84rpx;
+				height: 84rpx;
+				background-color: #fff;
+				box-shadow: 0px 8rpx 24rpx 0px rgba(220, 222, 229, 0.4);
+				border-radius: 50%;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+		}
+	}
+	
+	
+</style>

+ 261 - 0
pages/index/vote-detail/poster.vue

xqd
@@ -0,0 +1,261 @@
+<template>
+	<view>
+		<view class="poster-container" v-if="poster.show">
+			<l-painter
+			v-if="poster.show"
+			  isRenderImage
+			   width="600rpx"  height="940rpx"
+			   custom-style="position: fixed;z-index:999; left: 0rpx;right:0rpx;margin:0rpx auto;bottom:440rpx;background:#fff;border-radius:20rpx"
+			  :board="poster.base"
+			  @success="poster.path = $event"
+			/>
+		</view>
+		
+		<view :class="{'poster-share':true, on:poster.show}">
+			<view>分享到</view>
+			<view class="poster-share-panel">
+				<view @click="share">
+					 <button class="shareButton" open-type="share"><image src="/static/icon/wechat.svg" mode="aspectFit"/>
+					<text>微信分享</text></button>
+				</view>
+				<view @click="save">
+					<image src="/static/icon/wechat_moments.svg" mode="aspectFit"/>
+					<text>保存相册</text>
+				</view>
+			</view>
+			<view @click="cancel">取消分享</view>
+		</view>
+	</view>
+	
+</template>
+
+<script>
+	import lPainter from '@/components/lime-painter/index.vue'
+	
+	export default {
+		components: {lPainter},
+		props: ["title", "name", "img", "qrcode"],
+		data() {
+			return {
+				poster:{
+					show:false,
+					path: "",
+					base: {
+						width: '600rpx',
+						height: '940rpx',
+						background: "#fff",
+						radius: "20rpx",
+						views: [
+							{
+								type: 'text',
+								text: '成都IHG大酒店',
+								css: {
+									width: "500rpx",
+									height: "80rpx",
+									left: "50rpx",
+									top: '20rpx',
+									fontSize: '32rpx',
+									fontWeight: "bold",
+									lineHeight: '80rpx',
+									color:'#000',
+									textAlign: 'center',
+								}
+							},
+							{
+								type: 'text',
+								text: '正在参与',
+								css: {
+									width: "170rpx",
+									height: "80rpx",
+									left: "50rpx",
+									top: '70rpx',
+									fontSize: '26rpx',
+									lineHeight: '80rpx',
+									color:'grey',
+									textAlign: 'right',
+								}
+							},
+							{
+								type: 'text',
+								text: '“最受欢迎-IHG酒店”',
+								css: {
+									width: "330rpx",
+									height: "80rpx",
+									left: "220rpx",
+									display: "flex",
+									justifyContent: 'center',
+									top: '70rpx',
+									fontSize: '26rpx',
+									lineHeight: '80rpx',
+									color:'#EEA470',
+									textAlign: 'left',
+								}
+							},
+							{
+								type: 'image',
+								src: 'http://img.xjishu.com/img/zl/2018/6/30/1241359458913.gif',
+								css: {
+									left: '240rpx',
+									top: '720rpx',
+									width: '120rpx',
+									height: '120rpx',
+									borderRadius: '30px'
+								}
+							},
+							{
+								type: 'text',
+								text: '长按识别小程序码给他投票',
+								css: {
+									width: "500rpx",
+									height: "80rpx",
+									left: "50rpx",
+									top: '830rpx',
+									fontSize: '26rpx',
+									lineHeight: '80rpx',
+									color:'grey',
+									textAlign: 'center',
+								}
+							},
+							{
+								type: 'image',
+								src: 'https://img1.baidu.com/it/u=3841234653,2748754224&fm=253&fmt=auto&app=138&f=JPEG?w=900&h=500',
+								css: {
+									left: '30rpx',
+									top: '150rpx',
+									width: '540rpx',
+									height: '540rpx',
+									borderRadius: '20rpx'
+								}
+							}
+						]
+					}
+				},
+			};
+		},
+		methods:{
+			show({name, title, imgUrl, qrcodeUrl}){
+				this.poster.base.views[0].text = name;
+				this.poster.base.views[2].text = title;
+				imgUrl && (this.poster.base.views[5].src = imgUrl);
+				qrcodeUrl && (this.poster.base.views[3].src = qrcodeUrl);
+				
+				
+				uni.pageScrollTo({
+					scrollTop: 0,
+					duration: 1
+				});
+				this.poster.show = true;
+			},
+			cancel(){
+				this.poster.show = false;
+			},
+			save(){
+				uni.saveImageToPhotosAlbum({
+					filePath: this.poster.path,
+					success(res) {
+						uni.showToast({
+							title: '已保存到相册',
+							icon: 'success',
+							duration: 2000
+						})
+					}
+				})
+			},
+			share(){
+				// wx.downloadFile({
+				// 	url: this.poster.path, // 下载url
+				// 	success (res) {
+				// 	  // 下载完成后转发
+				// 		wx.shareFileMessage({
+				// 			filePath: res.tempFilePath,
+				// 			success() {
+				// 				console.log('转发成功')
+				// 			},
+				// 			fail: console.error,
+				// 		})
+				// 	},
+				// 	fail: console.error,
+				// })
+			}
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+.poster-container{
+	width:100%;
+	height:100%;
+	position: fixed;
+	top:0;
+	left:0;
+	z-index: 999;
+	background-color: rgba(0, 0, 0, 0.4);
+}
+.poster-share{
+	position: fixed;
+	bottom:0;
+	width: 100%;
+	height: 380rpx;
+	background-color: #fff;
+	border-radius: 30rpx 30rpx 0px 0px;
+	transform: translateY(500rpx);
+	padding-top: 40rpx;
+	transition: 0.3s all;
+	z-index: 1000;
+	color:rgba(0,0,0,0.5);
+	display: flex;
+	flex-direction: column;
+	justify-content: space-between;
+	
+	&.on{
+		transform: translateY(0rpx);
+	}
+	
+	>view:first-child{
+		text-align: center;		
+		color: #000;
+		font-weight:bold;
+		margin-bottom: 40rpx;
+	}
+	
+	>view:nth-child(2){
+		display: flex;
+		justify-content: flex-start;
+		align-items: center;
+		margin-bottom: 40rpx;
+		
+		>view{
+			text-align: center;
+			margin-left: 40rpx;
+		}
+		
+		image{
+			width: 80rpx;
+			height: 80rpx;
+		}
+		
+		text{
+			width: 100rpx;
+			display: block;
+			font-size: 24rpx;
+			text-align: center;
+		}
+	}
+	>view:last-child{
+		height: 100rpx;
+		line-height: 100rpx;
+		text-align: center;
+		border-top: 1px solid rgba(0,0,0,0.1);
+	}
+	.shareButton{
+		background: transparent;
+		border: 0px;
+		line-height: inherit;
+		color: inherit;
+		
+		&::after{
+			border:0px;
+		}
+	}
+}
+</style>

+ 294 - 0
pages/login/login.vue

xqd
@@ -0,0 +1,294 @@
+<template>
+	<view class="login">
+		<view class="img">
+			<image src="https://t9.9026.com/imgs/bg_1.jpg" mode="scaleToFill"></image>
+
+		</view>
+		<view class="title">
+			<view class="line"></view>
+			<view class="logintype"><text>登录方式</text></view>
+			<view class="line"></view>
+		</view>
+		<view class="typebtn">
+			<view class="item" @click="goYouyue">
+				<image src="/static/icon/youyue.png" mode="scaleToFill"></image>
+				<text>加入优悦会</text>
+			</view>
+			<view class="item" @click="getmsg">
+				<image src="/static/icon/wechart.png" mode="scaleToFill"></image>
+				<text v-if="!isLoginOff">微信登录</text>
+				<text v-if="isLoginOff">授权登录</text>
+			</view>
+		</view>
+
+		<u-modal @close="closeMask" closeOnClickOverlay="true" :show="modal.show" :title="modal.title"
+			:show-confirm-button="false">
+			<view>
+				<button class="avatar" open-type="chooseAvatar" @chooseavatar="handleChooseAvatar">
+					<image class="user-avatar" style="height: 176rpx;width: 176rpx;border-radius: 50%;"
+						:src="modal.avatar?modal.avatar:'/static/icon/avatar.png'" />
+				</button>
+				<input class="avatar" type="nickname" :value="modal.nickname" placeholder="填写昵称"
+					@change="handleChangeNickname">
+				<button class="confirm" @click="handleConfirmWechatUserInfo">提交</button>
+			</view>
+		</u-modal>
+
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				imgBase64:'',
+				isLoginOff: false,
+				modal: {
+					show: false,
+					title: '用户信息获取',
+					nickname: '',
+					avatar: ''
+				},
+				code: '',
+				encryptedData: '',
+				iv: '',
+				data: {}
+			}
+		},
+		onLoad() {
+			this.isLoginOff = this.$store.getters.userInfo
+		},
+		methods: {
+			//关闭遮罩层
+			closeMask() {
+				this.modal.show = false
+			},
+			//提交
+			handleConfirmWechatUserInfo() {
+				if (!this.modal.avatar) {
+					this.$u.toast('请上传头像')
+					return
+				}
+				if (!this.modal.nickname) {
+					this.$u.toast('请填写昵称')
+					return
+				}
+				this.$loading('数据提交中...')
+				this.$api.my.update({
+					avatar: this.modal.avatar,
+					nickname: this.modal.nickname
+				}).then(res => {
+					this.$hideLoading()
+					this.$store.dispatch('user/info', res.data)
+					this.modal.show = false
+					uni.switchTab({
+						url: '/pages/my/my'
+					})
+				})
+			},
+			handleGetWechatUserInfo() {
+				this.modal.show = true
+			},
+			// 获取头像
+			handleChooseAvatar(e) {
+				console.log(e.detail, '------>e.detail');
+				this.modal.avatar = e.detail.avatarUrl
+				uni.getFileSystemManager().readFile({
+					filePath: e.detail.avatarUrl, //选择图片返回的相对路径
+					encoding: 'base64', //编码格式
+					success: res => { //成功的回调
+						console.log(res);
+						this.imgBase64 = 'data:image/jpeg;base64,' + res.data //不加上这串字符,在页面无法显示的哦
+						this.$api.my.UserUploadFile({
+							file:this.imgBase64 
+						}).then(res=>{
+							console.log(res.data,'------->res.data');
+						})
+						
+					},
+					fail: (e) => {
+						console.log("图片转换失败");
+					}
+				})
+			},
+			//获取昵称
+			handleChangeNickname(res) {
+				this.modal.nickname = res.detail.value
+			},
+			// 加入优悦会
+			goYouyue() {
+				uni.navigateTo({
+					url: '/pages/login/youyue'
+				})
+			},
+			getCode() {
+				return new Promise((resolve, reject) => {
+					uni.getUserInfo({
+						success: loginRes => {
+							this.data.encryptData = loginRes.encryptedData,
+								this.data.iv = loginRes.iv
+							resolve(this.data)
+						}
+					})
+				})
+			},
+			//获取微信登录的code码
+			getmsg() {
+				if (this.isLoginOff) {
+					uni.switchTab({
+						url: '/pages/my/my'
+					})
+				} else {
+					uni.login({
+						provider: uni.$u.platform,
+						success: res => {
+							this.getCode().then((data) => {
+								const params = {
+									code: res.code,
+									iv: data.iv,
+									encryptData: data.encryptData
+								}
+								console.log(params);
+								this.$api.my.myLogin(params).then(res => {
+									let {
+										token
+									} = res.data
+									this.$store.dispatch('user/token', token)
+									this.handleGetWechatUserInfo()
+									this.handleConfirmWechatUserInfo()
+								})
+							})
+						}
+					})
+				}
+
+			},
+
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	.login {
+		height: 100%;
+		background: $bgColor;
+		box-sizing: border-box;
+	}
+
+	.avatar {
+		width: 176rpx;
+		height: 176rpx;
+		border-radius: 50%;
+	}
+
+	.user-avatar {
+		object-fit: cover;
+		object-position: center;
+	}
+
+	.userinfo {
+		position: absolute;
+		top: 38rpx;
+		left: 200rpx;
+
+		.unlogin {
+			width: 220rpx;
+			font-size: 44rpx;
+			font-family: PingFang-SC-Heavy, PingFang-SC;
+			font-weight: 500;
+			color: #FFFFFF;
+			display: block;
+			margin-top: 20rpx;
+		}
+
+		.username {
+			width: 184rpx;
+			height: 44rpx;
+			font-size: 44rpx;
+			font-family: PingFang-SC-Heavy, PingFang-SC;
+			font-weight: 500;
+			color: #FFFFFF;
+			line-height: 44rpx;
+			display: block;
+			margin-bottom: 24rpx;
+		}
+
+		.userId {
+			font-size: 32rpx;
+			font-family: PingFang-SC-Medium, PingFang-SC;
+			font-weight: 400;
+			color: #FFFFFF;
+			line-height: 32rpx;
+		}
+	}
+
+
+
+	.img {
+		image {
+			width: 100vw;
+			height: 910rpx;
+		}
+	}
+
+	.title {
+		height: 40rpx;
+		width: 690rpx;
+		// margin-top: 168rpx;
+		margin-left: 30rpx;
+		margin-bottom: 72rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.line {
+			width: 240rpx;
+			height: 2rpx;
+			background: #EDEDED;
+			border-radius: 1rpx;
+		}
+
+		.logintype {
+			text {
+				font-size: 28rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #333333;
+			}
+		}
+
+	}
+
+	.typebtn {
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+
+		.item {
+			width: 140rpx;
+			height: 156rpx;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+
+			image {
+				width: 104rpx;
+				height: 104rpx;
+				margin-bottom: 12rpx;
+			}
+
+			text {
+				display: block;
+				font-size: 28rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+	}
+</style>

+ 457 - 0
pages/login/youyue.vue

xqd
@@ -0,0 +1,457 @@
+<template>
+	<view class="youyue">
+		<view class="nav">
+			<image src="http://t9.9026.com/imgs/logo@2x.png"></image>
+		</view>
+		<view class="title">
+			IHG优悦会忠诚计划优悦随行悦享世界
+		</view>
+		<view class="detail">
+			<view><text>HG优悦会是洲际酒店集团的会员忠诚计划。在全球拥有超过1亿会员。</text></view>
+			<view><text> 即刻加入HG优悦会,一键开启会员专享价及会员专属礼遇。轻松赚取积分,使用灵活的积分兑换及竞拍,畅享独特且多元的犒赏体验。</text></view>
+		</view>
+
+		<view class="boxitem">
+			<text class="boxitemtitle">优悦会会员权益</text>
+		</view>
+		<view class="boxitem" style="border-top: none;">
+			<text class="boxitemtitle">入会第一天起即可臻享礼遇</text>
+		</view>
+		<view class="boxitem" style="border-top: none;">
+			<text class="boxitemtitle">赚取酒店积分兑换奖励住宿以及更多</text>
+			<text class="boxitemcontent">积分不仅可以兑换体验,目录商品等,还可以兑换全球6000等多个目的地奖励住宿</text>
+			<image src="/static/icon/loginicon1.png"></image>
+		</view>
+		<view class="boxitem" style="border-top: none;">
+			<text class="boxitemtitle">会员专享价</text>
+			<text class="boxitemcontent" style="margin-bottom: 30rpx;">直接预订可享受我们会员专属的优惠房价</text>
+			<image src="/static/icon/loginicon2.png"></image>
+		</view>
+		<view class="boxitem" style="border-top: none;">
+			<text class="boxitemtitle">会员促销</text>
+			<text class="boxitemcontent" style="margin-bottom: 30rpx;">尽情享受会员促销,赚取更多奖励积分</text>
+			<image src="/static/icon/loginicon3.png"></image>
+		</view>
+
+		<view class="item"><text class="itemtitle">畅享网络</text></view>
+
+		<view class="itemLast">我们所有酒店均提供免费WIFI,让您始终顺畅连通</view>
+
+		<view class="btn" @click="goOther">
+			<text>立即加入会员</text>
+		</view>
+
+		<view class="logintitle">
+			<view class="line"></view>
+			<view class="logintype"><text>其他登录</text></view>
+			<view class="line"></view>
+		</view>
+		<view class="typebtn" @click="getmsg">
+			<view class="item">
+				<image src="/static/icon/wechart.png" mode="scaleToFill"></image>
+				<text>微信登录</text>
+			</view>
+		</view>
+		<u-modal @close="closeMask" closeOnClickOverlay="true" :show="modal.show" :title="modal.title"
+			:show-confirm-button="false">
+			<view>
+				<button class="avatar" open-type="chooseAvatar" @chooseavatar="handleChooseAvatar">
+					<image class="user-avatar" style="height: 176rpx;width: 176rpx;border-radius: 50%;"
+						:src="modal.avatar?modal.avatar:'/static/icon/avatar.png'" />
+				</button>
+				<input class="avatar" type="nickname" :value="modal.nickname" placeholder="填写昵称"
+					@change="handleChangeNickname">
+				<button class="confirm" @click="handleConfirmWechatUserInfo">提交</button>
+			</view>
+		</u-modal>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				imgBase64: '',
+				isLoginOff: false,
+				modal: {
+					show: false,
+					title: '用户信息获取',
+					nickname: '',
+					avatar: ''
+				},
+				code: '',
+				encryptedData: '',
+				iv: '',
+				data: {}
+			}
+		},
+		onLoad() {
+			this.isLoginOff = this.$store.getters.userInfo
+		},
+		methods: {
+			//关闭遮罩层
+			closeMask() {
+				this.modal.show = false
+			},
+			//提交微信名称和头像
+			handleConfirmWechatUserInfo() {
+				if (!this.modal.avatar) {
+					this.$u.toast('请上传头像')
+					return
+				}
+				if (!this.modal.nickname) {
+					this.$u.toast('请填写昵称')
+					return
+				}
+				this.$loading('数据提交中...')
+				this.$api.my.update({
+					avatar: this.modal.avatar,
+					nickname: this.modal.nickname
+				}).then(res => {
+					this.$hideLoading()
+					this.$store.dispatch('user/info', res.data)
+					this.modal.show = false
+					uni.switchTab({
+						url: '/pages/my/my'
+					})
+				})
+			},
+			handleGetWechatUserInfo() {
+				this.modal.show = true
+			},
+			// 微信获取头像
+			handleChooseAvatar(e) {
+				console.log(e.detail, '------>e.detail');
+				this.modal.avatar = e.detail.avatarUrl
+				// uni.getFileSystemManager().readFile({
+				// 	filePath: e.detail.avatarUrl, //选择图片返回的相对路径
+				// 	encoding: 'base64', //编码格式
+				// 	success: res => { //成功的回调
+				// 		console.log(res);
+				// 		this.imgBase64 = 'data:image/jpeg;base64,' + res.data //不加上这串字符,在页面无法显示的哦
+				// 		this.modal.avatar = this.imgBase64
+				// 	},
+				// 	fail: (e) => {
+				// 		console.log("图片转换失败");
+				// 	}
+				// })
+			},
+			handleChangeNickname(res) {
+				this.modal.nickname = res.detail.value
+			},
+
+
+			//获取当前页面路径
+			getPageUrl() {
+				const pages = getCurrentPages();
+				console.log(pages,'--------->pages')
+				if(pages.length==1){
+					const currentPage = pages[0];
+					let pageUrl = `/${currentPage.route}`;
+					return pageUrl
+					console.log('当前页面url:', pageUrl);
+				}else{
+					const currentPage = pages[pages.length - 1];
+					let pageUrl = `/${currentPage.route}`;
+					return pageUrl
+					console.log('当前页面url:', pageUrl);
+				}
+				
+				// pageUrl = this.pageUrl + '?id=' + this.detailID;
+				
+			},
+
+
+			// 跳转其他小程序
+			goOther() {
+				let _this = this
+				wx.navigateToMiniProgram({
+					appId: 'wx255b58f0992b3c53', //appid
+					path: 'newUIMain/enrollment/enrollment', //path
+					extraData: { //参数
+						foo: 'bar'
+					},
+					// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+					success(res) {
+						let page = _this.getPageUrl()
+						console.log('成功', page)
+						_this.$api.my.userMemberAdd({
+							user_id: 0,
+							page,
+						}).then(res => {
+							console.log(res.data);
+						})
+						// 打开成功
+					},
+					fail(e) {
+						console.log(e, '失败')
+					}
+				})
+			},
+			getCode() {
+				return new Promise((resolve, reject) => {
+					uni.getUserInfo({
+						success: loginRes => {
+							this.data.encryptData = loginRes.encryptedData,
+								this.data.iv = loginRes.iv
+							resolve(this.data)
+						}
+					})
+				})
+			},
+			//获取微信登录的code码
+			getmsg() {
+				if (this.isLoginOff) {
+					uni.switchTab({
+						url: '/pages/my/my'
+					})
+				} else {
+					uni.login({
+						provider: uni.$u.platform,
+						success: res => {
+							this.getCode().then((data) => {
+								const params = {
+									code: res.code,
+									iv: data.iv,
+									encryptData: data.encryptData
+								}
+								console.log(params);
+								this.$api.my.myLogin(params).then(res => {
+									let {
+										token
+									} = res.data
+									this.$store.dispatch('user/token', token)
+									this.handleGetWechatUserInfo()
+									this.handleConfirmWechatUserInfo()
+								})
+							})
+						}
+					})
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	.youyue {
+		height: 100%;
+		background: $bgColor;
+		padding: 192rpx 30rpx 140rpx 30rpx;
+		position: relative;
+	}
+
+
+
+	.avatar {
+		width: 176rpx;
+		height: 176rpx;
+		border-radius: 50%;
+	}
+
+	.user-avatar {
+		object-fit: cover;
+		object-position: center;
+	}
+
+	.userinfo {
+		position: absolute;
+		top: 38rpx;
+		left: 200rpx;
+
+		.unlogin {
+			width: 220rpx;
+			font-size: 44rpx;
+			font-family: PingFang-SC-Heavy, PingFang-SC;
+			font-weight: 500;
+			color: #FFFFFF;
+			display: block;
+			margin-top: 20rpx;
+		}
+
+		.username {
+			width: 184rpx;
+			height: 44rpx;
+			font-size: 44rpx;
+			font-family: PingFang-SC-Heavy, PingFang-SC;
+			font-weight: 500;
+			color: #FFFFFF;
+			line-height: 44rpx;
+			display: block;
+			margin-bottom: 24rpx;
+		}
+
+		.userId {
+			font-size: 32rpx;
+			font-family: PingFang-SC-Medium, PingFang-SC;
+			font-weight: 400;
+			color: #FFFFFF;
+			line-height: 32rpx;
+		}
+	}
+
+
+	.nav {
+		position: absolute;
+		top: 0rpx;
+		left: 0rpx;
+
+		image {
+			width: 750rpx;
+			height: 142rpx;
+		}
+	}
+
+	.title {
+		width: 400rpx;
+		height: 120rpx;
+		font-size: 44rpx;
+		font-family: PingFang-SC-Bold, PingFang-SC;
+		font-weight: bold;
+		color: #333333;
+		line-height: 60rpx;
+		margin-bottom: 64rpx;
+	}
+
+	.detail {
+		width: 690rpx;
+		height: 220rpx;
+		margin-bottom: 64rpx;
+
+		text {
+			font-size: 32rpx;
+			font-family: PingFang-SC-Medium, PingFang-SC;
+			font-weight: 500;
+			color: #333333;
+		}
+	}
+
+	.item {
+		margin: 40rpx 0;
+
+		.itemtitle {
+			font-size: 32rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #333333;
+		}
+	}
+
+	.itemLast {
+		width: 690rpx;
+		font-size: 24rpx;
+		font-family: PingFang-SC-Medium, PingFang-SC;
+		font-weight: 500;
+		color: #333333;
+		margin-bottom: 64rpx;
+	}
+
+	.btn {
+		width: 688rpx;
+		height: 92rpx;
+		background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		border-radius: 12rpx;
+
+		text {
+			font-size: 30rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #FFFFFF;
+		}
+	}
+
+	.logintitle {
+		height: 40rpx;
+		width: 690rpx;
+		margin-top: 64rpx;
+		margin-bottom: 64rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.line {
+			width: 240rpx;
+			height: 2rpx;
+			background: #EDEDED;
+			border-radius: 1rpx;
+		}
+
+		.logintype {
+			text {
+				font-size: 28rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #333333;
+			}
+		}
+
+	}
+
+	.typebtn {
+		display: flex;
+		align-items: center;
+		justify-content: space-around;
+
+		.item {
+			width: 140rpx;
+			height: 156rpx;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+
+			image {
+				width: 104rpx;
+				height: 104rpx;
+				margin-bottom: 12rpx;
+			}
+
+			text {
+				display: block;
+				font-size: 28rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+	}
+
+	.boxitem {
+		border-top: #F0F0F0 2rpx solid;
+		border-bottom: #F0F0F0 2rpx solid;
+		padding: 40rpx 0;
+		position: relative;
+
+		image {
+			top: 35%;
+			right: 0rpx;
+			width: 96rpx;
+			height: 96rpx;
+			position: absolute;
+		}
+
+		.boxitemtitle {
+			font-size: 32rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #333333;
+		}
+
+		.boxitemcontent {
+			margin-top: 24rpx;
+			width: 512rpx;
+			display: block;
+			font-size: 28rpx;
+			font-family: PingFang-SC-Medium, PingFang-SC;
+			font-weight: 500;
+			color: #333333;
+		}
+	}
+</style>

+ 366 - 0
pages/map/hotel-book/index.vue

xqd
@@ -0,0 +1,366 @@
+<template>
+	<view class="hotel-book">
+		<!-- 自定义导航栏 -->
+		<u-navbar :leftText='title' fixed safeAreaInsetTop :placeholder='true'  :bgColor="bgColor" @leftClick='back'>
+		</u-navbar>
+		<!-- 背景图 -->
+		<view class="hotel-book-img">
+			<uni-swiper-dot :mode="mode" :info="info" :current="current1" :dots-styles="dotsStyles">
+				<swiper class="swiper-box" @change="change1" circular>
+					<swiper-item v-for="(item ,index) in info" :key="index"  v-if="resource_type == 1 ">
+						<view class="swiper-item">
+							<image style="width: 100%;height:564rpx;" :src="item.img" mode="aspectFill"></image>
+						</view>
+					</swiper-item>
+					<swiper-item  v-if="resource_type == 2 ">
+						<view class="swiper-item">
+							<video class="baner-video" id="myVideo" ref="myVideo" style="width: 100%; height: 564rpx;"
+								:src="video_url" controls :enable-progress-gesture="false">
+							</video>
+						</view>
+					</swiper-item>
+				</swiper>
+			</uni-swiper-dot>
+		</view>
+
+		<!-- 酒店介绍 -->
+		<view class="hotel-content">
+			<view class="hotel-content-top">
+				<image style="width: 48rpx;height: 48rpx;" src="/static/icon/local01.png" mode=""></image>
+				<view class="hotel-content-top-text">
+					<text>{{hotelDetail.name}}</text>
+				</view>
+			</view>
+			<view class="hotel-content-introduce">
+				<view class="introduce-top">
+					<text class="introduce-top-rule1"></text>
+					<text style="margin: 0 8rpx;">酒店介绍</text>
+					<text class="introduce-top-rule2"></text>
+				</view>
+				<view class="introduce-btn-text introduce-btn">
+					<view v-html="hotelDetail.details"></view>
+				</view>
+			</view>
+
+		</view>
+
+		<view class="hotel-btn">
+			<view class="hotel-btn-left">
+				<view class="hotel-btn-left-text" @click="goIndex">
+					<view style="width: 48rpx;height: 48rpx;display: flex;align-items: center;justify-content: center;">
+						<image style="width: 40rpx;height: 42rpx;" src="/static/icon/home04.png" mode=""></image>
+					</view>
+					<text>首页</text>
+				</view>
+				<view class="hotel-btn-left-text" @click="goJoin">
+					<view
+						style="width: 48rpx;height: 48rpx; display: flex;align-items: center;justify-content: center; ">
+						<image style="width: 52rpx;height: 46rpx;" src="/static/icon/vip02.png" mode=""></image>
+					</view>
+					<text>会员</text>
+				</view>
+				<view class="hotel-btn-left-text">
+					<view style="width: 48rpx;height: 48rpx;display: flex;align-items: center;justify-content: center;">
+						<image style=" width: 44rpx;height: 44rpx;" src="/static/icon/home03.png" mode=""></image>
+					</view>
+					<text>导航</text>
+				</view>
+			</view>
+			<view class="hotel-btn-right" @click="goJump">
+				<text>预订</text>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				//轮播图
+				info: [],
+				//自定义导航栏
+				bgColor: '#fff',
+				title: '',
+				//酒店id
+				hotel_id: '',
+				hotelDetail: '',
+				jump_type: '',
+				jump_config: '',
+				resource_type: '',
+				video_url: '',
+				//指示点显示位置
+				dotsStyles: {
+					backgroundColor: 'rgba(255, 255, 255, .3)',
+					border: '1px rgba(255, 255, 255, .3) solid',
+					color: '#fff',
+					selectedBackgroundColor: 'rgba(255, 255, 255, 1)',
+					selectedBorder: '1px rgba(255, 255, 255, 1) solid'
+				},
+				//指示点显示位置
+				current1: 0,
+				mode: 'dot'
+			}
+		},
+		onReady: function(res) {
+			this.videoContext = uni.createVideoContext('myVideo')
+		},
+
+		onLoad(o) {
+			if (o.hotel_id) {
+				this.hotel_id = o.hotel_id
+				this.getDetail()
+			}
+		},
+
+		methods: {
+			// 切换轮播图指示点
+			change1(e) {
+				this.current1 = e.detail.current;
+			},
+			//视频自动播放
+			openVideoPlay() {
+				this.videoContext.play()
+			},
+			//返回上一级
+			back() {
+				const pages = getCurrentPages();
+				if (pages.length === 2) {
+					uni.navigateBack({
+						delta: 1
+					});
+				} else if (pages.length === 1) {
+					uni.switchTab({
+						url: '/pages/index/index',
+					})
+				} else {
+					uni.navigateBack({
+						delta: 1
+					});
+				}
+			},
+			//预约跳转
+			goJump() {
+				//跳转h5
+				if (this.hotelDetail.reserve_jump_type == 1) {
+					const url = this.hotelDetail.reserve_jump_config; // 跳转的外链
+					const navtitle = 'H5'; // 这个标题是你自己可以设置的
+					uni.navigateTo({
+						// 跳转到webview页面
+						url: `/pages/webview/webview?url=${url}&nav=${navtitle}`,
+						success: () => {
+							console.log('成功')
+						},
+						fail: (e) => {
+							console.log(e, "失败")
+						}
+					});
+				} else if (this.hotelDetail.reserve_jump_type == 2) {
+					let obj = JSON.parse(this.hotelDetail.reserve_jump_config)
+					console.log(obj);
+					wx.navigateToMiniProgram({
+						appId: `${obj.appid}`, //appid
+						path: `${obj.path}`, //path
+						extraData: { //参数
+							foo: 'bar'
+						},
+						// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+						success(res) {
+							console.log('成功')
+							// 打开成功
+						},
+						fail(e) {
+							console.log(e, '失败')
+						}
+					})
+				}
+			},
+			//获取酒店详情
+			getDetail() {
+				this.$api.hotel.getHotelDetail({
+					hotel_id: this.hotel_id
+				}).then(res => {
+					this.hotelDetail = res.data
+					this.title = res.data.name
+					this.info = JSON.parse(res.data.img_urls).map(item => {
+						return {
+							img: item
+						}
+					})
+					//跳转h5和小程序
+					this.jump_type = res.data.jump_type,
+						this.jump_config = res.data.jump_config
+					//banner展示视频或者图片
+					this.resource_type = res.data.resource_type
+					this.video_url = res.data.video_url
+					console.log(this.video_url, '--->this.video_url');
+					//视频自动播放
+					this.openVideoPlay()
+				})
+			},
+
+			// 跳转其他小程序
+			goJoin() {
+				wx.navigateToMiniProgram({
+					appId: 'wx255b58f0992b3c53', //appid
+					path: 'newUIMain/enrollment/enrollment', //path
+					extraData: { //参数
+						foo: 'bar'
+					},
+					// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+					success(res) {
+						console.log('成功')
+						// 打开成功
+					},
+					fail(e) {
+						console.log(e, '失败')
+					}
+				})
+			},
+			// 跳转首页
+			goIndex() {
+				uni.reLaunch({
+					url: '/pages/index/index'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.hotel-book {
+		height: 100%;
+		background: #fff;
+	}
+
+	.hotel-book-img {
+		height: 564rpx;
+
+		.swiper-box {
+			height: 564rpx;
+		}
+	}
+
+	.hotel-btn {
+		padding: 0 30rpx;
+		position: fixed;
+		bottom: 0;
+		width: 100%;
+		height: 148rpx;
+		background: #FFFFFF;
+		box-shadow: 0px -2rpx 20rpx 0px rgba(0, 0, 0, 0.04);
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.hotel-btn-left {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.hotel-btn-left-text {
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				justify-content: flex-start;
+				font-weight: 500;
+				color: #999999;
+				font-size: 22rpx;
+				margin-right: 48rpx;
+			}
+		}
+
+		.hotel-btn-right {
+			width: 396rpx;
+			height: 92rpx;
+			background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+			border-radius: 12rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			font-weight: bold;
+			color: #FFFFFF;
+			font-size: 30rpx;
+		}
+	}
+
+	.hotel-content {
+		width: 100%;
+		padding: 40rpx 30rpx 100rpx;
+
+		.hotel-content-top {
+			height: 48rpx;
+			display: flex;
+			align-items: center;
+			justify-content: flex-start;
+
+			.hotel-content-top-text {
+				margin-top: -2rpx;
+				font-weight: bold;
+				color: #333333;
+				font-size: 32rpx;
+				margin-left: 8rpx;
+			}
+		}
+
+		.hotel-content-introduce {
+			margin-top: 32rpx;
+			padding: 48rpx 22rpx;
+			background: #FFFFFF;
+			border-radius: 4rpx;
+			border: 2rpx solid #999999;
+			margin-bottom: 100rpx;
+		}
+	}
+
+	.introduce-top {
+		height: 32rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		font-size: 32rpx;
+		font-weight: bold;
+		letter-spacing: 2rpx;
+
+		.introduce-top-rule1 {
+			width: 56rpx;
+			height: 4rpx;
+			background: linear-gradient(90deg, #FFFFFF 0%, #D9A94D 100%);
+		}
+
+		.introduce-top-rule2 {
+			width: 56rpx;
+			height: 4rpx;
+			background: linear-gradient(-90deg, #FFFFFF 0%, #D9A94D 100%);
+		}
+	}
+
+	.introduce-btn-text {
+		margin-top: 72rpx;
+		font-size: 28rpx;
+		color: #333;
+		font-weight: bold;
+		line-height: 56rpx;
+	}
+
+	.introduce-btn {
+		margin-top: 72rpx;
+		width: 100%;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		font-size: 30rpx;
+		color: #101010;
+		font-weight: bold;
+	}
+</style>

+ 664 - 0
pages/map/map - 副本.vue

xqd
@@ -0,0 +1,664 @@
+<template>
+	<view class="map">
+		<!-- 查询 -->
+		<view class="address">
+			<view style="width: 750rpx; height:1200rpx;">
+				<map subkey='CQIBZ-P2MR5-PM3IB-QRKTX-SEVJE-GYF34' id="map" class="maps"
+					@regionchange="onMapRegionChange" @tap="onMapTap" @markertap="onmarkertap" enable3D="true"
+					enableBuilding="true" enableScroll="true" enableZoom="true" :latitude="latitude"
+					:layerStyle="mapStyle" :longitude="longitude" :showCompass="false" :showLocation="true"
+					:showScale="false" :scale="scale" :markers="markers"></map>
+			</view>
+		</view>
+		<tab-bar></tab-bar>
+	</view>
+</template>
+
+<script>
+	import TabBar from '../../components/TabBar/tabbar.vue'
+	import HchPosition from '../../components/hch-position/hch-position.vue'
+	export default {
+		components: {
+			TabBar,
+			HchPosition
+		},
+		data() {
+			return {
+				latitude: 39.924361, //中心纬度
+				longitude: 116.518557, //中心经度
+				mapStyle: 1, //个性化地图
+				scale: 16,//缩放级别
+				markers:[],//标记点
+			}
+		},
+
+		onLoad() {
+			//获取酒店列表
+			this.getList()
+			this.updated()
+		},
+
+		methods: {
+			//获取用户定位
+			updated() {
+				let _this = this
+				wx.getLocation({
+					type: "gcj02", //返回可以用于wx.openLocation的经纬度
+					success: function(res) {
+						_this.latitude = res.latitude
+						_this.longitude = res.longitude
+					},
+					fail: function(res) {
+						console.log(res);
+					}
+				})
+			},
+			//视野发生变化时触发
+			onMapRegionChange: function(e) {
+				// var t = e.causedBy, r = e.type, i = e.detail.region;
+				// if (("drag" == t || "scale" == t) && "end" == r) {
+				//     for (var n = i.northeast, o = i.southwest, l = this.data.markersSource, s = [], c = 0, u = l.length; c < u; c++) {
+				//         var d = l[c], g = d.latitude, p = d.longitude;
+				//         !d.load && g > o.latitude && g < n.latitude & p > o.longitude && p < n.longitude && (d.load = !0, 
+				//         s.push(d));
+				//     }
+				//     a.addMarkers({
+				//         markers: s,
+				//         clear: !1
+				//     });
+				// }
+			},
+			//点击地图时触发
+			onMapTap: function(e) {},
+			//点击标记点时触发
+			onmarkertap: function(e) {
+				var t = e.detail.markerId;
+				wx.vibrateShort({
+					type: "light"
+				});
+				var a = this.data,
+					r = a.swiperCurrent;
+				a.markersSource;
+				this.updateActiveMarker(r, t), this.setData({
+					swiperCurrent: t
+			 });
+			},
+			getList() {
+				this.$api.hotel.getHotelList({
+					page: 1
+				}).then(res => {
+					this.hotelList = res.data.data
+					console.log(this.hotelList);
+					this.markers = this.hotelList.map(item => {
+						return {
+							id: item.id,
+							latitude: item.latitude,
+							longitude: item.longitude,
+							width: '34rpx',
+							height: '40rpx',
+							iconPath: '/../../static/navigation.png',
+							callout: {
+								content: item.name,
+								borderRadius: 10,
+								padding: 10,
+								display: "ALWAYS",
+							}
+						}
+					})
+					console.log(this.markers);
+				})
+			},
+			//去预定页面
+			goBook() {
+				uni.navigateTo({
+					url: '/pages/map/hotel-book/index'
+				})
+			},
+			//返回上一级
+			returnBtn() {
+				this.isShow = !this.isShow
+			},
+			//打开酒店列表
+			goHotelList() {
+				console.log(111);
+				this.isShow = !this.isShow
+			},
+			//是否展示加盟品牌
+			selectJoin() {
+				this.isJoin = !this.isJoin
+			},
+			//是否展示合作伙伴
+			selectPartner() {
+				this.isPartner = !this.isPartner
+			},
+			//合作伙伴刷选
+			change(e) {
+				console.log('e:', e);
+			},
+			//菜单index切换
+			checked(index) {
+				this.isActive = index
+			},
+			//展开地区选择
+			openArea() {
+				console.log(111);
+				this.isSelectArea = !this.isSelectArea
+			},
+			//展开品牌选择
+			openBrand() {
+				this.isSelectBrand = !this.isSelectBrand
+			},
+			//展开筛选选择
+			openSift() {
+				this.isSelectSift = !this.isSelectSift
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	page {
+		height: 100%;
+	}
+
+	.map {
+		height: 100%;
+		background-color: #f9f9f9;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.maps {
+		width: 100%;
+		height: 1200rpx;
+	}
+
+	.return-btn {
+		position: fixed;
+		right: 0;
+		top: 927rpx;
+		z-index: 99;
+	}
+
+	.home-bottom {
+		height: 60rpx;
+		background-color: #f9f9f9;
+	}
+
+	.hotel-list {
+		width: 100%;
+		background-color: #f9f9f9;
+		padding: 32rpx 30rpx;
+		padding-bottom: 200rpx;
+
+		.hotel-list-item {
+			width: 100%;
+			margin-bottom: 20rpx;
+
+			.wrap {
+				width: 100%;
+				height: 318rpx;
+				position: relative;
+				box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.08);
+				border-radius: 10rpx;
+
+				.inner {
+					width: 100%;
+					height: 318rpx;
+					border-radius: 10rpx;
+					background: rgba(0, 0, 0, 0.4);
+					position: absolute;
+					z-index: 2;
+					top: 0;
+					left: 0;
+
+					.address-detail-main {
+						position: absolute;
+						left: 0;
+						bottom: 30rpx;
+						width: 100%;
+						display: flex;
+						align-items: flex-end;
+						justify-content: space-between;
+
+						.address-detail-main-left {
+							position: absolute;
+							left: 20rpx;
+
+							.title {
+								font-size: 32rpx;
+								font-weight: bold;
+								color: #FFFFFF;
+							}
+
+							.content {
+								margin: 12rpx 0 20rpx;
+								width: 92rpx;
+								height: 34rpx;
+								background: rgba(142, 160, 166, .6);
+								border-radius: 17rpx;
+								color: #ffffff;
+								font-size: 22rpx;
+								display: flex;
+								align-items: center;
+								justify-content: center;
+							}
+
+							.bottom {
+								display: flex;
+								align-items: center;
+								justify-content: flex-start;
+
+								.bottom-left {
+									font-size: 24rpx;
+									font-weight: bold;
+									color: #ffffff;
+									margin-right: 6rpx;
+								}
+
+								.bottom-right {
+									font-size: 32rpx;
+									font-weight: bold;
+									color: #ffffff;
+								}
+							}
+						}
+
+						.address-detail-main-right {
+							position: absolute;
+							right: 24rpx;
+							width: 120rpx;
+							height: 44rpx;
+							background: #FF6300;
+							box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.08);
+							border-radius: 22rpx;
+							display: flex;
+							align-items: center;
+							justify-content: center;
+							color: #ffffff;
+							font-size: 28rpx;
+						}
+					}
+
+					.address-detail-position {
+						position: absolute;
+						top: 22rpx;
+						right: 24rpx;
+						display: flex;
+						align-items: center;
+						justify-content: center;
+						font-weight: 500;
+						color: #FFFFFF;
+						font-size: 20rpx;
+					}
+				}
+			}
+
+
+		}
+	}
+
+	.search-detail {
+		width: 100%;
+		position: absolute;
+		top: 88rpx;
+		z-index: 999 !important;
+		background-color: #ffffff;
+		box-shadow: 0px 12rpx 16rpx 0px rgba(220, 222, 229, 0.4);
+		padding: 20rpx 30rpx 20rpx;
+
+		.partner {
+			.partner-top {
+				height: 88rpx;
+				border-top: 2rpx solid #F0F0F0;
+				border-bottom: 2rpx solid #F0F0F0;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				color: #333;
+				font-size: 28rpx;
+			}
+
+			.partner-main {
+				margin-top: 32rpx;
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box {
+					width: 26%;
+				}
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box .checkbox__inner {
+					width: 48rpx;
+					height: 48rpx;
+				}
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box .checkbox__inner .checkbox__inner-icon {
+					top: 6rpx !important;
+					left: 17rpx !important;
+					height: 24rpx !important;
+					width: 15rpx !important;
+					border-right-color: #ff6200;
+					border-bottom-color: #ff6200;
+				}
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box.is--default.is-checked .checklist-text {
+					color: #666 !important;
+					font-size: 24rpx !important;
+				}
+
+				::v-deep .checklist-text {
+					font-size: 24rpx !important;
+				}
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box.is--default.is-checked .checkbox__inner {
+					border-color: #EDEDED !important;
+					background-color: #ffffff;
+				}
+			}
+		}
+
+		.search-detail-area {
+			width: 100%;
+			display: flex;
+			flex-wrap: wrap;
+			justify-content: flex-start;
+			align-items: center;
+
+			.areaTitle {
+				width: 156rpx;
+				height: 56rpx;
+				background: #FFFFFF;
+				border: 2rpx solid #EDEDED;
+				border-radius: 28rpx;
+				font-size: 28rpx;
+				color: #666;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				margin-right: 20rpx;
+				margin-bottom: 18rpx;
+
+				&:nth-child(4n) {
+					margin-right: 0;
+				}
+			}
+
+			// .areaTitle-item {
+			// 	width: 156rpx;
+			// 	height: 56rpx;
+			// 	background-color: #F1F1F1;
+			// 	border-radius: 26rpx;
+			// 	font-size: 24rpx;
+			// 	color: #999;
+			// 	display: flex;
+			// 	justify-content: center;
+			// 	align-items: center;
+			// }
+			.active-area {
+				width: 156rpx;
+				height: 56rpx;
+				border-radius: 28rpx;
+				background-color: #FF6200;
+				color: #fff;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+			}
+		}
+
+		.search-detail-btn {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			margin: 38rpx 0 20rpx;
+
+			.search-detail-btn-left {
+				flex: 1;
+				height: 76rpx;
+				background: rgba(237, 237, 237, .55);
+				border-radius: 8rpx;
+				color: #999999;
+				font-size: 30rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-weight: bold;
+
+			}
+
+			.search-detail-btn-right {
+				flex: 1;
+				height: 76rpx;
+				background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+				border-radius: 8rpx;
+				color: #FFFFFF;
+				font-size: 30rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-left: 22rpx;
+				font-weight: bold;
+			}
+
+		}
+
+		::v-deep .u-input {
+			width: 690rpx !important;
+			height: 68rpx !important;
+			background: #F1F1F1;
+			border-radius: 74rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper {
+			padding-left: 36rpx;
+		}
+	}
+
+
+	.search-top {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+	}
+
+	.search {
+		position: relative;
+		flex: none;
+		width: 100%;
+		background: #FFFFFF;
+		box-shadow: 0px 12rpx 16rpx 0px rgba(220, 222, 229, 0.4);
+		display: flex;
+		flex-direction: column;
+		align-items: inherit;
+		justify-content: space-between;
+
+		.search-loupe {
+			flex: none;
+			width: 60rpx;
+			height: 60rpx;
+			background: #FFFFFF;
+			border-radius: 50%;
+			border: 2rpx solid #EDEDED;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			margin-right: 16rpx;
+		}
+
+		.search-area-all {
+			flex: 1;
+			display: flex;
+			align-items: center;
+			justify-content: flex-start;
+
+			.search-areaClick {
+				padding: 12rpx 22rpx;
+				height: 52rpx;
+				background: #FFFFFF;
+				border-radius: 26rpx;
+				border: 2rpx solid #FF6200;
+				font-weight: 500;
+				color: #FF6200;
+				font-size: 28rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-right: 16rpx;
+
+				text {
+					margin-right: 8rpx;
+				}
+			}
+
+			.search-area {
+				padding: 12rpx 22rpx;
+				height: 52rpx;
+				background: #FFFFFF;
+				border-radius: 26rpx;
+				border: 2rpx solid #EDEDED;
+				font-weight: 500;
+				color: #666666;
+				font-size: 28rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-right: 16rpx;
+
+				text {
+					margin-right: 8rpx;
+				}
+			}
+		}
+
+	}
+
+	.address-nav {
+		position: absolute;
+		width: 100%;
+		bottom: 34rpx;
+		padding: 0 16rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: space-between;
+		overflow-x: scroll;
+
+		.address-nav-btn {
+			width: 100%;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+		}
+
+	}
+
+	.address {
+		flex: 1;
+		position: relative;
+
+		.address-detail {
+			position: relative;
+			flex: none;
+			width: 496rpx;
+			border-radius: 10rpx;
+			margin-right: 16rpx;
+
+			&:last-child {
+				margin-right: 0rpx;
+			}
+
+			.inner {
+				width: 100%;
+				height: 318rpx;
+				border-radius: 10rpx;
+				background: rgba(0, 0, 0, 0.4);
+				position: absolute;
+				z-index: 2;
+				top: 0;
+				left: 0;
+
+				.address-detail-main {
+					position: absolute;
+					left: 0;
+					bottom: 30rpx;
+					width: 100%;
+					display: flex;
+					align-items: flex-end;
+					justify-content: space-between;
+
+					.address-detail-main-left {
+						position: absolute;
+						left: 20rpx;
+
+						.title {
+							font-size: 32rpx;
+							font-weight: bold;
+							color: #FFFFFF;
+						}
+
+						.content {
+							margin: 12rpx 0 20rpx;
+							width: 92rpx;
+							height: 34rpx;
+							background: rgba(142, 160, 166, .6);
+							border-radius: 17rpx;
+							color: #ffffff;
+							font-size: 22rpx;
+							display: flex;
+							align-items: center;
+							justify-content: center;
+						}
+
+						.bottom {
+							display: flex;
+							align-items: center;
+							justify-content: flex-start;
+
+							.bottom-left {
+								font-size: 24rpx;
+								font-weight: bold;
+								color: #ffffff;
+								margin-right: 6rpx;
+							}
+
+							.bottom-right {
+								font-size: 32rpx;
+								font-weight: bold;
+								color: #ffffff;
+							}
+						}
+					}
+
+					.address-detail-main-right {
+						position: absolute;
+						right: 24rpx;
+						width: 120rpx;
+						height: 44rpx;
+						background: #FF6300;
+						box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.08);
+						border-radius: 22rpx;
+						display: flex;
+						align-items: center;
+						justify-content: center;
+						color: #ffffff;
+						font-size: 28rpx;
+					}
+
+				}
+
+				.address-detail-position {
+					position: absolute;
+					top: 22rpx;
+					right: 24rpx;
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					font-weight: 500;
+					color: #FFFFFF;
+					font-size: 20rpx;
+				}
+			}
+
+
+		}
+	}
+</style>

+ 1021 - 0
pages/map/map.vue

xqd
@@ -0,0 +1,1021 @@
+<template>
+	<view class="map">
+		<MyNav title="IHG地图" bgColor="" :backIcon="false"></MyNav>
+		<!-- 查询 -->
+		<view class="search" v-if="true">
+			<view class="search-top" style="padding: 16rpx 30rpx 0rpx;margin-bottom: 20rpx;">
+				<view class="search-loupe" @click="isopenSearch = !isopenSearch">
+					<image style="width: 32rpx;height: 32rpx;" src="/static/icon/search02.png" mode=""></image>
+				</view>
+				<view class="search-area-all">
+					<view :class="isSelectArea?'search-area':'search-areaClick'" @click="openArea">
+						<text>地区</text>
+						<image v-if="isSelectArea" style="width: 16rpx;height: 10rpx;" src="/static/icon/down01.png"
+							mode="">
+						</image>
+						<image v-if="!isSelectArea" style="width: 16rpx;height: 10rpx;" src="/static/icon/up01.png"
+							mode="">
+						</image>
+					</view>
+					<view :class="isSelectBrand?'search-area':'search-areaClick'" @click="openBrand">
+						<text>品牌</text>
+						<image v-if="isSelectBrand" style="width: 16rpx;height: 10rpx;" src="/static/icon/down01.png"
+							mode="">
+						</image>
+						<image v-if="!isSelectBrand" style="width: 16rpx;height: 10rpx;" src="/static/icon/up01.png"
+							mode="">
+						</image>
+					</view>
+					<view class="search-area" :class="isSelectSift?'search-area':'search-areaClick'" @click="openSift">
+						<text>更多筛选</text>
+						<image v-if="isSelectSift" style="width: 16rpx;height: 10rpx;" src="/static/icon/down01.png"
+							mode="">
+						</image>
+						<image v-if="!isSelectSift" style="width: 16rpx;height: 10rpx;" src="/static/icon/up01.png"
+							mode="">
+						</image>
+					</view>
+				</view>
+				<image style=" flex: none; width: 52rpx;height: 46rpx;" src="/static/icon/vip.png" mode=""></image>
+			</view>
+			<view class="search-detail" v-if="isopenSearch">
+				<u-input placeholder="输入酒店/城市名称搜索酒店" border='none'>
+					<template slot="suffix" style='margin-right:40rpx;'>
+						<u-image :showLoading="true" :showError='true' src="/static/icon/search.png" width="40rpx"
+							height="32rpx"></u-image>
+					</template>
+				</u-input>
+			</view>
+			<!-- 选择地区 -->
+			<view class="search-detail" v-if="!isSelectArea">
+				<view class="search-detail-area">
+					<view class="areaTitle" v-for="(item,index) in areaList" :key="index" @click="checked(index)">
+						<view :class="{'active-area':isActive === index}">
+							{{item.title}}
+						</view>
+					</view>
+				</view>
+				<view class="search-detail-btn">
+					<view class="search-detail-btn-left">
+						<text>取消</text>
+					</view>
+					<view class="search-detail-btn-right">
+						<text>确认</text>
+					</view>
+				</view>
+			</view>
+			<!-- 选择品牌-->
+			<view class="search-detail" v-if="!isSelectBrand">
+				<view class="search-detail-area">
+					<view class="areaTitle" v-for="(item,index) in brandList" :key="index" @click="checked(index)">
+						<view :class="{'active-area':isActive === index}">
+							{{item.title}}
+						</view>
+					</view>
+				</view>
+				<view class="search-detail-btn">
+					<view class="search-detail-btn-left">
+						<text>取消</text>
+					</view>
+					<view class="search-detail-btn-right">
+						<text>确认</text>
+					</view>
+				</view>
+			</view>
+			<!-- 筛选-->
+			<view class="search-detail" v-if="!isSelectSift">
+				<view class="partner">
+					<view class="partner-top" @click="selectPartner">
+						<text>合作伙伴</text>
+						<image v-if="isPartner" style=" width: 20rpx; height: 12rpx; " src="/static/icon/up02.png"
+							mode=""></image>
+						<image v-if="!isPartner" style=" width: 20rpx; height: 12rpx; " src="/static/icon/down02.png"
+							mode=""></image>
+					</view>
+					<view class="partner-main" v-if="isPartner">
+						<uni-data-checkbox multiple v-model="value" :localdata="partner" @change="change">
+						</uni-data-checkbox>
+					</view>
+
+					<view class="partner-top" style="border-top: none;" @click="selectJoin">
+						<text>加盟品牌</text>
+						<image v-if="isJoin" style=" width: 20rpx; height: 12rpx; " src="/static/icon/up02.png" mode="">
+						</image>
+						<image v-if="!isJoin" style=" width: 20rpx; height: 12rpx; " src="/static/icon/down02.png"
+							mode=""></image>
+					</view>
+					<view class="partner-main" v-if="isJoin">
+						<uni-data-checkbox multiple v-model="value" :localdata="partner" @change="change">
+						</uni-data-checkbox>
+					</view>
+
+					<view class="search-detail-btn">
+						<view class="search-detail-btn-left">
+							<text>取消</text>
+						</view>
+						<view class="search-detail-btn-right">
+							<text>确认</text>
+						</view>
+					</view>
+				</view>
+
+			</view>
+
+		</view>
+		<view class="address" v-if="isShow">
+			<view style="height:1232rpx;">
+				<hch-position ref="map" :markers="markers" @moveToMarkId="moveToMarkId"/>
+			</view>
+			<view class="address-nav" style="overflow-x: visible;">
+				<view class="address-nav-btn">
+					<view class="" @click="goLocation">
+						<image style="width: 84rpx;height: 84rpx;" src="/static/icon/location.png" mode=""></image>
+					</view>
+					<view class="" @click="goHotelList">
+						<image style="width: 84rpx;height: 84rpx;" src="/static/icon/list.png" mode=""></image>
+					</view>
+				</view>
+				<view id="switch-container"
+					style="width: 100%; overflow-x: scroll; display: none;align-items: center;justify-content: space-between;">	
+				</view>
+				<scroll-view style="width: calc(100% + 32rpx);height:318rpx;white-space: nowrap;" :scroll-x="true" :scroll-left="scrolls.scrollX" :scroll-with-animation="true">
+					<view style="width: 16rpx;display: inline-block;"></view>
+					<view class="address-detail" v-for="(item,index) in hotelList" :key="index">
+						<view class="mark">
+							<image style=""
+								:src="item.bg_img" mode="aspectFill"></image>
+						</view>
+						<view class="inner">
+							<view class="address-detail-main">
+								<view class="address-detail-main-left">
+									<text class="title">{{item.name}}</text>
+									<view class="content">
+										<text>{{item.label}}</text>
+									</view>
+									<view class="bottom">
+										<text class="bottom-left">¥</text>
+										<text class="bottom-right">{{item.min_price}}起</text>
+									</view>
+								</view>
+								<view class="address-detail-main-right" @click="goBook(item.id)">
+									<text>预订</text>
+								</view>
+							</view>
+							<view class="address-detail-position">
+								<image style="width: 18rpx;height: 22rpx;" src="/static/icon/address02.png" mode="">
+								</image>
+								<text style="margin-left:4rpx ;">{{item.distance}}km</text>
+							</view>
+						</view>
+					</view>
+					<view style="width: 1rpx;display: inline-block;"></view>
+				</scroll-view>
+			</view>
+		</view>
+
+		<!-- 酒店列表 -->
+		<view class="hotel-list" v-if="!isShow">
+			<view class="hotel-list-item" v-for="(item,index) in hotelList" :key="index" @click="goBook(item.id)">
+				<view class="wrap">
+					<view class="mark">
+						<image style="width: 694rpx;height: 318rpx;border-radius: 10rpx;" :src="item.bg_img"
+							mode=""></image>
+					</view>
+					<view class="inner">
+						<view class="address-detail-main">
+							<view class="address-detail-main-left">
+								<text class="title">{{item.name}}</text>
+								<view class="content">
+									<text>{{item.label}}</text>
+								</view>
+								<view class="bottom">
+									<text class="bottom-left">¥</text>
+									<text class="bottom-right">{{item.min_price}}起</text>
+								</view>
+							</view>
+							<view class="address-detail-main-right" @click.stop="goBook(item.id)">
+								<text>预订</text>
+							</view>
+						</view>
+						<view class="address-detail-position">
+							<image style="width: 18rpx;height: 22rpx;" src="/static/icon/address02.png" mode=""></image>
+							<text style="margin-left:4rpx ;">{{item.distance}}km</text>
+						</view>
+					</view>
+				</view>
+			</view>
+			<!-- 触底 -->
+			<view class="home-bottom">
+				<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText" />
+			</view>
+			<view class="return-btn" @click="returnBtn">
+				<image style="width: 132rpx;height: 132rpx;border-radius: 50%;" src="/static/icon/return01.png" mode="">
+				</image>
+			</view>
+
+		</view>
+		<view style="height: 110rpx;"></view>
+		<tab-bar></tab-bar>
+	</view>
+</template>
+
+<script>
+	import TabBar from '../../components/TabBar/tabbar.vue'
+	import HchPosition from '../../components/hch-position/hch-position.vue'
+	import MyNav from "@/components/my-nav/my-nav.vue"
+	export default {
+		components: {
+			TabBar,
+			HchPosition,
+			MyNav
+		},
+		data() {
+			return {
+				scrolls:{scrollX: 0},
+				hotelList:[],
+				//门店在地图上的标记 以下字段必填
+				markers: [],
+				//经纬度
+				latitude:'',
+				longitude:'',
+				//暂无数据
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				//是否展示地图
+				isShow: true,
+				value: [0],
+				//合作伙伴
+				partner: [{
+					text: '足球',
+					value: 0
+				}, {
+					text: '篮球',
+					value: 1
+				}, {
+					text: '游泳',
+					value: 2
+				}, {
+					text: '游泳',
+					value: 3
+				}, {
+					text: '游泳',
+					value: 4
+				}, {
+					text: '游泳',
+					value: 5
+				}, {
+					text: '游泳',
+					value: 6
+				}, {
+					text: '游泳',
+					value: 7
+				}, ],
+
+				//品牌
+				brandList: [{
+					title: '谷歌'
+				}, {
+					title: '微软'
+				}, {
+					title: 'iphone'
+				}, {
+					title: '新希望'
+				}, {
+					title: '三江重工'
+				}, {
+					title: 'JavaScript'
+				}],
+				//地区
+				areaList: [{
+					title: '重庆'
+				}, {
+					title: '成都'
+				}, {
+					title: '绵阳'
+				}, {
+					title: '广汉'
+				}, {
+					title: '内江'
+				}, {
+					title: '宜宾'
+				}, {
+					title: '大理'
+				}, {
+					title: '自贡'
+				}, {
+					title: '贵州'
+				}, {
+					title: '泸州'
+				}],
+				//激活指定table菜单
+				isActive: 0,
+				//展开搜索
+				isopenSearch: false,
+				//选择地区
+				isSelectArea: true,
+				//选择品牌
+				isSelectBrand: true,
+				//刷选
+				isSelectSift: true,
+				//是否展示合作伙伴
+				isPartner: false,
+				//是否展示加盟品牌
+				isJoin: false,
+			}
+		},
+		onLoad() {
+			//获取经纬度
+			this.updated()
+			
+			this.$api.hotel.getHotelCategory().then(res=>{
+				console.log(res)
+			})
+		},
+
+		methods: {
+			goLocation(){
+				let _this = this
+				uni.getLocation({
+					type: "gcj02", //返回可以用于wx.openLocation的经纬度
+					success: function(res) {
+						_this.latitude = res.latitude
+						_this.longitude = res.longitude
+						_this.$refs.map.goLocation(res.latitude,res.longitude)
+						//获取酒店列表
+						_this.getList()
+					},
+					fail: function(res) {
+						console.log(res)
+					}
+				})
+			},
+			//在地图渲染更新完成时触发的方法
+			updated() {
+				let _this = this
+				uni.getLocation({
+					type: "gcj02", //返回可以用于wx.openLocation的经纬度
+					success: function(res) {
+						_this.latitude = res.latitude
+						_this.longitude = res.longitude
+						_this.$refs.map.goLocation(res.latitude,res.longitude)
+						//获取酒店列表
+						_this.getList()
+					},
+					fail: function(res) {
+						console.log(res)
+					}
+				})
+			},
+			//计算酒店距离我的位置--int
+			calcDistanceFromHotel({x0,y0},{x1,y1}){
+				//x0,y0是我的坐标(经纬度)
+				//x1,y1是酒店坐标(经纬度)
+				// console.log(x0,y0,x1,y1);
+				return this.space(x0,y0,x1,y1);
+				return Math.sqrt(Math.pow(Math.abs(x1-x0),2)+Math.pow(Math.abs(y1-y0),2));//返回距离
+			},
+			//遍历所有酒店,并计算出酒店分别与我的距离--数组
+			setEachHotelDistance(hotelArray=[],{x0,y0}){
+				hotelArray.map(item=>{
+					item.distanceToMe=this.calcDistanceFromHotel({x0,y0},{x1:item.longitude,y1:item.latitude})
+					return item;
+				})
+				return hotelArray;
+				
+			},
+			//筛选出距离我最近的酒店--对象
+			getMinDistanceHotel({x0,y0}){
+				this.markers=this.setEachHotelDistance(this.markers,{x0,y0});
+				this.markers.sort((prev,next)=>{
+					return prev.distanceToMe-next.distanceToMe;
+				})
+				return this.markers[0];
+			},
+			space(lat1, lng1, lat2, lng2) {
+			  var radLat1 = lat1 * Math.PI / 180.0;
+			  var radLat2 = lat2 * Math.PI / 180.0;
+			  var a = radLat1 - radLat2;
+			  var b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0;
+			  var s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
+					 Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
+			  s = s * 6378.137;
+			  s = Math.round(s * 10000) / 10000;
+			  return s  // 单位千米
+			},
+			//-------------------------------------
+			getList() {
+				this.$api.hotel.getHotelList({
+					page: 1
+				}).then(res => {
+					this.hotelList = res.data.data
+					this.markers = this.hotelList.map(item=>{
+						const distance =this.calcDistanceFromHotel({x0:this.latitude, y0:this.longitude}, {x1:item.latitude,y1:item.longitude}).toFixed(1);
+						item.distance = distance;
+						return {
+							id:item.id,
+							latitude: item.latitude,
+							longitude: item.longitude,
+							width:'34rpx',
+							height:'40rpx',
+							iconPath:'../../static/icon/late02.png' ,
+							distance: distance,
+							active: {
+								width: '90rpx',
+								height: '100rpx',
+								iconPath: item.logo,
+							},
+							noActive:{
+								width:'34rpx',
+								height:'40rpx',
+								iconPath:'../../static/icon/late02.png' ,
+							},
+							callout1: {
+								content:item.name,
+								borderRadius: 10,
+								padding: 10,
+								display: "ALWAYS",
+							}	
+						}
+					})
+					console.log(this.markers, '----->markers')
+					let mylongitude = this.longitude
+					let mylatitude = this.latitude
+					let a = this.getMinDistanceHotel({x0:mylongitude,y0:mylatitude})
+					console.log(a,'----->最近酒店');
+				})
+			},
+			//去预定页面
+			goBook(id) {
+				uni.navigateTo({
+					url: '/pages/map/hotel-book/index?hotel_id='+id
+				})
+			},
+			//返回上一级
+			returnBtn() {
+				this.isShow = !this.isShow
+			},
+			//打开酒店列表
+			goHotelList() {
+				console.log(111);
+				this.isShow = !this.isShow
+			},
+			//是否展示加盟品牌
+			selectJoin() {
+				this.isJoin = !this.isJoin
+			},
+			//是否展示合作伙伴
+			selectPartner() {
+				this.isPartner = !this.isPartner
+			},
+			//合作伙伴刷选
+			change(e) {
+				console.log('e:', e);
+			},
+			//菜单index切换
+			checked(index) {
+				this.isActive = index
+			},
+			//展开地区选择
+			openArea() {
+				console.log(111);
+				this.isSelectArea = !this.isSelectArea
+			},
+			//展开品牌选择
+			openBrand() {
+				this.isSelectBrand = !this.isSelectBrand
+			},
+			//展开筛选选择
+			openSift() {
+				this.isSelectSift = !this.isSelectSift
+			},
+			//下面酒店位移
+			moveToMarkId(markId){
+				this.markers.forEach((item,index) => {
+					if(markId == item.id){
+						this.scrolls.scrollX = ((496+16) * index) + 'rpx';
+						return;
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	page {
+		height: 100%;
+	}
+
+	.map {
+		height: 100%;
+		background-color: #f9f9f9;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.return-btn {
+		position: fixed;
+		right: 0;
+		top: 927rpx;
+		z-index: 99;
+	}
+
+	.home-bottom {
+		height: 60rpx;
+		background-color: #f9f9f9;
+	}
+
+	.hotel-list {
+		width: 100%;
+		background-color: #f9f9f9;
+		padding: 32rpx 30rpx;
+		padding-bottom: 200rpx;
+
+		.hotel-list-item {
+			width: 100%;
+			margin-bottom: 20rpx;
+
+			.wrap {
+				width: 100%;
+				height: 318rpx;
+				position: relative;
+				box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.08);
+				border-radius: 10rpx;
+
+				.inner {
+					width: 100%;
+					height: 318rpx;
+					border-radius: 10rpx;
+					position: absolute;
+					z-index: 2;
+					top: 0;
+					left: 0;
+
+					.address-detail-main {
+						position: absolute;
+						left: 0;
+						bottom: 30rpx;
+						width: 100%;
+						display: flex;
+						align-items: flex-end;
+						justify-content: space-between;
+
+						.address-detail-main-left {
+							position: absolute;
+							left: 20rpx;
+
+							.title {
+								font-size: 32rpx;
+								font-weight: bold;
+								color: #FFFFFF;
+							}
+
+							.content {
+								margin: 12rpx 0 20rpx;
+								width: 92rpx;
+								height: 34rpx;
+								background: rgba(142, 160, 166, .6);
+								border-radius: 17rpx;
+								color: #ffffff;
+								font-size: 22rpx;
+								display: flex;
+								align-items: center;
+								justify-content: center;
+							}
+
+							.bottom {
+								display: flex;
+								align-items: center;
+								justify-content: flex-start;
+
+								.bottom-left {
+									font-size: 24rpx;
+									font-weight: bold;
+									color: #ffffff;
+									margin-right: 6rpx;
+								}
+
+								.bottom-right {
+									font-size: 32rpx;
+									font-weight: bold;
+									color: #ffffff;
+								}
+							}
+						}
+
+						.address-detail-main-right {
+							position: absolute;
+							right: 24rpx;
+							width: 120rpx;
+							height: 44rpx;
+							background: #FF6300;
+							box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.08);
+							border-radius: 22rpx;
+							display: flex;
+							align-items: center;
+							justify-content: center;
+							color: #ffffff;
+							font-size: 28rpx;
+						}
+					}
+
+					.address-detail-position {
+						position: absolute;
+						top: 22rpx;
+						right: 24rpx;
+						display: flex;
+						align-items: center;
+						justify-content: center;
+						font-weight: 500;
+						color: #FFFFFF;
+						font-size: 20rpx;
+					}
+				}
+			}
+
+
+		}
+	}
+
+	.search-detail {
+		width: 100%;
+		position: absolute;
+		top: 88rpx;
+		z-index: 999 !important;
+		background-color: #ffffff;
+		box-shadow: 0px 12rpx 16rpx 0px rgba(220, 222, 229, 0.4);
+		padding: 20rpx 30rpx 20rpx;
+
+		.partner {
+			.partner-top {
+				height: 88rpx;
+				border-top: 2rpx solid #F0F0F0;
+				border-bottom: 2rpx solid #F0F0F0;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				color: #333;
+				font-size: 28rpx;
+			}
+
+			.partner-main {
+				margin-top: 32rpx;
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box {
+					width: 26%;
+				}
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box .checkbox__inner {
+					width: 48rpx;
+					height: 48rpx;
+				}
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box .checkbox__inner .checkbox__inner-icon {
+					top: 6rpx !important;
+					left: 17rpx !important;
+					height: 24rpx !important;
+					width: 15rpx !important;
+					border-right-color: #ff6200;
+					border-bottom-color: #ff6200;
+				}
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box.is--default.is-checked .checklist-text {
+					color: #666 !important;
+					font-size: 24rpx !important;
+				}
+
+				::v-deep .checklist-text {
+					font-size: 24rpx !important;
+				}
+
+				::v-deep .uni-data-checklist .checklist-group .checklist-box.is--default.is-checked .checkbox__inner {
+					border-color: #EDEDED !important;
+					background-color: #ffffff;
+				}
+			}
+		}
+
+		.search-detail-area {
+			width: 100%;
+			display: flex;
+			flex-wrap: wrap;
+			justify-content: flex-start;
+			align-items: center;
+
+			.areaTitle {
+				width: 156rpx;
+				height: 56rpx;
+				background: #FFFFFF;
+				border: 2rpx solid #EDEDED;
+				border-radius: 28rpx;
+				font-size: 28rpx;
+				color: #666;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+				margin-right: 20rpx;
+				margin-bottom: 18rpx;
+
+				&:nth-child(4n) {
+					margin-right: 0;
+				}
+			}
+
+			// .areaTitle-item {
+			// 	width: 156rpx;
+			// 	height: 56rpx;
+			// 	background-color: #F1F1F1;
+			// 	border-radius: 26rpx;
+			// 	font-size: 24rpx;
+			// 	color: #999;
+			// 	display: flex;
+			// 	justify-content: center;
+			// 	align-items: center;
+			// }
+			.active-area {
+				width: 156rpx;
+				height: 56rpx;
+				border-radius: 28rpx;
+				background-color: #FF6200;
+				color: #fff;
+				display: flex;
+				justify-content: center;
+				align-items: center;
+			}
+		}
+
+		.search-detail-btn {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			margin: 38rpx 0 20rpx;
+
+			.search-detail-btn-left {
+				flex: 1;
+				height: 76rpx;
+				background: rgba(237, 237, 237, .55);
+				border-radius: 8rpx;
+				color: #999999;
+				font-size: 30rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				font-weight: bold;
+
+			}
+
+			.search-detail-btn-right {
+				flex: 1;
+				height: 76rpx;
+				background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+				border-radius: 8rpx;
+				color: #FFFFFF;
+				font-size: 30rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-left: 22rpx;
+				font-weight: bold;
+			}
+
+		}
+
+		::v-deep .u-input {
+			width: 690rpx !important;
+			height: 68rpx !important;
+			background: #F1F1F1;
+			border-radius: 74rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper {
+			padding-left: 36rpx;
+		}
+	}
+
+
+	.search-top {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+	}
+
+	.search {
+		position: relative;
+		flex: none;
+		width: 100%;
+		background: #FFFFFF;
+		box-shadow: 0px 12rpx 16rpx 0px rgba(220, 222, 229, 0.4);
+		display: flex;
+		flex-direction: column;
+		align-items: inherit;
+		justify-content: space-between;
+
+		.search-loupe {
+			flex: none;
+			width: 60rpx;
+			height: 60rpx;
+			background: #FFFFFF;
+			border-radius: 50%;
+			border: 2rpx solid #EDEDED;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			margin-right: 16rpx;
+		}
+
+		.search-area-all {
+			flex: 1;
+			display: flex;
+			align-items: center;
+			justify-content: flex-start;
+
+			.search-areaClick {
+				padding: 12rpx 22rpx;
+				height: 52rpx;
+				background: #FFFFFF;
+				border-radius: 26rpx;
+				border: 2rpx solid #FF6200;
+				font-weight: 500;
+				color: #FF6200;
+				font-size: 28rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-right: 16rpx;
+
+				text {
+					margin-right: 8rpx;
+				}
+			}
+
+			.search-area {
+				padding: 12rpx 22rpx;
+				height: 52rpx;
+				background: #FFFFFF;
+				border-radius: 26rpx;
+				border: 2rpx solid #EDEDED;
+				font-weight: 500;
+				color: #666666;
+				font-size: 28rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-right: 16rpx;
+
+				text {
+					margin-right: 8rpx;
+				}
+			}
+		}
+
+	}
+
+	.address-nav {
+		position: absolute;
+		width: 100%;
+		bottom: 34rpx;
+		padding: 0 16rpx;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: space-between;
+		overflow-x: scroll;
+
+		.address-nav-btn {
+			width: 100%;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+		}
+
+	}
+
+	.address {
+		flex: 1;
+		position: relative;
+		
+
+		.address-detail {
+			display: inline-block;
+			position: relative;
+			flex: none;
+			width: 496rpx;
+			height: 318rpx;
+			border-radius: 10rpx;
+			margin-right: 16rpx;
+
+			&:last-child {
+				margin-right: 0rpx;
+			}
+			
+			.mark{
+				height: inherit;
+				width: inherit;
+				
+				image{
+					width: 100%;
+					height:100%;
+					border-radius: 10rpx;
+				}
+			}
+
+			.inner {
+				width: 100%;
+				height: inherit;
+				border-radius: 10rpx;
+				position: absolute;
+				z-index: 2;
+				top: 0;
+				left: 0;
+
+				.address-detail-main {
+					position: absolute;
+					left: 0;
+					bottom: 30rpx;
+					width: 100%;
+					display: flex;
+					align-items: flex-end;
+					justify-content: space-between;
+					
+
+					.address-detail-main-left {
+						position: absolute;
+						left: 20rpx;
+
+						.title {
+							font-size: 32rpx;
+							font-weight: bold;
+							color: #FFFFFF;
+						}
+
+						.content {
+							margin: 12rpx 0 20rpx;
+							width: 92rpx;
+							height: 34rpx;
+							background: rgba(142, 160, 166, .6);
+							border-radius: 17rpx;
+							color: #ffffff;
+							font-size: 22rpx;
+							display: flex;
+							align-items: center;
+							justify-content: center;
+						}
+
+						.bottom {
+							display: flex;
+							align-items: center;
+							justify-content: flex-start;
+
+							.bottom-left {
+								font-size: 24rpx;
+								font-weight: bold;
+								color: #ffffff;
+								margin-right: 6rpx;
+							}
+
+							.bottom-right {
+								font-size: 32rpx;
+								font-weight: bold;
+								color: #ffffff;
+							}
+						}
+					}
+
+					.address-detail-main-right {
+						position: absolute;
+						right: 24rpx;
+						width: 120rpx;
+						height: 44rpx;
+						background: #FF6300;
+						box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.08);
+						border-radius: 22rpx;
+						display: flex;
+						align-items: center;
+						justify-content: center;
+						color: #ffffff;
+						font-size: 28rpx;
+					}
+
+				}
+
+				.address-detail-position {
+					position: absolute;
+					top: 22rpx;
+					right: 24rpx;
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					font-weight: 500;
+					color: #FFFFFF;
+					font-size: 20rpx;
+				}
+			}
+
+
+		}
+	}
+</style>

+ 236 - 0
pages/msg/msg.vue

xqd
@@ -0,0 +1,236 @@
+<template>
+
+	<view class="msg">
+		<MyNav title="消息" bgColor="" :backIcon="false"></MyNav>
+		<!-- <!自定义导航栏
+		 <u-navbar title='消息' fixed safeAreaInsetTop :placeholder='true' :bgColor="bgColor" >
+		 </u-navbar> -->
+		<!-- 搜索框 -->
+		<view class="search">
+			<u-input placeholder="搜索" border='none' v-model="search"  @input="searchText">
+				<template slot="suffix" style='margin-right:40rpx;'>
+					<u-image :showLoading="true" :showError='true' src="/static/icon/search.png" width="40rpx"
+						height="32rpx"></u-image>
+				</template>
+			</u-input>
+		</view>
+
+		<!-- 消息列表 -->
+		<view class="msgListBox">
+			<view class="childBox" v-for="(item,index) in messageList" :key="index" >
+				<view class="childBox-top" >{{item.title}}</view>
+				<view  class="childBox-content" >
+					<text>{{item.content}}</text>
+					<image style="width: 12rpx;height: 20rpx;" src="/static/icon/right.png" ></image>
+				</view>
+				<view class="childBox-bom">{{item.created_at}}</view>
+			</view>
+			<uni-swipe-action v-if="false">
+				<uni-swipe-action-item :right-options="options" v-for="(item,index) in messageList" :key="index">
+					<template v-slot:right>
+						<view style="display: flex;align-items: center;justify-content: center;">
+							<image src="/static/icon//data.png" style="width: 60rpx; height: 54rpx;"></image>
+							<text class="slot-button-text">删除</text>
+						</view>
+					</template>
+					<view class="childBox">
+						<view class="childBox-top">{{item.title}}</view>
+						<view class="childBox-content">
+							<text>{{item.content}}</text>
+							<image style="width: 12rpx;height: 20rpx;" src="/static/icon/right.png"></image>
+						</view>
+						<view class="childBox-bom">{{item.created_at}}</view>
+					</view>
+				</uni-swipe-action-item>
+			</uni-swipe-action>
+		</view>
+
+		<!-- 触底 -->
+		<view class="home-bottom">
+			<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText" />
+		</view>
+
+		<!-- 底部导航栏 -->
+		<view style="height: 140rpx; width: 100%;"></view>
+		<tab-bar checked="msg"></tab-bar>
+
+	</view>
+</template>
+
+<script>
+	import util from '@/utils/util.js'
+	import TabBar from '../../components/TabBar/tabbar.vue'
+	import MyNav from "@/components/my-nav/my-nav.vue"
+	export default {
+		components: {
+			TabBar,
+			MyNav
+		},
+		data() {
+			return {
+				//自定义导航栏
+				bgColor: '#fff',
+				//搜索文字
+				search:'',
+				//删除按钮
+				options: [{
+					text: '删除',
+					style: {
+						backgroundColor: '#dd524d'
+					}
+				}],
+				//消息列表
+				messageList: '',
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+			};
+		},
+		onLoad() {
+			//获取消息列表
+			this.getMessageList()
+		},
+		methods: {
+			// 搜索防抖
+			searchText:util.debounce(function(){
+				if(this.search !=''){
+					this.goSearch()
+				}else{
+					this.getMessageList()
+				}
+			},500),
+			//搜索
+			goSearch(){
+				uni.showLoading({
+					title:'加载中'
+				})
+				this.$api.my.messageList({
+					page: 0,
+					keyword:this.search,
+				}).then(res=>{
+					if(res.code==0){
+						uni.hideLoading()
+						this.messageList = res.data.data
+					}
+				})
+			},
+			//获取消息列表
+			getMessageList() {
+				this.$api.my.messageList({
+					page: 0
+				}).then(res => {
+					this.messageList = res.data.data
+					console.log(this.messageList, '------>this.messageList');
+				})
+			},
+
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	// flex布局居中对齐
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.msg {
+		height: 100%;
+		background-color: $pageColor;
+	}
+
+	.home-bottom {
+		background-color: #f9f9f9;
+		padding-top: 120rpx;
+	}
+
+	// 搜索
+	.search {
+		// position: fixed;
+		// top: 0;
+		// width: 100%;
+		padding: 0 30rpx;
+		height: 124rpx;
+		background-color: $bgColor;
+		box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.04);
+		@include flexlayout;
+
+		::v-deep .u-input {
+			width: 690rpx !important;
+			height: 68rpx !important;
+			background: #F1F1F1;
+			border-radius: 74rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper {
+			padding-left: 36rpx;
+		}
+
+		::v-deep .u-input__content__field-wrapper__field {
+			color: #999999 !important;
+			font-size: 28rpx !important;
+		}
+	}
+
+	// 消息列表
+	.msgListBox {
+		padding: 48rpx 30rpx;
+		padding-top: 0;
+		margin-top: 24rpx;
+		background: $bgColor;
+		box-shadow: 0rpx 4rpx 24rpx -10rpx rgba(101, 95, 90, 0.3);
+		border-radius: 12rpx;
+		.childBox {
+			padding-top: 40rpx;
+			padding-bottom: 40rpx;
+			border-bottom: 2rpx solid rgba(240, 240, 240, .7);
+		
+			&:last-child {
+				padding-bottom: 0;
+				border-bottom: none;
+			}
+		
+			&:first-child {
+				padding-top: 48rpx;
+			}
+		
+			.childBox-top {
+				font-weight: bold;
+				color: #333333;
+				font-size: 32rpx;
+			}
+		
+			.childBox-content {
+				padding-right: 24rpx;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				color: #333333;
+				font-size: 28rpx;
+				margin: 24rpx 0 12rpx;
+			}
+		
+			.childBox-bom {
+				color: #999999;
+				font-size: 26rpx;
+			}
+		}
+	}
+
+	::v-deep .uni-swipe_text--center {
+		padding-bottom: 40rpx;
+		border-bottom: 2rpx solid rgba(240, 240, 240, 0.7);
+		&:last-child {
+			padding-bottom: 0;
+			border-bottom: none;
+		}		
+	}
+</style>

+ 182 - 0
pages/my/Kudos/Kudos.vue

xqd
@@ -0,0 +1,182 @@
+<template>
+	<view class="kudos">
+		<!-- 点赞列表 -->
+		<view class="List">
+			<view class="ListItem" v-for="(item,index) in List" :key="index" @click="goVoteDetail(item.id)">
+				<image :src="item.cover_img" style="width: 640rpx;height:420rpx;border-radius: 12rpx;"></image>
+				<view class="kudosicon">
+					<image src="/static/icon/Kudos.png" v-if="item.is_like!=1" @click.stop="clickKudos(item.id,index)"></image>
+					<image src="/static/icon/Kudos(1).png" v-if="item.is_like==1" @click.stop="clickKudos(item.id,index)"></image>
+				</view>
+				<view class="nav">
+					<view class="events">
+						<text>{{item.title}}</text>
+					</view>
+					<view class="voteStatus">
+						<text v-if="false">未开始</text>
+						<text style="color:#FF6503 ;">投票中</text>
+					</view>
+				</view>
+				<view class="foot">
+					<image src="/static/icon/data.png"></image>
+					<text>{{item.end_time}} 结束</text>
+				</view>
+			</view>
+		</view>
+		<!-- 已经到底啦 -->
+		<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText"/>
+	</view>
+</template>
+
+<script>
+	export default{
+		data(){
+			return{
+				//组件uni-load-more
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				// 点赞列表
+				List:[],
+			}
+		},
+		onLoad() {
+			this.getList()
+		},
+		methods:{
+			// 获取点赞列表
+			getList(){
+				this.$api.active.getActiveList({
+					page:1,
+					is_my_like:1
+				}).then(res=>{
+					console.log(res,"点赞列表")
+					if(res.code==0){
+						this.List=res.data.data
+					}else{
+						uni.showToast({
+							title:res.msg,
+							icon:'none'
+						})
+					}
+				})
+			},
+			// 跳转投票详情
+			goVoteDetail(id){
+				uni.navigateTo({
+					url:'/pages/index/active-detail/index?id='+id
+				})
+			},
+			// 点赞
+			clickKudos(id,index){
+				let beforeLike=this.List[index].is_like
+				this.$api.active.kudos({
+					activity_id:id
+				}).then(res=>{
+					console.log(res,'点赞')
+					if(res.code==0){
+						if(beforeLike==1){
+							this.List[index].is_like=0
+						}else{
+							this.List[index].is_like=1
+						}
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.kudos {
+		height: 100%;
+		background: $pageColor;
+	}
+
+	.List {
+		padding: 0 30rpx;
+		box-sizing: border-box;
+		padding-top: 24rpx;
+
+		.ListItem {
+			position: relative;
+			margin-bottom: 24rpx;
+			width: 690rpx;
+			height: 562rpx;
+			background: $bgColor;
+			box-shadow: 0rpx 12rpx 40rpx 0rpx rgba(220, 222, 229, 0.4);
+			border-radius: 24rpx;
+			padding: 20rpx 26rpx 26rpx 24rpx;
+
+			.kudosicon {
+				width: 48rpx;
+				position: absolute;
+				top: 52rpx;
+				right: 58rpx;
+				border-radius: 50%;
+				height: 48rpx;
+				background: #FFFFFF;
+				opacity: 0.84;
+				@include flexlayout()
+				image{
+					width: 29rpx;
+					height: 26rpx;
+				}
+			}
+
+			.nav {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+
+				.events {
+					text {
+						font-size: 30rpx;
+						font-family: PingFang-SC-Bold, PingFang-SC;
+						font-weight: bold;
+						color: #333333;
+					}
+				}
+
+				.voteStatus {
+					font-size: 30rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #999999;
+				}
+			}
+
+			.foot {
+				margin-top: 10rpx;
+				display: flex;
+				align-items: center;
+
+				image {
+					width: 28rpx;
+					height: 28rpx;
+					margin-right: 8rpx;
+				}
+
+				text {
+					font-size: 24rpx;
+					font-weight: 500;
+					color: #999999;
+					display: block;
+				}
+			}
+
+		}
+	}
+</style>

+ 323 - 0
pages/my/PersonalData/personalData.vue

xqd
@@ -0,0 +1,323 @@
+<template>
+	<view class="personalData">
+		<view class="form">
+			<uni-forms :modelValue="formData" label-position="top">
+				<uni-forms-item label="昵称" name="nickname">
+					<uni-easyinput placeholderStyle="color: #999; font-size:30rpx " type="text"
+						v-model="formData.nickname" placeholder="请输入姓名" />
+				</uni-forms-item>
+
+				<!--地区选择-->
+				<uni-forms-item label="地区" name="region">
+					<pickerAddress @change="change">
+						<view class="selectType">
+							<view class="uni-input">
+								<text style="color: #999999 ; font-size: 30rpx;" v-if="region==''">所在地区</text>
+								<text style="font-size: 30rpx;" v-if="region!=''">{{region}}</text>
+							</view>
+							<image src="/static/icon/right.png"
+								style="width: 14rpx;height: 24rpx;position: absolute;top:24rpx;right: 24rpx;">
+							</image>
+						</view>
+					</pickerAddress>
+				</uni-forms-item>
+
+				<uni-forms-item label="性别" name="sex">
+					<view class="sex">
+						<picker mode="selector" :value="sex_text" :range='sexSelect' @change="bindSexChange">
+							<view class="uni-input" @change="bindSexChange">
+								<text v-if="formData.sex==''||formData.sex==null"
+									style="color: #999999; font-size: 30rpx; ">选择性别</text>
+								<text v-if="formData.sex!=''">{{sex_text}}</text>
+							</view>
+							<image src="/static/icon/right.png" @change="bindSexChange"
+								style="width: 14rpx;height: 24rpx;position: absolute;top:22rpx;right: 30rpx;"></image>
+						</picker>
+					</view>
+				</uni-forms-item>
+				<uni-forms-item label="手机号" name="phone">
+					<uni-easyinput maxlength="11" placeholderStyle="color: #999; font-size:30rpx " type="number"
+						v-model="formData.mobile" placeholder="输入手机号" @blur="getPhone" />
+				</uni-forms-item>
+				<uni-forms-item label="生日" name="birthday">
+					<view class="birthday">
+						<picker mode="date" :value="formData.birthday" :start="startDate" :end="endDate"
+							@change="bindDateChange">
+							<view class="uni-input" @change="bindDateChange">
+								<text v-if="formData.birthday==''||formData.birthday==null"
+									style="color: #999999; font-size: 30rpx; ">选择生日</text>
+								<text v-if="formData.birthday!=''">{{formData.birthday}}</text>
+							</view>
+							<image src="/static/icon/right.png" @change="bindDateChange"
+								style="width: 14rpx;height: 24rpx;position: absolute;top:22rpx;right: 30rpx;"></image>
+						</picker>
+					</view>
+				</uni-forms-item>
+
+				<view class="keep-msg" @click="saveBtn">
+					<text>保存信息</text>
+				</view>
+
+			</uni-forms>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	import pickerAddress from '@/uni_modules/hu-pickerAddress/hu-pickerAddress.vue'
+	export default {
+		components: {
+			pickerAddress
+		},
+		data() {
+			const currentDate = this.getDate({
+				format: true
+			})
+			return {
+				formData: {
+					nickname: '',
+					sex: '',
+					birthday: '',
+					mobile: '',
+					area_id: ''
+				},
+				sexSelect: ['男', '女', '其他'],
+				sex_text: '',
+				region: '',
+			}
+		},
+		computed: {
+			startDate() {
+				return this.getDate('start');
+			},
+			endDate() {
+				return this.getDate('end');
+			}
+		},
+
+		onLoad() {
+			this.formData.nickname = this.$store.getters.userInfo.nickname
+			//获取用户信息
+			this.getUserInfo()
+		},
+
+		methods: {
+			//获取用户信息
+			getUserInfo(){
+				this.$api.my.userInfo().then(res=>{
+					console.log(res.data,'---->用户信息');
+					let obj ={}
+					obj.nickname = res.data.nickname
+					obj.mobile = res.data.mobile
+					obj.sex = res.data.sex
+					obj.birthday = res.data.birthday
+					obj.area_id = res.data.area_id
+					this.region = res.data.region
+					this.formData = obj
+					if(this.formData.sex == 0){
+						this.sex_text = '未知'
+					}else if(this.formData.sex == 1){
+						this.sex_text = '男'
+					}else if(this.formData.sex == 2){
+						this.sex_text = '女'
+					}
+					this.$store.getters.userInfo.nickname = obj.nickname
+				})
+			},
+		
+		
+			//获取手机号
+			getPhone() {
+				let phoneReg = /^[1][3,4,5,7,8,9][0-9]{9}$/
+				if (!phoneReg.test(this.formData.mobile)) {
+					uni.showToast({
+						title: '请输入合法手机号',
+						icon: "none"
+					})
+					return
+				}
+			},
+			change(ret) {
+				this.region = ret.data.join('-')
+				this.formData.area_id = ret.code[2]
+
+			},
+			bindDateChange: function(e) {
+				this.formData.birthday = e.detail.value
+			},
+			bindSexChange: function(e) {
+				if (e.detail.value == 0) {
+					this.sex_text = '男'
+					this.formData.sex = 1
+				} else if (e.detail.value == 1) {
+					this.sex_text = '女'
+					this.formData.sex = 2
+				} else {
+					this.sex_text = '其他'
+					this.formData.sex = 0
+				}
+			},
+			getDate(type) {
+				const date = new Date();
+				let year = date.getFullYear();
+				let month = date.getMonth() + 1;
+				let day = date.getDate();
+
+				if (type === 'start') {
+					year = year - 60;
+				} else if (type === 'end') {
+					year = year;
+				}
+				month = month > 9 ? month : '0' + month;
+				day = day > 9 ? day : '0' + day;
+				return `${year}-${month}-${day}`;
+			},
+
+			//保存信息
+			saveBtn() {
+				if (this.formData.nickname == '') {
+					uni.showToast({
+						title: '请输入昵称',
+						icon: "none"
+					})
+					return
+				}
+				if (this.formData.area_id == '') {
+					uni.showToast({
+						title: '请输入地区',
+						icon: "none"
+					})
+					return
+				}
+				if (this.formData.sex == '') {
+					uni.showToast({
+						title: '请输入性别',
+						icon: "none"
+					})
+					return
+				}
+				if (this.formData.mobile == '') {
+					uni.showToast({
+						title: '请输入手机号',
+						icon: "none"
+					})
+					return
+				}
+				if (this.formData.birthday == '') {
+					uni.showToast({
+						title: '请输入生日',
+						icon: "none"
+					})
+					return
+				}
+				this.$api.my.refreshPersonData(this.formData).then(res => {
+					if (res.code == 0) {
+						uni.showToast({
+							title: '保存成功',
+							icon: "none"
+						})
+						setTimeout(()=>{
+							uni.switchTab({
+								url:'/pages/my/my'
+							})
+						},500)
+						// let personData = JSON.parse(JSON.stringify(this.formData))
+						// personData.region = this.region
+						// personData.sex = this.sex_text
+						// console.log(personData,'---->personDate');
+						// this.$store.dispatch('user/person',personData)
+					} else {
+						uni.showToast({
+							title: res.msg,
+							icon: "none"
+						})
+					}
+				})
+
+			},
+
+
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	.personalData {
+		height: 100%;
+		background: $pageColor;
+	}
+
+	.selectType {
+		width: 100%;
+		height: 74rpx;
+		background: #FFFFFF;
+		border-radius: 8rpx;
+		border: 2rpx solid #EAEAEA;
+		display: flex;
+		align-items: center;
+		padding-left: 20rpx;
+		box-sizing: border-box;
+		position: relative;
+	}
+
+
+
+	.keep-msg {
+		width: 100%;
+		height: 92rpx;
+		background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+		border-radius: 12rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+
+		text {
+			font-weight: bold;
+			color: #FFFFFF;
+			font-size: 30rpx;
+		}
+	}
+
+	.form {
+		padding: 24rpx 48rpx 0 50rpx;
+
+		.birthday,
+		.sex {
+			width: 652rpx;
+			height: 74rpx;
+			background: #FFFFFF;
+			border-radius: 8rpx;
+			border: 1px solid #EAEAEA;
+			display: flex;
+			align-items: center;
+			padding-left: 20rpx;
+			box-sizing: border-box;
+			position: relative;
+		}
+	}
+
+	::v-deep .uni-forms-item__label {
+		font-weight: bold;
+		color: #333333;
+		font-size: 32rpx;
+	}
+
+	::v-deep .uni-easyinput__content-input {
+		color: #333333;
+		font-size: 32rpx;
+	}
+
+	::v-deep .is-input-border {
+		border-color: #e5e5e5 !important;
+		background-color: #fff !important;
+	}
+
+	::v-deep .uni-icons {
+		color: #c0c4cc !important;
+		font-size: 24px !important;
+	}
+</style>

+ 363 - 0
pages/my/integral/integral.vue

xqd
@@ -0,0 +1,363 @@
+<template>
+	<view class="integral">
+		<!-- 标题栏 -->
+		<view class="nav">
+			<image src="http://t9.9026.com/imgs/integralbg.png" style="width: 100%; height: 100%;"></image>
+			<view class="PointsColumn">
+				<image src="/static/icon/integralicon.png"></image>
+				<text>{{userIntegral}}</text>
+			</view>
+			<view class="titletext">
+				<view class="textitem" @click="gointegralRecord">
+					<image src="/static/icon/integralrecord.png"></image>
+					<text>积分记录</text>
+				</view>
+				<view class="textitem" @click="goMyorder">
+					<image src="/static/icon/lament.png"></image>
+					<text>我的兑换</text>
+				</view>
+				<view class="textitem" @click="gointegralRule">
+					<image src="/static/icon/integralrule.png"></image>
+					<text>积分规则</text>
+				</view>
+			</view>
+		</view>
+		
+		<!-- 占位 -->
+		<view  style="width: 100%; height: 238rpx; "></view>
+		
+		
+		<!-- 积分商品 -->
+		<view class="shopList">
+			<view class="listTop">
+				<text>积分兑换</text>
+			</view>
+			<view class="ListContent">
+				<!-- <view :class="item.short?'[contentItemShort,contentItem]':'[contentItemLong,contentItem]'" v-for="item in integralList" @click="goIntegralDetail(item.id)" >
+					<image :src="item.cover_img?item.cover_img:'http://t9.9026.com/imgs/loginBg.png'" ></image>
+					<view class="itemName">{{item.name}}</view>
+					<view class="itemPrice">{{item.integral}}积分</view>
+				</view> -->
+				<view class="home-hotel-img-content">
+				
+					<view @click="goIntegralDetail(item.id)" class="home-hotel-img-content-item" v-for="(item,index) in integralList" :key="index"
+						:style="{marginTop:item.marginTop || 0 }" >
+						<image class="home-hotel-img-content-item-img"
+							:class="item.short?'home-hotel-img-content-item-img': 'home-hotel-img-content-item-img-long' "
+							:src="item.cover_img" mode=""></image>
+						<view class="text">
+							<text class="text-top">{{item.name}}</text>
+							<text class="text-main">{{item.hotel.name}}</text>
+						</view>
+					</view>
+				
+				</view>
+			</view>
+			
+			<!-- 触底 -->
+			<view class="home-bottom">
+				<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText" />
+			</view>
+			
+		</view>
+	</view>
+</template>
+
+<script>
+	
+	export default{
+		data(){
+			return{
+				// 用户积分
+				userIntegral:0,
+				// 组件uni-load-more	
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				// 积分产品列表
+				integralList:[],	
+				arr:[],
+			
+			}
+		},
+		onLoad() {
+			this.getProductList()
+			console.log(this.$store.getters.userInfo)
+			this.userIntegral=this.$store.getters.userInfo.integral
+		},
+		methods:{
+			// 获取积分产品列表
+			getProductList(){
+				this.$api.product.getProducts({
+					page:0,
+					type:2,
+				}).then(res=>{
+					console.log(res,"积分产品")
+					if(res.code==0){
+						this.integralList=res.data.data
+						this.shortLong()
+					}
+				})
+			},
+			
+			shortLong() {
+				this.integralList.forEach((item, index, arr) => {
+					if (index % 4 === 0) {
+						item.short = true
+					}
+					if (index % 4 === 1) {
+						item.long = true
+					}
+					if (index % 4 === 2) {
+						item.long = true
+						item.marginTop = -68 + "rpx"
+					}
+					if (index % 4 === 3) {
+						item.short = true
+					}
+				})
+				console.log(this.goodsList);
+			},
+			
+			
+			
+			// 跳转积分规则
+			gointegralRule(){
+				uni.navigateTo({
+					url:'/pages/my/integral/integralRule'
+				})
+			},
+			// 跳转积分记录
+			gointegralRecord(){
+				uni.navigateTo({
+					url:'/pages/my/integral/integralRecord'
+				})
+			},
+			// 跳转积分产品详情
+			goIntegralDetail(id){
+				uni.navigateTo({
+					url:`/pages/goods/goods-detail/index?id=${id}&type=2`
+				})
+			},
+			// 跳转订单记录
+			goMyorder(){
+				uni.navigateTo({
+					url:'/pages/my/myorders/orders'
+				})
+			},
+
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+	// flex布局居中对齐
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+	.integral{
+		height: 100%;
+		background:$bgColor ;
+	}
+	.home-bottom {
+		background-color: #FFF;
+		padding-bottom: 84rpx;
+	}
+	.nav{
+		width: 100%;
+		height: 238rpx;
+		position: fixed;
+		z-index: 100;
+		background-color: #F9F9F9;
+		.PointsColumn{
+			position: absolute;
+			width: 690rpx;
+			border-radius: 8rpx;
+			height: 74rpx;
+			background: #FFFFFF;
+			border-radius: $bgColor;
+			left:30rpx;
+			top:32rpx;
+			display: flex;
+			align-items: center;
+			image{
+				margin-left: 30rpx;
+				width: 46rpx;
+				height: 46rpx;
+			}
+			text{
+				margin-left: 16rpx;
+				font-size: 48rpx;
+				font-family: DINAlternate-Bold, DINAlternate;
+				font-weight: 500;
+				color: #333333;
+			}
+		}
+		.titletext{
+			position: absolute;
+			bottom:30rpx;
+			left: 30rpx;
+			width: 690rpx;
+			height: 74rpx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			.textitem{
+				display: flex;
+				align-items: center;
+				image{
+					width: 44rpx;
+					height: 44rpx;
+				}
+				text{
+					margin-left: 8rpx;
+					font-size: 30rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: bold;
+					color: $bgColor;
+				}
+			}
+		}
+	}
+	.shopList{
+		padding-top: 24rpx;
+		width: 100%;
+		background: $bgColor;
+		border-radius: 16rpx 16rpx 0px 0px;
+		padding: 0 30rpx;
+		box-sizing: border-box;
+		padding-top: 32rpx;
+		.listTop{
+			@include flexlayout;
+			margin-bottom: 40rpx;
+			text{
+				font-size: 36rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #333333;
+			}
+		}
+		.ListContent{
+			
+			.home-hotel-img-content {
+					display: flex;
+					align-items: flex-start;
+					justify-content: space-between;
+					flex-wrap: wrap;
+			
+					.home-hotel-img-content-item {
+						width: 332rpx;
+						background: #FFFFFF;
+						box-shadow: 0px 4rpx 8rpx 0px rgba(0, 0, 0, 0.04);
+						border-radius: 12rpx;
+						margin-bottom: 26rpx;
+			
+						.home-hotel-img-content-item-img {
+							width: 332rpx;
+							height: 332rpx;
+							object-fit: cover;
+							object-position: center;
+						}
+			
+						.home-hotel-img-content-item-img-long {
+							width: 332rpx;
+							height: 400rpx;
+							object-fit: cover;
+							object-position: center;
+						}
+			
+						.text {
+							display: flex;
+							flex-direction: column;
+							align-items: flex-start;
+							justify-content: center;
+							padding: 18rpx 22rpx 32rpx;
+			
+							.text-top {
+								font-size: 28rpx;
+								font-weight: bold;
+								color: #333;
+							}
+			
+							.text-main {
+								margin-top: 20rpx;
+								font-size: 24rpx;
+								color: #999999;
+							}
+						}
+					}
+				}
+			}
+			
+			// display: flex;
+			// flex-wrap: wrap;
+		// 	.contentItemShort{
+		// 		width: 332rpx;
+		// 		background: $bgColor;
+		// 		box-sizing: border-box;
+		// 		box-shadow: 0px 4rpx 8rpx 0px rgba(0,0,0,0.04);
+		// 		border-radius: 12rpx;
+		// 		display: inline-block;
+		// 		margin-bottom: 24rpx;
+		// 		image{
+		// 			width: 332rpx;
+		// 			height: 332rpx;
+		// 		}
+		// 		.itemName{
+		// 			margin:0 18rpx 20rpx 22rpx ;
+		// 			font-size: 28rpx;
+		// 			font-family: PingFang-SC-Bold, PingFang-SC;
+		// 			font-weight: bold;
+		// 			color: #333333;
+		// 			overflow: hidden;
+		// 		}
+		// 		.itemPrice{
+		// 			margin-left: 22rpx;
+		// 			font-size: 28rpx;
+		// 			font-family: PingFang-SC-Bold, PingFang-SC;
+		// 			font-weight: bold;
+		// 			color: #FF6200;
+		// 		}
+		// 	}
+		// 	.contentItemLong{
+		// 		width: 332rpx;
+		// 		background: $bgColor;
+		// 		box-sizing: border-box;
+		// 		box-shadow: 0px 4rpx 8rpx 0px rgba(0,0,0,0.04);
+		// 		border-radius: 12rpx;
+		// 		margin-bottom: 24rpx;
+		// 		display: inline-block;
+		// 		clear: both;
+		// 		image{
+		// 			width: 332rpx;
+		// 			height: 400rpx;
+		// 		}
+		// 		.itemName{
+		// 			margin:0 18rpx 20rpx 22rpx ;
+		// 			font-size: 28rpx;
+		// 			font-family: PingFang-SC-Bold, PingFang-SC;
+		// 			font-weight: bold;
+		// 			color: #333333;
+		// 			overflow: hidden;
+		// 		}
+		// 		.itemPrice{
+		// 			margin-left: 22rpx;
+		// 			font-size: 28rpx;
+		// 			font-family: PingFang-SC-Bold, PingFang-SC;
+		// 			font-weight: bold;
+		// 			color: #FF6200;
+		// 		}
+		// 	}
+		// 	.contentItem:nth-child(odd){
+		// 		margin-right: 26rpx;
+		// 	}
+		// }
+	}
+</style>

+ 188 - 0
pages/my/integral/integralExchange.vue

xqd
@@ -0,0 +1,188 @@
+<template>
+	<view class="exchangeDetail">
+		<!-- 兑换状态 -->
+		<view class="detailCard">
+			<image src="/static/icon/success.png"></image>
+			<text style="margin-bottom: 20rpx;">商品兑换成功</text>
+			<text>-{{integral}}积分</text>
+		</view>
+		<!-- 按钮 -->
+		<view class="btn">
+			<view class="back" @click="goBack">
+				<text>返回首页</text>
+			</view>
+			<view class="checkout" @click="goOrderDetail">
+				<text>查看订单</text>
+			</view>
+		</view>
+		<!-- 加入会员 -->
+		<view class="bottomCard" @click="goOther">
+			<image src="http://t9.9026.com/imgs/Kudosbg.png"></image>
+			<view class="content">
+				<text>立即加入IHG会员</text>
+				<image src="/static/icon/right.png"></image>
+			</view>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				// 积分
+				integral:0,
+			}
+		},
+		onLoad(op) {
+			console.log(op)
+			this.integral=op.integral
+		},
+		methods: {
+			// 返回首页
+			goBack() {
+				uni.reLaunch({
+					url: '/pages/my/my'
+				})
+			},
+			// 跳转订单详情
+			goOrderDetail() {
+				uni.navigateTo({
+					url: '/pages/my/myorders/orders'
+				})
+			},
+			// 跳转其他小程序
+			goOther() {
+				wx.navigateToMiniProgram({
+					appId: 'wx255b58f0992b3c53', //appid
+					path: 'newUIMain/enrollment/enrollment', //path
+					extraData: { //参数
+						foo: 'bar'
+					},
+					// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+					success(res) {
+						console.log('成功')
+						// 打开成功
+					},
+					fail(e) {
+						console.log(e, '失败')
+					}
+				})
+			},
+			
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.exchangeDetail {
+		height: 100%;
+		background: $pageColor;
+	}
+
+	.detailCard {
+		width: 750rpx;
+		height: 446rpx;
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+
+		image {
+			width: 120rpx;
+			height: 120rpx;
+			margin-bottom: 48rpx;
+		}
+
+		text {
+			display: block;
+			font-size: 32rpx;
+			font-family: PingFangSC-Medium, PingFang SC;
+			font-weight: 500;
+			color: #080F18;
+		}
+	}
+
+	.btn {
+		width: 750rpx;
+		height: 76rpx;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding:0 32rpx;
+
+		.back {
+			width: 332rpx;
+			height: 76rpx;
+			background: #F5F5F5;
+			border-radius: 8rpx;
+
+			@include flexlayout() text {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #FF6301;
+			}
+		}
+
+		.checkout {
+			width: 332rpx;
+			height: 76rpx;
+			background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+			border-radius: 8rpx;
+
+			@include flexlayout() text {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #FFFFFF;
+			}
+		}
+	}
+
+	.bottomCard {
+		width: 690rpx;
+		height: 584rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 8rpx 16rpx 0px rgba(220, 222, 229, 0.71);
+		border-radius: 20rpx;
+		background: $bgColor;
+		margin-left: 30rpx;
+		margin-top: 64rpx;
+
+		image {
+			width: 690rpx;
+			height: 492rpx;
+		}
+
+		.content {
+			width: 690rpx;
+			height: 92rpx;
+			position: relative;
+			margin-top:-9rpx;
+			@include flexlayout();
+			image{
+				width: 12rpx;
+				height: 20rpx; 
+				margin-left: 8rpx;
+			}
+			text {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #333333;
+				text-shadow: 0px 8rpx 16rpx rgba(220, 222, 229, 0.71);
+			}
+		}
+	}
+</style>

+ 558 - 0
pages/my/integral/integralOrder.vue

xqd
@@ -0,0 +1,558 @@
+<template>
+	<view class="exchangePrize">
+		<!-- 表单 -->
+		<view class="form">
+			<view class="">
+				<uni-forms :modelValue="formData">
+					<uni-forms-item name="type" v-if="istype">
+						<view class="selectType" @click="openSelect">
+							<view class="uni-input">
+								<text v-if="formData.type==''||formData.type==null"
+									style="color: #999999 ;font-size: 30rpx;">请选择配送方式</text>
+								<text v-if="formData.type!=''" style="font-size: 30rpx;">{{formData.type}}</text>
+							</view>
+							<image src="/static/icon/right.png"
+								style="width: 14rpx;height: 24rpx;position: absolute;top:31rpx;right: 30rpx;">
+							</image>
+						</view>
+					</uni-forms-item>
+					<uni-forms-item name="name" v-if="formData.type!=''||isVerification==true">
+						<uni-easyinput type="text" v-model="Data.receiver" placeholder="填写联系人" />
+					</uni-forms-item>
+					<uni-forms-item name="phone" v-if="formData.type!=''||isVerification==true">
+						<uni-easyinput type="number" v-model="Data.phone" placeholder="填写联系电话" maxlength=11 />
+					</uni-forms-item>
+					<uni-forms-item name="region" v-if="formData.type=='快递配送'">
+						
+						<pickerAddress @change="change">
+							<!-- <uni-easyinput type="text" v-model="formData.region" placeholder="所在地区" /> -->
+							<view class="selectType">
+								<view class="uni-input">
+									<text v-if="formData.region==''||formData.region==null"
+										style="color: #999999 ; font-size: 30rpx; ">所在地区</text>
+									<text style="font-size: 30rpx;" v-if="formData.region!=''">{{formData.region}}</text>
+								</view>
+								<image src="/static/icon/right.png"
+									style="width: 14rpx;height: 24rpx;position: absolute;top:31rpx;right: 30rpx;">
+								</image>
+							</view>
+							
+						</pickerAddress>
+					</uni-forms-item>
+					<uni-forms-item name="region" v-if="formData.type=='快递配送'">
+						<textarea placeholder-style="#999" class="text-area" type="text" placeholder="详细地址"  v-model="Data.address" />
+
+					</uni-forms-item>
+					<uni-forms-item name="region" v-if="formData.type=='到店自提'||isVerification==true">
+						<view class="selectType" @click="openShop">
+							<view class="uni-input">
+								<text v-if="formData.shop==''||formData.shop==null"
+									style="color: #999999 ; font-size: 30rpx; ">请选择门店</text>
+								<text style="font-size: 30rpx;" v-if="formData.shop!=''">{{formData.shop}}</text>
+							</view>
+							<image src="/static/icon/right.png"
+								style="width: 14rpx;height: 24rpx;position: absolute;top:31rpx;right: 30rpx;">
+							</image>
+						</view>
+					</uni-forms-item>
+				</uni-forms>
+			</view>
+		</view>
+		<!-- 产品信息 -->
+		<view class="msg">
+			<view class="title">
+				<text>产品信息</text>
+			</view>
+			<view class="shopCard">
+				<image :src="productDetail.cover_img?productDetail.cover_img:'http://t9.9026.com/imgs/Kudosbg.png'"></image>
+				<view style="margin-left: 24rpx;">
+					<text class="name">{{productDetail.name}}</text>
+					<text class="tag">礼盒装 </text>
+				</view>
+			</view>
+			<view class="shopNumber">
+				<text>件数</text>
+				<text>1件</text>
+			</view>
+			<view class="shopNumber">
+				<text>积分</text>
+				<text>{{productDetail.integral}}积分</text>
+			</view>
+			<view style="width: 694rpx;height: 4rpx;border: 2rpx solid #F2F2F2;margin-top: 38rpx;"></view>
+			<view class="shopNumber">
+				<text>合计</text>
+				<text>{{productDetail.integral}}积分</text>
+			</view>
+		</view>
+		<!-- 兑换按钮 -->
+		<view class="bottombtn" @click="goExchange">
+			<view class="btnitem">
+				<text>确认兑换</text>
+			</view>
+		</view>
+		<!-- 配送方式-->
+		<uni-popup ref="Recipient" type="bottom" mask-background-color=" rgba(0,0,0,0.7);">
+			<view class="pop">
+				<view class="popuptitle">
+					<view @click="cancelBtn" style="width: 68rpx;color: #999;font-size: 32rpx;">
+						<text>取消</text>
+					</view>
+					<view>
+						<text style="font-weight: bold; font-size: 32rpx; color: #080F18; ">配送方式</text>
+					</view>
+					<view @click="sureBtn" style="width: 68rpx;"><text
+							style="font-size: 32rpx; color: #FF6200;line-height: 34rpx">确定</text></view>
+				</view>
+				<view class="chooselag">
+					<view @click="companyed(item.name,index)" class="language" v-for="(item,index) in typeSelect "
+						:sgActive='activeIndex==index'>
+						<text>{{item.name}}</text>
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+		<!-- 门店选择-->
+		<uni-popup ref="shopSelected" type="bottom" mask-background-color=" rgba(0,0,0,0.7);">
+			<view class="pop">
+				<view class="popuptitle">
+					<view @click="cancelShopBtn" style="width: 68rpx;color: #999;font-size: 32rpx;">
+						<text>取消</text>
+					</view>
+					<view>
+						<text style="font-weight: bold; font-size: 32rpx; color: #080F18; ">配送方式</text>
+					</view>
+					<view @click="sureShopBtn" style="width: 68rpx;"><text
+							style="font-size: 32rpx; color: #FF6200;line-height: 34rpx">确定</text></view>
+				</view>
+				<view class="chooselag">
+					<view @click="companyedShop(item.name,index)" class="language" v-for="(item,index) in regionSelect "
+						:sgActive='activeIndex==index'>
+						<text>{{item.name}}</text>
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+
+
+	</view>
+</template>
+
+<script>
+	import pickerAddress from '@/uni_modules/hu-pickerAddress/hu-pickerAddress.vue'
+	export default {
+		components: {
+			pickerAddress
+		},
+		data() {
+			return {
+				activeIndex: null,
+				// 是否核销
+				isVerification: false,
+				// 产品信息
+				productDetail:'',
+				// 表单数据
+				formData: {
+					type: '',
+					phone: '',
+					name: '',
+					region: '',
+					shop: '',
+					address: '',
+				},
+				Data:{
+					// 快递类型(1.快递发货 2.到店自提也是线下核销)
+					express_type:'',
+					// 收货人
+					receiver:"",
+					// 联系电话
+					phone:'',
+					// 地址ID,最小行政单位地区ID,express_type=1时必传
+					area_id:2000,
+					// 详细地址,express_type=1时必传
+					address:'',
+					// 门店ID,express_type=2时必传
+					hotel_id:'',
+					// 产品ID
+					product_id:'',
+					// 产品规格ID
+					product_attr_id:1,
+				},
+				// 配送方式
+				typeSelect: [{
+					name: '快递配送',
+				}, {
+					name: '到店自提',
+				}],
+				// 是否显示配送方式
+				istype: true,
+				// 选择门店
+				regionSelect: [{
+					name: '第一门店',
+				}, {
+					name: '第二门店',
+				}, {
+					name: '第三门店',
+				}, {
+					name: '第四门店',
+				}, {
+					name: '第五门店',
+				}, {
+					name: '第六门店',
+				}, {
+					name: '第七门店',
+				}]
+			}
+		},
+		onLoad(op) {
+			console.log(op,"产品id")
+			this.Data.product_id=op.product_id
+			this.getProductDetail(op.product_id)
+		},
+		methods: {
+			change(ret){
+				this.formData.region = ret.data.join('-')
+
+			},
+			//打开门店弹框
+			openShop() {
+				this.$refs.shopSelected.open('bottom')
+			},
+			companyedShop(i, index) {
+				this.typestatus2 = i
+				this.activeIndex = index
+				console.log(i, this.activeIndex)
+				this.Data.hotel_id=index
+			},
+			//确定按钮
+			sureShopBtn() {
+				if (this.typestatus2 == undefined) {
+					uni.showToast({
+						icon: "none",
+						title: '请选择门店'
+					})
+				} else {
+					this.formData.shop = this.typestatus2
+					this.$refs.shopSelected.close()
+				}
+			},
+			//取消按钮
+			cancelShopBtn() {
+				this.$refs.shopSelected.close()
+			},
+
+			// 打开配送弹框
+			openSelect() {
+				this.$refs.Recipient.open('bottom')
+			},
+			//选择配送方式
+			companyed(i, index) {
+				this.typestatus1 = i
+				this.activeIndex = index
+				console.log(i, this.activeIndex)
+				if(index==0){
+					this.Data.express_type=1
+				}else if(index==1){
+					this.Data.express_type=2
+				}
+			},
+			//确定按钮
+			sureBtn() {
+				if (this.typestatus1 == undefined) {
+					uni.showToast({
+						icon: "none",
+						title: '请选择配送方式'
+					})
+				} else {
+					this.formData.type = this.typestatus1
+					this.$refs.Recipient.close()
+				}
+			},
+			//取消按钮
+			cancelBtn() {
+				this.$refs.Recipient.close()
+			},
+
+			// 跳转积分兑换详情
+			goExDetail(integral) {
+				uni.navigateTo({
+					url: '/pages/my/integral/integralExchange?integral='+integral
+				})
+			},
+			// 积分兑换
+			goExchange(){
+				console.log(this.Data,"提交表单")
+				this.$api.integral.integralExchange({
+					...this.Data
+				}).then(res=>{
+					console.log(res)
+					if(res.code==0){
+						this.goExDetail(this.productDetail.integral)
+					}else{
+						uni.showToast({
+							title:res.msg,
+							icon:'none'
+						})
+					}
+				})
+			},
+			// 获取产品信息
+			getProductDetail(id){
+				this.$loading()
+				this.$api.product.getProductDetail({
+					product_id:id
+				}).then(res=>{
+					console.log(res,"产品信息")
+					this.$hideLoading()
+					if(res.code==0){
+						this.productDetail=res.data
+					}else{
+						uni.showToast({
+							title:res.msg,
+							icon:'none'
+						})
+					}
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.exchangePrize {
+		height: 100%;
+		// background: #f9f9f9;
+	}
+	
+	.uni-input-area{
+		width: 100%;
+		height: 98rpx;
+		padding: 34rpx 20rpx;
+		background: #FFFFFF;
+		border-radius: 8rpx;
+		border: 2rpx solid #EAEAEA;
+		font-size: 30rpx;
+		color: #000;
+		line-height: 30rpx;
+	}
+
+	//底部弹框样式
+	.pop {
+		width: 100%;
+		height: 616rpx;
+		background: #FFFFFF;
+		border-radius: 16rpx 16rpx 0 0;
+		overflow: scroll;
+
+		.popuptitle {
+			position: fixed;
+			top: 0;
+			display: flex;
+			width: 100%;
+			padding: 0 30rpx;
+			height: 122rpx;
+			background: #fff;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			image {
+				display: inline-block;
+				width: 33rpx;
+				height: 33rpx;
+				border-radius: 1rpx;
+			}
+		}
+
+		.chooselag {
+
+			flex-direction: column;
+			justify-content: center;
+			align-items: center;
+			background: #FFFFFF;
+			padding: 0 30rpx;
+			overflow-y: scroll;
+			margin-top: 122rpx;
+
+			.language {
+				width: 100%;
+				font-size: 32rpx;
+				font-weight: 400;
+				color: #777777;
+				border-bottom: 1rpx #E2E4EA solid;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				padding-top: 40rpx;
+				padding-bottom: 40rpx;
+
+				&[sgActive] {
+					color: #405E49 !important;
+					font-weight: bold !important;
+				}
+			}
+		}
+	}
+
+
+
+	.text-area {
+		width: 100%;
+		height: 130rpx;
+		padding: 34rpx 20rpx;
+		background: #FFFFFF;
+		border-radius: 8rpx;
+		border: 2rpx solid #EAEAEA;
+		font-size: 30rpx;
+		color: #000;
+		line-height: 30rpx;
+	}
+
+
+
+	::v-deep .uni-forms-item {
+		// height: 98rpx;
+		margin-bottom: 0;
+		margin-top: 24rpx;
+		font-size: 30rpx !important;
+
+		&:first-child {
+			margin-top: 0;
+		}
+	}
+
+	::v-deep .is-input-border {
+		background-color: #ffffff !important;
+		border: 2rpx solid #EAEAEA !important;
+		height: 98rpx;
+
+	}
+
+	::v-deep .uni-icons {
+		color: #c0c4cc !important;
+	}
+
+	::v-deep .uni-easyinput__placeholder-class {
+		font-size: 30rpx !important;
+		color: #999 !important;
+	}
+
+	::v-deep .uni-easyinput__content-input {
+		font-size: 30rpx !important;
+		color: #000 !important;
+	}
+
+
+	.form {
+		background: $pageColor;
+		width: 750rpx;
+		padding: 24rpx 30rpx;
+		box-sizing: border-box;
+
+		.selectType {
+			width: 690rpx;
+			height: 98rpx;
+			background: #FFFFFF;
+			border-radius: 8rpx;
+			border: 2rpx solid #EAEAEA;
+			display: flex;
+			align-items: center;
+			padding-left: 20rpx;
+			box-sizing: border-box;
+			position: relative;
+		}
+	}
+
+	.msg {
+		width: 750rpx;
+		height: 700rpx;
+		background: $bgColor;
+		border-radius: 12rpx 12rpx 0px 0px;
+		padding: 32rpx 30rpx;
+
+		.title {
+			margin-bottom: 24rpx;
+
+			text {
+				font-size: 32rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #080F18;
+			}
+		}
+
+		.shopCard {
+			margin-top: 28rpx;
+			width: 694rpx;
+			height: 164rpx;
+			background: #F4F5F6;
+			border-radius: 10rpx;
+			display: flex;
+			align-items: center;
+
+			image {
+				width: 132rpx;
+				height: 132rpx;
+				margin-left: 16rpx;
+				display: inline-block;
+				border-radius: 10rpx;
+			}
+
+			.name {
+				font-size: 28rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #080F18;
+				display: block;
+			}
+
+			.tag {
+				font-size: 24rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+
+		.shopNumber {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			margin-top: 25rpx;
+
+			text {
+				font-size: 26rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #000000;
+			}
+		}
+	}
+
+	.bottombtn {
+		width: 690rpx;
+		height: 92rpx;
+		background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+		border-radius: 12rpx;
+		margin-left: 30rpx;
+		position: fixed;
+		bottom: 72rpx;
+
+		@include flexlayout() .btnitem {
+			@include flexlayout() text {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: $bgColor;
+			}
+		}
+	}
+</style>

+ 271 - 0
pages/my/integral/integralRecord.vue

xqd
@@ -0,0 +1,271 @@
+<template>
+	<view class="integralRecord">
+		<!-- 分段器 -->
+		<view class="segmented">
+				<view class="tab_nav">
+					<view class="navTitle" v-for="(item,index) in items" :key="index">
+						<view :class="{'active':isActive == index}" @click="checked(index)">
+							{{item}}
+						</view>
+					</view>
+				</view>
+		</view>
+		
+		<!-- 收入 -->
+		<view class="List" v-if="isActive == 0">
+			<view class="ListItem" v-for="item in incomeList">
+				<view style="display: flex; justify-content: space-between;">
+					<view class="title"><text>{{item.change_integral}}积分</text> </view>
+					<view class='data'><text>{{item.created_at}}</text></view>
+				</view>
+				<view class="content" v-if="item.type==1"><text>投票奖励获得</text></view>
+				<view class="content" v-if="item.type==2"><text>抽奖奖励获得</text></view>
+			</view>
+		</view>
+		
+		<!-- 支出 -->
+		<view class="List" :style="{'--height':ListHeight+'rpx'}" v-if="isActive == 1">
+			<view class="ListItem" v-for="item in spendingList">
+				<view style="display: flex; justify-content: space-between;">
+					<view class="title"><text>{{item.change_integral}}积分</text> </view>
+					<view class='data'><text>{{item.created_at}}</text></view>
+				</view>
+				<view class="content" v-if="item.type==3"><text>兑换商品消耗</text></view>
+				<view class="content" v-if="item.type==4"><text>后台增加/减少</text></view>
+			</view>
+		</view>
+		
+		<!-- 已经到底啦 -->
+		<view class="home-bottom" style="margin-top: 88rpx;padding-bottom: 60rpx;" >
+			<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText"/>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default{
+		data(){
+			return{
+				// 分段器
+				items: ['收入', '支出',],
+				isActive: 0,
+				// list高度
+				ListHeight: 800,
+				// 组件uni-load-more
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				// 收入列表
+				incomeList:[],
+				// 支出列表
+				spendingList:[],
+			}
+		},
+		onLoad() {
+			// 收入
+			this.getIntegralList(1)
+			// 支出
+			this.getIntegralList(2)
+		},
+		methods:{
+			//菜单index切换
+			checked(index) {
+				this.isActive = index
+			},
+			// 获取积分日志
+			getIntegralList(type){
+				if(type==1){
+					this.$api.integral.getIntegralLog({
+						page:1,
+						type:1
+					}).then(res=>{
+						console.log(res,'收入积分日志')
+						if(res.code==0){
+							this.incomeList=res.data.data
+						}
+					})
+				} else if (type==2){
+					this.$api.integral.getIntegralLog({
+						page:1,
+						type:2
+					}).then(res=>{
+						console.log(res,'支出积分日志')
+						if(res.code==0){
+							this.spendingList=res.data.data
+						}
+					})
+				}else{
+					uni.showToast({
+						title:'请传入正确type值!',
+						icon:'none'
+					})
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+	// flex布局居中对齐
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+	.integralRecord{
+		height: 100%;
+		background: $pageColor;
+	}
+	.segmented{
+		height: 112rpx;
+		width: 750rpx;
+		background: $bgColor;
+		box-shadow: 0px 4rpx 8rpx 0px rgba(0,0,0,0.04);
+		border-radius: 0px 0px 16rpx 16rpx;
+		//菜单切换
+		.tab_nav {
+			width: 690rpx;
+			margin-left: 30rpx;
+			padding:0 80rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			font-family: PingFang-SC-Heavy, PingFang-SC;
+		}
+		.tab_nav .navTitle {
+			@include flexlayout()
+			margin-top: 20rpx;
+			width: 128rpx;
+			flex: none;
+			height: 28rpx;
+			font-size: 32rpx;
+			color: #666;
+			position: relative;
+		}
+		.active {
+			color: #D9A94D;
+			font-weight: bold;
+		
+			&::after {
+				display: inline-block;
+				content: '';
+				width: 48rpx;
+				height: 12rpx;
+				background: linear-gradient(90deg, #F3D69F 0%, #D9A94D 100%);
+				border-radius: 6px;
+				position: absolute;
+				bottom: -30rpx;
+				left: 40rpx;
+			}
+		}
+	}
+	::v-deep .segmented-control__text {
+		font-size: 32rpx !important;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		font-weight: 500 !important;
+		color: #666666 !important;
+	}
+	
+	::v-deep .segmented-control__item--text {
+		font-size: 32rpx;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		font-weight: 800 !important;
+		padding: 10rpx 0 !important;
+		border-radius: 4rpx !important;
+		color: #D9A94D !important;
+	}
+	.List {
+		width: 750rpx;
+		background: $bgColor;
+		box-shadow: 0px 4rpx 24rpx -10rpx rgba(101, 95, 90, 0.3);
+		border-radius: 12rpx;
+		margin-top: 24rpx;
+		padding: 0rpx 28rpx 0 32rpx;
+		box-sizing: border-box;
+	
+		.ListItem {
+			width: 690rpx;
+			border-bottom: #F0F0F0 solid 0.5rpx;
+			position: relative;
+			padding-top: 40rpx;
+			padding-bottom: 40rpx;
+			box-sizing: border-box;
+			&:first-child{
+				padding-top: 48rpx;
+			}
+			&:last-child{
+				border-bottom: none;
+			}
+			.title {
+				margin-bottom: 10rpx;
+				text {
+					font-size: 32rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: bold;
+					color: #333333;
+				}
+			}
+	
+			.data {
+				text {
+					font-size: 26rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #999999;
+				}
+			}
+			.content {
+				text {
+					font-size: 28rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #333333;
+				}
+			}
+			
+		}
+		// 消除最后一个下划线
+		.ListItem:last-child {
+			width: 690rpx;
+			height: 160rpx;
+			border-bottom: #F0F0F0 solid 0rpx;
+			position: relative;
+			padding-top: 35rpx;
+			box-sizing: border-box;
+			
+			.title {
+				margin-bottom: 10rpx;
+				text {
+					font-size: 32rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: bold;
+					color: #333333;
+				}
+			}
+			
+			.data {
+				text {
+					font-size: 26rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #999999;
+				}
+			}
+			.content {
+				text {
+					font-size: 28rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #333333;
+				}
+			}
+			
+		}
+	}
+	
+</style>

+ 62 - 0
pages/my/integral/integralRule.vue

xqd
@@ -0,0 +1,62 @@
+<template>
+	<view class="UserAgreement">
+		<view v-html="integralRule"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				integralRule:'',
+			}
+		},
+		onLoad() {
+			this.integralRule = this.$store.getters.allset.integral_rule.value.integral_rule
+			console.log(this.integralRule);
+		},
+		methods: {
+			
+			
+	
+		}
+	}
+	
+	
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+	.UserAgreement{
+		height: 100%;
+		background: $bgColor;
+		padding: 0 30rpx;
+	}
+	.title{
+		height: 82rpx;
+		width: 750rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		text{
+			font-size: 32rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #333333;
+		}
+	}
+	.content{
+		padding: 0 30rpx;
+		view{
+			margin-bottom: 24rpx;
+			text{
+				font-size: 28rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #333333;
+			}
+		}
+		
+	}
+</style>

+ 568 - 0
pages/my/my.vue

xqd
@@ -0,0 +1,568 @@
+<template>
+
+	<view class="my">
+		<MyNav title="我的" bgColor="" :backIcon="false"></MyNav>
+		<view class="topCard" :style="{backgroundImage:'url('+imgurl+')'}">
+			<!-- 用户名 -->
+			<view class="user">
+				<view v-if="admin.avatar">
+					<button class="avatar" open-type="chooseAvatar" @click="handleGetWechatUserInfo">
+						<image class="user-avatar" style="height: 176rpx;width: 176rpx;border-radius: 50%;"
+							:src="admin.avatar? admin.avatar : '/static/icon/avatar.png'" />
+					</button>
+					<view class="userinfo" @click="goPersonData">
+						<text class="unlogin">{{admin.nickname}}</text>
+					</view>
+				</view>
+				<view v-else>
+					<image class="user-avatar" src="/static/icon/avatar.png" style="height: 176rpx;width: 176rpx;">
+					</image>
+					<view class="userinfo">
+						<text class="unlogin" v-if="!islogin" @click="login">请点击登录</text>
+					</view>
+				</view>
+				<image src="/static/icon/setting.png" @click="goSetting"
+					style="width: 44rpx;height: 44rpx; position: absolute;top:0rpx;right: 24rpx;"></image>
+			</view>
+
+			<!-- 会员 -->
+			<view class="membership" @click="goJoin">
+				<view class="flex">
+					<view style="display: flex;align-items: center;">
+						<image style="width: 68rpx ;height: 62rpx;" src="../../static/icon/vip.png"></image>
+						<text class="join">加入会员</text>
+					</view>
+
+					<view style="display: flex;align-items: center;">
+						<text class="gojoin">去加入</text>
+						<image style="width: 12rpx ;height: 20rpx;" src="../../static/icon/right05.png"></image>
+					</view>
+				</view>
+			</view>
+
+			<!-- 订单 -->
+			<view class="orders">
+				<view class="nav">
+					<view class="myorder">我的订单</view>
+					<view class="more">
+						<text style="margin-right: 8rpx;" @click="goMyorders(0)">查看更多</text>
+						<image style="width: 12rpx ;height: 20rpx;" src="../../static/icon/right05.png"></image>
+					</view>
+				</view>
+
+				<view class="content">
+					<view class="flexbox" @click="goMyorders(1)">
+						<view
+							style="width: 56rpx; height: 56rpx; display: flex;align-items: center;justify-content: center; ">
+							<image style="width: 56rpx ;height: 42rpx;" src="../../static/icon/exchange.png"></image>
+						</view>
+						<text>待兑换</text>
+					</view>
+					<view class="flexbox" @click="goMyorders(2)">
+						<view
+							style="width: 56rpx; height: 56rpx;display: flex;align-items: center;justify-content: center; ">
+							<image style="width: 54rpx ;height: 52rpx;" src="../../static/icon/shipments.png"></image>
+						</view>
+						<text>待发货</text>
+					</view>
+					<view class="flexbox" @click="goMyorders(3)">
+						<view
+							style="width: 56rpx; height: 56rpx;display: flex;align-items: center;justify-content: center; ">
+							<image style="width: 56rpx ;height: 56rpx;" src="../../static/icon/Receipt.png"></image>
+						</view>
+						<text>待收货</text>
+					</view>
+					<view class="flexbox" @click="goMyorders(4)">
+						<view
+							style="width: 56rpx; height: 56rpx;display: flex;align-items: center;justify-content: center; ">
+							<image style="width: 54rpx ;height: 54rpx;" src="../../static/icon/finish.png"></image>
+						</view>
+						<text>已完成</text>
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<!-- 列表 -->
+		<view style="padding:0 30rpx;">
+			<view class="list" v-for="(item,index) in list" :key="index" @click="goDetail(index)">
+				<view class="title">{{item.title}}</view>
+				<view class="container">{{item.content}}</view>
+				<image src="../../static/icon/right.png"></image>
+			</view>
+
+		</view>
+		<u-modal @close="closeMask" closeOnClickOverlay="true" :show="modal.show" :title="modal.title"
+			:show-confirm-button="false">
+			<view>
+				<button class="avatar" open-type="chooseAvatar" @chooseavatar="handleChooseAvatar">
+					<image class="user-avatar" style="height: 176rpx;width: 176rpx;border-radius: 50%;"
+						:src="modal.avatar?modal.avatar:'/static/icon/avatar.png'" />
+				</button>
+				<input class="avatar" type="nickname" :value="modal.nickname" placeholder="填写昵称"
+					@change="handleChangeNickname">
+				<button class="confirm" @click="handleConfirmWechatUserInfo">提交</button>
+			</view>
+		</u-modal>
+		<!-- 底部导航栏 -->
+		<view style="height: 140rpx; width: 100%;"></view>
+		<tab-bar checked="my"></tab-bar>
+	</view>
+</template>
+
+<script>
+	// 引入组件
+	import TabBar from '../../components/TabBar/tabbar.vue'
+	import MyNav from "@/components/my-nav/my-nav.vue"
+	export default {
+		// 注册组件
+		components: {
+			TabBar,
+			MyNav
+		},
+		data() {
+			return {
+				modal: {
+					show: false,
+					title: '用户信息获取',
+					nickname: '',
+					avatar: ''
+				},
+				admin: '',
+				// 顶部背景图
+				imgurl: 'http://t9.9026.com/imgs/bg@2x.png',
+				// 是否登录
+				islogin: false,
+				// 列表内容
+				list: [{
+					title: '积分',
+					content: '积分兑换奖品'
+				}, {
+					title: '奖品',
+					content: '查看所有奖品'
+				}, {
+					title: '点赞',
+					content: '查看所有点赞'
+				}]
+			};
+		},
+
+		onShow() {
+			this.admin = this.$store.getters.userInfo
+			console.log(this.admin);
+		},
+
+		methods: {
+			//关闭遮罩层
+			closeMask() {
+				this.modal.show = false
+			},
+			// 微信获取头像
+			handleGetWechatUserInfo() {
+				console.log(1111);
+				this.modal.show = true
+				this.modal.nickname = this.admin.nickname
+				this.modal.avatar = this.admin.avatar
+			},
+			//提交微信名称和头像
+			handleConfirmWechatUserInfo() {
+				if (!this.modal.avatar) {
+					this.$u.toast('请上传头像')
+					return
+				}
+				if (!this.modal.nickname) {
+					this.$u.toast('请填写昵称')
+					return
+				}
+				this.$loading('数据提交中...')
+				this.$api.my.update({
+					avatar: this.modal.avatar,
+					nickname: this.modal.nickname
+				}).then(res => {
+					this.$hideLoading()
+					this.$store.dispatch('user/info', res.data)
+					this.admin = this.$store.getters.userInfo
+					this.modal.show = false
+				})
+			},
+			// 微信获取头像
+			handleChooseAvatar(e) {
+				console.log(e.detail);
+				this.modal.avatar = e.detail.avatarUrl
+			},
+			handleChangeNickname(res) {
+				this.modal.nickname = res.detail.value
+			},
+
+			// 跳转登录页
+			login() {
+				uni.navigateTo({
+					url: '/pages/login/login'
+				})
+			},
+			// 跳转个人信息
+			goPersonData() {
+				uni.navigateTo({
+					url: '/pages/my/PersonalData/personalData'
+				})
+			},
+			// 跳转设置页面
+			goSetting() {
+				if (this.admin == undefined) {
+					uni.navigateTo({
+						url: '/pages/login/login'
+					})
+				} else {
+					uni.navigateTo({
+						url: '/pages/my/setting/setting'
+					})
+				}
+			},
+			// 跳转积分页
+			goDetail(index) {
+				if (this.admin == undefined) {
+					uni.navigateTo({
+						url: '/pages/login/login'
+					})
+				} else {
+					if (index == 0) {
+						uni.navigateTo({
+							url: '/pages/my/integral/integral'
+						})
+					} else if (index == 1) {
+						uni.navigateTo({
+							url: '/pages/my/prize/prize'
+						})
+					} else {
+						uni.navigateTo({
+							url: '/pages/my/Kudos/Kudos'
+						})
+					}
+				}
+
+			},
+			// 跳转订单页
+			goMyorders(index) {
+				if (this.admin == undefined) {
+					uni.navigateTo({
+						url: '/pages/login/login'
+					})
+				} else {
+					switch (index) {
+						case 0:
+							uni.navigateTo({
+								url: '/pages/my/myorders/orders'
+							})
+							break;
+						case 1:
+							uni.navigateTo({
+								url: '/pages/my/myorders/orders?isActive=' + 1
+							})
+							break;
+						case 2:
+							uni.navigateTo({
+								url: '/pages/my/myorders/orders?isActive=' + 2
+							})
+							break;
+						case 3:
+							uni.navigateTo({
+								url: '/pages/my/myorders/orders?isActive=' + 3
+							})
+							break;
+						case 4:
+							uni.navigateTo({
+								url: '/pages/my/myorders/orders?isActive=' + 4
+							})
+							break;
+					}
+				}
+			},
+			//获取当前页面路径
+			getPageUrl() {
+				const pages = getCurrentPages();
+				console.log(pages,'--------->pages')
+				if(pages.length==1){
+					const currentPage = pages[0];
+					let pageUrl = `/${currentPage.route}`;
+					return pageUrl
+					console.log('当前页面url:', pageUrl);
+				}else{
+					const currentPage = pages[pages.length - 1];
+					let pageUrl = `/${currentPage.route}`;
+					return pageUrl
+					console.log('当前页面url:', pageUrl);
+				}
+			},
+			// 跳转其他小程序
+			goJoin() {
+				let _this = this
+				wx.navigateToMiniProgram({
+					appId: 'wx255b58f0992b3c53', //appid
+					path: 'newUIMain/enrollment/enrollment', //path
+					extraData: { //参数
+						foo: 'bar'
+					},
+					// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+					success(res) {
+						let page = _this.getPageUrl()
+						let user_id = ''
+						if (_this.admin != null) {
+							user_id = _this.admin.id
+						} else {
+							user_id = 0
+						}
+						console.log('成功', page)
+						_this.$api.my.userMemberAdd({
+							user_id,
+							page,
+						}).then(res => {
+							console.log(res.data);
+						})
+
+						// 打开成功
+					},
+					fail(e) {
+						console.log(e, '失败')
+					}
+				})
+			},
+			// 上传头像
+			uploadAvatar() {
+				// let img = []
+				// uni.chooseImage({
+				// 	count: 1, //默认9
+				// 	sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
+				// 	sourceType: ['album'], //从相册选择
+				// 	success: function (res) {
+				// 		console.log(JSON.stringify(res.tempFilePaths));
+				// 		img = res.tempFilePaths[0]
+				// 		uni.uploadFile({
+				// 			//后端接口地址
+				// 			url: `${baseUrl}` + '/api/attachment/upload',
+				// 			//图片临时地址
+				// 			filePath: img,
+				// 			// 上传文件类型
+				// 			formData: {
+				// 				tag: 'avatar'
+				// 			},
+				// 			success: (res) => {
+				// 				//后端返回的图片名称
+				// 				let data = JSON.parse(res.data)
+				// 				// _this.formData.avatar = data.data.file
+				// 			},
+				// 		})
+				// 	},
+				// });
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	.my {
+		height: 100%;
+		background-color: $pageColor;
+	}
+
+	.avatar {
+		width: 176rpx;
+		height: 176rpx;
+		border-radius: 50%;
+	}
+
+
+
+	.topCard {
+		width: 100%;
+		border-radius: 0rpx 0rpx 16rpx 16rpx;
+		padding: 40rpx 30rpx 38rpx 30rpx;
+		box-sizing: border-box;
+		background-position: center;
+		background-repeat: no-repeat;
+		background-size: cover;
+
+
+		.user {
+			width: 690rpx;
+			height: 176rpx;
+			position: relative;
+			margin-bottom: 38rpx;
+
+			.user-avatar {
+				object-fit: cover;
+				object-position: center;
+			}
+
+			.userinfo {
+				position: absolute;
+				top: 38rpx;
+				left: 200rpx;
+
+				.unlogin {
+					width: 220rpx;
+					font-size: 44rpx;
+					font-family: PingFang-SC-Heavy, PingFang-SC;
+					font-weight: 500;
+					color: #FFFFFF;
+					display: block;
+					margin-top: 20rpx;
+				}
+
+				.username {
+					width: 184rpx;
+					height: 44rpx;
+					font-size: 44rpx;
+					font-family: PingFang-SC-Heavy, PingFang-SC;
+					font-weight: 500;
+					color: #FFFFFF;
+					line-height: 44rpx;
+					display: block;
+					margin-bottom: 24rpx;
+				}
+
+				.userId {
+					font-size: 32rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 400;
+					color: #FFFFFF;
+					line-height: 32rpx;
+				}
+			}
+		}
+
+		.membership {
+			width: 690rpx;
+			height: 110rpx;
+			background: $bgColor;
+			border-radius: 8rpx;
+			display: flex;
+			align-items: center;
+			padding-left: 28rpx;
+			padding-right: 24rpx;
+			box-sizing: border-box;
+			margin-bottom: 24rpx;
+
+			.flex {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				height: 68rpx;
+				width: 650rpx;
+
+				.join {
+					font-size: 36rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: 600;
+					color: #627885;
+					margin-left: 8rpx;
+				}
+
+				.gojoin {
+					font-size: 30rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: 600;
+					color: #627885;
+					margin-right: 8rpx;
+				}
+			}
+
+
+		}
+
+		.orders {
+			width: 690rpx;
+			background: $bgColor;
+			border-radius: 8rpx;
+			padding: 40rpx 30rpx 36rpx 36rpx;
+			box-sizing: border-box;
+
+			.nav {
+				height: 50rpx;
+				width: 633rpx;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+
+				.myorder {
+					font-size: 28rpx;
+					font-family: PingFang-SC-Heavy, PingFang-SC;
+					font-weight: 800;
+					color: #333333;
+				}
+
+				.more {
+					font-size: 28rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: bold;
+					color: #627885;
+
+				}
+			}
+
+			.content {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				padding: 0 20rpx;
+				margin-top: 72rpx;
+
+				.flexbox {
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+
+					text {
+						margin-top: 16rpx;
+						font-size: 28rpx;
+						font-family: PingFang-SC-Medium, PingFang-SC;
+						font-weight: 500;
+						color: #627885;
+					}
+				}
+			}
+		}
+
+
+	}
+
+	.list {
+		width: 100%;
+		padding-top: 32rpx;
+		padding-bottom: 32rpx;
+		border-bottom: 2rpx solid #F0F0F0;
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		position: relative;
+
+		&:first-child {
+			padding-top: 50rpx;
+		}
+
+		.title {
+			font-size: 36rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #333333;
+			margin-bottom: 16rpx;
+		}
+
+		.container {
+			font-size: 28rpx;
+			font-family: PingFang-SC-Medium, PingFang-SC;
+			font-weight: 500;
+			color: #333333;
+		}
+
+		image {
+			width: 12rpx;
+			height: 20rpx;
+			position: absolute;
+			top: 70rpx;
+			right: 0rpx;
+		}
+	}
+</style>

+ 371 - 0
pages/my/myorders/orderDetail.vue

xqd
@@ -0,0 +1,371 @@
+<template>
+	<view class="orderDetail">
+		<!-- 标题栏 -->
+		<view class="nav">
+			<text class="orderStatus">待收货</text>
+		</view>
+
+		<view class="midBox">
+			<!-- 物流信息 -->
+			<view class="logistics" v-if="true">
+				<view class="logisticsTitle">物流信息</view>
+				<view class="logisticsMsg"><text>快递公司</text><text style="margin-left: 26rpx;">京东快递</text></view>
+				<view class="logisticsMsg"><text>快递单号</text><text style="margin-left: 26rpx;">JD39084237234</text>
+				</view>
+				<view class="copy" @click="copyOrder">复制</view>
+			</view>
+			<!-- 配送信息 -->
+			<view class="delivery">
+				<view class="deliveryTitle">
+					<text>配送信息</text>
+				</view>
+				<view class="deliveryMsg" >
+					<image class="bgimg" src="http://t9.9026.com/imgs/ordermap.png"></image>
+					<!-- 联系信息 -->
+					<view class="deliveryicon">
+						<image src="/static/icon/phone.png"></image>
+						<text>联系信息</text>
+					</view>
+					<view class="deliverytext">
+						<text>刘奕伶</text>
+						<text style="margin-left: 24rpx;">400-123-4567</text>
+					</view>
+
+					<!-- 发货方式 -->
+					<view class="deliveryicon">
+						<image src="/static/icon/delivery.png"></image>
+						<text>发货方式</text>
+					</view>
+					<view class="deliverytext">
+						<text>快递发货</text>
+					</view>
+
+					<!-- 收货地址 -->
+					<view class="deliveryicon" v-if="true">
+						<image src="/static/icon/position.png"></image>
+						<text>收货地址</text>
+					</view>
+					<view class="deliverytext" v-if="true">
+						<text>四川省 成都市 高新区 XXX小区 XXX号</text>
+					</view>
+
+					<!-- 门店地址 -->
+					<view class="deliveryicon" v-if="false">
+						<image src="/static/icon/position.png"></image>
+						<text>门店地址</text>
+					</view>
+					<view class="deliverytext" v-if="false" style="position:relative;">
+						<text>四川省 成都市 高新区 XXX小区 XXX号</text>
+						<image src="/static/icon/navigation.png"
+							style="width: 50rpx;height: 48rpx; position: absolute; top: 0rpx;right: 30rpx;"></image>
+					</view>
+
+					<!-- 门店联系方式 -->
+					<view class="deliveryicon" v-if="false">
+						<image src="/static/icon/phone.png"></image>
+						<text>门店联系方式</text>
+					</view>
+					<view class="deliverytext" v-if="false">
+						<text>400-123-4567</text>
+					</view>
+				</view>
+			</view>
+			<!-- 订单信息 -->
+			<view class="myorder">
+				<view class="orderTitle">订单信息</view>
+				<view class="orderMsg"><text>订单编号</text><text style="margin-left: 26rpx;">62aae0eb9c6fd622</text></view>
+				<view class="orderMsg"><text>下单时间</text><text style="margin-left: 26rpx;">2022-08-20 12:32:12</text>
+				</view>
+				<view class="copyorder" @click="copyOrder">复制</view>
+			</view>
+		</view>
+
+		<!-- 产品信息 -->
+		<view class="shopMsg">
+			<view class="title">
+				<text>产品信息</text>
+			</view>
+			<view class="shopCard">
+				<image src="/static/icon/Kudosbg.png"></image>
+				<view style="margin-left: 24rpx;">
+					<text class="name">端午佳节五香肉粽子,仅限前</text>
+					<text class="tag">礼盒装 2000积分</text>
+				</view>
+			</view>
+			<view class="shopNumber">
+				<text>件数</text>
+				<text>1件</text>
+			</view>
+			<view class="shopNumber">
+				<text>积分</text>
+				<text>2000积分</text>
+			</view>
+			<view style="width: 694rpx;height: 4rpx;border: 2rpx solid #F2F2F2;margin-top: 38rpx;"></view>
+			<view class="shopNumber">
+				<text>合计</text>
+				<text>2000积分</text>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+			}
+		},
+		
+		methods: {
+			// 复制订单号
+			copyOrder(){
+				uni.setClipboardData({
+					data: 'hello',
+					success: function () {
+						uni.showToast({
+							title:'复制成功!'
+						})
+					}
+				});
+			}
+		},
+		computed: {
+			
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	// flex布局居中对齐
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.orderDetail {
+		height: 100%;
+		background: $pageColor;
+	}
+
+	.nav {
+		width: 750rpx;
+		height: 108rpx;
+		background: $bgColor;
+		border-radius: 0px 0px 16rpx 16rpx;
+		padding: 32rpx 0 0 28rpx;
+		box-sizing: border-box;
+
+		.orderStatus {
+			font-size: 40rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #FF6200;
+		}
+	}
+
+	.midBox {
+		margin-top: 24rpx;
+		width: 750rpx;
+		background: $bgColor;
+		border-radius: 16rpx;
+		position: relative;
+		padding: 40rpx 28rpx;
+		box-sizing: border-box;
+
+
+		.logistics {
+			position: relative;
+			.logisticsTitle {
+				margin-bottom: 25rpx;
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #080F18;
+			}
+
+			.logisticsMsg {
+				margin-bottom: 25rpx;
+
+				text {
+					font-size: 28rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #666666;
+				}
+			}
+
+			.copy {
+				position: absolute;
+				right: 30rpx;
+				top: 68rpx;
+				font-size: 28rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #FF6200;
+			}
+		}
+
+		.myorder {
+			position: relative;
+
+			.orderTitle {
+				margin-bottom: 25rpx;
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #080F18;
+			}
+
+			.orderMsg {
+				margin-bottom: 25rpx;
+
+				text {
+					font-size: 28rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #666666;
+				}
+			}
+
+			.copyorder {
+				position: absolute;
+				right: 30rpx;
+				bottom: 72rpx;
+				font-size: 28rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #FF6200;
+			}
+		}
+
+		.delivery {
+			margin-bottom: 20rpx;
+
+			.deliveryTitle {
+				margin-bottom: 24rpx;
+
+				text {
+					font-size: 32rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: bold;
+					color: #080F18;
+				}
+			}
+
+			.deliveryMsg {
+				width: 694rpx;
+				display: flex;
+				flex-direction: column;
+				justify-content: center;
+				padding-top: 24rpx;
+				position: relative;
+				.bgimg{
+					width: 100%;
+					height: 100%;
+					position: absolute;
+					top:0rpx;
+				}
+				.deliveryicon {
+					margin-bottom: 15rpx;
+					display: flex;
+					align-items: center;
+					z-index: 999;
+					image {
+						width: 26rpx;
+						height: 26rpx;
+						margin-right: 5rpx;
+					}
+
+					text {
+						font-size: 28rpx;
+						font-family: PingFang-SC-Medium, PingFang-SC;
+						font-weight: 500;
+						color: #333333;
+					}
+				}
+
+				.deliverytext {
+					margin-bottom: 20rpx;
+					z-index: 999;
+					text {
+						font-size: 28rpx;
+						font-family: PingFangSC-Medium, PingFang SC;
+						font-weight: 500;
+						color: #080F18;
+					}
+				}
+			}
+		}
+	}
+
+	.shopMsg {
+		margin-top: 24rpx;
+		width: 750rpx;
+		height: 534rpx;
+		background: $bgColor;
+		border-radius: 12rpx 12rpx 0px 0px;
+		padding: 32rpx 30rpx;
+		box-sizing: border-box;
+
+		.title {
+			margin-bottom: 24rpx;
+
+			text {
+				font-size: 32rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #080F18;
+			}
+		}
+
+		.shopCard {
+			margin-top: 28rpx;
+			width: 694rpx;
+			height: 164rpx;
+			background: #F4F5F6;
+			border-radius: 10rpx;
+			display: flex;
+			align-items: center;
+			image {
+				width: 132rpx;
+				height: 132rpx;
+				margin-left: 16rpx;
+				display: inline-block;
+				border-radius: 10rpx;
+			}
+
+			.name {
+				font-size: 28rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #080F18;
+				display: block;
+			}
+
+			.tag {
+				font-size: 24rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+
+		.shopNumber {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			margin-top: 25rpx;
+
+			text {
+				font-size: 26rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #000000;
+			}
+		}
+	}
+</style>

+ 604 - 0
pages/my/myorders/orders.vue

xqd
@@ -0,0 +1,604 @@
+<template>
+	<view class="orders">
+		<view class="nav">
+			<!-- 搜索栏 -->
+			<view class="navbox">
+				<view class="search">
+					<u-input placeholder="搜索" border='none' v-model='search' @input="searchText">
+						<template slot="suffix" style='margin-right:40rpx;'>
+							<u-image :showLoading="true" :showError='true' src="/static/icon/search.png" width="40rpx"
+								height="32rpx"></u-image>
+						</template>
+					</u-input>
+				</view>
+			</view>
+			<!-- 分段器 -->
+			<view class="segmented">
+				<view class="tab_nav">
+					<view class="navTitle" v-for="(item,index) in items" :key="index">
+						<view :class="{'active':isActive == index}" @click="checked(index)">
+							{{item}}
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<!-- 全部 -->
+		<view v-if="isActive === 0">
+			<view class="card" v-for="item in orderList">
+				<view class="toptitle">
+					<view>订单号:62aae0eb9c6fd622</view>
+					<view>未核销</view>
+				</view>
+				<view class="shopCard">
+					<image src="http://t9.9026.com/imgs/Kudosbg.png"></image>
+					<view style="margin-left: 24rpx;">
+						<text class="name">端午佳节五香肉粽子,仅限前</text>
+						<text class="tag">礼盒装 2000积分</text>
+					</view>
+				</view>
+				<view class="points">
+					<text class="totalName" style="margin-right: 50rpx;">共一项</text>
+					<text class="totalName">共计:</text>
+					<text class="totalContent">2000积分</text>
+				</view>
+				<view class="btn">
+					<view class="btnitem" @click="openVFcode">
+						<text>核销码</text>
+					</view>
+					<view class="btnitem" v-if="false">
+						<text>取消</text>
+					</view>
+					<view class="btnitem" v-if="false">
+						<text>兑换</text>
+					</view>
+					<view class="btnitem" v-if="false">
+						<text>确认收货</text>
+					</view>
+				</view>
+			</view>
+		</view>
+		<!-- 待兑换 -->
+		<view v-if="isActive == 1">
+			<view class="card" v-for="item in orderList">
+				<view class="toptitle">
+					<view>订单号:62aae0eb9c6fd622</view>
+					<view>未核销</view>
+				</view>
+				<view class="shopCard">
+					<image src="http://t9.9026.com/imgs/Kudosbg.png"></image>
+					<view style="margin-left: 24rpx;">
+						<text class="name">端午佳节五香肉粽子,仅限前</text>
+						<text class="tag">礼盒装 2000积分</text>
+					</view>
+				</view>
+				<view class="points">
+					<text class="totalName" style="margin-right: 50rpx;">共一项</text>
+					<text class="totalName">共计:</text>
+					<text class="totalContent">2000积分</text>
+				</view>
+				<view class="btn">
+
+					<view class="btnitem">
+						<text>取消</text>
+					</view>
+					<view class="btnitem" @click="goIntegralExchange">
+						<text>兑换</text>
+					</view>
+
+				</view>
+			</view>
+		</view>
+		<!-- 待发货 -->
+		<view v-if="isActive ==2">
+			<view class="card" v-for="item in orderList">
+				<view class="toptitle">
+					<view>订单号:62aae0eb9c6fd622</view>
+					<view>未核销</view>
+				</view>
+				<view class="shopCard">
+					<image src="http://t9.9026.com/imgs/Kudosbg.png"></image>
+					<view style="margin-left: 24rpx;">
+						<text class="name">端午佳节五香肉粽子,仅限前</text>
+						<text class="tag">礼盒装 2000积分</text>
+					</view>
+				</view>
+				<view class="points">
+					<text class="totalName" style="margin-right: 50rpx;">共一项</text>
+					<text class="totalName">共计:</text>
+					<text class="totalContent">2000积分</text>
+				</view>
+				<view class="btn">
+
+					<view class="btnitem" v-if="false">
+						<text>取消</text>
+					</view>
+					<view class="btnitem" v-if="false" >
+						<text>兑换</text>
+					</view>
+
+				</view>
+			</view>
+		</view>
+		<!-- 待收货 -->
+		<view v-if="isActive == 3">
+			<view class="card" v-for="item in orderList" @click="goOrderDetail">
+				<view class="toptitle">
+					<view>订单号:62aae0eb9c6fd622</view>
+					<view>未核销</view>
+				</view>
+				<view class="shopCard">
+					<image src="http://t9.9026.com/imgs/Kudosbg.png"></image>
+					<view style="margin-left: 24rpx;">
+						<text class="name">端午佳节五香肉粽子,仅限前</text>
+						<text class="tag">礼盒装 2000积分</text>
+					</view>
+				</view>
+				<view class="points">
+					<text class="totalName" style="margin-right: 50rpx;">共一项</text>
+					<text class="totalName">共计:</text>
+					<text class="totalContent">2000积分</text>
+				</view>
+				<view class="btn">
+					<view class="btnitem">
+						<text>确认收货</text>
+					</view>
+				</view>
+			</view>
+		</view>
+		<!-- 已完成 -->
+		<view v-if="isActive == 4">
+			<view class="card" v-for="item in orderList">
+				<view class="toptitle">
+					<view>订单号:62aae0eb9c6fd622</view>
+					<view>未核销</view>
+				</view>
+				<view class="shopCard">
+					<image src="http://t9.9026.com/imgs/Kudosbg.png"></image>
+					<view style="margin-left: 24rpx;">
+						<text class="name">端午佳节五香肉粽子,仅限前</text>
+						<text class="tag">礼盒装 2000积分</text>
+					</view>
+				</view>
+				<view class="points">
+					<text class="totalName" style="margin-right: 50rpx;">共一项</text>
+					<text class="totalName">共计:</text>
+					<text class="totalContent">2000积分</text>
+				</view>
+				<view class="btn">
+
+				</view>
+			</view>
+		</view>
+		
+		<!-- 已经到底啦 -->
+		<view class="home-bottom">
+			<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText"/>
+		</view>
+		
+		<!-- 弹出层/核销码 -->
+		<uni-popup ref="popup" type="center">
+			<view class="pop">
+				<view class="title"><text>核销码</text></view>
+				<view style="margin-left:30rpx;width: 580rpx;height: 2rpx;background: #F0F0F0;"></view>
+				<view class="img">
+					<image src="http://t9.9026.com/imgs/Kudosbg.png"></image>
+				</view>
+				<view class="btn">
+					<view class="cancel" @click="closeVFcode"><text>取消</text></view>
+					<view class="download" @click="handleDownImg"><text>保存图片</text></view>
+				</view>
+			</view>
+		</uni-popup>
+		
+	</view>
+</template>
+
+<script>
+	import util from './../../../utils/util.js'
+	export default {
+		data() {
+			return {
+				// 搜索
+				search:'',
+				// 分段器标题
+				items: ['全部', '待兑换', '待发货', '待收货', '已完成'],
+				isActive: 0,
+				// 组件uni-load-more
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				// 订单列表
+				orderList:[],
+			}
+		},
+		onLoad(o) {
+			if (o.isActive) {
+				this.isActive = o.isActive
+				this.getMyOrder(o.isActive)
+			}else{
+				this.getMyOrder()
+			}
+		},
+		methods: {
+			// 获取订单列表
+			getMyOrder(type){
+				this.$api.orders.getOrderList({
+					page:1,
+					status:type||'',
+					keyword:this.search
+				}).then(res=>{
+					console.log(res,type,"订单列表")
+					if(res.code==0){
+						this.orderList=res.data.data
+					}
+				})
+			},
+			//菜单index切换
+			checked(index) {
+				this.isActive = index
+				this.getMyOrder(index)
+			},
+			// 搜索防抖
+			searchText:util.debounce(function(){
+				this.goSearch()
+			},1000),
+			// 搜索
+			goSearch(){
+				this.$api.orders.getOrderList({
+					status:this.isActive,
+					page:1,
+					keyword:this.search
+				}).then(res=>{
+					console.log(res,"搜索活动项目列表")
+					if(res.code==0){
+						this.orderList=res.data.data
+					}
+				})
+			},
+			// 跳转订单详情
+			goOrderDetail() {
+				uni.navigateTo({
+					url: '/pages/my/myorders/orderDetail'
+				})
+			},
+			// 跳转积分兑换
+			goIntegralExchange(){
+				uni.navigateTo({
+					url: '/pages/my/integral/integralOrder'
+				})
+			},
+			// 打开弹出层
+			openVFcode() {
+				this.$refs.popup.open()
+			},
+			// 关闭弹出层
+			closeVFcode() {
+				this.$refs.popup.close()
+			},
+			// 保存图片
+			handleDownImg() {
+				this.$refs.popup.close()
+				// const that = this;
+				// uni.downloadFile({
+				//     url:'网络路径',
+				//     success: res => {
+				//         if (res.statusCode === 200) {
+				//             uni.saveImageToPhotosAlbum({
+				//                 filePath: res.tempFilePath,
+				//                 success: function() {
+				//                     this.tools.toast('保存成功');
+				// 		this.$refs.popup.close()
+				//                 },
+				//                 fail: function() {
+				//                     this.tools.toast('保存失败,请稍后重试');
+			 //                 }
+				//             });
+				//         } else {
+				//             this.tools.toast('下载失败');
+				//         }
+				//     }
+				// });
+			},
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	// flex布局居中对齐
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.orders {
+		height: 100%;
+		background: $pageColor;
+	}
+	
+	.home-bottom {
+		padding-top: 80rpx;
+		background-color: #f9f9f9;
+	}
+	
+
+	::v-deep .segmented-control__text {
+		font-size: 32rpx !important;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		font-weight: 500 !important;
+		color: #666666 !important;
+
+	}
+
+	::v-deep .segmented-control__item--text {
+		font-size: 32rpx !important;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		font-weight: 800 !important;
+		padding: 10rpx 0 !important;
+		color: #D9A94D !important;
+		border-radius: 4rpx !important;
+
+	}
+	
+	
+	
+	.nav {
+		height: 220rpx;
+		width: 750rpx;
+		background: $bgColor;
+
+		.navbox {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 0 30rpx;
+			box-sizing: border-box;
+
+			// 搜索
+			.search {
+				height: 124rpx;
+				width: 690px;
+				background-color: $bgColor;
+				@include flexlayout;
+
+				::v-deep .u-input {
+					width: 690rpx !important;
+					height: 68rpx !important;
+					background: #F1F1F1;
+					border-radius: 74rpx;
+				}
+
+				::v-deep .u-input__content__field-wrapper {
+					padding-left: 36rpx;
+				}
+				::v-deep .u-input__content__field-wrapper__field{
+					color:#999999 !important;
+					font-size: 28rpx !important;
+				}
+			}
+		}
+		.segmented {
+			margin-top: 18rpx;
+			width: 750rpx;
+			border-radius: 0rpx 0rpx 16rpx 16rpx;
+			padding:0 30rpx;
+			box-sizing: border-box;
+			//菜单切换
+			.tab_nav {
+				width: 690rpx;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				font-family: PingFang-SC-Heavy, PingFang-SC;
+				
+			}
+			
+			.tab_nav .navTitle {
+				width: 128rpx;
+				flex: none;
+				height: 28rpx;
+				font-size: 32rpx;
+				color: #666;
+				display: flex;
+				align-items: center;
+				justify-content: space-around;
+				position: relative;
+			}
+			
+			.active {
+				color: #D9A94D;
+				font-weight: bold;
+			
+				&::after {
+					display: inline-block;
+					content: '';
+					width: 48rpx;
+					height: 12rpx;
+					background: linear-gradient(90deg, #F3D69F 0%, #D9A94D 100%);
+					border-radius: 6px;
+					position: absolute;
+					bottom: -30rpx;
+					left: 40rpx;
+				}
+			}
+			}
+		
+	}
+
+	.card {
+		margin-top: 24rpx;
+		background: $bgColor;
+		border-radius: 16rpx;
+		padding: 32rpx 28rpx 24rpx 28rpx;
+		box-sizing: border-box;
+
+		.toptitle {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			font-size: 28rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #080F18;
+		}
+
+		.shopCard {
+			margin-top: 28rpx;
+			width: 694rpx;
+			height: 164rpx;
+			background: #F4F5F6;
+			border-radius: 10rpx;
+			display: flex;
+			align-items: center;
+
+			image {
+				width: 132rpx;
+				height: 132rpx;
+				margin-left: 16rpx;
+				display: inline-block;
+				border-radius: 12rpx;
+			}
+
+			.name {
+				font-size: 28rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #080F18;
+				display: block;
+			}
+
+			.tag {
+				font-size: 24rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+
+		.points {
+			display: flex;
+			justify-content: flex-end;
+			align-items: center;
+			margin-top: 30rpx;
+
+			.totalName {
+				font-size: 22rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #080F18;
+				margin-right: 10rpx;
+			}
+
+			.totalContent {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Heavy, PingFang-SC;
+				font-weight: 800;
+				color: #080F18;
+			}
+		}
+
+		.btn {
+			margin-top: 30rpx;
+			display: flex;
+			justify-content: flex-end;
+
+			.btnitem {
+				margin-left: 16rpx;
+				width: 170rpx;
+				height: 60rpx;
+				background: #FFFFFF;
+				border-radius: 30rpx;
+				border: 2rpx solid #D0D0D0;
+
+				@include flexlayout() text {
+					font-size: 26rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #080F18;
+				}
+			}
+		}
+
+	}
+
+	.pop {
+		width: 640rpx;
+		height: 764rpx;
+		background: $bgColor;
+		border-radius: 20rpx;
+		padding-top: 64rpx;
+		box-sizing: border-box;
+
+		.title {
+			@include flexlayout();
+			margin-bottom: 24rpx;
+
+			text {
+				font-size: 34rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #333333;
+			}
+		}
+
+		.img {
+			margin-top: 10rpx;
+			margin-left: 48rpx;
+			width: 544rpx;
+			height: 468rpx;
+			background: $bgColor;
+			border-radius: 2rpx;
+			@include flexlayout();
+
+			image {
+				width: 392rpx;
+				height: 390rpx;
+			}
+		}
+
+		.btn {
+			margin-top: 40rpx;
+			width: 100%;
+			height: 110rpx;
+			display: flex;
+			align-items: center;
+
+			.cancel {
+				@include flexlayout();
+				width: 50%;
+				height: 100%;
+				border-top: #E5E5E5 solid 1rpx;
+				border-right: #E5E5E5 solid 1rpx;
+
+				text {
+					font-size: 32rpx;
+					font-family: PingFangSC-Medium, PingFang SC;
+					font-weight: 500;
+					color: #666666;
+				}
+			}
+
+			.download {
+				border-top: #E5E5E5 solid 1rpx;
+				// border-left:#E5E5E5 solid 0.3rpx;
+				@include flexlayout();
+				height: 100%;
+				width: 50%;
+
+				text {
+					font-size: 32rpx;
+					font-family: PingFangSC-Medium, PingFang SC;
+					font-weight: 500;
+					color: #FF7119;
+				}
+			}
+		}
+	}
+</style>

+ 182 - 0
pages/my/prize/exchangeDetail.vue

xqd
@@ -0,0 +1,182 @@
+<template>
+	<view class="exchangeDetail">
+		<!-- 兑换状态 -->
+		<view class="detailCard">
+			<image src="/static/icon/success.png"></image>
+			<text>奖品兑换成功</text>
+		</view>
+		<!-- 按钮 -->
+		<view class="btn">
+			<view class="back" @click="goBack">
+				<text>返回首页</text>
+			</view>
+			<view class="checkout" @click="goOrderDetail">
+				<text>查看订单</text>
+			</view>
+		</view>
+		<!-- 加入会员 -->
+		<view class="bottomCard" @click="goOther">
+			<image src="/static/icon/Kudosbg.png"></image>
+			<view class="content">
+				<text>立即加入IHG会员</text>
+				<image src="/static/icon/right.png"></image>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+
+			}
+		},
+
+		methods: {
+			// 返回首页
+			goBack() {
+				uni.reLaunch({
+					url: '/pages/my/my'
+				})
+			},
+			// 跳转订单详情
+			goOrderDetail() {
+				uni.navigateTo({
+					url: '/pages/my/myorders/orders'
+				})
+			},
+			// 跳转其他小程序
+			goOther() {
+				wx.navigateToMiniProgram({
+					appId: 'wx255b58f0992b3c53', //appid
+					path: 'newUIMain/enrollment/enrollment', //path
+					extraData: { //参数
+						foo: 'bar'
+					},
+					// envVersion: 'develop', //开发版develop 开发版 trial   体验版 release 正式版 
+					success(res) {
+						console.log('成功')
+						// 打开成功
+					},
+					fail(e) {
+						console.log(e, '失败')
+					}
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.exchangeDetail {
+		height: 100%;
+		background: $pageColor;
+	}
+
+	.detailCard {
+		width: 750rpx;
+		height: 446rpx;
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		align-items: center;
+
+		image {
+			width: 120rpx;
+			height: 120rpx;
+			margin-bottom: 48rpx;
+		}
+
+		text {
+			display: block;
+			font-size: 32rpx;
+			font-family: PingFangSC-Medium, PingFang SC;
+			font-weight: 500;
+			color: #080F18;
+		}
+	}
+
+	.btn {
+		width: 750rpx;
+		height: 76rpx;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding:0 32rpx;
+		.back {
+			width: 332rpx;
+			height: 76rpx;
+			background: #F5F5F5;
+			border-radius: 8rpx;
+
+			@include flexlayout() text {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #FF6301;
+			}
+		}
+
+		.checkout {
+			width: 332rpx;
+			height: 76rpx;
+			background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);
+			border-radius: 8rpx;
+
+			@include flexlayout() text {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #FFFFFF;
+			}
+		}
+	}
+
+	.bottomCard {
+		width: 690rpx;
+		height: 584rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 8rpx 16rpx 0px rgba(220, 222, 229, 0.71);
+		border-radius: 20rpx;
+		background: $bgColor;
+		margin-left: 30rpx;
+		margin-top: 64rpx;
+
+		image {
+			width: 690rpx;
+			height: 492rpx;
+		}
+
+		.content {
+			width: 690rpx;
+			height: 92rpx;
+			position: relative;
+			margin-top:-9rpx;
+			border:1rpx solid;
+			@include flexlayout();
+			image {
+				width: 12rpx;
+				height: 20rpx; 
+				margin-left: 8rpx;
+			}
+			text {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #333333;
+				text-shadow: 0px 8rpx 16rpx rgba(220, 222, 229, 0.71);
+			}
+		}
+	}
+</style>

+ 259 - 0
pages/my/prize/exchangePrize.vue

xqd
@@ -0,0 +1,259 @@
+<template>
+	<view class="exchangePrize">
+		<!-- 表单 -->
+		<view class="form">
+			<uni-forms :modelValue="formData" >
+				<uni-forms-item  name="type" v-if="istype">
+					<view class="selectType">
+						<picker mode="selector" :value="formData.type" :range='typeSelect'
+							@change="bindTypeChange">
+							<view class="uni-input" >
+								<text v-if="formData.type==''||formData.type==null"
+									style="color: #999999 ;">请选择配送方式</text>
+								<text v-if="formData.type!=''">{{formData.type}}</text>
+							</view>
+							<image src="/static/icon/right.png"
+								style="width: 14rpx;height: 24rpx;position: absolute;top:20rpx;right: 30rpx;"></image>
+						</picker>
+					</view>
+				</uni-forms-item>
+				<uni-forms-item  name="name" v-if="formData.type!=''||isVerification==true">
+					<uni-easyinput type="text" v-model="formData.name" placeholder="填写联系人" />
+				</uni-forms-item>
+				<uni-forms-item  name="phone" v-if="formData.type!=''||isVerification==true">
+					<uni-easyinput type="number" v-model="formData.phone" placeholder="填写联系电话" />
+				</uni-forms-item>
+				<uni-forms-item  name="region" v-if="formData.type=='快递配送'">
+					<uni-easyinput type="text" v-model="formData.region" placeholder="所在地区" />
+				</uni-forms-item>
+				<uni-forms-item  name="region" v-if="formData.type=='快递配送'">
+					<uni-easyinput type="text" v-model="formData.region" placeholder="详细地址" />
+				</uni-forms-item>
+				<uni-forms-item  name="region" v-if="formData.type=='到店自提'||isVerification==true">
+					<view class="selectType">
+						<picker mode="selector" :value="formData.region" :range='regionSelect'
+							@change="bindregionChange">
+							<view class="uni-input" >
+								<text v-if="formData.region==''||formData.region==null"
+									style="color: #999999 ;">请选择门店</text>
+								<text v-if="formData.region!=''">{{formData.region}}</text>
+							</view>
+							<image src="/static/icon/right.png"
+								style="width: 14rpx;height: 24rpx;position: absolute;top:20rpx;right: 30rpx;"></image>
+						</picker>
+					</view>
+				</uni-forms-item>
+			</uni-forms>
+		</view>
+		
+		<!-- 奖品信息 -->
+		<view class="msg">
+			<view class="title">
+				<text>奖品信息</text>
+			</view>
+			<view class="shopCard">
+				<image  src="/static/icon/Kudosbg.png"></image>
+				<view style="margin-left: 24rpx;">
+					<text class="name">端午佳节五香肉粽子,仅限前</text>
+					<text class="tag">礼盒装 </text>
+				</view>
+			</view>
+			<view class="shopNumber">
+				<text>件数</text>
+				<text>1件</text>
+			</view>
+		</view>
+		
+		<!-- 兑换按钮 -->
+		<view class="bottombtn" @click="goExDetail">
+			<view class="btnitem" >
+				<text>确认兑换</text>
+			</view>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	export default {
+		data(){
+			return{
+				//产品
+				id:'',
+				// 是否核销
+				isVerification:false,
+				// 表单数据
+				formData:{
+					type:'',
+					phone:'',
+					name:'',
+					region:'',
+					address:'',
+				},
+				// 配送方式
+				typeSelect:['快递配送','到店自提'],
+				// 是否显示配送方式
+				istype:true,
+				// 选择门店
+				regionSelect:['第一门店','第二门店','第三门店','第四门店']
+			}
+		},
+		
+		onLoad(o) {
+			if(o.id){
+				this.id = o.id
+				this.getProductDetail()
+			}
+			
+			
+		},
+		
+		methods:{
+			getProductDetail(){
+				this.$api.product.getProductDetail({
+					product_id:this.id
+				}).then(res=>{
+					console.log(res,'------->res');
+				})
+			},
+			
+			// 选择快递方式
+			bindTypeChange:function(e){
+				if(e.detail.value==0){
+					this.formData.type='快递配送'
+				}else{
+					this.formData.type='到店自提'
+				}
+			},
+			// 跳转兑换详情
+			goExDetail(){
+				uni.navigateTo({
+					url:'/pages/my/prize/exchangeDetail'
+				})
+			},
+			// 选择门店
+			bindregionChange:function(e){
+				this.formData.region=this.regionSelect[e.detail.value]
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+	.exchangePrize{
+		height: 100%;
+		background:$bgColor ;
+	}
+	::v-deep .uni-forms-item{
+		margin-bottom: 24rpx;
+	}
+	::v-deep .uni-forms-item__content{
+		font-size: 30rpx;
+		border: 2rpx solid #EAEAEA;
+		padding:18rpx 0;
+		border-radius: 8rpx;
+		background-color: #fff;
+	}
+	::v-deep .is-input-border{
+		border: none;
+	}
+	.form{
+		background:$pageColor ;
+		width: 750rpx;
+		padding:24rpx 30rpx 12rpx 30rpx;
+		box-sizing: border-box;
+		.selectType{
+			width: 690rpx;
+			height: 68rpx;
+			background: #FFFFFF;
+			display: flex;
+			align-items:center;
+			padding-left: 20rpx; 
+			box-sizing: border-box;
+			position: relative;
+		}
+	}
+	.msg{
+		width: 750rpx;
+		height: 700rpx;
+		background:$bgColor;
+		border-radius: 12rpx 12rpx 0px 0px;
+		padding:32rpx 30rpx;
+		.title{
+			margin-bottom: 24rpx;
+			text{
+				font-size: 32rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #080F18;
+			}
+		}
+		.shopCard{
+			margin-top: 28rpx;
+			width: 694rpx;
+			height: 164rpx;
+			background: #F4F5F6;
+			border-radius: 10rpx;
+			display: flex;
+			align-items: center;
+			image{
+				width: 132rpx;
+				height: 132rpx; 
+				margin-left: 16rpx;
+				display: inline-block;
+				border-radius: 10rpx;
+			}
+			.name{
+				font-size: 28rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #080F18;
+				display: block;
+			}
+			.tag{
+				font-size: 24rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+		.shopNumber{
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			margin-top: 25rpx;
+			text{
+				font-size: 26rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #000000;
+			}
+		}
+	}
+	.bottombtn{
+		width: 690rpx;
+		height: 92rpx;
+		background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);	
+		border-radius: 12rpx;
+		margin-left: 30rpx;
+		position: fixed;
+		bottom: 72rpx;
+		@include flexlayout();
+		.btnitem{
+			@include flexlayout();
+			text{
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: $bgColor;
+			}
+		}
+	}
+</style>

+ 374 - 0
pages/my/prize/prize.vue

xqd
@@ -0,0 +1,374 @@
+<template>
+	<view class="prize">
+		<!-- 分段器 -->
+		<view class="segmented">
+			<view class="tab_nav">
+				<view class="navTitle" v-for="(item,index) in items" :key="index">
+					<view :class="{'active':isActive == index}" @click="checked(index)">
+						{{item}}
+					</view>
+				</view>
+			</view>
+		</view>
+
+		<view style="margin-bottom: 60rpx; ">
+			<!-- 实物奖品 -->
+			<view class="prizeList" :style="{'--height':ListHeight+'rpx'}" v-if="isActive == 0">
+				<view class="ListItem" v-for="(item,index) in PhysicalPrizes" :key="index">
+					<view class="title"><text>{{item.name}}</text></view>
+					<view class='data'><text>{{item.created_at}}</text></view>
+					<view class="alreadyBtn" v-if="false">
+						<text>已兑换</text>
+					</view>
+					<view class="instantBtn" @click="goExchangePhy(item.id)">
+						<text>立即兑换</text>
+					</view>
+				</view>
+			</view>
+			
+			<!-- 线下奖品 -->
+			<view class="prizeList" :style="{'--height':ListHeight+'rpx'}" v-if="isActive == 1">
+				<view class="ListItem" v-for="(item,index) in VirtualPrizes" :key="index">
+					<view class="title"><text>{{item.name}}</text></view>
+					<view class='data'><text>{{item.created_at}}</text></view>
+					<view class="alreadyBtn" v-if="false">
+						<text>已兑换</text>
+					</view>
+					<view class="instantBtn" @click="goExchangeVir(item.id)">
+						<text>立即兑换</text>
+					</view>
+				</view>
+			</view>
+			
+			<!-- 中奖记录 -->
+			<view class="prizeList" :style="{'--height':ListHeight+'rpx'}" v-if="isActive == 2">
+				<view class="ListItem" v-for="(item,index) in prizeRecord" :key="index"> 
+					<view style="display: flex; justify-content: space-between;">
+						<view class="title"><text>{{item.name}}</text> </view>
+						<view class='data'><text>{{item.created_at}}</text></view>
+					</view>
+					<view class="content"><text>{{item.remark||'无'}}</text></view>
+				</view>
+			</view>
+		</view>
+		
+		<!-- 已经到底啦 -->
+		<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText" />
+
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				// 分段器标题
+				items: ['实物奖品', '虚拟奖品', '中奖记录'],
+				isActive: 0,
+				// 列表高度
+				ListHeight: 800,
+				// 组件uni-load-more
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '—— 已经到底啦 ——'
+				},
+				// 实物奖品列表
+				PhysicalPrizes:[],
+				// 虚拟奖品列表
+				VirtualPrizes:[],
+				// 中奖记录
+				prizeRecord:[]
+			}
+		},
+		onLoad() {
+			// 中奖记录
+			this.getPrizeRecord()
+			//实物奖品
+			this.getPrizeList(0)
+			//虚拟奖品
+			this.getPrizeList(1)
+		},
+		methods: {
+			// 获取奖品列表
+			getPrizeList(type){
+				this.$api.lottery.getDrawRecord({
+					is_virtual:type,
+					page:1
+				}).then(res=>{
+					//实物奖品
+					if(type == 0){
+						this.PhysicalPrizes = res.data.data
+					}else{
+						this.VirtualPrizes = res.data.data
+					}
+				})
+			},
+			// 获取中奖记录
+			getPrizeRecord(){
+				this.$api.lottery.getDrawRecord({
+					page:0
+				}).then(res=>{
+					console.log(res,"中奖记录")
+					if(res.code==0){
+						this.prizeRecord=res.data.data
+					}
+				})
+			},
+			//分段器标题切换
+			checked(index) {
+				this.isActive = index
+			},
+			// 实物立即兑换
+			goExchangePhy(id) {
+				uni.navigateTo({
+					url: '/pages/my/prize/exchangePrize?id='+id
+				})
+			},
+			// 虚拟立即兑换
+			goExchangeVir(id) {
+				uni.navigateTo({
+					url: '/pages/my/prize/exchangePrize?id='+id
+				})
+			},
+		},
+
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.prize {
+		height: 100%;
+		background: $pageColor;
+	}
+
+
+
+	.segmented {
+		width: 750rpx;
+		height: 112rpx;
+		background: $bgColor;
+		box-shadow: 0px 4rpx 8rpx 0rpx rgba(0, 0, 0, 0.04);
+		border-radius: 0rpx 0rpx 16rpx 16rpx;
+		margin-bottom: 24rpx;
+		padding:0rpx 30rpx;
+		box-sizing: border-box;
+		//菜单切换
+		.tab_nav {
+			width: 690rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			font-family: PingFang-SC-Heavy, PingFang-SC;
+		}
+		.tab_nav .navTitle {
+			margin-top: 20rpx;
+			width: 128rpx;
+			flex: none;
+			height: 28rpx;
+			font-size: 32rpx;
+			color: #666;
+			position: relative;
+		}
+		.active {
+			color: #D9A94D;
+			font-weight: bold;
+
+			&::after {
+				display: inline-block;
+				content: '';
+				width: 48rpx;
+				height: 12rpx;
+				background: linear-gradient(90deg, #F3D69F 0%, #D9A94D 100%);
+				border-radius: 6px;
+				position: absolute;
+				bottom: -35rpx;
+				left: 40rpx;
+			}
+		}
+	}
+
+	::v-deep .segmented-control__text {
+		font-size: 32rpx !important;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		font-weight: 500 !important;
+	}
+
+	::v-deep .segmented-control__item--text {
+		font-size: 32rpx;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		font-weight: 800 !important;
+		padding: 10rpx 0 !important;
+		border-radius: 4rpx !important;
+	}
+
+	.prizeList {
+		width: 750rpx;
+		// height: var(--height);
+		background: $bgColor;
+		box-shadow: 0px 4rpx 24rpx -10rpx rgba(101, 95, 90, 0.3);
+		border-radius: 12rpx;
+		padding: 0rpx 28rpx 0 32rpx;
+		box-sizing: border-box;
+
+		.ListItem {
+			width: 690rpx;
+			height: 160rpx;
+			border-bottom: #F0F0F0 solid 0.5rpx;
+			position: relative;
+			padding-top: 35rpx;
+			box-sizing: border-box;
+
+			.title {
+				margin-bottom: 5rpx;
+
+				text {
+					font-size: 32rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: bold;
+					color: #333333;
+				}
+			}
+
+			.data {
+				text {
+					font-size: 26rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #999999;
+				}
+			}
+
+			.alreadyBtn {
+				position: absolute;
+				top: 50rpx;
+				right: 0rpx;
+				width: 148rpx;
+				height: 60rpx;
+				background: $bgColor;
+				border-radius: 30rpx;
+				border: 2rpx solid #D0D0D0;
+				@include flexlayout();
+
+				text {
+					font-size: 26rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #D0D0D0;
+				}
+			}
+
+			.instantBtn {
+				position: absolute;
+				top: 50rpx;
+				right: 0rpx;
+				width: 148rpx;
+				height: 60rpx;
+				background: $bgColor;
+				border-radius: 30rpx;
+				border: 2rpx solid #FF6200;
+				@include flexlayout();
+
+				text {
+					font-size: 26rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					color: #FF6200;
+				}
+			}
+
+			.content {
+				text {
+					font-size: 28rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #333333;
+				}
+			}
+		}
+
+		.ListItem:last-child {
+			width: 690rpx;
+			height: 160rpx;
+			border-bottom: #F0F0F0 solid 0rpx;
+			position: relative;
+			padding-top: 35rpx;
+			box-sizing: border-box;
+
+			.title {
+				margin-bottom: 10rpx;
+
+				text {
+					font-size: 32rpx;
+					font-family: PingFang-SC-Bold, PingFang-SC;
+					font-weight: bold;
+					color: #333333;
+				}
+			}
+
+			.data {
+				text {
+					font-size: 26rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					color: #999999;
+				}
+			}
+
+			.alreadyBtn {
+				position: absolute;
+				top: 50rpx;
+				right: 0rpx;
+				width: 148rpx;
+				height: 60rpx;
+				background: $bgColor;
+				border-radius: 30rpx;
+				border: 2rpx solid #D0D0D0;
+				@include flexlayout();
+
+				text {
+					font-size: 26rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #D0D0D0;
+				}
+			}
+
+			.instantBtn {
+				position: absolute;
+				top: 50rpx;
+				right: 0rpx;
+				width: 148rpx;
+				height: 60rpx;
+				background: $bgColor;
+				border-radius: 30rpx;
+				border: 2rpx solid #FF6200;
+				@include flexlayout();
+
+				text {
+					font-size: 26rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #FF6200;
+				}
+			}
+
+			.content {
+				text {
+					font-size: 28rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #333333;
+				}
+			}
+		}
+	}
+</style>

+ 76 - 0
pages/my/protocol/PrivacyPolicy.vue

xqd
@@ -0,0 +1,76 @@
+<template>
+	<view class="Privacy">
+		<view class="content" v-html="content"></view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				content: '',
+			}
+		},
+		onLoad() {
+			let obj = this.$store.getters.allset.privacy
+			this.content = obj.value.privacy
+		},
+		methods: {
+			// 获取隐私协议
+			// getPrivacy() {
+			// 	this.$loading();
+			// 	this.$api.document.privacy().then(res => {
+			// 		console.log(res, "隐私协议")
+			// 		if (res.code == 0) {
+			// 			this.content = res.data.value.privacy
+			// 		};
+			// 		this.$hideLoading();
+			// 	}).catch(e => {
+			// 		console.log(e)
+			// 		this.$hideLoading()
+			// 	})
+			// }
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	.Privacy {
+		height: 100%;
+		background: $bgColor;
+	}
+
+	.title {
+		height: 82rpx;
+		width: 750rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+
+		text {
+			font-size: 32rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #333333;
+		}
+	}
+
+	.content {
+		padding: 0 30rpx;
+
+		view {
+			margin-bottom: 24rpx;
+
+			text {
+				font-size: 28rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #333333;
+			}
+		}
+
+	}
+</style>

+ 74 - 0
pages/my/protocol/UserAgreement.vue

xqd
@@ -0,0 +1,74 @@
+<template>
+	<view class="UserAgreement">
+		<!-- <view class="title"><text>用户协议</text></view> -->
+		<view class="content" v-html="content">
+			
+		</view>
+	</view>
+</template>
+
+<script>
+	export default{
+		data(){
+			return{
+				content:'',
+			}
+		},
+		onLoad(){
+			// this.getAgreement()
+			let obj = this.$store.getters.allset.agreement
+			this.content = obj.value.agreement
+		},
+		methods:{
+			// 获取用户协议
+			// getAgreement(){
+			// 	this.$loading();
+			// 	this.$api.document.agreement().then(res=>{
+			// 		console.log(res,"用户协议")
+			// 		if(res.code==0){
+			// 			this.content=res.data.value.agreement
+			// 		}
+			// 		this.$hideLoading();
+			// 	}).catch(err=>{
+			// 		console.log(err)
+			// 		this.$hideLoading();
+			// 	})
+			// }
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+	.UserAgreement{
+		height: 100%;
+		background: $bgColor;
+	}
+	.title{
+		height: 82rpx;
+		width: 750rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		text{
+			font-size: 32rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #333333;
+		}
+	}
+	.content{
+		padding: 0 30rpx;
+		view{
+			margin-bottom: 24rpx;
+			text{
+				font-size: 28rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #333333;
+			}
+		}
+		
+	}
+</style>

+ 168 - 0
pages/my/setting/setting.vue

xqd
@@ -0,0 +1,168 @@
+<template>
+	<view class="setting">
+		<!-- 占位元素 -->
+		<view style="height: 24rpx;"></view>
+		<!-- 列表 -->
+		<view class="cell">
+			<view class="cell_item" @click="goPrivacy">
+				<text>隐私政策</text>
+				<image src="/static/icon/right.png"></image>
+			</view>
+			<view class="cell_item" @click="goUser">
+				<text>用户协议</text>
+				<image src="/static/icon/right.png"></image>
+			</view>
+			<view class="cell_item" @click="goVerfication" v-if="staff !=null">
+				<text>核销中心</text>
+				<image src="/static/icon/right.png"></image>
+			</view>
+		</view>
+		<!-- 按钮 -->
+		<view class="btn" @click="loginOut">
+			<text>退出登录</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				staff:'',
+			}
+		},
+		onLoad() {
+			this.staff = this.$store.getters.staff
+		},
+		methods: {
+			// 跳转隐私政策
+			goPrivacy() {
+				uni.navigateTo({
+					url: '/pages/my/protocol/PrivacyPolicy'
+				})
+			},
+			// 跳转用户协议
+			goUser() {
+				uni.navigateTo({
+					url: '/pages/my/protocol/UserAgreement'
+				})
+			},
+			// 跳转核销中心
+			goVerfication() {
+				uni.navigateTo({
+					url: '/pages/my/verification/verification'
+				})
+			},
+			// 退出登录
+			loginOut() {
+				if (this.$store.getters.token) {
+					//记录用户曾经登录过
+					this.$store.getters.userInfo.isLoginOff = true
+					this.$store.dispatch("user/info", this.$store.getters.userInfo)
+					// this.$store.dispatch("user/token", null)
+					// uni.removeStorageSync('auth_token')
+					// uni.removeStorageSync('userInfo')
+					uni.reLaunch({
+						url:'/pages/login/login'
+					})
+				} else {
+					uni.showToast({
+						title: '请先登录!',
+						icon: 'error'
+					})
+				}
+
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.setting {
+		height: 100%;
+		background: $pageColor;
+	}
+
+	.cell {
+		width: 100%;
+		border-radius: 16rpx;
+		padding: 0 30rpx;
+		background: $bgColor;
+		margin-bottom: 48rpx;
+
+		.cell_item {
+			box-sizing: border-box;
+			height: 110rpx;
+			width: 690rpx;
+			border-bottom: solid 2rpx #F0F0F0;
+			display: flex;
+			align-items: center;
+			position: relative;
+
+			text {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #000000;
+			}
+
+			image {
+				width: 12rpx;
+				height: 20rpx;
+				position: absolute;
+				right: 0rpx;
+				top: 46rpx;
+			}
+		}
+
+		.cell_item:nth-last-child(1) {
+			box-sizing: border-box;
+			height: 110rpx;
+			width: 690rpx;
+			border-bottom: solid 0rpx #F0F0F0;
+			display: flex;
+			align-items: center;
+			position: relative;
+
+			text {
+				font-size: 30rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #000000;
+			}
+
+			image {
+				width: 12rpx;
+				height: 20rpx;
+				position: absolute;
+				right: 0rpx;
+				top: 46rpx;
+			}
+		}
+
+	}
+
+	.btn {
+		width: 690rpx;
+		height: 92rpx;
+		background: $bgColor;
+		border-radius: 16rpx;
+		margin-left: 30rpx;
+
+		@include flexlayout() text {
+			font-size: 28rpx;
+			font-family: PingFang-SC-Medium, PingFang-SC;
+			font-weight: 500;
+			color: #333333;
+		}
+	}
+</style>

+ 271 - 0
pages/my/verification/orderVerification.vue

xqd
@@ -0,0 +1,271 @@
+<template>
+	<view class="ordersVerification">
+		<view style="height: 24rpx;width: 100%;background:#F9F9F9 ;"></view>
+		<!-- 表单 -->
+		<view class="form">
+			<uni-forms ref="baseForm" :modelValue="FormData">
+				<uni-forms-item label="收货人" labelWidth="150rpx">
+					<uni-easyinput v-model="FormData.name" placeholder="请输入收货人" />
+				</uni-forms-item>
+				<uni-forms-item label="联系方式" labelWidth="150rpx">
+					<uni-easyinput v-model="FormData.contact" placeholder="请输入联系方式" />
+				</uni-forms-item>
+				<uni-forms-item label="兑换时间" labelWidth="150rpx">
+					<uni-easyinput v-model="FormData.date" placeholder="请输入兑换时间" />
+				</uni-forms-item>
+				
+				<!-- <uni-forms-item label="兑换时间" labelWidth="150rpx">
+					<view class="date">
+						<picker mode="date" :value="FormData.date" :start="startDate" :end="endDate"
+							@change="bindDateChange">
+							<view class="uni-input" >
+								<text v-if="FormData.date==''||FormData.date==null"
+									style="color: #999999 ;">选择兑换时间</text>
+								<text v-if="FormData.date!=''">{{FormData.date}}</text>
+							</view>
+						</picker>
+					</view>
+				</uni-forms-item> -->
+				
+			</uni-forms>
+		</view>
+		
+		<!-- 商品信息 -->
+		<view class="card" >
+			<view class="toptitle">
+				<view>洲际天堂大饭店</view>
+				<view>未核销</view>
+			</view>
+			<view class="shopCard">
+				<image  src="/static/icon/Kudosbg.png"></image>
+				<view style="margin-left: 24rpx;">
+					<text class="name">端午佳节五香肉粽子,仅限前</text>
+					<text class="tag">礼盒装 2000积分</text>
+				</view>
+			</view>
+			<view class="points">
+				<text class="totalName">共计:</text>
+				<text class="totalContent">2000积分</text>
+			</view>
+			<view class="btn" >
+				<text>核销</text>
+			</view>
+		</view>
+		
+		<!-- 核销订单按钮 -->
+		<view class="bottombtn">
+			<view class="btnitem" @click="verificationOrder">
+				<text>核销订单</text>
+			</view>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	export default{
+		data(){
+			const currentDate = this.getDate({
+				format: true
+			})
+			return{
+				// 表单数据
+				FormData:{
+					name:'',
+					contact:'',
+					date:'',
+				},
+			}
+		},
+		computed: {
+			startDate() {
+				return this.getDate('start');
+			},
+			endDate() {
+				return this.getDate('end');
+			}
+		},
+		methods:{
+			// 核销订单
+			verificationOrder(){
+				uni.showModal({
+					title: '提示',
+					content: '是否核销订单',
+					cancelColor:'#333333',
+					confirmColor:'#FF6200',
+					success: function (res) {
+						if (res.confirm) {
+							console.log('用户点击确定');
+						} else if (res.cancel) {
+							console.log('用户点击取消');
+						}
+					}
+				});
+			},
+			// 选择兑换时间
+			bindDateChange: function(e) {
+				this.FormData.date=e.detail.value
+			},
+			// 获取时间
+			getDate(type) {
+				const date = new Date();
+				let year = date.getFullYear();
+				let month = date.getMonth() + 1;
+				let day = date.getDate();
+			
+				if (type === 'start') {
+					year = year - 60;
+				} else if (type === 'end') {
+					year = year + 2;
+				}
+				month = month > 9 ? month : '0' + month;
+				day = day > 9 ? day : '0' + day;
+				return `${year}-${month}-${day}`;
+			}
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+
+	// flex布局居中对齐
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.ordersVerification {
+		height: 100%;
+		background: $pageColor;
+	}
+	::v-deep .uni-forms-item.is-direction-left{
+		border-bottom: 2rpx solid #F0F0F0;
+	}
+	::v-deep .uni-forms-item.is-direction-left:last-child{
+		border-bottom: 0rpx solid #F0F0F0;
+	}
+	::v-deep .is-input-border {
+		border: none;
+	}
+	.form {
+		width: 750rpx;
+		height: 328rpx;
+		background: $bgColor;
+		border-radius: 16rpx;
+		padding:10rpx 30rpx;
+		box-sizing: border-box;
+	}
+	.card{
+		margin-top: 24rpx;
+		// width: 750rpx;
+		// height: 426rpx;
+		background: $bgColor;
+		border-radius: 16rpx;
+		padding:32rpx 28rpx 24rpx 28rpx;
+		box-sizing: border-box;
+		.toptitle{
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			font-size: 28rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #080F18;
+		}
+		.shopCard{
+			margin-top: 28rpx;
+			width: 694rpx;
+			height: 164rpx;
+			background: #F4F5F6;
+			border-radius: 10rpx;
+			display: flex;
+			align-items: center;
+			image{
+				width: 132rpx;
+				height: 132rpx; 
+				margin-left: 16rpx;
+				display: inline-block;
+			}
+			.name{
+				font-size: 28rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #080F18;
+				display: block;
+			}
+			.tag{
+				font-size: 24rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+		.points{
+			display: flex;
+			justify-content: flex-end;
+			align-items: center;
+			margin-top: 30rpx;
+			.totalName{
+				font-size: 22rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #080F18;
+				margin-right: 10rpx;
+			}
+			.totalContent{
+				font-size: 30rpx;
+				font-family: PingFang-SC-Heavy, PingFang-SC;
+				font-weight: 800;
+				color: #080F18;
+			}
+		}
+		.btn{
+			width: 170rpx;
+			height: 60rpx;
+			background: #FFFFFF;
+			border-radius: 30rpx;
+			border: 2rpx solid #D0D0D0;
+			margin-left: 524rpx;
+			margin-top: 15rpx;
+			@include flexlayout()
+			text{
+				font-size: 26rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #080F18;
+			}
+		}
+	}
+	.bottombtn{
+		width: 690rpx;
+		height: 92rpx;
+		background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);	
+		border-radius: 12rpx;
+		margin-left: 30rpx;
+		position: fixed;
+		bottom: 72rpx;
+		@include flexlayout()
+		.btnitem{
+			@include flexlayout()
+			text{
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: $bgColor;
+			}
+		}
+	}
+	.date{
+		width: 545rpx;
+		height: 74rpx;
+		background: #FFFFFF;
+		display: flex;
+		align-items:center;
+		padding-left: 20rpx; 
+		box-sizing: border-box;
+		position: relative;
+	}
+</style>

+ 376 - 0
pages/my/verification/verification.vue

xqd
@@ -0,0 +1,376 @@
+<template>
+	<view class="verification">
+		<view class="nav">
+			<!-- 搜索栏 -->
+			<view class="navbox">
+				<view class="search">
+					<u-input placeholder="搜索" border='none' v-model="search"  @input="searchText">
+						<template slot="suffix" style='margin-right:40rpx;'>
+							<u-image :showLoading="true" :showError='true' src="/static/icon/search.png" width="40rpx"
+								height="32rpx"></u-image>
+						</template>
+					</u-input>
+				</view>
+				<view>
+					<image src="/static/icon/scan.png" style="width: 48rpx ;height: 48rpx;" @click="scanCode"></image>
+				</view>
+			</view>
+			<!-- 分段器 -->
+			<view class="segmented">
+					<view class="tab_nav">
+						<view class="navTitle" v-for="(item,index) in items" :key="index">
+							<view :class="{'active':isActive == index}" @click="checked(index)">
+								{{item}}
+							</view>
+						</view>
+					</view>
+			</view>
+		</view>
+		
+		<!-- 未核销列表 -->
+		<view v-if="isActive === 0">
+			<view class="card" v-for="item in orderList" >
+				<view class="toptitle">
+					<view>洲际天堂大饭店</view>
+					<view>未核销</view>
+				</view>
+				<view class="shopCard">
+					<image  src="/static/icon/Kudosbg.png"></image>
+					<view style="margin-left: 24rpx;">
+						<text class="name">端午佳节五香肉粽子,仅限前</text>
+						<text class="tag">礼盒装 2000积分</text>
+					</view>
+				</view>
+				<view class="points">
+					<text class="totalName">共计:</text>
+					<text class="totalContent">2000积分</text>
+				</view>
+				<view class="btn" @click="goOrderVF">
+					<text>核销</text>
+				</view>
+			</view>
+		</view>
+		<!-- 已核销列表 -->
+		<view v-if="isActive === 1">
+			<view class="card" v-for="item in orderList" @click="goDetail">
+				<view class="toptitle">
+					<view>洲际天堂大饭店</view>
+					<view>未核销</view>
+				</view>
+				<view class="shopCard">
+					<image  src="/static/icon/Kudosbg.png"></image>
+					<view style="margin-left: 24rpx;">
+						<text class="name">端午佳节五香肉粽子,仅限前</text>
+						<text class="tag">礼盒装 2000积分</text>
+					</view>
+				</view>
+				<view class="points">
+					<text class="totalName">共计:</text>
+					<text class="totalContent">2000积分</text>
+				</view>
+				<view class="btn" v-if="false">
+					<text>核销</text>
+				</view>
+			</view>
+		</view>
+		<!-- 我的列表 -->
+		<view v-if="isActive === 2" >
+			<view class="card" v-for="item in orderList" @click="goDetail">
+				<view class="toptitle">
+					<view>洲际天堂大饭店</view>
+					<view>未核销</view>
+				</view>
+				<view class="shopCard">
+					<image  src="http://t9.9026.com/imgs/Kudosbg.png"></image>
+					<view style="margin-left: 24rpx;">
+						<text class="name">端午佳节五香肉粽子,仅限前</text>
+						<text class="tag">礼盒装 2000积分</text>
+					</view>
+				</view>
+				<view class="points">
+					<text class="totalName">共计:</text>
+					<text class="totalContent">2000积分</text>
+				</view>
+				<view class="btn" v-if="false">
+					<text>核销</text>
+				</view>
+			</view>
+		</view>
+		<!-- 已经到底啦 -->
+		<view class="home-bottom">
+			<uni-load-more :status="status" color="#CCCCCC" :content-text="contentText"/>
+		</view>
+	</view>
+</template>
+
+<script>
+	import util from './../../../utils/util.js'
+	export default{
+		data(){
+			return{
+				// 搜索
+				search:'',
+				// 分段器标题
+				items: ['未核销', '已核销', '我的'],
+				isActive: 0,
+				// 组件uni-load-more
+				status: 'noMore',
+				contentText: {
+					contentdown: '查看更多',
+					contentrefresh: '加载中',
+					contentnomore: '——  已经到底啦  ——'
+				},
+				// 订单列表
+				orderList:[],
+			}
+		},
+		onLoad() {
+			this.getMyOrder(1)
+		},
+		methods:{
+			// 获取订单列表
+			getMyOrder(type){
+				this.$api.orders.getOrderList({
+					page:1,
+					confirm_status:type||'',
+					keyword:this.search
+				}).then(res=>{
+					console.log(res,type,"订单列表")
+					if(res.code==0){
+						this.orderList=res.data.data
+					}
+				})
+			},
+			//菜单index切换
+			checked(index) {
+				console.log(index)
+				this.isActive = index
+				this.getMyOrder(index+1)
+			},
+			// 搜索防抖
+			searchText:util.debounce(function(){
+				this.goSearch()
+			},1000),
+			// 搜索
+			goSearch(){
+				this.$api.orders.getOrderList({
+					confirm_status:this.isActive+1,
+					page:1,
+					keyword:this.search
+				}).then(res=>{
+					console.log(res,"搜索活动项目列表")
+					if(res.code==0){
+						this.orderList=res.data.data
+					}
+				})
+			},
+			// 跳转核销订单
+			goOrderVF(){
+				uni.navigateTo({
+					url:'/pages/my/verification/orderVerification'
+				})
+			},
+			// 跳转核销详情
+			goDetail(){
+				uni.navigateTo({
+					url:'/pages/my/verification/verificationDetail'
+				})
+			},
+			// 扫码
+			scanCode(){
+				uni.scanCode({
+					success: function (res) {
+						console.log('条码类型:' + res.scanType);
+						console.log('条码内容:' + res.result);
+					}
+				});
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+	
+	// flex布局居中对齐
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.verification {
+		height: 100%;
+		background: $pageColor;
+	}
+	// ::v-deep .segmented-control__item{
+	// 	justify-content: center !important;
+	// 	margin: 0 30rpx;
+	// }
+		
+	.nav {
+		height: 216rpx;
+		width: 750rpx;
+		background: $bgColor;
+		box-shadow: 0px 4rpx 8rpx 0px rgba(0,0,0,0.04);
+		border-radius: 0px 0px 16rpx 16rpx;
+		.navbox {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 0 30rpx;
+			box-sizing: border-box;
+			margin-bottom: 15rpx;
+			// 搜索
+			.search {
+				height: 124rpx;
+				width: 614rpx;
+				background-color: $bgColor;
+				@include flexlayout;
+			
+				::v-deep .u-input {
+					width: 690rpx !important;
+					height: 68rpx !important;
+					background: #F1F1F1;
+					border-radius: 74rpx;
+				}
+			
+				::v-deep .u-input__content__field-wrapper {
+					padding-left: 36rpx;
+				}
+				::v-deep .u-input__content__field-wrapper__field{
+					color:#999999 !important;
+					font-size: 28rpx !important;
+				}
+			}
+		}
+		.segmented {
+			width: 750rpx;
+			box-sizing: border-box;
+			//菜单切换
+			.tab_nav {
+				width: 750rpx;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				padding:0 30rpx;
+				font-family: PingFang-SC-Heavy, PingFang-SC;
+			}
+		
+			.tab_nav .navTitle {
+				@include flexlayout()
+				width: 128rpx;
+				flex: none;
+				height: 28rpx;
+				font-size: 32rpx;
+				color: #666;
+				position: relative;
+			}
+		
+			.active {
+				color: #D9A94D;
+				font-weight: bold;
+				box-sizing: border-box;
+				&::after {
+					display: inline-block;
+					content: '';
+					width: 48rpx;
+					height: 12rpx;
+					background: linear-gradient(90deg, #F3D69F 0%, #D9A94D 100%);
+					border-radius: 6px;
+					position: absolute;
+					bottom: -28rpx;
+					left: 42rpx;
+				}
+			}
+		}
+	}
+	.card{
+		margin-top: 24rpx;
+		// width: 750rpx;
+		// height: 426rpx;
+		background: $bgColor;
+		border-radius: 16rpx;
+		padding:32rpx 28rpx 24rpx 28rpx;
+		box-sizing: border-box;
+		.toptitle{
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			font-size: 28rpx;
+			font-family: PingFang-SC-Bold, PingFang-SC;
+			font-weight: bold;
+			color: #080F18;
+		}
+		.shopCard{
+			margin-top: 28rpx;
+			width: 694rpx;
+			height: 164rpx;
+			background: #F4F5F6;
+			border-radius: 10rpx;
+			display: flex;
+			align-items: center;
+			
+			image{
+				width: 132rpx;
+				height: 132rpx; 
+				margin-left: 16rpx;
+				display: inline-block;
+				border-radius: 12rpx;
+			}
+			.name{
+				font-size: 28rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #080F18;
+				display: block;
+			}
+			.tag{
+				font-size: 24rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+		.points{
+			display: flex;
+			justify-content: flex-end;
+			align-items: center;
+			margin-top: 30rpx;
+			.totalName{
+				font-size: 22rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #080F18;
+				margin-right: 10rpx;
+			}
+			.totalContent{
+				font-size: 30rpx;
+				font-family: PingFang-SC-Heavy, PingFang-SC;
+				font-weight: 800;
+				color: #080F18;
+			}
+		}
+		.btn{
+			width: 170rpx;
+			height: 60rpx;
+			background: #FFFFFF;
+			border-radius: 30rpx;
+			border: 2rpx solid #D0D0D0;
+			margin-left: 524rpx;
+			margin-top: 15rpx;
+			@include flexlayout()
+			text{
+				font-size: 26rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #080F18;
+			}
+		}
+	}
+	.home-bottom {
+		padding-top: 80rpx;
+		background-color: #f9f9f9;
+	}
+</style>

+ 297 - 0
pages/my/verification/verificationDetail.vue

xqd
@@ -0,0 +1,297 @@
+<template>
+	<view class="verificationDetail">
+		<!-- 核销状态 -->
+		<view class="nav">
+			<text class="verificationDate" >核销时间:2020-10-20</text>
+			<text class="notVerification" v-if="false">未核销</text>
+		</view>
+		
+		<!-- 地址+产品信息 -->
+		<view class="address">
+			<view class="title">
+				<text>地址</text>
+			</view>
+			<view class="addressCard">
+				<image style="width: 694rpx;height: 134rpx;position: absolute;" src="http://t9.9026.com/imgs/addressMap.png"></image>
+				<view class="addressName">
+					<image src="/static/icon/position.png"></image>
+					<text>天堂洲际大饭店</text>
+				</view>
+				<view class="addressDetail">四川省 成都市 高新区 XXX小区 XXX号</view>
+			</view>
+			<view class="title">
+				<text>产品信息</text>
+			</view>
+			<view class="shopCard">
+				<image  src="/static/icon/Kudosbg.png"></image>
+				<view style="margin-left: 24rpx;">
+					<text class="name">端午佳节五香肉粽子,仅限前</text>
+					<text class="tag">礼盒装 2000积分</text>
+				</view>
+			</view>
+			<view class="shopNumber">
+				<text>件数</text>
+				<text>1件</text>
+			</view>
+			<view class="tatol">
+				<text>合计</text>
+				<text>2000积分</text>
+			</view>
+		</view>
+		
+		<!-- 收货信息 -->
+		<view class="message">
+			<view class="messageCard">
+				<view class="title">
+					<text>收货信息</text>
+				</view>
+				<view class="content" >
+					<text>收货人</text>
+					<text>张三</text>
+				</view>
+				<view class="content">
+					<text>联系方式</text>
+					<text>12325646</text>
+				</view>
+			</view>
+			<view class="messageCard">
+				<view class="title">
+					<text>订单信息</text>
+				</view>
+				<view class="content" >
+					<text>订单编号</text>
+					<text>62aae0eb9c6fd622</text>
+				</view>
+				<view class="content">
+					<text>时间</text>
+					<text>2022-08-20 12:32:12</text>
+				</view>
+			</view>
+			<view class="messageCard" >
+				<view class="title">
+					<text>核销信息</text>
+				</view>
+				<view class="content" >
+					<text>核销员</text>
+					<text>张武</text>
+				</view>
+				<view class="content">
+					<text>核销时间</text>
+					<text>2022-08-20 12:32:12</text>
+				</view>
+			</view>
+		</view>
+		
+		<!-- 核销按钮 -->
+		<view class="bottombtn" v-if="false">
+			<view class="btnitem" @click="goOrderVF">
+				<text>去核销</text>
+			</view>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	export default{
+		data(){
+			return{
+				
+			}
+		},
+		methods:{
+			// 跳转核销订单
+			goOrderVF(){
+				uni.navigateTo({
+					url:'/pages/my/verification/orderVerification'
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	$pageColor:#F9F9F9;
+	$bgColor:#FFFFFF;
+	// flex布局居中对齐
+	@mixin flexlayout {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+	}
+	
+	.verificationDetail{
+		height: 100%;
+		background:$pageColor ;
+	}
+	.nav{
+		width: 750rpx;
+		height: 108rpx;
+		background: $bgColor;
+		border-radius: 0px 0px 16rpx 16rpx;
+		padding:32rpx 0 0 28rpx;
+		box-sizing: border-box;
+		.verificationDate{
+			font-size: 40rpx;
+			font-family: PingFang-SC-Medium, PingFang-SC;
+			font-weight: 500;
+			color: #333333;
+		}
+		.notVerification{
+			// 继承.verificationDate类的属性
+			@extend .verificationDate;
+			color: #FF6200;
+		}
+	}
+	.address{
+		margin-top: 24rpx;
+		width: 750rpx;
+		height: 650rpx;
+		background: $bgColor;
+		border-radius: 16rpx;
+		padding:40rpx 30rpx;
+		box-sizing: border-box;
+		.title{
+			margin-bottom: 24rpx;
+			text{
+				font-size: 32rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #080F18;
+			}
+		}
+		.addressCard{
+			width: 694rpx;
+			height: 134rpx;
+			display: flex;
+			margin-bottom: 40rpx;
+			flex-direction: column;
+			justify-content: center;
+			position: relative;
+			background: linear-gradient(270deg, rgba(255,255,255,0.06) 0%, #FFFFFF 100%);
+			.addressName{
+				z-index: 999;
+				display: flex;
+				align-items: center;
+				margin-bottom: 18rpx;
+				image{
+					width: 22rpx;
+					height: 28rpx;
+				}
+				text{
+					margin-left: 8rpx;
+					font-size: 28rpx;
+					font-family: PingFang-SC-Medium, PingFang-SC;
+					font-weight: 500;
+					color: #333333;
+				}
+			}
+			.addressDetail{
+				z-index: 999;
+				font-size: 28rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #080F18;
+			}
+		}
+		.shopCard{
+			margin-top: 28rpx;
+			width: 694rpx;
+			height: 164rpx;
+			background: #F4F5F6;
+			border-radius: 10rpx;
+			display: flex;
+			align-items: center;
+			image{
+				border-radius: 10rpx;
+				width: 132rpx;
+				height: 132rpx; 
+				margin-left: 16rpx;
+				display: inline-block;
+			}
+			.name{
+				font-size: 28rpx;
+				font-family: PingFangSC-Medium, PingFang SC;
+				font-weight: 500;
+				color: #080F18;
+				display: block;
+			}
+			.tag{
+				font-size: 24rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+			}
+		}
+		.shopNumber{
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			margin-top: 25rpx;
+			text{
+				font-size: 26rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #000000;
+			}
+		}
+		.tatol{
+			@extend .shopNumber;
+		}
+	}
+	.message{
+		margin-top: 24rpx;
+		width: 750rpx;
+		height: 690rpx;
+		background: $bgColor;
+		border-radius: 16rpx;
+		padding:40rpx 30rpx;
+		box-sizing: border-box;
+		.messageCard{
+			.title{
+				margin-bottom: 40rpx;
+				width: 120rpx;
+				height: 30rpx;
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: #080F18;
+				line-height: 30rpx;
+			}
+			.content{
+				margin-bottom: 32rpx;
+				width: 600rpx;
+				height: 28rpx;
+				font-size: 28rpx;
+				font-family: PingFang-SC-Medium, PingFang-SC;
+				font-weight: 500;
+				color: #666666;
+				line-height: 28rpx;
+				position: relative;
+				text:last-child{
+					position: absolute;
+					left:176rpx;
+				}
+			}
+		}
+	}
+	.bottombtn{
+		width: 690rpx;
+		height: 92rpx;
+		background: linear-gradient(270deg, #FF6200 0%, #FF9342 100%);	
+		border-radius: 12rpx;
+		margin-left: 30rpx;
+		position: fixed;
+		bottom: 72rpx;
+		@include flexlayout()
+		.btnitem{
+			@include flexlayout()
+			text{
+				font-size: 30rpx;
+				font-family: PingFang-SC-Bold, PingFang-SC;
+				font-weight: bold;
+				color: $bgColor;
+			}
+		}
+	}
+</style>

+ 36 - 0
pages/webview/webview.vue

xqd
@@ -0,0 +1,36 @@
+<template>
+	<view class="webview">
+		<web-view :src='url'></web-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				title:'',
+			}
+		},
+		onLoad(op) {
+			console.log(op)
+			this.url = op.url
+			this.title=op.nav
+			this.getWebviewPage()
+		},
+		methods: {
+			getWebviewPage() {
+				//设置 webview 界面的状态栏的 title
+				uni.setNavigationBarTitle({
+					title: this.title
+				});
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	.webview {
+		width: 100vw;
+		height: 100vh;
+	}
+</style>

+ 16 - 0
setting.js

xqd
@@ -0,0 +1,16 @@
+/**
+ * Created by JianJia.Zhou<jianjia.zhou> on 2022/3/18.
+ */
+const IS_DEV = process.env.NODE_ENV === 'development'
+// const URL = 'https://zhangsiye.9026.com'
+const URL = 'https://t9.9026.com'
+// const URL = 'https://ihg.9026.com'
+
+module.exports = {
+  // 版本
+  VERSION: '0.0.1',
+  // API 接口URL
+  BASE_URL: IS_DEV ? 'https://t9.9026.com/api' : URL + '/api',
+  // API 接口URL
+  IMAGE_URL: IS_DEV ? 'https://t9.9026.com/static/image' : URL + '/static/image'
+}

+ 29 - 0
static/css/common.scss

xqd
@@ -0,0 +1,29 @@
+view,image,text,rich-text,progress,button,input,form,label,textarea{
+  box-sizing: border-box;
+  margin: 0;
+  padding: 0;
+}
+
+page,
+uni-page-body{
+  box-sizing: border-box;
+  height: 100%;
+  background: #fff;
+}
+.hidden{
+  display: flex;
+  visibility: hidden;
+}
+
+.df{
+	display: flex;
+	justify-content: center;
+	align-items: center;
+}
+
+
+
+
+
+
+

+ 266 - 0
static/css/flex.scss

xqd
@@ -0,0 +1,266 @@
+.dir-left-nowrap {
+    /* 主轴 排列方式从左侧开始 不换行*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-direction: row;
+    flex-direction: row;
+    flex-wrap: nowrap;
+}
+
+.dir-left-wrap {
+    /* 主轴 排列方式从左侧开始 换行*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-direction: row;
+    flex-direction: row;
+    flex-wrap: wrap;
+}
+
+.dir-left-wrap-reverse {
+    /* 主轴 排列方式从左侧开始 换行 第一行在下方*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-direction: row;
+    flex-direction: row;
+    flex-wrap: wrap-reverse;
+}
+
+.dir-right-nowrap {
+    /* 主轴 排列方式从 右侧开始 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-direction: row-reverse;
+    flex-direction: row-reverse;
+    flex-wrap: nowrap;
+}
+
+.dir-right-wrap {
+    /* 主轴 排列方式从 右侧开始 换行*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-direction: row;
+    flex-direction: row;
+    flex-wrap: wrap;
+}
+
+.dir-right-wrap-reverse {
+    /* 主轴 排列方式从 右侧开始 换行 第一行在下方*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-direction: row;
+    flex-direction: row;
+    flex-wrap: wrap-reverse;
+}
+
+.dir-top-nowrap {
+    /* 主轴 排列方式从顶部开始 不换行 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-flex-direction: column;
+    flex-direction: column;
+    flex-wrap: nowrap;
+}
+
+.dir-top-wrap {
+    /* 主轴 排列方式从顶部开始  换行*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-flex-direction: column;
+    flex-direction: column;
+    flex-wrap: wrap;
+}
+
+.dir-top-wrap-reverse {
+    /* 主轴 排列方式从顶部开始 不换行换行 第一行在下方*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-flex-direction: column;
+    flex-direction: column;
+    flex-wrap: wrap-reverse;
+}
+
+.dir-bottom-nowrap {
+    /* 主轴 排列方式从底部开始 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-direction: column-reverse;
+    flex-direction: column-reverse;
+    flex-wrap: nowrap;
+}
+
+.dir-bottom-wrap {
+    /* 主轴 排列方式从底部开始 不换行 换行*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-flex-direction: column;
+    flex-direction: column;
+    flex-wrap: wrap;
+}
+
+.dir-bottom-wrap-reverse {
+    /* 主轴 排列方式从底部开始 不换行换行 第一行在下方*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-box-orient: vertical;
+    -webkit-flex-direction: column;
+    flex-direction: column;
+    flex-wrap: wrap-reverse;
+}
+
+.main-left {
+    /* 主轴 左对齐 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-justify-content: flex-start;
+    justify-content: flex-start;
+}
+
+.main-right {
+    /* 主轴 右对齐 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-justify-content: flex-end;
+    justify-content: flex-end;
+}
+
+.main-between {
+    /* 主轴 两端对齐 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-justify-content: space-between;
+    justify-content: space-between;
+}
+
+.main-center {
+    /* 主轴 居中对齐 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-box-pack: center;
+    -webkit-justify-content: center;
+    -ms-flex-pack: center;
+    justify-content: center;
+}
+
+.main-around {
+    /* 主轴 项目位于各行之前、之间、之后都留有空白的容器内*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-justify-content: space-around;
+    justify-content: space-around;
+}
+
+.cross-top {
+    /* 交叉轴 起点对齐 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: flex-start;
+    align-items: flex-start;
+}
+
+.cross-bottom {
+    /* 交叉轴 终点对齐 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-box-align: end;
+    -webkit-align-items: flex-end;
+    -ms-flex-align: end;
+    -ms-grid-row-align: flex-end;
+    align-items: flex-end;
+}
+
+.cross-baseline {
+    /* 交叉轴 第一行文字基线对齐 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: baseline;
+    align-items: baseline;
+}
+
+.cross-center {
+    /* 交叉轴 居中对齐 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+}
+
+.cross-stretch {
+    /* 交叉轴 高度并排铺满 高度不固定*/
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: stretch;
+    align-items: stretch;
+}
+
+.flex-wrap {
+    /* 流模式 第一行在上方 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-wrap: wrap;
+    flex-wrap: wrap;
+}
+
+.flex-wrap-reverse {
+    /* 流模式 第一行在下方 */
+    display: -webkit-box;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-wrap: wrap-reverse;
+    flex-wrap: wrap-reverse;
+}
+
+.box-grow-0 {
+    /* flex 子元素固定宽度*/
+    min-width: 0;
+    -webkit-box-flex: 0;
+    -webkit-flex-grow: 0;
+    -ms-flex-positive: 0;
+    flex-grow: 0;
+    -webkit-flex-shrink: 0;
+    -ms-flex-negative: 0;
+    flex-shrink: 0;
+}
+
+.box-grow-1 {
+    /* flex 子元素等分 */
+    min-width: 0;
+    -webkit-box-flex: 1;
+    -webkit-flex-grow: 1;
+    -ms-flex-positive: 1;
+    flex-grow: 1;
+    -webkit-flex-shrink: 1;
+    -ms-flex-negative: 1;
+    flex-shrink: 1;
+}
+
+.inline-flex {
+    display: -webkit-inline-flex;
+    display: inline-flex;
+}

File diff suppressed because it is too large
+ 3 - 0
static/css/iconfont.css


+ 12 - 0
static/css/mixin.scss

xqd
@@ -0,0 +1,12 @@
+@mixin vipBorder(){
+  border: 4rpx solid;
+  border-image: linear-gradient(to bottom, #F58A82,#733213) 1;
+  background: linear-gradient(#783518,#EC857C);
+}
+
+@mixin background(){
+  background: linear-gradient(#4C453D, #201B15);
+}
+@mixin backgroundCancel(){
+  background: linear-gradient(#f5f7fa 0%, #c3cfe2 100%);
+}

+ 172 - 0
static/css/store-buy.scss

xqd
@@ -0,0 +1,172 @@
+@import "@/static/css/mixin";
+.store-buy {
+  background: url("@/static/image/buy-bg.jpg") no-repeat top;
+  background-size: 100% 40vh;
+  background-repeat: no-repeat;
+  padding-top: 50rpx;
+  .card{
+    width: 720rpx;
+    margin: 0 auto;
+  }
+  .card-info{
+    background: url("/static/image/coupon_wait_use.png") no-repeat top right;
+    width: 700rpx;
+    flex-shrink: 0;
+    height: 190rpx;
+    background-size: 100% 100%;
+    .left-box{
+      flex: 1;
+      padding: 0 20rpx;
+      .price{
+        white-space: nowrap;
+        color: #888d93;
+        font-size: 28rpx;
+        .num{
+          color: #E8B388;
+          font-size: 60rpx;
+        }
+      }
+      .info-box{
+        margin-left: 20rpx;
+        .tags{
+          margin-top: 10rpx;
+          .tag{
+            background: #FDE7DA;
+            color: #424751;
+            padding: 3rpx 8rpx;
+            margin-right: 8rpx;
+            font-size: 22rpx;
+            border-radius: 6rpx;
+          }
+        }
+      }
+    }
+    .right-box{
+      width: 165rpx;
+    }
+  }
+  .price-tags{
+    margin-bottom: 50rpx;
+    margin-top: 20rpx;
+    padding: 0 20rpx;
+    .price-tag{
+      flex: 1;
+      color: #fff;
+      font-size: 26rpx;
+      padding: 4rpx 6rpx;
+      white-space: nowrap;
+      &.normal-price{
+        background: linear-gradient(#858A90,#4C525E);
+      }
+      &.sale-price{
+        background: linear-gradient(#504740,#1F1A14);
+        margin: 0 50rpx;
+      }
+      &.vip-price{
+        @include vipBorder;
+        border-width: 1rpx;
+      }
+    }
+  }
+  .store-info{
+    background: #fff;
+    border-radius: 10rpx;
+    padding: 10rpx 30rpx;
+  }
+  .desc{
+    .content{
+      color: $text-deep-grey-color;
+    }
+  }
+  .buy-btn{
+    @include background;
+    color: #fff;
+    width: 90vw;
+    margin: 80rpx auto 0rpx;
+    padding: 20rpx 0;
+    border-radius: 10rpx;
+    bottom: 0;
+    text-align: center;
+  }
+  .buy-popup{
+    padding: 30rpx 0;
+    font-size: 26rpx;
+    .goods-box{
+      padding: 0 30rpx;
+      .cover-img{
+        width: 240rpx;
+        height: 200rpx;
+        >image{
+          width: 100%;
+          height: 100%;
+        }
+      }
+      .goods-info{
+        background: #FEF9F6;
+        flex: 1;
+        padding: 20rpx;
+      }
+    }
+    .spec-box{
+      padding: 0 30rpx;
+      font-size: 26rpx;
+      .name{
+        color: $text-black-color;
+      }
+    }
+    .spec-detail{
+      box-shadow: 0 0 10rpx rgba(0,0,0,.15);
+      border-radius: 12rpx;
+      padding: 32rpx 16rpx;
+      .spec-name{
+        color: $text-black-color;
+        text-align: center;
+        padding-bottom: 22rpx;
+      }
+      .detail-box{
+        height: 150rpx;
+        .detail-item{
+          padding: 12rpx 0;
+          text-align: center;
+          color: $text-grey-color;
+          >text{
+            flex: 1;
+          }
+          .name{
+            flex: 2;
+          }
+        }
+      }
+    }
+    .price-box{
+      padding: 16rpx 32rpx;
+      position: relative;
+      margin-bottom: 16rpx;
+      margin-top: 16rpx;
+      &:after{
+        content: "";
+        position: absolute;
+        height: 1rpx;
+        width: 95%;
+        background: $grey-color;
+        bottom: 0;
+        left: 50%;
+        transform: translateX(-50%);
+      }
+      .normal-price{
+        flex: 1;
+        text{
+          margin-right: 16rpx;
+        }
+      }
+      .goods-num{
+        display: flex;
+        flex: 1;
+        justify-content: flex-end;
+      }
+    }
+    .buy-btn{
+      margin-top: 30rpx;
+    }
+  }
+}

+ 8 - 0
static/css/variable.scss

xqd
@@ -0,0 +1,8 @@
+$bg-color: #151729;
+
+$primary-color: #6EEBE8;
+$dark-color: #48979C;
+$default-color: #FFFFFF;
+$info-color: #6F717F;
+
+$pink-color: #FF74B9;

BIN
static/icon/Kudos(1).png


BIN
static/icon/Kudos.png


BIN
static/icon/Receipt.png


BIN
static/icon/add01.png


BIN
static/icon/address01.png


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