lhl 4 rokov pred
rodič
commit
a08febf4e7
100 zmenil súbory, kde vykonal 10357 pridanie a 1303 odobranie
  1. 2 1
      App.vue
  2. 64 0
      api/package.js
  3. 8 0
      api/user.js
  4. 9 2
      main.js
  5. 2 5
      manifest.json
  6. 136 42
      pages.json
  7. 483 0
      pages/appointment/appointment.vue
  8. 11 4
      pages/category/category.vue
  9. 694 151
      pages/index/index.vue
  10. 2 2
      pages/product/common/productBottom.vue
  11. 6 6
      pages/product/product.vue
  12. 5 5
      pages/public/forget.vue
  13. 15 42
      pages/public/login.vue
  14. 39 177
      pages/public/register.vue
  15. 345 0
      pages/purchase/purchase.vue
  16. 102 0
      pages/purchase/upload.vue
  17. 458 0
      pages/sellout/sellout.vue
  18. 1 1
      pages/set/password.vue
  19. 361 0
      pages/set/userdata.vue
  20. 3 3
      pages/set/userinfo.vue
  21. 4 4
      pages/user/extension.vue
  22. 4 4
      pages/user/integral.vue
  23. 185 17
      pages/user/user.vue
  24. 249 0
      pages/vip/contract.vue
  25. 250 0
      pages/vip/extension.vue
  26. 431 0
      pages/vip/fwbDetail.vue
  27. 377 0
      pages/vip/mytz.vue
  28. 82 0
      pages/vip/success.vue
  29. 89 0
      pages/vip/tzzz.vue
  30. 399 0
      pages/vip/vip.vue
  31. BIN
      static/icon/c3.png
  32. BIN
      static/icon/c5.png
  33. BIN
      static/icon/c7.png
  34. BIN
      static/icon/c8.png
  35. BIN
      static/icon/close.png
  36. BIN
      static/icon/code.png
  37. BIN
      static/icon/g1.png
  38. BIN
      static/icon/g2.png
  39. BIN
      static/icon/g3.png
  40. BIN
      static/icon/g4.png
  41. BIN
      static/icon/g5.png
  42. BIN
      static/icon/g6.png
  43. BIN
      static/icon/g7.png
  44. BIN
      static/icon/g8.png
  45. BIN
      static/icon/kt1.png
  46. BIN
      static/icon/kt2.png
  47. BIN
      static/icon/kt3.png
  48. BIN
      static/icon/kt4.png
  49. BIN
      static/icon/kt5.png
  50. BIN
      static/icon/kt6.png
  51. BIN
      static/icon/kt7.png
  52. BIN
      static/icon/mrlogo.png
  53. BIN
      static/icon/myyy.png
  54. BIN
      static/icon/phone.png
  55. BIN
      static/icon/pswd.png
  56. BIN
      static/icon/tg.png
  57. BIN
      static/img/fwb.png
  58. BIN
      static/img/hybg.png
  59. BIN
      static/img/img17.png
  60. BIN
      static/img/jfbg.png
  61. BIN
      static/img/ktbg.png
  62. BIN
      static/img/success.png
  63. BIN
      static/img/teambg.png
  64. BIN
      static/img/tgbg.png
  65. BIN
      static/img/tzbg.png
  66. BIN
      static/img/upimg.png
  67. BIN
      static/tabBar/tab-cart-current.png
  68. BIN
      static/tabBar/tab-cart.png
  69. BIN
      static/tabBar/tab-cate-current.png
  70. BIN
      static/tabBar/tab-cate.png
  71. BIN
      static/tabBar/tab-home-current.png
  72. BIN
      static/tabBar/tab-home.png
  73. BIN
      static/tabBar/tab-my-current.png
  74. BIN
      static/tabBar/tab-my.png
  75. 1 1
      store/index.js
  76. 2 1
      uni.scss
  77. 25 25
      unpackage/dist/dev/app-plus/__uniappview.html
  78. 0 0
      unpackage/dist/dev/app-plus/app-config-service.js
  79. 3 3
      unpackage/dist/dev/app-plus/app-service.js
  80. 206 254
      unpackage/dist/dev/app-plus/app-view.js
  81. 0 0
      unpackage/dist/dev/app-plus/manifest.json
  82. 553 553
      unpackage/dist/dev/app-plus/static/css/cmy.css
  83. 0 0
      unpackage/dist/dev/app-plus/view.css
  84. 0 0
      unpackage/dist/dev/app-plus/view.umd.min.js
  85. 53 0
      utils/tabbar.js
  86. 21 0
      uview-ui/LICENSE
  87. 106 0
      uview-ui/README.md
  88. 190 0
      uview-ui/components/u-action-sheet/u-action-sheet.vue
  89. 256 0
      uview-ui/components/u-alert-tips/u-alert-tips.vue
  90. 290 0
      uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue
  91. 1265 0
      uview-ui/components/u-avatar-cropper/weCropper.js
  92. 24 0
      uview-ui/components/u-avatar/u-avatar.vue
  93. 153 0
      uview-ui/components/u-back-top/u-back-top.vue
  94. 216 0
      uview-ui/components/u-badge/u-badge.vue
  95. 596 0
      uview-ui/components/u-button/u-button.vue
  96. 639 0
      uview-ui/components/u-calendar/u-calendar.vue
  97. 257 0
      uview-ui/components/u-car-keyboard/u-car-keyboard.vue
  98. 299 0
      uview-ui/components/u-card/u-card.vue
  99. 70 0
      uview-ui/components/u-cell-group/u-cell-group.vue
  100. 316 0
      uview-ui/components/u-cell-item/u-cell-item.vue

+ 2 - 1
App.vue

@@ -75,7 +75,8 @@ export default {
 };
 </script>
 
-<style lang="scss">
+<style lang="scss">
+@import "uview-ui/index.scss";
 /*全局公共样式和字体图标*/
 @import '/static/css/cmy.css';
 view,

+ 64 - 0
api/package.js

@@ -0,0 +1,64 @@
+import request from '@/utils/request'
+
+//获取包列表
+export function getPackageList(data) {
+	return request({
+		url: '/api/package/lst',
+		method: 'get',
+		data
+	});
+}
+
+//预约包
+export function packageReserve(data) {
+	return request({
+		url: '/api/package/reserve',
+		method: 'post',
+		data
+	});
+}
+
+//兑换包
+export function packageExchange(data) {
+	return request({
+		url: '/api/package/exchange',
+		method: 'post',
+		data
+	});
+}
+
+//我的预约
+export function packageMyReserveList(data) {
+	return request({
+		url: '/api/package/myList',
+		method: 'post',
+		data
+	});
+}
+
+//我的卖出
+export function packageOrder(data) {
+	return request({
+		url: '/api/package/order',
+		method: 'post',
+		data
+	});
+}
+
+//上传凭证
+export function evaluationUpload(data) {
+	return request({
+		url: '/api/package/evaluation',
+		method: 'post',
+		data
+	});
+}
+
+//我的审核
+export function packageAudit(data) {
+	return request({
+		url: '/api/package/audit',
+		method: 'post',
+		data
+	});
+}

+ 8 - 0
api/user.js

@@ -210,3 +210,11 @@ export function addJiedian(data){
 		data
 	})
 }
+//开通会员
+export function becomeVip(data) {
+	return request({
+		url: '/api/level/recharge',
+		method: 'post',
+		data
+	});
+}

+ 9 - 2
main.js

@@ -1,6 +1,9 @@
 import Vue from 'vue'
 import store from './store'
-import App from './App'
+import App from './App'
+import uView from "uview-ui";
+
+
 /**
  *  所有测试用数据均存放于根目录json.js
  *  
@@ -36,7 +39,11 @@ Vue.prototype.$fire = new Vue();
 Vue.prototype.$store = store;
 Vue.prototype.$api = {msg, prePage};
 
-App.mpType = 'app'
+App.mpType = 'app'
+
+
+
+Vue.use(uView);
 
 const app = new Vue({
     ...App

+ 2 - 5
manifest.json

@@ -14,9 +14,7 @@
             "autoclose" : true,
             "delay" : 0
         },
-        "modules" : {
-            "Payment" : {}
-        },
+        "modules" : {},
         /* 模块配置 */
         "distribute" : {
             /* 应用发布信息 */
@@ -24,7 +22,6 @@
                 /* android打包配置 */
                 "permissions" : [
                     "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
-                    "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
                     "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
                     "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>"
                 ],
@@ -143,7 +140,7 @@
         "devServer" : {
             "proxy" : {
                 "/api" : {
-                    "target" : "http://shop.zhengyjk1994.com", //请求的目标域名
+                    "target" : "http://fb.frp.liuniu946.com", //请求的目标域名
                     "changeOrigin" : true,
                     // "secure": false,
                     "pathRewrite" : {}

+ 136 - 42
pages.json

@@ -1,4 +1,7 @@
 {
+	"easycom": {
+			"^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
+		},
 	"pages": [{
 			"path": "pages/index/index",
 			"style": {
@@ -212,33 +215,11 @@
 		{
 			"path": "pages/user/extension",
 			"style": {
-				// "navigationBarTextStyle": "black",
-				// "navigationBarBackgroundColor": "transparent",
-				// "app-plus": {
-				// 	"titleNView": {
-				// 		"type": "float",
-				// 		"titleText": "我的推广"
-				// 	}
-				// }
-				"navigationBarTitleText": "我的推广",
-				"navigationBarBackgroundColor":"#D7EEB6",
-				"navigationBarTextStyle":"black"
+				"navigationBarTitleText": "我的团队",
+				"navigationBarBackgroundColor": "#ff4c4c",
+				"navigationBarTextStyle": "white"
 			}
 		},
-		// {
-		// 	"path": "pages/user/applyMember",
-		// 	"style": {
-		// 		"navigationStyle": "custom",
-		// 		"navigationBarTitleText": "申请会员"
-		// 	}
-		// },
-		// {
-		// 	"path": "pages/user/minMember",
-		// 	"style": {
-		// 		"navigationStyle": "custom",
-		// 		"navigationBarTitleText": "我的会员"
-		// 	}
-		// },
 		{
 			"path": "pages/order/order",
 			"style": {
@@ -396,8 +377,8 @@
 			"path": "pages/user/integral",
 			"style": {
 				"navigationBarTitleText": "我的积分",
-				"navigationBarBackgroundColor":"#D7EEB6",
-				"navigationBarTextStyle":"black"
+				"navigationBarBackgroundColor":"#ff4c4c",
+				"navigationBarTextStyle":"white"
 			}
 		},
 		{
@@ -435,7 +416,113 @@
                 "enablePullDownRefresh": false
             }
             
-        }
+        },
+		{
+			"path" : "pages/purchase/purchase",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "买入",
+			    "enablePullDownRefresh": false
+			}
+		},
+		{
+			"path" : "pages/purchase/upload",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "上传凭证",
+			    "enablePullDownRefresh": false
+			}
+		},
+		{
+			"path" : "pages/sellout/sellout",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "卖出",
+			    "enablePullDownRefresh": false
+			}
+		},
+		{
+			"path" : "pages/appointment/appointment",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "我的预约",
+			    "enablePullDownRefresh": false
+			}
+		},
+		{
+			"path" : "pages/vip/vip",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "开通会员",
+			    "enablePullDownRefresh": false
+			}
+		},
+		{
+			"path" : "pages/vip/fwbDetail",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "服务包专区",
+			    "enablePullDownRefresh": false
+			}
+		},
+		{
+			"path" : "pages/vip/tzzz",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "通证转账",
+			    "enablePullDownRefresh": false
+			}
+		},
+		{
+			"path" : "pages/vip/mytz",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "我的通证",
+			    "enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#ff5246",
+				"navigationBarTextStyle": "white"
+			}
+		},
+		{
+			"path" : "pages/vip/contract",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "合约收益",
+			    "enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#ff5246",
+				"navigationBarTextStyle": "white"
+			}
+		},
+		{
+			"path" : "pages/vip/extension",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "推广收益",
+			    "enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#ff5246",
+				"navigationBarTextStyle": "white"
+			}
+		},
+		{
+			"path" : "pages/vip/success",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "开通成功",
+			    "enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#fff",
+				"navigationBarTextStyle": "black"
+			}
+		},
+		{
+			"path" : "pages/set/userdata",
+			"style" :                                                                                    
+			{
+			    "navigationBarTitleText": "会员资料",
+			    "enablePullDownRefresh": false,
+				"navigationBarBackgroundColor": "#fff",
+				"navigationBarTextStyle": "black"
+			}
+		}
     ],
 	"globalStyle": {
 		"navigationBarTextStyle": "black",
@@ -445,33 +532,40 @@
 	},
 	"tabBar": {
 		"color": "#C0C4CC",
-		"selectedColor": "#3F7C1F",
+		"selectedColor": "#ff4c4c",
 		"borderStyle": "black",
 		"backgroundColor": "#ffffff",
-		"list": [{
+		"list": [
+			{
 				"pagePath": "pages/index/index",
 				"iconPath": "static/tabBar/tab-home.png",
 				"selectedIconPath": "static/tabBar/tab-home-current.png",
 				"text": "首页"
 			},
+			// {
+			// 	"pagePath": "pages/purchase/purchase",
+			// 	"iconPath": "static/tabBar/tab-home.png",
+			// 	"selectedIconPath": "static/tabBar/tab-home-current.png",
+			// 	"text": "买入"
+			// },
+			// {
+			// 	"pagePath": "pages/sellout/sellout",
+			// 	"iconPath": "static/tabBar/tab-home.png",
+			// 	"selectedIconPath": "static/tabBar/tab-home-current.png",
+			// 	"text": "卖出"
+			// },
+			// {
+			// 	"pagePath": "pages/appointment/appointment",
+			// 	"iconPath": "static/tabBar/tab-cate.png",
+			// 	"selectedIconPath": "static/tabBar/tab-cate-current.png",
+			// 	"text": "我的预约"
+			// },
 			{
 				"pagePath": "pages/category/category",
 				"iconPath": "static/tabBar/tab-cate.png",
 				"selectedIconPath": "static/tabBar/tab-cate-current.png",
 				"text": "分类"
 			},
-			{
-				"pagePath": "pages/story/story",
-				"iconPath": "static/tabBar/tab-store.png",
-				"selectedIconPath": "static/tabBar/tab-store-current.png",
-				"text": "品牌故事"
-			},
-			{
-				"pagePath": "pages/cart/cart",
-				"iconPath": "static/tabBar/tab-cart.png",
-				"selectedIconPath": "static/tabBar/tab-cart-current.png",
-				"text": "购物车"
-			},
 			{
 				"pagePath": "pages/user/user",
 				"iconPath": "static/tabBar/tab-my.png",

+ 483 - 0
pages/appointment/appointment.vue

@@ -0,0 +1,483 @@
+<template>
+	<view class="">
+		<!-- <view class="">
+			我的预约
+		</view> -->
+
+		<view class="navbar flex">
+			<view class="nav-item" v-for="(navitem,index) in navList" :class="{'action': index == currentIndex}"
+				@click="navClick(index)">
+				{{navitem.tit}}
+			</view>
+		</view>
+		<swiper :interval="3000" :duration="1000" :style="{'height': height}" class="swiper-box" @scrolltolower="loadData()">
+			<swiper-item>
+				<scroll-view scroll-y="true" :style="{'height': height}">
+					<empty v-if="navList[currentIndex].loaded === true && navList[currentIndex].list.length === 0">
+					</empty>
+					<view class="buy-item" v-for="item in navList[currentIndex].list">
+						<view class="item-top">
+							<view class="top-left">
+								<image src="../../static/icon/mrlogo.png" mode=""></image><text
+									class="top-name clamp">{{item.order_id}}</text>
+							</view>
+							<view class="top-right">
+								{{item.status | status}}
+							</view>
+						</view>
+						<view class="item-info">
+							<view class="info-data">
+								<view class="info-tit">收益:</view>
+								<view class="info-val">{{item.day}}天/{{item.proportion}}%</view>
+							</view>
+							<!-- <view class="info-data">
+								<view class="info-tit">开始时间:</view>
+								<view class="info-val">10:20</view>
+							</view> -->
+							<view class="info-data">
+								<view class="info-tit">可获通证:</view>
+								<view class="info-val">{{item.pass}}%</view>
+							</view>
+							<!-- <view class="info-data">
+								<view class="info-tit">终止释放时间:</view>
+								<view class="info-val">10:20</view>
+							</view> -->
+							<view class="info-data" v-if="item.status == 1 || item.status == -1">
+								<view class="info-tit">是否中奖:</view>
+								<view class="info-val">{{item.status == 1?'中奖':item.status == -1 ? '未中奖': ''}}</view>
+							</view>
+							<view class="info-data">
+								<view class="info-tit">价值:</view>
+								<view class="info-val">{{item.price}}</view>
+							</view>
+							<view class="btn-wrap flex" v-if="item.status == 1 || item.status == 2">
+								<!-- <view class="btn" @click="open(item.id)"> -->
+								<view class="btn" @click="navto('/pages/purchase/upload?id=' + item.id + '&paytype=' + JSON.stringify(item.touser) )">
+									提交凭证
+								</view>
+							</view>
+						</view>
+					</view>
+					<uni-load-more :status="navList[currentIndex].loadingType"></uni-load-more>
+				</scroll-view>
+			</swiper-item>
+		</swiper>
+		<uni-popup ref="popup1" type="center" :maskClick="false">
+			<view class="upload-wrap">
+				<view class="tit">
+					上传支付凭证
+				</view>
+				<view class="up-wrap" @click="imgsub('upimg')">
+					<image :src="upimg" mode="" v-if="upimg"></image>
+					<image v-else src="../../static/img/upimg.png" mode=""></image>
+				</view>
+				<view class="btn-wrap">
+					<view class="btn qx" @click="qx">
+						取消
+					</view>
+					<view class="btn" @click="evaluationUpload">提交</view>
+				</view>
+				
+			</view>
+		</uni-popup>
+		<!-- <u-tabbar v-model="current" :list="tabbar" active-color="#FF0000" inactive-color="#f19c99"></u-tabbar> -->
+	</view>
+</template>
+
+<script>
+	import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
+	import empty from '@/components/empty';
+
+	import {
+		packageMyReserveList, evaluationUpload
+	} from '@/api/package.js'
+
+	import {
+		tabbar,
+		tabbar1
+	} from "@/utils/tabbar.js";
+	import { upload } from '@/api/user.js';
+	export default {
+		components: {
+			uniLoadMore,
+			empty
+		},
+		filters: {
+			status(val) {
+				let str = ''
+				// 状态:0-预约,1-待支付,2-待审核,3-释放中,4-释放完成,5-重新发放,6-完成,-1-没抢到,-2-审核无效
+				switch (val) {
+					case 0:
+						str = '预约'
+						break;
+					case 1:
+						str = '待支付'
+						break;
+					case 2:
+						str = '待审核'
+						break;
+					case 3:
+						str = '释放中'
+						break;
+					case 4:
+						str = '释放完成'
+						break;
+					case 5:
+						str = '重新发放'
+						break;
+					case 6:
+						str = '完成'
+						break;
+					case -1:
+						str = '没抢到'
+						break;
+					case -2:
+						str = '审核无效'
+						break;
+					default:
+						str = ''
+				}
+
+
+				return str
+			}
+		},
+		data() {
+			return {
+				height: '',
+				currentIndex: 0,
+				navList: [{
+						status: 'today',
+						tit: '当天预约',
+						list: [],
+						page: 1,
+						limit: 10,
+						loadingType: 'more',
+						loaded: false,
+					},
+					{
+						status: 1,
+						tit: '待支付',
+						list: [],
+						page: 1,
+						limit: 10,
+						loadingType: 'more',
+						loaded: false,
+					},
+					{
+						status: '',
+						tit: '所有预约',
+						list: [],
+						page: 1,
+						limit: 10,
+						loadingType: 'more',
+						loaded: false,
+					}
+				],
+				tabbar: tabbar,
+				tabbar1: tabbar1,
+				current: 3,
+				choose_order: '',
+				upimg: '',
+			}
+		},
+		onLoad() {
+			console.log('我的预约')
+			this.loadData()
+		},
+		onReady(res) {
+			var obj = this;
+			uni.getSystemInfo({
+				success: resu => {
+					const query = uni.createSelectorQuery();
+					query.select('.swiper-box').boundingClientRect();
+					query.exec(function(res) {
+						console.log(res, 'ddddddddddddd');
+						obj.height = resu.windowHeight - res[0].top + 'px';
+						console.log('打印页面的剩余高度', obj.height);
+					});
+				},
+				fail: res => {}
+			});
+		},
+		methods: {
+			navto(url) {
+				uni.navigateTo({
+					url: url
+				})
+			},
+			qx() {
+				this.upimg = ''
+				this.choose_order = ''
+				this.$refs.popup1.close()
+			},
+			open(orderId) {
+				this.choose_order = orderId
+				this.$refs.popup1.open()
+				
+			},
+			imgsub(text) {
+				console.log('imgsub');
+				upload({
+					filename: ''
+				}).then(data => {
+					// this.upimg = data[0].url;
+					this.$set(this,text,data[0].url)
+				});
+			},
+			//提交审核
+			evaluationUpload() {
+				let obj = this
+				evaluationUpload({
+					pay_evaluation: obj.upimg,
+					id: obj.choose_order
+				}).then( res => {
+					this.qx()
+					uni.showToast({
+						title:'提交成功',
+						duration:2000
+					});
+					this.page = 1
+					this.list = []
+					this.loadingType = 'more'
+					this.loadData()
+					console.log(res,'上传凭证+++++')
+				})
+			},
+			navClick(index) {
+				this.currentIndex = index
+				this.loadData('swiper')
+			},
+			loadData(text) {
+				let obj = this
+				let index = obj.currentIndex
+				let navItem = obj.navList[index]
+
+				if (text == 'swiper' && navItem.loaded) {
+					return
+				}
+				if (navItem.loadingType == 'loading' || navItem.loadingType == 'noMore') {
+					return
+				}
+				navItem.loadingType = 'loading'
+				if(navItem.status == 1) {
+					packageMyReserveList({
+						page: navItem.page,
+						limit: navItem.limit,
+						status: 1
+					}).then(({
+						data
+					}) => {
+						// console.log(res)
+						navItem.list = navItem.list.concat(data.data)
+						this.page++
+						if (data.data.length == navItem.limit) {
+							navItem.loadingType = 'more'
+						} else {
+							navItem.loadingType = 'noMore'
+						}
+						obj.$set(navItem, 'loaded', true)
+					})
+				}else {
+					packageMyReserveList({
+						page: navItem.page,
+						limit: navItem.limit,
+						data: navItem.status
+					}).then(({
+						data
+					}) => {
+						// console.log(res)
+						navItem.list = navItem.list.concat(data.data)
+						this.page++
+						if (data.data.length == navItem.limit) {
+							navItem.loadingType = 'more'
+						} else {
+							navItem.loadingType = 'noMore'
+						}
+						obj.$set(navItem, 'loaded', true)
+					})
+				}
+				
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.navbar {
+		background-color: #fff;
+		height: 80rpx;
+
+		.nav-item {
+			width: 50%;
+			text-align: center;
+			font-size: 30rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: #333333;
+		}
+
+		.action {
+			font-weight: bold;
+			position: relative;
+
+			&::after {
+				content: '';
+				width: 84rpx;
+				height: 4rpx;
+				background: #FF4C4C;
+				border-radius: 2px;
+				position: absolute;
+				bottom: -20rpx;
+				left: 0;
+				right: 0;
+				margin: auto;
+			}
+		}
+	}
+
+	.swiper-box {
+		// background-color: red;
+		padding-top: 20rpx;
+		// padding-bottom: 20rpx;
+	}
+
+	.buy-item {
+		width: 690rpx;
+		// height: 235rpx;
+		margin: 0 auto 20rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 0px 17rpx 0px rgba(0, 0, 0, 0.05);
+		border-radius: 20rpx;
+		padding: 26rpx 30rpx;
+
+		.item-top {
+			display: flex;
+			justify-content: space-between;
+			height: 50rpx;
+
+			.top-left {
+				font-size: 34rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #0F253A;
+				line-height: 50rpx;
+				display: flex;
+				align-items: center;
+
+				image {
+					width: 48rpx;
+					height: 46rpx;
+				}
+
+				.top-name {
+					width: 450rpx;
+					padding-left: 11rpx;
+				}
+			}
+
+			.top-right {
+				line-height: 50rpx;
+				width: 100rpx;
+				text-align: right;
+				font-size: 26rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #6D7C88;
+			}
+		}
+
+		.item-info {
+			width: 100%;
+			margin-top: 28rpx;
+			line-height: 50rpx;
+			font-size: 26rpx;
+			font-family: PingFang SC;
+			display: flex;
+			flex-wrap: wrap;
+
+			.info-data {
+				width: 50%;
+				display: flex;
+
+				.info-tit {
+
+					font-weight: 500;
+					color: #6D7C88;
+				}
+
+				.info-val {
+					color: #0F253A;
+					font-weight: bold;
+				}
+			}
+			.btn-wrap {
+				padding-top: 20rpx;
+				width: 100%;
+				justify-content: flex-end;
+				.btn {
+					text-align: center;
+					width: 144rpx;
+					line-height: 50rpx;
+					background: #FFFFFF;
+					border: 2rpx solid #FF4C4C;
+					border-radius: 25rpx;
+					font-size: 26rpx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #FF4C4C;
+				}
+			}
+
+		}
+	}
+	.upload-wrap {
+		width: 500rpx;
+		height: 500rpx;
+		background-color: #fff;
+		border-radius: 20rpx;
+		.tit {
+			padding: 30rpx 25rpx;
+			text-align: center;
+			font-size: 32rpx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			color: #101010;
+		}
+		
+		.up-wrap {
+			margin:auto;
+			width: 225rpx;
+			height: 225rpx;
+			background: #FFFFFF;
+			border-radius: 10rpx;
+		
+			image {
+				width: 225rpx;
+				height: 225rpx;
+				border-radius: 10rpx;
+			}
+		}
+		.btn-wrap {
+			display: flex;
+			.btn {
+				margin: 50rpx auto 0;
+				width: 150rpx;
+				line-height: 84rpx;
+				background: linear-gradient(30deg, #FF4C4C, #FE6238);
+				border-radius: 10rpx;
+				font-size: 32rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #FFFFFF;
+				text-align: center;
+			}
+			.qx {
+				background: #fff;
+				border: 1px solid #999;
+				color: #999;
+			}
+		}
+		
+	}
+</style>

+ 11 - 4
pages/category/category.vue

@@ -13,19 +13,26 @@
 					</view>
 				</view>
 			</view>
-		</scroll-view>
+		</scroll-view>
+		<!-- <u-tabbar v-model="current" :list="tabbar1" active-color="#FF0000" inactive-color="#f19c99"></u-tabbar> -->
 	</view>
 </template>
 
 <script>
-import { getCategoryList } from '@/api/product.js';
+import { getCategoryList } from '@/api/product.js';
+import {
+		tabbar,tabbar1
+	} from "@/utils/tabbar.js";
 export default {
 	data() {
-		return {
+		return {
+			tabbar: tabbar,
+			tabbar1: tabbar1,
 			sizeCalcState: false,
 			tabScrollTop: 0,
 			currentId: 9,
-			flist: [],
+			flist: [],
+			current: 4
 		};
 	},
 	onLoad() {

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 694 - 151
pages/index/index.vue


+ 2 - 2
pages/product/common/productBottom.vue

@@ -169,7 +169,7 @@ export default {
 		border: none;
 		width: 375rpx;
 		height: 97rpx;
-		background: #6EAB4E;
+		background: #ff4c4c;
 		font-size: 36rpx;
 		font-weight: 500;
 		color: #fff;
@@ -179,7 +179,7 @@ export default {
 	.quck {
 		width: 699rpx;
 		height: 90rpx;
-		background: #6EAB4E;
+		background: #ff4c4c;
 		border-radius: 45rpx;
 		margin: auto;
 	}

+ 6 - 6
pages/product/product.vue

@@ -4,14 +4,14 @@
 		<top-swiper :imgList="imgList"></top-swiper>
 		<!-- 标题 -->
 		<view class="introduce-section" v-if="goodsType == 0">
-			<button class="shareDate" style="border: none;" @click="callf()">
+			<!-- <button class="shareDate" style="border: none;" @click="callf()">
 				<image class="share-img" src="../../static/icon/share.png"></image>
-			</button>
+			</button> -->
 			<view class="price-box">
-				<text class="price-tip">¥</text>
+				<text class="price-tip">积分</text>
 				<view class="price">
 					{{ goodsObjact.price }}
-					<text class="m-price">¥{{ goodsObjact.ot_price }}</text>
+					<!-- <text class="m-price">¥{{ goodsObjact.ot_price }}</text> -->
 				</view>
 			</view>
 			<text class="title clamp2" v-if="goodsObjact.title">{{ goodsObjact.title }}</text>
@@ -63,7 +63,7 @@
 					<view class="right">
 						<text class="name clamp">{{ goodsObjact.store_name }}</text>
 						<view class="price">
-							<text>¥</text>
+							<text>积分</text>
 							{{ actionPrice * goodsNumber }}
 						</view>
 						<image src="../../static/icon/del.png" mode="" class="right-img" @click="closes()"></image>
@@ -674,7 +674,7 @@
 				height: 66rpx;
 				line-height: 66rpx;
 				border-radius: 100rpx;
-				background: #6EAB4E;
+				background:#ff4c4c;
 				font-size: $font-base + 2rpx;
 				color: #fff;
 				margin: 30rpx auto 20rpx;

+ 5 - 5
pages/public/forget.vue

@@ -6,11 +6,11 @@
 		<view class="loginTitle"><text>手机号登录</text></view>
 		<view class="login_text">
 			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/img03.png"></image></view>
+				<view class="login_img"><image src="../../static/icon/phone.png"></image></view>
 				<view class="login_name"><input class="uni-input" v-model="phone" focus placeholder="请输入手机号" /></view>
 			</view>
 			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/img06.png"></image></view>
+				<view class="login_img"><image src="../../static/icon/code.png"></image></view>
 				<view class="login_name flex">
 					<input class="uni-input width" v-model="code" focus placeholder="请输入验证码" />
 					<view class="code" @click="verification">{{ countDown == 0 ? '验证码' : countDown }}</view>
@@ -131,7 +131,7 @@ page {
 .container_text {
 	width: 100%;
 	height: 500rpx;
-	background-color: #abd56f;
+	background-color: #ff4c4c;
 	top: 0rpx;
 	.banner-img {
 		width: 100%;
@@ -164,7 +164,7 @@ page {
 				width: 325rpx !important;
 			}
 			.code {
-				color: #abd56f;
+				color: #ff4c4c;
 				font-size: 23rpx;
 				border-left: 1px solid #eeeeee;
 				width: 150rpx;
@@ -175,7 +175,7 @@ page {
 	}
 	.uni-button-green {
 		color: #ffffff;
-		background-color: #abd56f;
+		background-color: #ff4c4c;
 		margin: 40rpx 10rpx;
 		border-radius: 50rpx;
 	}

+ 15 - 42
pages/public/login.vue

@@ -1,58 +1,28 @@
 <template>
 	<view class="container">
 		<view class="container_text">
-
-			<image class="banner-img" src="/static/img/login.png" mode="scaleToFill">
-
-			<image class="banner-img" src="/static/img/logo.png" mode="scaleToFill">
+			<!-- <image class="banner-img" src="/static/img/login.png" mode="scaleToFill">
+			<image class="banner-img" src="/static/img/logo.png" mode="scaleToFill"> -->
 
 		</image>
 		</view>
 		<view class="loginTitle"><text>登录</text></view>
 		<view class="login_text">
 			<view class="login_input flex">
-				<view class="login_img"><image src="/static/img/login01.png"></image></view>
+				<view class="login_img"><image src="../../static/icon/phone.png"></image></view>
 				<view class="login_name"><input class="uni-input" v-model="username" focus placeholder="请输入手机号" /></view>
 			</view>
 			<view class="login_input flex">
-				<view class="login_img"><image src="/static/img/public3.png"></image></view>
+				<view class="login_img"><image src="../../static/icon/pswd.png"></image></view>
 				<view class="login_name"><input class="uni-input" type="password" v-model="passward" focus placeholder="请输入密码" /></view>
 			</view>
 			<view><button type="green" class="uni-button uni-button-green" @click="toLogin">登录</button></view>
-			<!-- <view><button type="green" class="uni-button uni-button-green uni-button-green-plain" plain="true" hover-class="none" @click="register">注册</button></view> -->
-			<navigator url="./externalRegistered" style="margin-bottom: 18rpx;"><view class="forget">注册</view></navigator>
+			<navigator url="./register" style="margin-bottom: 18rpx;"><view class="forget">注册</view></navigator>
 			<navigator url="./forget"><view class="forget">忘记密码</view></navigator>
-			<!-- <view class="flex other">
-				<view class="fenge"></view>
-				<view class="qita">其他方式登录</view>
-				<view class="fenge"></view>
-			</view> -->
 			<!-- #ifndef APP-PLUS -->
-
-			<!-- <view class="weixin" @click="wecahtLogin"><image src="/static/img/img05.png"></image></view>
-			<view class="weixin_text" @click="wecahtLogin">微信登录</view>
- -->
 			<!-- #endif -->
 			<!-- #ifdef APP-PLUS -->
-			<!-- <block v-if="!is_ios">
-				<view class="weixin" @click="wecahtLogin"><image src="/static/img/img05.png" mode="scaleToFill"></image></view>
-<<<<<<< HEAD
-				<view class="weixin_text" @click="wecahtLogin">微信登录</view>
-			</block>
-=======
-				<!-- <view class="weixin_text" @click="wecahtLogin">微信登录</view> -->
-			<!-- </block>
->>>>>>> 096bfe13572299bb8c079d664b260aed0d2398c9
-			<block v-else>
-				<view class="ios_login flex" @click="wecahtLogin('weixin')">
-					<text class="iconfont iconweixin"></text>
-					<text class="weixin_text">微信登录</text>
-				</view>
-				<view v-if="is_apple_login" class="ios_login flex" @click="wecahtLogin('apple')">
-					<image class="loginIcon" src="/static/icon/appleIcon.png" mode=" scaleToFill"></image>
-					<text class="weixin_text">通过Apple登录</text>
-				</view>
-			</block> -->
+			
 			<!-- #endif -->
 		</view>
 	</view>
@@ -307,16 +277,19 @@ page {
 	width: 100%;
 	height: 500rpx;
 	top: 0rpx;
+	background: #ff4c4c;
 	.banner-img {
 		width: 100%;
 		height: 100%;
 	}
 }
 .login_text {
-	height: calc(100% - 500rpx);
+	margin: auto 30rpx;
 	position: relative;
-	padding: 100rpx 60rpx 0;
+	padding: 100rpx 102rpx;
 	background-color: #ffffff;
+	margin-top: -180rpx;
+	border-radius: 20rpx;
 	
 	
 	.login_input {
@@ -371,20 +344,20 @@ page {
 		text-align: center;
 		font-family: PingFang SC;
 		font-weight: 500;
-		color: #6EAB4E;
+		color:#ff4c4c;
 	}
 
 	.uni-button-green {
 		color: #ffffff;
-		background-color: #6EAB4E;
+		background-color: #ff4c4c;
 		margin: 40rpx 10rpx;
 		border-radius: 10rpx;
 	}
 	.uni-button-green-plain {
-		border: 1px solid #6EAB4E;
+		border: 1px solid #ff4c4c;
 		margin: 40rpx 10rpx;
 		border-radius: 50rpx;
-		color: #6EAB4E;
+		color: #ff4c4c;
 		background-color: #ffffff;
 	}
 	.uni-button {

+ 39 - 177
pages/public/register.vue

@@ -1,57 +1,35 @@
 <template>
 	<view class="container">
 		<view class="container_text" >
-			<image class="banner-img" src="/static/img/logo.png" mode="scaleToFill"></image>
+			<!-- <image class="banner-img" src="/static/img/img01.png" mode="scaleToFill"></image> -->
 		</view>
 		<view class="loginTitle"><text>注册</text></view>
 		<view class="login_text">
 			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/phone.png"></image></view>
-				<view class="login_name"><input class="uni-input" type="text" v-model="phone" focus placeholder="请输入账号" /></view>
-			</view>
-			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/pread.png"></image></view>
-				<view class="login_name"><input class="uni-input" type="text" v-model="invitation" focus placeholder="请输入接点人id" :disabled="isinvitation" /></view>
+				<view class="login_img"><image src="../../static/icon/phone.png"></image></view>
+				<view class="login_name"><input class="uni-input" v-model="phone" focus placeholder="请输入账号" /></view>
 			</view>
 			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/psw.png"></image></view>
+				<view class="login_img"><image src="../../static/icon/pswd.png"></image></view>
 				<view class="login_name"><input class="uni-input" type="password" v-model="password" focus placeholder="请输入密码" /></view>
 			</view>
 			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/psw.png"></image></view>
+				<view class="login_img"><image src="../../static/icon/pswd.png"></image></view>
 				<view class="login_name"><input class="uni-input" type="password" v-model="repassword" focus placeholder="请重复输入密码" /></view>
 			</view>
 			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/code.png"></image></view>
-				<view class="login_name flex">
-					<input class="uni-input width" v-model="code" focus placeholder="请输入验证码" />
-					<view class="code" @click="verification">{{ countDown == 0 ? '验证码' : countDown }}</view>
-				</view>
-			</view>
-			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/dw.png"></image></view>
-				<picker v-if="!isparent_area" @change="bindParentArea" :value="parent_area" :range="parent_areas" class="uni-input">
-					<view class="placeholder" v-if="parent_area === ''">请选择区域</view>
-					<text>{{ parent_area }}</text>
-				</picker>
-				<view class="login_name" v-else><input class="uni-input" type="text" v-model="parent_area" focus disabled /></view>
-			</view>
-			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/dw.png"></image></view>
-				<picker @change="bindPayType" :value="pay_type" :range="pay_types" class="uni-input">
-					<view class="placeholder" v-if="pay_type === ''">请选择支付方式</view>
-					<text>{{ pay_type }}</text>
-				</picker>
-			</view>
+				<view class="login_img"><image src="../../static/icon/tg.png"></image></view>
+				<view class="login_name"><input class="uni-input" type="text" v-model="invitation" focus placeholder="请输入邀请码" /></view>
+			</view>
 			<view class="login_input flex">
-				<view class="login_img"><image src="/static/icon/jft.png"></image></view>
-				<view class="uni-input" style="color: #999;">
-					是否使用积分抵扣
-					<image src="../../static/icon/noselect.png" mode="" v-if="!isSelsect" @click="jfdk(1)"></image>
-					<image src="../../static/icon/select.png" mode="" v-if="isSelsect" @click="jfdk(0)"></image>
+				<view class="login_img"><image src="../../static/icon/code.png"></image></view>
+				<view class="login_name flex">
+					<input class="uni-input width" v-model="code" focus placeholder="请输入验证码" />
+					<view class="code" @click="verification">{{ countDown == 0 ? '验证码' : countDown }}</view>
 				</view>
 			</view>
 			<view><button type="green" @click="register" class="uni-button uni-button-green">注册账号</button></view>
+			<view><button class="uni-button uni-button-green uni-button-green-plain" type="green" plain="true" hover-class="none" @click="login">返回登录</button></view>
 		</view>
 	</view>
 </template>
@@ -63,31 +41,15 @@ export default {
 			phone: '', //用户
 			password: '', //密码
 			repassword: '',
-			invitation: '', //接点人id
+			invitation: '', //邀请码
 			code: '', //验证码
 			time: '', //保存倒计时对象
-			countDown: 0 ,//倒计时
-			parent_area: '',//区域
-			parent_areas: ['A','B','C'],//区域列表
-			pay_type: '',
-			pay_types: ['余额','佣金','支付宝','微信'],
-			isSelsect: false,
-			isinvitation: false,
-			isparent_area: false,
+			countDown: 0 ,//倒计时
 		};
 	},
-	onLoad(option) {
-		if(option.id){
-			this.invitation = option.id
-			console.log(this.invitation)
-			this.isinvitation = true;
-		}
-		if(option.area){
-			this.parent_area = option.area
-			this.isparent_area = true
-		}
+	onLoad() {
 		// 获取扫码邀请人id
-		// this.invitation = uni.getStorageSync('spread')||'';
+		this.invitation = uni.getStorageSync('spread')||'';
 	},
 	watch: {
 		// 监听倒计时
@@ -97,30 +59,7 @@ export default {
 			}
 		}
 	},
-	methods: {
-		//选择是否积分抵扣
-		jfdk(index) {
-			if(index == 1) {
-				this.isSelsect = true
-			}else {
-				this.isSelsect = false
-			}
-		},
-		//选择区域
-		bindParentArea(e) {
-			console.log(e.detail.value)
-			this.parent_area = this.parent_areas[e.detail.value]
-		},
-		//选择值支付方式
-		bindPayType(e) {
-			console.log(e)
-			if(e.detail.value) {
-				this.pay_type = this.pay_types[e.detail.value]
-			}else if(e.detail.value == 0){
-				this.pay_type = this.pay_types[e.detail.value]
-			}
-			
-		},
+	methods: {
 		// 注册
 		register() {
 			let obj = this;
@@ -139,95 +78,26 @@ export default {
 			if (obj.repassword != obj.password) {
 				obj.$api.msg('两次密码不正确');
 				return;
-			}
-			if(obj.code == '') {
-				obj.$api.msg('请输入验证吗');
-				return;
-			}
-			if(obj.parent_area == '') {
-				obj.$api.msg('请选择区域');
-				return;
-			}
-			if(obj.pay_type == '') {
-				obj.$api.msg('请选择支付方式');
-				return;
-			}
-			let paytype = ''
-			if(obj.pay_type == '微信') {
-				paytype = 'weixin'
-			}else if(obj.pay_type == '余额') {
-				paytype = 'yue'
-			}else if(obj.pay_type == '佣金') {
-				paytype = 'brokerage'
-			}else if(obj.pay_type == '支付宝') {
-				paytype = 'ali'
 			}
 			register({
 				account: obj.phone, //账号
-				captcha: obj.code, //验证码
+				captcha: 123456, //验证码
 				password: obj.password ,//密码
-				parent: obj.invitation,//接点人uid
-				parent_area: obj.parent_area,//区域
-				pay_type: paytype,
-				use_integral: obj.isSelsect ? '1':'0',
-				from: 'APP'
-			}).then(({da}) => {
-				if (obj.pay_type == 'weixin' || obj.pay_type == 'routine') {
-					// let da = data.result.jsConfig;
-					console.log('--da--', da);
-					let data = {
-						appid:da.appid,
-						noncestr: da.noncestr,
-						package: da.package,
-						partnerid:da.partnerid,
-						prepayid:da.prepayid,
-						timestamp: da.timestamp,
-						sign:da.sign
-					};
-					console.log('--data--', data);
-					uni.requestPayment({
-						provider: 'wxpay',
-						orderInfo: data,
-						success(res) {
-							console.log(res)
-						}
-					})
-				}
-				if (obj.pay_type == 'ali') {
-					const url = data.result.jsConfig;
-					console.log(url, 'url');
-					uni.requestPayment({
-						provider: 'alipay',
-						orderInfo: url,
-						success: res => {
-							console.log(res);
-							uni.showToast({
-								title: '支付成功',
-								duration: 2000
-							});
-						},
-						fail: e => {
-							console.log(e);
-						},
-						complete: () => {}
-					});
-					obj.payLoding = false;
-				}
-				if (obj.pay_type == 'yue' || obj.pay_type == 'brokerage'){
-					uni.showToast({
-						title:'注册成功',
-						duration:2000,
-						position:'top'
-					});
-					setTimeout(function () {
-						uni.navigateTo({
-							url: '/pages/user/jiedian'
-						});
-					},1000)
-				}
-			}).catch( err => {
-				console.log(err)
-			})
+				spread:this.invitation//上级推广人
+			}).then(function(e) {
+				uni.showToast({
+					title:'注册成功',
+					duration:2000,
+					position:'top'
+				});
+				setTimeout(function () {
+					uni.navigateTo({
+						url: '/pages/public/login'
+					});
+				},1000)
+				
+			});
+			//调用注册接口,成功跳转登录页
 		},
 		//发送验证码
 		verification() {
@@ -276,14 +146,13 @@ page {
 .container {
 	width: 100%;
 	height: 100%;
-	background-size: 100%;
-	background-color: #fff;
+	background-size: 100%;
 }
 .container_text {
 	width: 100%;
 	height: 500rpx;
 	top: 0rpx;
-	// background-color: #FF4343;
+	background-color: #FF4343;
 	.banner-img {
 		width: 100%;
 		height: 100%;
@@ -294,7 +163,7 @@ page {
 	position: relative;
 	padding: 100rpx 102rpx;
 	background-color: #ffffff;
-	// margin-top: -180rpx;
+	margin-top: -180rpx;
 	border-radius: 20rpx;
 	.login_input {
 		border-bottom: 1px solid #f0f0f0;
@@ -307,14 +176,7 @@ page {
 		.uni-input {
 			text-align: left;
 			width: 470rpx;
-			font-size: 28rpx !important;
-			position: relative;
-			image {
-				width: 30rpx;
-				height: 30rpx;
-				position: absolute;
-				right: 0;
-			}
+			font-size: 28rpx !important;
 		}
 		.login_name {
 			color: #333333;
@@ -358,7 +220,7 @@ page {
 		color: #ffffff;
 		background-color:  $base-color;
 		margin: 40rpx 10rpx;
-		border-radius: 10rpx;
+		border-radius: 50rpx;
 	}
 	.uni-button-green-plain {
 		border: 1px solid  $base-color;

+ 345 - 0
pages/purchase/purchase.vue

@@ -0,0 +1,345 @@
+<template>
+	<view class="">
+		<!-- <view class="">
+			买入
+		</view> -->
+		<view class="jg" style="height: 20rpx;"></view>
+		<empty v-if="loaded === true && list.length === 0"></empty>
+		<view class="buy-item" v-for="item in list" v-if="item.status !== -1">
+			<view class="item-top">
+				<view class="top-left">
+					<image src="../../static/icon/mrlogo.png" mode=""></image><text class="top-name clamp">{{item.order_id}}</text>
+				</view>
+				<view class="top-right">
+					{{item.status | status}}
+				</view>
+			</view>
+			<view class="item-info">
+				<view class="info-data">
+					<view class="info-tit">收益:</view>
+					<view class="info-val">{{item.day}}天/{{item.proportion}}%</view>
+				</view>
+				<!-- <view class="info-data">
+					<view class="info-tit">:</view>
+					<view class="info-val">10:20</view>
+				</view> -->
+				<view class="info-data">
+					<view class="info-tit">可获通证:</view>
+					<view class="info-val">1.0%</view>
+				</view>
+				<view class="info-data">
+					<view class="info-tit">价值:</view>
+					<view class="info-val">{{item.price}}</view>
+				</view>
+				<view class="btn-wrap flex" v-if="item.status == 1 || item.status == 2">
+					<view class="btn" @click="open(item.order_id)">
+						提交凭证
+					</view>
+				</view>
+			</view>
+		</view>
+		<uni-load-more :status="loadingType"></uni-load-more>
+		<uni-popup ref="popup1" type="center" :maskClick="false">
+			<view class="upload-wrap">
+				<view class="tit">
+					上传支付凭证
+				</view>
+				<view class="up-wrap" @click="imgsub('upimg')">
+					<image :src="upimg" mode="" v-if="upimg"></image>
+					<image v-else src="../../static/img/upimg.png" mode=""></image>
+				</view>
+				<view class="btn-wrap">
+					<view class="btn qx" @click="qx">
+						取消
+					</view>
+					<view class="btn" @click="evaluationUpload">提交</view>
+				</view>
+				
+			</view>
+		</uni-popup>
+		<!-- <u-tabbar v-model="current" :list="tabbar" active-color="#FF0000" inactive-color="#f19c99"></u-tabbar> -->
+	</view>
+</template>
+
+<script>
+	import uniPopup from '@/components/uni-popup/uni-popup.vue';
+	import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
+	import empty from '@/components/empty';
+	
+	import { packageMyReserveList, evaluationUpload } from '@/api/package.js'
+	import { upload } from '@/api/user.js';
+	
+	import {
+		tabbar,tabbar1
+	} from "@/utils/tabbar.js";
+	export default {
+		components: {
+			uniLoadMore,
+			empty,
+			uniPopup
+		},
+		filters: {
+			status(val) {
+				let str = ''
+				// 状态:0-预约,1-待支付,2-待审核,3-释放中,4-释放完成,5-重新发放,6-完成,-1-没抢到,-2-审核无效
+				switch (val) {
+					case 0:
+						str = '预约'
+						break;
+					case 1:
+						str = '待支付'
+						break;
+					case 2:
+						str = '待审核'
+						break;
+					case 3:
+						str = '释放中'
+						break;
+					case 4:
+						str = '释放完成'
+						break;
+					case 5:
+						str = '已完成'
+						break;
+					case 6:
+						str = '已完成'
+						break;
+					case -1:
+						str = '没抢到'
+						break;
+					case -2:
+						str = '审核无效'
+						break;
+					default:
+						str = ''
+				}
+		
+		
+				return str
+			}
+		},
+		data() {
+			return {
+				tabbar: tabbar,
+				tabbar1: tabbar1,
+				current: 1,
+				list: [],
+				loadingType: 'more',
+				page: 1,
+				limit: 20,
+				loaded: false,
+				choose_order: '',
+				upimg: '',
+			}
+		},
+		onLoad() {
+			console.log('买入')
+			// this.$refs.upload.open()
+			this.loadData()
+			// this.$refs.popup1.open()
+		},
+		//上拉加载更多
+		onReachBottom() {
+			this.loadData()
+		},
+		methods: {
+			qx() {
+				this.upimg = ''
+				this.choose_order = ''
+				this.$refs.popup1.close()
+			},
+			imgsub(text) {
+				console.log('imgsub');
+				upload({
+					filename: ''
+				}).then(data => {
+					// this.upimg = data[0].url;
+					this.$set(this,text,data[0].url)
+				});
+			},
+			open(orderId) {
+				this.choose_order = orderId
+				this.$refs.popup1.open()
+				
+			},
+			navto(url) {
+				uni.navigateTo({
+					url: url
+				})
+			},
+			loadData() {
+				let obj = this
+				if(obj.loadingType == 'noMore' || obj.loadingType == 'loading') {
+					return 
+				}
+				obj.loadingType = 'loading'
+				packageMyReserveList({
+					page: obj.page,
+					limit: obj.limit,
+					status: 3
+				}).then( ({data}) => {
+					obj.list = obj.list.concat(data.data)
+					this.page++
+					if (data.data.length == obj.limit) {
+						obj.loadingType = 'more'
+					} else {
+						obj.loadingType = 'noMore'
+					}
+					obj.$set(obj, 'loaded', true)
+				})
+			},
+			//提交审核
+			evaluationUpload() {
+				let obj = this
+				evaluationUpload({
+					pay_evaluation: obj.upimg,
+					id: obj.choose_order
+				}).then( res => {
+					this.qx()
+					uni.showToast({
+						title:'提交成功',
+						duration:2000
+					});
+					this.page = 1
+					this.list = []
+					this.loadingType = 'more'
+					this.loadData()
+					console.log(res,'上传凭证+++++')
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.buy-item {
+		width: 690rpx;
+		// height: 235rpx;
+		margin: 0 auto 20rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 0px 17rpx 0px rgba(0, 0, 0, 0.05);
+		border-radius: 20rpx;
+		padding: 26rpx 30rpx;
+		.item-top {
+			display: flex;
+			justify-content: space-between;
+			height: 50rpx;
+			.top-left {
+				font-size: 34rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #0F253A;
+				line-height: 50rpx;
+				display: flex;
+				align-items: center;
+				image {
+					width: 48rpx;
+					height: 46rpx;
+				}
+				.top-name {
+					width: 450rpx;
+					padding-left: 11rpx;
+				}
+			}
+			.top-right {
+				line-height: 50rpx;
+				width: 100rpx;
+				text-align: right;
+				font-size: 26rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #6D7C88;
+			}
+		}
+		.item-info {
+			width: 100%;
+			margin-top: 28rpx;
+			line-height: 50rpx;
+			font-size: 26rpx;
+			font-family: PingFang SC;
+			display: flex;
+			flex-wrap: wrap;
+			.info-data {
+				width: 50%;
+				display: flex;
+				.info-tit {
+					
+					font-weight: 500;
+					color: #6D7C88;
+				}
+				.info-val {
+					color: #0F253A;
+					font-weight: bold;
+				}
+			}
+			.btn-wrap {
+				padding-top: 20rpx;
+				width: 100%;
+				justify-content: flex-end;
+				.btn {
+					text-align: center;
+					width: 144rpx;
+					line-height: 50rpx;
+					background: #FFFFFF;
+					border: 2rpx solid #FF4C4C;
+					border-radius: 25rpx;
+					font-size: 26rpx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #FF4C4C;
+				}
+			}
+			
+			
+		}
+	}
+	.upload-wrap {
+		width: 500rpx;
+		height: 500rpx;
+		background-color: #fff;
+		border-radius: 20rpx;
+		.tit {
+			padding: 30rpx 25rpx;
+			text-align: center;
+			font-size: 32rpx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			color: #101010;
+		}
+		
+		.up-wrap {
+			margin:auto;
+			width: 225rpx;
+			height: 225rpx;
+			background: #FFFFFF;
+			border-radius: 10rpx;
+		
+			image {
+				width: 225rpx;
+				height: 225rpx;
+				border-radius: 10rpx;
+			}
+		}
+		.btn-wrap {
+			display: flex;
+			.btn {
+				margin: 50rpx auto 0;
+				width: 150rpx;
+				line-height: 84rpx;
+				background: linear-gradient(30deg, #FF4C4C, #FE6238);
+				border-radius: 10rpx;
+				font-size: 32rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #FFFFFF;
+				text-align: center;
+			}
+			.qx {
+				background: #fff;
+				border: 1px solid #999;
+				color: #999;
+			}
+		}
+		
+	}
+</style>

+ 102 - 0
pages/purchase/upload.vue

@@ -0,0 +1,102 @@
+<template>
+	<view class="content">
+		<view class="">
+			{{chooseId}}
+		</view>
+		<view class="choose-wrap">
+			<picker mode="selector" :range="chooseList" @change="bangTypeChange">
+				<view>{{type || '请选择支付方式'}}</view>
+			</picker>
+		</view>
+		<view class="tit">
+			上传支付凭证
+		</view>
+		<view class="up-wrap" @click="imgsub('upimg')">
+			<image :src="upimg" mode="" v-if="upimg"></image>
+			<image v-else src="../../static/img/upimg.png" mode=""></image>
+		</view>
+		<view class="btn" @click="evaluationUpload">提交审核</view>
+	</view>
+</template>
+
+<script>
+	import { upload } from '@/api/user.js';
+	import { evaluationUpload } from '@/api/package.js'
+	
+	export default {
+		data() {
+			return {
+				upimg: '',
+				type: '',
+				toUser: {},
+				chooseList: ['微信','支付宝','银行卡'],
+				chooseId: ''
+			}
+		},
+		onload(opt) {
+			if(opt.id) {
+				this.chooseId = opt.id
+				console.log(this.chooseId,'this.chooseId')
+			}
+			console.log(opt,'dd')
+		},
+		methods: {
+			bangTypeChange(e) {
+				
+				this.type = this.chooseList[e.detail.value]
+			},
+			imgsub(text) {
+				console.log('imgsub');
+				upload({
+					filename: ''
+				}).then(data => {
+					// this.upimg = data[0].url;
+					this.$set(this,text,data[0].url)
+				});
+			},
+			//提交审核
+			evaluationUpload() {
+				evaluationUpload().then( res => {
+					console.log(res,'上传凭证+++++')
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.tit {
+		padding: 30rpx 25rpx;
+		text-align: center;
+		font-size: 32rpx;
+		font-family: PingFang SC;
+		font-weight: bold;
+		color: #101010;
+	}
+	
+	.up-wrap {
+		margin:auto;
+		width: 225rpx;
+		height: 225rpx;
+		background: #FFFFFF;
+		border-radius: 10rpx;
+	
+		image {
+			width: 225rpx;
+			height: 225rpx;
+			border-radius: 10rpx;
+		}
+	}
+	.btn {
+		margin: 70rpx auto 0;
+		width: 702rpx;
+		line-height: 84rpx;
+		background: linear-gradient(30deg, #FF4C4C, #FE6238);
+		border-radius: 10rpx;
+		font-size: 32rpx;
+		font-family: PingFang SC;
+		font-weight: bold;
+		color: #FFFFFF;
+		text-align: center;
+	}
+</style>

+ 458 - 0
pages/sellout/sellout.vue

@@ -0,0 +1,458 @@
+<template>
+	<view class="">
+		<!-- <view class="out-wrapper">
+			卖出
+		</view> -->
+		<view class="jg" style="height: 20rpx;"></view>
+		<empty v-if="loaded === true && list.length === 0"></empty>
+		<view class="out-wrapper" v-for="item in list" :class="{'outt': item.status == 2}">
+			<view class="out-top flex">
+				<view class="buy-info flex">
+					<view class="fsz">卖家:</view>
+					<image :src="item.user.avatar" mode="" class="user-logo fsz"></image>
+					<view class="user-name fsz clamp">{{item.user.real_name}}</view>
+					<view class="user-phone fsz">
+						{{item.user.phone}}
+					</view>
+				</view>
+				<view class="buy-status">{{item.status | status}}</view>
+			</view>
+			<view class="item-info">
+				<view class="info-data">
+					<view class="info-tit">编号:</view>
+					<view class="info-val">{{item.order_id}}</view>
+				</view>
+				<view class="info-data">
+					<view class="info-tit">价值:</view>
+					<view class="info-val">300</view>
+				</view>
+			</view>
+			<view class="upimg">
+				<view class="up-tit">
+					打款凭证:
+				</view>
+				<view class="img-wrap" v-if="item.pay_evaluation" @click="lookimg(item.pay_evaluation)">
+					<image :src="item.pay_evaluation" mode=""></image>
+				</view>
+				<view class="" style="color: #0F253A;font-weight: bold;font-size: 26rpx;">
+					买家未上传支付凭证
+				</view>
+			</view>
+			<template v-if="item.status == 2">
+				<view class="mc-btn pass" @click="passPackage(item)">
+					通过
+				</view>
+				<view class="mc-btn fail" @click="openrefuse">
+					拒绝
+				</view>
+			</template>
+			
+		</view>
+		<uni-load-more :status="loadingType"></uni-load-more>
+		<uni-popup ref="refuse" type="center">
+			<view class="refuse-box">
+				<view class="box-tit">
+					请输入拒绝原因
+				</view>
+				<textarea :value="resone" placeholder="请输入拒绝原因" class="resone-wrapper" focus />
+				<view class="btn-wrap">
+					<view class="btn" @click="refusFali">
+						取消
+					</view>
+					<view class="btn" style="color: #000000;" @click="refusOk">
+						确定
+					</view>
+				</view>
+			</view>
+		</uni-popup>
+		<uni-popup ref="lookimg" type="center">
+			<view class="pop-wrap" style="position: relative;" >
+				<movable-area class="popup-box">
+					<movable-view class="popup-item" :scale="true" direction="all">
+						<image src="chooseImg" mode=""></image>
+					</movable-view>
+				</movable-area>
+				<image src="../../static/icon/close.png" mode="" class="close" style="width: 80rpx;height: 80rpx;" @click="closePup"></image>
+			</view>
+		</uni-popup>
+	</view>
+</template>
+
+<script>
+	import uniPopup from '@/components/uni-popup/uni-popup.vue';
+	import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
+	import empty from '@/components/empty';
+	import { packageOrder, packageAudit } from '@/api/package.js'
+	import {
+		tabbar,
+		tabbar1
+	} from "@/utils/tabbar.js";
+	export default {
+		components: {
+			uniLoadMore,
+			empty,
+			uniPopup
+		},
+		filters: {
+			status(val) {
+				let str = ''
+				// 状态:0-预约,1-待支付,2-待审核,3-释放中,4-释放完成,5-重新发放,6-完成,-1-没抢到,-2-审核无效
+				switch (val) {
+					case 0:
+						str = '预约'
+						break;
+					case 1:
+						str = '待支付'
+						break;
+					case 2:
+						str = '待审核'
+						break;
+					case 3:
+						str = '释放中'
+						break;
+					case 4:
+						str = '释放完成'
+						break;
+					case 5:
+						str = '重新发放'
+						break;
+					case 6:
+						str = '完成'
+						break;
+					case -1:
+						str = '没抢到'
+						break;
+					case -2:
+						str = '审核无效'
+						break;
+					default:
+						str = ''
+				}
+
+
+				return str
+			}
+		},
+		data() {
+			return {
+				resone: '', //拒绝理由
+				tabbar: tabbar,
+				tabbar1: tabbar1,
+				current: 2,
+				list: [],
+				loadingType: 'more',
+				page: 1,
+				limit: 10,
+				loaded: false,
+				chooseImg: '',//选择要查看的图片
+				choose_order: ''
+			}
+		},
+		onLoad() {
+			console.log('卖出')
+			this.loadData()
+		},
+		//上拉加载更多
+		onReachBottom() {
+			this.loadData()
+		},
+		methods: {
+			lookimg(src) {
+				this.chooseImg = src
+				
+			},
+			loadData() {
+				let obj = this
+				if (obj.loadingType == 'noMore' || obj.loadingType == 'loading') {
+					return
+				}
+				obj.loadingType = 'loading'
+				packageOrder({
+					page: obj.page,
+					limit: obj.limit,
+					status: 1
+				}).then(({
+					data
+				}) => {
+					console.log(data)
+					obj.list = data.data
+					obj.page++
+					if (obj.limit == data.data.length) {
+						obj.loadingType = 'more'
+					} else {
+						obj.loadingType = 'noMore'
+					}
+					obj.loaded = true
+				})
+
+			},
+			openrefuse() {
+				this.$refs.refuse.open()
+			},
+			//取消拒绝
+			refusFali() {
+				this.resone = ''
+				this.$refs.refuse.close()
+			},
+			//确定拒绝
+			refusOk() {
+				let obj = this
+				if(obj.resone == '') {
+					obj.$api.msg('请输入拒绝理由')
+					return
+				}
+				
+				packageAudit({
+					re: obj.resone,
+					id: obj.choose_order,
+					status: -2
+				}).then(res => {
+					obj.resone = ''
+					obj.$refs.refuse.close()
+					obj.page = 0
+					obj.list = []
+					obj.loaded = false
+					obj.loadingType = 'more'
+					obj.loadData()
+				})
+				
+			},
+			closePup() {
+				this.chooseImg = ''
+				this.$refs.lookimg.close()
+			},
+			passPackage() {
+				packageAudit({
+					re: '',
+					id: obj.choose_order,
+					status: 3
+				}).then(res => {
+					console.log(res)
+					obj.$refs.refuse.close()
+					obj.page = 0
+					obj.list = []
+					obj.loaded = false
+					obj.loadingType = 'more'
+					obj.loadData()
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.outt {
+		height: 392rpx;
+	}
+	.out-wrapper {
+		width: 690rpx;
+		// height: 392rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 0px 17rpx 0px rgba(0, 0, 0, 0.05);
+		border-radius: 20rpx;
+		margin: 0 auto 20rpx;
+		padding: 30rpx;
+		position: relative;
+		.outt {
+			height: 392rpx;
+		}
+		.out-top {
+			line-height: 46rpx;
+			justify-content: space-between;
+
+			.buy-info {
+				width: 450rpx;
+				font-size: 32rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #0F253A;
+				justify-content: flex-start;
+
+				.fsz {
+					flex-shrink: 0;
+				}
+
+				.user-name {
+					max-width: 180rpx;
+				}
+
+				.user-phone {
+					padding-left: 10rpx;
+					font-size: 24rpx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #999999;
+				}
+
+				.user-logo {
+					width: 46rpx;
+					height: 46rpx;
+					border-radius: 50%;
+					background-color: red;
+					padding-right: 10rpx;
+				}
+			}
+
+			.buy-status {
+				font-size: 26rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #6D7C88;
+			}
+		}
+
+		.item-info {
+			width: 100%;
+			margin-top: 28rpx;
+			line-height: 50rpx;
+			font-size: 26rpx;
+			font-family: PingFang SC;
+			display: flex;
+			flex-wrap: wrap;
+
+			.info-data {
+				width: 100%;
+				display: flex;
+
+				.info-tit {
+
+					font-weight: 500;
+					color: #6D7C88;
+				}
+
+				.info-val {
+					color: #0F253A;
+					font-weight: bold;
+				}
+			}
+		}
+
+		.upimg {
+			padding-top: 10rpx;
+			display: flex;
+
+			.up-tit {
+				display: inline-block;
+				font-size: 26rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #6D7C88;
+			}
+
+			.img-wrap {
+				width: 153rpx;
+				height: 152rpx;
+
+				border-radius: 20rpx;
+
+				image {
+					border-radius: 20rpx;
+					width: 153rpx;
+					height: 152rpx;
+					background-color: red;
+				}
+			}
+		}
+
+		.mc-btn {
+			width: 144rpx;
+			line-height: 50rpx;
+			border-radius: 25px;
+			background: #FFFFFF;
+			font-size: 26rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			text-align: center;
+			position: absolute;
+			bottom: 47rpx;
+		}
+
+		.pass {
+			color: #FF4C4C;
+			border: 2px solid #FF4C4C;
+			right: 190rpx;
+		}
+
+		.fail {
+			color: #999999;
+			border: 2px solid #EBEBEB;
+
+			right: 36rpx;
+		}
+	}
+
+	.refuse-box {
+		width: 549rpx;
+		height: 437rpx;
+		background: #FFFFFF;
+		border-radius: 14rpx;
+
+		.box-tit {
+			line-height: 120rpx;
+			text-align: center;
+			font-size: 37rpx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			color: #333333;
+		}
+
+		.resone-wrapper {
+			width: 494rpx;
+			height: 181rpx;
+			margin: auto;
+			background: rgba(224, 224, 224, 0.35);
+			border-radius: 10px;
+			padding: 10rpx;
+			font-size: 28rpx;
+		}
+
+		.btn-wrap {
+			margin-top: 60rpx;
+			display: flex;
+
+			.btn {
+				width: 50%;
+				font-size: 37rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #999999;
+				text-align: center;
+			}
+		}
+	}
+	.pop-wrap {
+		width: 522rpx;
+		height: 800rpx;
+		// background-color: red;
+	}
+	.popup-box {
+		width: 522rpx;
+		height: 800rpx;
+		border-radius: 20rpx;
+		position: relative;
+		overflow: hidden;
+		background-color: #fff;
+		.popup-item {
+			width: 522rpx;
+			height: 800rpx;
+			
+			image {
+				min-height: 605rpx;
+				min-width: 522rpx;
+			}
+		}
+		
+	}
+	.close {
+		display: block;
+		width: 40rpx;
+		height: 40rpx;
+		border: 50%;
+		position: absolute;
+		// background-color: red;
+		bottom: -100rpx;
+		left: 0;
+		right: 0;
+		margin: 0 auto;
+	}
+</style>

+ 1 - 1
pages/set/password.vue

@@ -151,7 +151,7 @@ page {
 	background-color: $color-gray;
 }
 .code {
-	color: #5dbc7c;
+	color: #ff4c4c;
 	font-size: 23rpx;
 	border-left: 1px solid #eeeeee;
 	width: 150rpx;

+ 361 - 0
pages/set/userdata.vue

@@ -0,0 +1,361 @@
+<template>
+	<view class="content">
+		<view class="tit">
+			上传收款码
+		</view>
+		<view class="up-wrap" @click="imgsub('upimg')">
+			<image :src="upimg" mode="" v-if="upimg"></image>
+			<image v-else src="../../static/img/upimg.png" mode=""></image>
+		</view>
+		<view class="tit">
+			基本信息
+		</view>
+		<view class="base-info">
+			<view class="base-item">
+				<view class="item-name">头像</view>
+				<view class="avatar" @click="imgsub('avatar')">
+					<image :src="avatar || '../../static/error/missing-face.png'" mode="" ></image>
+				</view>
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">昵称</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的昵称" v-model="nickname" />
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">手机号</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的手机号" v-model="phone" />
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">姓名</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的姓名" v-model="real_name" />
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">微信号</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的微信号" v-model="wx_no" />
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">支付宝姓名</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的支付宝姓名" v-model="alipay_name" />
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">支付宝账号</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的支付宝账号" v-model="alipay_no" />
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">开户行</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的开户行" v-model="account_Bank" />
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">所属支行</view>
+				<input type="text" value="" class="item-val" placeholder="输入所属支行" v-model="bank_branch" />
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">开户行姓名</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的开户行姓名" v-model="bank_name" />
+			</view>
+			<view class="base-item flex">
+				<view class="item-name">银行卡账号</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的银行卡账号" v-model="bank_card" />
+			</view>
+			<!-- <view class="base-item flex">
+				<view class="item-name">出生日期</view>
+				<picker mode="date" @change="bindDateChange">
+					<view class="item-val" v-if="birthday">{{birthday}}</view>
+					<view class="item-val" v-else style="color: #999;">输入您的出生日期</view>
+				</picker>
+			</view> -->
+			<!-- <view class="base-item flex">
+				<view class="item-name">所在城市</view>
+				<input type="text" value="" class="item-val" placeholder="输入您的所在城市" />
+			</view> -->
+		</view>
+		<view class="btn" @click="subInfo">提交保存</view>
+		<view class="btn1" @click="toLogout">退出登录</view>
+		<view class="jg" style="height: 70rpx;">
+
+		</view>
+	</view>
+</template>
+
+<script>
+	import { mapState, mapMutations } from 'vuex';
+	import { getUserInfo } from '@/api/user.js';
+	// import { upload } from '@/api/order.js';
+	import { uploads, edit, upload} from '@/api/user.js';
+	  import { logout } from '@/api/set.js';
+	export default {
+		computed: {
+			...mapState('user',['userInfo'])
+		},
+		data() {
+			return {
+				avatar: '',
+				upimg: '',
+				real_name: '',
+				nickname: '',
+				phone: '',
+				wx_no: '',
+				alipay_name: '',
+				alipay_no: '',
+				account_Bank: '',
+				bank_branch: '',
+				bank_card: '',
+				bank_name: '',
+				// birthday: '',
+				city: '',
+				card_id: '',//身份证
+			}
+		},
+		onLoad() {
+			let obj = this
+			obj.avatar = obj.userInfo.avatar || ''
+			obj.alipay_name = obj.userInfo.alipay_name || ''
+			obj.alipay_no = obj.userInfo.alipay_no || '',
+			obj.bank_branch = obj.userInfo.bank_branch || ''
+			obj.account_Bank = obj.userInfo.account_Bank || ''
+			obj.bank_card = obj.userInfo.bank_card || '',
+			obj.bank_name = obj.userInfo.bank_name || ''
+			// obj.birthday = obj.userInfo.birthday || ''
+			// obj.card_id: obj.userInfo.card_id  || ''
+			obj.upimg = obj.userInfo.wx_qr || ''
+			obj.wx_no = obj.userInfo.wx_no || ''
+			obj.phone = obj.userInfo.phone || ''
+			obj.real_name = obj.userInfo.real_name || ''
+			obj.nickname = obj.userInfo.nickname || ''
+		},
+		methods: {
+			...mapMutations('user', ['setUserInfo', 'setOrderInfo','logout']),
+			//退出登录
+			toLogout() {
+				let obj = this;
+				uni.showModal({
+					content: '确定要退出登录么',
+					success: e => {
+						if (e.confirm) {
+							logout({}).then(e => {
+								obj.logout();
+								uni.navigateTo({
+									url:'/pages/public/login'
+								})
+							})
+							.catch(e => {
+								console.log(e);
+							});
+						}
+					}
+				});
+			},
+			imgsub(text) {
+				console.log('imgsub');
+				upload({
+					filename: ''
+				}).then(data => {
+					// this.upimg = data[0].url;
+					this.$set(this,text,data[0].url)
+				});
+			},
+			getUserInfo() {
+				getUserInfo({})
+					.then(({ data }) => {
+						this.setUserInfo(data);
+						
+					})
+					.catch(e => {
+						console.log(e);
+					});
+			},
+			bindDateChange(e) {
+				this.birthday = e.detail.value
+			},
+			subInfo() {
+				let obj = this
+				if(obj.upimg == '') {
+					obj.$api.msg('请上传收款码')
+					return
+				}
+				if(obj.avatar == '') {
+					obj.$api.msg('请上传头像')
+					return
+				}
+				if(obj.nickname == '') {
+					obj.$api.msg('请输入昵称')
+					return
+				}
+				if(obj.phone == '') {
+					obj.$api.msg('请输入手机号')
+					return
+				}
+				const reg = /^(\+?0?86-?)?1[\d]\d{9}$/;
+				if (!reg.test(obj.phone)) {
+					obj.$api.msg('请填写正确的手机号码');
+					return;
+				}
+				if(obj.real_name == '') {
+					obj.$api.msg('请输入姓名')
+					return
+				}
+				if(obj.wx_no == '') {
+					obj.$api.msg('请输入微信号')
+					return
+				}
+				if(obj.alipay_name == '') {
+					obj.$api.msg('请输入支付宝姓名')
+					return
+				}
+				if(obj.alipay_no == '') {
+					obj.$api.msg('请输入支付宝账号')
+					return
+				}
+				if(obj.account_Bank == '') {
+					obj.$api.msg('请输入开户行')
+					return
+				}
+				if(obj.bank_branch == '') {
+					obj.$api.msg('请输入所属支行')
+					return
+				}
+				if(obj.bank_name == '') {
+					obj.$api.msg('请输入开户姓名')
+					return
+				}
+				if(obj.bank_card == '') {
+					obj.$api.msg('请输入银行卡账号')
+					return
+				}
+				// if(obj.birthday == '') {
+				// 	obj.$api.msg('请输入出生日期')
+				// 	return
+				// }
+				
+				uni.showLoading({
+					title: '提交中...',
+					mask:true
+				})
+				edit({
+					avatar: obj.avatar,
+					alipay_name: obj.alipay_name,
+					alipay_no: obj.alipay_no,
+					account_Bank: obj.account_Bank,
+					bank_branch: obj.bank_branch,
+					bank_card: obj.bank_card,
+					bank_name: obj.bank_name,
+					// birthday: obj.birthday,
+					// card_id: obj.card_id,
+					wx_no: obj.wx_no,
+					phone: obj.phone,
+					real_name: obj.real_name,
+					nickname: obj.nickname,
+					wx_qr: obj.upimg
+					
+				}).then( res => {
+					obj.getUserInfo()
+					
+					obj.$api.msg('修改成功');
+					setTimeout(()=> {
+						uni.switchTab({
+							url:'/pages/user/user'
+						});
+					}, 1000);
+					
+				}).catch( err => {
+					console.log(err)
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.tit {
+		padding: 30rpx 25rpx;
+		font-size: 32rpx;
+		font-family: PingFang SC;
+		font-weight: bold;
+		color: #101010;
+	}
+
+	.up-wrap {
+		margin-left: 30rpx;
+		width: 225rpx;
+		height: 225rpx;
+		background: #FFFFFF;
+		border-radius: 10rpx;
+
+		image {
+			width: 225rpx;
+			height: 225rpx;
+			border-radius: 10rpx;
+		}
+	}
+
+	.base-info {
+		margin: auto;
+		width: 702rpx;
+		// height: 1106px;
+		background: #FFFFFF;
+		box-shadow: 0px 0px 20rpx 0px rgba(50, 50, 52, 0.06);
+		border-radius: 20rpx;
+
+		.base-item {
+			border: 1px solid #eee;
+			line-height: 100rpx;
+			font-size: 30rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: #333333;
+			padding-left: 25rpx;
+			.avatar {
+				margin: auto;
+				width: 200rpx;
+				height: 200rpx;
+				border-radius: 50%;
+				// background-color: #aaa;
+				image {
+					width: 200rpx;
+					height: 200rpx;
+					border-radius: 50%;
+				}
+			}
+			.item-name {
+				font-weight: bold;
+			}
+			.item-val {
+				display: block;
+				line-height: 100rpx;
+				height: 100rpx;
+				width: 478rpx;
+				font-size: 28rpx;
+				font-family: PingFang SC;
+				font-weight: 400;
+				color: #000;
+			}
+		}
+
+	}
+
+	.btn {
+		margin: 70rpx auto 0;
+		width: 702rpx;
+		line-height: 84rpx;
+		background: linear-gradient(30deg, #FF4C4C, #FE6238);
+		border-radius: 10rpx;
+		font-size: 32rpx;
+		font-family: PingFang SC;
+		font-weight: bold;
+		color: #FFFFFF;
+		text-align: center;
+	}
+	.btn1 {
+		margin: 30rpx auto 0;
+		width: 702rpx;
+		line-height: 84rpx;
+		color: #FF4C4C;
+		border: 1px solid #FF4C4C;
+		background-color: #fff;
+		border-radius: 10rpx;
+		font-size: 32rpx;
+		font-family: PingFang SC;
+		font-weight: bold;
+		text-align: center;
+	}
+</style>

+ 3 - 3
pages/set/userinfo.vue

@@ -194,7 +194,7 @@
   		.submit{
   			margin: 40rpx auto;
   			width: 560rpx;
-  			background-color: #6EAB4E;
+  			background-color: #ff4c4c;
   			color: #FFFFFF;
   			text-align: center;
   			padding:26rpx 0rpx;
@@ -203,9 +203,9 @@
 		.submit1{
 			margin: 40rpx auto;
 			width: 560rpx;
-			border: 1px solid #6EAB4E;
+			border: 1px solid #ff4c4c;
 			background-color: #FFFFFF;
-			color: #6EAB4E;
+			color: #ff4c4c;
 			text-align: center;
 			padding:26rpx 0rpx;
 			border-radius: 50rpx;

+ 4 - 4
pages/user/extension.vue

@@ -2,7 +2,7 @@
  	<view class="content">
  		<view class="content-money">
  			<view class="money-box">
- 				<image class="tuiguang_bg" src="../../static/image/jiedian.png"></image>
+ 				<image class="tuiguang_bg" src="../../static/img/teambg.png"></image>
  			 <view class="money-frame">
  				 <view class="money_num">
  					{{userInfo.spread_count || '0'}}
@@ -222,7 +222,7 @@
  			
  			font-size: 32rpx;
  			font-weight: bold;
- 			color: #3F7C1F;
+ 			color: #fff;
  		}
  		.text {
  			padding-bottom: 26rpx;
@@ -230,7 +230,7 @@
  			font-weight: 500;
  			color: #666666;
  			&.current {
- 				border-bottom: 2px solid #3F7C1F;
+ 				border-bottom: 2px solid #ff4c4c;
  			}
  		}
  		.icon {
@@ -322,7 +322,7 @@
  		font-size: 72rpx;
  		font-family: PingFang SC;
  		font-weight: bold;
- 		color: #3F7C1F;
+ 		color: #fff;
  		.money_ren {
  			font-size: 36rpx;
  		}

+ 4 - 4
pages/user/integral.vue

@@ -2,7 +2,7 @@
 	<view class="container">
 		<!-- 头部 -->
 		<view class="header">
-			<image src="../../static/img/img38.png" mode="scaleToFill"></image>
+			<image src="../../static/img/jfbg.png" mode="scaleToFill"></image>
 			<view class="money">{{+integralAll || 0}}</view>
 		</view>
 		<!-- 收入和支出 -->
@@ -151,9 +151,9 @@ export default {
 			font-size: 72rpx;
 			font-family: PingFang SC;
 			font-weight: 500;
-			color: #3f7c1f;
+			color: #fff;
 			position: absolute;
-			top: 60%;
+			top: 50%;
 			left: 50%;
 			transform: translate(-50%, -50%);
 		}
@@ -194,7 +194,7 @@ export default {
 					transform: translateX(-50%);
 					width: 44px;
 					height: 0;
-					border-bottom: 2px solid #3f7c1f;
+					border-bottom: 2px solid #ff4c4c;
 				}
 			}
 		}

+ 185 - 17
pages/user/user.vue

@@ -7,7 +7,7 @@
 			<!-- 用户头像和信息 -->
 			<view class="infor">
 				<!-- 用户信息 -->
-				<view class="infor-left">
+				<view class="infor-left" @click="nav('/pages/set/userdata')">
 					<image :src=" userInfo.avatar || '../../static/error/missing-face.png' "></image>
 					<view class="info-box">
 						<view class="username">{{ userInfo.nickname || '游客' }}</view>
@@ -15,10 +15,10 @@
 					</view>
 				</view>
 				<!-- 设置 -->
-				<view class="infor-right" @click="nav('/pages/set/userinfo')">
+				<!-- <view class="infor-right" @click="nav('/pages/set/userinfo')">
 					<image src="../../static/img/img18.png" mode="scaleToFill"></image>
 					<view class="setting">设置</view>
-				</view>
+				</view> -->
 			</view>
 			<!-- 我的订单 -->
 			<view class="order-box">
@@ -48,9 +48,49 @@
 			</view>
 		</view>
 		<!-- 下部分 -->
-		<view class="item-box">
-			<!-- 我的余额 -->
-			<view class="order-section">
+		<view class="my-tools">
+			<view class="my-order">
+				<view class="order">我的工具</view>
+				<!-- <image src="../../static/img/xiangxia.png" mode="scaleToFill"></image> -->
+			</view>
+			<view class="tool flex">
+				<view class="tool-item" @click="nav('/pages/vip/vip')" v-if="userInfo.level == 0">
+					<view class="tool-img"><image src="../../static/icon/g1.png" mode=""></image></view>
+					<view class="tool-name">成为会员</view>
+				</view>
+				<view class="tool-item" @click="nav('/pages/vip/fwbDetail')" v-if="userInfo.level > 0">
+					<view class="tool-img"><image src="../../static/icon/g1.png" mode=""></image></view>
+					<view class="tool-name">服务包专区</view>
+				</view>
+				<view class="tool-item" @click="nav('/pages/user/shareQrCode')">
+					<view class="tool-img"><image src="../../static/icon/g2.png" mode=""></image></view>
+					<view class="tool-name">推广二维码</view>
+				</view>
+				<view class="tool-item" @click="nav('/pages/user/extension')">
+					<view class="tool-img"><image src="../../static/icon/g3.png" mode=""></image></view>
+					<view class="tool-name">我的团队</view>
+				</view>
+				<view class="tool-item" @click="nav('/pages/set/address')">
+					<view class="tool-img"><image src="../../static/icon/g4.png" mode=""></image></view>
+					<view class="tool-name">我的地址</view>
+				</view>
+				<view class="tool-item" @click="nav('/pages/set/password')">
+					<view class="tool-img"><image src="../../static/icon/g6.png" mode=""></image></view>
+					<view class="tool-name">修改密码</view>
+				</view>
+				<view class="tool-item" @click="open()">
+					<view class="tool-img"><image src="../../static/icon/g7.png" mode=""></image></view>
+					<view class="tool-name">联系客服</view>
+				</view>
+				<view class="tool-item" @click="nav('/pages/set/userdata')">
+					<view class="tool-img"><image src="../../static/icon/g8.png" mode=""></image></view>
+					<view class="tool-name">设置</view>
+				</view>
+			</view>
+		</view>
+		<!-- <view class="item-box"> -->
+			
+			<!-- <view class="order-section">
 				<view class="order-item" @click="nav('/pages/money/wallet')">
 					<image src="../../static/img/img26.png" mode="scaleToFill"></image>
 					<view class="text">我的余额</view>
@@ -67,9 +107,9 @@
 					<image src="../../static/img/img25.png" mode="scaleToFill"></image>
 					<view class="text">我的推广</view>
 				</view>
-			</view>
+			</view> -->
 			<!-- 底部列表 -->
-			<view class="btm">
+			<!-- <view class="btm">
 				<view class="ul-btm" @click="nav('/pages/user/jiedian')">
 					<image src="../../static/img/img27.png" mode="scaleToFill"></image>
 					<view class="text">我的接点</view>
@@ -100,8 +140,8 @@
 					<view class="text">联系客服</view>
 					<image class="jiantou" src="../../static/img/img32.png" mode="scaleToFill"></image>
 				</view>
-			</view>
-		</view>
+			</view> -->
+		<!-- </view> -->
 		<uni-popup ref="popup" type="center">
 			<view class="popup-box">
 				<view class="img"><image src="../../static/img/img009.png" mode=""></image></view>
@@ -118,21 +158,28 @@
 				</view>
 			</view>
 		</uni-popup>
+		<!-- <u-tabbar v-if="userInfo.uid" v-model="current" :list="tabbar" active-color="#FF0000" inactive-color="#f19c99"></u-tabbar>
+		<u-tabbar v-else v-model="current" :list="tabbar1" active-color="#FF0000" inactive-color="#f19c99"></u-tabbar> -->
 	</view>
 </template>
 
 <script>
+	
 	import { orderData, getUserInfo,service } from '@/api/user.js';
 	import uniPopup from '@/components/uni-popup/uni-popup.vue';
 	import uniCopy from '@/utils/uni-copy.js';
 	import { mapState, mapMutations } from 'vuex';
 	import { saveUrl, interceptor } from '@/utils/loginUtils.js';
+	import { tabbar,tabbar1 } from "@/utils/tabbar.js";
 	export default {
 		components: {
 			uniPopup
 		},
 		data() {
 			return {
+				tabbar: tabbar,
+				tabbar1: tabbar1,
+				current: 5,
 				text:'123465'
 			}
 		},
@@ -202,6 +249,7 @@
 					// 登录拦截
 					interceptor();
 				}else {
+					console.log('ddd')
 					uni.navigateTo({
 						url
 					})
@@ -261,15 +309,15 @@
 			display: flex;
 			justify-content: space-around; // 水平平均分布
 			align-items: center; // 垂直居中 
-			margin-top: 138rpx;
-
+			margin-top: 80rpx;
+			text-align: center;
 			.infor-left {
 				width: 100%;
 				height: 126.5rpx;
 				display: flex;
 				align-items: center;
 				padding-left: 23rpx;
-
+				flex-direction: column;
 				image {
 					width: 126.5rpx;
 					height: 126.5rpx;
@@ -285,7 +333,7 @@
 					font-size: 34rpx;
 					font-family: PingFang SC;
 					font-weight: bold;
-					color: #3F7C1F;
+					color: #fff;
 				}
 
 				.phone {
@@ -293,7 +341,7 @@
 					font-size: 26rpx;
 					font-family: PingFang SC;
 					font-weight: 500;
-					color: #3F7C1F;
+					color: #fff;
 				}
 			}
 
@@ -388,7 +436,67 @@
 	.item-box {
 		padding-top: 80rpx;
 		height: 900rpx;
-
+		.order-box {
+			width: 710rpx;
+			height: 221rpx;
+			background: #FFFFFF;
+			box-shadow: 0rpx 0rpx 20rpx 0rpx rgba(50, 50, 52, 0.06);
+			border-radius: 20rpx;
+			position: absolute;
+			top: 335rpx;
+			// display: flex;
+			// justify-content: center; // 水平居中
+			margin-left: 20rpx;
+		
+			.my-order {
+				height: 73rpx;
+				width: 100%;
+				border-bottom: 2rpx solid #F5F5F5;
+				display: flex;
+				align-items: center;
+				justify-content: flex-start;
+		
+				.order {
+					font-size: 30rpx;
+					font-family: PingFang SC;
+					font-weight: bold;
+					color: #333333;
+					margin-left: 36rpx;
+					margin-right: 520rpx;
+				}
+		
+				image {
+					width: 12rpx;
+					height: 22rpx;
+				}
+			}
+		
+			.order-section {
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+		
+				.order-item {
+					flex: 1;
+					display: flex;
+					flex-direction: column;
+					align-items: center;
+					justify-content: center;
+					margin-top: 30rpx;
+		
+					image {
+						width: 42rpx;
+						height: 42rpx;
+					}
+		
+					.text {
+						margin-top: 20rpx;
+						font-size: 24rpx;
+						color: #333333;
+					}
+				}
+			}
+		}
 		// background-color: #fff;
 		// background-color: pink;
 		.order-section {
@@ -533,5 +641,65 @@
 			}
 		}
 	}
-	
+	.my-tools {
+		width: 710rpx;
+		height: 418rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 0px 20rpx 0px rgba(50, 50, 52, 0.06);
+		border-radius: 20rpx;
+		margin: 120rpx auto;
+		// background-color: red;
+		.my-order {
+			height: 73rpx;
+			width: 100%;
+			border-bottom: 2rpx solid #F5F5F5;
+			display: flex;
+			align-items: center;
+			justify-content: flex-start;
+		
+			.order {
+				font-size: 30rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #333333;
+				margin-left: 36rpx;
+				margin-right: 520rpx;
+			}
+		
+			image {
+				width: 12rpx;
+				height: 22rpx;
+			}
+		}
+		.tool {
+			flex-wrap: wrap;
+			justify-content: flex-start;
+			align-items: center;
+			.tool-item {
+				width: 25%;
+				height: 160rpx;
+				// background-color: #bfa;
+				display: flex;
+				align-items: center;
+				flex-direction: column;
+				justify-content: center;
+				.tool-img {
+					width: 42rpx;
+					height: 42rpx;
+					image {
+						width: 100%;
+						height: 100%;
+					}
+				}
+				.tool-name {
+					padding-top: 10rpx;
+					font-size: 24rpx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #333333;
+				}
+			}
+			
+		}
+	}
 </style>

+ 249 - 0
pages/vip/contract.vue

@@ -0,0 +1,249 @@
+<template>
+	<view class="container">
+		<!-- 头部 -->
+		<view class="header">
+			<image src="../../static/img/hybg.png" mode="scaleToFill"></image>
+			<view class="money">{{+integralAll || 0}}</view>
+		</view>
+		<!-- 收入和支出 -->
+		<view class="navbar">
+			<view class="nav-item" v-for="(item, index) in navList" :key="index" :class="{ current: tabCurrentIndex === index }" @click="tabClick(index)">{{ item.text }}</view>
+		</view>
+		<swiper class="swiper-box" :current="tabCurrentIndex" duration="300" @change="changeTab" :style="{'height':height}">
+			<swiper-item class="tab-content" v-for="(tabItem, tabIndex) in navList" :key="tabIndex">
+				<!-- 空白页 -->
+				<empty v-if="tabItem.loaded === true && tabItem.orderList.length === 0"></empty>
+				<!-- 推广奖励 -->
+				<scroll-view class="scorll" scroll-y="true" :style="{'height':height}">
+					<view class="cost">
+						<view class="award" v-for="item in tabItem.orderList">
+							<view class="award-left">
+								<view class="text clamp">{{ item.mark }}</view>
+								<view class="time">{{ item.add_time }}</view>
+							</view>
+							<view class="award-right">{{ item.pm == 1 ? '+' : '-' }}{{ item.number }}</view>
+						</view>
+					</view>
+				</scroll-view>
+				<uni-load-more :status="tabItem.loadingType"></uni-load-more>
+			</swiper-item>
+		</swiper>
+	</view>
+</template>
+
+<script>
+// 组件
+import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
+import empty from '@/components/empty';
+//接口
+import { integral } from '@/api/wallet.js';
+import { getUserInfo } from '@/api/user.js';
+export default {
+	components: {
+		empty,
+		uniLoadMore
+	},
+	data() {
+		return {
+			height: '',
+			tabCurrentIndex: 0,
+			navList: [
+				{
+					state: 1,
+					text: '收入',
+					loadingType: 'more',
+					orderList: [],
+					page: 1, //当前页数
+					limit: 10 //每次信息条数
+				},
+				{
+					state: 0,
+					text: '支出',
+					loadingType: 'more',
+					orderList: [],
+					page: 1, //当前页数
+					limit: 10 //每次信息条数
+				}
+			],
+			list: [],
+			// money: '',
+			integralAll: '',//当前积分
+		};
+	},
+	onLoad() {
+		this.loadData();
+		this.userinfo()
+	},
+	onReady(res) {
+		var _this = this;
+		uni.getSystemInfo({
+			success: resu => {
+				const query = uni.createSelectorQuery();
+				query.select('.swiper-box').boundingClientRect();
+				query.exec(function(res) {
+					_this.height = resu.windowHeight - res[0].top + 'px';
+					console.log('打印页面的剩余高度', _this.height);
+				});
+			},
+			fail: res => {}
+		});
+	},
+	methods: {
+		//加载用户信息
+		userinfo() {
+			getUserInfo({}).then(({ data }) => {
+				this.integralAll = data.integral;
+			});
+		},
+		//swiper 切换
+		changeTab(e) {
+			this.tabCurrentIndex = e.target.current;
+			this.loadData('tabChange');
+		},
+		//顶部tab点击
+		tabClick(index) {
+			this.tabCurrentIndex = index;
+		},
+		loadData(type) {
+			let obj = this;
+			let index = obj.tabCurrentIndex;
+			let navItem = obj.navList[index];
+			if (navItem.loadingType == 'loading' || navItem.loadingType == 'noMore') {
+				return;
+			}
+			if (type == 'tabChange' && navItem.loaded == 'loaded') {
+				return;
+			}
+			navItem.loadingType == 'loading';
+			integral({
+				page: navItem.page,
+				limit: navItem.limit,
+				pm: navItem.state
+			}).then(res => {
+				navItem.orderList = navItem.orderList.concat(res.data);
+				if (navItem.limit == res.data.length) {
+					navItem.loadingType = 'more';
+					return;
+				} else {
+					navItem.loadingType = 'noMore';
+				}
+				uni.hideLoading();
+				this.$set(navItem, 'loaded', true);
+			});
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+.container {
+	width: 750rpx;
+	background-color: #f1f1f1;
+
+	.header {
+		position: relative;
+		image {
+			width: 750rpx;
+			height: 400rpx;
+		}
+
+		.money {
+			font-size: 72rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: #fff;
+			position: absolute;
+			top: 50%;
+			left: 50%;
+			transform: translate(-50%, -50%);
+		}
+	}
+
+	
+
+	
+
+	.navbar {
+		display: flex;
+		height: 100rpx;
+		padding: 0 5rpx;
+		background: #fff;
+		box-shadow: 0 1rpx 5rpx rgba(0, 0, 0, 0.06);
+		position: relative;
+		z-index: 10;
+		margin-top: 25rpx;
+
+		.nav-item {
+			flex: 1;
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			height: 100%;
+			font-size: 15px;
+			color: #999999;
+			position: relative;
+
+			&.current {
+				color: #333333;
+
+				&:after {
+					content: '';
+					position: absolute;
+					left: 50%;
+					bottom: 0;
+					transform: translateX(-50%);
+					width: 44px;
+					height: 0;
+					border-bottom: 2px solid #ff4c4c;
+				}
+			}
+		}
+	}
+
+	.cost {
+		width: 750rpx;
+		height: auto;
+		background-color: #fff;
+
+		.award {
+			width: 100%;
+			border-bottom: 1px solid #f0f4f8;
+			padding: 20rpx 25rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+
+			.award-left {
+				width: 60%;
+				.text {
+					width: 100%;
+					font-size: 30rpx;
+					font-family: PingFang SC;
+					font-weight: bold;
+					color: #666666;
+					margin-bottom: 16rpx;
+				}
+
+				.time {
+					font-size: 26rpx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #aeaeae;
+				}
+			}
+
+			.award-right {
+				font-size: 36rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #ff0000;
+				margin-right: 30rpx;
+			}
+		}
+	}
+}
+.swiper-box {
+		// height: calc(100% - 536rpx);
+		background-color: #fff;
+	}
+</style>

+ 250 - 0
pages/vip/extension.vue

@@ -0,0 +1,250 @@
+<template>
+	<view class="container">
+		<!-- 头部 -->
+		<view class="header">
+			<image src="../../static/img/hybg.png" mode="scaleToFill"></image>
+			<view class="money">{{+integralAll || 0}}</view>
+		</view>
+		<!-- 收入和支出 -->
+		<view class="navbar">
+			<view class="nav-item" v-for="(item, index) in navList" :key="index" :class="{ current: tabCurrentIndex === index }" @click="tabClick(index)">{{ item.text }}</view>
+		</view>
+		<swiper class="swiper-box" :current="tabCurrentIndex" duration="300" @change="changeTab" :style="{'height':height}">
+			<swiper-item class="tab-content" v-for="(tabItem, tabIndex) in navList" :key="tabIndex">
+				<!-- 空白页 -->
+				<empty v-if="tabItem.loaded === true && tabItem.orderList.length === 0"></empty>
+				<!-- 推广奖励 -->
+				<scroll-view class="scorll" scroll-y="true" :style="{'height':height}">
+					<view class="cost">
+						<view class="award" v-for="item in tabItem.orderList">
+							<view class="award-left">
+								<view class="text clamp">{{ item.mark }}</view>
+								<view class="time">{{ item.add_time }}</view>
+							</view>
+							<view class="award-right">{{ item.pm == 1 ? '+' : '-' }}{{ item.number }}</view>
+						</view>
+					</view>
+				</scroll-view>
+				<uni-load-more :status="tabItem.loadingType"></uni-load-more>
+			</swiper-item>
+		</swiper>
+	</view>
+</template>
+
+<script>
+// 组件
+import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
+import empty from '@/components/empty';
+//接口
+import { integral } from '@/api/wallet.js';
+import { getUserInfo } from '@/api/user.js';
+export default {
+	components: {
+		empty,
+		uniLoadMore
+	},
+	data() {
+		return {
+			height: '',
+			tabCurrentIndex: 0,
+			navList: [
+				{
+					state: 1,
+					text: '收入',
+					loadingType: 'more',
+					orderList: [],
+					page: 1, //当前页数
+					limit: 10 //每次信息条数
+				},
+				{
+					state: 0,
+					text: '支出',
+					loadingType: 'more',
+					orderList: [],
+					page: 1, //当前页数
+					limit: 10 //每次信息条数
+				}
+			],
+			list: [],
+			// money: '',
+			integralAll: '',//当前积分
+		};
+	},
+	onLoad() {
+		this.loadData();
+		this.userinfo()
+	},
+	onReady(res) {
+		var _this = this;
+		uni.getSystemInfo({
+			success: resu => {
+				const query = uni.createSelectorQuery();
+				query.select('.swiper-box').boundingClientRect();
+				query.exec(function(res) {
+					_this.height = resu.windowHeight - res[0].top + 'px';
+					console.log('打印页面的剩余高度', _this.height);
+				});
+			},
+			fail: res => {}
+		});
+	},
+	methods: {
+		//加载用户信息
+		userinfo() {
+			getUserInfo({}).then(({ data }) => {
+				this.integralAll = data.integral;
+			});
+		},
+		//swiper 切换
+		changeTab(e) {
+			this.tabCurrentIndex = e.target.current;
+			this.loadData('tabChange');
+		},
+		//顶部tab点击
+		tabClick(index) {
+			this.tabCurrentIndex = index;
+		},
+		loadData(type) {
+			let obj = this;
+			let index = obj.tabCurrentIndex;
+			let navItem = obj.navList[index];
+			if (navItem.loadingType == 'loading' || navItem.loadingType == 'noMore') {
+				return;
+			}
+			if (type == 'tabChange' && navItem.loaded == 'loaded') {
+				return;
+			}
+			navItem.loadingType == 'loading';
+			integral({
+				page: navItem.page,
+				limit: navItem.limit,
+				pm: navItem.state
+			}).then(res => {
+				navItem.orderList = navItem.orderList.concat(res.data);
+				if (navItem.limit == res.data.length) {
+					navItem.loadingType = 'more';
+					return;
+				} else {
+					navItem.loadingType = 'noMore';
+				}
+				uni.hideLoading();
+				this.$set(navItem, 'loaded', true);
+			});
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+.container {
+	width: 750rpx;
+	background-color: #f1f1f1;
+
+	.header {
+		position: relative;
+		image {
+			width: 750rpx;
+			height: 400rpx;
+		}
+
+		.money {
+			font-size: 72rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: #fff;
+			position: absolute;
+			top: 50%;
+			left: 50%;
+			transform: translate(-50%, -50%);
+		}
+	}
+
+	
+
+	
+
+	.navbar {
+		display: flex;
+		height: 100rpx;
+		padding: 0 5rpx;
+		background: #fff;
+		box-shadow: 0 1rpx 5rpx rgba(0, 0, 0, 0.06);
+		position: relative;
+		z-index: 10;
+		margin-top: 25rpx;
+
+		.nav-item {
+			flex: 1;
+			display: flex;
+			justify-content: center;
+			align-items: center;
+			height: 100%;
+			font-size: 15px;
+			color: #999999;
+			position: relative;
+
+			&.current {
+				color: #333333;
+
+				&:after {
+					content: '';
+					position: absolute;
+					left: 50%;
+					bottom: 0;
+					transform: translateX(-50%);
+					width: 44px;
+					height: 0;
+					border-bottom: 2px solid #ff4c4c;
+				}
+			}
+		}
+	}
+
+	.cost {
+		width: 750rpx;
+		height: auto;
+		background-color: #fff;
+
+		.award {
+			width: 100%;
+			border-bottom: 1px solid #f0f4f8;
+			padding: 20rpx 25rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+
+			.award-left {
+				width: 60%;
+				.text {
+					width: 100%;
+					font-size: 30rpx;
+					font-family: PingFang SC;
+					font-weight: bold;
+					color: #666666;
+					margin-bottom: 16rpx;
+				}
+
+				.time {
+					font-size: 26rpx;
+					font-family: PingFang SC;
+					font-weight: 500;
+					color: #aeaeae;
+				}
+			}
+
+			.award-right {
+				font-size: 36rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #ff0000;
+				margin-right: 30rpx;
+			}
+		}
+	}
+}
+.swiper-box {
+		// height: calc(100% - 536rpx);
+		background-color: #fff;
+	}
+</style>
+

+ 431 - 0
pages/vip/fwbDetail.vue

@@ -0,0 +1,431 @@
+<template>
+	<view class="content">
+		<view class="top-wrap">
+			<view class="top-bg">
+				
+			</view>
+			<view class="user-data flex">
+				<view class="data" @click="navto('/pages/vip/contract')">
+					<view class="data-val">200</view>
+					<view class="data-tit">合约收益</view>
+				</view>
+				<view class="data" @click="navto('/pages/vip/extension')">
+					<view class="data-val">200</view>
+					<view class="data-tit">推广收益</view>
+				</view>
+				<view class="data" @click="navto('/pages/vip/mytz')">
+					<view class="data-val">200</view>
+					<view class="data-tit">我的通证</view>
+				</view>
+				<view class="data" @click="navto('/pages/user/integral')">
+					<view class="data-val">200</view>
+					<view class="data-tit">我的积分</view>
+				</view>
+			</view>
+		</view>
+		<view class="fwb-logo">
+			<image src="../../static/img/fwb.png" mode=""></image>
+		</view>
+		<scroll-view scroll-y="true" :style="{'height': height}" class="scoll-wrap" @scrolltolower="loadData()">
+			<view class="buy-item" v-for="item in list">
+				<view class="item-top">
+					<view class="top-left">
+						<image src="../../static/icon/mrlogo.png" mode=""></image><text class="top-name clamp">{{item.name || ''}}</text>
+					</view>
+					<view class="top-right">
+						{{item.status}}
+					</view>
+				</view>
+				<view class="item-info">
+					<view class="info-data">
+						<view class="info-tit">收益:</view>
+						<view class="info-val">{{item.day}}天/{{item.proportion}}%</view>
+					</view>
+					<!-- <view class="info-data">
+						<view class="info-tit">开始时间:</view>
+						<view class="info-val">10:20</view>
+					</view> -->
+					<view class="info-data">
+						<view class="info-tit">可获通证:</view>
+						<view class="info-val">{{item.pass}}%</view>
+					</view>
+					<!-- <view class="info-data">
+						<view class="info-tit">终止释放时间:</view>
+						<view class="info-val">10:20</view>
+					</view> -->
+					<view class="info-data">
+						<view class="info-tit">预约人数:</view>
+						<view class="info-val">{{item.cts}}</view>
+					</view>
+					<view class="info-data">
+						<view class="info-tit">价值:</view>
+						<view class="info-val">{{item.price}}</view>
+					</view>
+				</view>
+				<view class="mc-btn yy could" @click="packageReserve(item)">
+					立即预约
+				</view>
+				<view class="mc-btn pass could" @click="packageExchange(item,2)">
+					合约兑换
+				</view>
+				<view class="mc-btn fail" :class="{'could':item.am == 0}" @click="item.am == 0?packageExchange(item,1):''">
+					推广兑换
+				</view>
+			</view>
+			<uni-load-more :status="loadingType"></uni-load-more>
+		</scroll-view>
+		<view class="btm-btn flex">
+			<view class="btm-left flex"  @click="navto('/pages/appointment/appointment')">
+				<image src="../../static/icon/myyy.png" mode=""></image>
+				<view class="">
+					我的预约
+				</view>
+			</view>
+			<view class="btm-right" style="background-color: #FFB238;" @click="navto('/pages/sellout/sellout')">
+				卖出
+			</view>
+			<view class="btm-right" style="background-color: #FF4C4C;"  @click="navto('/pages/purchase/purchase')">
+				买入
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { getPackageList, packageReserve, packageExchange } from '@/api/package.js'
+	import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
+	import { mapState, mapMutations } from 'vuex';
+	
+	export default {
+		computed:{
+			...mapState('user',['userInfo'])
+		},
+		components: {
+			uniLoadMore,
+		},
+		data() {
+			return {
+				height: '',
+				list: [],
+				loadingType: 'more',
+				page: 1,
+				limit: 10,
+				// loaded: false,
+				
+			}
+		},
+		onReady(res) {
+			var obj = this;
+			uni.getSystemInfo({
+				success: resu => {
+					const query = uni.createSelectorQuery();
+					query.select('.scoll-wrap').boundingClientRect();
+					query.exec(function(res) {
+						console.log(res, 'ddddddddddddd');
+						obj.height = resu.windowHeight - res[0].top + 'px';
+						console.log('打印页面的剩余高度', obj.height);
+					});
+				},
+				fail: res => {}
+			});
+		},
+		onLoad() {
+			// this.getPackageList()
+			console.log(this.userInfo)
+			this.loadData()
+		},
+		methods: {
+			getPackageList() {
+				getPackageList().then(res => {
+					console.log(res,'getPackageList')
+				})
+			},
+			navTo(url) {
+				uni.switchTab({
+					url: url
+				})
+			},
+			navto(url) {
+				console.log('dianji ')
+				uni.navigateTo({
+					url: url
+				})
+			},
+			loadData() {
+				let obj = this
+				if(obj.loadingType == 'noMore' || obj.loadingType == 'loading') {
+					return 
+				}
+				obj.loadingType = 'loading'
+				getPackageList({
+					page: obj.page,
+					limit: obj.limit
+				}).then(({data}) => {
+					// console.log(res,'getPackageList')
+					obj.list = obj.list.concat(data)
+					console.log(obj.list,'dd')
+					obj.page++
+					if(obj.limit == data.length) {
+						obj.loadingType = 'more'
+					}else {
+						obj.loadingType = 'noMore'
+					}
+				})
+			},
+			// 兑换包
+			packageExchange(item,type) {
+				console.log(item)
+				// this.judgeBase()
+				packageExchange({
+					package_manager: item.id,
+					type: type,
+					price: item.price,
+					day: item.day,
+					proportion: item.proportion,
+					pass: item.pass,
+					consume_pass: item.consume_pass
+				}).then( res => {
+					console.log(res)
+					uni.showToast({
+						title:'兑换成功',
+						duration:2000
+					});
+				}).catch(err => {
+					console.log(err)
+				})
+			},
+			//预约包
+			packageReserve(item) {
+				// this.judgeBase()
+				packageReserve({
+					package_manager: item.id,
+					price: item.price,
+					day: item.day,
+					proportion: item.proportion,
+					pass: item.pass
+				}).then(res => {
+					uni.showToast({
+						title:'预约成功',
+						duration:2000
+					});
+					console.log(res)
+				}).catch(err => {
+					console.log(err)
+				})
+			},
+			//判断是否由基本信息
+			judgeBase() {
+				let obj = this
+				console.log(obj.userInfo.wx_qr,'obj.userInfo.wx_qr')
+				if(obj.userInfo.wx_qr) {
+					console.log('hhhhhh')
+					console.log(obj.userInfo.wx_qr)
+				}else {
+					console.log(obj.userInfo.wx_qr,'console.log(obj.userInfo.wx_qr)')
+					// obj.$api.msg('修改成功');
+					setTimeout(()=> {
+						uni.navigateTo({
+							url:'/pages/set/userdata'
+						})
+					}, 1000);
+					return
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.top-wrap {
+		position: relative;
+		.top-bg {
+			width: 750rpx;
+			height: 100rpx;
+			background: linear-gradient(30deg, #FF4C4C, #FE6238);
+			border-radius: 0 0 10rpx 10rpx;
+			position: absolute;
+			top: 0;
+		}
+		padding-top: 20rpx;
+		.user-data {
+			width: 710rpx;
+			height: 165rpx;
+			background: #FFFFFF;
+			box-shadow: 0px 0px 20rpx 0px rgba(50, 50, 52, 0.06);
+			border-radius: 20rpx;
+			margin: auto;
+			position: relative;
+			.data {
+				display: flex;
+				width: 25%;
+				flex-direction: column;
+				justify-content: center;
+				align-items: center;
+				
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #666666;
+				position: relative;
+				.data-val {
+					font-size: 36rpx;
+				}
+				.data-tit {
+					font-size: 26rpx;
+					padding-top: 10rpx;
+				}
+				&::after {
+					content: '';
+					width: 1px;
+					height: 36rpx;
+					background: #d6d6d6;
+					position: absolute;
+					right: 0;
+					top: 0;
+					bottom: 0;
+					margin: auto;
+				}
+				&:last-of-type {
+					&::after {
+						background: #fff;
+					}
+				}
+			}
+		}
+	}
+	.fwb-logo {
+		height: 99rpx;
+		display: flex;
+		justify-content: space-around;
+		align-items: center;
+		image {
+			width: 374rpx;
+			height: 33rpx;
+		}
+	}
+	.buy-item {
+		width: 690rpx;
+		height: 300rpx;
+		margin: 0 auto 20rpx;
+		background: #FFFFFF;
+		box-shadow: 0px 0px 17rpx 0px rgba(0, 0, 0, 0.05);
+		border-radius: 20rpx;
+		padding: 26rpx 30rpx;
+		position: relative;
+		.item-top {
+			display: flex;
+			justify-content: space-between;
+			height: 50rpx;
+			.top-left {
+				font-size: 34rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #0F253A;
+				line-height: 50rpx;
+				display: flex;
+				align-items: center;
+				image {
+					width: 48rpx;
+					height: 46rpx;
+				}
+				.top-name {
+					width: 450rpx;
+					padding-left: 11rpx;
+				}
+			}
+			.top-right {
+				line-height: 50rpx;
+				width: 100rpx;
+				text-align: right;
+				font-size: 26rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #6D7C88;
+			}
+		}
+		.item-info {
+			width: 100%;
+			margin-top: 28rpx;
+			line-height: 50rpx;
+			font-size: 26rpx;
+			font-family: PingFang SC;
+			display: flex;
+			flex-wrap: wrap;
+			.info-data {
+				width: 50%;
+				display: flex;
+				.info-tit {
+					
+					font-weight: 500;
+					color: #6D7C88;
+				}
+				.info-val {
+					color: #0F253A;
+					font-weight: bold;
+				}
+			}
+			
+		}
+		.mc-btn {
+			width: 144rpx;
+			line-height: 50rpx;
+			border-radius: 25px;
+			background: #FFFFFF;
+			font-size: 26rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			text-align: center;
+			position: absolute;
+			bottom: 25rpx;
+			color: #999999;
+			border: 2px solid #EBEBEB;
+		}
+		.yy {
+			right: 344rpx;
+		}
+		.pass {
+			right: 190rpx;
+		}
+		.fail {
+			right: 36rpx;
+		}
+		.could{
+			color: #FF4C4C;
+			border: 2px solid #FF4C4C;
+		}
+		.cant {
+			color: #999999;
+			border: 2px solid #EBEBEB;
+		}
+	}
+	.scoll-wrap {
+		padding-bottom: 120rpx;
+	}
+	.btm-btn {
+		height: 100rpx;
+		position: fixed;
+		bottom: 0;
+		.btm-left {
+			flex-direction: column;
+			justify-content: center;
+			align-items: center;
+			height: 100rpx;
+			width: 136rpx;
+			image {
+				width: 48rpx;
+				height: 48rpx;
+				background-color: #fff;
+			}
+		}
+		.btm-right {
+			width: 307rpx;
+			height: 100rpx;
+			background: #FFB238;
+			text-align: center;
+			color: #fff;
+			font-size: 34rpx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			line-height: 100rpx;
+		}
+	}
+</style>

+ 377 - 0
pages/vip/mytz.vue

@@ -0,0 +1,377 @@
+<template>
+	<view class="content">
+		<view class="content-money">
+			<view class="money-box">
+				<image src="../../static/img/tzbg.png" mode=""></image>
+				<view class="money"><text class="money-icon">¥</text>{{ userInfo.now_money | getMoneyStyle }}</view>
+				<view class="tzzz" @click="navto('/pages/vip/tzzz')">
+					通证转账
+				</view>
+			</view>
+		</view>
+		<view class="navbar">
+			<view v-for="(item, index) in navList" :key="index" class="nav-item" :class="{ current: tabCurrentIndex === index }" @click="tabClick(index)" v-if="item.text!=='全部'">{{ item.text }}</view>
+		</view>
+		<swiper :current="tabCurrentIndex" :style="{'height':maxheight+'px'}" class="swiper-box" duration="300" @change="changeTab">
+			<swiper-item class="tab-content" v-for="(tabItem, tabIndex) in navList" :key="tabIndex">
+				<scroll-view class="list-scroll-content" scroll-y @scrolltolower="loadData">
+					<!-- 空白页 -->
+					<empty v-if="tabItem.loaded === true && tabItem.orderList.length === 0"></empty>
+
+					<!-- 订单列表 -->
+					<view v-for="(item, index) in tabItem.orderList" :key="index" class="order-item flex">
+						<view class="title-box">
+							<view class="title">
+								<text>{{ item.title }}</text>
+							</view>
+							<view class="time">
+								<text>{{ item.add_time }}</text>
+							</view>
+						</view>
+						<view class="money">
+							<text>{{ (item.pm == 0 ? '-' : '+') + item.number }}</text>
+						</view>
+						<view class="jg"></view>
+					</view>
+					<uni-load-more :status="tabItem.loadingType"></uni-load-more>
+				</scroll-view>
+			</swiper-item>
+		</swiper>
+		<!-- <view class="add-btn" @click="addmoney">立刻充值</view> -->
+	</view>
+</template>
+
+<script>
+import { mapState, mapMutations } from 'vuex';
+import { spreadCommission, userBalance } from '@/api/wallet.js';
+import { getMoneyStyle } from '@/utils/rocessor.js';
+import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
+import empty from '@/components/empty';
+export default {
+	filters: {
+		getMoneyStyle
+	},
+	components: {
+		empty,
+		uniLoadMore
+	},
+	onReady() {
+		// 初始化获取页面宽度
+		uni.createSelectorQuery()
+			.select('.content')
+			.fields(
+				{
+					size: true
+				},
+				data => {
+					console.log(data);
+					console.log(Math.floor((data.width / 750) * 300));
+					// 保存头部高度
+					this.maxheight =data.height - Math.floor((data.width / 750) * 570);
+					console.log(this.maxheight);
+				}
+			)
+			.exec();
+	},
+	data() {
+		return {
+			// 头部图高度
+			maxheight:'',
+			tabCurrentIndex: 0,
+			navList: [
+				{
+					state: 2,
+					text: '收入',
+					loadingType: 'more',
+					orderList: [],
+					page: 1, //当前页数
+					limit: 10 //每次信息条数
+				},
+				{
+					state: 1,
+					text: '支出',
+					loadingType: 'more',
+					orderList: [
+					],
+					page: 1, //当前页数
+					limit: 10 //每次信息条数
+				},
+				
+			],
+			money: ''
+		};
+	},
+	computed: {
+		...mapState('user', ['userInfo', 'orderInfo', 'hasLogin'])
+	},
+	onLoad(options) {},
+	onShow() {
+		this.loadData();
+		// 获取用户余额
+		
+	},
+	methods: {
+		// 页面跳转
+		navto(e) {
+			uni.navigateTo({
+				url: e
+			});
+		},
+		//获取收入支出信息
+		async loadData(source) {
+			//这里是将订单挂载到tab列表下
+			let index = this.tabCurrentIndex;
+			let navItem = this.navList[index];
+			let state = navItem.state;
+			if (source === 'tabChange' && navItem.loaded === true) {
+				//tab切换只有第一次需要加载数据
+				return;
+			}
+			if (navItem.loadingType === 'loading') {
+				//防止重复加载
+				return;
+			}
+			// 修改当前对象状态为加载中
+			navItem.loadingType = 'loading';
+
+			spreadCommission(
+				{
+					page: navItem.page,
+					limit: navItem.limit
+				},
+				state
+			)
+				.then(({ data }) => {
+					console.log(data);
+					// if (data.count > 0) {
+					// 	navItem.orderList = navItem.orderList.concat(data.list);
+					// 	console.log(navItem.orderList);
+					// 	navItem.page++;
+					// }
+					if (data.length > 0) {
+						navItem.orderList = navItem.orderList.concat(data[0].list);
+						console.log(navItem.orderList);
+						navItem.page++;
+					}
+					if (navItem.limit == data.length) {
+						//判断是否还有数据, 有改为 more, 没有改为noMore
+						navItem.loadingType = 'more';
+						return;
+					} else {
+						//判断是否还有数据, 有改为 more, 没有改为noMore
+						navItem.loadingType = 'noMore';
+					}
+					uni.hideLoading();
+					this.$set(navItem, 'loaded', true);
+					
+				})
+				.catch(e => {
+					console.log(e);
+				});
+		},
+
+		//swiper 切换
+		changeTab(e) {
+			this.tabCurrentIndex = e.target.current;
+			this.loadData('tabChange');
+		},
+		//顶部tab点击
+		tabClick(index) {
+			this.tabCurrentIndex = index;
+		},
+		addmoney() {
+			uni.navigateTo({
+				url: '/pages/money/recharge'
+			})
+		}
+	}
+};
+</script>
+
+<style lang="scss">
+page {
+	background: #ffffff;
+	height: 100%;
+}
+.content-money {
+	padding-bottom: 30rpx;
+	background: $page-color-base;
+	.moneyTx {
+		position: absolute;
+		top: 150rpx;
+		right: 0rpx;
+		width: 150rpx;
+		padding: 10rpx 30rpx;
+		border: 2px solid #ffffff;
+		border-top-left-radius: 99rpx;
+		border-bottom-left-radius: 99rpx;
+		color: #ffffff;
+		line-height: 1;
+		font-size: $font-base;
+	}
+	.buttom-box {
+		background-color: #ffffff;
+		text-align: center;
+		margin: 0 30rpx;
+		padding: 20rpx 0;
+		border-radius: $border-radius-sm;
+		margin-top: -60rpx;
+		.buttom {
+			font-size: $font-lg;
+			flex-grow: 1;
+		}
+		.interval {
+			width: 2px;
+			height: 60rpx;
+			background-color: #eeeeee;
+		}
+		.icon {
+			height: 50rpx;
+			width: 48rpx;
+			margin: 0 auto;
+			.icon-img {
+				width: 100%;
+				height: 100%;
+			}
+		}
+	}
+}
+.money-box {
+	// background-color: $base-color;
+	// padding-top: var(--status-bar-height);
+	height: 400rpx;
+	color: #FF4C4C;
+	text-align: center;
+	position: relative;
+	.tzzz {
+		width: 139rpx;
+		line-height: 50rpx;
+		background: #fff;
+		border-radius: 7rpx;
+		position: absolute;
+		top: 20rpx;
+		right: 0;
+		text-align: center;
+		font-size: 26rpx;
+		font-family: PingFang SC;
+		font-weight: bold;
+		color: #E83F30;
+	}
+	image {
+		position: absolute;
+		top: 0;
+		right: 0;
+		height: 100%;
+		width: 100%;
+		// z-index: 1;
+	}
+	.text {
+		padding-top: 147rpx;
+		font-size: $font-sm;
+		position: relative;
+	}
+	.money {
+		padding-top: 175rpx;
+		// margin: auto 0;
+		font-size: 56rpx;
+		font-weight: bold;
+		color: #fff;
+		position: relative;
+		.money-icon {
+			font-size: 38rpx;
+			font-weight: bold;
+			color: #Fff;
+		}
+	}
+}
+
+.navbar {
+	display: flex;
+	height: 40px;
+	padding: 0 5px;
+	background: #fff;
+	box-shadow: 0 1px 5px rgba(0, 0, 0, 0.06);
+	position: relative;
+	z-index: 10;
+	.nav-item {
+		flex: 1;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		height: 100%;
+		font-size: 15px;
+		color: #999999;
+		position: relative;
+		&.current {
+			color: $base-color;
+			&:after {
+				content: '';
+				position: absolute;
+				left: 50%;
+				bottom: 0;
+				transform: translateX(-50%);
+				width: 44px;
+				height: 0;
+				border-bottom: 2px solid $base-color;
+			}
+		}
+	}
+}
+// 列表
+
+.swiper-box {
+	padding-top: 10rpx;
+	.order-item {
+		padding: 20rpx 30rpx;
+		line-height: 1.5;
+		position: relative;
+		// border-bottom: 1rpx black solid;
+		.title-box {
+			.title {
+				font-size: $font-lg;
+				color: $font-color-base;
+			}
+			.time {
+				font-size: $font-base;
+				color: $font-color-light;
+			}
+		}
+		.money {
+			// color: #fd5b23;
+			color: #901B21;
+			font-size: $font-lg;
+		}
+		.jg {
+			width: 701rpx;
+			height: 2rpx;
+			background: #F0F4F8;
+			margin: 0 auto;
+			position: absolute;
+			bottom: 0;
+		}
+	}
+}
+.list-scroll-content {
+	height: 100%;
+}
+.content {
+	height: 100%;
+	.empty-content {
+		background-color: #ffffff;
+	}
+}
+.add-btn {
+	position: fixed;
+	bottom: 51rpx;
+	right: 39rpx;
+	width: 674rpx;
+	height: 88rpx;
+	background: $base-color;
+	border-radius: 44rpx;
+	color: #fff;
+	text-align: center;
+	line-height: 88rpx;
+	font-size: 34rpx;
+}
+</style>
+

+ 82 - 0
pages/vip/success.vue

@@ -0,0 +1,82 @@
+<template>
+ <view class="container">
+<!--   <view class="top">
+   <view class="bg">
+    <image src="../../static/img/submit.png" mode=""></image>
+   </view>
+  </view>
+  <view class="between">
+   提交成功
+  </view>
+  <view class="bottom">
+   返回首页
+  </view> -->
+  <view class="re-succ-box">
+   <image class="re-succ-img" src="../../static/img/success.png" mode=""></image>
+   <view class="re-succ-tit">提交成功</view>
+   <view class="re-succ-btn" @click="goBack()">
+    返回首页
+   </view>
+  </view>
+ </view>
+</template>
+
+<script>
+	export default{
+		methods: {
+			goBack(){
+				uni.switchTab({
+					url:'/pages/index/index'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+page {
+ height: 100%;
+}
+.container{
+ height: 100%;
+ background: #FFFFFF;
+ // .line-top{
+ //  width: 750rpx;
+ //  height: 20rpx;
+ //  background: #F5F5F5;
+ // }
+ .re-succ-box {
+  padding-top: 170rpx;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  .re-succ-img{
+   margin-left: -50rpx;
+   width: 320rpx;
+   height:260rpx;
+   display: block;
+  }
+  .re-succ-tit{
+   margin-top: -26rpx;
+   font-size: 40rpx;
+   font-family: PingFang SC;
+   font-weight: 500;
+  }
+  .re-succ-btn {
+   margin-top: 80rpx;
+   width: 350rpx;
+   height: 80rpx;
+   background: linear-gradient(-35deg, #F8DD4F, #FBEB77);
+   border-radius: 40rpx;
+   font-size: 36rpx;
+   font-family: PingFang SC;
+   
+   
+   display: flex;
+   align-items: center;
+   justify-content: center;
+  }
+ }
+}
+ 
+</style>

+ 89 - 0
pages/vip/tzzz.vue

@@ -0,0 +1,89 @@
+<template>
+	<view class="content">
+		<view class="jg" style="height: 20rpx;"></view>
+		<view class="user-info">
+			<view class="money">300</view>
+			<view class="can-move">
+				可转账通证
+			</view>
+		</view>
+		<view class="to-user">
+			<view class="to-tit">
+				收款人账户
+			</view>
+			<input type="text" v-model="touser_id" placeholder="请输入收款人账户"/>
+		</view>
+		<view class="to-user">
+			<view class="to-tit">
+				转账数量
+			</view>
+			<input type="text" v-model="touser_num" placeholder="请输入转账数量"/>
+		</view>
+		<view class="btn">
+			提交申请
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		methods: {
+			
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.user-info {
+		width: 750rpx;
+		height: 139rpx;
+		background: #FFFFFF;
+		text-align: center;
+		.money {
+			padding-top: 25rpx;
+			font-size: 42rpx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			color: #333333;
+		}
+		.can-move {
+			font-size: 28rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: #666666;
+		}
+	}
+	.to-user {
+		margin-top: 20rpx;
+		width: 750rpx;
+		height: 160rpx;
+		background: #FFFFFF;
+		padding: 36rpx 25rpx;
+		.to-tit {
+			font-size: 30rpx;
+			font-family: PingFang SC;
+			font-weight: 400;
+			color: #333333;
+			padding-bottom: 25rpx;
+		}
+	}
+	.btn {
+		
+		width: 630rpx;
+		line-height: 90rpx;
+		margin: auto;
+		margin-top: 120rpx;
+		background: #ff4c4c;
+		border-radius: 10rpx;
+		font-size: 36rpx;
+		font-family: PingFang SC;
+		font-weight: bold;
+		color: #FFFFFF;
+		text-align: center;
+	}
+</style>

+ 399 - 0
pages/vip/vip.vue

@@ -0,0 +1,399 @@
+<template>
+	<view class="contet">
+		<!-- <view class="jg" style="height: 20rpx;background-color: #fff;"></view> -->
+		<view class="" style="background-color: #fff;padding-top: 40rpx;position: relative;">
+			<image src="../../static/img/ktbg.png" mode="" style="position: absolute;top: 0;width: 750rpx;height: 200rpx;"></image>
+			<view class="card" style="position: relative;">
+				<view class="card-top flex">
+					<view class="avtur"><image :src="userInfo.avatar || '/static/error/missing-face.png'" mode=""></image></view>
+					<view class="main">
+						<view class="name">{{ userInfo.nickname }}</view>
+						<view class="tip" v-if="userInfo.level == 0">尚未开通会员</view>
+					</view>
+				</view>
+				<view class="now-wrap">
+					立即开通
+				</view>
+				<view class="card-info">
+					<view class="info-tit">
+						会员卡
+					</view>
+					<view class="info-val">
+						100通行证 终身付费会员
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="hyjl">
+			<view class="jl-tit">会员奖励</view>
+			<view class="tool flex">
+				<view class="tool-item">
+					<view class="tool-img"><image src="../../static/icon/kt1.png" mode=""></image></view>
+					<view class="tool-name">佣金奖励</view>
+				</view>
+				<view class="tool-item" >
+					<view class="tool-img"><image src="../../static/icon/kt2.png" mode=""></image></view>
+					<view class="tool-name">专属折扣</view>
+				</view>
+				<view class="tool-item" >
+					<view class="tool-img"><image src="../../static/icon/kt3.png" mode=""></image></view>
+					<view class="tool-name">专属服务</view>
+				</view>
+				<view class="tool-item" >
+					<view class="tool-img"><image src="../../static/icon/kt4.png" mode=""></image></view>
+					<view class="tool-name">团队奖励</view>
+				</view>
+			</view>
+		</view>
+		<view class="hyjl" style="padding-bottom: 20rpx;">
+			<view class="jl-tit">会员优选</view>
+			<view class="tool flex">
+				<view class="tool-item1">
+					<view class="tool-name">会员独享</view>
+					<view class="tool-name bold">优惠价</view>
+					<view class="tool-img"><image src="../../static/icon/kt5.png" mode=""></image></view>
+				</view>
+				<view class="tool-item1" >
+					<view class="tool-name">会员专属</view>
+					<view class="tool-name bold">专属服务包</view>
+					<view class="tool-img"><image src="../../static/icon/kt6.png" mode=""></image></view>
+					
+				</view>
+				<view class="tool-item1" >
+					<view class="tool-name">推广得</view>
+					<view class="tool-name bold">更多佣金</view>
+					<view class="tool-img"><image src="../../static/icon/kt7.png" mode=""></image></view>
+					
+				</view>
+			</view>
+		</view>
+		<view class="bottom-btn">
+			<view class="btm-left">
+				永久付费会员100通行证
+			</view>
+			<view class="btm-right" @click="readyPay()">
+				马上开通
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { becomeVip, getVip, setUserRed, claseauto } from '@/api/user.js';
+	import { mapState, mapMutations } from 'vuex';
+	import { getUserInfo } from '@/api/user.js';
+	export default {
+		computed: {
+			...mapState('user', ['userInfo', 'orderInfo', 'hasLogin'])
+		},
+		data() {
+			return {
+				
+			}
+		},
+		onLoad() {
+			
+		},
+		methods:{
+			...mapMutations('user', ['setUserInfo', 'setOrderInfo']),
+			getUserInfoB() {
+				getUserInfo({})
+					.then(({ data }) => {
+						this.setUserInfo(data);
+						if(data.wx_qr) {
+							uni.navigateTo({
+								url: '/pages/vip/success'
+							});
+						}else {
+							this.$api.msg('请完善会员信息')
+							setTimeout(()=> {
+								uni.navigateTo({
+									url:'/pages/set/userdata'
+								});
+							}, 1000);
+						}
+						
+					})
+					.catch(e => {
+						console.log(e);
+					});
+			},
+			// 开通会员
+			readyPay() {
+				let obj = this;
+				if(obj.userInfo.level > 0) {
+					return obj.$api.msg('您已开通会员')
+				}
+				console.log('点击');
+				try {
+					let obj = this;
+					obj.payLoding = true;
+					// #ifdef H5
+					// 获取当前是否为微信浏览器
+					obj.froms = uni.getStorageSync('weichatBrowser') || '';
+					// #endif
+					uni.showLoading({
+						title: '支付中',
+						mask: true
+					});
+					let data = {
+						pay_type: 'yue',
+						level_id: 1,
+						// #ifdef H5
+						from: obj.froms ? 'weixin' : 'H5', //来源
+						// #endif
+						// #ifdef MP-WEIXIN
+						from: 'routine', //来源
+						// #endif
+						// #ifdef APP-PLUS
+						from: 'app' //来源
+						// #endif
+					};
+					console.log(data, '传值');
+					becomeVip(data).then(({ data }) => {
+						console.log('fufei', data);
+						uni.hideLoading();
+						
+						if (data.status == 'PAY_ERROR') {
+							console.log(data);
+						}
+						if (data.status == 'SUCCESS') {
+							
+							obj.getUserInfoB();
+						}
+						console.log('-----', data);
+						let da = data.result.jsConfig;
+						if (obj.payName == 'weixin' || obj.payName == 'routine') {
+							// let da = data.result.jsConfig;
+							console.log('--da--', da);
+							let data = {
+								// #ifdef H5
+								timestamp: da.timestamp,
+								// #endif
+								// #ifdef MP
+								timeStamp: da.timestamp,
+								// #endif
+								nonceStr: da.nonceStr,
+								package: da.package,
+								signType: da.signType,
+								paySign: da.paySign,
+								success: function(res) {
+									console.log(res);
+									obj.getUserInfoB();
+								},
+								fail: e => {
+									console.log(e);
+								}
+							};
+							console.log('--data--', data);
+							// #ifdef MP
+							wx.requestPayment(data);
+							// #endif
+							// #ifdef H5
+							if (obj.payName == 'weixin') {
+								weixinObj.chooseWXPay(data);
+							}
+							// #endif
+						}
+				
+						uni.hideLoading();
+						// #ifdef H5
+						if (data.status == 'PAY_ERROR') {
+							console.log(data);
+						}
+						if (data.status == 'SUCCESS') {
+							
+							obj.getUserInfoB();
+						}
+						// #endif
+					});
+				} catch (e) {
+					console.log('fufiecw', e);
+					//TODO handle the exception
+				}
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.card {
+		position: relative;
+		margin: auto;
+		z-index: 10;
+		width: 655rpx;
+		height: 324rpx;
+		background: linear-gradient(225deg, #ffeed2 0%, #fed591 100%);
+		border-radius: 24rpx;
+		padding: 28rpx 25rpx 30rpx 36rpx;
+		.now-wrap {
+			width: 190rpx;
+			line-height: 69rpx;
+			background: #C09852;
+			border-radius: 35rpx;
+			position: absolute;
+			top:39rpx;
+			right: 25rpx;
+			font-size: 30rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: #F6DCA9;
+			text-align: center;
+			
+		}
+		.card-top {
+			justify-content: flex-start;
+			.avtur {
+				width: 90rpx;
+				height: 90rpx;
+				border-radius: 50%;
+				margin-right: 10rpx;
+				image {
+					width: 100%;
+					height: 100%;
+					border-radius: 50%;
+				}
+			}
+			.name {
+				font-size: 30rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #333333;
+			}
+			.tip {
+				font-size: 20rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #333333;
+				opacity: 0.52;
+			}
+		}
+		.btn {
+			position: absolute;
+			top: 40rpx;
+			right: 24rpx;
+			width: 190rpx;
+			height: 69rpx;
+			background: #3a3a3b;
+			border-radius: 35rpx;
+			font-size: 30rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: #ffffff;
+			line-height: 69rpx;
+			text-align: center;
+		}
+		.card-info {
+			height: 120rpx;
+			position: absolute;
+			bottom: 30rpx;
+			left: 43rpx;
+			.info-tit {
+				line-height: 70rpx;
+				font-size: 40rpx;
+				font-family: PingFang SC;
+				font-weight: bold;
+				color: #333333;
+			}
+			.info-val {
+				font-size: 28rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #343434;
+			}
+		}
+	}
+	.hyjl {
+		background-color: #fff;
+		padding:30rpx 30rpx 0;
+		margin-bottom: 20rpx;
+		.jl-tit {
+			font-size: 36rpx;
+			font-family: PingFang SC;
+			font-weight: 500;
+			color: #000000;
+		}
+	}
+	.tool {
+		flex-wrap: wrap;
+		justify-content: flex-start;
+		align-items: center;
+		.tool-item {
+			width: 25%;
+			height: 160rpx;
+			display: flex;
+			align-items: center;
+			flex-direction: column;
+			justify-content: center;
+			.tool-img {
+				width: 45rpx;
+				height: 45rpx;
+				image {
+					width: 100%;
+					height: 100%;
+				}
+			}
+			.tool-name {
+				padding-top: 20rpx;
+				font-size: 28rpx;
+				font-family: PingFang SC;
+				font-weight: 400;
+				color: #505050;
+			}
+		}
+		.tool-item1 {
+			background: #FAFBFF;
+			display: flex;
+			align-items: center;
+			flex-direction: column;
+			justify-content: center;
+			width: 222rpx;
+			height: 298rpx;
+			background: #FAFBFF;
+			border-radius: 10rpx;
+			.tool-name {
+				font-size: 30rpx;
+				font-family: PingFang SC;
+				font-weight: 500;
+				color: #7B7B7B;
+			}
+			.bold {
+				font-weight: bold;
+				color: #000;
+			}
+			.tool-img {
+				width: 157rpx;
+				height: 112rpx;
+				margin-top: 37rpx;
+				image {
+					width: 100%;
+					height: 100%;
+				}
+			}
+		}
+		
+	}
+	.bottom-btn {
+		display: flex;
+		align-items: flex-end;
+		position: fixed;
+		bottom: 0;
+		text-align: center;
+		.btm-left {
+			width: 750rpx - 280rpx;
+			line-height: 100rpx;
+			background-color: #34332F;
+			color: #fff;
+		}
+		.btm-right {
+			width: 280rpx;
+			line-height: 108rpx;
+			
+			background: #EFD4A1;
+			font-size: 36rpx;
+			font-family: PingFang SC;
+			font-weight: bold;
+			color: #5A5A5A;
+		}
+	}
+</style>

BIN
static/icon/c3.png


BIN
static/icon/c5.png


BIN
static/icon/c7.png


BIN
static/icon/c8.png


BIN
static/icon/close.png


BIN
static/icon/code.png


BIN
static/icon/g1.png


BIN
static/icon/g2.png


BIN
static/icon/g3.png


BIN
static/icon/g4.png


BIN
static/icon/g5.png


BIN
static/icon/g6.png


BIN
static/icon/g7.png


BIN
static/icon/g8.png


BIN
static/icon/kt1.png


BIN
static/icon/kt2.png


BIN
static/icon/kt3.png


BIN
static/icon/kt4.png


BIN
static/icon/kt5.png


BIN
static/icon/kt6.png


BIN
static/icon/kt7.png


BIN
static/icon/mrlogo.png


BIN
static/icon/myyy.png


BIN
static/icon/phone.png


BIN
static/icon/pswd.png


BIN
static/icon/tg.png


BIN
static/img/fwb.png


BIN
static/img/hybg.png


BIN
static/img/img17.png


BIN
static/img/jfbg.png


BIN
static/img/ktbg.png


BIN
static/img/success.png


BIN
static/img/teambg.png


BIN
static/img/tgbg.png


BIN
static/img/tzbg.png


BIN
static/img/upimg.png


BIN
static/tabBar/tab-cart-current.png


BIN
static/tabBar/tab-cart.png


BIN
static/tabBar/tab-cate-current.png


BIN
static/tabBar/tab-cate.png


BIN
static/tabBar/tab-home-current.png


BIN
static/tabBar/tab-home.png


BIN
static/tabBar/tab-my-current.png


BIN
static/tabBar/tab-my.png


+ 1 - 1
store/index.js

@@ -7,7 +7,7 @@ const store = new Vuex.Store({
 	namespaced: true,
 	state: {
 		// baseURL:"http://yrh.liuniu946.com",//'http://eb.shuibo.net',//请求地址配置 
-		baseURL:'http://shop.zhengyjk1994.com',//请求地址配置 
+		baseURL:'http://fb.frp.liuniu946.com',//请求地址配置 
 		urlFile:'/index',//项目部署所在文件夹
 		userInfo: {}, //登录信息
 		loginInterceptor:false,//是否打开强制登录

+ 2 - 1
uni.scss

@@ -1,10 +1,11 @@
+@import 'uview-ui/theme.scss';
 /* 页面左右间距 */
 $page-row-spacing: 30rpx;
 //页面基础颜色
 $page-color-base: #f8f8f8;//页面背景颜色
 $page-color-light: #f8f6fc;
 // 主题颜色
-$base-color: #6EAB4E;//项目颜色
+$base-color: #ff4343;//项目颜色
 $box-shadow-color:#5dbc7c;//阴影颜色
 $font-color:#5dbc7c;//字体颜色
 $font-color-spec: #5dbc7c;//可操作文字颜色

+ 25 - 25
unpackage/dist/dev/app-plus/__uniappview.html

@@ -1,25 +1,25 @@
-<!DOCTYPE html>
-<html lang="zh-CN">
-
-  <head>
-    <meta charset="UTF-8" />
-    <script>
-      var __UniViewStartTime__ = Date.now();
-      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>View</title>
-    <link rel="stylesheet" href="view.css" />
-  </head>
-
-  <body>
-    <div id="app"></div>
-    <script src="__uniappes6.js"></script>
-    <script src="view.umd.min.js"></script>
-    <script src="app-view.js"></script>
-  </body>
-
-</html>
+<!DOCTYPE html>
+<html lang="zh-CN">
+
+  <head>
+    <meta charset="UTF-8" />
+    <script>
+      var __UniViewStartTime__ = Date.now();
+      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>View</title>
+    <link rel="stylesheet" href="view.css" />
+  </head>
+
+  <body>
+    <div id="app"></div>
+    <script src="__uniappes6.js"></script>
+    <script src="view.umd.min.js"></script>
+    <script src="app-view.js"></script>
+  </body>
+
+</html>

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
unpackage/dist/dev/app-plus/app-config-service.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 3 - 3
unpackage/dist/dev/app-plus/app-service.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 206 - 254
unpackage/dist/dev/app-plus/app-view.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
unpackage/dist/dev/app-plus/manifest.json


+ 553 - 553
unpackage/dist/dev/app-plus/static/css/cmy.css

@@ -1,554 +1,554 @@
-/*初始化类*/
-@font-face {
-	font-family: 'iconfont';
-	/* project id 1482221 */
-	src: url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.eot');
-	src: url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.eot?#iefix') format('embedded-opentype'),
-		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.woff2') format('woff2'),
-		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.woff') format('woff'),
-		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.ttf') format('truetype'),
-		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.svg#iconfont') format('svg');
-}
-
-.acea-row {
-	display: -webkit-box;
-	display: -moz-box;
-	display: -webkit-flex;
-	display: -ms-flexbox;
-	display: flex;
-	-webkit-box-lines: multiple;
-	-moz-box-lines: multiple;
-	-o-box-lines: multiple;
-	-webkit-flex-wrap: wrap;
-	-ms-flex-wrap: wrap;
-	flex-wrap: wrap
-}
-
-.acea-row.row-middle {
-	-webkit-box-align: center;
-	-moz-box-align: center;
-	-o-box-align: center;
-	-ms-flex-align: center;
-	-webkit-align-items: center;
-	align-items: center
-}
-
-.bg-color-red {
-	background-color: #e93323 !important;
-}
-
-.acea-row.row-right {
-	-webkit-box-pack: end;
-	-moz-box-pack: end;
-	-o-box-pack: end;
-	-ms-flex-pack: end;
-	-webkit-justify-content: flex-end;
-	justify-content: flex-end
-}
-
-.acea-row.row-between-wrapper {
-	-webkit-box-align: center;
-	-moz-box-align: center;
-	-o-box-align: center;
-	-ms-flex-align: center;
-	-webkit-align-items: center;
-	align-items: center;
-	-webkit-box-pack: justify;
-	-moz-box-pack: justify;
-	-o-box-pack: justify;
-	-ms-flex-pack: justify;
-	-webkit-justify-content: space-between;
-	justify-content: space-between
-}
-
-.acea-row.row-column-around {
-	-webkit-flex-direction: column;
-	-ms-flex-direction: column;
-	flex-direction: column;
-	justify-content: space-around;
-	-webkit-justify-content: space-around
-}
-
-.acea-row.row-center-wrapper {
-	-webkit-box-align: center;
-	-moz-box-align: center;
-	-o-box-align: center;
-	-ms-flex-align: center;
-	-webkit-align-items: center;
-	align-items: center;
-	-webkit-box-pack: center;
-	-moz-box-pack: center;
-	-o-box-pack: center;
-	-ms-flex-pack: center;
-	-webkit-justify-content: center;
-	justify-content: center
-}
-
-.iconfont {
-	font-family: "iconfont" !important;
-	font-size: 34rpx;
-	font-style: normal;
-	-webkit-font-smoothing: antialiased;
-	-webkit-text-stroke-width: 0rpx;
-	-moz-osx-font-smoothing: grayscale;
-}
-
-.iconedit:before {
-	content: "\e649";
-}
-
-.iconfavorfill:before {
-	content: "\e64b";
-}
-
-.iconfavor:before {
-	content: "\e64c";
-}
-
-.iconlocation:before {
-	content: "\e651";
-}
-
-.iconroundcheckfill:before {
-	content: "\e656";
-}
-
-.iconroundcheck:before {
-	content: "\e657";
-}
-
-.iconunfold:before {
-	content: "\e661";
-}
-
-.iconlikefill:before {
-	content: "\e668";
-}
-
-.iconlike:before {
-	content: "\e669";
-}
-
-.iconshop:before {
-	content: "\e676";
-}
-
-.iconcart:before {
-	content: "\e6af";
-}
-
-.icondelete:before {
-	content: "\e6b4";
-}
-
-.iconhome:before {
-	content: "\e6b8";
-}
-
-.iconcartfill:before {
-	content: "\e6b9";
-}
-
-.iconhomefill:before {
-	content: "\e6bb";
-}
-
-.iconlock:before {
-	content: "\e6c0";
-}
-
-.iconfriendadd:before {
-	content: "\e6ca";
-}
-
-.iconfold:before {
-	content: "\e6de";
-}
-
-.iconapps:before {
-	content: "\e729";
-}
-
-.iconadd:before {
-	content: "\e767";
-}
-
-.iconmove:before {
-	content: "\e768";
-}
-
-.icontriangledownfill:before {
-	content: "\e79b";
-}
-
-.icontriangleupfill:before {
-	content: "\e79c";
-}
-
-.iconshaixuan:before {
-	content: "\e74a";
-}
-
-.iconyanzhengma:before {
-	content: "\e684";
-}
-
-.iconjifen:before {
-	content: "\e60f";
-}
-
-.iconwuliuxinxi:before {
-	content: "\e62b";
-}
-
-.iconmessage:before {
-	content: "\e78a";
-}
-
-.iconsetting:before {
-	content: "\e78e";
-}
-
-.iconaddition:before {
-	content: "\e6e0";
-}
-
-.iconclose:before {
-	content: "\e6e9";
-}
-
-.iconenter:after {
-	content: "\e6f8";
-}
-
-.iconprompt:before {
-	content: "\e71b";
-}
-
-.iconreturn:before {
-	content: "\e720";
-}
-
-.iconsearch:before {
-	content: "\e741";
-}
-
-.iconpengyouquan:before {
-	content: "\e62c";
-}
-
-.iconweixin:before {
-	content: "\e60e";
-}
-
-.iconzhifubao:before {
-	content: "\e673";
-}
-
-.iconyue:before {
-	content: "\e618";
-}
-
-.iconweixin1:before {
-	content: "\e622";
-}
-
-.iconlock1:before {
-	content: "\e64d";
-}
-
-.iconuser:before {
-	content: "\e64e";
-}
-
-.iconchenggongtixianshouyi:before {
-	content: "\e64f";
-}
-
-.iconviptuiguangdingdan:before {
-	content: "\e650";
-}
-
-.icondaifukuan:before {
-	content: "\e652";
-}
-
-.icondaijiesuanshouyi:before {
-	content: "\e653";
-}
-
-.icondaidakuanshouyi:before {
-	content: "\e654";
-}
-
-.icondaifahuo:before {
-	content: "\e655";
-}
-
-.icondaishouhuoshouyi:before {
-	content: "\e658";
-}
-
-.icondaishouhuo:before {
-	content: "\e659";
-}
-
-.iconwuxiaoshouyi:before {
-	content: "\e65a";
-}
-
-.icontixianmingxi:before {
-	content: "\e65b";
-}
-
-.iconshouyi:before {
-	content: "\e65c";
-}
-
-.iconkouchutixianshouxufei:before {
-	content: "\e65d";
-}
-
-.iconyishenqingshouyi:before {
-	content: "\e65e";
-}
-
-.icontuihuanhuo:before {
-	content: "\e65f";
-}
-
-
-/*水平线*/
-.hr {
-	width: 100%;
-	position: relative;
-	border-bottom: 1px solid #dddddd;
-	/* height: 0.5rpx; */
-}
-
-/* 一行显示 */
-.clamp {
-	overflow: hidden;
-	text-overflow: ellipsis;
-	white-space: nowrap;
-	display: block;
-}
-
-/* 二行显示 */
-.clamp2 {
-	overflow: hidden;
-	text-overflow: ellipsis;
-	display: -webkit-box;
-	-webkit-line-clamp: 2;
-	-webkit-box-orient: vertical;
-}
-
-/* 二行显示 */
-.ellipsis {
-	overflow: hidden;
-	text-overflow: ellipsis;
-	display: -webkit-box;
-	-webkit-box-orient: vertical;
-	-webkit-line-clamp: 2;
-}
-
-.common-hover {
-	background: #f5f5f5;
-}
-
-/* 角标 */
-.corner {
-	background-color: #e51c23;
-	position: absolute;
-	right: -18rpx;
-	top: -18rpx;
-	color: #FFFFFF;
-	text-align: center;
-	border-radius: 999px;
-	font-size: 24rpx !important;
-	min-width: 35rpx;
-	min-height: 35rpx;
-	display: flex;
-	align-items: center;
-	justify-content: center;
-	line-height: 1;
-}
-
-.flex_item {
-	display: flex;
-	align-items: center;
-	/* justify-content: space-between; */
-}
-
-/* 左右顶格加上下居中 */
-.flex-between-center {
-	display: flex;
-	justify-content: space-between;
-	align-items: center;
-}
-
-/* flex布局-整体居中 */
-.flex-center {
-	display: flex;
-	align-items: center;
-	justify-content: center;
-}
-
-.flex-start {
-	display: flex;
-	align-items: center;
-	justify-content: flex-start;
-}
-
-/*文字对齐*/
-.text-left {
-	text-align: left !important;
-}
-
-.text-center {
-	text-align: center !important;
-}
-
-.text-justify {
-	text-align: justify !important;
-}
-
-.text-right {
-	text-align: right !important;
-}
-
-.text-default {
-	color: #212121 !important;
-}
-
-.text-white {
-	color: #ffffff !important;
-}
-
-.text-primary {
-	color: #00bcd4 !important;
-}
-
-.text-success {
-	color: #009688 !important;
-}
-
-.text-info {
-	color: #03a9f4 !important;
-}
-
-.text-warning {
-	color: #ffc107 !important;
-}
-
-.text-danger {
-	color: #e51c23 !important;
-}
-
-.text-pink {
-	color: #e91e63 !important;
-}
-
-.text-purple {
-	color: #673ab7 !important;
-}
-
-.text-indigo {
-	color: #3f51b5 !important;
-}
-
-.text-gray {
-	color: #999999 !important;
-}
-
-.bg-default {
-	background-color: #f5f5f5 !important;
-}
-
-.bg-primary {
-	background-color: #00bcd4 !important;
-}
-
-.bg-success {
-	background-color: #009688 !important;
-}
-
-.bg-info {
-	background-color: #03a9f4 !important;
-}
-
-.bg-warning {
-	background-color: #FFB238 !important;
-}
-
-.bg-danger {
-	background-color: #DC4D46 !important;
-}
-
-.bg-pink {
-	background-color: #e91e63 !important;
-}
-
-.bg-purple {
-	background-color: #673ab7 !important;
-}
-
-.bg-indigo {
-	background-color: #3f51b5 !important;
-}
-
-.bg-white {
-	background-color: white !important;
-}
-
-.bg-gray {
-	background-color: #e3e3e3 !important;
-}
-
-/* 边框 */
-.border-radius-15 {
-	border-radius: 15rpx;
-}
-
-.border-radius-10 {
-	border-radius: 10rpx;
-}
-
-.border-radius-all {
-	border-radius: 1000rpx;
-}
-
-/* 底部边线 */
-.borde-b {
-	border-bottom: 1px solid #dddddd;
-}
-
-/* 弹性盒子 */
-.flex {
-	display: flex;
-	align-items: center;
-	justify-content: space-between;
-}
-
-.items-left {
-	justify-content: flex-start;
-}
-
-.items-right {
-	justify-content: flex-end;
-}
-
-.flex-shrink-false {
-	flex-shrink: 0;
-}
-
-.flex-grow-true {
-	flex-grow: 1;
-}
-
-.position-relative {
-	position: relative;
-}
-.rich-img {
-		width: 100% !important;
+/*初始化类*/
+@font-face {
+	font-family: 'iconfont';
+	/* project id 1482221 */
+	src: url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.eot');
+	src: url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.eot?#iefix') format('embedded-opentype'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.woff2') format('woff2'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.woff') format('woff'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.ttf') format('truetype'),
+		url('https://at.alicdn.com/t/font_1482221_x9emymthrxs.svg#iconfont') format('svg');
+}
+
+.acea-row {
+	display: -webkit-box;
+	display: -moz-box;
+	display: -webkit-flex;
+	display: -ms-flexbox;
+	display: flex;
+	-webkit-box-lines: multiple;
+	-moz-box-lines: multiple;
+	-o-box-lines: multiple;
+	-webkit-flex-wrap: wrap;
+	-ms-flex-wrap: wrap;
+	flex-wrap: wrap
+}
+
+.acea-row.row-middle {
+	-webkit-box-align: center;
+	-moz-box-align: center;
+	-o-box-align: center;
+	-ms-flex-align: center;
+	-webkit-align-items: center;
+	align-items: center
+}
+
+.bg-color-red {
+	background-color: #e93323 !important;
+}
+
+.acea-row.row-right {
+	-webkit-box-pack: end;
+	-moz-box-pack: end;
+	-o-box-pack: end;
+	-ms-flex-pack: end;
+	-webkit-justify-content: flex-end;
+	justify-content: flex-end
+}
+
+.acea-row.row-between-wrapper {
+	-webkit-box-align: center;
+	-moz-box-align: center;
+	-o-box-align: center;
+	-ms-flex-align: center;
+	-webkit-align-items: center;
+	align-items: center;
+	-webkit-box-pack: justify;
+	-moz-box-pack: justify;
+	-o-box-pack: justify;
+	-ms-flex-pack: justify;
+	-webkit-justify-content: space-between;
+	justify-content: space-between
+}
+
+.acea-row.row-column-around {
+	-webkit-flex-direction: column;
+	-ms-flex-direction: column;
+	flex-direction: column;
+	justify-content: space-around;
+	-webkit-justify-content: space-around
+}
+
+.acea-row.row-center-wrapper {
+	-webkit-box-align: center;
+	-moz-box-align: center;
+	-o-box-align: center;
+	-ms-flex-align: center;
+	-webkit-align-items: center;
+	align-items: center;
+	-webkit-box-pack: center;
+	-moz-box-pack: center;
+	-o-box-pack: center;
+	-ms-flex-pack: center;
+	-webkit-justify-content: center;
+	justify-content: center
+}
+
+.iconfont {
+	font-family: "iconfont" !important;
+	font-size: 34rpx;
+	font-style: normal;
+	-webkit-font-smoothing: antialiased;
+	-webkit-text-stroke-width: 0rpx;
+	-moz-osx-font-smoothing: grayscale;
+}
+
+.iconedit:before {
+	content: "\e649";
+}
+
+.iconfavorfill:before {
+	content: "\e64b";
+}
+
+.iconfavor:before {
+	content: "\e64c";
+}
+
+.iconlocation:before {
+	content: "\e651";
+}
+
+.iconroundcheckfill:before {
+	content: "\e656";
+}
+
+.iconroundcheck:before {
+	content: "\e657";
+}
+
+.iconunfold:before {
+	content: "\e661";
+}
+
+.iconlikefill:before {
+	content: "\e668";
+}
+
+.iconlike:before {
+	content: "\e669";
+}
+
+.iconshop:before {
+	content: "\e676";
+}
+
+.iconcart:before {
+	content: "\e6af";
+}
+
+.icondelete:before {
+	content: "\e6b4";
+}
+
+.iconhome:before {
+	content: "\e6b8";
+}
+
+.iconcartfill:before {
+	content: "\e6b9";
+}
+
+.iconhomefill:before {
+	content: "\e6bb";
+}
+
+.iconlock:before {
+	content: "\e6c0";
+}
+
+.iconfriendadd:before {
+	content: "\e6ca";
+}
+
+.iconfold:before {
+	content: "\e6de";
+}
+
+.iconapps:before {
+	content: "\e729";
+}
+
+.iconadd:before {
+	content: "\e767";
+}
+
+.iconmove:before {
+	content: "\e768";
+}
+
+.icontriangledownfill:before {
+	content: "\e79b";
+}
+
+.icontriangleupfill:before {
+	content: "\e79c";
+}
+
+.iconshaixuan:before {
+	content: "\e74a";
+}
+
+.iconyanzhengma:before {
+	content: "\e684";
+}
+
+.iconjifen:before {
+	content: "\e60f";
+}
+
+.iconwuliuxinxi:before {
+	content: "\e62b";
+}
+
+.iconmessage:before {
+	content: "\e78a";
+}
+
+.iconsetting:before {
+	content: "\e78e";
+}
+
+.iconaddition:before {
+	content: "\e6e0";
+}
+
+.iconclose:before {
+	content: "\e6e9";
+}
+
+.iconenter:after {
+	content: "\e6f8";
+}
+
+.iconprompt:before {
+	content: "\e71b";
+}
+
+.iconreturn:before {
+	content: "\e720";
+}
+
+.iconsearch:before {
+	content: "\e741";
+}
+
+.iconpengyouquan:before {
+	content: "\e62c";
+}
+
+.iconweixin:before {
+	content: "\e60e";
+}
+
+.iconzhifubao:before {
+	content: "\e673";
+}
+
+.iconyue:before {
+	content: "\e618";
+}
+
+.iconweixin1:before {
+	content: "\e622";
+}
+
+.iconlock1:before {
+	content: "\e64d";
+}
+
+.iconuser:before {
+	content: "\e64e";
+}
+
+.iconchenggongtixianshouyi:before {
+	content: "\e64f";
+}
+
+.iconviptuiguangdingdan:before {
+	content: "\e650";
+}
+
+.icondaifukuan:before {
+	content: "\e652";
+}
+
+.icondaijiesuanshouyi:before {
+	content: "\e653";
+}
+
+.icondaidakuanshouyi:before {
+	content: "\e654";
+}
+
+.icondaifahuo:before {
+	content: "\e655";
+}
+
+.icondaishouhuoshouyi:before {
+	content: "\e658";
+}
+
+.icondaishouhuo:before {
+	content: "\e659";
+}
+
+.iconwuxiaoshouyi:before {
+	content: "\e65a";
+}
+
+.icontixianmingxi:before {
+	content: "\e65b";
+}
+
+.iconshouyi:before {
+	content: "\e65c";
+}
+
+.iconkouchutixianshouxufei:before {
+	content: "\e65d";
+}
+
+.iconyishenqingshouyi:before {
+	content: "\e65e";
+}
+
+.icontuihuanhuo:before {
+	content: "\e65f";
+}
+
+
+/*水平线*/
+.hr {
+	width: 100%;
+	position: relative;
+	border-bottom: 1px solid #dddddd;
+	/* height: 0.5rpx; */
+}
+
+/* 一行显示 */
+.clamp {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	display: block;
+}
+
+/* 二行显示 */
+.clamp2 {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-line-clamp: 2;
+	-webkit-box-orient: vertical;
+}
+
+/* 二行显示 */
+.ellipsis {
+	overflow: hidden;
+	text-overflow: ellipsis;
+	display: -webkit-box;
+	-webkit-box-orient: vertical;
+	-webkit-line-clamp: 2;
+}
+
+.common-hover {
+	background: #f5f5f5;
+}
+
+/* 角标 */
+.corner {
+	background-color: #e51c23;
+	position: absolute;
+	right: -18rpx;
+	top: -18rpx;
+	color: #FFFFFF;
+	text-align: center;
+	border-radius: 999px;
+	font-size: 24rpx !important;
+	min-width: 35rpx;
+	min-height: 35rpx;
+	display: flex;
+	align-items: center;
+	justify-content: center;
+	line-height: 1;
+}
+
+.flex_item {
+	display: flex;
+	align-items: center;
+	/* justify-content: space-between; */
+}
+
+/* 左右顶格加上下居中 */
+.flex-between-center {
+	display: flex;
+	justify-content: space-between;
+	align-items: center;
+}
+
+/* flex布局-整体居中 */
+.flex-center {
+	display: flex;
+	align-items: center;
+	justify-content: center;
+}
+
+.flex-start {
+	display: flex;
+	align-items: center;
+	justify-content: flex-start;
+}
+
+/*文字对齐*/
+.text-left {
+	text-align: left !important;
+}
+
+.text-center {
+	text-align: center !important;
+}
+
+.text-justify {
+	text-align: justify !important;
+}
+
+.text-right {
+	text-align: right !important;
+}
+
+.text-default {
+	color: #212121 !important;
+}
+
+.text-white {
+	color: #ffffff !important;
+}
+
+.text-primary {
+	color: #00bcd4 !important;
+}
+
+.text-success {
+	color: #009688 !important;
+}
+
+.text-info {
+	color: #03a9f4 !important;
+}
+
+.text-warning {
+	color: #ffc107 !important;
+}
+
+.text-danger {
+	color: #e51c23 !important;
+}
+
+.text-pink {
+	color: #e91e63 !important;
+}
+
+.text-purple {
+	color: #673ab7 !important;
+}
+
+.text-indigo {
+	color: #3f51b5 !important;
+}
+
+.text-gray {
+	color: #999999 !important;
+}
+
+.bg-default {
+	background-color: #f5f5f5 !important;
+}
+
+.bg-primary {
+	background-color: #00bcd4 !important;
+}
+
+.bg-success {
+	background-color: #009688 !important;
+}
+
+.bg-info {
+	background-color: #03a9f4 !important;
+}
+
+.bg-warning {
+	background-color: #FFB238 !important;
+}
+
+.bg-danger {
+	background-color: #DC4D46 !important;
+}
+
+.bg-pink {
+	background-color: #e91e63 !important;
+}
+
+.bg-purple {
+	background-color: #673ab7 !important;
+}
+
+.bg-indigo {
+	background-color: #3f51b5 !important;
+}
+
+.bg-white {
+	background-color: white !important;
+}
+
+.bg-gray {
+	background-color: #e3e3e3 !important;
+}
+
+/* 边框 */
+.border-radius-15 {
+	border-radius: 15rpx;
+}
+
+.border-radius-10 {
+	border-radius: 10rpx;
+}
+
+.border-radius-all {
+	border-radius: 1000rpx;
+}
+
+/* 底部边线 */
+.borde-b {
+	border-bottom: 1px solid #dddddd;
+}
+
+/* 弹性盒子 */
+.flex {
+	display: flex;
+	align-items: center;
+	justify-content: space-between;
+}
+
+.items-left {
+	justify-content: flex-start;
+}
+
+.items-right {
+	justify-content: flex-end;
+}
+
+.flex-shrink-false {
+	flex-shrink: 0;
+}
+
+.flex-grow-true {
+	flex-grow: 1;
+}
+
+.position-relative {
+	position: relative;
+}
+.rich-img {
+		width: 100% !important;
 	}

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
unpackage/dist/dev/app-plus/view.css


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
unpackage/dist/dev/app-plus/view.umd.min.js


+ 53 - 0
utils/tabbar.js

@@ -0,0 +1,53 @@
+export const tabbar = [
+	{
+		pagePath: "/pages/index/index",
+		iconPath: require('@/static/tabBar/tab-home.png'),
+		selectedIconPath: require("@/static/tabBar/tab-home-current.png"),
+		text: "商城"
+	},
+	{
+		pagePath: "/pages/purchase/purchase",
+		iconPath: require('@/static/tabBar/tab-home.png'),
+		selectedIconPath: require("@/static/tabBar/tab-home-current.png"),
+		text: "买入"
+	},
+	{
+		pagePath: "/pages/sellout/sellout",
+		iconPath: require("@/static/tabBar/tab-cate.png"),
+		selectedIconPath: require("@/static/tabBar/tab-cate-current.png"),
+		text: "卖出"
+	},
+	{
+		pagePath: "/pages/appointment/appointment",
+		iconPath: require("@/static/tabBar/tab-cart.png"),
+		selectedIconPath: require("@/static/tabBar/tab-cart-current.png"),
+		text: "我的预约"
+	},
+	{
+		pagePath: "/pages/user/user",
+		iconPath: require('@/static/tabBar/tab-home.png'),
+		selectedIconPath: require("@/static/tabBar/tab-home-current.png"),
+		text: "我的"
+	},
+]
+
+export const tabbar1 = [
+	{
+		pagePath: "/pages/index/index",
+		iconPath: require('@/static/tabBar/tab-home.png'),
+		selectedIconPath: require("@/static/tabBar/tab-home-current.png"),
+		text: "商城"
+	},
+	{
+		pagePath: "/pages/category/category",
+		iconPath: require('@/static/tabBar/tab-home.png'),
+		selectedIconPath: require("@/static/tabBar/tab-home-current.png"),
+		text: "分类"
+	},
+	{
+		pagePath: "/pages/user/user",
+		iconPath: require('@/static/tabBar/tab-home.png'),
+		selectedIconPath: require("@/static/tabBar/tab-home-current.png"),
+		text: "我的"
+	},
+]

+ 21 - 0
uview-ui/LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 www.uviewui.com
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 106 - 0
uview-ui/README.md

@@ -0,0 +1,106 @@
+<p align="center">
+    <img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
+</p>
+<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView</h3>
+<h3 align="center">多平台快速开发的UI框架</h3>
+
+
+## 说明
+
+uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
+
+## 特性
+
+- 兼容安卓,iOS,微信小程序,H5,QQ小程序,百度小程序,支付宝小程序,头条小程序
+- 60+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用
+- 众多贴心的JS利器,让您飞镖在手,召之即来,百步穿杨
+- 众多的常用页面和布局,让您专注逻辑,事半功倍
+- 详尽的文档支持,现代化的演示效果
+- 按需引入,精简打包体积
+
+
+## 安装
+
+```bash
+# npm方式安装
+npm i uview-ui
+```
+
+## 快速上手
+
+1. `main.js`引入uView库
+```js
+// main.js
+import uView from 'uview-ui';
+Vue.use(uView);
+```
+
+2. `App.vue`引入基础样式(注意style标签需声明scss属性支持)
+```css
+/* App.vue */
+<style lang="scss">
+@import "uview-ui/index.scss";
+</style>
+```
+
+3. `uni.scss`引入全局scss变量文件
+```css
+/* uni.scss */
+@import "uview-ui/theme.scss";
+```
+
+4. `pages.json`配置easycom规则(按需引入)
+
+```js
+// pages.json
+{
+	"easycom": {
+		// npm安装的方式不需要前面的"@/",下载安装的方式需要"@/"
+		// npm安装方式
+		"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
+		// 下载安装方式
+		// "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
+	},
+	// 此为本身已有的内容
+	"pages": [
+		// ......
+	]
+}
+```
+
+请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容 
+
+## 使用方法
+配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
+
+```html
+<template>
+	<u-button>按钮</u-button>
+</template>
+```
+
+请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容 
+
+## 链接
+
+- [官方文档](https://uviewui.com/)
+- [更新日志](https://uviewui.com/components/changelog.html)
+- [升级指南](https://uviewui.com/components/changelog.html)
+- [关于我们](https://uviewui.com/cooperation/about.html)
+
+## 预览
+
+您可以通过**微信**扫码,查看最佳的演示效果。
+<br>
+<br>
+<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
+
+<!-- ## 捐赠uView的研发
+
+uView文档和源码全部开源免费,如果您认为uView帮到了您的开发工作,您可以捐赠uView的研发工作,捐赠无门槛,哪怕是一杯可乐也好(相信这比打赏主播更有意义)。
+
+<img src="https://uviewui.com/common/wechat.png" width="220" >
+<img style="margin-left: 100px;" src="https://uviewui.com/common/alipay.png" width="220" >
+ -->
+## 版权信息
+uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。

+ 190 - 0
uview-ui/components/u-action-sheet/u-action-sheet.vue

@@ -0,0 +1,190 @@
+<template>
+	<u-popup mode="bottom" :border-radius="borderRadius" :popup="false" v-model="value" :maskCloseAble="maskCloseAble"
+	    length="auto" :safeAreaInsetBottom="safeAreaInsetBottom" @close="popupClose" :z-index="uZIndex">
+		<view class="u-tips u-border-bottom" v-if="tips.text" :style="[tipsStyle]">
+			{{tips.text}}
+		</view>
+		<block v-for="(item, index) in list" :key="index">
+			<view 
+				@touchmove.stop.prevent 
+				@tap="itemClick(index)" 
+				:style="[itemStyle(index)]" 
+				class="u-action-sheet-item u-line-1" 
+				:class="[index < list.length - 1 ? 'u-border-bottom' : '']"
+				:hover-stay-time="150"
+			>
+				<text>{{item.text}}</text>
+				<text class="u-action-sheet-item__subtext u-line-1" v-if="item.subText">{{item.subText}}</text>
+			</view>
+		</block>
+		<view class="u-gab" v-if="cancelBtn">
+		</view>
+		<view @touchmove.stop.prevent class="u-actionsheet-cancel u-action-sheet-item" hover-class="u-hover-class"
+		    :hover-stay-time="150" v-if="cancelBtn" @tap="close">{{cancelText}}</view>
+	</u-popup>
+</template>
+
+<script>
+	/**
+	 * actionSheet 操作菜单
+	 * @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
+	 * @tutorial https://www.uviewui.com/components/actionSheet.html
+	 * @property {Array<Object>} list 按钮的文字数组,见官方文档示例
+	 * @property {Object} tips 顶部的提示文字,见官方文档示例
+	 * @property {String} cancel-text 取消按钮的提示文字
+	 * @property {Boolean} cancel-btn 是否显示底部的取消按钮(默认true)
+	 * @property {Number String} border-radius 弹出部分顶部左右的圆角值,单位rpx(默认0)
+	 * @property {Boolean} mask-close-able 点击遮罩是否可以关闭(默认true)
+	 * @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
+	 * @property {Number String} z-index z-index值(默认1075)
+	 * @property {String} cancel-text 取消按钮的提示文字
+	 * @event {Function} click 点击ActionSheet列表项时触发
+	 * @event {Function} close 点击取消按钮时触发
+	 * @example <u-action-sheet :list="list" @click="click" v-model="show"></u-action-sheet>
+	 */
+	export default {
+		name: "u-action-sheet",
+		props: {
+			// 点击遮罩是否可以关闭actionsheet
+			maskCloseAble: {
+				type: Boolean,
+				default: true
+			},
+			// 按钮的文字数组,可以自定义颜色和字体大小,字体单位为rpx
+			list: {
+				type: Array,
+				default () {
+					// 如下
+					// return [{
+					// 	text: '确定',
+					// 	color: '',
+					// 	fontSize: ''
+					// }]
+					return [];
+				}
+			},
+			// 顶部的提示文字
+			tips: {
+				type: Object,
+				default () {
+					return {
+						text: '',
+						color: '',
+						fontSize: '26'
+					}
+				}
+			},
+			// 底部的取消按钮
+			cancelBtn: {
+				type: Boolean,
+				default: true
+			},
+			// 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
+			safeAreaInsetBottom: {
+				type: Boolean,
+				default: false
+			},
+			// 通过双向绑定控制组件的弹出与收起
+			value: {
+				type: Boolean,
+				default: false
+			},
+			// 弹出的顶部圆角值
+			borderRadius: {
+				type: [String, Number],
+				default: 0
+			},
+			// 弹出的z-index值
+			zIndex: {
+				type: [String, Number],
+				default: 0
+			},
+			// 取消按钮的文字提示
+			cancelText: {
+				type: String,
+				default: '取消'
+			}
+		},
+		computed: {
+			// 顶部提示的样式
+			tipsStyle() {
+				let style = {};
+				if (this.tips.color) style.color = this.tips.color;
+				if (this.tips.fontSize) style.fontSize = this.tips.fontSize + 'rpx';
+				return style;
+			},
+			// 操作项目的样式
+			itemStyle() {
+				return (index) => {
+					let style = {};
+					if (this.list[index].color) style.color = this.list[index].color;
+					if (this.list[index].fontSize) style.fontSize = this.list[index].fontSize + 'rpx';
+					// 选项被禁用的样式
+					if (this.list[index].disabled) style.color = '#c0c4cc';
+					return style;
+				}
+			},
+			uZIndex() {
+				// 如果用户有传递z-index值,优先使用
+				return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
+			}
+		},
+		methods: {
+			// 点击取消按钮
+			close() {
+				// 发送input事件,并不会作用于父组件,而是要设置组件内部通过props传递的value参数
+				// 这是一个vue发送事件的特殊用法
+				this.popupClose();
+				this.$emit('close');
+			},
+			// 弹窗关闭
+			popupClose() {
+				this.$emit('input', false);
+			},
+			// 点击某一个item
+			itemClick(index) {
+				// disabled的项禁止点击
+				if(this.list[index].disabled) return;
+				this.$emit('click', index);
+				this.$emit('input', false);
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+
+	.u-tips {
+		font-size: 26rpx;
+		text-align: center;
+		padding: 34rpx 0;
+		line-height: 1;
+		color: $u-tips-color;
+	}
+
+	.u-action-sheet-item {
+		@include vue-flex;;
+		line-height: 1;
+		justify-content: center;
+		align-items: center;
+		font-size: 32rpx;
+		padding: 34rpx 0;
+		flex-direction: column;
+	}
+	
+	.u-action-sheet-item__subtext {
+		font-size: 24rpx;
+		color: $u-tips-color;
+		margin-top: 20rpx;
+	}
+
+	.u-gab {
+		height: 12rpx;
+		background-color: rgb(234, 234, 236);
+	}
+
+	.u-actionsheet-cancel {
+		color: $u-main-color;
+	}
+</style>

+ 256 - 0
uview-ui/components/u-alert-tips/u-alert-tips.vue

@@ -0,0 +1,256 @@
+<template>
+	<view class="u-alert-tips" v-if="show" :class="[
+		!show ? 'u-close-alert-tips': '',
+		type ? 'u-alert-tips--bg--' + type + '-light' : '',
+		type ? 'u-alert-tips--border--' + type + '-disabled' : '',
+	]" :style="{
+		backgroundColor: bgColor,
+		borderColor: borderColor
+	}">
+		<view class="u-icon-wrap">
+			<u-icon v-if="showIcon" :name="uIcon" :size="description ? 40 : 32" class="u-icon" :color="uIconType" :custom-style="iconStyle"></u-icon>
+		</view>
+		<view class="u-alert-content" @tap.stop="click">
+			<view class="u-alert-title" :style="[uTitleStyle]">
+				{{title}}
+			</view>
+			<view v-if="description" class="u-alert-desc" :style="[descStyle]">
+				{{description}}
+			</view>
+		</view>
+		<view class="u-icon-wrap">
+			<u-icon @click="close" v-if="closeAble && !closeText" hoverClass="u-type-error-hover-color" name="close" color="#c0c4cc"
+			 :size="22" class="u-close-icon" :style="{
+				top: description ? '18rpx' : '24rpx'
+			}"></u-icon>
+		</view>
+		<text v-if="closeAble && closeText" class="u-close-text" :style="{
+			top: description ? '18rpx' : '24rpx'
+		}">{{closeText}}</text>
+	</view>
+</template>
+
+<script>
+	/**
+	 * alertTips 警告提示
+	 * @description 警告提示,展现需要关注的信息
+	 * @tutorial https://uviewui.com/components/alertTips.html
+	 * @property {String} title 显示的标题文字
+	 * @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
+	 * @property {String} type 关闭按钮(默认为叉号icon图标)
+	 * @property {String} icon 图标名称
+	 * @property {Object} icon-style 图标的样式,对象形式
+	 * @property {Object} title-style 标题的样式,对象形式
+	 * @property {Object} desc-style 描述的样式,对象形式
+	 * @property {String} close-able 用文字替代关闭图标,close-able为true时有效
+	 * @property {Boolean} show-icon 是否显示左边的辅助图标
+	 * @property {Boolean} show 显示或隐藏组件
+	 * @event {Function} click 点击组件时触发
+	 * @event {Function} close 点击关闭按钮时触发
+	 */
+	export default {
+		name: 'u-alert-tips',
+		props: {
+			// 显示文字
+			title: {
+				type: String,
+				default: ''
+			},
+			// 主题,success/warning/info/error
+			type: {
+				type: String,
+				default: 'warning'
+			},
+			// 辅助性文字
+			description: {
+				type: String,
+				default: ''
+			},
+			// 是否可关闭
+			closeAble: {
+				type: Boolean,
+				default: false
+			},
+			// 关闭按钮自定义文本
+			closeText: {
+				type: String,
+				default: ''
+			},
+			// 是否显示图标
+			showIcon: {
+				type: Boolean,
+				default: false
+			},
+			// 文字颜色,如果定义了color值,icon会失效
+			color: {
+				type: String,
+				default: ''
+			},
+			// 背景颜色
+			bgColor: {
+				type: String,
+				default: ''
+			},
+			// 边框颜色
+			borderColor: {
+				type: String,
+				default: ''
+			},
+			// 是否显示
+			show: {
+				type: Boolean,
+				default: true
+			},
+			// 左边显示的icon
+			icon: {
+				type: String,
+				default: ''
+			},
+			// icon的样式
+			iconStyle: {
+				type: Object,
+				default() {
+					return {}
+				}
+			},
+			// 标题的样式
+			titleStyle: {
+				type: Object,
+				default() {
+					return {}
+				}
+			},
+			// 描述文字的样式
+			descStyle: {
+				type: Object,
+				default() {
+					return {}
+				}
+			},
+		},
+		data() {
+			return {
+			}
+		},
+		computed: {
+			uTitleStyle() {
+				let style = {};
+				// 如果有描述文字的话,标题进行加粗
+				style.fontWeight = this.description ? 500 : 'normal';
+				// 将用户传入样式对象和style合并,传入的优先级比style高,同属性会被覆盖
+				return this.$u.deepMerge(style, this.titleStyle);
+			},
+			uIcon() {
+				// 如果有设置icon名称就使用,否则根据type主题,推定一个默认的图标
+				return this.icon ? this.icon : this.$u.type2icon(this.type);
+			},
+			uIconType() {
+				// 如果有设置图标的样式,优先使用,没有的话,则用type的样式
+				return Object.keys(this.iconStyle).length ? '' : this.type;
+			}
+		},
+		methods: {
+			// 点击内容
+			click() {
+				this.$emit('click');
+			},
+			// 点击关闭按钮
+			close() {
+				this.$emit('close');
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+	
+	.u-alert-tips {
+		@include vue-flex;
+		align-items: center;
+		padding: 16rpx 30rpx;
+		border-radius: 8rpx;
+		position: relative;
+		transition: all 0.3s linear;
+		border: 1px solid #fff;
+		
+		&--bg--primary-light {
+			background-color: $u-type-primary-light;
+		}
+		
+		&--bg--info-light {
+			background-color: $u-type-info-light;
+		}
+		
+		&--bg--success-light {
+			background-color: $u-type-success-light;
+		}
+		
+		&--bg--warning-light {
+			background-color: $u-type-warning-light;
+		}
+		
+		&--bg--error-light {
+			background-color: $u-type-error-light;
+		}
+		
+		&--border--primary-disabled {
+			border-color: $u-type-primary-disabled;
+		}
+		
+		&--border--success-disabled {
+			border-color: $u-type-success-disabled;
+		}
+		
+		&--border--error-disabled {
+			border-color: $u-type-error-disabled;
+		}
+		
+		&--border--warning-disabled {
+			border-color: $u-type-warning-disabled;
+		}
+		
+		&--border--info-disabled {
+			border-color: $u-type-info-disabled;
+		}
+	}
+
+	.u-close-alert-tips {
+		opacity: 0;
+		visibility: hidden;
+	}
+
+	.u-icon {
+		margin-right: 16rpx;
+	}
+
+	.u-alert-title {
+		font-size: 28rpx;
+		color: $u-main-color;
+	}
+
+	.u-alert-desc {
+		font-size: 26rpx;
+		text-align: left;
+		color: $u-content-color;
+	}
+
+	.u-close-icon {
+		position: absolute;
+		top: 20rpx;
+		right: 20rpx;
+	}
+
+	.u-close-hover {
+		color: red;
+	}
+	
+	.u-close-text {
+		font-size: 24rpx;
+		color: $u-tips-color;
+		position: absolute;
+		top: 20rpx;
+		right: 20rpx;
+		line-height: 1;
+	}
+</style>

+ 290 - 0
uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue

@@ -0,0 +1,290 @@
+<template>
+	<view class="content">
+		<view class="cropper-wrapper" :style="{ height: cropperOpt.height + 'px' }">
+			<canvas
+				class="cropper"
+				:disable-scroll="true"
+				@touchstart="touchStart"
+				@touchmove="touchMove"
+				@touchend="touchEnd"
+				:style="{ width: cropperOpt.width, height: cropperOpt.height, backgroundColor: 'rgba(0, 0, 0, 0.8)' }"
+				canvas-id="cropper"
+				id="cropper"
+			></canvas>
+			<canvas
+				class="cropper"
+				:disable-scroll="true"
+				:style="{
+					position: 'fixed',
+					top: `-${cropperOpt.width * cropperOpt.pixelRatio}px`,
+					left: `-${cropperOpt.height * cropperOpt.pixelRatio}px`,
+					width: `${cropperOpt.width * cropperOpt.pixelRatio}px`,
+					height: `${cropperOpt.height * cropperOpt.pixelRatio}`
+				}"
+				canvas-id="targetId"
+				id="targetId"
+			></canvas>
+		</view>
+		<view class="cropper-buttons safe-area-padding" :style="{ height: bottomNavHeight + 'px' }">
+			<!-- #ifdef H5 -->
+			<view class="upload" @tap="uploadTap">选择图片</view>
+			<!-- #endif -->
+			<!-- #ifndef H5 -->
+			<view class="upload" @tap="uploadTap">重新选择</view>
+			<!-- #endif -->
+			<view class="getCropperImage" @tap="getCropperImage(false)">确定</view>
+		</view>
+	</view>
+</template>
+
+<script>
+import WeCropper from './weCropper.js';
+export default {
+	props: {
+		// 裁剪矩形框的样式,其中可包含的属性为lineWidth-边框宽度(单位rpx),color: 边框颜色,
+		// mask-遮罩颜色,一般设置为一个rgba的透明度,如"rgba(0, 0, 0, 0.35)"
+		boundStyle: {
+			type: Object,
+			default() {
+				return {
+					lineWidth: 4,
+					borderColor: 'rgb(245, 245, 245)',
+					mask: 'rgba(0, 0, 0, 0.35)'
+				};
+			}
+		}
+		// // 裁剪框宽度,单位rpx
+		// rectWidth: {
+		// 	type: [String, Number],
+		// 	default: 400
+		// },
+		// // 裁剪框高度,单位rpx
+		// rectHeight: {
+		// 	type: [String, Number],
+		// 	default: 400
+		// },
+		// // 输出图片宽度,单位rpx
+		// destWidth: {
+		// 	type: [String, Number],
+		// 	default: 400
+		// },
+		// // 输出图片高度,单位rpx
+		// destHeight: {
+		// 	type: [String, Number],
+		// 	default: 400
+		// },
+		// // 输出的图片类型,如果发现裁剪的图片很大,可能是因为设置为了"png",改成"jpg"即可
+		// fileType: {
+		// 	type: String,
+		// 	default: 'jpg',
+		// },
+		// // 生成的图片质量
+		// // H5上无效,目前不考虑使用此参数
+		// quality: {
+		// 	type: [Number, String],
+		// 	default: 1
+		// }
+	},
+	data() {
+		return {
+			// 底部导航的高度
+			bottomNavHeight: 50,
+			originWidth: 200,
+			width: 0,
+			height: 0,
+			cropperOpt: {
+				id: 'cropper',
+				targetId: 'targetCropper',
+				pixelRatio: 1,
+				width: 0,
+				height: 0,
+				scale: 2.5,
+				zoom: 8,
+				cut: {
+					x: (this.width - this.originWidth) / 2,
+					y: (this.height - this.originWidth) / 2,
+					width: this.originWidth,
+					height: this.originWidth
+				},
+				boundStyle: {
+					lineWidth: uni.upx2px(this.boundStyle.lineWidth),
+					mask: this.boundStyle.mask,
+					color: this.boundStyle.borderColor
+				}
+			},
+			// 裁剪框和输出图片的尺寸,高度默认等于宽度
+			// 输出图片宽度,单位px
+			destWidth: 200,
+			// 裁剪框宽度,单位px
+			rectWidth: 200,
+			// 输出的图片类型,如果'png'类型发现裁剪的图片太大,改成"jpg"即可
+			fileType: 'jpg',
+			src: '', // 选择的图片路径,用于在点击确定时,判断是否选择了图片
+		};
+	},
+	onLoad(option) {
+		let rectInfo = uni.getSystemInfoSync();
+		this.width = rectInfo.windowWidth;
+		this.height = rectInfo.windowHeight - this.bottomNavHeight;
+		this.cropperOpt.width = this.width;
+		this.cropperOpt.height = this.height;
+		this.cropperOpt.pixelRatio = rectInfo.pixelRatio;
+
+		if (option.destWidth) this.destWidth = option.destWidth;
+		if (option.rectWidth) {
+			let rectWidth = Number(option.rectWidth);
+			this.cropperOpt.cut = {
+				x: (this.width - rectWidth) / 2,
+				y: (this.height - rectWidth) / 2,
+				width: rectWidth,
+				height: rectWidth
+			};
+		}
+		this.rectWidth = option.rectWidth;
+		if (option.fileType) this.fileType = option.fileType;
+		// 初始化
+		this.cropper = new WeCropper(this.cropperOpt)
+			.on('ready', ctx => {
+				// wecropper is ready for work!
+			})
+			.on('beforeImageLoad', ctx => {
+				// before picture loaded, i can do something
+			})
+			.on('imageLoad', ctx => {
+				// picture loaded
+			})
+			.on('beforeDraw', (ctx, instance) => {
+				// before canvas draw,i can do something
+			});
+		// 设置导航栏样式,以免用户在page.json中没有设置为黑色背景
+		uni.setNavigationBarColor({
+			frontColor: '#ffffff',
+			backgroundColor: '#000000'
+		});
+		uni.chooseImage({
+			count: 1, // 默认9
+			sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
+			sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
+			success: res => {
+				this.src = res.tempFilePaths[0];
+				//  获取裁剪图片资源后,给data添加src属性及其值
+				this.cropper.pushOrign(this.src);
+			}
+		});
+	},
+	methods: {
+		touchStart(e) {
+			this.cropper.touchStart(e);
+		},
+		touchMove(e) {
+			this.cropper.touchMove(e);
+		},
+		touchEnd(e) {
+			this.cropper.touchEnd(e);
+		},
+		getCropperImage(isPre = false) {
+			if(!this.src) return this.$u.toast('请先选择图片再裁剪');
+
+			let cropper_opt = {
+				destHeight: Number(this.destWidth), // uni.canvasToTempFilePath要求这些参数为数值
+				destWidth: Number(this.destWidth),
+				fileType: this.fileType
+			};
+			this.cropper.getCropperImage(cropper_opt, (path, err) => {
+				if (err) {
+					uni.showModal({
+						title: '温馨提示',
+						content: err.message
+					});
+				} else {
+					if (isPre) {
+						uni.previewImage({
+							current: '', // 当前显示图片的 http 链接
+							urls: [path] // 需要预览的图片 http 链接列表
+						});
+					} else {
+						uni.$emit('uAvatarCropper', path);
+						this.$u.route({
+							type: 'back'
+						});
+					}
+				}
+			});
+		},
+		uploadTap() {
+			const self = this;
+			uni.chooseImage({
+				count: 1, // 默认9
+				sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
+				sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
+				success: (res) => {
+					self.src = res.tempFilePaths[0];
+					//  获取裁剪图片资源后,给data添加src属性及其值
+
+					self.cropper.pushOrign(this.src);
+				}
+			});
+		}
+	}
+};
+</script>
+
+<style scoped lang="scss">
+@import '../../libs/css/style.components.scss';
+
+.content {
+	background: rgba(255, 255, 255, 1);
+}
+
+.cropper {
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 100%;
+	height: 100%;
+	z-index: 11;
+}
+
+.cropper-buttons {
+	background-color: #000000;
+	color: #eee;
+}
+
+.cropper-wrapper {
+	position: relative;
+	@include vue-flex;
+	flex-direction: row;
+	justify-content: space-between;
+	align-items: center;
+	width: 100%;
+	background-color: #000;
+}
+
+.cropper-buttons {
+	width: 100vw;
+	@include vue-flex;
+	flex-direction: row;
+	justify-content: space-between;
+	align-items: center;
+	position: fixed;
+	bottom: 0;
+	left: 0;
+	font-size: 28rpx;
+}
+
+.cropper-buttons .upload,
+.cropper-buttons .getCropperImage {
+	width: 50%;
+	text-align: center;
+}
+
+.cropper-buttons .upload {
+	text-align: left;
+	padding-left: 50rpx;
+}
+
+.cropper-buttons .getCropperImage {
+	text-align: right;
+	padding-right: 50rpx;
+}
+</style>

+ 1265 - 0
uview-ui/components/u-avatar-cropper/weCropper.js

@@ -0,0 +1,1265 @@
+/**
+ * we-cropper v1.3.9
+ * (c) 2020 dlhandsome
+ * @license MIT
+ */
+(function(global, factory) {
+	typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+		typeof define === 'function' && define.amd ? define(factory) :
+		(global.WeCropper = factory());
+}(this, (function() {
+	'use strict';
+
+	var device = void 0;
+	var TOUCH_STATE = ['touchstarted', 'touchmoved', 'touchended'];
+
+	function firstLetterUpper(str) {
+		return str.charAt(0).toUpperCase() + str.slice(1)
+	}
+
+	function setTouchState(instance) {
+		var arg = [],
+			len = arguments.length - 1;
+		while (len-- > 0) arg[len] = arguments[len + 1];
+
+		TOUCH_STATE.forEach(function(key, i) {
+			if (arg[i] !== undefined) {
+				instance[key] = arg[i];
+			}
+		});
+	}
+
+	function validator(instance, o) {
+		Object.defineProperties(instance, o);
+	}
+
+	function getDevice() {
+		if (!device) {
+			device = uni.getSystemInfoSync();
+		}
+		return device
+	}
+
+	var tmp = {};
+
+	var ref = getDevice();
+	var pixelRatio = ref.pixelRatio;
+
+	var DEFAULT = {
+		id: {
+			default: 'cropper',
+			get: function get() {
+				return tmp.id
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'string') {
+					console.error(("id:" + value + " is invalid"));
+				}
+				tmp.id = value;
+			}
+		},
+		width: {
+			default: 750,
+			get: function get() {
+				return tmp.width
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("width:" + value + " is invalid"));
+				}
+				tmp.width = value;
+			}
+		},
+		height: {
+			default: 750,
+			get: function get() {
+				return tmp.height
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("height:" + value + " is invalid"));
+				}
+				tmp.height = value;
+			}
+		},
+		pixelRatio: {
+			default: pixelRatio,
+			get: function get() {
+				return tmp.pixelRatio
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("pixelRatio:" + value + " is invalid"));
+				}
+				tmp.pixelRatio = value;
+			}
+		},
+		scale: {
+			default: 2.5,
+			get: function get() {
+				return tmp.scale
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("scale:" + value + " is invalid"));
+				}
+				tmp.scale = value;
+			}
+		},
+		zoom: {
+			default: 5,
+			get: function get() {
+				return tmp.zoom
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'number') {
+					console.error(("zoom:" + value + " is invalid"));
+				} else if (value < 0 || value > 10) {
+					console.error("zoom should be ranged in 0 ~ 10");
+				}
+				tmp.zoom = value;
+			}
+		},
+		src: {
+			default: '',
+			get: function get() {
+				return tmp.src
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'string') {
+					console.error(("src:" + value + " is invalid"));
+				}
+				tmp.src = value;
+			}
+		},
+		cut: {
+			default: {},
+			get: function get() {
+				return tmp.cut
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'object') {
+					console.error(("cut:" + value + " is invalid"));
+				}
+				tmp.cut = value;
+			}
+		},
+		boundStyle: {
+			default: {},
+			get: function get() {
+				return tmp.boundStyle
+			},
+			set: function set(value) {
+				if (typeof(value) !== 'object') {
+					console.error(("boundStyle:" + value + " is invalid"));
+				}
+				tmp.boundStyle = value;
+			}
+		},
+		onReady: {
+			default: null,
+			get: function get() {
+				return tmp.ready
+			},
+			set: function set(value) {
+				tmp.ready = value;
+			}
+		},
+		onBeforeImageLoad: {
+			default: null,
+			get: function get() {
+				return tmp.beforeImageLoad
+			},
+			set: function set(value) {
+				tmp.beforeImageLoad = value;
+			}
+		},
+		onImageLoad: {
+			default: null,
+			get: function get() {
+				return tmp.imageLoad
+			},
+			set: function set(value) {
+				tmp.imageLoad = value;
+			}
+		},
+		onBeforeDraw: {
+			default: null,
+			get: function get() {
+				return tmp.beforeDraw
+			},
+			set: function set(value) {
+				tmp.beforeDraw = value;
+			}
+		}
+	};
+
+	var ref$1 = getDevice();
+	var windowWidth = ref$1.windowWidth;
+
+	function prepare() {
+		var self = this;
+
+		// v1.4.0 版本中将不再自动绑定we-cropper实例
+		self.attachPage = function() {
+			var pages = getCurrentPages();
+			// 获取到当前page上下文
+			var pageContext = pages[pages.length - 1];
+			// 把this依附在Page上下文的wecropper属性上,便于在page钩子函数中访问
+			Object.defineProperty(pageContext, 'wecropper', {
+				get: function get() {
+					console.warn(
+						'Instance will not be automatically bound to the page after v1.4.0\n\n' +
+						'Please use a custom instance name instead\n\n' +
+						'Example: \n' +
+						'this.mycropper = new WeCropper(options)\n\n' +
+						'// ...\n' +
+						'this.mycropper.getCropperImage()'
+					);
+					return self
+				},
+				configurable: true
+			});
+		};
+
+		self.createCtx = function() {
+			var id = self.id;
+			var targetId = self.targetId;
+
+			if (id) {
+				self.ctx = self.ctx || uni.createCanvasContext(id);
+				self.targetCtx = self.targetCtx || uni.createCanvasContext(targetId);
+			} else {
+				console.error("constructor: create canvas context failed, 'id' must be valuable");
+			}
+		};
+
+		self.deviceRadio = windowWidth / 750;
+	}
+
+	var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !==
+		'undefined' ? self : {};
+
+
+
+
+
+	function createCommonjsModule(fn, module) {
+		return module = {
+			exports: {}
+		}, fn(module, module.exports), module.exports;
+	}
+
+	var tools = createCommonjsModule(function(module, exports) {
+		/**
+		 * String type check
+		 */
+		exports.isStr = function(v) {
+			return typeof v === 'string';
+		};
+		/**
+		 * Number type check
+		 */
+		exports.isNum = function(v) {
+			return typeof v === 'number';
+		};
+		/**
+		 * Array type check
+		 */
+		exports.isArr = Array.isArray;
+		/**
+		 * undefined type check
+		 */
+		exports.isUndef = function(v) {
+			return v === undefined;
+		};
+
+		exports.isTrue = function(v) {
+			return v === true;
+		};
+
+		exports.isFalse = function(v) {
+			return v === false;
+		};
+		/**
+		 * Function type check
+		 */
+		exports.isFunc = function(v) {
+			return typeof v === 'function';
+		};
+		/**
+		 * Quick object check - this is primarily used to tell
+		 * Objects from primitive values when we know the value
+		 * is a JSON-compliant type.
+		 */
+		exports.isObj = exports.isObject = function(obj) {
+			return obj !== null && typeof obj === 'object'
+		};
+
+		/**
+		 * Strict object type check. Only returns true
+		 * for plain JavaScript objects.
+		 */
+		var _toString = Object.prototype.toString;
+		exports.isPlainObject = function(obj) {
+			return _toString.call(obj) === '[object Object]'
+		};
+
+		/**
+		 * Check whether the object has the property.
+		 */
+		var hasOwnProperty = Object.prototype.hasOwnProperty;
+		exports.hasOwn = function(obj, key) {
+			return hasOwnProperty.call(obj, key)
+		};
+
+		/**
+		 * Perform no operation.
+		 * Stubbing args to make Flow happy without leaving useless transpiled code
+		 * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/)
+		 */
+		exports.noop = function(a, b, c) {};
+
+		/**
+		 * Check if val is a valid array index.
+		 */
+		exports.isValidArrayIndex = function(val) {
+			var n = parseFloat(String(val));
+			return n >= 0 && Math.floor(n) === n && isFinite(val)
+		};
+	});
+
+	var tools_7 = tools.isFunc;
+	var tools_10 = tools.isPlainObject;
+
+	var EVENT_TYPE = ['ready', 'beforeImageLoad', 'beforeDraw', 'imageLoad'];
+
+	function observer() {
+		var self = this;
+
+		self.on = function(event, fn) {
+			if (EVENT_TYPE.indexOf(event) > -1) {
+				if (tools_7(fn)) {
+					event === 'ready' ?
+						fn(self) :
+						self[("on" + (firstLetterUpper(event)))] = fn;
+				}
+			} else {
+				console.error(("event: " + event + " is invalid"));
+			}
+			return self
+		};
+	}
+
+	function wxPromise(fn) {
+		return function(obj) {
+			var args = [],
+				len = arguments.length - 1;
+			while (len-- > 0) args[len] = arguments[len + 1];
+
+			if (obj === void 0) obj = {};
+			return new Promise(function(resolve, reject) {
+				obj.success = function(res) {
+					resolve(res);
+				};
+				obj.fail = function(err) {
+					reject(err);
+				};
+				fn.apply(void 0, [obj].concat(args));
+			})
+		}
+	}
+
+	function draw(ctx, reserve) {
+		if (reserve === void 0) reserve = false;
+
+		return new Promise(function(resolve) {
+			ctx.draw(reserve, resolve);
+		})
+	}
+
+	var getImageInfo = wxPromise(uni.getImageInfo);
+
+	var canvasToTempFilePath = wxPromise(uni.canvasToTempFilePath);
+
+	var base64 = createCommonjsModule(function(module, exports) {
+		/*! http://mths.be/base64 v0.1.0 by @mathias | MIT license */
+		(function(root) {
+
+			// Detect free variables `exports`.
+			var freeExports = 'object' == 'object' && exports;
+
+			// Detect free variable `module`.
+			var freeModule = 'object' == 'object' && module &&
+				module.exports == freeExports && module;
+
+			// Detect free variable `global`, from Node.js or Browserified code, and use
+			// it as `root`.
+			var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal;
+			if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
+				root = freeGlobal;
+			}
+
+			/*--------------------------------------------------------------------------*/
+
+			var InvalidCharacterError = function(message) {
+				this.message = message;
+			};
+			InvalidCharacterError.prototype = new Error;
+			InvalidCharacterError.prototype.name = 'InvalidCharacterError';
+
+			var error = function(message) {
+				// Note: the error messages used throughout this file match those used by
+				// the native `atob`/`btoa` implementation in Chromium.
+				throw new InvalidCharacterError(message);
+			};
+
+			var TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
+			// http://whatwg.org/html/common-microsyntaxes.html#space-character
+			var REGEX_SPACE_CHARACTERS = /[\t\n\f\r ]/g;
+
+			// `decode` is designed to be fully compatible with `atob` as described in the
+			// HTML Standard. http://whatwg.org/html/webappapis.html#dom-windowbase64-atob
+			// The optimized base64-decoding algorithm used is based on @atk’s excellent
+			// implementation. https://gist.github.com/atk/1020396
+			var decode = function(input) {
+				input = String(input)
+					.replace(REGEX_SPACE_CHARACTERS, '');
+				var length = input.length;
+				if (length % 4 == 0) {
+					input = input.replace(/==?$/, '');
+					length = input.length;
+				}
+				if (
+					length % 4 == 1 ||
+					// http://whatwg.org/C#alphanumeric-ascii-characters
+					/[^+a-zA-Z0-9/]/.test(input)
+				) {
+					error(
+						'Invalid character: the string to be decoded is not correctly encoded.'
+					);
+				}
+				var bitCounter = 0;
+				var bitStorage;
+				var buffer;
+				var output = '';
+				var position = -1;
+				while (++position < length) {
+					buffer = TABLE.indexOf(input.charAt(position));
+					bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer;
+					// Unless this is the first of a group of 4 characters…
+					if (bitCounter++ % 4) {
+						// …convert the first 8 bits to a single ASCII character.
+						output += String.fromCharCode(
+							0xFF & bitStorage >> (-2 * bitCounter & 6)
+						);
+					}
+				}
+				return output;
+			};
+
+			// `encode` is designed to be fully compatible with `btoa` as described in the
+			// HTML Standard: http://whatwg.org/html/webappapis.html#dom-windowbase64-btoa
+			var encode = function(input) {
+				input = String(input);
+				if (/[^\0-\xFF]/.test(input)) {
+					// Note: no need to special-case astral symbols here, as surrogates are
+					// matched, and the input is supposed to only contain ASCII anyway.
+					error(
+						'The string to be encoded contains characters outside of the ' +
+						'Latin1 range.'
+					);
+				}
+				var padding = input.length % 3;
+				var output = '';
+				var position = -1;
+				var a;
+				var b;
+				var c;
+				var buffer;
+				// Make sure any padding is handled outside of the loop.
+				var length = input.length - padding;
+
+				while (++position < length) {
+					// Read three bytes, i.e. 24 bits.
+					a = input.charCodeAt(position) << 16;
+					b = input.charCodeAt(++position) << 8;
+					c = input.charCodeAt(++position);
+					buffer = a + b + c;
+					// Turn the 24 bits into four chunks of 6 bits each, and append the
+					// matching character for each of them to the output.
+					output += (
+						TABLE.charAt(buffer >> 18 & 0x3F) +
+						TABLE.charAt(buffer >> 12 & 0x3F) +
+						TABLE.charAt(buffer >> 6 & 0x3F) +
+						TABLE.charAt(buffer & 0x3F)
+					);
+				}
+
+				if (padding == 2) {
+					a = input.charCodeAt(position) << 8;
+					b = input.charCodeAt(++position);
+					buffer = a + b;
+					output += (
+						TABLE.charAt(buffer >> 10) +
+						TABLE.charAt((buffer >> 4) & 0x3F) +
+						TABLE.charAt((buffer << 2) & 0x3F) +
+						'='
+					);
+				} else if (padding == 1) {
+					buffer = input.charCodeAt(position);
+					output += (
+						TABLE.charAt(buffer >> 2) +
+						TABLE.charAt((buffer << 4) & 0x3F) +
+						'=='
+					);
+				}
+
+				return output;
+			};
+
+			var base64 = {
+				'encode': encode,
+				'decode': decode,
+				'version': '0.1.0'
+			};
+
+			// Some AMD build optimizers, like r.js, check for specific condition patterns
+			// like the following:
+			if (
+				typeof undefined == 'function' &&
+				typeof undefined.amd == 'object' &&
+				undefined.amd
+			) {
+				undefined(function() {
+					return base64;
+				});
+			} else if (freeExports && !freeExports.nodeType) {
+				if (freeModule) { // in Node.js or RingoJS v0.8.0+
+					freeModule.exports = base64;
+				} else { // in Narwhal or RingoJS v0.7.0-
+					for (var key in base64) {
+						base64.hasOwnProperty(key) && (freeExports[key] = base64[key]);
+					}
+				}
+			} else { // in Rhino or a web browser
+				root.base64 = base64;
+			}
+
+		}(commonjsGlobal));
+	});
+
+	function makeURI(strData, type) {
+		return 'data:' + type + ';base64,' + strData
+	}
+
+	function fixType(type) {
+		type = type.toLowerCase().replace(/jpg/i, 'jpeg');
+		var r = type.match(/png|jpeg|bmp|gif/)[0];
+		return 'image/' + r
+	}
+
+	function encodeData(data) {
+		var str = '';
+		if (typeof data === 'string') {
+			str = data;
+		} else {
+			for (var i = 0; i < data.length; i++) {
+				str += String.fromCharCode(data[i]);
+			}
+		}
+		return base64.encode(str)
+	}
+
+	/**
+	 * 获取图像区域隐含的像素数据
+	 * @param canvasId canvas标识
+	 * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标
+	 * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标
+	 * @param width 将要被提取的图像数据矩形区域的宽度
+	 * @param height 将要被提取的图像数据矩形区域的高度
+	 * @param done 完成回调
+	 */
+	function getImageData(canvasId, x, y, width, height, done) {
+		uni.canvasGetImageData({
+			canvasId: canvasId,
+			x: x,
+			y: y,
+			width: width,
+			height: height,
+			success: function success(res) {
+				done(res, null);
+			},
+			fail: function fail(res) {
+				done(null, res);
+			}
+		});
+	}
+
+	/**
+	 * 生成bmp格式图片
+	 * 按照规则生成图片响应头和响应体
+	 * @param oData 用来描述 canvas 区域隐含的像素数据 { data, width, height } = oData
+	 * @returns {*} base64字符串
+	 */
+	function genBitmapImage(oData) {
+		//
+		// BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx
+		// BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx
+		//
+		var biWidth = oData.width;
+		var biHeight = oData.height;
+		var biSizeImage = biWidth * biHeight * 3;
+		var bfSize = biSizeImage + 54; // total header size = 54 bytes
+
+		//
+		//  typedef struct tagBITMAPFILEHEADER {
+		//  	WORD bfType;
+		//  	DWORD bfSize;
+		//  	WORD bfReserved1;
+		//  	WORD bfReserved2;
+		//  	DWORD bfOffBits;
+		//  } BITMAPFILEHEADER;
+		//
+		var BITMAPFILEHEADER = [
+			// WORD bfType -- The file type signature; must be "BM"
+			0x42, 0x4D,
+			// DWORD bfSize -- The size, in bytes, of the bitmap file
+			bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff,
+			// WORD bfReserved1 -- Reserved; must be zero
+			0, 0,
+			// WORD bfReserved2 -- Reserved; must be zero
+			0, 0,
+			// DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.
+			54, 0, 0, 0
+		];
+
+		//
+		//  typedef struct tagBITMAPINFOHEADER {
+		//  	DWORD biSize;
+		//  	LONG  biWidth;
+		//  	LONG  biHeight;
+		//  	WORD  biPlanes;
+		//  	WORD  biBitCount;
+		//  	DWORD biCompression;
+		//  	DWORD biSizeImage;
+		//  	LONG  biXPelsPerMeter;
+		//  	LONG  biYPelsPerMeter;
+		//  	DWORD biClrUsed;
+		//  	DWORD biClrImportant;
+		//  } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
+		//
+		var BITMAPINFOHEADER = [
+			// DWORD biSize -- The number of bytes required by the structure
+			40, 0, 0, 0,
+			// LONG biWidth -- The width of the bitmap, in pixels
+			biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff,
+			// LONG biHeight -- The height of the bitmap, in pixels
+			biHeight & 0xff, biHeight >> 8 & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff,
+			// WORD biPlanes -- The number of planes for the target device. This value must be set to 1
+			1, 0,
+			// WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap
+			// has a maximum of 2^24 colors (16777216, Truecolor)
+			24, 0,
+			// DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed
+			0, 0, 0, 0,
+			// DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps
+			biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff,
+			// LONG biXPelsPerMeter, unused
+			0, 0, 0, 0,
+			// LONG biYPelsPerMeter, unused
+			0, 0, 0, 0,
+			// DWORD biClrUsed, the number of color indexes of palette, unused
+			0, 0, 0, 0,
+			// DWORD biClrImportant, unused
+			0, 0, 0, 0
+		];
+
+		var iPadding = (4 - ((biWidth * 3) % 4)) % 4;
+
+		var aImgData = oData.data;
+
+		var strPixelData = '';
+		var biWidth4 = biWidth << 2;
+		var y = biHeight;
+		var fromCharCode = String.fromCharCode;
+
+		do {
+			var iOffsetY = biWidth4 * (y - 1);
+			var strPixelRow = '';
+			for (var x = 0; x < biWidth; x++) {
+				var iOffsetX = x << 2;
+				strPixelRow += fromCharCode(aImgData[iOffsetY + iOffsetX + 2]) +
+					fromCharCode(aImgData[iOffsetY + iOffsetX + 1]) +
+					fromCharCode(aImgData[iOffsetY + iOffsetX]);
+			}
+
+			for (var c = 0; c < iPadding; c++) {
+				strPixelRow += String.fromCharCode(0);
+			}
+
+			strPixelData += strPixelRow;
+		} while (--y)
+
+		var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData);
+
+		return strEncoded
+	}
+
+	/**
+	 * 转换为图片base64
+	 * @param canvasId canvas标识
+	 * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标
+	 * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标
+	 * @param width 将要被提取的图像数据矩形区域的宽度
+	 * @param height 将要被提取的图像数据矩形区域的高度
+	 * @param type 转换图片类型
+	 * @param done 完成回调
+	 */
+	function convertToImage(canvasId, x, y, width, height, type, done) {
+		if (done === void 0) done = function() {};
+
+		if (type === undefined) {
+			type = 'png';
+		}
+		type = fixType(type);
+		if (/bmp/.test(type)) {
+			getImageData(canvasId, x, y, width, height, function(data, err) {
+				var strData = genBitmapImage(data);
+				tools_7(done) && done(makeURI(strData, 'image/' + type), err);
+			});
+		} else {
+			console.error('暂不支持生成\'' + type + '\'类型的base64图片');
+		}
+	}
+
+	var CanvasToBase64 = {
+		convertToImage: convertToImage,
+		// convertToPNG: function (width, height, done) {
+		//   return convertToImage(width, height, 'png', done)
+		// },
+		// convertToJPEG: function (width, height, done) {
+		//   return convertToImage(width, height, 'jpeg', done)
+		// },
+		// convertToGIF: function (width, height, done) {
+		//   return convertToImage(width, height, 'gif', done)
+		// },
+		convertToBMP: function(ref, done) {
+			if (ref === void 0) ref = {};
+			var canvasId = ref.canvasId;
+			var x = ref.x;
+			var y = ref.y;
+			var width = ref.width;
+			var height = ref.height;
+			if (done === void 0) done = function() {};
+
+			return convertToImage(canvasId, x, y, width, height, 'bmp', done)
+		}
+	};
+
+	function methods() {
+		var self = this;
+
+		var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度
+		var boundHeight = self.height; // 裁剪框默认高度,即整个画布高度
+
+		var id = self.id;
+		var targetId = self.targetId;
+		var pixelRatio = self.pixelRatio;
+
+		var ref = self.cut;
+		var x = ref.x;
+		if (x === void 0) x = 0;
+		var y = ref.y;
+		if (y === void 0) y = 0;
+		var width = ref.width;
+		if (width === void 0) width = boundWidth;
+		var height = ref.height;
+		if (height === void 0) height = boundHeight;
+
+		self.updateCanvas = function(done) {
+			if (self.croperTarget) {
+				//  画布绘制图片
+				self.ctx.drawImage(
+					self.croperTarget,
+					self.imgLeft,
+					self.imgTop,
+					self.scaleWidth,
+					self.scaleHeight
+				);
+			}
+			tools_7(self.onBeforeDraw) && self.onBeforeDraw(self.ctx, self);
+
+			self.setBoundStyle(self.boundStyle); //	设置边界样式
+
+			self.ctx.draw(false, done);
+			return self
+		};
+
+		self.pushOrigin = self.pushOrign = function(src) {
+			self.src = src;
+
+			tools_7(self.onBeforeImageLoad) && self.onBeforeImageLoad(self.ctx, self);
+
+			return getImageInfo({
+					src: src
+				})
+				.then(function(res) {
+					var innerAspectRadio = res.width / res.height;
+					var customAspectRadio = width / height;
+
+					self.croperTarget = res.path;
+
+					if (innerAspectRadio < customAspectRadio) {
+						self.rectX = x;
+						self.baseWidth = width;
+						self.baseHeight = width / innerAspectRadio;
+						self.rectY = y - Math.abs((height - self.baseHeight) / 2);
+					} else {
+						self.rectY = y;
+						self.baseWidth = height * innerAspectRadio;
+						self.baseHeight = height;
+						self.rectX = x - Math.abs((width - self.baseWidth) / 2);
+					}
+
+					self.imgLeft = self.rectX;
+					self.imgTop = self.rectY;
+					self.scaleWidth = self.baseWidth;
+					self.scaleHeight = self.baseHeight;
+
+					self.update();
+
+					return new Promise(function(resolve) {
+						self.updateCanvas(resolve);
+					})
+				})
+				.then(function() {
+					tools_7(self.onImageLoad) && self.onImageLoad(self.ctx, self);
+				})
+		};
+
+		self.removeImage = function() {
+			self.src = '';
+			self.croperTarget = '';
+			return draw(self.ctx)
+		};
+
+		self.getCropperBase64 = function(done) {
+			if (done === void 0) done = function() {};
+
+			CanvasToBase64.convertToBMP({
+				canvasId: id,
+				x: x,
+				y: y,
+				width: width,
+				height: height
+			}, done);
+		};
+
+		self.getCropperImage = function(opt, fn) {
+			var customOptions = opt;
+
+			var canvasOptions = {
+				canvasId: id,
+				x: x,
+				y: y,
+				width: width,
+				height: height
+			};
+
+			var task = function() {
+				return Promise.resolve();
+			};
+
+			if (
+				tools_10(customOptions) &&
+				customOptions.original
+			) {
+				// original mode
+				task = function() {
+					self.targetCtx.drawImage(
+						self.croperTarget,
+						self.imgLeft * pixelRatio,
+						self.imgTop * pixelRatio,
+						self.scaleWidth * pixelRatio,
+						self.scaleHeight * pixelRatio
+					);
+
+					canvasOptions = {
+						canvasId: targetId,
+						x: x * pixelRatio,
+						y: y * pixelRatio,
+						width: width * pixelRatio,
+						height: height * pixelRatio
+					};
+
+					return draw(self.targetCtx)
+				};
+			}
+
+			return task()
+				.then(function() {
+					if (tools_10(customOptions)) {
+						canvasOptions = Object.assign({}, canvasOptions, customOptions);
+					}
+
+					if (tools_7(customOptions)) {
+						fn = customOptions;
+					}
+
+					var arg = canvasOptions.componentContext ?
+						[canvasOptions, canvasOptions.componentContext] :
+						[canvasOptions];
+
+					return canvasToTempFilePath.apply(null, arg)
+				})
+				.then(function(res) {
+					var tempFilePath = res.tempFilePath;
+
+					return tools_7(fn) ?
+						fn.call(self, tempFilePath, null) :
+						tempFilePath
+				})
+				.catch(function(err) {
+					if (tools_7(fn)) {
+						fn.call(self, null, err);
+					} else {
+						throw err
+					}
+				})
+		};
+	}
+
+	/**
+	 * 获取最新缩放值
+	 * @param oldScale 上一次触摸结束后的缩放值
+	 * @param oldDistance 上一次触摸结束后的双指距离
+	 * @param zoom 缩放系数
+	 * @param touch0 第一指touch对象
+	 * @param touch1 第二指touch对象
+	 * @returns {*}
+	 */
+	var getNewScale = function(oldScale, oldDistance, zoom, touch0, touch1) {
+		var xMove, yMove, newDistance;
+		// 计算二指最新距离
+		xMove = Math.round(touch1.x - touch0.x);
+		yMove = Math.round(touch1.y - touch0.y);
+		newDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove));
+
+		return oldScale + 0.001 * zoom * (newDistance - oldDistance)
+	};
+
+	function update() {
+		var self = this;
+
+		if (!self.src) {
+			return
+		}
+
+		self.__oneTouchStart = function(touch) {
+			self.touchX0 = Math.round(touch.x);
+			self.touchY0 = Math.round(touch.y);
+		};
+
+		self.__oneTouchMove = function(touch) {
+			var xMove, yMove;
+			// 计算单指移动的距离
+			if (self.touchended) {
+				return self.updateCanvas()
+			}
+			xMove = Math.round(touch.x - self.touchX0);
+			yMove = Math.round(touch.y - self.touchY0);
+
+			var imgLeft = Math.round(self.rectX + xMove);
+			var imgTop = Math.round(self.rectY + yMove);
+
+			self.outsideBound(imgLeft, imgTop);
+
+			self.updateCanvas();
+		};
+
+		self.__twoTouchStart = function(touch0, touch1) {
+			var xMove, yMove, oldDistance;
+
+			self.touchX1 = Math.round(self.rectX + self.scaleWidth / 2);
+			self.touchY1 = Math.round(self.rectY + self.scaleHeight / 2);
+
+			// 计算两指距离
+			xMove = Math.round(touch1.x - touch0.x);
+			yMove = Math.round(touch1.y - touch0.y);
+			oldDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove));
+
+			self.oldDistance = oldDistance;
+		};
+
+		self.__twoTouchMove = function(touch0, touch1) {
+			var oldScale = self.oldScale;
+			var oldDistance = self.oldDistance;
+			var scale = self.scale;
+			var zoom = self.zoom;
+
+			self.newScale = getNewScale(oldScale, oldDistance, zoom, touch0, touch1);
+
+			//  设定缩放范围
+			self.newScale <= 1 && (self.newScale = 1);
+			self.newScale >= scale && (self.newScale = scale);
+
+			self.scaleWidth = Math.round(self.newScale * self.baseWidth);
+			self.scaleHeight = Math.round(self.newScale * self.baseHeight);
+			var imgLeft = Math.round(self.touchX1 - self.scaleWidth / 2);
+			var imgTop = Math.round(self.touchY1 - self.scaleHeight / 2);
+
+			self.outsideBound(imgLeft, imgTop);
+
+			self.updateCanvas();
+		};
+
+		self.__xtouchEnd = function() {
+			self.oldScale = self.newScale;
+			self.rectX = self.imgLeft;
+			self.rectY = self.imgTop;
+		};
+	}
+
+	var handle = {
+		//  图片手势初始监测
+		touchStart: function touchStart(e) {
+			var self = this;
+			var ref = e.touches;
+			var touch0 = ref[0];
+			var touch1 = ref[1];
+
+			if (!self.src) {
+				return
+			}
+
+			setTouchState(self, true, null, null);
+
+			// 计算第一个触摸点的位置,并参照改点进行缩放
+			self.__oneTouchStart(touch0);
+
+			// 两指手势触发
+			if (e.touches.length >= 2) {
+				self.__twoTouchStart(touch0, touch1);
+			}
+		},
+
+		//  图片手势动态缩放
+		touchMove: function touchMove(e) {
+			var self = this;
+			var ref = e.touches;
+			var touch0 = ref[0];
+			var touch1 = ref[1];
+
+			if (!self.src) {
+				return
+			}
+
+			setTouchState(self, null, true);
+
+			// 单指手势时触发
+			if (e.touches.length === 1) {
+				self.__oneTouchMove(touch0);
+			}
+			// 两指手势触发
+			if (e.touches.length >= 2) {
+				self.__twoTouchMove(touch0, touch1);
+			}
+		},
+
+		touchEnd: function touchEnd(e) {
+			var self = this;
+
+			if (!self.src) {
+				return
+			}
+
+			setTouchState(self, false, false, true);
+			self.__xtouchEnd();
+		}
+	};
+
+	function cut() {
+		var self = this;
+		var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度
+		var boundHeight = self.height;
+		// 裁剪框默认高度,即整个画布高度
+		var ref = self.cut;
+		var x = ref.x;
+		if (x === void 0) x = 0;
+		var y = ref.y;
+		if (y === void 0) y = 0;
+		var width = ref.width;
+		if (width === void 0) width = boundWidth;
+		var height = ref.height;
+		if (height === void 0) height = boundHeight;
+
+		/**
+		 * 设置边界
+		 * @param imgLeft 图片左上角横坐标值
+		 * @param imgTop 图片左上角纵坐标值
+		 */
+		self.outsideBound = function(imgLeft, imgTop) {
+			self.imgLeft = imgLeft >= x ?
+				x :
+				self.scaleWidth + imgLeft - x <= width ?
+				x + width - self.scaleWidth :
+				imgLeft;
+
+			self.imgTop = imgTop >= y ?
+				y :
+				self.scaleHeight + imgTop - y <= height ?
+				y + height - self.scaleHeight :
+				imgTop;
+		};
+
+		/**
+		 * 设置边界样式
+		 * @param color	边界颜色
+		 */
+		self.setBoundStyle = function(ref) {
+			if (ref === void 0) ref = {};
+			var color = ref.color;
+			if (color === void 0) color = '#04b00f';
+			var mask = ref.mask;
+			if (mask === void 0) mask = 'rgba(0, 0, 0, 0.3)';
+			var lineWidth = ref.lineWidth;
+			if (lineWidth === void 0) lineWidth = 1;
+
+			var half = lineWidth / 2;
+			var boundOption = [{
+					start: {
+						x: x - half,
+						y: y + 10 - half
+					},
+					step1: {
+						x: x - half,
+						y: y - half
+					},
+					step2: {
+						x: x + 10 - half,
+						y: y - half
+					}
+				},
+				{
+					start: {
+						x: x - half,
+						y: y + height - 10 + half
+					},
+					step1: {
+						x: x - half,
+						y: y + height + half
+					},
+					step2: {
+						x: x + 10 - half,
+						y: y + height + half
+					}
+				},
+				{
+					start: {
+						x: x + width - 10 + half,
+						y: y - half
+					},
+					step1: {
+						x: x + width + half,
+						y: y - half
+					},
+					step2: {
+						x: x + width + half,
+						y: y + 10 - half
+					}
+				},
+				{
+					start: {
+						x: x + width + half,
+						y: y + height - 10 + half
+					},
+					step1: {
+						x: x + width + half,
+						y: y + height + half
+					},
+					step2: {
+						x: x + width - 10 + half,
+						y: y + height + half
+					}
+				}
+			];
+
+			// 绘制半透明层
+			self.ctx.beginPath();
+			self.ctx.setFillStyle(mask);
+			self.ctx.fillRect(0, 0, x, boundHeight);
+			self.ctx.fillRect(x, 0, width, y);
+			self.ctx.fillRect(x, y + height, width, boundHeight - y - height);
+			self.ctx.fillRect(x + width, 0, boundWidth - x - width, boundHeight);
+			self.ctx.fill();
+
+			boundOption.forEach(function(op) {
+				self.ctx.beginPath();
+				self.ctx.setStrokeStyle(color);
+				self.ctx.setLineWidth(lineWidth);
+				self.ctx.moveTo(op.start.x, op.start.y);
+				self.ctx.lineTo(op.step1.x, op.step1.y);
+				self.ctx.lineTo(op.step2.x, op.step2.y);
+				self.ctx.stroke();
+			});
+		};
+	}
+
+	var version = "1.3.9";
+
+	var WeCropper = function WeCropper(params) {
+		var self = this;
+		var _default = {};
+
+		validator(self, DEFAULT);
+
+		Object.keys(DEFAULT).forEach(function(key) {
+			_default[key] = DEFAULT[key].default;
+		});
+		Object.assign(self, _default, params);
+
+		self.prepare();
+		self.attachPage();
+		self.createCtx();
+		self.observer();
+		self.cutt();
+		self.methods();
+		self.init();
+		self.update();
+
+		return self
+	};
+
+	WeCropper.prototype.init = function init() {
+		var self = this;
+		var src = self.src;
+
+		self.version = version;
+
+		typeof self.onReady === 'function' && self.onReady(self.ctx, self);
+
+		if (src) {
+			self.pushOrign(src);
+		} else {
+			self.updateCanvas();
+		}
+		setTouchState(self, false, false, false);
+
+		self.oldScale = 1;
+		self.newScale = 1;
+
+		return self
+	};
+
+	Object.assign(WeCropper.prototype, handle);
+
+	WeCropper.prototype.prepare = prepare;
+	WeCropper.prototype.observer = observer;
+	WeCropper.prototype.methods = methods;
+	WeCropper.prototype.cutt = cut;
+	WeCropper.prototype.update = update;
+
+	return WeCropper;
+
+})));

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 24 - 0
uview-ui/components/u-avatar/u-avatar.vue


+ 153 - 0
uview-ui/components/u-back-top/u-back-top.vue

@@ -0,0 +1,153 @@
+<template>
+	<view @tap="backToTop" class="u-back-top" :class="['u-back-top--mode--' + mode]" :style="[{
+		bottom: bottom + 'rpx',
+		right: right + 'rpx',
+		borderRadius: mode == 'circle' ? '10000rpx' : '8rpx',
+		zIndex: uZIndex,
+		opacity: opacity
+	}, customStyle]">
+		<view class="u-back-top__content" v-if="!$slots.default && !$slots.$default">
+			<u-icon @click="backToTop" :name="icon" :custom-style="iconStyle"></u-icon>
+			<view class="u-back-top__content__tips">
+				{{tips}}
+			</view>
+		</view>
+		<slot v-else />
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'u-back-top',
+		props: {
+			// 返回顶部的形状,circle-圆形,square-方形
+			mode: {
+				type: String,
+				default: 'circle'
+			},
+			// 自定义图标
+			icon: {
+				type: String,
+				default: 'arrow-upward'
+			},
+			// 提示文字
+			tips: {
+				type: String,
+				default: ''
+			},
+			// 返回顶部滚动时间
+			duration: {
+				type: [Number, String],
+				default: 100
+			},
+			// 滚动距离
+			scrollTop: {
+				type: [Number, String],
+				default: 0
+			},
+			// 距离顶部多少距离显示,单位rpx
+			top: {
+				type: [Number, String],
+				default: 400
+			},
+			// 返回顶部按钮到底部的距离,单位rpx
+			bottom: {
+				type: [Number, String],
+				default: 200
+			},
+			// 返回顶部按钮到右边的距离,单位rpx
+			right: {
+				type: [Number, String],
+				default: 40
+			},
+			// 层级
+			zIndex: {
+				type: [Number, String],
+				default: '9'
+			},
+			// 图标的样式,对象形式
+			iconStyle: {
+				type: Object,
+				default() {
+					return {
+						color: '#909399',
+						fontSize: '38rpx'
+					}
+				}
+			},
+			// 整个组件的样式
+			customStyle: {
+				type: Object,
+				default() {
+					return {}
+				}
+			}
+		},
+		watch: {
+			showBackTop(nVal, oVal) {
+				// 当组件的显示与隐藏状态发生跳变时,修改组件的层级和不透明度
+				// 让组件有显示和消失的动画效果,如果用v-if控制组件状态,将无设置动画效果
+				if(nVal) {
+					this.uZIndex = this.zIndex;
+					this.opacity = 1;
+				} else {
+					this.uZIndex = -1;
+					this.opacity = 0;
+				}
+			}
+		},
+		computed: {
+			showBackTop() {
+				// 由于scrollTop为页面的滚动距离,默认为px单位,这里将用于传入的top(rpx)值
+				// 转为px用于比较,如果滚动条到顶的距离大于设定的距离,就显示返回顶部的按钮
+				return this.scrollTop > uni.upx2px(this.top);
+			},
+		},
+		data() {
+			return {
+				// 不透明度,为了让组件有一个显示和隐藏的过渡动画
+				opacity: 0,
+				// 组件的z-index值,隐藏时设置为-1,就会看不到
+				uZIndex: -1
+			}
+		},
+		methods: {
+			backToTop() {
+				uni.pageScrollTo({
+					scrollTop: 0,
+					duration: this.duration
+				});
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+	
+	.u-back-top {
+		width: 80rpx;
+		height: 80rpx;
+		position: fixed;
+		z-index: 9;
+		@include vue-flex;
+		flex-direction: column;
+		justify-content: center;
+		background-color: #E1E1E1;
+		color: $u-content-color;
+		align-items: center;
+		transition: opacity 0.4s;
+		
+		&__content {
+			@include vue-flex;
+			flex-direction: column;
+			align-items: center;
+			
+			&__tips {
+				font-size: 24rpx;
+				transform: scale(0.8);
+				line-height: 1;
+			}
+		}
+	}
+</style>

+ 216 - 0
uview-ui/components/u-badge/u-badge.vue

@@ -0,0 +1,216 @@
+<template>
+	<view v-if="show" class="u-badge" :class="[
+			isDot ? 'u-badge-dot' : '', 
+			size == 'mini' ? 'u-badge-mini' : '',
+			type ? 'u-badge--bg--' + type : ''
+		]" :style="[{
+			top: offset[0] + 'rpx',
+			right: offset[1] + 'rpx',
+			fontSize: fontSize + 'rpx',
+			position: absolute ? 'absolute' : 'static',
+			color: color,
+			backgroundColor: bgColor
+		}, boxStyle]"
+	>
+		{{showText}}
+	</view>
+</template>
+
+<script>
+	/**
+	 * badge 角标
+	 * @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
+	 * @tutorial https://www.uviewui.com/components/badge.html
+	 * @property {String Number} count 展示的数字,大于 overflowCount 时显示为 ${overflowCount}+,为0且show-zero为false时隐藏
+	 * @property {Boolean} is-dot 不展示数字,只有一个小点(默认false)
+	 * @property {Boolean} absolute 组件是否绝对定位,为true时,offset参数才有效(默认true)
+	 * @property {String Number} overflow-count 展示封顶的数字值(默认99)
+	 * @property {String} type 使用预设的背景颜色(默认error)
+	 * @property {Boolean} show-zero 当数值为 0 时,是否展示 Badge(默认false)
+	 * @property {String} size Badge的尺寸,设为mini会得到小一号的Badge(默认default)
+	 * @property {Array} offset 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,单位rpx。absolute为true时有效(默认[20, 20])
+	 * @property {String} color 字体颜色(默认#ffffff)
+	 * @property {String} bgColor 背景颜色,优先级比type高,如设置,type参数会失效
+	 * @property {Boolean} is-center 组件中心点是否和父组件右上角重合,优先级比offset高,如设置,offset参数会失效(默认false)
+	 * @example <u-badge type="error" count="7"></u-badge>
+	 */
+	export default {
+		name: 'u-badge',
+		props: {
+			// primary,warning,success,error,info
+			type: {
+				type: String,
+				default: 'error'
+			},
+			// default, mini
+			size: {
+				type: String,
+				default: 'default'
+			},
+			//是否是圆点
+			isDot: {
+				type: Boolean,
+				default: false
+			},
+			// 显示的数值内容
+			count: {
+				type: [Number, String],
+			},
+			// 展示封顶的数字值
+			overflowCount: {
+				type: Number,
+				default: 99
+			},
+			// 当数值为 0 时,是否展示 Badge
+			showZero: {
+				type: Boolean,
+				default: false
+			},
+			// 位置偏移
+			offset: {
+				type: Array,
+				default: () => {
+					return [20, 20]
+				}
+			},
+			// 是否开启绝对定位,开启了offset才会起作用
+			absolute: {
+				type: Boolean,
+				default: true
+			},
+			// 字体大小
+			fontSize: {
+				type: [String, Number],
+				default: '24'
+			},
+			// 字体演示
+			color: {
+				type: String,
+				default: '#ffffff'
+			},
+			// badge的背景颜色
+			bgColor: {
+				type: String,
+				default: ''
+			},
+			// 是否让badge组件的中心点和父组件右上角重合,配置的话,offset将会失效
+			isCenter: {
+				type: Boolean,
+				default: false
+			}
+		},
+		computed: {
+			// 是否将badge中心与父组件右上角重合
+			boxStyle() {
+				let style = {};
+				if(this.isCenter) {
+					style.top = 0;
+					style.right = 0;
+					// Y轴-50%,意味着badge向上移动了badge自身高度一半,X轴50%,意味着向右移动了自身宽度一半
+					style.transform = "translateY(-50%) translateX(50%)";
+				} else {
+					style.top = this.offset[0] + 'rpx';
+					style.right = this.offset[1] + 'rpx';
+					style.transform = "translateY(0) translateX(0)";
+				}
+				// 如果尺寸为mini,后接上scal()
+				if(this.size == 'mini') {
+					style.transform = style.transform + " scale(0.8)";
+				}
+				return style;
+			},
+			// isDot类型时,不显示文字
+			showText() {
+				if(this.isDot) return '';
+				else {
+					if(this.count > this.overflowCount) return `${this.overflowCount}+`;
+					else return this.count;
+				}
+			},
+			// 是否显示组件
+			show() {
+				// 如果count的值为0,并且showZero设置为false,不显示组件
+				if(this.count == 0 && this.showZero == false) return false;
+				else return true;
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+	
+	.u-badge {
+		/* #ifndef APP-NVUE */
+		display: inline-flex;
+		/* #endif */
+		justify-content: center;
+		align-items: center;
+		line-height: 24rpx;
+		padding: 4rpx 8rpx;
+		border-radius: 100rpx;
+		z-index: 9;
+		
+		&--bg--primary {
+			background-color: $u-type-primary;
+		}
+		
+		&--bg--error {
+			background-color: $u-type-error;
+		}
+		
+		&--bg--success {
+			background-color: $u-type-success;
+		}
+		
+		&--bg--info {
+			background-color: $u-type-info;
+		}
+		
+		&--bg--warning {
+			background-color: $u-type-warning;
+		}
+	}
+	
+	.u-badge-dot {
+		height: 16rpx;
+		width: 16rpx;
+		border-radius: 100rpx;
+		line-height: 1;
+	}
+	
+	.u-badge-mini {
+		transform: scale(0.8);
+		transform-origin: center center;
+	}
+	
+	// .u-primary {
+	// 	background: $u-type-primary;
+	// 	color: #fff;
+	// }
+	
+	// .u-error {
+	// 	background: $u-type-error;
+	// 	color: #fff;
+	// }
+	
+	// .u-warning {
+	// 	background: $u-type-warning;
+	// 	color: #fff;
+	// }
+	
+	// .u-success {
+	// 	background: $u-type-success;
+	// 	color: #fff;
+	// }
+	
+	// .u-black {
+	// 	background: #585858;
+	// 	color: #fff;
+	// }
+	
+	.u-info {
+		background-color: $u-type-info;
+		color: #fff;
+	}
+</style>

+ 596 - 0
uview-ui/components/u-button/u-button.vue

@@ -0,0 +1,596 @@
+<template>
+	<button
+		id="u-wave-btn"
+		class="u-btn u-line-1 u-fix-ios-appearance"
+		:class="[
+			'u-size-' + size,
+			plain ? 'u-btn--' + type + '--plain' : '',
+			loading ? 'u-loading' : '',
+			shape == 'circle' ? 'u-round-circle' : '',
+			hairLine ? showHairLineBorder : 'u-btn--bold-border',
+			'u-btn--' + type,
+			disabled ? `u-btn--${type}--disabled` : '',
+		]"
+		:hover-start-time="Number(hoverStartTime)"
+		:hover-stay-time="Number(hoverStayTime)"
+		:disabled="disabled"
+		:form-type="formType"
+		:open-type="openType"
+		:app-parameter="appParameter"
+		:hover-stop-propagation="hoverStopPropagation"
+		:send-message-title="sendMessageTitle"
+		send-message-path="sendMessagePath"
+		:lang="lang"
+		:data-name="dataName"
+		:session-from="sessionFrom"
+		:send-message-img="sendMessageImg"
+		:show-message-card="showMessageCard"
+		@getphonenumber="getphonenumber"
+		@getuserinfo="getuserinfo"
+		@error="error"
+		@opensetting="opensetting"
+		@launchapp="launchapp"
+		:style="[customStyle, {
+			overflow: ripple ? 'hidden' : 'visible'
+		}]"
+		@tap.stop="click($event)"
+		:hover-class="getHoverClass"
+		:loading="loading"
+	>
+		<slot></slot>
+		<view
+			v-if="ripple"
+			class="u-wave-ripple"
+			:class="[waveActive ? 'u-wave-active' : '']"
+			:style="{
+				top: rippleTop + 'px',
+				left: rippleLeft + 'px',
+				width: fields.targetWidth + 'px',
+				height: fields.targetWidth + 'px',
+				'background-color': rippleBgColor || 'rgba(0, 0, 0, 0.15)'
+			}"
+		></view>
+	</button>
+</template>
+
+<script>
+/**
+ * button 按钮
+ * @description Button 按钮
+ * @tutorial https://www.uviewui.com/components/button.html
+ * @property {String} size 按钮的大小
+ * @property {Boolean} ripple 是否开启点击水波纹效果
+ * @property {String} ripple-bg-color 水波纹的背景色,ripple为true时有效
+ * @property {String} type 按钮的样式类型
+ * @property {Boolean} plain 按钮是否镂空,背景色透明
+ * @property {Boolean} disabled 是否禁用
+ * @property {Boolean} hair-line 是否显示按钮的细边框(默认true)
+ * @property {Boolean} shape 按钮外观形状,见文档说明
+ * @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈)
+ * @property {String} form-type 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
+ * @property {String} open-type 开放能力
+ * @property {String} data-name 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
+ * @property {String} hover-class 指定按钮按下去的样式类。当 hover-class="none" 时,没有点击态效果(App-nvue 平台暂不支持)
+ * @property {Number} hover-start-time 按住后多久出现点击态,单位毫秒
+ * @property {Number} hover-stay-time 手指松开后点击态保留时间,单位毫秒
+ * @property {Object} custom-style 对按钮的自定义样式,对象形式,见文档说明
+ * @event {Function} click 按钮点击
+ * @event {Function} getphonenumber open-type="getPhoneNumber"时有效
+ * @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo
+ * @event {Function} error 当使用开放能力时,发生错误的回调
+ * @event {Function} opensetting 在打开授权设置页并关闭后回调
+ * @event {Function} launchapp 打开 APP 成功的回调
+ * @example <u-button>月落</u-button>
+ */
+export default {
+	name: 'u-button',
+	props: {
+		// 是否细边框
+		hairLine: {
+			type: Boolean,
+			default: true
+		},
+		// 按钮的预置样式,default,primary,error,warning,success
+		type: {
+			type: String,
+			default: 'default'
+		},
+		// 按钮尺寸,default,medium,mini
+		size: {
+			type: String,
+			default: 'default'
+		},
+		// 按钮形状,circle(两边为半圆),square(带圆角)
+		shape: {
+			type: String,
+			default: 'square'
+		},
+		// 按钮是否镂空
+		plain: {
+			type: Boolean,
+			default: false
+		},
+		// 是否禁止状态
+		disabled: {
+			type: Boolean,
+			default: false
+		},
+		// 是否加载中
+		loading: {
+			type: Boolean,
+			default: false
+		},
+		// 开放能力,具体请看uniapp稳定关于button组件部分说明
+		// https://uniapp.dcloud.io/component/button
+		openType: {
+			type: String,
+			default: ''
+		},
+		// 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
+		// 取值为submit(提交表单),reset(重置表单)
+		formType: {
+			type: String,
+			default: ''
+		},
+		// 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
+		// 只微信小程序、QQ小程序有效
+		appParameter: {
+			type: String,
+			default: ''
+		},
+		// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
+		hoverStopPropagation: {
+			type: Boolean,
+			default: false
+		},
+		// 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
+		lang: {
+			type: String,
+			default: 'en'
+		},
+		// 会话来源,open-type="contact"时有效。只微信小程序有效
+		sessionFrom: {
+			type: String,
+			default: ''
+		},
+		// 会话内消息卡片标题,open-type="contact"时有效
+		// 默认当前标题,只微信小程序有效
+		sendMessageTitle: {
+			type: String,
+			default: ''
+		},
+		// 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
+		// 默认当前分享路径,只微信小程序有效
+		sendMessagePath: {
+			type: String,
+			default: ''
+		},
+		// 会话内消息卡片图片,open-type="contact"时有效
+		// 默认当前页面截图,只微信小程序有效
+		sendMessageImg: {
+			type: String,
+			default: ''
+		},
+		// 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
+		// 用户点击后可以快速发送小程序消息,open-type="contact"时有效
+		showMessageCard: {
+			type: Boolean,
+			default: false
+		},
+		// 手指按(触摸)按钮时按钮时的背景颜色
+		hoverBgColor: {
+			type: String,
+			default: ''
+		},
+		// 水波纹的背景颜色
+		rippleBgColor: {
+			type: String,
+			default: ''
+		},
+		// 是否开启水波纹效果
+		ripple: {
+			type: Boolean,
+			default: false
+		},
+		// 按下的类名
+		hoverClass: {
+			type: String,
+			default: ''
+		},
+		// 自定义样式,对象形式
+		customStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
+		dataName: {
+			type: String,
+			default: ''
+		},
+		// 节流,一定时间内只能触发一次
+		throttleTime: {
+			type: [String, Number],
+			default: 1000
+		},
+		// 按住后多久出现点击态,单位毫秒
+		hoverStartTime: {
+			type: [String, Number],
+			default: 20
+		},
+		// 手指松开后点击态保留时间,单位毫秒
+		hoverStayTime: {
+			type: [String, Number],
+			default: 150
+		},
+	},
+	computed: {
+		// 当没有传bgColor变量时,按钮按下去的颜色类名
+		getHoverClass() {
+			// 如果开启水波纹效果,则不启用hover-class效果
+			if (this.loading || this.disabled || this.ripple || this.hoverClass) return '';
+			let hoverClass = '';
+			hoverClass = this.plain ? 'u-' + this.type + '-plain-hover' : 'u-' + this.type + '-hover';
+			return hoverClass;
+		},
+		// 在'primary', 'success', 'error', 'warning'类型下,不显示边框,否则会造成四角有毛刺现象
+		showHairLineBorder() {
+			if (['primary', 'success', 'error', 'warning'].indexOf(this.type) >= 0 && !this.plain) {
+				return '';
+			} else {
+				return 'u-hairline-border';
+			}
+		}
+	},
+	data() {
+		return {
+			rippleTop: 0, // 水波纹的起点Y坐标到按钮上边界的距离
+			rippleLeft: 0, // 水波纹起点X坐标到按钮左边界的距离
+			fields: {}, // 波纹按钮节点信息
+			waveActive: false // 激活水波纹
+		};
+	},
+	methods: {
+		// 按钮点击
+		click(e) {
+			// 进行节流控制,每this.throttle毫秒内,只在开始处执行
+			this.$u.throttle(() => {
+				// 如果按钮时disabled和loading状态,不触发水波纹效果
+				if (this.loading === true || this.disabled === true) return;
+				// 是否开启水波纹效果
+				if (this.ripple) {
+					// 每次点击时,移除上一次的类,再次添加,才能触发动画效果
+					this.waveActive = false;
+					this.$nextTick(function() {
+						this.getWaveQuery(e);
+					});
+				}
+				this.$emit('click', e);
+			}, this.throttleTime);
+		},
+		// 查询按钮的节点信息
+		getWaveQuery(e) {
+			this.getElQuery().then(res => {
+				// 查询返回的是一个数组节点
+				let data = res[0];
+				// 查询不到节点信息,不操作
+				if (!data.width || !data.width) return;
+				// 水波纹的最终形态是一个正方形(通过border-radius让其变为一个圆形),这里要保证正方形的边长等于按钮的最长边
+				// 最终的方形(变换后的圆形)才能覆盖整个按钮
+				data.targetWidth = data.height > data.width ? data.height : data.width;
+				if (!data.targetWidth) return;
+				this.fields = data;
+				let touchesX = '',
+					touchesY = '';
+				// #ifdef MP-BAIDU
+				touchesX = e.changedTouches[0].clientX;
+				touchesY = e.changedTouches[0].clientY;
+				// #endif
+				// #ifdef MP-ALIPAY
+				touchesX = e.detail.clientX;
+				touchesY = e.detail.clientY;
+				// #endif
+				// #ifndef MP-BAIDU || MP-ALIPAY
+				touchesX = e.touches[0].clientX;
+				touchesY = e.touches[0].clientY;
+				// #endif
+				// 获取触摸点相对于按钮上边和左边的x和y坐标,原理是通过屏幕的触摸点(touchesY),减去按钮的上边界data.top
+				// 但是由于`transform-origin`默认是center,所以这里再减去半径才是水波纹view应该的位置
+				// 总的来说,就是把水波纹的矩形(变换后的圆形)的中心点,移动到我们的触摸点位置
+				this.rippleTop = touchesY - data.top - data.targetWidth / 2;
+				this.rippleLeft = touchesX - data.left - data.targetWidth / 2;
+				this.$nextTick(() => {
+					this.waveActive = true;
+				});
+			});
+		},
+		// 获取节点信息
+		getElQuery() {
+			return new Promise(resolve => {
+				let queryInfo = '';
+				// 获取元素节点信息,请查看uniapp相关文档
+				// https://uniapp.dcloud.io/api/ui/nodes-info?id=nodesrefboundingclientrect
+				queryInfo = uni.createSelectorQuery().in(this);
+				//#ifdef MP-ALIPAY
+				queryInfo = uni.createSelectorQuery();
+				//#endif
+				queryInfo.select('.u-btn').boundingClientRect();
+				queryInfo.exec(data => {
+					resolve(data);
+				});
+			});
+		},
+		// 下面为对接uniapp官方按钮开放能力事件回调的对接
+		getphonenumber(res) {
+			this.$emit('getphonenumber', res);
+		},
+		getuserinfo(res) {
+			this.$emit('getuserinfo', res);
+		},
+		error(res) {
+			this.$emit('error', res);
+		},
+		opensetting(res) {
+			this.$emit('opensetting', res);
+		},
+		launchapp(res) {
+			this.$emit('launchapp', res);
+		}
+	}
+};
+</script>
+
+<style scoped lang="scss">
+@import '../../libs/css/style.components.scss';
+.u-btn::after {
+	border: none;
+}
+
+.u-btn {
+	position: relative;
+	border: 0;
+	//border-radius: 10rpx;
+	/* #ifndef APP-NVUE */
+	display: inline-flex;		
+	/* #endif */
+	// 避免边框某些场景可能被“裁剪”,不能设置为hidden
+	overflow: visible;
+	line-height: 1;
+	@include vue-flex;
+	align-items: center;
+	justify-content: center;
+	cursor: pointer;
+	padding: 0 40rpx;
+	z-index: 1;
+	box-sizing: border-box;
+	transition: all 0.15s;
+	
+	&--bold-border {
+		border: 1px solid #ffffff;
+	}
+	
+	&--default {
+		color: $u-content-color;
+		border-color: #c0c4cc;
+		background-color: #ffffff;
+	}
+	
+	&--primary {
+		color: #ffffff;
+		border-color: $u-type-primary;
+		background-color: $u-type-primary;
+	}
+	
+	&--success {
+		color: #ffffff;
+		border-color: $u-type-success;
+		background-color: $u-type-success;
+	}
+	
+	&--error {
+		color: #ffffff;
+		border-color: $u-type-error;
+		background-color: $u-type-error;
+	}
+	
+	&--warning {
+		color: #ffffff;
+		border-color: $u-type-warning;
+		background-color: $u-type-warning;
+	}
+	
+	&--default--disabled {
+		color: #ffffff;
+		border-color: #e4e7ed;
+		background-color: #ffffff;
+	}
+	
+	&--primary--disabled {
+		color: #ffffff!important;
+		border-color: $u-type-primary-disabled!important;
+		background-color: $u-type-primary-disabled!important;
+	}
+	
+	&--success--disabled {
+		color: #ffffff!important;
+		border-color: $u-type-success-disabled!important;
+		background-color: $u-type-success-disabled!important;
+	}
+	
+	&--error--disabled {
+		color: #ffffff!important;
+		border-color: $u-type-error-disabled!important;
+		background-color: $u-type-error-disabled!important;
+	}
+	
+	&--warning--disabled {
+		color: #ffffff!important;
+		border-color: $u-type-warning-disabled!important;
+		background-color: $u-type-warning-disabled!important;
+	}
+	
+	&--primary--plain {
+		color: $u-type-primary!important;
+		border-color: $u-type-primary-disabled!important;
+		background-color: $u-type-primary-light!important;
+	}
+	
+	&--success--plain {
+		color: $u-type-success!important;
+		border-color: $u-type-success-disabled!important;
+		background-color: $u-type-success-light!important;
+	}
+	
+	&--error--plain {
+		color: $u-type-error!important;
+		border-color: $u-type-error-disabled!important;
+		background-color: $u-type-error-light!important;
+	}
+	
+	&--warning--plain {
+		color: $u-type-warning!important;
+		border-color: $u-type-warning-disabled!important;
+		background-color: $u-type-warning-light!important;
+	}
+}
+
+.u-hairline-border:after {
+	content: ' ';
+	position: absolute;
+	pointer-events: none;
+	// 设置为border-box,意味着下面的scale缩小为0.5,实际上缩小的是伪元素的内容(border-box意味着内容不含border)
+	box-sizing: border-box;
+	// 中心点作为变形(scale())的原点
+	-webkit-transform-origin: 0 0;
+	transform-origin: 0 0;
+	left: 0;
+	top: 0;
+	width: 199.8%;
+	height: 199.7%;
+	-webkit-transform: scale(0.5, 0.5);
+	transform: scale(0.5, 0.5);
+	border: 1px solid currentColor;
+	z-index: 1;
+}
+
+.u-wave-ripple {
+	z-index: 0;
+	position: absolute;
+	border-radius: 100%;
+	background-clip: padding-box;
+	pointer-events: none;
+	user-select: none;
+	transform: scale(0);
+	opacity: 1;
+	transform-origin: center;
+}
+
+.u-wave-ripple.u-wave-active {
+	opacity: 0;
+	transform: scale(2);
+	transition: opacity 1s linear, transform 0.4s linear;
+}
+
+.u-round-circle {
+	border-radius: 100rpx;
+}
+
+.u-round-circle::after {
+	border-radius: 100rpx;
+}
+
+.u-loading::after {
+	background-color: hsla(0, 0%, 100%, 0.35);
+}
+
+.u-size-default {
+	font-size: 30rpx;
+	height: 80rpx;
+	line-height: 80rpx;
+}
+
+.u-size-medium {
+	/* #ifndef APP-NVUE */
+	display: inline-flex;		
+	/* #endif */
+	width: auto;
+	font-size: 26rpx;
+	height: 70rpx;
+	line-height: 70rpx;
+	padding: 0 80rpx;
+}
+
+.u-size-mini {
+	/* #ifndef APP-NVUE */
+	display: inline-flex;		
+	/* #endif */
+	width: auto;
+	font-size: 22rpx;
+	padding-top: 1px;
+	height: 50rpx;
+	line-height: 50rpx;
+	padding: 0 20rpx;
+}
+
+.u-primary-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-primary-dark !important;
+}
+
+.u-default-plain-hover {
+	color: $u-type-primary-dark !important;
+	background: $u-type-primary-light !important;
+}
+
+.u-success-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-success-dark !important;
+}
+
+.u-warning-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-warning-dark !important;
+}
+
+.u-error-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-error-dark !important;
+}
+
+.u-info-plain-hover {
+	color: #ffffff !important;
+	background: $u-type-info-dark !important;
+}
+
+.u-default-hover {
+	color: $u-type-primary-dark !important;
+	border-color: $u-type-primary-dark !important;
+	background-color: $u-type-primary-light !important;
+}
+
+.u-primary-hover {
+	background: $u-type-primary-dark !important;
+	color: #fff;
+}
+
+.u-success-hover {
+	background: $u-type-success-dark !important;
+	color: #fff;
+}
+
+.u-info-hover {
+	background: $u-type-info-dark !important;
+	color: #fff;
+}
+
+.u-warning-hover {
+	background: $u-type-warning-dark !important;
+	color: #fff;
+}
+
+.u-error-hover {
+	background: $u-type-error-dark !important;
+	color: #fff;
+}
+</style>

+ 639 - 0
uview-ui/components/u-calendar/u-calendar.vue

@@ -0,0 +1,639 @@
+<template>
+	<u-popup closeable :maskCloseAble="maskCloseAble" mode="bottom" :popup="false" v-model="value" length="auto"
+	 :safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex" :border-radius="borderRadius" :closeable="closeable">
+		<view class="u-calendar">
+			<view class="u-calendar__header">
+				<view class="u-calendar__header__text" v-if="!$slots['tooltip']">
+					{{toolTip}}
+				</view>
+				<slot v-else name="tooltip" />
+			</view>
+			<view class="u-calendar__action u-flex u-row-center">
+				<view class="u-calendar__action__icon">
+					<u-icon v-if="changeYear" name="arrow-left-double" :color="yearArrowColor" @click="changeYearHandler(0)"></u-icon>
+				</view>
+				<view class="u-calendar__action__icon">
+					<u-icon v-if="changeMonth" name="arrow-left" :color="monthArrowColor" @click="changeMonthHandler(0)"></u-icon>
+				</view>
+				<view class="u-calendar__action__text">{{ showTitle }}</view>
+				<view class="u-calendar__action__icon">
+					<u-icon v-if="changeMonth" name="arrow-right" :color="monthArrowColor" @click="changeMonthHandler(1)"></u-icon>
+				</view>
+				<view class="u-calendar__action__icon">
+					<u-icon v-if="changeYear" name="arrow-right-double" :color="yearArrowColor" @click="changeYearHandler(1)"></u-icon>
+				</view>
+			</view>
+			<view class="u-calendar__week-day">
+				<view class="u-calendar__week-day__text" v-for="(item, index) in weekDayZh" :key="index">{{item}}</view>
+			</view>
+			<view class="u-calendar__content">
+				<!-- 前置空白部分 -->
+				<block v-for="(item, index) in weekdayArr" :key="index">
+					<view class="u-calendar__content__item"></view>
+				</block>
+				<view class="u-calendar__content__item" :class="{
+					'u-hover-class':openDisAbled(year,month,index+1),
+					'u-calendar__content--start-date': (mode == 'range' && startDate==`${year}-${month}-${index+1}`) || mode== 'date',
+					'u-calendar__content--end-date':(mode== 'range' && endDate==`${year}-${month}-${index+1}`) || mode == 'date'
+				}" :style="{backgroundColor: getColor(index,1)}" v-for="(item, index) in daysArr" :key="index"
+				 @tap="dateClick(index)">
+					<view class="u-calendar__content__item__inner" :style="{color: getColor(index,2)}">
+						<view>{{ index + 1 }}</view>
+					</view>
+					<view class="u-calendar__content__item__tips" :style="{color:activeColor}" v-if="mode== 'range' && startDate==`${year}-${month}-${index+1}` && startDate!=endDate">{{startText}}</view>
+					<view class="u-calendar__content__item__tips" :style="{color:activeColor}" v-if="mode== 'range' && endDate==`${year}-${month}-${index+1}`">{{endText}}</view>
+				</view>
+				<view class="u-calendar__content__bg-month">{{month}}</view>
+			</view>
+			<view class="u-calendar__bottom">
+				<view class="u-calendar__bottom__choose">
+					<text>{{mode == 'date' ? activeDate : startDate}}</text>
+					<text v-if="endDate">至{{endDate}}</text>
+				</view>
+				<view class="u-calendar__bottom__btn">
+					<u-button :type="btnType" shape="circle" size="default" @click="btnFix(false)">确定</u-button>
+				</view>
+			</view>
+		</view>
+	</u-popup>
+</template>
+<script>
+	/**
+	 * calendar 日历
+	 * @description 此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中。
+	 * @tutorial http://uviewui.com/components/calendar.html
+	 * @property {String} mode 选择日期的模式,date-为单个日期,range-为选择日期范围
+	 * @property {Boolean} v-model 布尔值变量,用于控制日历的弹出与收起
+	 * @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
+	 * @property {Boolean} change-year 是否显示顶部的切换年份方向的按钮(默认true)
+	 * @property {Boolean} change-month 是否显示顶部的切换月份方向的按钮(默认true)
+	 * @property {String Number} max-year 可切换的最大年份(默认2050)
+	 * @property {String Number} min-year 最小可选日期(默认1950)
+	 * @property {String Number} min-date 可切换的最小年份(默认1950-01-01)
+	 * @property {String Number} max-date 最大可选日期(默认当前日期)
+	 * @property {String Number} 弹窗顶部左右两边的圆角值,单位rpx(默认20)
+	 * @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭日历(默认true)
+	 * @property {String} month-arrow-color 月份切换按钮箭头颜色(默认#606266)
+	 * @property {String} year-arrow-color 年份切换按钮箭头颜色(默认#909399)
+	 * @property {String} color 日期字体的默认颜色(默认#303133)
+	 * @property {String} active-bg-color 起始/结束日期按钮的背景色(默认#2979ff)
+	 * @property {String Number} z-index 弹出时的z-index值(默认10075)
+	 * @property {String} active-color 起始/结束日期按钮的字体颜色(默认#ffffff)
+	 * @property {String} range-bg-color 起始/结束日期之间的区域的背景颜色(默认rgba(41,121,255,0.13))
+	 * @property {String} range-color 选择范围内字体颜色(默认#2979ff)
+	 * @property {String} start-text 起始日期底部的提示文字(默认 '开始')
+	 * @property {String} end-text 结束日期底部的提示文字(默认 '结束')
+	 * @property {String} btn-type 底部确定按钮的主题(默认 'primary')
+	 * @property {String} toolTip 顶部提示文字,如设置名为tooltip的slot,此参数将失效(默认 '选择日期')
+	 * @property {Boolean} closeable 是否显示右上角的关闭图标(默认true)
+	 * @example <u-calendar v-model="show" :mode="mode"></u-calendar>
+	 */
+	
+	export default {
+		name: 'u-calendar',
+		props: {
+			safeAreaInsetBottom: {
+				type: Boolean,
+				default: false
+			},
+			// 是否允许通过点击遮罩关闭Picker
+			maskCloseAble: {
+				type: Boolean,
+				default: true
+			},
+			// 通过双向绑定控制组件的弹出与收起
+			value: {
+				type: Boolean,
+				default: false
+			},
+			// 弹出的z-index值
+			zIndex: {
+				type: [String, Number],
+				default: 0
+			},
+			// 是否允许切换年份
+			changeYear: {
+				type: Boolean,
+				default: true
+			},
+			// 是否允许切换月份
+			changeMonth: {
+				type: Boolean,
+				default: true
+			},
+			// date-单个日期选择,range-开始日期+结束日期选择
+			mode: {
+				type: String,
+				default: 'date'
+			},
+			// 可切换的最大年份
+			maxYear: {
+				type: [Number, String],
+				default: 2050
+			},
+			// 可切换的最小年份
+			minYear: {
+				type: [Number, String],
+				default: 1950
+			},
+			// 最小可选日期(不在范围内日期禁用不可选)
+			minDate: {
+				type: [Number, String],
+				default: '1950-01-01'
+			},
+			/**
+			 * 最大可选日期
+			 * 默认最大值为今天,之后的日期不可选
+			 * 2030-12-31
+			 * */
+			maxDate: {
+				type: [Number, String],
+				default: ''
+			},
+			// 弹窗顶部左右两边的圆角值
+			borderRadius: {
+				type: [String, Number],
+				default: 20
+			},
+			// 月份切换按钮箭头颜色
+			monthArrowColor: {
+				type: String,
+				default: '#606266'
+			},
+			// 年份切换按钮箭头颜色
+			yearArrowColor: {
+				type: String,
+				default: '#909399'
+			},
+			// 默认日期字体颜色
+			color: {
+				type: String,
+				default: '#303133'
+			},
+			// 选中|起始结束日期背景色
+			activeBgColor: {
+				type: String,
+				default: '#2979ff'
+			},
+			// 选中|起始结束日期字体颜色
+			activeColor: {
+				type: String,
+				default: '#ffffff'
+			},
+			// 范围内日期背景色
+			rangeBgColor: {
+				type: String,
+				default: 'rgba(41,121,255,0.13)'
+			}, 
+			// 范围内日期字体颜色
+			rangeColor: {
+				type: String,
+				default: '#2979ff'
+			},
+			// mode=range时生效,起始日期自定义文案
+			startText: {
+				type: String,
+				default: '开始'
+			},
+			// mode=range时生效,结束日期自定义文案
+			endText: {
+				type: String,
+				default: '结束'
+			},
+			//按钮样式类型
+			btnType: {
+				type: String,
+				default: 'primary'
+			},
+			// 当前选中日期带选中效果
+			isActiveCurrent: {
+				type: Boolean,
+				default: true
+			},
+			// 切换年月是否触发事件 mode=date时生效
+			isChange: {
+				type: Boolean,
+				default: false
+			},
+			// 是否显示右上角的关闭图标
+			closeable: {
+				type: Boolean,
+				default: true
+			},
+			// 顶部的提示文字
+			toolTip: {
+				type: String,
+				default: '选择日期'
+			}
+		},
+		data() {
+			return {
+				// 星期几,值为1-7
+				weekday: 1, 
+				weekdayArr:[],
+				// 当前月有多少天
+				days: 0, 
+				daysArr:[],
+				showTitle: '',
+				year: 2020,
+				month: 0,
+				day: 0,
+				startYear: 0,
+				startMonth: 0,
+				startDay: 0,
+				endYear: 0,
+				endMonth: 0,
+				endDay: 0,
+				today: '',
+				activeDate: '',
+				startDate: '',
+				endDate: '',
+				isStart: true,
+				min: null,
+				max: null,
+				weekDayZh: ['日', '一', '二', '三', '四', '五', '六']
+			};
+		},
+		computed: {
+			dataChange() {
+				return `${this.mode}-${this.minDate}-${this.maxDate}`;
+			},
+			uZIndex() {
+				// 如果用户有传递z-index值,优先使用
+				return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
+			}
+		},
+		watch: {
+			dataChange(val) {
+				this.init()
+			}
+		},
+		created() {
+			this.init()
+		},
+		methods: {
+			getColor(index, type) {
+				let color = type == 1 ? '' : this.color;
+				let day = index + 1
+				let date = `${this.year}-${this.month}-${day}`
+				let timestamp = new Date(date.replace(/\-/g, '/')).getTime();
+				let start = this.startDate.replace(/\-/g, '/')
+				let end = this.endDate.replace(/\-/g, '/')
+				if ((this.isActiveCurrent && this.activeDate == date) || this.startDate == date || this.endDate == date) {
+					color = type == 1 ? this.activeBgColor : this.activeColor;
+				} else if (this.endDate && timestamp > new Date(start).getTime() && timestamp < new Date(end).getTime()) {
+					color = type == 1 ? this.rangeBgColor : this.rangeColor;
+				}
+				return color;
+			},
+			init() {
+				let now = new Date();
+				this.year = now.getFullYear();
+				this.month = now.getMonth() + 1;
+				this.day = now.getDate();
+				this.today = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
+				this.activeDate = this.today;
+				this.min = this.initDate(this.minDate);
+				this.max = this.initDate(this.maxDate || this.today);
+				this.startDate = "";
+				this.startYear = 0;
+				this.startMonth = 0;
+				this.startDay = 0;
+				this.endYear = 0;
+				this.endMonth = 0;
+				this.endDay = 0;
+				this.endDate = "";
+				this.isStart = true;
+				this.changeData();
+			},
+			//日期处理
+			initDate(date) {
+				let fdate = date.split('-');
+				return {
+					year: Number(fdate[0] || 1920),
+					month: Number(fdate[1] || 1),
+					day: Number(fdate[2] || 1)
+				}
+			},
+			openDisAbled: function(year, month, day) {
+				let bool = true;
+				let date = `${year}/${month}/${day}`;
+				// let today = this.today.replace(/\-/g, '/');
+				let min = `${this.min.year}/${this.min.month}/${this.min.day}`;
+				let max = `${this.max.year}/${this.max.month}/${this.max.day}`;
+				let timestamp = new Date(date).getTime();
+				if (timestamp >= new Date(min).getTime() && timestamp <= new Date(max).getTime()) {
+					bool = false;
+				}
+				return bool;
+			},
+			generateArray: function(start, end) {
+				return Array.from(new Array(end + 1).keys()).slice(start);
+			},
+			formatNum: function(num) {
+				return num < 10 ? '0' + num : num + '';
+			},
+			//一个月有多少天
+			getMonthDay(year, month) {
+				let days = new Date(year, month, 0).getDate();
+				return days;
+			},
+			getWeekday(year, month) {
+				let date = new Date(`${year}/${month}/01 00:00:00`);
+				return date.getDay();
+			},
+			checkRange(year) {
+				let overstep = false;
+				if (year < this.minYear || year > this.maxYear) {
+					uni.showToast({
+						title: "日期超出范围啦~",
+						icon: 'none'
+					})
+					overstep = true;
+				}
+				return overstep;
+			},
+			changeMonthHandler(isAdd) {
+				if (isAdd) {
+					let month = this.month + 1;
+					let year = month > 12 ? this.year + 1 : this.year;
+					if (!this.checkRange(year)) {
+						this.month = month > 12 ? 1 : month;
+						this.year = year;
+						this.changeData();
+					}
+
+				} else {
+					let month = this.month - 1;
+					let year = month < 1 ? this.year - 1 : this.year;
+					if (!this.checkRange(year)) {
+						this.month = month < 1 ? 12 : month;
+						this.year = year;
+						this.changeData();
+					}
+				}
+			},
+			changeYearHandler(isAdd) {
+				let year = isAdd ? this.year + 1 : this.year - 1;
+				if (!this.checkRange(year)) {
+					this.year = year;
+					this.changeData();
+				}
+			},
+			changeData() {
+				this.days = this.getMonthDay(this.year, this.month);
+				this.daysArr=this.generateArray(1,this.days)
+				this.weekday = this.getWeekday(this.year, this.month);
+				this.weekdayArr=this.generateArray(1,this.weekday)
+				this.showTitle = `${this.year}年${this.month}月`;
+				if (this.isChange && this.mode == 'date') {
+					this.btnFix(true);
+				}
+			},
+			dateClick: function(day) {
+				day += 1;
+				if (!this.openDisAbled(this.year, this.month, day)) {
+					this.day = day;
+					let date = `${this.year}-${this.month}-${day}`;
+					if (this.mode == 'date') {
+						this.activeDate = date;
+					} else {
+						let compare = new Date(date.replace(/\-/g, '/')).getTime() < new Date(this.startDate.replace(/\-/g, '/')).getTime()
+						if (this.isStart || compare) {
+							this.startDate = date;
+							this.startYear = this.year;
+							this.startMonth = this.month;
+							this.startDay = this.day;
+							this.endYear = 0;
+							this.endMonth = 0;
+							this.endDay = 0;
+							this.endDate = "";
+							this.activeDate = "";
+							this.isStart = false;
+						} else {
+							this.endDate = date;
+							this.endYear = this.year;
+							this.endMonth = this.month;
+							this.endDay = this.day;
+							this.isStart = true;
+						}
+					}
+				}
+			},
+			close() {
+				// 修改通过v-model绑定的父组件变量的值为false,从而隐藏日历弹窗
+				this.$emit('input', false);
+			},
+			getWeekText(date) {
+				date = new Date(`${date.replace(/\-/g, '/')} 00:00:00`);
+				let week = date.getDay();
+				return '星期' + ['日', '一', '二', '三', '四', '五', '六'][week];
+			},
+			btnFix(show) {
+				if (!show) {
+					this.close();
+				}
+				if (this.mode == 'date') {
+					let arr = this.activeDate.split('-')
+					let year = this.isChange ? this.year : Number(arr[0]);
+					let month = this.isChange ? this.month : Number(arr[1]);
+					let day = this.isChange ? this.day : Number(arr[2]);
+					//当前月有多少天
+					let days = this.getMonthDay(year, month);
+					let result = `${year}-${this.formatNum(month)}-${this.formatNum(day)}`;
+					let weekText = this.getWeekText(result);
+					let isToday = false;
+					if (`${year}-${month}-${day}` == this.today) {
+						//今天
+						isToday = true;
+					}
+					this.$emit('change', {
+						year: year,
+						month: month,
+						day: day,
+						days: days,
+						result: result,
+						week: weekText,
+						isToday: isToday,
+						// switch: show //是否是切换年月操作
+					});
+				} else {
+					if (!this.startDate || !this.endDate) return;
+					let startMonth = this.formatNum(this.startMonth);
+					let startDay = this.formatNum(this.startDay);
+					let startDate = `${this.startYear}-${startMonth}-${startDay}`;
+					let startWeek = this.getWeekText(startDate)
+
+					let endMonth = this.formatNum(this.endMonth);
+					let endDay = this.formatNum(this.endDay);
+					let endDate = `${this.endYear}-${endMonth}-${endDay}`;
+					let endWeek = this.getWeekText(endDate);
+					this.$emit('change', {
+						startYear: this.startYear,
+						startMonth: this.startMonth,
+						startDay: this.startDay,
+						startDate: startDate,
+						startWeek: startWeek,
+						endYear: this.endYear,
+						endMonth: this.endMonth,
+						endDay: this.endDay,
+						endDate: endDate,
+						endWeek: endWeek
+					});
+				}
+			}
+		}
+	};
+</script>
+
+<style scoped lang="scss">
+	@import "../../libs/css/style.components.scss";
+	
+	.u-calendar {
+		color: $u-content-color;
+		
+		&__header {
+			width: 100%;
+			box-sizing: border-box;
+			font-size: 30rpx;
+			background-color: #fff;
+			color: $u-main-color;
+			
+			&__text {
+				margin-top: 30rpx;
+				padding: 0 60rpx;
+				@include vue-flex;
+				justify-content: center;
+				align-items: center;
+			}
+		}
+		
+		&__action {
+			padding: 40rpx 0 40rpx 0;
+			
+			&__icon {
+				margin: 0 16rpx;
+			}
+			
+			&__text {
+				padding: 0 16rpx;
+				color: $u-main-color;
+				font-size: 32rpx;
+				line-height: 32rpx;
+				font-weight: bold;
+			}
+		}
+	
+		&__week-day {
+			@include vue-flex;
+			align-items: center;
+			justify-content: center;
+			padding: 6px 0;
+			overflow: hidden;
+			
+			&__text {
+				flex: 1;
+				text-align: center;
+			}
+		}
+	
+		&__content {
+			width: 100%;
+			@include vue-flex;
+			flex-wrap: wrap;
+			padding: 6px 0;
+			box-sizing: border-box;
+			background-color: #fff;
+			position: relative;
+			
+			&--end-date {
+				border-top-right-radius: 8rpx;
+				border-bottom-right-radius: 8rpx;
+			}
+			
+			&--start-date {
+				border-top-left-radius: 8rpx;
+				border-bottom-left-radius: 8rpx;
+			}
+			
+			&__item {
+				width: 14.2857%;
+				@include vue-flex;
+				align-items: center;
+				justify-content: center;
+				padding: 6px 0;
+				overflow: hidden;
+				position: relative;
+				z-index: 2;
+				
+				&__inner {
+					height: 84rpx;
+					@include vue-flex;
+					align-items: center;
+					justify-content: center;
+					flex-direction: column;
+					font-size: 32rpx;
+					position: relative;
+					border-radius: 50%;
+					
+					&__desc {
+						width: 100%;
+						font-size: 24rpx;
+						line-height: 24rpx;
+						transform: scale(0.75);
+						transform-origin: center center;
+						position: absolute;
+						left: 0;
+						text-align: center;
+						bottom: 2rpx;
+					}
+				}
+				
+				&__tips {
+					width: 100%;
+					font-size: 24rpx;
+					line-height: 24rpx;
+					position: absolute;
+					left: 0;
+					transform: scale(0.8);
+					transform-origin: center center;
+					text-align: center;
+					bottom: 8rpx;
+					z-index: 2;
+				}
+			}
+			
+			&__bg-month {
+				position: absolute;
+				font-size: 130px;
+				line-height: 130px;
+				left: 50%;
+				top: 50%;
+				transform: translate(-50%, -50%);
+				color: #e4e7ed;
+				z-index: 1;
+			}
+		}
+	
+		&__bottom {
+			width: 100%;
+			@include vue-flex;
+			align-items: center;
+			justify-content: center;
+			flex-direction: column;
+			background-color: #fff;
+			padding: 0 40rpx 30rpx;
+			box-sizing: border-box;
+			font-size: 24rpx;
+			color: $u-tips-color;
+			
+			&__choose {
+				height: 50rpx;
+			}
+			
+			&__btn {
+				width: 100%;
+			}
+		}
+	}
+</style>

+ 257 - 0
uview-ui/components/u-car-keyboard/u-car-keyboard.vue

@@ -0,0 +1,257 @@
+<template>
+	<view class="u-keyboard" @touchmove.stop.prevent="() => {}">
+		<view class="u-keyboard-grids">
+			<block>
+				<view class="u-keyboard-grids-item" v-for="(group, i) in abc ? EngKeyBoardList : areaList" :key="i">
+					<view :hover-stay-time="100" @tap="carInputClick(i, j)" hover-class="u-carinput-hover" class="u-keyboard-grids-btn"
+					 v-for="(item, j) in group" :key="j">
+						{{ item }}
+					</view>
+				</view>
+				<view @touchstart="backspaceClick" @touchend="clearTimer" :hover-stay-time="100" class="u-keyboard-back"
+				 hover-class="u-hover-class">
+					<u-icon :size="38" name="backspace" :bold="true"></u-icon>
+				</view>
+				<view :hover-stay-time="100" class="u-keyboard-change" hover-class="u-carinput-hover" @tap="changeCarInputMode">
+					<text class="zh" :class="[!abc ? 'active' : 'inactive']">中</text>
+					/
+					<text class="en" :class="[abc ? 'active' : 'inactive']">英</text>
+				</view>
+			</block>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: "u-keyboard",
+		props: {
+			// 是否打乱键盘按键的顺序
+			random: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				// 车牌输入时,abc=true为输入车牌号码,bac=false为输入省份中文简称
+				abc: false
+			};
+		},
+		computed: {
+			areaList() {
+				let data = [
+					'京',
+					'沪',
+					'粤',
+					'津',
+					'冀',
+					'豫',
+					'云',
+					'辽',
+					'黑',
+					'湘',
+					'皖',
+					'鲁',
+					'苏',
+					'浙',
+					'赣',
+					'鄂',
+					'桂',
+					'甘',
+					'晋',
+					'陕',
+					'蒙',
+					'吉',
+					'闽',
+					'贵',
+					'渝',
+					'川',
+					'青',
+					'琼',
+					'宁',
+					'挂',
+					'藏',
+					'港',
+					'澳',
+					'新',
+					'使',
+					'学'
+				];
+				let tmp = [];
+				// 打乱顺序
+				if (this.random) data = this.$u.randomArray(data);
+				// 切割成二维数组
+				tmp[0] = data.slice(0, 10);
+				tmp[1] = data.slice(10, 20);
+				tmp[2] = data.slice(20, 30);
+				tmp[3] = data.slice(30, 36);
+				return tmp;
+			},
+			EngKeyBoardList() {
+				let data = [
+					1,
+					2,
+					3,
+					4,
+					5,
+					6,
+					7,
+					8,
+					9,
+					0,
+					'Q',
+					'W',
+					'E',
+					'R',
+					'T',
+					'Y',
+					'U',
+					'I',
+					'O',
+					'P',
+					'A',
+					'S',
+					'D',
+					'F',
+					'G',
+					'H',
+					'J',
+					'K',
+					'L',
+					'Z',
+					'X',
+					'C',
+					'V',
+					'B',
+					'N',
+					'M'
+				];
+				let tmp = [];
+				if (this.random) data = this.$u.randomArray(data);
+				tmp[0] = data.slice(0, 10);
+				tmp[1] = data.slice(10, 20);
+				tmp[2] = data.slice(20, 30);
+				tmp[3] = data.slice(30, 36);
+				return tmp;
+			}
+		},
+		methods: {
+			// 点击键盘按钮
+			carInputClick(i, j) {
+				let value = '';
+				// 不同模式,获取不同数组的值
+				if (this.abc) value = this.EngKeyBoardList[i][j];
+				else value = this.areaList[i][j];
+				this.$emit('change', value);
+			},
+			// 修改汽车牌键盘的输入模式,中文|英文
+			changeCarInputMode() {
+				this.abc = !this.abc;
+			},
+			// 点击退格键
+			backspaceClick() {
+				this.$emit('backspace');
+				clearInterval(this.timer); //再次清空定时器,防止重复注册定时器
+				this.timer = null;
+				this.timer = setInterval(() => {
+					this.$emit('backspace');
+				}, 250);
+			},
+			clearTimer() {
+				clearInterval(this.timer);
+				this.timer = null;
+			},
+		}
+	};
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+
+	.u-keyboard-grids {
+		background: rgb(215, 215, 217);
+		padding: 24rpx 0;
+		position: relative;
+	}
+
+	.u-keyboard-grids-item {
+		@include vue-flex;
+		align-items: center;
+		justify-content: center;
+	}
+
+	.u-keyboard-grids-btn {
+		text-decoration: none;
+		width: 62rpx;
+		flex: 0 0 64rpx;
+		height: 80rpx;
+		/* #ifndef APP-NVUE */
+		display: inline-flex;		
+		/* #endif */
+		font-size: 36rpx;
+		text-align: center;
+		line-height: 80rpx;
+		background-color: #fff;
+		margin: 8rpx 5rpx;
+		border-radius: 8rpx;
+		box-shadow: 0 2rpx 0rpx #888992;
+		font-weight: 500;
+		justify-content: center;
+	}
+
+	.u-carinput-hover {
+		background-color: rgb(185, 188, 195) !important;
+	}
+
+	.u-keyboard-back {
+		position: absolute;
+		width: 96rpx;
+		right: 22rpx;
+		bottom: 32rpx;
+		height: 80rpx;
+		background-color: rgb(185, 188, 195);
+		@include vue-flex;
+		align-items: center;
+		border-radius: 8rpx;
+		justify-content: center;
+		box-shadow: 0 2rpx 0rpx #888992;
+	}
+
+	.u-keyboard-change {
+		font-size: 24rpx;
+		box-shadow: 0 2rpx 0rpx #888992;
+		position: absolute;
+		width: 96rpx;
+		left: 22rpx;
+		line-height: 1;
+		bottom: 32rpx;
+		height: 80rpx;
+		background-color: #ffffff;
+		@include vue-flex;
+		align-items: center;
+		border-radius: 8rpx;
+		justify-content: center;
+	}
+
+	.u-keyboard-change .inactive.zh {
+		transform: scale(0.85) translateY(-10rpx);
+	}
+
+	.u-keyboard-change .inactive.en {
+		transform: scale(0.85) translateY(10rpx);
+	}
+
+	.u-keyboard-change .active {
+		color: rgb(237, 112, 64);
+		font-size: 30rpx;
+	}
+
+	.u-keyboard-change .zh {
+		transform: translateY(-10rpx);
+	}
+
+	.u-keyboard-change .en {
+		transform: translateY(10rpx);
+	}
+</style>

+ 299 - 0
uview-ui/components/u-card/u-card.vue

@@ -0,0 +1,299 @@
+<template>
+	<view
+		class="u-card"
+		@tap.stop="click"
+		:class="{ 'u-border': border, 'u-card-full': full, 'u-card--border': borderRadius > 0 }"
+		:style="{
+			borderRadius: borderRadius + 'rpx',
+			margin: margin,
+			boxShadow: boxShadow
+		}"
+	>
+		<view
+			v-if="showHead"
+			class="u-card__head"
+			:style="[{padding: padding + 'rpx'}, headStyle]"
+			:class="{
+				'u-border-bottom': headBorderBottom
+			}"
+			@tap="headClick"
+		>
+			<view v-if="!$slots.head" class="u-flex u-row-between">
+				<view class="u-card__head--left u-flex u-line-1" v-if="title">
+					<image
+						:src="thumb"
+						class="u-card__head--left__thumb"
+						mode="aspectfull"
+						v-if="thumb"
+						:style="{ 
+							height: thumbWidth + 'rpx', 
+							width: thumbWidth + 'rpx', 
+							borderRadius: thumbCircle ? '100rpx' : '6rpx' 
+						}"
+					></image>
+					<text
+						class="u-card__head--left__title u-line-1"
+						:style="{
+							fontSize: titleSize + 'rpx',
+							color: titleColor
+						}"
+					>
+						{{ title }}
+					</text>
+				</view>
+				<view class="u-card__head--right u-line-1" v-if="subTitle">
+					<text
+						class="u-card__head__title__text"
+						:style="{
+							fontSize: subTitleSize + 'rpx',
+							color: subTitleColor
+						}"
+					>
+						{{ subTitle }}
+					</text>
+				</view>
+			</view>
+			<slot name="head" v-else />
+		</view>
+		<view @tap="bodyClick" class="u-card__body" :style="[{padding: padding + 'rpx'}, bodyStyle]"><slot name="body" /></view>
+		<view
+			v-if="showFoot"
+			class="u-card__foot"
+			 @tap="footClick"
+			:style="[{padding: $slots.foot ? padding + 'rpx' : 0}, footStyle]"
+			:class="{
+				'u-border-top': footBorderTop
+			}"
+		>
+			<slot name="foot" />
+		</view>
+	</view>
+</template>
+
+<script>
+/**
+ * card 卡片
+ * @description 卡片组件一般用于多个列表条目,且风格统一的场景
+ * @tutorial https://www.uviewui.com/components/card.html
+ * @property {Boolean} full 卡片与屏幕两侧是否留空隙(默认false)
+ * @property {String} title 头部左边的标题
+ * @property {String} title-color 标题颜色(默认#303133)
+ * @property {String | Number} title-size 标题字体大小,单位rpx(默认30)
+ * @property {String} sub-title 头部右边的副标题
+ * @property {String} sub-title-color 副标题颜色(默认#909399)
+ * @property {String | Number} sub-title-size 副标题字体大小(默认26)
+ * @property {Boolean} border 是否显示边框(默认true)
+ * @property {String | Number} index 用于标识点击了第几个卡片
+ * @property {String} box-shadow 卡片外围阴影,字符串形式(默认none)
+ * @property {String} margin 卡片与屏幕两边和上下元素的间距,需带单位,如"30rpx 20rpx"(默认30rpx)
+ * @property {String | Number} border-radius 卡片整体的圆角值,单位rpx(默认16)
+ * @property {Object} head-style 头部自定义样式,对象形式
+ * @property {Object} body-style 中部自定义样式,对象形式
+ * @property {Object} foot-style 底部自定义样式,对象形式
+ * @property {Boolean} head-border-bottom 是否显示头部的下边框(默认true)
+ * @property {Boolean} foot-border-top 是否显示底部的上边框(默认true)
+ * @property {Boolean} show-head 是否显示头部(默认true)
+ * @property {Boolean} show-head 是否显示尾部(默认true)
+ * @property {String} thumb 缩略图路径,如设置将显示在标题的左边,不建议使用相对路径
+ * @property {String | Number} thumb-width 缩略图的宽度,高等于宽,单位rpx(默认60)
+ * @property {Boolean} thumb-circle 缩略图是否为圆形(默认false)
+ * @event {Function} click 整个卡片任意位置被点击时触发
+ * @event {Function} head-click 卡片头部被点击时触发
+ * @event {Function} body-click 卡片主体部分被点击时触发
+ * @event {Function} foot-click 卡片底部部分被点击时触发
+ * @example <u-card padding="30" title="card"></u-card>
+ */
+export default {
+	name: 'u-card',
+	props: {
+		// 与屏幕两侧是否留空隙
+		full: {
+			type: Boolean,
+			default: false
+		},
+		// 标题
+		title: {
+			type: String,
+			default: ''
+		},
+		// 标题颜色
+		titleColor: {
+			type: String,
+			default: '#303133'
+		},
+		// 标题字体大小,单位rpx
+		titleSize: {
+			type: [Number, String],
+			default: '30'
+		},
+		// 副标题
+		subTitle: {
+			type: String,
+			default: ''
+		},
+		// 副标题颜色
+		subTitleColor: {
+			type: String,
+			default: '#909399'
+		},
+		// 副标题字体大小,单位rpx
+		subTitleSize: {
+			type: [Number, String],
+			default: '26'
+		},
+		// 是否显示外部边框,只对full=false时有效(卡片与边框有空隙时)
+		border: {
+			type: Boolean,
+			default: true
+		},
+		// 用于标识点击了第几个
+		index: {
+			type: [Number, String, Object],
+			default: ''
+		},
+		// 用于隔开上下左右的边距,带单位的写法,如:"30rpx 30rpx","20rpx 20rpx 30rpx 30rpx"
+		margin: {
+			type: String,
+			default: '30rpx'
+		},
+		// card卡片的圆角
+		borderRadius: {
+			type: [Number, String],
+			default: '16'
+		},
+		// 头部自定义样式,对象形式
+		headStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 主体自定义样式,对象形式
+		bodyStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 底部自定义样式,对象形式
+		footStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 头部是否下边框
+		headBorderBottom: {
+			type: Boolean,
+			default: true
+		},
+		// 底部是否有上边框
+		footBorderTop: {
+			type: Boolean,
+			default: true
+		},
+		// 标题左边的缩略图
+		thumb: {
+			type: String,
+			default: ''
+		},
+		// 缩略图宽高,单位rpx
+		thumbWidth: {
+			type: [String, Number],
+			default: '60'
+		},
+		// 缩略图是否为圆形
+		thumbCircle: {
+			type: Boolean,
+			default: false
+		},
+		// 给head,body,foot的内边距
+		padding: {
+			type: [String, Number],
+			default: '30'
+		},
+		// 是否显示头部
+		showHead: {
+			type: Boolean,
+			default: true
+		},
+		// 是否显示尾部
+		showFoot: {
+			type: Boolean,
+			default: true
+		},
+		// 卡片外围阴影,字符串形式
+		boxShadow: {
+			type: String,
+			default: 'none'
+		}
+	},
+	data() {
+		return {};
+	},
+	methods: {
+		click() {
+			this.$emit('click', this.index);
+		},
+		headClick() {
+			this.$emit('head-click', this.index);
+		},
+		bodyClick() {
+			this.$emit('body-click', this.index);
+		},
+		footClick() {
+			this.$emit('foot-click', this.index);
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../libs/css/style.components.scss";
+	
+.u-card {
+	position: relative;
+	overflow: hidden;
+	font-size: 28rpx;
+	background-color: #ffffff;
+	box-sizing: border-box;
+	
+	&-full {
+		// 如果是与屏幕之间不留空隙,应该设置左右边距为0
+		margin-left: 0 !important;
+		margin-right: 0 !important;
+		width: 100%;
+	}
+	
+	&--border:after {
+		border-radius: 16rpx;
+	}
+
+	&__head {
+		&--left {
+			color: $u-main-color;
+			
+			&__thumb {
+				margin-right: 16rpx;
+			}
+			
+			&__title {
+				max-width: 400rpx;
+			}
+		}
+
+		&--right {
+			color: $u-tips-color;
+			margin-left: 6rpx;
+		}
+	}
+
+	&__body {
+		color: $u-content-color;
+	}
+
+	&__foot {
+		color: $u-tips-color;
+	}
+}
+</style>

+ 70 - 0
uview-ui/components/u-cell-group/u-cell-group.vue

@@ -0,0 +1,70 @@
+<template>
+	<view class="u-cell-box">
+		<view class="u-cell-title" v-if="title" :style="[titleStyle]">
+			{{title}}
+		</view>
+		<view class="u-cell-item-box" :class="{'u-border-bottom u-border-top': border}">
+			<slot />
+		</view>
+	</view>
+</template>
+
+<script>
+	/**
+	 * cellGroup 单元格父组件Group
+	 * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。搭配u-cell-item
+	 * @tutorial https://www.uviewui.com/components/cell.html
+	 * @property {String} title 分组标题
+	 * @property {Boolean} border 是否显示外边框(默认true)
+	 * @property {Object} title-style 分组标题的的样式,对象形式,如{'font-size': '24rpx'} 或 {'fontSize': '24rpx'}
+	 * @example <u-cell-group title="设置喜好">
+	 */
+	export default {
+		name: "u-cell-group",
+		props: {
+			// 分组标题
+			title: {
+				type: String,
+				default: ''
+			},
+			// 是否显示分组list上下边框
+			border: {
+				type: Boolean,
+				default: true
+			},
+			// 分组标题的样式,对象形式,注意驼峰属性写法
+			// 类似 {'font-size': '24rpx'} 和 {'fontSize': '24rpx'}
+			titleStyle: {
+				type: Object,
+				default () {
+					return {};
+				}
+			}
+		},
+		data() {
+			return {
+				index: 0,
+			}
+		},
+	}
+</script>
+
+<style lang="scss" scoped>
+	@import "../../libs/css/style.components.scss";
+	
+	.u-cell-box {
+		width: 100%;
+	}
+
+	.u-cell-title {
+		padding: 30rpx 32rpx 10rpx 32rpx;
+		font-size: 30rpx;
+		text-align: left;
+		color: $u-tips-color;
+	}
+
+	.u-cell-item-box {
+		background-color: #FFFFFF;
+		flex-direction: row;
+	}
+</style>

+ 316 - 0
uview-ui/components/u-cell-item/u-cell-item.vue

@@ -0,0 +1,316 @@
+<template>
+	<view
+		@tap="click"
+		class="u-cell"
+		:class="{ 'u-border-bottom': borderBottom, 'u-border-top': borderTop, 'u-col-center': center, 'u-cell--required': required }"
+		hover-stay-time="150"
+		:hover-class="hoverClass"
+		:style="{
+			backgroundColor: bgColor
+		}"
+	>
+		<u-icon :size="iconSize" :name="icon" v-if="icon" :custom-style="iconStyle" class="u-cell__left-icon-wrap"></u-icon>
+		<view class="u-flex" v-else>
+			<slot name="icon"></slot>
+		</view>
+		<view
+			class="u-cell_title"
+			:style="[
+				{
+					width: titleWidth ? titleWidth + 'rpx' : 'auto'
+				},
+				titleStyle
+			]"
+		>
+			<block v-if="title !== ''">{{ title }}</block>
+			<slot name="title" v-else></slot>
+
+			<view class="u-cell__label" v-if="label || $slots.label" :style="[labelStyle]">
+				<block v-if="label !== ''">{{ label }}</block>
+				<slot name="label" v-else></slot>
+			</view>
+		</view>
+
+		<view class="u-cell__value" :style="[valueStyle]">
+			<block class="u-cell__value" v-if="value !== ''">{{ value }}</block>
+			<slot v-else></slot>
+		</view>
+		<view class="u-flex u-cell_right" v-if="$slots['right-icon']">
+			<slot name="right-icon"></slot>
+		</view>
+		<u-icon v-if="arrow" name="arrow-right" :style="[arrowStyle]" class="u-icon-wrap u-cell__right-icon-wrap"></u-icon>
+	</view>
+</template>
+
+<script>
+/**
+ * cellItem 单元格Item
+ * @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。搭配u-cell-group使用
+ * @tutorial https://www.uviewui.com/components/cell.html
+ * @property {String} title 左侧标题
+ * @property {String} icon 左侧图标名,只支持uView内置图标,见Icon 图标
+ * @property {Object} icon-style 左边图标的样式,对象形式
+ * @property {String} value 右侧内容
+ * @property {String} label 标题下方的描述信息
+ * @property {Boolean} border-bottom 是否显示cell的下边框(默认true)
+ * @property {Boolean} border-top 是否显示cell的上边框(默认false)
+ * @property {Boolean} center 是否使内容垂直居中(默认false)
+ * @property {String} hover-class 是否开启点击反馈,none为无效果(默认true)
+ * // @property {Boolean} border-gap border-bottom为true时,Cell列表中间的条目的下边框是否与左边有一个间隔(默认true)
+ * @property {Boolean} arrow 是否显示右侧箭头(默认true)
+ * @property {Boolean} required 箭头方向,可选值(默认right)
+ * @property {Boolean} arrow-direction 是否显示左边表示必填的星号(默认false)
+ * @property {Object} title-style 标题样式,对象形式
+ * @property {Object} value-style 右侧内容样式,对象形式
+ * @property {Object} label-style 标题下方描述信息的样式,对象形式
+ * @property {String} bg-color 背景颜色(默认transparent)
+ * @property {String Number} index 用于在click事件回调中返回,标识当前是第几个Item
+ * @property {String Number} title-width 标题的宽度,单位rpx
+ * @example <u-cell-item icon="integral-fill" title="会员等级" value="新版本"></u-cell-item>
+ */
+export default {
+	name: 'u-cell-item',
+	props: {
+		// 左侧图标名称(只能uView内置图标),或者图标src
+		icon: {
+			type: String,
+			default: ''
+		},
+		// 左侧标题
+		title: {
+			type: [String, Number],
+			default: ''
+		},
+		// 右侧内容
+		value: {
+			type: [String, Number],
+			default: ''
+		},
+		// 标题下方的描述信息
+		label: {
+			type: [String, Number],
+			default: ''
+		},
+		// 是否显示下边框
+		borderBottom: {
+			type: Boolean,
+			default: true
+		},
+		// 是否显示上边框
+		borderTop: {
+			type: Boolean,
+			default: false
+		},
+		// 多个cell中,中间的cell显示下划线时,下划线是否给一个到左边的距离
+		// 1.4.0版本废除此参数,默认边框由border-top和border-bottom提供,此参数会造成干扰
+		// borderGap: {
+		// 	type: Boolean,
+		// 	default: true
+		// },
+		// 是否开启点击反馈,即点击时cell背景为灰色,none为无效果
+		hoverClass: {
+			type: String,
+			default: 'u-cell-hover'
+		},
+		// 是否显示右侧箭头
+		arrow: {
+			type: Boolean,
+			default: true
+		},
+		// 内容是否垂直居中
+		center: {
+			type: Boolean,
+			default: false
+		},
+		// 是否显示左边表示必填的星号
+		required: {
+			type: Boolean,
+			default: false
+		},
+		// 标题的宽度,单位rpx
+		titleWidth: {
+			type: [Number, String],
+			default: ''
+		},
+		// 右侧箭头方向,可选值:right|up|down,默认为right
+		arrowDirection: {
+			type: String,
+			default: 'right'
+		},
+		// 控制标题的样式
+		titleStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 右侧显示内容的样式
+		valueStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 描述信息的样式
+		labelStyle: {
+			type: Object,
+			default() {
+				return {};
+			}
+		},
+		// 背景颜色
+		bgColor: {
+			type: String,
+			default: 'transparent'
+		},
+		// 用于识别被点击的是第几个cell
+		index: {
+			type: [String, Number],
+			default: ''
+		},
+		// 是否使用lable插槽
+		useLabelSlot: {
+			type: Boolean,
+			default: false
+		},
+		// 左边图标的大小,单位rpx,只对传入icon字段时有效
+		iconSize: {
+			type: [Number, String],
+			default: 34
+		},
+		// 左边图标的样式,对象形式
+		iconStyle: {
+			type: Object,
+			default() {
+				return {}
+			}
+		},
+	},
+	data() {
+		return {
+
+		};
+	},
+	computed: {
+		arrowStyle() {
+			let style = {};
+			if (this.arrowDirection == 'up') style.transform = 'rotate(-90deg)';
+			else if (this.arrowDirection == 'down') style.transform = 'rotate(90deg)';
+			else style.transform = 'rotate(0deg)';
+			return style;
+		}
+	},
+	methods: {
+		click() {
+			this.$emit('click', this.index);
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+@import "../../libs/css/style.components.scss";
+.u-cell {
+	@include vue-flex;
+	align-items: center;
+	position: relative;
+	/* #ifndef APP-NVUE */
+	box-sizing: border-box;
+	/* #endif */
+	width: 100%;
+	padding: 26rpx 32rpx;
+	font-size: 28rpx;
+	line-height: 54rpx;
+	color: $u-content-color;
+	background-color: #fff;
+	text-align: left;
+}
+
+.u-cell_title {
+	font-size: 28rpx;
+}
+
+.u-cell__left-icon-wrap {
+	margin-right: 10rpx;
+	font-size: 32rpx;
+}
+
+.u-cell__right-icon-wrap {
+	margin-left: 10rpx;
+	color: #969799;
+	font-size: 28rpx;
+}
+
+.u-cell__left-icon-wrap,
+.u-cell__right-icon-wrap {
+	@include vue-flex;
+	align-items: center;
+	height: 48rpx;
+}
+
+.u-cell-border:after {
+	position: absolute; 
+	/* #ifndef APP-NVUE */
+	box-sizing: border-box;
+	content: ' ';
+	pointer-events: none;
+	border-bottom: 1px solid $u-border-color;
+	/* #endif */
+	right: 0;
+	left: 0;
+	top: 0;
+	transform: scaleY(0.5);
+}
+
+.u-cell-border {
+	position: relative;
+}
+
+.u-cell__label {
+	margin-top: 6rpx;
+	font-size: 26rpx;
+	line-height: 36rpx;
+	color: $u-tips-color;
+	/* #ifndef APP-NVUE */
+	word-wrap: break-word;
+	/* #endif */
+}
+
+.u-cell__value {
+	overflow: hidden;
+	text-align: right;
+	/* #ifndef APP-NVUE */
+	vertical-align: middle;
+	/* #endif */
+	color: $u-tips-color;
+	font-size: 26rpx;
+}
+
+.u-cell__title,
+.u-cell__value {
+	flex: 1;
+}
+
+.u-cell--required {
+	/* #ifndef APP-NVUE */
+	overflow: visible;
+	/* #endif */
+	@include vue-flex;
+	align-items: center;
+}
+
+.u-cell--required:before {
+	position: absolute;
+	/* #ifndef APP-NVUE */
+	content: '*';
+	/* #endif */
+	left: 8px;
+	margin-top: 4rpx;
+	font-size: 14px;
+	color: $u-type-error;
+}
+
+.u-cell_right {
+	line-height: 1;
+}
+</style>

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov