Quellcode durchsuchen

Merge branch 'deploy_yh1.0' of chelingzhu-web/zxyj-channe-mini-html into master

lilei vor 4 Jahren
Ursprung
Commit
687b40da77
47 geänderte Dateien mit 3987 neuen und 1178 gelöschten Zeilen
  1. 4 4
      App.vue
  2. 0 37
      api/coupon.js
  3. 0 27
      api/goods.js
  4. 61 0
      api/officialPartnerGoldLog.js
  5. 0 61
      api/order.js
  6. 0 36
      api/shoppingCart.js
  7. 11 26
      api/user.js
  8. 1 0
      components/m-input.vue
  9. 0 40
      components/uni-cart-fix/uni-cart-fix.vue
  10. 0 121
      components/uni-coods/uni-coods.vue
  11. 0 0
      components/w-picker/areadata/areadata.js
  12. 742 0
      components/w-picker/date-picker.vue
  13. 345 0
      components/w-picker/half-picker.vue
  14. 274 0
      components/w-picker/linkage-picker.vue
  15. 344 0
      components/w-picker/range-picker.vue
  16. 183 0
      components/w-picker/region-picker.vue
  17. 129 0
      components/w-picker/selector-picker.vue
  18. 250 0
      components/w-picker/shortterm-picker.vue
  19. 218 0
      components/w-picker/time-picker.vue
  20. 26 0
      components/w-picker/w-picker.css
  21. 341 0
      components/w-picker/w-picker.vue
  22. 2 2
      manifest.json
  23. 34 9
      pages.json
  24. 83 295
      pages/agreement/agreement.vue
  25. 228 128
      pages/index/index.vue
  26. 197 0
      pages/index/searchModal.vue
  27. 51 0
      pages/ledouHexiao/hexiaoSuccess.vue
  28. 270 0
      pages/ledouHexiao/ledouHexiao.vue
  29. 0 261
      pages/login/apply-trial.vue
  30. 5 4
      pages/login/login.scss
  31. 51 100
      pages/login/login.vue
  32. 3 6
      pages/userCenter/aboutUs.vue
  33. 13 11
      pages/userCenter/changePwd.vue
  34. 20 10
      pages/userCenter/index.vue
  35. 101 0
      pages/userCenter/leDouQuery.vue
  36. BIN
      static/filter.png
  37. BIN
      static/ledou.png
  38. BIN
      static/logo-h.png
  39. BIN
      static/logo.jpg
  40. BIN
      static/tabbar/home-active.png
  41. BIN
      static/tabbar/home.png
  42. BIN
      static/tabbar/record-active.png
  43. BIN
      static/tabbar/record.png
  44. BIN
      static/tabbar/shop-active.png
  45. BIN
      static/tabbar/shop.png
  46. BIN
      static/tabbar/user-active.png
  47. BIN
      static/tabbar/user.png

+ 4 - 4
App.vue

@@ -1,8 +1,8 @@
 <script>
-	// const uat_URL = 'https://carwash.test.zyucgj.com/gc-shop/' // 预发布
-	const uat_URL = 'http://192.168.16.105:8302/gc-shop/' // 本地
-	const pro_URL = 'https://carwash.zyucgj.com/gc-shop/'  // 生产
-	const buildType = 0 // 打包环境对应类型,1 生产 0 预发布
+	const uat_URL = 'https://lese.test.sxzxyj.net/gc-channel/' // 预发布
+	// const uat_URL = 'http://192.168.16.105:8303/gc-channel/' // 本地
+	const pro_URL = 'https://lese.sxzxyj.net/gc-channel/'  // 生产
+	const buildType = 1 // 打包环境对应类型,1 生产 0 预发布
 	const buildURL = buildType ? pro_URL : uat_URL // 打包后实际对应的url
 	const envText = ['预发布环境','生产环境']
 	const envTips = process.env.NODE_ENV == 'development' ? envText[0] : envText[buildType]

+ 0 - 37
api/coupon.js

@@ -1,37 +0,0 @@
-import axios from '@/libs/axios.js';
-// 确认领取优惠券
-export const receivesCoupon = (params) => {
-	return axios.request({
-		url: `couponReceives/receivesCoupon`,
-		method: 'post',
-		data: params
-	})
-}
-
-// 根据券码查询优惠券信息
-export const couponData = (params) => {
-	return axios.request({
-		url: `coupon/findByCode/${params.couponCode}`,
-		method: 'get'
-	})
-}
-
-// 优惠券领取明细查询
-export const couponListFind = (params) => {
-	let url = `couponReceives/findPage/${params.pageNo}/${params.pageSize}`
-	delete params.pageNo
-	delete params.pageSize
-	return axios.request({
-		url: url,
-		method: 'post',
-		data: params
-	})
-}
-// 订单可用优惠券查询
-export const couponEnable = (params) => {
-	return axios.request({
-		url: 'couponReceives/findUsableCoupon',
-		method: 'post',
-		data: params
-	})
-}

+ 0 - 27
api/goods.js

@@ -1,27 +0,0 @@
-import axios from '@/libs/axios.js';
-
-// 获取商品分类
-export const getGoodsClass = params => {
-  return axios.request({
-    url: `goodsType/queryList`,
-    method: 'post',
-	data: params
-  })
-};
-
-// 获取商品列表
-export const getGoodsList = params => {
-  return axios.request({
-    url: `goods/query/${params.pageNo}/${params.pageSize}`,
-    method: 'post',
-	data: params
-  })
-};
-
-// 获取商品详情
-export const getGoodsDetail = params => {
-  return axios.request({
-    url: `goods/findById/${params.id}`,
-    method: 'get',
-  })
-};

+ 61 - 0
api/officialPartnerGoldLog.js

@@ -0,0 +1,61 @@
+import axios from '@/libs/axios.js';
+
+// 交易记录列表
+export const getGoldLogList = params => {
+	let url = `officialPartnerGoldLog/query/${params.pageNo}/${params.pageSize}`
+	delete params.pageNo
+	delete params.pageSize
+	return axios.request({
+		url: url,
+		method: 'post',
+		data: params
+	})
+};
+// 撤销单据
+export const GoldLogCancel = params => {
+  return axios.request({
+    url: `officialPartnerGoldLog/cancel/${params.id}`,
+    method: 'get',
+  })
+};
+
+// 总计乐豆数
+export const GoldLogTotal = params => {
+	return axios.request({
+	  url: `officialPartnerGoldLog/total`,
+	  method: 'post',
+	  data: params
+	})
+}
+
+// 根据手机号码查询用户乐豆余额
+export const queryldByMobile = params => {
+  return axios.request({
+    url: `customer/queryByMobile/${params.mobile}`,
+    method: 'get',
+  })
+};
+
+// 乐豆核销
+export const offPartnerHx = params => {
+	return axios.request({
+	  url: `offPartner/verification`,
+	  method: 'post',
+	  data: params
+	})
+}
+
+// 发送短信验证码
+export const sendVerifyCode = params => {
+  return axios.request({
+    url: `offPartner/sendVerifiCode/${params.mobile}`,
+    method: 'get',
+  })
+}
+// 校验验证码
+export const checkVerificationCode = params => {
+  return axios.request({
+    url: `offPartner/checkVerificationCode/${params.mobile}/${params.code}`,
+    method: 'get',
+  })
+}

+ 0 - 61
api/order.js

@@ -1,61 +0,0 @@
-import axios from '@/libs/axios.js';
-
-// 获取网点下的服务项目
-export const getStoreItems = params => {
-  return axios.request({
-    url: `item/storeItems/?storeId=${params.storeId}`,
-    method: 'get',
-  })
-};
-
-// 下单 保存订单
-export const saveOrder = params => {
-  return axios.request({
-    url: `order/save`,
-    method: 'post',
-	data: params
-  })
-};
-
-// 下单 预支付
-export const signPay  = params => {
-  return axios.request({
-    url: `order/pay?orderId=${params.orderId}`,
-    method: 'get',
-  })
-};
-
-// 我的订单
-export const getOrderList = params => {
-	let url = `order/query/${params.pageNo}/${params.pageSize}`
-	delete params.pageNo
-	delete params.pageSize
-	return axios.request({
-		url: url,
-		method: 'post',
-		data: params
-	})
-};
-// 订单详情
-export const orderDetail = params => {
-  return axios.request({
-    url: `order/find/${params.id}`,
-    method: 'get',
-  })
-};
-
-// 查询当前是否有未完成的订单
-export const getUnFinishedOrder = params => {
-	return axios.request({
-	  url: `order/unFinishedOrderRunStatus`,
-	  method: 'get',
-	})
-}
-
-// 取消订单
-export const cancleOrder = params => {
-	return axios.request({
-	  url: `order/cancel/${params.id}`,
-	  method: 'get',
-	})
-}

+ 0 - 36
api/shoppingCart.js

@@ -1,36 +0,0 @@
-import axios from '@/libs/axios.js';
-
-// 添加商品到购物车
-export const addGoodsToCart = params => {
-  return axios.request({
-    url: `shoppingCart/addGoods`,
-    method: 'post',
-	data: params
-  })
-};
-
-// 从购物车删除商品
-export const deleteGoodsFormCart = params => {
-  return axios.request({
-    url: `shoppingCart/deleteGoods`,
-    method: 'post',
-	data: params
-  })
-};
-
-// 查询购物车列表
-export const getCartList = params => {
-  return axios.request({
-    url: `shoppingCart/queryList`,
-    method: 'post',
-	data: params
-  })
-};
-
-// 更新商品购买数量
-export const updateGoodsBuyQty = params => {
-  return axios.request({
-    url: `shoppingCart/updateGoodsBuyQty/${params.id}/${params.buyQty}`,
-    method: 'get'
-  })
-};

+ 11 - 26
api/user.js

@@ -5,7 +5,7 @@ import axios from '@/libs/axios.js'
 // 登录
 export const login = (params) => {
   return axios.request({
-    url: 'auth/login',
+    url: 'login',
     data: params,
     method: 'post'
   }, true)
@@ -25,40 +25,18 @@ export const getCaptcha = randomCode => {
     responseType: 'blob',
   }, true)
 }
-// 发送短信验证码
-export const sendVerifyCode = params => {
-  return axios.request({
-    url: 'org/apply/sendVerifyCode',
-    method: 'post',
-    data: params
-  }, true)
-}
-// 申请试用
-export const apply = params => {
-  return axios.request({
-    url: 'org/apply/apply',
-    method: 'post',
-    data: params
-  }, true)
-}
-// 获取门店名称
-export const getStore = (token) => {
-  return axios.request({
-    url: 'getStore',
-    method: 'get'
-  })
-}
+ 
 // 登出
 export const logout = () => {
   return axios.request({
-    url: 'auth/logout',
+    url: 'logout',
     method: 'get'
   })
 }
 // 修改密码
 export const changePwd = params => {
   return axios.request({
-    url: 'employee/changePWD',
+    url: 'user/updatePwd',
     method: 'post',
     data: {
       oldPassword: params.oldPassword,
@@ -130,4 +108,11 @@ export const getMessage = params => {
     data: params,
     method: 'post'
   })
+}
+// 获取用户信息
+export const getUserInfo = params => {
+  return axios.request({
+    url: `user/userInfo`,
+    method: 'get'
+  })
 }

+ 1 - 0
components/m-input.vue

@@ -105,6 +105,7 @@
 		/* width: 100%; */
 		flex: 1;
 		padding: 0 10px;
+		margin-top: 20rpx;
 	}
 
 	.m-input-input {

+ 0 - 40
components/uni-cart-fix/uni-cart-fix.vue

@@ -1,40 +0,0 @@
-<template>
-	 <view class="cart-fix" @click="toCart">
-	 	<u-image width="70rpx" height="70rpx" src="/static/cart.png"></u-image>
-	 	<u-badge absolute :offset="[15,10]" type="error" :count="count"></u-badge>
-	 </view>
-</template>
-	<script>
-		export default {
-			computed: {
-				count() {
-					let arr = this.$store.state.vuex_cartList
-					let count = 0
-					arr.map(item=>{
-						count = count + item.shoppingCartGoodsList.length
-					})
-					return count
-				},
-			},
-			methods: {
-				toCart() {
-					uni.navigateTo({
-						url:"/pages/cart/cart"
-					})
-				}
-			},
-		}
-	</script>
-
-<style lang="scss">
-	.cart-fix{
-		position: fixed;
-		z-index: 100000;
-		background: rgba($color: #ffffff, $alpha: 0.7);
-		padding: 10upx;
-		border-radius: 100%;
-		bottom: 40%;
-		right: 2%;
-		box-shadow: 3upx 3upx 8upx #ccc;
-	}
-</style>

+ 0 - 121
components/uni-coods/uni-coods.vue

@@ -1,121 +0,0 @@
-<template>
-	<view class="goods-list">
-		<view class="goods-item" v-for="item in list" :key="item.id" @click="toDetail(item)">
-			<view class="goods-imgs">
-				<view v-if="item.inventoryQty == 0" class="goods-staus">已售罄</view>
-				<u-lazy-load img-mode="scaleToFill" :height="imgHeight" :image="item.homeImage" :loading-img="loadingImg" :error-img="errorImg"></u-lazy-load>
-			</view>
-			<view class="name ellipsis-two">{{item.name}}</view>
-			<view class="price">
-				<view>
-					<text>{{item.sellGold}}</text>
-					<u-image mode="scaleToFill" width="40rpx" height="40rpx" src="/static/ledou.png"></u-image>
-				</view>
-				<view @click.stop="addCart(item)" v-if="item.inventoryQty > 0">
-					<u-image mode="scaleToFill" width="45rpx" height="45rpx" src="/static/addCart.png"></u-image>
-				</view>
-			</view>
-		</view>
-	</view>
-</template>
-
-<script>
-	export default {
-		props: {
-			imgHeight: {
-				type: Number,
-				default: 250
-			},
-			list:{
-				type: Array,
-				default: function(){
-					return []
-				}
-			}
-		},
-		data() {
-			return {
-				loadingImg: '/static/loading.gif',
-				errorImg: '/static/imgError.png',
-				timer: null,
-				finger: {x:0,y:0},
-				linePos: null
-			}
-		},
-		methods: {
-			// 加入购物车
-			addCart(item) {
-				uni.$emit("addCart",{goodsNo:item.goodsNo,buyQty:1})
-			},
-			// 商品详情
-			toDetail(item){
-				uni.navigateTo({
-					url:"/pages/goods/goodsDetail?id="+item.id
-				})
-			}
-		},
-	}
-</script>
-
-<style lang="scss" scoped>
-.goods-list{
-	display: flex;
-	flex-wrap: wrap;
-	justify-content: space-between;
-	padding-top: 20upx;
-	.goods-item{
-		background: #FFFFFF;
-		width: 48%;
-		margin-bottom: 5upx;
-		.goods-imgs{
-			position: relative;
-			border-radius: 28upx 28upx 0 0;
-			overflow: hidden;
-			.goods-staus{
-				width: 100%;
-				height: 100%;
-				position: absolute;
-				z-index: 100;
-				border-radius: 15rpx 15rpx 0 0;
-				background: rgba($color: #000000, $alpha: 0.4);
-				text-align: center;
-				line-height: 250rpx;
-				left: 0;
-				top: 0;
-				color: #eee;
-				font-size: 30upx;
-				font-weight: bold;
-			}
-		}
-		.name{
-			padding: 10upx 20upx 0;
-			font-weight: bold;
-		}
-		.price{
-			display: flex;
-			align-items: center;
-			justify-content: space-between;
-			padding: 15upx 20upx;
-			text{
-				color: #d42a26;
-				font-size: 36upx;
-				margin-right: 6upx;
-				font-weight: bold;
-			}
-			>view{
-				&:first-child{
-					font-size: 22upx;
-					display: flex;
-					align-items: center;
-				}
-				&:last-child{
-					&:active{
-						opacity: 0.5;
-					}
-				}
-			}
-		}
-	}
-}
-
-</style>

Datei-Diff unterdrückt, da er zu groß ist
+ 0 - 0
components/w-picker/areadata/areadata.js


+ 742 - 0
components/w-picker/date-picker.vue

@@ -0,0 +1,742 @@
+<template>
+	<view class="w-picker-view">
+		<picker-view v-if="fields=='year'" class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.years" :key="index">{{item}}年</view>
+			</picker-view-column>
+		</picker-view>
+		<picker-view v-if="fields=='month'" class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.years" :key="index">{{item}}年</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.months" :key="index">{{item}}月</view>
+			</picker-view-column>
+		</picker-view>
+		<picker-view v-if="fields=='day'" class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.years" :key="index">{{item}}年</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.months" :key="index">{{item}}月</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.days" :key="index">{{item}}日</view>
+			</picker-view-column>
+		</picker-view>
+		<picker-view v-if="fields=='hour'" class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.years" :key="index">{{item}}年</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.months" :key="index">{{item}}月</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.days" :key="index">{{item}}日</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.hours" :key="index">{{item}}时</view>
+			</picker-view-column>
+		</picker-view>
+		<picker-view v-if="fields=='minute'" class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.years" :key="index">{{item}}年</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.months" :key="index">{{item}}月</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.days" :key="index">{{item}}日</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.hours" :key="index">{{item}}时</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.minutes" :key="index">{{item}}分</view>
+			</picker-view-column>
+		</picker-view>
+		<picker-view v-if="fields=='second'" class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.years" :key="index">{{item}}年</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.months" :key="index">{{item}}月</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.days" :key="index">{{item}}日</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.hours" :key="index">{{item}}时</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.minutes" :key="index">{{item}}分</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.seconds" :key="index">{{item}}秒</view>
+			</picker-view-column>
+		</picker-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				pickVal:[],
+				range:{
+					years:[],
+					months:[],
+					days:[],
+					hours:[],
+					minutes:[],
+					seconds:[]
+				},
+				checkObj:{}
+			};
+		},
+		props:{
+			itemHeight:{
+				type:String,
+				default:"44px"
+			},
+			startYear:{
+				type:[String,Number],
+				default:""
+			},
+			endYear:{
+				type:[String,Number],
+				default:""
+			},
+			value:{
+				type:[String,Array,Number],
+				default:""
+			},
+			current:{//是否默认选中当前日期
+				type:Boolean,
+				default:false
+			},
+			disabledAfter:{//是否禁用当前之后的日期
+				type:Boolean,
+				default:false
+			},
+			fields:{
+				type:String,
+				default:"day"
+			}
+		},
+		watch:{
+			fields(val){
+				this.initData();
+			},
+			value(val){
+				this.initData();
+			}
+		},
+		created() {
+			this.initData();
+		},
+		methods:{
+			formatNum(n){
+				return (Number(n)<10?'0'+Number(n):Number(n)+'');
+			},
+			checkValue(value){
+				let strReg,example
+				switch(this.fields){
+					case "year":
+						strReg=/^\d{4}$/;
+						example="2019";
+						break;
+					case "month":
+						strReg=/^\d{4}-\d{2}$/;
+						example="2019-02";
+						break;
+					case "day":
+						strReg=/^\d{4}-\d{2}-\d{2}$/;
+						example="2019-02-01";
+						break;
+					case "hour":
+						strReg=/^\d{4}-\d{2}-\d{2} \d{2}(:\d{2}){1,2}?$/;
+						example="2019-02-01 18:00:00或2019-02-01 18";
+						break;
+					case "minute":
+						strReg=/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2}){0,1}?$/;
+						example="2019-02-01 18:06:00或2019-02-01 18:06";
+						break;
+					case "second":
+						strReg=/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
+						example="2019-02-01 18:06:01";
+						break;
+				}
+				if(!strReg.test(value)){
+					console.log(new Error("请传入与mode、fields匹配的value值,例value="+example+""))
+				}
+				return strReg.test(value);
+			},
+			resetData(year,month,day,hour,minute){
+				let curDate=this.getCurrenDate();
+				let curFlag=this.current;
+				let curYear=curDate.curYear;
+				let curMonth=curDate.curMonth;
+				let curDay=curDate.curDay;
+				let curHour=curDate.curHour;
+				let curMinute=curDate.curMinute;
+				let curSecond=curDate.curSecond;
+				let months=[],days=[],hours=[],minutes=[],seconds=[];
+				let disabledAfter=this.disabledAfter;
+				let monthsLen=disabledAfter?(year*1<curYear?12:curMonth):12;
+				let totalDays=new Date(year,month,0).getDate();//计算当月有几天;
+				let daysLen=disabledAfter?((year*1<curYear||month*1<curMonth)?totalDays:curDay):totalDays;
+				let hoursLen=disabledAfter?((year*1<curYear||month*1<curMonth||day*1<curDay)?24:curHour+1):24;
+				let minutesLen=disabledAfter?((year*1<curYear||month*1<curMonth||day*1<curDay||hour*1<curHour)?60:curMinute+1):60;
+				let secondsLen=disabledAfter?((year*1<curYear||month*1<curMonth||day*1<curDay||hour*1<curHour||minute*1<curMinute)?60:curSecond+1):60;
+				for(let month=1;month<=monthsLen;month++){
+					months.push(this.formatNum(month));
+				};
+				for(let day=1;day<=daysLen;day++){
+					days.push(this.formatNum(day));
+				}
+				for(let hour=0;hour<hoursLen;hour++){
+					hours.push(this.formatNum(hour));
+				}
+				for(let minute=0;minute<minutesLen;minute++){
+					minutes.push(this.formatNum(minute));
+				}
+				for(let second=0;second<secondsLen;second++){
+					seconds.push(this.formatNum(second));
+				}
+				return{
+					months,
+					days,
+					hours,
+					minutes,
+					seconds
+				}
+			},
+			isLeapYear (Year) {
+				if (((Year % 4)==0) && ((Year % 100)!=0) || ((Year % 400)==0)) {
+					return true;
+				} else { 
+					return false; 
+				}
+			},
+			getData(dVal){
+				//用来处理初始化数据
+				let curFlag=this.current;
+				let disabledAfter=this.disabledAfter;
+				let fields=this.fields;
+				let curDate=this.getCurrenDate();
+				let curYear=curDate.curYear;
+				let curMonthdays=curDate.curMonthdays;
+				let curMonth=curDate.curMonth;
+				let curDay=curDate.curDay;
+				let curHour=curDate.curHour;
+				let curMinute=curDate.curMinute;
+				let curSecond=curDate.curSecond;
+				let defaultDate=this.getDefaultDate();
+				let startYear=this.getStartDate().getFullYear();
+				let endYear=this.getEndDate().getFullYear();
+				//颗粒度,禁用当前之后日期仅对year,month,day,hour生效;分钟秒禁用没有意义,
+				let years=[],months=[],days=[],hours=[],minutes=[],seconds=[];
+				let year=dVal[0]*1;
+				let month=dVal[1]*1;
+				let day=dVal[2]*1;
+				let hour=dVal[3]*1;
+				let minute=dVal[4]*1;
+				let monthsLen=disabledAfter?(year<curYear?12:curDate.curMonth):12;
+				let daysLen=disabledAfter?((year<curYear||month<curMonth)?defaultDate.defaultDays:curDay):(curFlag?curMonthdays:defaultDate.defaultDays);
+				let hoursLen=disabledAfter?((year<curYear||month<curMonth||day<curDay)?24:curHour+1):24;
+				let minutesLen=disabledAfter?((year<curYear||month<curMonth||day<curDay||hour<curHour)?60:curMinute+1):60;
+				let secondsLen=disabledAfter?((year<curYear||month<curMonth||day<curDay||hour<curHour||minute<curMinute)?60:curSecond+1):60;
+				for(let year=startYear;year<=(disabledAfter?curYear:endYear);year++){
+					years.push(year.toString())
+				}
+				for(let month=1;month<=monthsLen;month++){
+					months.push(this.formatNum(month));
+				}
+				for(let day=1;day<=daysLen;day++){
+					days.push(this.formatNum(day));
+				}
+				for(let hour=0;hour<hoursLen;hour++){
+					hours.push(this.formatNum(hour));
+				}
+				for(let minute=0;minute<minutesLen;minute++){
+					minutes.push(this.formatNum(minute));
+				}
+				// for(let second=0;second<(disabledAfter?curDate.curSecond+1:60);second++){
+				// 	seconds.push(this.formatNum(second));
+				// }
+				for(let second=0;second<60;second++){
+					seconds.push(this.formatNum(second));
+				}
+				return {
+					years,
+					months,
+					days,
+					hours,
+					minutes,
+					seconds
+				}
+			},
+			getCurrenDate(){
+				let curDate=new Date();
+				let curYear=curDate.getFullYear();
+				let curMonth=curDate.getMonth()+1;
+				let curMonthdays=new Date(curYear,curMonth,0).getDate();
+				let curDay=curDate.getDate();
+				let curHour=curDate.getHours();
+				let curMinute=curDate.getMinutes();
+				let curSecond=curDate.getSeconds();
+				return{
+					curDate,
+					curYear,
+					curMonth,
+					curMonthdays,
+					curDay,
+					curHour,
+					curMinute,
+					curSecond
+				}
+			},
+			getDefaultDate(){
+				let value=this.value;
+				let reg=/-/g;
+				let defaultDate=value?new Date(value.replace(reg,"/")):new Date();
+				let defaultYear=defaultDate.getFullYear();
+				let defaultMonth=defaultDate.getMonth()+1;
+				let defaultDay=defaultDate.getDate();
+				let defaultDays=new Date(defaultYear,defaultMonth,0).getDate()*1;
+				return{
+					defaultDate,
+					defaultYear,
+					defaultMonth,
+					defaultDay,
+					defaultDays
+				}
+			},
+			getStartDate(){
+				let start=this.startYear;
+				let startDate="";
+				let reg=/-/g;
+				if(start){
+					startDate=new Date(start+"/01/01");
+				}else{
+					startDate=new Date("1970/01/01");
+				}
+				return startDate;
+			},
+			getEndDate(){
+				let end=this.endYear;
+				let reg=/-/g;
+				let endDate="";
+				if(end){
+					endDate=new Date(end+"/12/01");
+				}else{
+					endDate=new Date();
+				}
+				return endDate;
+			},
+			getDval(){
+				let value=this.value;
+				let fields=this.fields;
+				let dVal=null;
+				let aDate=new Date();
+				let year=this.formatNum(aDate.getFullYear());
+				let month=this.formatNum(aDate.getMonth()+1);
+				let day=this.formatNum(aDate.getDate());
+				let hour=this.formatNum(aDate.getHours());
+				let minute=this.formatNum(aDate.getMinutes());
+				let second=this.formatNum(aDate.getSeconds());
+				if(value){
+					let flag=this.checkValue(value);
+					if(!flag){
+						dVal=[year,month,day,hour,minute,second]
+					}else{
+						switch(this.fields){
+							case "year":
+								dVal=value?[value]:[];	
+								break;
+							case "month":
+								dVal=value?value.split("-"):[];
+								break;
+							case "day":
+								dVal=value?value.split("-"):[];
+								break;
+							case "hour":
+								dVal=[...value.split(" ")[0].split("-"),...value.split(" ")[1].split(":")];
+								break;
+							case "minute":
+								dVal=value?[...value.split(" ")[0].split("-"),...value.split(" ")[1].split(":")]:[];
+								break;
+							case "second":
+								dVal=[...value.split(" ")[0].split("-"),...value.split(" ")[1].split(":")];
+								break;
+						}
+					}
+				}else{
+					dVal=[year,month,day,hour,minute,second]
+				}
+				return dVal;
+			},
+			initData(){
+				let startDate,endDate,startYear,endYear,startMonth,endMonth,startDay,endDay;
+				let years=[],months=[],days=[],hours=[],minutes=[],seconds=[];
+				let dVal=[],pickVal=[];
+				let value=this.value;
+				let reg=/-/g;
+				let range={};
+				let result="",full="",year,month,day,hour,minute,second,obj={};
+				let defaultDate=this.getDefaultDate();
+				let defaultYear=defaultDate.defaultYear;
+				let defaultMonth=defaultDate.defaultMonth;
+				let defaultDay=defaultDate.defaultDay;
+				let defaultDays=defaultDate.defaultDays;
+				let curFlag=this.current;
+				let disabledAfter=this.disabledAfter;
+				let curDate=this.getCurrenDate();
+				let curYear=curDate.curYear;
+				let curMonth=curDate.curMonth;
+				let curMonthdays=curDate.curMonthdays;
+				let curDay=curDate.curDay;
+				let curHour=curDate.curHour;
+				let curMinute=curDate.curMinute;
+				let curSecond=curDate.curSecond;
+				let dateData=[];
+				dVal=this.getDval();
+				
+				startDate=this.getStartDate();
+				endDate=this.getEndDate();
+				startYear=startDate.getFullYear();
+				startMonth=startDate.getMonth();
+				startDay=startDate.getDate();
+				endYear=endDate.getFullYear();
+				endMonth=endDate.getMonth();
+				endDay=endDate.getDate();
+				dateData=this.getData(dVal);
+				years=dateData.years;
+				months=dateData.months;
+				days=dateData.days;
+				hours=dateData.hours;
+				minutes=dateData.minutes;
+				seconds=dateData.seconds;
+				switch(this.fields){
+					case "year":
+						pickVal=disabledAfter?[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0
+						]:(curFlag?[
+							years.indexOf(curYear+'')
+						]:[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0
+						]);
+						range={years};
+						year=dVal[0]?dVal[0]:years[0];
+						result=full=`${year}`;
+						obj={
+							year
+						}
+						break;
+					case "month":
+						pickVal=disabledAfter?[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0
+						]:(curFlag?[
+							years.indexOf(curYear+''),
+							months.indexOf(this.formatNum(curMonth))
+						]:[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0
+						]);
+						range={years,months};
+						year=dVal[0]?dVal[0]:years[0];
+						month=dVal[1]?dVal[1]:months[0];
+						result=full=`${year+'-'+month}`;
+						obj={
+							year,
+							month
+						}
+						break;
+					case "day":
+						pickVal=disabledAfter?[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+							dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0
+						]:(curFlag?[
+							years.indexOf(curYear+''),
+							months.indexOf(this.formatNum(curMonth)),
+							days.indexOf(this.formatNum(curDay)),
+						]:[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+							dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0
+						]);
+						range={years,months,days};
+						year=dVal[0]?dVal[0]:years[0];
+						month=dVal[1]?dVal[1]:months[0];
+						day=dVal[2]?dVal[2]:days[0];
+						result=full=`${year+'-'+month+'-'+day}`;
+						obj={
+							year,
+							month,
+							day
+						}
+						break;
+					case "hour":
+						pickVal=disabledAfter?[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+							dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0,
+							dVal[3]&&hours.indexOf(dVal[3])!=-1?hours.indexOf(dVal[3]):0
+						]:(curFlag?[
+							years.indexOf(curYear+''),
+							months.indexOf(this.formatNum(curMonth)),
+							days.indexOf(this.formatNum(curDay)),
+							hours.indexOf(this.formatNum(curHour)),
+						]:[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+							dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0,
+							dVal[3]&&hours.indexOf(dVal[3])!=-1?hours.indexOf(dVal[3]):0
+						]);
+						range={years,months,days,hours};
+						year=dVal[0]?dVal[0]:years[0];
+						month=dVal[1]?dVal[1]:months[0];
+						day=dVal[2]?dVal[2]:days[0];
+						hour=dVal[3]?dVal[3]:hours[0];
+						result=`${year+'-'+month+'-'+day+' '+hour}`;
+						full=`${year+'-'+month+'-'+day+' '+hour+':00:00'}`;
+						obj={
+							year,
+							month,
+							day,
+							hour
+						}
+						break;
+					case "minute":
+						pickVal=disabledAfter?[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+							dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0,
+							dVal[3]&&hours.indexOf(dVal[3])!=-1?hours.indexOf(dVal[3]):0,
+							dVal[4]&&minutes.indexOf(dVal[4])!=-1?minutes.indexOf(dVal[4]):0
+						]:(curFlag?[
+							years.indexOf(curYear+''),
+							months.indexOf(this.formatNum(curMonth)),
+							days.indexOf(this.formatNum(curDay)),
+							hours.indexOf(this.formatNum(curHour)),
+							minutes.indexOf(this.formatNum(curMinute)),
+						]:[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+							dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0,
+							dVal[3]&&hours.indexOf(dVal[3])!=-1?hours.indexOf(dVal[3]):0,
+							dVal[4]&&minutes.indexOf(dVal[4])!=-1?minutes.indexOf(dVal[4]):0
+						]);
+						range={years,months,days,hours,minutes};
+						year=dVal[0]?dVal[0]:years[0];
+						month=dVal[1]?dVal[1]:months[0];
+						day=dVal[2]?dVal[2]:days[0];
+						hour=dVal[3]?dVal[3]:hours[0];
+						minute=dVal[4]?dVal[4]:minutes[0];
+						full=`${year+'-'+month+'-'+day+' '+hour+':'+minute+':00'}`;
+						result=`${year+'-'+month+'-'+day+' '+hour+':'+minute}`;
+						obj={
+							year,
+							month,
+							day,
+							hour,
+							minute
+						}
+						break;
+					case "second":
+						pickVal=disabledAfter?[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+							dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0,
+							dVal[3]&&hours.indexOf(dVal[3])!=-1?hours.indexOf(dVal[3]):0,
+							dVal[4]&&minutes.indexOf(dVal[4])!=-1?minutes.indexOf(dVal[4]):0,
+							dVal[5]&&seconds.indexOf(dVal[5])!=-1?seconds.indexOf(dVal[5]):0
+						]:(curFlag?[
+							years.indexOf(curYear+''),
+							months.indexOf(this.formatNum(curMonth)),
+							days.indexOf(this.formatNum(curDay)),
+							hours.indexOf(this.formatNum(curHour)),
+							minutes.indexOf(this.formatNum(curMinute)),
+							seconds.indexOf(this.formatNum(curSecond)),
+						]:[
+							dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+							dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+							dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0,
+							dVal[3]&&hours.indexOf(dVal[3])!=-1?hours.indexOf(dVal[3]):0,
+							dVal[4]&&minutes.indexOf(dVal[4])!=-1?minutes.indexOf(dVal[4]):0,
+							dVal[5]&&seconds.indexOf(dVal[5])!=-1?seconds.indexOf(dVal[5]):0
+						]);
+						range={years,months,days,hours,minutes,seconds};
+						year=dVal[0]?dVal[0]:years[0];
+						month=dVal[1]?dVal[1]:months[0];
+						day=dVal[2]?dVal[2]:days[0];
+						hour=dVal[3]?dVal[3]:hours[0];
+						minute=dVal[4]?dVal[4]:minutes[0];
+						second=dVal[5]?dVal[5]:seconds[0];
+						result=full=`${year+'-'+month+'-'+day+' '+hour+':'+minute+':'+second}`;
+						obj={
+							year,
+							month,
+							day,
+							hour,
+							minute,
+							second
+						}
+						break;
+					default:
+						range={years,months,days};
+						break;
+				}
+				this.range=range;
+				this.checkObj=obj;
+				this.$emit("change",{
+					result:result,
+					value:full,
+					obj:obj
+				});
+				this.$nextTick(()=>{
+					this.pickVal=pickVal;
+				})
+			},
+			handlerChange(e){
+				let arr=[...e.detail.value];
+				let data=this.range;
+				let year="",month="",day="",hour="",minute="",second="";
+				let result="",full="",obj={};
+				let months=null,days=null,hours=null,minutes=null,seconds=null;
+				let disabledAfter=this.disabledAfter;
+				let leapYear=false,resetData={};
+				year=(arr[0]||arr[0]==0)?data.years[arr[0]]||data.years[data.years.length-1]:"";
+				month=(arr[1]||arr[1]==0)?data.months[arr[1]]||data.months[data.months.length-1]:"";
+				day=(arr[2]||arr[2]==0)?data.days[arr[2]]||data.days[data.days.length-1]:"";
+				hour=(arr[3]||arr[3]==0)?data.hours[arr[3]]||data.hours[data.hours.length-1]:"";
+				minute=(arr[4]||arr[4]==0)?data.minutes[arr[4]]||data.minutes[data.minutes.length-1]:"";
+				second=(arr[5]||arr[5]==0)?data.seconds[arr[5]]||data.seconds[data.seconds.length-1]:"";
+				resetData=this.resetData(year,month,day,hour,minute);//重新拉取当前日期数据;
+				leapYear=this.isLeapYear(year);//判断是否为闰年;
+				switch(this.fields){
+					case "year":
+						result=full=`${year}`;
+						obj={
+							year
+						};
+						break;
+					case "month":
+						result=full=`${year+'-'+month}`;
+						if(this.disabledAfter)months=resetData.months;
+						if(months)this.range.months=months;
+						obj={
+							year,
+							month
+						}
+						break;
+					case "day":
+						result=full=`${year+'-'+month+'-'+day}`;
+						if(this.disabledAfter){
+							months=resetData.months;
+							days=resetData.days;
+						}else{
+							if(leapYear||(month!=this.checkObj.month)||month==2){
+								days=resetData.days;
+							}
+						}
+						if(months)this.range.months=months;
+						if(days)this.range.days=days;
+						obj={
+							year,
+							month,
+							day
+						}
+						break;
+					case "hour":
+						result=`${year+'-'+month+'-'+day+' '+hour}`;
+						full=`${year+'-'+month+'-'+day+' '+hour+':00:00'}`;
+						if(this.disabledAfter){
+							months=resetData.months;
+							days=resetData.days;
+							hours=resetData.hours;
+						}else{
+							if(leapYear||(month!=this.checkObj.month)||month==2){
+								days=resetData.days;
+							}
+						}
+						if(months)this.range.months=months;
+						if(days)this.range.days=days;
+						if(hours)this.range.hours=hours;
+						obj={
+							year,
+							month,
+							day,
+							hour
+						}
+						break;
+					case "minute":
+						full=`${year+'-'+month+'-'+day+' '+hour+':'+minute+':00'}`;
+						result=`${year+'-'+month+'-'+day+' '+hour+':'+minute}`;
+						if(this.disabledAfter){
+							months=resetData.months;
+							days=resetData.days;
+							hours=resetData.hours;
+							minutes=resetData.minutes;
+						}else{
+							if(leapYear||(month!=this.checkObj.month)||month==2){
+								days=resetData.days;
+							}
+						}
+						if(months)this.range.months=months;
+						if(days)this.range.days=days;
+						if(hours)this.range.hours=hours;
+						if(minutes)this.range.minutes=minutes;
+						obj={
+							year,
+							month,
+							day,
+							hour,
+							minute
+						};
+						break;
+					case "second":
+						result=full=`${year+'-'+month+'-'+day+' '+hour+':'+minute+':'+second}`;
+						if(this.disabledAfter){
+							months=resetData.months;
+							days=resetData.days;
+							hours=resetData.hours;
+							minutes=resetData.minutes;
+							//seconds=resetData.seconds;
+						}else{
+							if(leapYear||(month!=this.checkObj.month)||month==2){
+								days=resetData.days;
+							}
+						}
+						if(months)this.range.months=months;
+						if(days)this.range.days=days;
+						if(hours)this.range.hours=hours;
+						if(minutes)this.range.minutes=minutes;
+						//if(seconds)this.range.seconds=seconds;
+						obj={
+							year,
+							month,
+							day,
+							hour,
+							minute,
+							second
+						}
+						break;
+				}
+				this.checkObj=obj;
+				this.$emit("change",{
+					result:result,
+					value:full,
+					obj:obj
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import "./w-picker.css";
+</style>

+ 345 - 0
components/w-picker/half-picker.vue

@@ -0,0 +1,345 @@
+<template>
+	<view class="w-picker-view">
+		<picker-view class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.years" :key="index">{{item}}年</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.months" :key="index">{{item}}月</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.days" :key="index">{{item}}日</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.sections" :key="index">{{item}}</view>
+			</picker-view-column>
+		</picker-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				pickVal:[],
+				range:{},
+				checkObj:{}
+			};
+		},
+		props:{
+			itemHeight:{
+				type:String,
+				default:"44px"
+			},
+			startYear:{
+				type:String,
+				default:""
+			},
+			endYear:{
+				type:String,
+				default:""
+			},
+			value:{
+				type:[String,Array,Number],
+				default:""
+			},
+			current:{//是否默认选中当前日期
+				type:Boolean,
+				default:false
+			},
+			disabledAfter:{//是否禁用当前之后的日期
+				type:Boolean,
+				default:false
+			}
+		},
+		watch:{
+			value(val){
+				this.initData();
+			}
+		},
+		created() {
+			this.initData();
+		},
+		methods:{
+			formatNum(n){
+				return (Number(n)<10?'0'+Number(n):Number(n)+'');
+			},
+			checkValue(value){
+				let strReg=/^\d{4}-\d{2}-\d{2} [\u4e00-\u9fa5]{2}$/,example;
+				if(!strReg.test(value)){
+					console.log(new Error("请传入与mode、fields匹配的value值,例value="+example+""))
+				}
+				return strReg.test(value);
+			},
+			resetData(year,month,day){
+				let curDate=this.getCurrenDate();
+				let curFlag=this.current;
+				let curYear=curDate.curYear;
+				let curMonth=curDate.curMonth;
+				let curDay=curDate.curDay;
+				let curHour=curDate.curHour;
+				let months=[],days=[],sections=[];
+				let disabledAfter=this.disabledAfter;
+				let monthsLen=disabledAfter?(year*1<curYear?12:curMonth):12;
+				let totalDays=new Date(year,month,0).getDate();//计算当月有几天;
+				let daysLen=disabledAfter?((year*1<curYear||month*1<curMonth)?totalDays:curDay):totalDays;
+				let sectionFlag=disabledAfter?((year*1<curYear||month*1<curMonth||day*1<curDay)==true?false:true):(curHour>12==true?true:false);
+				sections=["上午","下午"];
+				for(let month=1;month<=monthsLen;month++){
+					months.push(this.formatNum(month));
+				};
+				for(let day=1;day<=daysLen;day++){
+					days.push(this.formatNum(day));
+				}
+				if(sectionFlag){
+					sections=["上午"];
+				}
+				return{
+					months,
+					days,
+					sections
+				}
+			},
+			getData(dVal){
+				//用来处理初始化数据
+				let curFlag=this.current;
+				let disabledAfter=this.disabledAfter;
+				let curDate=this.getCurrenDate();
+				let curYear=curDate.curYear;
+				let curMonthdays=curDate.curMonthdays;
+				let curMonth=curDate.curMonth;
+				let curDay=curDate.curDay;
+				let curHour=curDate.curHour;
+				let defaultDate=this.getDefaultDate();
+				let startYear=this.getStartDate().getFullYear();
+				let endYear=this.getEndDate().getFullYear();
+				let years=[],months=[],days=[],sections=[];
+				let year=dVal[0]*1;
+				let month=dVal[1]*1;
+				let day=dVal[2]*1;
+				let monthsLen=disabledAfter?(year<curYear?12:curDate.curMonth):12;
+				let daysLen=disabledAfter?((year<curYear||month<curMonth)?defaultDate.defaultDays:curDay):(curFlag?curMonthdays:defaultDate.defaultDays);
+				let sectionFlag=disabledAfter?((year*1<curYear||month*1<curMonth||day*1<curDay)==true?false:true):(curHour>12==true?true:false);
+				for(let year=startYear;year<=(disabledAfter?curYear:endYear);year++){
+					years.push(year.toString())
+				}
+				for(let month=1;month<=monthsLen;month++){
+					months.push(this.formatNum(month));
+				}
+				for(let day=1;day<=daysLen;day++){
+					days.push(this.formatNum(day));
+				}
+				if(sectionFlag){
+					sections=["下午"];
+				}else{
+					sections=["上午","下午"];
+				}
+				return {
+					years,
+					months,
+					days,
+					sections
+				}
+			},
+			getCurrenDate(){
+				let curDate=new Date();
+				let curYear=curDate.getFullYear();
+				let curMonth=curDate.getMonth()+1;
+				let curMonthdays=new Date(curYear,curMonth,0).getDate();
+				let curDay=curDate.getDate();
+				let curHour=curDate.getHours();
+				let curSection="上午";
+				if(curHour>=12){
+					curSection="下午";
+				}
+				return{
+					curDate,
+					curYear,
+					curMonth,
+					curMonthdays,
+					curDay,
+					curHour,
+					curSection
+				}
+			},
+			getDefaultDate(){
+				let value=this.value;
+				let reg=/-/g;
+				let defaultDate=value?new Date(value.split(" ")[0].replace(reg,"/")):new Date();
+				let defaultYear=defaultDate.getFullYear();
+				let defaultMonth=defaultDate.getMonth()+1;
+				let defaultDay=defaultDate.getDate();
+				let defaultDays=new Date(defaultYear,defaultMonth,0).getDate()*1;
+				return{
+					defaultDate,
+					defaultYear,
+					defaultMonth,
+					defaultDay,
+					defaultDays
+				}
+			},
+			getStartDate(){
+				let start=this.startYear;
+				let startDate="";
+				let reg=/-/g;
+				if(start){
+					startDate=new Date(start+"/01/01");
+				}else{
+					startDate=new Date("1970/01/01");
+				}
+				return startDate;
+			},
+			getEndDate(){
+				let end=this.endYear;
+				let reg=/-/g;
+				let endDate="";
+				if(end){
+					endDate=new Date(end+"/12/31");
+				}else{
+					endDate=new Date();
+				}
+				return endDate;
+			},
+			getDval(){
+				let value=this.value;
+				let dVal=null;
+				let aDate=new Date();
+				let year=this.formatNum(aDate.getFullYear());
+				let month=this.formatNum(aDate.getMonth()+1);
+				let day=this.formatNum(aDate.getDate());
+				let hour=aDate.getHours();
+				let section="上午";
+				if(hour>=12)section="下午";
+				if(value){
+					let flag=this.checkValue(value);
+					if(!flag){
+						dVal=[year,month,day,section]
+					}else{
+						let v=value.split(" ");
+						dVal=[...v[0].split("-"),v[1]];
+					}
+				}else{
+					dVal=[year,month,day,section]
+				}
+				return dVal;
+			},
+			initData(){
+				let startDate,endDate,startYear,endYear,startMonth,endMonth,startDay,endDay;
+				let years=[],months=[],days=[],sections=[];
+				let dVal=[],pickVal=[];
+				let value=this.value;
+				let reg=/-/g;
+				let range={};
+				let result="",full="",year,month,day,section,obj={};
+				let defaultDate=this.getDefaultDate();
+				let defaultYear=defaultDate.defaultYear;
+				let defaultMonth=defaultDate.defaultMonth;
+				let defaultDay=defaultDate.defaultDay;
+				let defaultDays=defaultDate.defaultDays;
+				let curFlag=this.current;
+				let disabledAfter=this.disabledAfter;
+				let curDate=this.getCurrenDate();
+				let curYear=curDate.curYear;
+				let curMonth=curDate.curMonth;
+				let curMonthdays=curDate.curMonthdays;
+				let curDay=curDate.curDay;
+				let curSection=curDate.curSection;
+				let dateData=[];
+				dVal=this.getDval();
+				startDate=this.getStartDate();
+				endDate=this.getEndDate();
+				startYear=startDate.getFullYear();
+				startMonth=startDate.getMonth();
+				startDay=startDate.getDate();
+				endYear=endDate.getFullYear();
+				endMonth=endDate.getMonth();
+				endDay=endDate.getDate();
+				dateData=this.getData(dVal);
+				years=dateData.years;
+				months=dateData.months;
+				days=dateData.days;
+				sections=dateData.sections;
+				pickVal=disabledAfter?[
+					dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+					dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+					dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0,
+					dVal[3]&&sections.indexOf(dVal[3])!=-1?sections.indexOf(dVal[3]):0
+				]:(curFlag?[
+					years.indexOf(curYear+''),
+					months.indexOf(this.formatNum(curMonth)),
+					days.indexOf(this.formatNum(curDay)),
+					sections.indexOf(curSection),
+				]:[
+					dVal[0]&&years.indexOf(dVal[0])!=-1?years.indexOf(dVal[0]):0,
+					dVal[1]&&months.indexOf(dVal[1])!=-1?months.indexOf(dVal[1]):0,
+					dVal[2]&&days.indexOf(dVal[2])!=-1?days.indexOf(dVal[2]):0,
+					dVal[3]&&sections.indexOf(dVal[3])!=-1?sections.indexOf(dVal[3]):0
+				]);
+				range={years,months,days,sections};
+				year=dVal[0]?dVal[0]:years[0];
+				month=dVal[1]?dVal[1]:months[0];
+				day=dVal[2]?dVal[2]:days[0];
+				section=dVal[3]?dVal[3]:sections[0];
+				result=full=`${year+'-'+month+'-'+day+' '+section}`;
+				obj={
+					year,
+					month,
+					day,
+					section
+				}
+				this.range=range;
+				this.checkObj=obj;
+				this.$nextTick(()=>{
+					this.pickVal=pickVal;
+				});
+				this.$emit("change",{
+					result:result,
+					value:full,
+					obj:obj
+				})
+			},
+			handlerChange(e){
+				let arr=[...e.detail.value];
+				let data=this.range;
+				let year="",month="",day="",section="";
+				let result="",full="",obj={};
+				let months=null,days=null,sections=null;
+				let disabledAfter=this.disabledAfter;
+				year=(arr[0]||arr[0]==0)?data.years[arr[0]]||data.years[data.years.length-1]:"";
+				month=(arr[1]||arr[1]==0)?data.months[arr[1]]||data.months[data.months.length-1]:"";
+				day=(arr[2]||arr[2]==0)?data.days[arr[2]]||data.days[data.days.length-1]:"";
+				section=(arr[3]||arr[3]==0)?data.sections[arr[3]]||data.sections[data.sections.length-1]:"";
+				result=full=`${year+'-'+month+'-'+day+' '+section}`;
+				let resetData=this.resetData(year,month,day);
+				if(this.disabledAfter){
+					months=resetData.months;
+					days=resetData.days;
+					sections=resetData.sections;
+				}else{
+					if(year%4==0||(month!=this.checkObj.month)){
+						days=resetData.days;
+					}
+				}
+				if(months)this.range.months=months;
+				if(days)this.range.days=days;
+				if(sections)this.range.sections=sections;
+				obj={
+					year,
+					month,
+					day,
+					section
+				}
+				this.checkObj=obj;
+				this.$emit("change",{
+					result:result,
+					value:full,
+					obj:obj
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import "./w-picker.css";
+</style>

+ 274 - 0
components/w-picker/linkage-picker.vue

@@ -0,0 +1,274 @@
+<template>
+	<view class="w-picker-view">
+		<picker-view class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column v-for="(group,gIndex) in range" :key="gIndex">
+				<view class="w-picker-item" v-for="(item,index) in group" :key="index">{{item[nodeKey]}}</view>
+			</picker-view-column>
+		</picker-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				pickVal:[],
+				range:[],
+				checkObj:{}
+			};
+		},
+		props:{
+			itemHeight:{
+				type:String,
+				default:"44px"
+			},
+			value:{
+				type:[Array,String],
+				default:""
+			},
+			defaultType:{
+				type:String,
+				default:"label"
+			},
+			options:{
+				type:Array,
+				default(){
+					return []
+				}
+			},
+			defaultProps:{
+				type:Object,
+				default(){
+					return{
+						lable:"label",
+						value:"value",
+						children:"children"
+					}
+				}
+			},
+			level:{
+				//多级联动层级,表示几级联动
+				type:[Number,String],
+				default:2
+			}
+		},
+		computed:{
+			nodeKey(){
+				return this.defaultProps.label;
+			},
+			nodeVal(){
+				return this.defaultProps.value;
+			},
+			nodeChild(){
+				return this.defaultProps.children;
+			}
+		},
+		watch:{
+			value(val){
+				if(this.options.length!=0){
+					this.initData();
+				}
+			},
+			options(val){
+				this.initData();
+			}
+		},
+		created() {
+			if(this.options.length!=0){
+				this.initData();
+			}
+		},
+		methods:{
+			getData(){
+				//用来处理初始化数据
+				let options=this.options;
+				let col1={},col2={},col3={},col4={};
+				let arr1=options,arr2=[],arr3=[],arr4=[];
+				let col1Index=0,col2Index=0,col3Index=0,col4Index=0;
+				let a1="",a2="",a3="",a4="";
+				let dVal=[],obj={};
+				let value=this.value;
+				let data=[];
+				a1=value[0];
+				a2=value[1];
+				if(this.level>2){
+					a3=value[2];
+				}
+				if(this.level>3){
+					a4=value[3];
+				};
+				/*第1列*/
+				col1Index=arr1.findIndex((v)=>{
+					return v[this.defaultType]==a1
+				});
+				col1Index=value?(col1Index!=-1?col1Index:0):0;
+				col1=arr1[col1Index];
+				
+				/*第2列*/
+				arr2=arr1[col1Index][this.nodeChild];
+				col2Index=arr2.findIndex((v)=>{
+					return v[this.defaultType]==a2
+				});
+				col2Index=value?(col2Index!=-1?col2Index:0):0;
+				col2=arr2[col2Index];
+				
+				/*第3列*/
+				if(this.level>2){
+					arr3=arr2[col2Index][this.nodeChild];
+					col3Index=arr3.findIndex((v)=>{
+						return v[this.defaultType]==a3;
+					});
+					col3Index=value?(col3Index!=-1?col3Index:0):0;
+					col3=arr3[col3Index];
+				};
+				
+				
+				/*第4列*/
+				if(this.level>3){
+					arr4=arr3[col4Index][this.nodeChild];
+					col4Index=arr4.findIndex((v)=>{
+						return v[this.defaultType]==a4;
+					});
+					col4Index=value?(col4Index!=-1?col4Index:0):0;
+					col4=arr4[col4Index];
+				};
+				switch(this.level*1){
+					case 2:
+						dVal=[col1Index,col2Index];
+						obj={
+							col1,
+							col2
+						}
+						data=[arr1,arr2];
+						break;
+					case 3:
+						dVal=[col1Index,col2Index,col3Index];
+						obj={
+							col1,
+							col2,
+							col3
+						}
+						data=[arr1,arr2,arr3];
+						break;
+					case 4:
+						dVal=[col1Index,col2Index,col3Index,col4Index];
+						obj={
+							col1,
+							col2,
+							col3,
+							col4
+						}
+						data=[arr1,arr2,arr3,arr4];
+						break
+				}
+				return {
+					data,
+					dVal,
+					obj
+				}
+			},
+			initData(){
+				let dataData=this.getData();
+				let data=dataData.data;
+				let arr1=data[0];
+				let arr2=data[1];
+				let arr3=data[2]||[];
+				let arr4=data[3]||[];
+				let obj=dataData.obj;
+				let col1=obj.col1,col2=obj.col2,col3=obj.col3||{},col4=obj.col4||{};
+				let result="",value=[];
+				let range=[];
+				switch(this.level){
+					case 2:
+						value=[col1[this.nodeVal],col2[this.nodeVal]];
+						result=`${col1[this.nodeKey]+col2[this.nodeKey]}`;
+						range=[arr1,arr2];
+						break;
+					case 3:
+						value=[col1[this.nodeVal],col2[this.nodeVal],col3[this.nodeVal]];
+						result=`${col1[this.nodeKey]+col2[this.nodeKey]+col3[this.nodeKey]}`;
+						range=[arr1,arr2,arr3];
+						break;
+					case 4:
+						value=[col1[this.nodeVal],col2[this.nodeVal],col3[this.nodeVal],col4[this.nodeVal]];
+						result=`${col1[this.nodeKey]+col2[this.nodeKey]+col3[this.nodeKey]+col4[this.nodeKey]}`;
+						range=[arr1,arr2,arr3,arr4];
+						break;
+				}
+				this.range=range;
+				this.checkObj=obj;
+				this.$nextTick(()=>{
+					this.pickVal=dataData.dVal;
+				});
+				this.$emit("change",{
+					result:result,
+					value:value,
+					obj:obj
+				})
+			},
+			handlerChange(e){
+				let arr=[...e.detail.value];
+				let col1Index=arr[0],col2Index=arr[1],col3Index=arr[2]||0,col4Index=arr[3]||0;
+				let arr1=[],arr2=[],arr3=[],arr4=[];
+				let col1,col2,col3,col4,obj={};
+				let result="",value=[];
+				arr1=this.options;
+				arr2=(arr1[col1Index]&&arr1[col1Index][this.nodeChild])||arr1[arr1.length-1][this.nodeChild]||[];
+				col1=arr1[col1Index]||arr1[arr1.length-1]||{};
+				col2=arr2[col2Index]||arr2[arr2.length-1]||{};
+				if(this.level>2){
+					arr3=(arr2[col2Index]&&arr2[col2Index][this.nodeChild])||arr2[arr2.length-1][this.nodeChild];
+					col3=arr3[col3Index]||arr3[arr3.length-1]||{};
+				}
+				if(this.level>3){
+					arr4=(arr3[col3Index]&&arr3[col3Index][this.nodeChild])||arr3[arr3.length-1][this.nodeChild]||[];
+					col4=arr4[col4Index]||arr4[arr4.length-1]||{};
+				}
+				switch(this.level){
+					case 2:
+						obj={
+							col1,
+							col2
+						}
+						this.range=[arr1,arr2];
+						result=`${(col1[this.nodeKey]||'')+(col2[this.nodeKey]||'')}`;
+						value=[col1[this.nodeVal]||'',col2[this.nodeVal]||''];
+						break;
+					case 3:
+						obj={
+							col1,
+							col2,
+							col3
+						}
+						this.range=[arr1,arr2,arr3];
+						result=`${(col1[this.nodeKey]||'')+(col2[this.nodeKey]||'')+(col3[this.nodeKey]||'')}`;
+						value=[col1[this.nodeVal]||'',col2[this.nodeVal]||'',col3[this.nodeVal]||''];
+						break;
+					case 4:
+						obj={
+							col1,
+							col2,
+							col3,
+							col4
+						}
+						this.range=[arr1,arr2,arr3,arr4];
+						result=`${(col1[this.nodeKey]||'')+(col2[this.nodeKey]||'')+(col3[this.nodeKey]||'')+(col4[this.nodeKey]||'')}`;
+						value=[col1[this.nodeVal]||'',col2[this.nodeVal]||'',col3[this.nodeVal]||'',col4[this.nodeVal]||''];
+						break;
+				}
+				this.checkObj=obj;
+				this.pickVal=arr;
+				this.$emit("change",{
+					result:result,
+					value:value,
+					obj:obj
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import "./w-picker.css";	
+</style>
+

+ 344 - 0
components/w-picker/range-picker.vue

@@ -0,0 +1,344 @@
+<template>
+	<view class="w-picker-view">
+		<picker-view  class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column class="w-picker-flex2">
+				<view class="w-picker-item" v-for="(item,index) in range.fyears" :key="index">{{item}}年</view>
+			</picker-view-column>
+			<picker-view-column class="w-picker-flex2">
+				<view class="w-picker-item" v-for="(item,index) in range.fmonths" :key="index">{{item}}月</view>
+			</picker-view-column>
+			<picker-view-column class="w-picker-flex2">
+				<view class="w-picker-item" v-for="(item,index) in range.fdays" :key="index">{{item}}日</view>
+			</picker-view-column>
+			<picker-view-column class="w-picker-flex1">
+				<view class="w-picker-item">-</view>
+			</picker-view-column>
+			<picker-view-column class="w-picker-flex2">
+				<view class="w-picker-item" v-for="(item,index) in range.tyears" :key="index">{{item}}年</view>
+			</picker-view-column>
+			<picker-view-column class="w-picker-flex2">
+				<view class="w-picker-item" v-for="(item,index) in range.tmonths" :key="index">{{item}}月</view>
+			</picker-view-column>
+			<picker-view-column class="w-picker-flex2">
+				<view class="w-picker-item" v-for="(item,index) in range.tdays" :key="index">{{item}}日</view>
+			</picker-view-column>
+		</picker-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				pickVal:[],
+				range:{},
+				checkObj:{}
+			};
+		},
+		props:{
+			itemHeight:{
+				type:String,
+				default:"44px"
+			},
+			value:{
+				type:[String,Array],
+				default(){
+					return []
+				}
+			},
+			current:{//是否默认选中当前日期
+				type:Boolean,
+				default:false
+			},
+			startYear:{
+				type:[String,Number],
+				default:1970
+			},
+			endYear:{
+				type:[String,Number],
+				default:new Date().getFullYear()
+			}
+		},
+		watch:{
+			value(val){
+				this.initData();
+			}
+		},
+		created() {
+			this.initData();
+		},
+		methods:{
+			formatNum(n){
+				return (Number(n)<10?'0'+Number(n):Number(n)+'');
+			},
+			checkValue(value){
+				let strReg=/^\d{4}-\d{2}-\d{2}$/,example="2020-04-03";
+				if(!strReg.test(value[0])||!strReg.test(value[1])){
+					console.log(new Error("请传入与mode匹配的value值,例["+example+","+example+"]"))
+				}
+				return strReg.test(value[0])&&strReg.test(value[1]);
+			},
+			resetToData(fmonth,fday,tyear,tmonth){
+				let range=this.range;
+				let tmonths=[],tdays=[];
+				let yearFlag=tyear!=range.tyears[0];
+				let monthFlag=tyear!=range.tyears[0]||tmonth!=range.tmonths[0];
+				let ttotal=new Date(tyear,tmonth,0).getDate();
+				for(let i=yearFlag?1:fmonth*1;i<=12;i++){
+					tmonths.push(this.formatNum(i))
+				}
+				for(let i=monthFlag?1:fday*1;i<=ttotal;i++){
+					tdays.push(this.formatNum(i))
+				}
+				return{
+					tmonths,
+					tdays
+				}
+			},
+			resetData(fyear,fmonth,fday,tyear,tmonth){
+				let fyears=[],fmonths=[],fdays=[],tyears=[],tmonths=[],tdays=[];
+				let startYear=this.startYear;
+				let endYear=this.endYear;
+				let ftotal=new Date(fyear,fmonth,0).getDate();
+				let ttotal=new Date(tyear,tmonth,0).getDate();
+				for(let i=startYear*1;i<=endYear;i++){
+					fyears.push(this.formatNum(i))
+				}
+				for(let i=1;i<=12;i++){
+					fmonths.push(this.formatNum(i))
+				}
+				for(let i=1;i<=ftotal;i++){
+					fdays.push(this.formatNum(i))
+				}
+				for(let i=fyear*1;i<=endYear;i++){
+					tyears.push(this.formatNum(i))
+				}
+				for(let i=fmonth*1;i<=12;i++){
+					tmonths.push(this.formatNum(i))
+				}
+				for(let i=fday*1;i<=ttotal;i++){
+					tdays.push(this.formatNum(i))
+				}
+				return {
+					fyears,
+					fmonths,
+					fdays,
+					tyears,
+					tmonths,
+					tdays
+				}
+			},
+			getData(dVal){
+				let start=this.startYear*1;
+				let end=this.endYear*1;
+				let value=dVal;
+				let flag=this.current;
+				let aToday=new Date();
+				let tYear,tMonth,tDay,tHours,tMinutes,tSeconds,pickVal=[];
+				let initstartDate=new Date(start.toString());
+				let endDate=new Date(end.toString());
+				if(start>end){
+					initstartDate=new Date(end.toString());
+					endDate=new Date(start.toString());
+				};
+				let startYear=initstartDate.getFullYear();
+				let startMonth=initstartDate.getMonth()+1;
+				let endYear=endDate.getFullYear();
+				let fyears=[],fmonths=[],fdays=[],tyears=[],tmonths=[],tdays=[],returnArr=[],startDVal=[],endDVal=[];
+				let curMonth=flag?value[1]*1:(startDVal[1]*1+1);
+				let curMonth1=flag?value[5][1]*1:(value[5]*1+1);
+				let totalDays=new Date(value[0],value[1],0).getDate();
+				let totalDays1=new Date(value[4],value[5],0).getDate();
+				for(let s=startYear;s<=endYear;s++){
+					fyears.push(this.formatNum(s));
+				};
+				for(let m=1;m<=12;m++){
+					fmonths.push(this.formatNum(m));
+				};
+				for(let d=1;d<=totalDays;d++){
+					fdays.push(this.formatNum(d));
+				};
+				for(let s=value[0]*1;s<=endYear;s++){
+					tyears.push(this.formatNum(s));
+				};
+				
+				if(value[4]*1>value[0]*1){
+					for(let m=1;m<=12;m++){
+						tmonths.push(this.formatNum(m));
+					};
+					for(let d=1;d<=totalDays1;d++){
+						tdays.push(this.formatNum(d));
+					};
+				}else{
+					for(let m=value[1]*1;m<=12;m++){
+						tmonths.push(this.formatNum(m));
+					};
+					for(let d=value[2]*1;d<=totalDays1;d++){
+						tdays.push(this.formatNum(d));
+					};
+				};
+				
+				pickVal=[
+					fyears.indexOf(value[0])==-1?0:fyears.indexOf(value[0]),
+					fmonths.indexOf(value[1])==-1?0:fmonths.indexOf(value[1]),
+					fdays.indexOf(value[2])==-1?0:fdays.indexOf(value[2]),
+					0,
+					tyears.indexOf(value[4])==-1?0:tyears.indexOf(value[4]),
+					tmonths.indexOf(value[5])==-1?0:tmonths.indexOf(value[5]),
+					tdays.indexOf(value[6])==-1?0:tdays.indexOf(value[6])
+				];
+				return {
+					fyears,
+					fmonths,
+					fdays,
+					tyears,
+					tmonths,
+					tdays,
+					pickVal
+				}
+			},
+			getDval(){
+				let value=this.value;
+				let fields=this.fields;
+				let dVal=null;
+				let aDate=new Date();
+				let fyear=this.formatNum(aDate.getFullYear());
+				let fmonth=this.formatNum(aDate.getMonth()+1);
+				let fday=this.formatNum(aDate.getDate());
+				let tyear=this.formatNum(aDate.getFullYear());
+				let tmonth=this.formatNum(aDate.getMonth()+1);
+				let tday=this.formatNum(aDate.getDate());
+				if(value&&value.length>0){
+					let flag=this.checkValue(value);
+					if(!flag){
+						dVal=[fyear,fmonth,fday,"-",tyear,tmonth,tday]
+					}else{
+						dVal=[...value[0].split("-"),"-",...value[1].split("-")];
+					}
+				}else{
+					dVal=[fyear,fmonth,fday,"-",tyear,tmonth,tday]
+				}
+				return dVal;
+			},
+			initData(){
+				let range=[],pickVal=[];
+				let result="",full="",obj={};
+				let dVal=this.getDval();
+				let dateData=this.getData(dVal);
+				let fyears=[],fmonths=[],fdays=[],tyears=[],tmonths=[],tdays=[];
+				let fyear,fmonth,fday,tyear,tmonth,tday;
+				pickVal=dateData.pickVal;
+				fyears=dateData.fyears;
+				fmonths=dateData.fmonths;
+				fdays=dateData.fdays;
+				tyears=dateData.tyears;
+				tmonths=dateData.tmonths;
+				tdays=dateData.tdays;
+				range={
+					fyears,
+					fmonths,
+					fdays,
+					tyears,
+					tmonths,
+					tdays,
+				}
+				fyear=range.fyears[pickVal[0]];
+				fmonth=range.fmonths[pickVal[1]];
+				fday=range.fdays[pickVal[2]];
+				tyear=range.tyears[pickVal[4]];
+				tmonth=range.tmonths[pickVal[5]];
+				tday=range.tdays[pickVal[6]];
+				obj={
+					fyear,
+					fmonth,
+					fday,
+					tyear,
+					tmonth,
+					tday
+				}
+				result=`${fyear+'-'+fmonth+'-'+fday+'至'+tyear+'-'+tmonth+'-'+tday}`;
+				this.range=range;
+				this.checkObj=obj;
+				this.$nextTick(()=>{
+					this.pickVal=pickVal;
+				});
+				this.$emit("change",{
+					result:result,
+					value:result.split("至"),
+					obj:obj
+				})
+			},
+			handlerChange(e){
+				let arr=[...e.detail.value];
+				let result="",full="",obj={};
+				let year="",month="",day="",hour="",minute="",second="",note=[],province,city,area;
+				let checkObj=this.checkObj;
+				let days=[],months=[],endYears=[],endMonths=[],endDays=[],startDays=[];
+				let mode=this.mode;
+				let col1,col2,col3,d,a,h,m;
+				let xDate=new Date().getTime();
+				let range=this.range;
+				let fyear=range.fyears[arr[0]]||range.fyears[range.fyears.length-1];
+				let fmonth=range.fmonths[arr[1]]||range.fmonths[range.fmonths.length-1];
+				let fday=range.fdays[arr[2]]||range.fdays[range.fdays.length-1];
+				let tyear=range.tyears[arr[4]]||range.tyears[range.tyears.length-1];
+				let tmonth=range.tmonths[arr[5]]||range.tmonths[range.tmonths.length-1];
+				let tday=range.tdays[arr[6]]||range.tdays[range.tdays.length-1];
+				let resetData=this.resetData(fyear,fmonth,fday,tyear,tmonth);
+				if(fyear!=checkObj.fyear||fmonth!=checkObj.fmonth||fday!=checkObj.fday){
+					arr[4]=0;
+					arr[5]=0;
+					arr[6]=0;
+					range.tyears=resetData.tyears;
+					range.tmonths=resetData.tmonths;
+					range.tdays=resetData.tdays;
+					tyear=range.tyears[0];
+					checkObj.tyears=range.tyears[0];
+					tmonth=range.tmonths[0];
+					checkObj.tmonths=range.tmonths[0];
+					tday=range.tdays[0];
+					checkObj.tdays=range.tdays[0];
+				}
+				if(fyear!=checkObj.fyear||fmonth!=checkObj.fmonth){
+					range.fdays=resetData.fdays;
+				};
+				if(tyear!=checkObj.tyear){
+					arr[5]=0;
+					arr[6]=0;
+					let toData=this.resetToData(fmonth,fday,tyear,tmonth);
+					range.tmonths=toData.tmonths;
+					range.tdays=toData.tdays;
+					tmonth=range.tmonths[0];
+					checkObj.tmonths=range.tmonths[0];
+					tday=range.tdays[0];
+					checkObj.tdays=range.tdays[0];
+				};
+				if(tmonth!=checkObj.tmonth){
+					arr[6]=0;
+					let toData=this.resetToData(fmonth,fday,tyear,tmonth);
+					range.tdays=toData.tdays;
+					tday=range.tdays[0];
+					checkObj.tdays=range.tdays[0];
+				};
+				result=`${fyear+'-'+fmonth+'-'+fday+'至'+tyear+'-'+tmonth+'-'+tday}`;
+				obj={
+					fyear,fmonth,fday,tyear,tmonth,tday
+				}
+				this.checkObj=obj;
+				this.$nextTick(()=>{
+					this.pickVal=arr;
+				})
+				this.$emit("change",{
+					result:result,
+					value:result.split("至"),
+					obj:obj
+				})
+				
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import "./w-picker.css";
+</style>

+ 183 - 0
components/w-picker/region-picker.vue

@@ -0,0 +1,183 @@
+<template>
+	<view class="w-picker-view">
+		<picker-view class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.provinces" :key="index">{{item.label}}</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.citys" :key="index">{{item.label}}</view>
+			</picker-view-column>
+			<picker-view-column v-if="!hideArea">
+				<view class="w-picker-item" v-for="(item,index) in range.areas" :key="index">{{item.label}}</view>
+			</picker-view-column>
+		</picker-view>
+	</view>
+</template>
+
+<script>
+	import areaData from "./areadata/areadata.js"
+	export default {
+		data() {
+			return {
+				pickVal:[],
+				range:{
+					provinces:[],
+					citys:[],
+					areas:[]
+				},
+				checkObj:{}
+			};
+		},
+		props:{
+			itemHeight:{
+				type:String,
+				default:"44px"
+			},
+			value:{
+				type:[Array,String],
+				default:""
+			},
+			defaultType:{
+				type:String,
+				default:"label"
+			},
+			hideArea:{
+				type:Boolean,
+				default:false
+			}
+		},
+		watch:{
+			value(val){
+				this.initData();
+			}
+		},
+		created() {
+			this.initData();
+		},
+		methods:{
+			getData(){
+				//用来处理初始化数据
+				let provinces=areaData;
+				let dVal=[];
+				let value=this.value;
+				let a1=value[0];//默认值省
+				let a2=value[1];//默认值市
+				let a3=value[2];//默认值区、县
+				let province,city,area;
+				let provinceIndex=provinces.findIndex((v)=>{
+					return v[this.defaultType]==a1
+				});
+				provinceIndex=value?(provinceIndex!=-1?provinceIndex:0):0;
+				let citys=provinces[provinceIndex].children;
+				let cityIndex=citys.findIndex((v)=>{
+					return v[this.defaultType]==a2
+				});
+				cityIndex=value?(cityIndex!=-1?cityIndex:0):0;
+				let areas=citys[cityIndex].children;
+				let areaIndex=areas.findIndex((v)=>{
+					return v[this.defaultType]==a3;
+				});
+				areaIndex=value?(areaIndex!=-1?areaIndex:0):0;
+				dVal=this.hideArea?[provinceIndex,cityIndex]:[provinceIndex,cityIndex,areaIndex];
+				province=provinces[provinceIndex];
+				city=citys[cityIndex];
+				area=areas[areaIndex];
+				let obj=this.hideArea?{
+					province,
+					city
+				}:{
+					province,
+					city,
+					area
+				}
+				return this.hideArea?{
+					provinces,
+					citys,
+					dVal,
+					obj
+				}:{
+					provinces,
+					citys,
+					areas,
+					dVal,
+					obj
+				}
+			},
+			initData(){
+				let dataData=this.getData();
+				let provinces=dataData.provinces;
+				let citys=dataData.citys;
+				let areas=this.hideArea?[]:dataData.areas;
+				let obj=dataData.obj;
+				let province=obj.province,city=obj.city,area=this.hideArea?{}:obj.area;
+				let value=this.hideArea?[province.value,city.value]:[province.value,city.value,area.value];
+				let result=this.hideArea?`${province.label+city.label}`:`${province.label+city.label+area.label}`;
+				this.range=this.hideArea?{
+					provinces,
+					citys,
+				}:{
+					provinces,
+					citys,
+					areas
+				};
+				this.checkObj=obj;
+				this.$nextTick(()=>{
+					this.pickVal=dataData.dVal;
+				});
+				this.$emit("change",{
+					result:result,
+					value:value,
+					obj:obj
+				})
+			},
+			handlerChange(e){
+				let arr=[...e.detail.value];
+				let provinceIndex=arr[0],cityIndex=arr[1],areaIndex=this.hideArea?0:arr[2];
+				let provinces=areaData;
+				let citys=(provinces[provinceIndex]&&provinces[provinceIndex].children)||provinces[provinces.length-1].children||[];
+				let areas=this.hideArea?[]:((citys[cityIndex]&&citys[cityIndex].children)||citys[citys.length-1].children||[]);
+				let province=provinces[provinceIndex]||provinces[provinces.length-1],
+				city=citys[cityIndex]||[citys.length-1],
+				area=this.hideArea?{}:(areas[areaIndex]||[areas.length-1]);
+				let obj=this.hideArea?{
+					province,
+					city
+				}:{
+					province,
+					city,
+					area
+				}
+				if(this.checkObj.province.label!=province.label){
+					//当省更新的时候需要刷新市、区县的数据;
+					this.range.citys=citys;
+					if(!this.hideArea){
+						this.range.areas=areas;
+					}
+					
+				}
+				if(this.checkObj.city.label!=city.label){
+					//当市更新的时候需要刷新区县的数据;
+					if(!this.hideArea){
+						this.range.areas=areas;
+					}
+				}
+				this.checkObj=obj;
+				this.$nextTick(()=>{
+					this.pickVal=arr;
+				})
+				let result=this.hideArea?`${province.label+city.label}`:`${province.label+city.label+area.label}`;
+				let value=this.hideArea?[province.value,city.value]:[province.value,city.value,area.value];
+				this.$emit("change",{
+					result:result,
+					value:value,
+					obj:obj
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import "./w-picker.css";	
+</style>
+

+ 129 - 0
components/w-picker/selector-picker.vue

@@ -0,0 +1,129 @@
+<template>
+	<view class="w-picker-view">
+		<picker-view class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range" :key="index">{{item[nodeKey]}}</view>
+			</picker-view-column>
+		</picker-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		props:{
+			itemHeight:{
+				type:String,
+				default:"44px"
+			},
+			options:{
+				type:[Array,Object],
+				default(){
+					return []
+				}
+			},
+			value:{
+				type:String,
+				default:""
+			},
+			defaultType:{
+				type:String,
+				default:"label"
+			},
+			defaultProps:{
+				type:Object,
+				default(){
+					return{
+						label:"label",
+						value:"value"
+					}
+				}
+			}
+		},
+		data() {
+			return {
+				pickVal:[]
+			};
+		},
+		computed:{
+			nodeKey(){
+				return this.defaultProps.label;
+			},
+			nodeValue(){
+				return this.defaultProps.value;
+			},
+			range(){
+				return this.options
+			}
+		},
+		watch:{
+			value(val){
+				if(this.options.length!=0){
+					this.initData();
+				}
+			},
+			options(val){
+				this.initData();
+			}
+		},
+		created() {
+			if(this.options.length!=0){
+				this.initData();
+			}
+		},
+		methods:{
+			initData(){
+				let dVal=this.value||"";
+				let data=this.range;
+				let pickVal=[0];
+				let cur=null;
+				let label="";
+				let value,idx;
+				if(this.defaultType==this.nodeValue){
+					value=data.find((v)=>v[this.nodeValue]==dVal);
+					idx=data.findIndex((v)=>v[this.nodeValue]==dVal);
+				}else{
+					value=data.find((v)=>v[this.nodeKey]==dVal);
+					idx=data.findIndex((v)=>v[this.nodeKey]==dVal);
+				}
+				pickVal=[idx!=-1?idx:0];
+				this.$nextTick(()=>{
+					this.pickVal=pickVal;
+				});
+				if(this.defaultType==this.nodeValue){
+					this.$emit("change",{
+						result:value?value[this.nodeKey]:data[0][this.nodeKey],
+						value:dVal||data[0][this.nodeKey],
+						obj:value?value:data[0]
+					})
+				}else{
+					this.$emit("change",{
+						result:dVal||data[0][this.nodeKey],
+						value:value?value[this.nodeValue]:data[0][this.nodeValue],
+						obj:value?value:data[0]
+					})
+				}
+				
+			},
+			handlerChange(e){
+				let arr=[...e.detail.value];
+				let pickVal=[arr[0]||0];
+				let data=this.range;
+				let cur=data[arr[0]];
+				let label="";
+				let value="";
+				this.$nextTick(()=>{
+					this.pickVal=pickVal;
+				});
+				this.$emit("change",{
+					result:cur[this.nodeKey],
+					value:cur[this.nodeValue],
+					obj:cur
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import "./w-picker.css";
+</style>

+ 250 - 0
components/w-picker/shortterm-picker.vue

@@ -0,0 +1,250 @@
+<template>
+	<view class="w-picker-view">
+		<picker-view class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.dates" :key="index">{{item.label}}</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.hours" :key="index">{{item.label}}时</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.minutes" :key="index">{{item.label}}分</view>
+			</picker-view-column>
+		</picker-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				pickVal:[],
+				range:{},
+				checkObj:{}
+			};
+		},
+		props:{
+			itemHeight:{
+				type:String,
+				default:"44px"
+			},
+			value:{
+				type:[String,Array,Number],
+				default:""
+			},
+			current:{//是否默认选中当前日期
+				type:Boolean,
+				default:false
+			},
+			expand:{
+				type:[Number,String],
+				default:30
+			}
+		},
+		watch:{
+			value(val){
+				this.initData();
+			}
+		},
+		created() {
+			this.initData();
+		},
+		methods:{
+			formatNum(n){
+				return (Number(n)<10?'0'+Number(n):Number(n)+'');
+			},
+			checkValue(value){
+				let strReg=/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2})?$/,example="2019-12-12 18:05:00或者2019-12-12 18:05";
+				if(!strReg.test(value)){
+					console.log(new Error("请传入与mode、fields匹配的value值,例value="+example+""))
+				}
+				return strReg.test(value);
+			},
+			resetData(year,month,day){
+				let curDate=this.getCurrenDate();
+				let curFlag=this.current;
+				let curYear=curDate.curYear;
+				let curMonth=curDate.curMonth;
+				let curDay=curDate.curDay;
+				let curHour=curDate.curHour;
+				let months=[],days=[],sections=[];
+				let disabledAfter=this.disabledAfter;
+				let monthsLen=disabledAfter?(year*1<curYear?12:curMonth):12;
+				let totalDays=new Date(year,month,0).getDate();//计算当月有几天;
+				for(let month=1;month<=monthsLen;month++){
+					months.push(this.formatNum(month));
+				};
+				for(let day=1;day<=daysLen;day++){
+					days.push(this.formatNum(day));
+				}
+				return{
+					months,
+					days,
+					sections
+				}
+			},
+			getData(dVal){
+				//用来处理初始化数据
+				let curFlag=this.current;
+				let disabledAfter=this.disabledAfter;
+				let dates=[],hours=[],minutes=[];
+				let curDate=new Date();
+				let curYear=curDate.getFullYear();
+				let curMonth=curDate.getMonth();
+				let curDay=curDate.getDate();
+				let aDate=new Date(curYear,curMonth,curDay);
+				for(let i=0;i<this.expand*1;i++){
+					aDate=new Date(curYear,curMonth,curDay+i);
+					let year=aDate.getFullYear();
+					let month=aDate.getMonth()+1;
+					let day=aDate.getDate();
+					let label=year+"-"+this.formatNum(month)+"-"+this.formatNum(day);
+					switch(i){
+						case 0:
+							label="今天";
+							break;
+						case 1:
+							label="明天";
+							break;
+						case 2:
+							label="后天";
+							break
+					}
+					dates.push({
+						label:label,
+						value:year+"-"+this.formatNum(month)+"-"+this.formatNum(day)
+					})
+				};
+				for(let i=0;i<24;i++){
+					hours.push({
+						label:this.formatNum(i),
+						value:this.formatNum(i)
+					})
+				}
+				for(let i=0;i<60;i++){
+					minutes.push({
+						label:this.formatNum(i),
+						value:this.formatNum(i)
+					})
+				}
+				return {
+					dates,
+					hours,
+					minutes
+				}
+			},
+			getDefaultDate(){
+				let value=this.value;
+				let reg=/-/g;
+				let defaultDate=value?new Date(value.replace(reg,"/")):new Date();
+				let defaultYear=defaultDate.getFullYear();
+				let defaultMonth=defaultDate.getMonth()+1;
+				let defaultDay=defaultDate.getDate();
+				let defaultDays=new Date(defaultYear,defaultMonth,0).getDate()*1;
+				return{
+					defaultDate,
+					defaultYear,
+					defaultMonth,
+					defaultDay,
+					defaultDays
+				}
+			},
+			getDval(){
+				let value=this.value;
+				let dVal=null;
+				let aDate=new Date();
+				let year=this.formatNum(aDate.getFullYear());
+				let month=this.formatNum(aDate.getMonth()+1);
+				let day=this.formatNum(aDate.getDate());
+				let date=this.formatNum(year)+"-"+this.formatNum(month)+"-"+this.formatNum(day);
+				let hour=aDate.getHours();
+				let minute=aDate.getMinutes();
+				if(value){
+					let flag=this.checkValue(value);
+					if(!flag){
+						dVal=[date,hour,minute]
+					}else{
+						let v=value.split(" ");
+						dVal=[v[0],...v[1].split(":")];
+					}
+				}else{
+					dVal=[date,hour,minute]
+				}
+				return dVal;
+			},
+			initData(){
+				let startDate,endDate,startYear,endYear,startMonth,endMonth,startDay,endDay;
+				let dates=[],hours=[],minutes=[];
+				let dVal=[],pickVal=[];
+				let value=this.value;
+				let reg=/-/g;
+				let range={};
+				let result="",full="",date,hour,minute,obj={};
+				let defaultDate=this.getDefaultDate();
+				let defaultYear=defaultDate.defaultYear;
+				let defaultMonth=defaultDate.defaultMonth;
+				let defaultDay=defaultDate.defaultDay;
+				let defaultDays=defaultDate.defaultDays;
+				let curFlag=this.current;
+				let disabledAfter=this.disabledAfter;
+				let dateData=[];
+				dVal=this.getDval();
+				dateData=this.getData(dVal);
+				dates=dateData.dates;
+				hours=dateData.hours;
+				minutes=dateData.minutes;
+				pickVal=[
+					dates.findIndex(n => n.value == dVal[0])!=-1?dates.findIndex(n => n.value == dVal[0]):0,
+					hours.findIndex(n => n.value == dVal[1])!=-1?hours.findIndex(n => n.value == dVal[1]):0,
+					minutes.findIndex(n => n.value == dVal[2])!=-1?minutes.findIndex(n => n.value == dVal[2]):0,
+				];
+				range={dates,hours,minutes};
+				date=dVal[0]?dVal[0]:dates[0].label;
+				hour=dVal[1]?dVal[1]:hours[0].label;
+				minute=dVal[2]?dVal[2]:minutes[0].label;
+				result=full=`${date+' '+hour+':'+minute}`;
+				obj={
+					date,
+					hour,
+					minute
+				}
+				this.range=range;
+				this.checkObj=obj;
+				this.$nextTick(()=>{
+					this.pickVal=pickVal;
+				});
+				this.$emit("change",{
+					result:result,
+					value:full,
+					obj:obj
+				})
+			},
+			handlerChange(e){
+				let arr=[...e.detail.value];
+				let data=this.range;
+				let date="",hour="",minute="";
+				let result="",full="",obj={};
+				let disabledAfter=this.disabledAfter;
+				date=(arr[0]||arr[0]==0)?data.dates[arr[0]]||data.dates[data.dates.length-1]:"";
+				hour=(arr[1]||arr[1]==0)?data.hours[arr[1]]||data.hours[data.hours.length-1]:"";
+				minute=(arr[2]||arr[2]==0)?data.minutes[arr[2]]||data.minutes[data.minutes.length-1]:"";
+				result=full=`${date.label+' '+hour.label+':'+minute.label+':00'}`;
+				obj={
+					date,
+					hour,
+					minute
+				}
+				this.checkObj=obj;
+				this.$emit("change",{
+					result:result,
+					value:full,
+					obj:obj
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import "./w-picker.css";
+</style>

+ 218 - 0
components/w-picker/time-picker.vue

@@ -0,0 +1,218 @@
+<template>
+	<view class="w-picker-view">
+		<picker-view class="d-picker-view" :indicator-style="itemHeight" :value="pickVal" @change="handlerChange">
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.hours" :key="index">{{item}}时</view>
+			</picker-view-column>
+			<picker-view-column>
+				<view class="w-picker-item" v-for="(item,index) in range.minutes" :key="index">{{item}}分</view>
+			</picker-view-column>
+			<picker-view-column v-if="second">
+				<view class="w-picker-item" v-for="(item,index) in range.seconds" :key="index">{{item}}秒</view>
+			</picker-view-column>
+		</picker-view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				pickVal:[],
+				range:{},
+				checkObj:{}
+			};
+		},
+		props:{
+			itemHeight:{
+				type:String,
+				default:"44px"
+			},
+			value:{
+				type:[String,Array,Number],
+				default:""
+			},
+			current:{//是否默认选中当前日期
+				type:Boolean,
+				default:false
+			},
+			second:{
+				type:Boolean,
+				default:true
+			}
+		},
+		watch:{
+			value(val){
+				this.initData();
+			}
+		},
+		created() {
+			this.initData();
+		},
+		methods:{
+			formatNum(n){
+				return (Number(n)<10?'0'+Number(n):Number(n)+'');
+			},
+			checkValue(value){
+				let strReg=/^\d{2}:\d{2}:\d{2}$/,example="18:00:05";
+				if(!strReg.test(value)){
+					console.log(new Error("请传入与mode、fields匹配的value值,例value="+example+""))
+				}
+				return strReg.test(value);
+			},
+			resetData(year,month,day,hour,minute){
+				let curDate=this.getCurrenDate();
+				let curFlag=this.current;
+				let curHour=curDate.curHour;
+				let curMinute=curDate.curMinute;
+				let curSecond=curDate.curSecond;
+				for(let hour=0;hour<24;hour++){
+					hours.push(this.formatNum(hour));
+				}
+				for(let minute=0;minute<60;minute++){
+					minutes.push(this.formatNum(minute));
+				}
+				for(let second=0;second<60;second++){
+					seconds.push(this.formatNum(second));
+				}
+				return{
+					hours,
+					minutes,
+					seconds
+				}
+			},
+			getData(curDate){
+				//用来处理初始化数据
+				let hours=[],minutes=[],seconds=[];
+				let curFlag=this.current;
+				let disabledAfter=this.disabledAfter;
+				let fields=this.fields;
+				let curHour=curDate.curHour;
+				let curMinute=curDate.curMinute;
+				let curSecond=curDate.curSecond;
+				for(let hour=0;hour<24;hour++){
+					hours.push(this.formatNum(hour));
+				}
+				for(let minute=0;minute<60;minute++){
+					minutes.push(this.formatNum(minute));
+				}
+				for(let second=0;second<60;second++){
+					seconds.push(this.formatNum(second));
+				}
+				return this.second?{
+					hours,
+					minutes,
+					seconds
+				}:{
+					hours,
+					minutes
+				}
+			},
+			getCurrenDate(){
+				let curDate=new Date();
+				let curHour=curDate.getHours();
+				let curMinute=curDate.getMinutes();
+				let curSecond=curDate.getSeconds();
+				return this.second?{
+					curHour,
+					curMinute,
+					curSecond
+				}:{
+					curHour,
+					curMinute,
+				}
+			},
+			getDval(){
+				let value=this.value;
+				let fields=this.fields;
+				let dVal=null;
+				let aDate=new Date();
+				let hour=this.formatNum(aDate.getHours());
+				let minute=this.formatNum(aDate.getMinutes());
+				let second=this.formatNum(aDate.getSeconds());
+				if(value){
+					let flag=this.checkValue(value);
+					if(!flag){
+						dVal=[hour,minute,second]
+					}else{
+						dVal=value?value.split(":"):[];
+					}
+				}else{
+					dVal=this.second?[hour,minute,second]:[hour,minute]
+				}
+				return dVal;
+			},
+			initData(){
+				let curDate=this.getCurrenDate();
+				let dateData=this.getData(curDate);
+				let pickVal=[],obj={},full="",result="",hour="",minute="",second="";
+				let dVal=this.getDval();
+				let curFlag=this.current;
+				let disabledAfter=this.disabledAfter;
+				let hours=dateData.hours;
+				let minutes=dateData.minutes;
+				let seconds=dateData.seconds;
+				let defaultArr=this.second?[
+					dVal[0]&&hours.indexOf(dVal[0])!=-1?hours.indexOf(dVal[0]):0,
+					dVal[1]&&minutes.indexOf(dVal[1])!=-1?minutes.indexOf(dVal[1]):0,
+					dVal[2]&&seconds.indexOf(dVal[2])!=-1?seconds.indexOf(dVal[2]):0
+				]:[
+					dVal[0]&&hours.indexOf(dVal[0])!=-1?hours.indexOf(dVal[0]):0,
+					dVal[1]&&minutes.indexOf(dVal[1])!=-1?minutes.indexOf(dVal[1]):0
+				];
+				pickVal=disabledAfter?defaultArr:(curFlag?(this.second?[
+					hours.indexOf(this.formatNum(curDate.curHour)),
+					minutes.indexOf(this.formatNum(curDate.curMinute)),
+					seconds.indexOf(this.formatNum(curDate.curSecond)),
+				]:[
+					hours.indexOf(this.formatNum(curDate.curHour)),
+					minutes.indexOf(this.formatNum(curDate.curMinute))
+				]):defaultArr);
+				this.range=dateData;
+				this.checkObj=obj;
+				hour=dVal[0]?dVal[0]:hours[0];
+				minute=dVal[1]?dVal[1]:minutes[0];
+				if(this.second)second=dVal[2]?dVal[2]:seconds[0];
+				result=this.second?`${hour+':'+minute+':'+second}`:`${hour+':'+minute}`;
+				full=this.second?`${hour+':'+minute+':'+second}`:`${hour+':'+minute+':00'}`;
+				this.$nextTick(()=>{
+					this.pickVal=pickVal;
+				});
+				this.$emit("change",{
+					result:result,
+					value:full,
+					obj:obj
+				})
+			},
+			handlerChange(e){
+				let arr=[...e.detail.value];
+				let data=this.range;
+				let hour="",minute="",second="",result="",full="",obj={};
+				hour=(arr[0]||arr[0]==0)?data.hours[arr[0]]||data.hours[data.hours.length-1]:"";
+				minute=(arr[1]||arr[1]==0)?data.minutes[arr[1]]||data.minutes[data.minutes.length-1]:"";
+				if(this.second)second=(arr[2]||arr[2]==0)?data.seconds[arr[2]]||data.seconds[data.seconds.length-1]:"";
+				obj=this.second?{
+					hour,
+					minute,
+					second
+				}:{
+					hour,
+					minute
+				};
+				this.checkObj=obj;
+				result=this.second?`${hour+':'+minute+':'+second}`:`${hour+':'+minute}`;
+				full=this.second?`${hour+':'+minute+':'+second}`:`${hour+':'+minute+':00'}`;
+				this.$emit("change",{
+					result:result,
+					value:full,
+					obj:obj
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	@import "./w-picker.css";	
+</style>
+

+ 26 - 0
components/w-picker/w-picker.css

@@ -0,0 +1,26 @@
+.w-picker-flex2{
+	flex:2;
+}
+.w-picker-flex1{
+	flex:1;
+}
+.w-picker-view {
+	width: 100%;
+	height: 476upx;
+	overflow: hidden;
+	background-color: rgba(255, 255, 255, 1);
+	z-index: 666;
+}
+.d-picker-view{
+	height: 100%;
+}
+
+.w-picker-item {
+  text-align: center;
+  width: 100%;
+  height: 88upx;
+  line-height: 88upx;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  font-size: 30upx;
+}

+ 341 - 0
components/w-picker/w-picker.vue

@@ -0,0 +1,341 @@
+<template name="w-picker">
+	<view class="w-picker" :key="createKey" :data-key="createKey">
+		<view class="mask" :class="{'visible':visible}" @tap="onCancel" @touchmove.stop.prevent catchtouchmove="true"></view>
+		<view class="w-picker-cnt" :class="{'visible':visible}">
+			<view class="w-picker-header"  @touchmove.stop.prevent catchtouchmove="true">
+				<text @tap.stop.prevent="onCancel">取消</text>
+				<slot></slot>
+				<text :style="{'color':themeColor}" @tap.stop.prevent="pickerConfirm">确定</text>
+			</view>
+			<date-picker 
+				v-if="mode=='date'" 
+				class="w-picker-wrapper"
+				:startYear="startYear"
+				:endYear="endYear"
+				:value="value"
+				:fields="fields"
+				:item-height="itemHeight"
+				:current="current"
+				:disabled-after="disabledAfter"
+				@change="handlerChange"
+				@touchstart="touchStart" 
+				@touchend="touchEnd">
+			</date-picker>
+			
+			<range-picker
+				v-if="mode=='range'" 
+				class="w-picker-wrapper"
+				:startYear="startYear"
+				:endYear="endYear"
+				:value="value"
+				:item-height="itemHeight"
+				:current="current"
+				@change="handlerChange"
+				@touchstart="touchStart" 
+				@touchend="touchEnd">
+			</range-picker>
+			
+			<half-picker
+				v-if="mode=='half'" 
+				class="w-picker-wrapper"
+				:startYear="startYear"
+				:endYear="endYear"
+				:value="value"
+				:item-height="itemHeight"
+				:current="current"
+				:disabled-after="disabledAfter"
+				@change="handlerChange"
+				@touchstart="touchStart" 
+				@touchend="touchEnd">
+			</half-picker>
+			
+			<shortterm-picker
+				v-if="mode=='shortTerm'" 
+				class="w-picker-wrapper"
+				:startYear="startYear"
+				:endYear="endYear"
+				:value="value"
+				:item-height="itemHeight"
+				:current="current"
+				expand="60"
+				:disabled-after="disabledAfter"
+				@change="handlerChange"
+				@touchstart="touchStart" 
+				@touchend="touchEnd">
+			</shortterm-picker>
+			
+			<time-picker
+				v-if="mode=='time'"
+				class="w-picker-wrapper"
+				:value="value"
+				:item-height="itemHeight"
+				:current="current"
+				:disabled-after="disabledAfter"
+				:second="second"
+				@change="handlerChange"
+				@touchstart="touchStart" 
+				@touchend="touchEnd">
+			</time-picker>
+			
+			<selector-picker
+				v-if="mode=='selector'"
+				class="w-picker-wrapper"
+				:value="value"
+				:item-height="itemHeight"
+				:options="options"
+				:default-type="defaultType"
+				:default-props="defaultProps"
+				@change="handlerChange"
+				@touchstart="touchStart" 
+				@touchend="touchEnd">
+			</selector-picker>
+			
+			<region-picker
+				v-if="mode=='region'"
+				class="w-picker-wrapper"
+				:value="value"
+				:hide-area="hideArea"
+				:default-type="defaultType"
+				:item-height="itemHeight"
+				@change="handlerChange"
+				@touchstart="touchStart" 
+				@touchend="touchEnd">
+			</region-picker>
+			
+			<linkage-picker
+				v-if="mode=='linkage'"
+				class="w-picker-wrapper"
+				:value="value"
+				:options="options"
+				:level="level"
+				:default-type="defaultType"
+				:default-props="defaultProps"
+				:item-height="itemHeight"
+				@change="handlerChange"
+				@touchstart="touchStart" 
+				@touchend="touchEnd">
+			</linkage-picker>
+		</view>
+	</view>
+</template>
+
+<script>
+	import datePicker from "./date-picker.vue"
+	import rangePicker from "./range-picker.vue"
+	import halfPicker from "./half-picker.vue"
+	import shorttermPicker from "./shortterm-picker.vue"
+	import timePicker from "./time-picker.vue"
+	import selectorPicker from "./selector-picker.vue"
+	import regionPicker from "./region-picker.vue"
+	import linkagePicker from "./linkage-picker.vue"
+	export default {
+		name:"w-picker",
+		components:{
+			datePicker,
+			rangePicker,
+			halfPicker,
+			timePicker,
+			selectorPicker,
+			shorttermPicker,
+			regionPicker,
+			linkagePicker
+		},
+		props:{
+			mode:{
+				type:String,
+				default:"date"
+			},
+			value:{//默认值
+				type:[String,Array,Number],
+				default:""
+			},
+			current:{//是否默认显示当前时间,如果是,传的默认值将失效
+				type:Boolean,
+				default:false
+			},
+			themeColor:{//确认按钮主题颜色
+				type:String,
+				default:"#f5a200"
+			},
+			fields:{//日期颗粒度:year、month、day、hour、minute、second
+				type:String,
+				default:"date"
+			},
+			disabledAfter:{//是否禁用当前之后的日期
+				type:Boolean,
+				default:false
+			},
+			second:{//time-picker是否显示秒
+				type:Boolean,
+				default:true
+			},
+			options:{//selector,region数据源
+				type:[Array,Object],
+				default(){
+					return []
+				}
+			},
+			defaultProps:{//selector,linkagle字段转换配置
+				type:Object,
+				default(){
+					return{
+						label:"label",
+						value:"value",
+						children:"children"
+					}
+				}
+			},
+			defaultType:{
+				type:String,
+				default:"label"
+			},
+			hideArea:{//mode=region时,是否隐藏区县列
+				type:Boolean,
+				default:false
+			},
+			level:{
+				//多级联动层级,表示几级联动,区间2-4;
+				type:[Number,String],
+				default:2
+			},
+			timeout:{//是否开启点击延迟,当快速滚动 还没有滚动完毕点击关闭时得到的值是不准确的
+				type:Boolean,
+				default:false
+			},
+			expand:{//mode=shortterm 默认往后拓展天数
+				type:[Number,String],
+				default:30
+			},
+			startYear:{
+				type:[String,Number],
+				default:1970
+			},
+			endYear:{
+				type:[String,Number],
+				default:new Date().getFullYear()
+			},
+			visible:{
+				type:Boolean,
+				default:false
+			}
+		},
+		created() {
+			this.createKey=Math.random()*1000;
+		},
+		data() {
+			return {
+				itemHeight:`height: ${uni.upx2px(88)}px;`,
+				result:{},
+				confirmFlag:true
+			};
+		},
+		methods:{
+			touchStart(){
+				if(this.timeout){
+					this.confirmFlag=false;
+				}
+			},
+			touchEnd(){
+				if(this.timeout){
+					setTimeout(()=>{
+						this.confirmFlag=true;
+					},500)
+				}
+			},
+			handlerChange(res){
+				let _this=this;
+				this.result={...res};
+			},
+			show(){
+				this.$emit("update:visible",true);
+			},
+			hide(){
+				this.$emit("update:visible",false);
+			},
+			onCancel(res){
+				this.$emit("update:visible",false);
+				this.$emit("cancel");
+			},
+			pickerConfirm(){
+				if(!this.confirmFlag){
+					return;
+				};
+				this.$emit("confirm",this.result);
+				this.$emit("update:visible",false);
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.w-picker-item {
+	  text-align: center;
+	  width: 100%;
+	  height: 88upx;
+	  line-height: 88upx;
+	  text-overflow: ellipsis;
+	  white-space: nowrap;
+	  font-size: 30upx;
+	}
+	.w-picker{
+		z-index: 888;
+		.mask {
+		  position: fixed;
+		  z-index: 1000;
+		  top: 0;
+		  right: 0;
+		  left: 0;
+		  bottom: 0;
+		  background: rgba(0, 0, 0, 0.6);
+		  visibility: hidden;
+		  opacity: 0;
+		  transition: all 0.3s ease;
+		  z-index: 999999;
+		}
+		.mask.visible{
+			visibility: visible;
+			opacity: 1;
+		}
+		.w-picker-cnt {
+		  position: fixed;
+		  bottom: 0;
+		  left: 0;
+		  width: 100%;
+		  transition: all 0.3s ease;
+		  transform: translateY(100%);
+		  z-index: 999999;
+		  background-color: #fff;
+		}
+		.w-picker-cnt.visible {
+		  transform: translateY(0);
+		}
+		.w-picker-header{
+		  display: flex;
+		  align-items: center;
+		  padding: 0 30upx;
+		  height: 88upx;
+		  background-color: #fff;
+		  position: relative;
+		  text-align: center;
+		  font-size: 32upx;
+		  justify-content: space-between;
+		  border-bottom: solid 1px #eee;
+		  .w-picker-btn{
+		  	font-size: 30upx;
+		  }
+		}
+		
+		.w-picker-hd:after {
+		  content: ' ';
+		  position: absolute;
+		  left: 0;
+		  bottom: 0;
+		  right: 0;
+		  height: 1px;
+		  border-bottom: 1px solid #e5e5e5;
+		  color: #e5e5e5;
+		  transform-origin: 0 100%;
+		  transform: scaleY(0.5);
+		}
+	}
+</style>

+ 2 - 2
manifest.json

@@ -1,6 +1,6 @@
 {
     "name" : "乐色助手",
-    "appid" : "wx0ac42ab03487bbae",
+    "appid" : "__UNI__D3A9765",
     "description" : "乐色助手合作商小程序",
     "versionName" : "1.0.0",
     "versionCode" : "100",
@@ -57,7 +57,7 @@
     "quickapp" : {},
     /* 小程序特有相关 */
     "mp-weixin" : {
-        "appid" : "wx623b3d89df212494",
+        "appid" : "wx0ac42ab03487bbae",
         "setting" : {
             "urlCheck" : false,
             "es6" : true,

+ 34 - 9
pages.json

@@ -4,23 +4,24 @@
 	},
 	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
 		{
-			"path": "pages/index/index", // 首页
+			"path": "pages/login/login",
 			"style": {
-				"navigationBarTitleText": "乐色助手",
-				"enablePullDownRefresh": false
+				"navigationBarTitleText": "登录"
 			}
 		},
 		{
-			"path": "pages/login/login",
+			"path": "pages/index/index", // 首页
 			"style": {
-				"navigationBarTitleText": "登录"
+				"navigationBarTitleText": "乐色助手",
+				"enablePullDownRefresh": false
 			}
 		},
+		
 		{
 			"path": "pages/userCenter/index",
 			"style": {
 				"navigationBarTitleText": "个人中心",
-				"navigationBarBackgroundColor": "#01c9b2",
+				"navigationBarBackgroundColor": "#2ab4e5",
 				"navigationBarTextStyle": "white"
 			}
 		},
@@ -36,12 +37,36 @@
 				"navigationBarTitleText": "注意事项及服务协议"
 			}
 		},
+		{
+			"path": "pages/userCenter/leDouQuery",
+			"style": {
+				"navigationBarTitleText": "乐豆查询"
+			}
+		},
 		{
 			"path": "pages/userCenter/changePwd",		//  我的>修改密码
 			"style": {
 				"navigationBarTitleText": "修改密码"
 			}
 		}
+        ,{
+            "path" : "pages/ledouHexiao/ledouHexiao",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "乐豆核销",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/ledouHexiao/hexiaoSuccess",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "核销成功",
+                "enablePullDownRefresh": false
+            }
+            
+        }
     ],
 	"globalStyle": {
 		"navigationBarTextStyle": "black",
@@ -56,14 +81,14 @@
 	},
 	"tabBar": {
 		"color": "#7A7E83",
-		"selectedColor": "#01c9b2",
+		"selectedColor": "#2ab4e5",
 		"backgroundColor": "#ffffff",
 		"fontSize": "14px",
 		"list": [
 		{
 			"pagePath": "pages/index/index",
-			"iconPath": "static/tabbar/home.png",
-			"selectedIconPath": "static/tabbar/home-active.png",
+			"iconPath": "static/tabbar/record.png",
+			"selectedIconPath": "static/tabbar/record-active.png",
 			"text": "交易记录"
 		},
 		{

+ 83 - 295
pages/agreement/agreement.vue

@@ -1,357 +1,157 @@
 <template>
 	<view class="content">
 		<view class="page-content">
-			<view class="page-care" v-if="!hideZysx">
-				<u-image width="750rpx" height="1200rpx" mode="aspectFit" src="/static/img/zysx.png"></u-image>
-			</view>
 			<view class="page-care agreement">
-				<view class="title">-服务协议-</view>
+				<view class="title">-乐色助手商户服务协议(声明)-</view>
 				<view class="xy-cons">
 					<view class="MsoNormal">
-						欢迎您使用智能快洗!
-					</view>
-					<view class="MsoNormal">
-						<text>本《智能快洗平台用户服务协议》(以下简称</text>“本服务协议”)是您与智能快洗平台之间就登录注册智能快洗用户账号及使用智能快洗的各项服务等相关事宜所订立的协议。为更好的体验智能快洗的服务,您应当仔细阅读并遵守本服务协议下的全部内容,特别是涉及免除或者责任限制的条款,该类条款可能以黑体加粗或加下划线的形式提示您重点注意。除非您已阅读并接受本服务协议所有条款,否则您将不能注册智能快洗账号或使用智能快洗的服务,如您不同意本服务条款的任意内容,请勿注册或使用智能快洗的服务,并应立即停止注册程序。如您对本服务协议的内容(特别是涉及免除或者责任限制的条款)有任何疑义,可随时按照本服务协议中列明的联系方式与我们联系,我们将根据您的要求为您进一步解释和说明相关内容。如您点击“同意、继续服务”等并通过登录注册程序或其他任何方式使用或接受智能快洗的任何服务,即视为您已阅读并同意本服务协议,自愿接受本服务协议的所有内容的约束。请您在决定注册或使用服务前再次确认您已知悉并完全理解本服务协议的所有内容。
-					</view>
-					<view class="MsoNormal">
-						<text>如果您未满</text>18<text>周岁,请务必在家长或其他法定监护人的陪同下阅读本服务协议,并在进行注册、下单、支付等任何行为或使用智能快洗的其他任何服务前,应事先征得您的家长或其他法定监护人的同意。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>本服务协议所述</text>“服务”指您使用智能快洗用户账号接受智能快洗平台所提供的服务。无论“服务”属于上述何种情形,本《智能快洗平台用户服务协议》都将予以适用。
-					</view>
-					<view class="MsoNormal">
-						一、协议的主体与范围
-					</view>
-					<view class="MsoNormal">
-						<text>【签约主体】</text> <text>视您所使用的具体服务而定,</text>“智能快洗”是指陕西山海高科信息技术有限公司旗下运营或提供您所使用的相关具体服务的相关主体的统称,您可在相关服务的具体服务条款或说明文件中查看上述主体的名称和信息。 “用户”是指使用智能快洗相关服务的使用人,在本服务协议中更多称呼为“您”。
-					</view>
-					<view class="MsoNormal">
-						【协议内容】本服务协议内容同时包括:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)本《智能快洗平台用户服务协议》文本;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)《智能快洗平台隐私政策》:智能快洗非常重视您的个人信息和隐私的保护,将按照《智能快洗平台隐私政策》中所公布的政策在具体服务中进行隐私及个人信息的收集、存储、使用、披露等活动。您在注册智能快洗账号前,应仔细阅读《智能快洗平台隐私政策》;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)专项商品或服务规则。为更好地提升用户体验,智能快洗在若干具体专项商品或服务中特别制定了详细的规则,供各方遵守。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>4<text>)第三方服务相关的用户授权协议。为方便您在使用智能快洗平台服务的同时,根据您自身需要,通过智能快洗平台进行跳转等方式,自愿选择接受独立第三方服务商及部分关联第三方服务商所提供的服务,您将在使用该等第三方服务前对相应的用户授权协议予以同意确认,以作为您和智能快洗平台之间就该等第三方服务的使用所涉及的相关事项的权利义务依据。</text>
-					</view>
-					<view class="MsoNormal">
-						上述各项内容之间如存在不一致之处,以时间上最新发布的内容为准,发布时间相同的,以本款【协议内容】中所包含的组成部分的序号倒序排列为准。
-					</view>
-					<view class="MsoNormal">
-						【协议遵守】您理解并同意:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)上述【协议内容】中所述的协议、政策、条款与规则构成本服务协议不可分割的组成部分,共同适用于您所使用的智能快洗平台服务。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)根据国家法律法规变化、运营需要或为提升服务质量的目的,智能快洗将在必要的时候对上述各项协议、条款与规则不时地进行修改更新,并通过在网页或移动客户端上发出公告、站内信等合理、醒目的方式向您进行提前通知,上述修改更新内容将在相关更新说明中指定的日期开始实施,通常情况下不短于发布之日后八个自然日。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)您应当及时查阅并了解相关更新修改内容,如您不同意相关更新修改内容,可停止使用相关更新修改内容所涉及的服务,此情形下,变更事项对您不产生效力;如您在上述更新修改内容实施后继续使用所涉及的服务,将视为您已同意各项更新修改内容。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>【适用平台】本服务协议适用于网页端、移动客户端(包括</text>IOS<text>、安卓及已有或未来将新增的任何其他移动客户端)等各类平台或媒介中智能快洗所提供的各项服务。您知悉并理解,为享受上述相关服务,您必须自行提供相关上网设备(如:个人电脑、手机、平板电脑或其他设备)并自行负担相关网络使用和商品服务支付所产生的有关费用。</text>
-					</view>
-					<view class="MsoNormal">
-						二、账号的注册
-					</view>
-					<view class="MsoNormal">
-						【注册资料】您应遵循诚实信用、合法善意的原则,向智能快洗提交相关注册资料,相关注册资料应当遵守法律法规、社会主义制度、国家利益、公民合法权益、公序良俗、信息真实等原则,不应提交任何违法或不良信息,相关资料如有变动,您应及时更新。如果因您所提供的注册资料不合法、不真实、不准确或未及时更新,从而导致相关法律责任或不利后果的,您将承担相应的法律责任及不利后果。
-					</view>
-					<view class="MsoNormal">
-						您已知悉,在智能快洗账号注册过程中,因安全性、内部管理等原因,部分初始注册资料可能将无法再次更改。因此,您应谨慎核查此部分注册资料,确保正确填写。
-					</view>
-					<view class="MsoNormal">
-						【民事行为能力】您知悉并承诺,您具有完全民事权利能力和行为能力或虽不具有完全民事权利能力和行为能力但已经过您的家长和其他法定监护人同意并由您的家长和其他法定监护人代理注册及使用智能快洗的各项服务。若您不具备前述相适应的民事行为能力即进行账号注册的,则您及您的家长和其他法定监护人应依照法律规定承担因此而导致的一切后果。
-					</view>
-					<view class="MsoNormal">
-						【真实身份】因国家法律法规、监管要求及特定门类的服务(如金融服务等)需要,您有可能需要在注册或使用该等服务的特定环节中填写真实的身份信息,并需通过相关验证流程后方可使用服务,如您填写的身份信息不完整、不真实或未通过验证,将导致您无法使用该服务、损害自身、他人利益或造成其他不利后果,该等后果将由您予以承担。
-					</view>
-					<view class="MsoNormal">
-						【注册信息保护】智能快洗将对您所提交的注册信息予以保护,不会将其披露给任何非关联的第三方,除非:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)相关法律法规或国家机关要求;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)智能快洗发生相关合并、分立、收购或资产转移;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)为提供相关服务所必须的</text>
-					</view>
-					<view class="MsoNormal">
-						对于您所提交的注册信息中涉及个人信息的内容,智能快洗将严格按照《智能快洗平台隐私政策》的规定进行收集、处理和使用。
-					</view>
-					<view class="MsoNormal">
-						【账号数量】除因历史原因、业务整合等智能快洗所认可的特殊情况外,智能快洗原则上只允许您使用一个智能快洗用户账号。如有证据证明或智能快洗有理由相信您存在不当注册或不当使用多个智能快洗账号的情形,智能快洗可将相关账号信息进行合并或采取其他合理措施,如因您不当注册或不当使用给智能快洗及相关方造成损失的,您还应承担相应的赔偿责任。此外,出于相关业务需要,智能快洗也可对同一用户的多个账号或相关信息进行合并,如该等合并将对您的权益产生实质影响,智能快洗将在进行上述合并前事先征得您的同意。
-					</view>
-					<view class="MsoNormal">
-						三、账号的使用
-					</view>
-					<view class="MsoNormal">
-						【账号登录】您可以使用注册账号时填写登记的并获得系统审核通过的账号密码登录智能快洗洗车平台。为了您的使用便利,智能快洗未来可能将适时提供指纹识别、人脸识别等更为安全便捷的登录方式,智能快洗可根据相关法律法规、监管要求、用户体验、风险控制等因素对登录方式予以适时调整或增减,或在具体业务门类的用户服务条款等规定中予以进一步细化或调整。
-					</view>
-					<view class="MsoNormal">
-						【账号使用】您应对您账号项下的所有行为(包括但不限于在线签署任何协议,浏览、购买、支付、点评、上传、发布、输入任何内容)所产生的一切后果负责,通过您的账号所发生的上述各项行为将视为您本人的真实意思表示。
-					</view>
-					<view class="MsoNormal">
-						智能快洗提示您,您通过自身账号在接受智能快洗的各项服务中所上传、发送的任何内容都应具有合法来源,如相关内容涉及任何第三方的合法权益,应事先获得相应的许可。如智能快洗收到涉及您的相关举报或投诉,智能快洗可采取相关法律法规所要求或允许的方式,向相关争议方、相关部门提供包括账号在内的必要的信息,以便解决纠纷争议,保护正当权利人的合法权益。
-					</view>
-					<view class="MsoNormal">
-						【账号借用】为保证相关账号安全,未经智能快洗的书面同意,您不应将智能快洗平台上所注册的账号借给他人使用,否则您应当承担由此产生的全部责任,智能快洗平台保留拒绝提供相应服务、冻结或收回注册账号或终止本服务协议的权利,并可要求您对智能快洗所承受的损失予以赔偿。
-					</view>
-					<view class="MsoNormal">
-						【安全义务】如您发现账号存在安全问题,请您立即联系智能快洗予以调查处理,否则智能快洗对潜在损失的产生或扩大不承担任何责任。
-					</view>
-					<view class="MsoNormal">
-						智能快洗特别提示您,您应该妥善保管您的账号和密码,当您使用完毕智能快洗的服务后,您应安全退出。此外,您不应轻信借款、索要密码或其他涉及财产的网络信息。涉及财产操作的,请一定先核实对方身份,并请经常留意智能快洗有关防范诈骗犯罪的提示。您知悉并同意,如您在账号信息的保管上、相关上网设备的网络安全维护上存在任何过失导致账号丢失、泄露,您应对此所产生的任何后果负责,智能快洗对此不负任何责任,如智能快洗因此产生相关支出,智能快洗将有权向您予以追偿。
-					</view>
-					<view class="MsoNormal">
-						【限制冻结】您知悉并同意,在符合法律法规的规定,或经国家机关要求的前提下,智能快洗有权对您的注册账号进行限制或冻结,在该等情况下,您可能无法继续登陆或使用您的注册账号。
-					</view>
-					<view class="MsoNormal">
-						四、服务说明、用户行为规范与责任承担
-					</view>
-					<view class="MsoNormal">
-						【服务说明】您应在享受智能洗车服务的过程中应按照下列操作进行:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)您每次使用都需严格按照要求把车停到洗车机器人指定区域,可以通过洗车机器人两侧辅助镜查看,确保车辆在黄线内,车头到达绿色区域,严禁在未按要求停好车的情况下启动智能快洗洗车机器人。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>) 您应按语言提示缓慢驶入或驶离洗车机器人,保持小心安全驾驶。并按要求停车后回正方向盘、挂</text><text>P</text><text>档、拉手刹、收后视镜、关车窗、关雨刮、收天线等超长加装件,保证车辆在洗车服务中安全。</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>) 智能快洗洗车机器人仅能服务低于</text><text>2</text><text>米高的普通轿车,您不能驾驶超过高</text><text>2</text><text>米、宽</text><text>2</text><text>米、长</text><text>5.3</text><text>米的车辆和货车等特殊车辆,强行使用智能快洗洗车机器人。</text>
+						“乐色助手商户小程序”(以下简称“商户小程序”)由陕西智享亿家环保科技有限公司(以下简称“本公司”)提供。商户在登录商户小程序时,均被视为已经仔细阅读本条款并完全同意。凡以任何方式登录本商户小程序,包括但不限于接受商户小程序服务、直接或间接使用本商户小程序资料、第三方链接等,均被视为自愿接受本商户小程序相关声明和商户服务协议的约束。
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>4<text>)在智能快洗洗车机器人服务过程中,用户应始终保持车辆静止,不得移动车辆,严禁上下车或伸出窗外张望,也不能在洗车机内部走动。</text>
+						一、商户小程序使用
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>5<text>) 车龄比较老的车,因为部件老化松动等情况,清洗有可能会损坏,不建议您使用洗车机服务。</text>
+						本商户小程序之设计、信息内容等任何组成部分均不得被复制、抄袭或被任何未经本公司允许的任何商业目的所使用。若本公司怀疑或确定商户行为违法或有损本公司利益,则本公司保留采取相关法律措施的权利,包括但不限于拒绝提供服务、冻结或删除商户帐户等。
 					</view>
 					<view class="MsoNormal">
-						【用户义务】您知悉并承诺,在使用智能快洗所提供的服务的过程中,您应遵守相关法律法规,不应从事如下违反法律法规的规定,影响正常服务提供或损害他人合法利益的行为:
+						二、链接
 					</view>
+						<view class="MsoNormal">(一) 本小程序对第三方网站的链接</view>
+						<view class="MsoNormal">
+							本小程序必要时将提供第三方经营的其他网站的超级链接或指引服务,或者通过帧联及其他方式在本小程序上提供第三方网站相关内容,此“内容”包括但不限于本商户小程序上包含或可获得的任何软件、资料、音频、信息以及本小程序上提供的其他任何信息。
+						</view>
+						<view class="MsoNormal">
+							对于第三方网站的超级链接或指引服务,仅限于方便之用。本公司保留任何时段终止对第三方网站超级链接的权利。所链接的网站、网站之内容及其网站所提供的产品与服务均不受本公司的控制,因此本公司不对任何该等网站及其内容、产品或服务(包括对第三方网站的进一步链接)负责,并且不对其作出任何认可、建议、批准或介绍。若您一旦登录或使用任何所链接网站,请仔细阅读该网站免责条款,同时自行采取防护措施。由于您自行登录或使用所链接的第三方网站所产生的任何风险和损失,责任自担 ; 除非本公司另行明确规定或同意,否则,本公司将不是您和任何所链网站提供者之间达成的任何协议的当事方。
+						</view>
 					<view class="MsoNormal">
-						<text>(</text>1<text>)不应利用智能快洗平台或相关服务危害国家安全、破坏政治稳定、泄露国家秘密,不侵犯国家、社会、集体利益和第三方的合法权益,不从事违法犯罪活动,不设立用于实施诈骗,传授犯罪方法,制作或者销售违禁物品、管制物品等违法犯罪活动的网站、通讯群组,不利用网络发布涉及实施诈骗,制作或者销售违禁物品、管制物品以及其他违法犯罪活动的信息;</text>
+						本商户小程序上出现对第三方网站的链接并不表示本公司或本商户小程序与其相关联,或已获得合法授权使用,包括但不限于被链接网站中显示的或可通过其链接到的任何商标、商号、标识或著作权等
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>2<text>)不应制作、发布、复制、查阅和传播、存储、链接下列信息:反对宪法所确定的基本原则的;危害国家安全,泄露国家秘密,颠覆国家政权,推翻社会主义制度,煽动分裂国家,破坏国家统一的;损害国家荣誉和利益的;煽动民族仇恨、民族歧视,破坏民族团结的;破坏国家宗教政策,宣扬邪教和封建迷信的;煽动非法集会、结社、游行、示威、聚众扰乱社会秩序的;捏造、散布谣言,侵犯他人权利,扰乱经济、社会秩序,破坏社会稳定的;散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的;侮辱或者诽谤他人,侵害他人合法权益的;宣扬恐怖主义、极端主义的;违背当地风俗习惯的;含有法律、行政法规禁止的其他内容的;</text>
+						<view class="MsoNormal">(二) 第三方网站对本商户小程序的链接</view>
+						<view class="MsoNormal">
+							第三方网站对本商户小程序的链接,并不必然表示本公司对第三方作出了某种认可、授权、赞助,或表明其属于本公司的关联企业、合资企业、合作企业或业务伙伴。多数情况下,本公司并未意识到或授权第三方提供对本商户小程序的链接。
+						</view>
+						
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>3<text>)不应从事下列危害计算机信息网络安全的活动:对网络服务及相关软硬件设施进行破解、破坏、删除、修改或者增加的;对计算机信息网络中存储或者传输的数据和应用程序进行删除、修改或者增加的;使用软件或硬件等方式窃取他人口令、非法入侵他人计算机系统;故意制作、传播计算机病毒等破坏性程序的;其他危害计算机信息网络安全的活动;</text>
+						三、前瞻性陈述
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>4<text>)不应擅自复制和使用网络上未公开和未授权的文件。除相关著作权人明示同意,不应在网络中擅自破解、传播、下载或复制第三人享有著作权的软件或进行其他任何侵害他人知识产权的活动;</text>
+						本商户小程序可能包含某些前瞻性陈述。这类前瞻性陈述包括但不限于:关于本公司业务经营策略的陈述;关于供应链服务网络扩建计划(包括与之有关的拟作出的资本投资)的陈述;关于计划发展的供应链服务及其相关应用的陈述;关于费用变动对本公司经营业绩的预期影响的陈述;关于竞争对本公司经营业绩的影响的陈述;关于供应链行业未来发展(包括行业结构调整及政府政策的变化)的陈述;以及与本公司未来业务发展、经营及业绩有关的其他陈述。本公司在使用“预期”、“相信”、“预测”、“期望”、“打算”及其他类似词语进行陈述时,旨在表明相关陈述属于前瞻性陈述。
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>5<text>)不应私自传播广告信息或以“刷单”等不正当方式帮助他人提升评价或利用评价权利对其他用户、商户实施威胁、敲诈勒索;</text>
+						这些前瞻性陈述本质上具有相当风险和不确定性。本公司不能保证会及时或不断地更新这类前瞻性陈述。这类前瞻性陈述反映的是本公司当前状态下对未来事件的预见或规划,并不属于对未来本公司经营和业务的保证。未来本公司的实际经营和业务很有可能会因诸多客观因素而与某些前瞻性陈述有重大差异,这些因素包括但不限于:供应链行业结构的进一步调整;所需政府批准及许可条件、政策、资本投资的优先程度等监管政策的变化;行业竞争对本公司服务的需求或价格的影响;以及中国内地的政治、经济、文化、法律以及社会各方面情况的变化(包括经济增长、通货膨胀、外汇及可动用的信用额度等政策的变化)。
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>6<text>)不应因对智能快洗相关服务的使用行为导致智能快洗卷入政治和公共事件;</text>
+						此外,本公司未来往来供应链的扩建或收缩、资金投资、发展计划和规划,均取决于诸多种因素,包括但不限于是否能以可接受的条款获得足够融资;我们的发展和获得新技术及其应用的能力;是否有合格的管理及技术人员等诸多因素。
 					</view>
 					<view class="MsoNormal">
-						<text>(</text>7<text>)不应通过侵犯第三人合法权益、作弊、扰乱系统、实施网络攻击、恶意套现、刷信誉、批量注册、用机器注册智能快洗平台账户、用机器模拟客户端等手段进行交易或参加智能快洗或其所授权的第三方发布的任何活动;</text>
+						四、商户隐私权的保护
 					</view>
+						<view class="MsoNormal">(一) 商户资料的收集</view>
+						<view class="MsoNormal">
+							本商户小程序商户在匿名的状态下即可访问并获取相关信息,本商户小程序请求商户提供相关商户信息之前,本商户小程序会释明商户相关信息用途。本公司承诺仅在与本公司经营活动和经营业务有关的合法目的下,并经商户同意以合法的方式收集必要的商户信息。
+						</view>
+						<view class="MsoNormal">
+							商户使用本商户小程序需注册后方提供的服务,商户需同意以下事项:依本商户小程序注册表之提示提供商户本人真实有效、正确、完整及最新的商户信息,并保证个人信息和资料的适时更新;本企业因商户所提供的不准确、不完整或未及时更新的商户信息给商户造成的任何损害,本公司不承担任何法律和赔偿责任。本公司因商户提供的不准确、不完整或未及时更新的商户信息给本公司造成损害的,本公司保留法律追责权利。
+						</view>
+						<view class="MsoNormal">(二) 商户资料的使用</view>
+						<view class="MsoNormal">
+							本公司有权为内部业务目的使用由您提供的商户信息,这类内部业务目的包括但不限于:促进本公司业务或本公司提供给客户的服务、产品的日常管理和运营;监测本商户小程序的使用及安全情况,实施内部控制、制备数据统计、进行规划和研究等;优化设计、服务和产品;市场调研和推广;记录、核对、确认及维护商户或其他相关人员的联络名单;解决争议、排除问题和执行本法律声明;服务本公司所涉及的任何经营活动或日常业务;或与上述任何一项目的直接相关的其它目的。
+						</view>
+						<view class="MsoNormal">
+							基于以上目的,对商户信息有使用权的人,除本公司外,还包括经本公司合法授权、与本公司业务和经营活动有关的本公司的任何附属公司、联营公司、业务伙伴和专业顾问,以及向本公司提供或与本公司业务和经营活动有关的行政管理、电信服务、收付款服务、计算机信息服务或其它服务的任何代理人、承包商或第三方服务提供者。
+						</view>
+						<view class="MsoNormal">(三) 用户资料的披露</view>
+						<view class="MsoNormal">本商户小程序将采取合理有效的安全手段保护用户所提供的用户信息,在未经得用户许可前,本公司承诺并保证绝不将用户的任何个人信息和资料提供给任何无关第三方,但有下列情形之一的除外:</view>
+						<view class="MsoNormal">
+							<text>(</text>1<text>)根据法律、行政法规的规定,有权机关要求提供的。</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>2<text>)由于用户对自身信息保密不当,导致商户非公开信息泄露的。</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>3<text>)由于网络线路、黑客攻击、计算机病毒等原因造成的用户信息和资料泄露、丢失、被盗用或被篡改的。</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>4<text>)为了保护本商户小程序用户的权利或财产。</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>5<text>)在紧急的情况下,为了保护本商户小程序及其用户本人或公众安全的。</text>
+						</view>
+						<view class="MsoNormal">
+							<text>(</text>6<text>)其他特殊或紧急情况。</text>
+						</view>
 					<view class="MsoNormal">
-						<text>(</text>8<text>)未经智能快洗事先书面许可,不应自行或授权、协助任何第三方非法抓取智能快洗所展示的任何内容(“非法抓取”是指采用未经智能快洗认可的程序或者非正常浏览等技术手段获取内容数据的行为)。</text>
+						五、知识产权保护
 					</view>
 					<view class="MsoNormal">
-						【责任承担】如您在使用智能快洗服务过程中涉及违反服务说明或违反用户义务中的一项或多项,则需要对自己的行为承担法律责任。承担法律责任的形式包括但不限于:造成的损失由您自己承担,对受到侵害者(包括智能快洗)进行赔偿。特别的,若您违反用户义务导致智能快洗承担了因您的行为导致的行政处罚或侵权损害赔偿责任等损失(含诉讼费、律师费等相关法律程序费用)后,您还应立即给予智能快洗等额的赔偿。此外,根据具体违法违规情形,智能快洗有权作出独立判断,立即暂停或终止对您提供部分或全部服务,包括锁定、注销、删除帐号等措施。
+						本商户小程序所载述的域名、商标、商号、信息、文字、图形、图像、声音、链接、软件及所有其它内容或组成部分均由本公司、内容或组成部分提供商或第三方许可人提供。上述内容的知识产权依具体情况分别为本公司、内容或组成部分提供商或第三方许可人所拥有。
 					</view>
 					<view class="MsoNormal">
-						您知悉并理解,如果智能快洗发现您的上述违法违规行为,依据相关法律法规的规定,智能快洗有权或有义务立即停止相关服务,删除或屏蔽相关违规信息、服务评价,并视情况进行调查取证,保存有关记录,或向国家有关机关举报。同时,智能快洗有权自主删除、屏蔽含有该内容的任何数据信息。智能快洗将根据国家相关法律法规要求,对依法删除、屏蔽的数据信息予以记录、保存。
+						未经本公司或商标权人事先书面许可,任何单位或个人不得以任何方式或理由对本商户小程序的商标、商号或标识的任何部分进行使用、复制、修改、传播或与其它产品捆绑使用。
 					</view>
 					<view class="MsoNormal">
-						【广告促销】您理解并同意:为向您提供更为细致、贴心的服务,在经过您的事先确认后,智能快洗或智能快洗授权、认可的第三方商家、广告商可能通过您注册时填写的手机号码或者电子邮箱向您发送您可能感兴趣的商品服务的广告宣传信息、促销优惠等商业性信息,其方式和范围可不经向您特别通知而变更;如果您不愿意接收此类信息,则您有权通过智能快洗平台提供的相应的退订方式进行退订。
+						除法律另有规定或双方另有约定外,未经本公司和/或其他权利人事先书面许可,任何人不得以任何形式通过任何方式(包括但不限于电子、机械复印或录制等方式)复制、展示、修改、转让、分发、重新发布、下载、张贴或传输本商户小程序的内容。
 					</view>
 					<view class="MsoNormal">
-						您理解并同意,对上述的相关广告信息,您应审慎判断其真实性和可靠性,除法律法规明确规定外,您应对依该广告信息进行的交易负责。
+						六、免责声明
 					</view>
 					<view class="MsoNormal">
-						【使用目的】除非在特定服务条款或规则中您与智能快洗另有约定或智能快洗另行予以书面同意,您将确保本服务协议下的服务仅为您个人非商业性质的使用。未经智能快洗书面同意,您不得使用未经智能快洗授权的任何插件、外挂或第三方工具对本服务协议下的服务进行干扰、破坏、修改或施加其他影响。
+						本商户小程序所提供的信息,仅供参考之用,不宜用于任何研究或商业用途。本商户小程序并不保证该等信息的准确性、有效性、及时性或完整性。本公司及其员工无需以任何方式就任何信息传递或传送的失误、不准确或错误对商户或任何其他人士负任何直接或间接责任。在法律和本商户小程序允许的范围内,本公司不承担商户或任何第三方就使用或未能使用本商户小程序所提供的信息或任何链接所引致的任何直接、间接的损害赔偿(包括但不限于收益、预期利润的损失或失去的业务、未实现预期的节减)。本公司保留自行决定及修改、更正本商户小程序中任何内容和组成部分的权利(包括任何遗漏或错误的信息和内容)。本公司可以在任何时间对本商户小程序、本商户小程序上所描述的内容、产品、项目、服务或价格作出任何修改,而无需事前通知和事后说明,有需要的情况除外。
 					</view>
 					<view class="MsoNormal">
-						五、知识产权
+						本商户小程序、本商户小程序所述的内容、信息和材料以及在本商户小程序上可获得的软件等均“依原样”提供,不包含任何明示或暗示性质的陈述或保证。在法律许可或不禁止范围内,本公司承诺不作出任何明示或暗示性质的陈述和保证,包括但不限于有关安全性、准确性、完整性、适销性、无侵权、适合某项特别目的或没有计算机病毒的保证。您应为使用本商户小程序承担全部责任和风险。
 					</view>
+					<view class="MsoNormal">如发生以下情况,本商户小程序不对用户的直接或间接损失承担法律责任:</view>
 					<view class="MsoNormal">
-						【知识产权】您理解并知悉,除另有书面声明以外,以下信息和内容的知识产权(包括但不限于专利权、著作权、商标权及商业秘密)归智能快洗所有:
+						<text>(</text>1<text>)营业中断。</text>
 					</view>
 					<view class="MsoNormal">
-						1. <text>在智能快洗相关服务中所提供的内容和信息(包括但不限于软件、技术、程序、网页、文字、图片、图像、地图、图标、音频、视频、图表、版面设计、电子文档、数据资料等);</text>
+						<text>(</text>2<text>)无法登录本商户小程序,或登录本商户小程序延迟或中断。</text>
 					</view>
 					<view class="MsoNormal">
-						2. <text>智能快洗用于提供上述内容和信息的基础设施和平台(包括但不限于软件、网站、应用程序等);</text>
+						<text>(</text>3<text>)数据无法传送、错误传送、毁损、灭失或其他修改。</text>
 					</view>
 					<view class="MsoNormal">
-						3. <text>在智能快洗提供相关服务中所使用的各项商标、商业形象、商业标识、技术诀窍、标语、文案等;</text>
+						<text>(</text>4<text>)因处理本商户小程序上对其它用户小程序的链接或本商户小程序上存在对其它用户小程序的链接所遭受的任何种类的损失或损害。</text>
 					</view>
 					<view class="MsoNormal">
-						4. <text>智能快洗平台服务的开发、运营、维护等过程中产生的所有数据和信息。</text>
+						<text>(</text>5<text>)就客户使用本商户小程序(包括链接到第三方小程序或自第三方小程序链接)而可能产生的计算机病毒、系统失灵或功能紊乱。</text>
 					</view>
 					<view class="MsoNormal">
-						智能快洗所拥有的上述权利及所提供服务中所包含的任何内容的知识产权均受到法律保护,未经智能快洗事先书面许可,您承诺不应且不应允许或协助任何人以任何形式(包括但不限于通过任何机器人、蜘蛛、截屏等程序或设备)进行使用、出租、出借、分发、展示、复制、修改、链接、转载、汇编、发表、出版、抓取、监视、引用或创造相关衍生作品。
+						<text>(</text>6<text>)本法律声明第四条第三项中规定的六种情形所引起的商户个人资料的披露或泄露。</text>
 					</view>
 					<view class="MsoNormal">
-						【用户生成内容】您理解并同意,您在使用智能快洗提供的服务时上传、提交、存储或发布的内容(包括但不限于文字、图片、视频、音频、动画等)均由您原创或已获合法授权。您通过智能快洗上传、提交、存储或发布的任何内容的知识产权归属您或原始著作权人所有,您的上传、提交、存储或发布行为不会侵犯他人的知识产权或其他合法权益。
+						<text>(</text>7<text>)因不可抗力或本公司无法合理控制的其他原因所导致的用户损失。</text>
 					</view>
 					<view class="MsoNormal">
-						您知悉、理解并同意,您一旦接受本服务协议,即表明您主动将上述内容的非专属、可转让的财产性权利,如著作权(包括但不限于:复制权、发行权、出租权、展览权、表演权、放映权、广播权、信息网络传播权、摄制权、改编权、翻译权、汇编权以及应当由著作权人享有的其他可转让权利),在全世界范围内永久、免费、独家且不可撤销地授权给智能快洗及其关联公司,智能快洗及其关联公司可基于该等授权使用上述内容(包括但不限于用于商业用途)或向第三方自主进行任何必要的转授权。该等授权、转授权的使用场景包括但不限于当前或其他任何网站、应用程序、产品或移动终端设备等,且智能快洗及其关联公司或智能快洗及其关联公司所授权许可的第三方可通过对上述授权内容进行修改、复制、改编、翻译、汇编或制作,形成衍生产品。在不违反相关法律法规的强制性规定、尊重相关原始授权内容的知识产权的基础上,该等衍生产品的相关知识产权归智能快洗及其关联公司或智能快洗所授权许可的第三方所有。
+						七、服务变更、暂停、中断或终止
 					</view>
 					<view class="MsoNormal">
-						您确认并同意授权智能快洗及其关联公司以自己的名义或委托专业第三方针对有关您上传、提交、存储或发布的内容(含衍生作品)的侵权行为进行独立自主的维权并获得全部赔偿。维权形式包括但不限于:监测侵权行为、发送维权函、提起诉讼或仲裁、调解、和解等。智能快洗及其关联公司有权对维权事宜做出独立决策并予以实施
+						如因系统升级或维护需要而暂停本商户小程序网络服务时,本商户小程序将尽可能事先通告
 					</view>
 					<view class="MsoNormal">
-						您同意,因您通过智能快洗上传、发布的任何内容导致的知识产权侵权问题,您将承担全部责任;如智能快洗及其关联公司,或智能快洗授权的其他服务提供方因第三方知识产权维权而产生损失,您将等额赔偿
+						如发生下列情形之一,本商户小程序有权随时暂停、中断或终止向用户提供本商户小程序商户服务而无需通知,并有权拒绝商户于当前、未来某时段或永久使用本商户小程序所提供服务之全部或任何部分:(1)用户提供任何错误、不实、过时、不完整或具有误导性的信息和资料,或本商户小程序有理由或有依据怀疑前述信息和资料为错误、不实、过时、不完整或具误导性的;(2)用户违反本法律声明或相关使用协议中规定的任何使用规则。
 					</view>
 					<view class="MsoNormal">
-						&nbsp;
+						除上述情形外,本商户小程序同时保留在不事先通知商户的情况下随时暂停、中断或终止部分或全部网络服务的权利,对于所有服务的暂停、中断或终止而造成的任何损失,除法律另有规定或双方另有约定外,本公司不对用户或任何第三方承担任何法律责任。
 					</view>
 					<view class="MsoNormal">
-						本服务协议已经构成《著作权法》第二十五条所规定的书面协议,其效力及于用户在智能快洗平台发布的任何受著作权法保护的作品内容,无论该内容形成于本服务协议签订前还是本服务协议签订后。智能快洗及智能快洗转授权、许可的相关方有权将您在智能快洗平台发表的产品使用体验、产品讨论或图片进行使用或者与其他人合作使用,使用范围包括但不限于网站、电子杂志、杂志、刊物、海报、公众号文章、微信小程序等。
+						八、条款修改
 					</view>
 					<view class="MsoNormal">
-						【软件使用】在使用智能快洗相关客户端的过程中,您可能需要下载特定软件。为了改善用户体验、修复漏洞、保障安全性等考虑,智能快洗有权对软件进行更新,您应该将相关软件更新至最新版本,否则智能快洗将不保证您能正常使用相关软件
+						本公司保留在任何时间自行修改、增删本法律声明中的任何内容和条款的权利。您每次登录或使用本商户小程序时,均视为同意接受当时已生效的商户声明条款的制约。因此,建议您每次登录或使用本商户小程序时查看本法律声明是否修订或增删及修订或增删的情况
 					</view>
 					<view class="MsoNormal">
-						如果您从未经智能快洗授权的第三方获取软件或与该软件名称相同的安装程序,智能快洗无法保证该软件能够正常使用,由此造成的相关损失,智能快洗不予负责。
+						九、法律适用与司法管辖
 					</view>
 					<view class="MsoNormal">
-						【软件使用禁止性规定】除非智能快洗书面许可,您在使用智能快洗的软件时不得从事下列任一行为:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)删除、编辑或遮挡软件及其副本上关于著作权、商标或其他权利标识或标记的信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)复制、发布、出售或出租软件或其任何部分;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)对软件进行反向工程、反向汇编、反向编译,或者以其他方式尝试挖掘、提取软件的源代码;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>4<text>)其他对软件、软件所产生的数据所进行的任何增加、删减、变动的任何行为,包含制作、利用、授权各种第三方外挂、插件、系统进行上述行为。</text>
-					</view>
-					<view class="MsoNormal">
-						六、协议的终止
-					</view>
-					<view class="MsoNormal">
-						【协议终止情形】本服务协议于以下任一情形下终止:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)智能快洗有权依据本服务协议约定,收回、注销用户账号,此情形下,本服务协议于账号收回、注销之日终止;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)在满足智能快洗平台公示的账号注销条件时,您通过网站自助服务或智能快洗的客服注销智能快洗的用户账号,本服务协议于账号注销之日终止。您理解并同意,您已认真阅读、认可《智能快洗隐私政策》,并已了解、同意相关用户注销流程及注销后的权利义务安排;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)智能快洗有权根据自身商业安排经过合理的提前通知终止全部智能快洗平台服务,本服务协议于智能快洗平台全部服务依法定程序及方式终止之日终止。</text>
-					</view>
-					<view class="MsoNormal">
-						本服务协议终止后,智能快洗将无法继续向您提供任何服务或履行任何其他义务,包括但不限于为您保留或向您披露其原智能快洗账号中的任何信息,向您或第三方转发任何未曾阅读或发送过的信息等。
-					</view>
-					<view class="MsoNormal">
-						<text>本服务协议的终止不影响第五条知识产权条款以及其他根据其内容应继续有效</text> <text>的条款的有效性,也不影响本服务协议终止前各方的相关权利和义务,包括但不</text> <text>限于守约方依据本服务协议向违约方追究相应的违约责任。</text>
-					</view>
-					<view class="MsoNormal">
-						七、通知与送达
-					</view>
-					<view class="MsoNormal">
-						您知悉并认可,智能快洗可视情况通过下列任意一种或几种方式向您通知重要信息:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)向您注册时所提交的电子邮箱地址发送电子信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)向您注册时所提交的手机号码发送电子信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)向您提供的实际地址进行寄送纸质载体信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>4<text>)在网站或客户端显著位置刊登电子信息;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>5<text>)向智能快洗网站或相应客户端的账户的站内信或其他即时通信客户端发送电子信息。</text>
-					</view>
-					<view class="MsoNormal">
-						上述电子信息在发送成功或刊登完成后即视为送达。相关纸质载体的发送以相关邮寄凭证上的邮寄日期后的第五个自然日视为送达。
-					</view>
-					<view class="MsoNormal">
-						上述送达方式同样可适用于相关仲裁或司法程序(含起诉、审理、执行等各阶段)。
-					</view>
-					<view class="MsoNormal">
-						您应当保证所提供的联系方式是准确、有效的,并进行适时更新,如因提供的联系方式不准确或怠于更新等不可归责于智能快洗的原因,导致相关通知、文件、文书无法送达或及时送达,您将自行承担由此可能产生的法律后果。
-					</view>
-					<view class="MsoNormal">
-						八、不可抗力或其他免责事由
-					</view>
-					<view class="MsoNormal">
-						【不可抗力】您理解并同意,在使用本服务的过程中,可能会遇到不可抗力等风险因素,使本服务协议下的服务发生中断或终止。不可抗力是指不能预见、不能克服并不能避免且对一方或双方造成重大影响的客观事件,包括但不限于信息网络设备维护、信息网络连接故障、电脑、通讯或其他系统的故障、电力故障、罢工、劳动争议、暴乱、起义、骚乱、生产力或生产资料不足、火灾、洪水、风暴、爆炸、战争、政府行为、法律法规变动、司法行政机关的命令、其他不可抗力或第三方的不作为而造成的不能服务或延迟服务等行为。出现上述情况时,智能快洗将努力在第一时间与相关部门配合,及时进行修复,但是由此给您造成的损失,智能快洗在法律允许的范围内免责。
-					</view>
-					<view class="MsoNormal">
-						【其他免责事由】您理解并同意,在法律允许的范围内,智能快洗对以下事由所导致的服务中断或终止不承担责任:
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>1<text>)受到计算机病毒、木马或其他恶意程序、黑客攻击的破坏;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>2<text>)用户或智能快洗的电脑软件、系统、硬件和通信线路出现故障;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>3<text>)用户操作不当;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>4<text>)用户通过非智能快洗授权的方式使用本服务;</text>
-					</view>
-					<view class="MsoNormal">
-						<text>(</text>5<text>)其他智能快洗无法控制或合理预见的情形。</text>
-					</view>
-					<view class="MsoNormal">
-						【信息真实性】智能快洗提示您,在使用本服务的过程中,您可能会遇到网络信息或其他用户行为带来的风险,该等风险包含他人匿名或冒名的含有威胁、诽谤、令人反感、非法、误导、欺骗等任何信息或行为所造成任何心理、生理上的伤害或经济损失。请您仔细甄别,并在遇到上述相关不法行为时及时向智能快洗或有关机关举报或投诉。智能快洗将对相关内容开展日常检查并在收到举报或投诉时进行相应处理,但请您注意,智能快洗不对非智能快洗所发出或刊登的任何信息的真实性、适用性、合法性承担责任,也不对因第三方侵权行为给您造成的损害负责。
-					</view>
-					<view class="MsoNormal">
-						【责任限制】除非另有明确书面说明,在符合法律法规规定的情况下,智能快洗不对其网站和客户端上的信息、内容、材料、产品或服务做任何形式的明示或默示的声明或担保。
-					</view>
-					<view class="MsoNormal">
-						九、管辖、法律适用与争议解决
-					</view>
-					<view class="MsoNormal">
-						本服务协议的成立、生效、履行、解释与纠纷解决,适用中华人民共和国大陆地区法律法规,并且排除一切冲突法规定的适用。
-					</view>
-					<view class="MsoNormal">
-						如因某项具体服务中的产品或服务问题导致您与智能快洗间出现纠纷,您同意,该等纠纷将由适用于该项具体服务的服务条款或规则中所规定的争议解决地的有管辖权人民法院受理。就本服务协议而言,如您因本服务协议文本与智能快洗产生争议纠纷,您同意交由本服务协议签订地有管辖权人民法院受理。本服务协议签订地为上海市杨浦区。
-					</view>
-					<view class="MsoNormal">
-						十、其他
-					</view>
-					<view class="MsoNormal">
-						【关键词】本服务协议各条款前所列关键词仅供帮助理解条款主旨及快速定位查询条款所用,不能代替条款的任何内容,亦不作为解释条款的依据,智能快洗建议您仔细阅读各条款的具体表述,以维护您的合法权益。
-					</view>
-					<view class="MsoNormal">
-						【可分性】如果本服务协议中任何一条被视为废止、无效或因任何理由不可执行,该条应视为可分的且并不影响任何其余条款的有效性和可执行性。
-					</view>
-					<view class="MsoNormal">
-						再次感谢您的耐心阅读!
-					</view>
-					<view style="text-align: right;">
-						陕西山海高科信息技术有限公司
-					</view>
-					<view style="text-align: right;">
-						2020年8月
+						本法律声明的制定、执行、解释及争议问题的解决和处理均适用中华人民共和国法律、法规。双方因使用本商户小程序所产生的争议,若协商不成,任何一方可向本公司所在地人民法院提起诉讼。
 					</view>
 				</view>
 			</view>
 		</view>
-		<view class="footer" @click="goBack" v-if="!hideZysx">
-			我已阅读并同意无人洗车《注意事项及服务协议》
-		</view>
 	</view>
 </template>
 
@@ -361,26 +161,14 @@
 		},
 		data() {
 			return {
-				hideZysx: false
 			}
 		},
 		onLoad(option) {
-			// 从个人中心打开的
-			if(option.fromPage == 'usercenter'){
-				this.hideZysx = true
-				uni.setNavigationBarTitle({
-					title: "服务协议"
-				})
-			}
+			uni.setNavigationBarTitle({
+				title: "服务协议"
+			})
 		},
 		methods: {
-			// 点击已阅读返回上一页
-			goBack () {
-				// 出发已阅读事件
-				uni.$emit('read',{msg:'read'})
-				uni.navigateBack()
-			}
-			
 		}
 	}
 </script>

+ 228 - 128
pages/index/index.vue

@@ -1,22 +1,45 @@
 <template>
 	<view class="homePage-container">
-		<!-- 筛选菜单 -->
-		<u-dropdown ref="uDropdown" class="filter-dropdown">
-			<u-dropdown-item v-model="queryParam.recordType" :title="titType" :options="optionsType" @change="searchHandle(1)"></u-dropdown-item>
-			<u-dropdown-item v-model="queryParam.recordScope" :title="titScope" :options="optionsScope" @change="searchHandle(1)"></u-dropdown-item>
-		</u-dropdown>
-		<scroll-view class="scroll-con" scroll-y @scrolltolower="onreachBottom">
+		<!-- 筛选弹框 -->
+		<search-modal v-if="openScreen" :visible="openScreen" :defaultParams="searchForm" @refresh="refresh" @close="openScreen=false"></search-modal>
+		<view class="homePage-head">
+			<view class="head-con">
+				<text class="homePage-tit">交易记录</text>
+				<view class="total-con">
+					总计:
+					<text class="goleNum">{{ldTotal}}</text>
+					<image src="/static/ledou.png" class="ld-icon"></image>
+				</view>
+			</view>
+			<image class="filter-icon" src="@/static/filter.png" @tap="openScreen=true"></image>
+		</view>
+		<scroll-view class="scroll-con" scroll-y :scroll-top="scrollTop" @scrolltolower="onreachBottom">
 			<!-- 列表数据 -->
 			<view class="cell-item-con">
 				<view class="cell-item" v-for="(item, index) in listdata" :key="index">
-					<text class="cell-item-month">{{item.month}}</text>
-					<view class="cell-item-main" v-for="(subItem, ind) in item.list" :key="ind">
-						<text :class="['cell-item-pic', subItem.type == 1?'orange':'']">{{subItem.type == 1 ? '收' : '支'}}</text>
-						<view class="cell-item-c">
-							<text class="cell-item-des">{{subItem.dec}}</text>
-							<text class="cell-item-date">{{subItem.creatDate}}</text>
+					<view class="cell-item-c">
+						<view class="cell-item-label">交易时间</view>
+						<view class="cell-item-main">{{item.createDate}}</view>
+					</view>
+					<view class="cell-item-c">
+						<view class="cell-item-label">支付账户</view>
+						<view class="cell-item-main">{{item.customerMobile}}</view>
+					</view>
+					<view class="cell-item-c">
+						<view class="cell-item-label">交易数量(个)</view>
+						<view :class="['cell-item-main', item.changeType=='ADD' ? 'red' : 'blue']">{{item.changeType=='ADD' ? '+' : item.changeType=='SUB' ? '-' : ''}}{{ item.changeNum }}</view>
+					</view>
+					<view class="cell-item-c">
+						<view class="cell-item-label">备注</view>
+						<view class="cell-item-main">{{item.remarks ? item.remarks : '--'}}</view>
+					</view>
+					<view class="cell-item-c handle-con">
+						<view class="cell-item-label">操作</view>
+						<view class="cell-item-main">
+							<u-button size="mini" v-if="item.changeType=='ADD' && item.cancelFlag==0" class="handle-btn" hover-class="none" :custom-style="customBtnStyle" @click="revokeFun(item)">撤销单据</u-button>
+							<text v-if="item.changeType=='ADD' && item.cancelFlag==1" style="color: #909399;">单据已撤销</text>
+							<text v-if="item.changeType=='SUB'" style="color: #909399;">扫码支付撤销</text>
 						</view>
-						<text :class="['cell-item-score', Number(subItem.score) > 0 ? 'red' : 'black']">{{Number(subItem.score)>0 ? '+'+subItem.score : subItem.score}}</text>
 					</view>
 				</view>
 			</view>
@@ -25,97 +48,127 @@
 				<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
 			</view>
 		</scroll-view>
+		
+		<view class="footer-bar">
+			<u-button shape="circle" @click="openQuery" size="medium" type="primary">用户乐豆查询/核销</u-button>
+		</view>
 	</view>
 </template>
-
 <script>
+	import searchModal from './searchModal.vue'
+	import { getUserInfo } from '@/api/user.js'
+	import { getGoldLogList, GoldLogCancel, GoldLogTotal } from '@/api/officialPartnerGoldLog.js'
 	export default {
+		components: { searchModal },
 		data() {
 			return {
-				listdata: [
-					{
-						month: '本月',
-						list: [
-							{ type: 1, dec: '投递可回收物获得乐豆', creatDate: '2020-11-04 14:08', score: +25 },
-							{ type: 2, dec: '投递可回收物获得乐豆', creatDate: '2020-11-04 14:08', score: -30 },
-							{ type: 3, dec: '投递可回收物获得乐豆', creatDate: '2020-11-04 14:08', score: -15 },
-						]
-					},
-					{
-						month: '10月',
-						list: [
-							{ type: 1, dec: '投递可回收物获得乐豆', creatDate: '2020-11-04 14:08', score: +25 },
-							{ type: 2, dec: '投递可回收物获得乐豆', creatDate: '2020-11-04 14:08', score: -30 },
-							{ type: 3, dec: '投递可回收物获得乐豆', creatDate: '2020-11-04 14:08', score: -15 },
-						]
-					}
-				],
+				listdata: [],
 				pageNo: 1,  //  当前页码
 				pageSize: 10,  //  每页条数
 				total: 0,  //  数据总条数
 				noDataText: '暂无数据',  //  列表请求状态提示语
 				status: 'loadmore',  //  加载中状态
-				queryParam: {  //  过滤条件
-					recordType: '',
-					recordScope: ''
+				openScreen: false,  //  是否打开筛选
+				searchForm: {  //  查询条件
+					beginDate: '',  //  创建时间默认筛选近7天
+					endDate: '',  //  创建时间默认筛选近7天
+					customerMobile: ''  //  支付账户
+				},
+				customBtnStyle: {  //  撤销单据  自定义按钮样式
+					borderColor: '#2ab4e5',
+					backgroundColor: '#2ab4e5',
+					color: '#fff'
 				},
-				optionsType: [
-					{ label: '所有记录', value: 1, },
-					{ label: '获取记录', value: 2, },
-					{ label: '使用记录', value: 3, }
-				]
+				scrollTop: 0,  //  滚动条位置
+				ldTotal: 0  //  乐豆总计数
 			}
 		},
 		onShow() {
-			this.searchHandle(1)
+			this.openScreen = false  //  关闭筛选框
+			this.refresh({})
+			this.getUserInfo()
 		},
-		onLoad() {
-			
-		},
-		computed: {
-			optionsScope(){  //  过滤条件  近3个月
-				let arr = [
-					{ label: '近3个月', value: 1 },
-					{ label: '本月', value: 2 }
-				]
-				arr[2] = { label: new Date().getMonth() + '月', value: 3 }
-				arr[3] = { label: new Date().getMonth()-1 + '月', value: 4 }
-				return arr
+		methods:{
+			//  获取用户信息
+			getUserInfo(){
+				getUserInfo().then(res => {
+					if(res.status == 200){
+						this.$u.vuex('vuex_userData', res.data);
+					}
+				})
 			},
-			titType(){  //  过滤条件 所有记录 title
-				const row = this.optionsType.find(item => item.value == this.queryParam.recordType)
-				return row ? row.label : this.optionsType[0].label
+			openQuery(){
+				uni.navigateTo({
+					url: "/pages/userCenter/leDouQuery"
+				})
+			},
+			//  总计
+			getGoldLogTotal(){
+				GoldLogTotal({
+					beginDate: this.searchForm.beginDate,
+					endDate: this.searchForm.endDate,
+					customerMobile: this.searchForm.customerMobile
+				}).then(res => {
+					if(res.status == 200){
+						this.ldTotal = res.data ? res.data.changeNum : 0
+					}else{
+						this.ldTotal = 0
+					}
+				})
+			},
+			// 获取查询参数 刷新列表
+			refresh(params){
+				this.searchForm = params
+				this.listdata = []
+				this.total = 0
+				this.searchHandle(1)
+				this.getGoldLogTotal()
+			},
+			//  撤销单据
+			revokeFun(row){
+				const _this = this
+				uni.showModal({
+				  title: '提示',
+				  content: '撤销单据后乐豆将全部退回给原支付账号,确认撤销吗?',
+				  success(res) {
+				    if (res.confirm) {
+				      GoldLogCancel({ id: row.id }).then(ret => {
+						  if(ret.status == 200){
+							  uni.showToast({ title: ret.message, icon: 'none' })
+							  _this.searchHandle(1)
+						  }
+					  })
+				    }
+				  }
+				})
 			},
-			titScope(){  //  过滤条件 近3个月 title
-				const row = this.optionsScope.find(item => item.value == this.queryParam.recordScope)
-				return row ? row.label : this.optionsScope[0].label
-			}
-		},
-		methods:{
 			// 搜索查询
 			searchHandle (pageNo) {
 				this.status = "loading"
 				pageNo ? this.pageNo = pageNo : null
-				// searchSuppliers({
-				// 	pageNo: this.pageNo,
-				// 	pageSize: this.pageSize,
-				// 	queryWord: this.queryValue
-				// }).then(res => {
-				// 	if (res.status == 200) {
-				// 		if(this.pageNo>1){
-				// 			this.listdata = this.listdata.concat(res.data.list || [])
-				// 		}else{
-				// 			this.listdata = res.data.list || []
-				// 		}
-				// 		this.total = res.data.count || 0
-				// 		this.listdata.length == 0 && this.queryValue != '' ? this.noDataText = '没有搜索到相关结果' : this.noDataText = '暂无数据'
-				// 	} else {
-				// 		this.noDataText = res.message
-				// 		this.listdata = []
-				// 		this.total = 0
-				// 	}
+				getGoldLogList({
+					pageNo: this.pageNo,
+					pageSize: this.pageSize,
+					beginDate: this.searchForm.beginDate,
+					endDate: this.searchForm.endDate,
+					customerMobile: this.searchForm.customerMobile
+				}).then(res => {
+					if (res.status == 200) {
+						if(this.pageNo>1){
+							this.listdata = this.listdata.concat(res.data.list || [])
+						}else{
+							this.listdata = res.data.list || []
+							this.scrollTop = 0
+						}
+						this.total = res.data.count || 0
+						this.noDataText = '暂无数据'
+					} else {
+						this.noDataText = res.message
+						this.listdata = []
+						this.total = 0
+					}
 					this.status = "loadmore"
-				// })
+				})
 			},
 			// scroll-view到底部加载更多
 			onreachBottom() {
@@ -132,80 +185,127 @@
 </script>
 
 <style lang="scss">
+	page{
+		height: 100%;
+	}
 	.homePage-container {
 		width: 100%;
+		height: 100%;
+		display: flex;
+		flex-direction: column;
+		padding: 102rpx 0;
+		.footer-bar{
+			width: 100%;
+			display: flex;
+			align-items: center;
+			height: 102rpx;
+			justify-content: center;
+			padding: 0 10%;
+			position: fixed;
+			bottom: 0;
+			left: 0;
+		}
 		// 筛选菜单
-		.filter-dropdown{
-			background-color: #fff!important;
-			.u-dropdown__menu__item{
-				background-color: #fff!important;
+		.homePage-head{
+			font-size: 30rpx;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			position: fixed;
+			top: 0;
+			left: 0;
+			z-index: 9;
+			padding: 26rpx 30rpx;
+			background-color: #fff;
+			box-shadow: 0rpx 0rpx 14rpx rgba(0,0,0,.05);
+			width: 100%;
+			border-top: 10rpx solid #f8f8f8;
+			.head-con{
+				flex-grow: 1;
+				display: flex;
+				align-items: center;
+				justify-content: space-between;
+				.homePage-tit{
+					color: #040301;
+				}
+				.total-con{
+					color: #040301;
+					.goleNum{
+						color: #eb0000;
+						font-size: 30rpx;
+						font-weight: bold;
+					}
+					.ld-icon{
+						width: 30rpx;
+						height: 30rpx;
+						margin: 0 0 0 10rpx;
+						vertical-align: middle;
+					}
+				}
+			}
+			.filter-icon{
+				flex-shrink: 0;
+				width: 36rpx;
+				height: 36rpx;
+				padding-left: 20rpx;
 			}
 		}
 		//  列表
 		.scroll-con{
-			height: calc(100% - 40);
+			flex: 1;
+			// height: calc(100% - 40);
 			overflow: auto;
 		}
 		//  列表样式
 		.cell-item-con{
+			margin: 20rpx;
 			.cell-item{
 				background-color: #fff;
 				color: #606266;
-				.cell-item-month{
-					display: block;
-					color: #909399;
-					font-size: 26rpx;
-					padding: 16rpx 30rpx;
-					background-color: #f8f8f8;
-				}
-				.cell-item-main{
+				padding: 0 30rpx;
+				margin-bottom: 20rpx;
+				border-radius: 16rpx;
+				font-size: 28rpx;
+				box-shadow: 3rpx 3rpx 5rpx #eee;
+				.cell-item-c{
 					display: flex;
-					align-items: center;
-					margin: 0 30rpx;
-					padding: 20rpx 0;
-					border-bottom: 1rpx solid #e9e9e9;
-					.cell-item-pic{
+					justify-content: space-between;
+					padding: 18rpx 0;
+					border-bottom: 1rpx solid #f2f2f2;
+					.cell-item-label{
 						flex-shrink: 0;
-						margin-right: 20rpx;
-						width: 90rpx;
-						height: 90rpx;
-						line-height: 90rpx;
-						background-color: #f3f4f6;
-						border-radius: 50%;
-						text-align: center;
+						width: 200rpx;
+						color: #303133;
 					}
-					.cell-item-c{
+					.cell-item-main{
 						flex-grow: 1;
-						.cell-item-des{
-							display: block;
-							color: #606266;
-							font-size: 26rpx;
-							margin-bottom: 18rpx;
-						}
-						.cell-item-date{
-							display: block;
-							color: #909399;
-							font-size: 24rpx;
+						text-align: right;
+						.handle-btn{
+							border-color: #fcbd71!important;
+							background-color: #fcbd71!important;
 						}
 					}
-					.cell-item-score{
-						flex-shrink: 0;
+					.blue {
+						color: #1890FF;
 					}
-					.black{
-						color: #000;
+					.green {
+						color: #16b50e;
 					}
-					.red{
-						color: #fa3534;
+					.red {
+						color: red;
 					}
-					.orange{
-						background-color: #fcbd71;
-						color: #fff;
+					&:last-child{
+						border: none;
 					}
 				}
-				.cell-item-main:last-child{
-					border: none;
+				.handle-con{
+					align-items: center;
+					// margin-top: 10rpx;
+					// padding-top: 18rpx;
+					// padding: 0;
 				}
 			}
 		}
+		
 	}
 </style>

+ 197 - 0
pages/index/searchModal.vue

@@ -0,0 +1,197 @@
+<template>
+	<!-- 待办单查询 -->
+	<div class="modal-content">
+		<u-popup v-model="isShow" class="search-popup" mode="right" @close="handleClose" length="85%">
+			<view class="search-title">筛选</view>
+			<u-form class="form-content" :model="form" ref="uForm" label-width="150">
+				<u-form-item label="支付时间" prop="time" class="form-item">
+					<u-input clearable v-model="form.time" disabled placeholder="请选择支付时间区间" class="form-item-inp" @click="openPicker" />
+					<u-icon v-show="form.time.length != 0" name="close-circle-fill" color="#c8c0cc" size="32" class="close-circle" @click="clearTime"></u-icon>
+				</u-form-item>
+				<u-form-item label="支付账号" prop="customerMobile" class="form-item"><u-input v-model="form.customerMobile" :maxlength="11" placeholder="请输入支付账号" /></u-form-item>
+			</u-form>
+			<view class="uni-list-btns">
+				<u-button class="handle-btn search-btn" size="medium" hover-class="none" :custom-style="customBtnStyle" @click="handleSearch">查询</u-button>
+				<u-button class="handle-btn" size="medium" hover-class="none" @click="resetForm">重置</u-button>
+			</view>
+		</u-popup>
+		<!-- 时间选择器 -->
+		<w-picker
+			class="date-picker"
+			:visible.sync="showPicker"
+			mode="range"
+			:current="true"
+			fields="day"
+			@confirm="onSelected($event, 'range')"
+			@cancel="showPicker = false"
+			ref="date"
+		></w-picker>
+	</div>
+</template>
+
+<script>
+import wPicker from '@/components/w-picker/w-picker.vue'
+export default {
+	components: { wPicker },
+	props: {
+		visible: {
+			type: Boolean,
+			default: false
+		},
+		defaultParams: {  //  默认筛选条件
+			type: Object,
+			default: () => {
+				return {};
+			}
+		}
+	},
+	watch: {
+		visible(newValue, oldValue) {
+			if (newValue) {
+				this.isShow = newValue
+			}
+		},
+		isShow(newValue, oldValue) {
+			if (newValue) {
+			} else {
+				this.init()
+				this.$emit('close')
+			}
+		}
+	},
+	data() {
+		return {
+			customBtnStyle: {  //  自定义按钮样式
+				borderColor: '#2ab4e5',
+				backgroundColor: '#2ab4e5',
+				color: '#fff'
+			},
+			isShow: this.visible, // 显示隐藏
+			showPicker: false, // 是否显示时间弹窗
+			form: {
+				time: '', // 发起时间区间
+				customerMobile: '', // 门店名称
+			},
+			beginDate: null, // 开始时间
+			endDate: null // 结束时间
+		};
+	},
+	mounted() {
+		this.init()
+	},
+	methods: {
+		//  初始化数据
+		init(){
+			if(this.defaultParams.beginDate && this.defaultParams.endDate){
+				this.form.time = this.defaultParams.beginDate + ' ~ ' + this.defaultParams.endDate
+			}
+			this.beginDate = this.defaultParams.beginDate ? this.defaultParams.beginDate : ''
+			this.endDate = this.defaultParams.endDate ? this.defaultParams.endDate : ''
+			this.form.customerMobile = this.defaultParams.customerMobile ? this.defaultParams.customerMobile : ''
+		},
+		//  清空创建时间
+		clearTime(){
+			this.form.time = ''
+			this.beginDate = ''
+			this.endDate = ''
+		},
+		// 关闭弹窗
+		handleClose() {
+			this.isShow = false
+		},
+		// 打开时间选择弹框
+		openPicker() {
+			this.showPicker = true
+		},
+		// 确认日期选择
+		onSelected(v) {
+			this.form.time = v.value[0] + ' ~ ' + v.value[1]
+			this.beginDate = v.value[0]
+			this.endDate = v.value[1]
+			this.showPicker = false
+		},
+		// 查询
+		handleSearch() {
+			let params = {
+				beginDate: this.beginDate,
+				endDate: this.endDate,
+				customerMobile: this.form.customerMobile,
+			};
+			this.$emit('refresh', params)
+			this.isShow = false
+		},
+		// 重置
+		resetForm() {
+			this.$refs.uForm.resetFields()
+			this.$emit('refresh', {})
+			this.isShow = false
+		}
+	}
+};
+</script>
+
+<style lang="scss" scoped>
+.modal-content {
+	position: relative;
+}
+.search-popup {
+	.search-title {
+		text-align: center;
+		padding: 18upx 22upx;
+		color: #333;
+		border-bottom: 1px solid #eee;
+	}
+	.form-content {
+		display: block;
+		padding: 0 20upx;
+		box-sizing: content-box;
+		.status-item {
+			width: 30%;
+			text-align: center;
+			line-height: 60upx;
+			background-color: #F8F8F8;
+			color: #333;
+			border-radius: 6upx;
+			font-size: 24upx;
+			margin: 0 10upx;
+		}
+		.active {
+			background-color: #ffaa00;
+			color: #fff;
+		}
+		.form-item-inp{
+			display: inline-block;
+			width: 88%;
+			vertical-align: top;
+		}
+	}
+	.uni-list {
+		margin: 20upx;
+		.uni-list-cell {
+			display: flex;
+			align-items: center;
+			border-bottom: 1px dashed #eeeeee;
+			.uni-list-cell-db {
+				flex: 1;
+			}
+			.uni-input {
+				height: 2.5em;
+				line-height: 2.5em;
+			}
+		}
+	}
+	.uni-list-btns {
+		display: flex;
+		padding: 20upx;
+		margin-top: 200rpx;
+		.handle-btn {
+			font-size: 28upx;
+			margin: 0 30upx;
+			width: 100%;
+			flex: 1;
+		}
+	}
+}
+.date-picker {
+}
+</style>

+ 51 - 0
pages/ledouHexiao/hexiaoSuccess.vue

@@ -0,0 +1,51 @@
+<template>
+	<view class="pages-content">
+		<view>
+			<u-icon name="checkmark-circle-fill" size="150" color="#00aaff"></u-icon>
+		</view>
+		<view class="pc-a">核销成功</view>
+		<view>{{changeNum}}个乐豆</view>
+		<view>
+			<u-button type="primary" @click="toPage">返回核销记录</u-button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				changeNum: 0
+			}
+		},
+		onLoad(opts) {
+			this.changeNum = opts.changeNum
+		},
+		methods: {
+			toPage(){
+				uni.reLaunch({
+					url:'/pages/index/index'
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="less">
+	.pages-content{
+		display: flex;
+		justify-content: center;
+		flex-direction: column;
+		width: 100%;
+		padding: 100rpx;
+		text-align: center;
+		height: 60vh;
+
+		.pc-a{
+			font-size: 40rpx;
+		}
+		>view{
+			padding: 20rpx 0;
+		}
+	}
+</style>

+ 270 - 0
pages/ledouHexiao/ledouHexiao.vue

@@ -0,0 +1,270 @@
+<template>
+	<view class="content">
+		<u-form :model="form" :error-type="['toast']" :label-width="180" ref="uForm">
+			<u-form-item label="收取门店">
+				<view class="txt-right">{{form.storeName}}</view>
+			</u-form-item>
+			<u-form-item label="支付用户">
+				<view class="txt-right">{{form.customerMobile}}</view>
+			</u-form-item>
+			<u-form-item label="备注" prop="remarks">
+				<u-input placeholder="请输入备注(最多10个字符)" :maxlength="10" :custom-style="{textAlign:'right'}" trim v-model="form.remarks" />
+			</u-form-item> 
+			<u-form-item label="核销数量" label-position="top" prop="changeNum" required>
+				<view class="ledu-input">
+					<view><u-input placeholder="请输入核销数量" :custom-style="{borderBottom:'1px solid #999',textAlign:'center',width:'100%'}" trim type="number" v-model="form.changeNum" /></view>
+					<text>个乐豆</text>
+				</view>
+			</u-form-item> 
+			<view class="form-button">
+				<u-button type="primary" @click="submit">确认核销</u-button>
+			</view>
+		</u-form>
+		
+		<!-- 确认核销弹窗 -->
+		 <u-popup mode="center" :mask-close-able="false" closeable @close="closeModal" negative-top="300" v-model="showModal" width="600rpx" >
+			<view class="slot-content">
+				<view class="slot-title">请输入验证码</view>
+				<view class="text-cont">
+					<view>
+						<text>用户手机:</text>
+						<text>{{form.customerMobile||'--'}}</text>
+					</view>
+				</view>
+				<view class="text-cont">
+					<view>
+						<text>验证码:</text>
+						<u-input type="number" v-model="code" :maxlength="6" placeholder="请输入验证码"></u-input>
+						<u-button size="mini" :disabled="isDisable" @click="getCodeValidate">{{nowVal}}</u-button>
+					</view>
+				</view>
+				<view class="fot-btn">
+					<u-button @click="confirm" :loading="loading" size="medium" type="primary" >确定</u-button>
+				</view>
+			</view>
+		</u-popup>
+		
+		<!-- 图文验证码 -->
+		<!-- <uni-popup ref="imageTxtPopup" type="center">
+			<popup-con type="forgetImageTxt" title="图文验证码" :popBtn="popBtn" :changeImg="changeImg" @captchaImg="captchaImg"></popup-con>
+		</uni-popup> -->
+	</view>
+</template>
+
+<script>
+	// import uniPopup from '@/components/uni-popup/uni-popup.vue'
+	// import popupCon from '@/components/uni-popup/popup-con.vue'
+	import { offPartnerHx, sendVerifyCode, checkVerificationCode } from '@/api/officialPartnerGoldLog.js'
+	export default {
+		components: {
+			// uniPopup,
+			// popupCon
+		},
+		data() {
+			return {
+				showModal: false,
+				nowVal: '获取验证码',  //  按钮显示内容
+				count: '',  //  当前秒数
+				timer: null,  //  倒计时
+				isDisable: false,  //  是否禁止获取验证码
+				code: '',
+				loading: false,
+				currentGold: 0,
+				form:{
+					storeName: '',
+					customerMobile: '',
+					remarks: '',
+					changeNum: ''
+				},
+				rules: {
+					changeNum: [
+						{ 
+							required: true, 
+							type: 'number',
+							message: '请输入乐豆', 
+							min: 1,
+							// 可以单个或者同时写两个触发验证方式 
+							trigger: ['change','blur'],
+						}
+					],
+					remarks: [
+						{
+							message: '请输入备注', 
+							trigger: 'change'
+						}
+					]
+				}
+			}
+		},
+		onLoad(opts) {
+			let data = JSON.parse(decodeURIComponent(opts.item))
+			let user = this.$store.state.vuex_userData
+			this.currentGold = data.currentGold
+			this.form.customerMobile = data.mobile
+			this.form.storeName = user.org.name
+		},
+		// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
+		onReady() {
+			this.$refs.uForm.setRules(this.rules);
+		},
+		methods: {
+			submit() {
+				this.$refs.uForm.validate(valid => {
+					console.log(valid)
+					if (valid) {
+						console.log('验证通过');
+						if(this.form.changeNum>0){
+							if(this.form.changeNum <= this.currentGold){
+								this.showModal = true
+							}else{
+								uni.showToast({icon: 'none',title: '乐豆余额不足'}) 
+							}
+						}else{
+							uni.showToast({icon: 'none',title: '请输入乐豆'}) 
+						}
+						
+					} else {
+						console.log('验证失败');
+					}
+				});
+			},
+			closeModal(){
+				this.showModal = false
+				this.code = ''
+			},
+			// 提交核销
+			saveHx(){
+				offPartnerHx({
+					"customerMobile": this.form.customerMobile,
+					"changeNum": this.form.changeNum,
+					"remarks": this.form.remarks
+				}).then(res => {
+					if(res.status == 200){
+						uni.navigateTo({
+							url: "/pages/ledouHexiao/hexiaoSuccess?changeNum="+this.form.changeNum
+						})
+					}else{
+						this.code = ''
+						uni.showToast({icon: 'none',title: res.message})
+					}
+					this.loading = false
+				})
+			},
+			// 确定验证码
+			confirm(){
+				if(this.code != ''&&this.code.length == 6){
+					this.loading = true
+					checkVerificationCode({mobile:this.form.customerMobile,code:this.code}).then(res => {
+						if(res.status == 200){
+							this.saveHx()
+						}else{
+							uni.showToast({icon: 'none',title: res.message})
+							this.loading = false
+						}
+					})
+				}else{
+					uni.showToast({icon: 'none',title: '请输入验证码'}) 
+				}
+			},
+			//  获取验证码
+			getCodeValidate(){
+				sendVerifyCode({mobile: this.form.customerMobile}).then(res => {
+					if(res.status == 200){
+						//  开启倒计时
+						this.getCodeFun()
+						uni.showToast({icon: 'none',title: '验证码发送成功'}) 
+					}else{
+						this.code = ''
+						uni.showToast({icon: 'none',title: res.message})
+					}
+				})
+			},
+			//  开始倒计时
+			getCodeFun(){
+				const TIME_COUNT = 60
+				if (!this.timer) {
+				  this.count = TIME_COUNT
+				  this.timer = setInterval(() => {
+				    if (this.count > 0 && this.count <= TIME_COUNT) {
+				      this.count--
+				      this.nowVal = this.count + 's后重发'
+				      this.isDisable = true
+				    } else {
+				      this.nowVal = '重新获取验证码'
+				      clearInterval(this.timer)
+				      this.timer = null
+				      this.isDisable = false
+				    }
+				  }, 1000)
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="less">
+.content{
+	width: 100%;
+	padding: 20upx 40upx;
+	background: #FFFFFF;
+	.ledu-input{
+		width: 60%;
+		margin: 0 auto;
+		display: flex;
+		align-items: center;
+		> text{
+			width: 150rpx;
+		}
+	}
+	.form-button{
+		padding: 60upx;
+	}
+	.txt-right{
+		text-align: right;
+		width: 100%;
+	}
+	
+	.slot-content{
+		padding: 30upx 0;
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: space-between;
+		.slot-title{
+			font-size: 30rpx;
+			padding: 20rpx 0;
+		}
+		.text-cont{
+			width: 100%;
+			margin-top: 10upx;
+			>view {
+				padding: 15upx 40upx;
+				display: flex;
+				align-items: center;
+				>text{
+					&:first-child {
+						margin: 0 10upx;
+						width: 130upx;
+					}
+				}
+				.u-input{
+					border-bottom: 1px solid #999;
+					margin: 0 15rpx;
+					text-align: center;
+				}
+			}
+		}
+		.footer{
+			width: 80%;
+			border-bottom: 1px solid #b1b1b1;
+			>input {
+				text-align: center;
+				padding: 10upx 0;
+			}
+		}
+		.fot-btn{
+			margin-top: 30upx;
+		}
+	}
+}
+</style>

+ 0 - 261
pages/login/apply-trial.vue

@@ -1,261 +0,0 @@
-<template>
-	<view class="apply-wrap">
-		<form class="login-form" @submit="formSubmit">
-			<view class="form-item">
-				<text class="require-tip">*</text>
-				<input v-model="form.name" class="item-inp" name="name" type="text" placeholder="请输入企业名称" />
-			</view>
-			<view class="form-item">
-				<text class="require-tip">*</text>
-				<input v-model="areaInfo.label" class="item-inp" type="text" :disabled="true" placeholder="请选择省市区" @tap="openAddress" />
-				<Address ref="applyAddress" @onConfirm="areaConfirm"></Address>
-			</view>
-			<view class="form-item">
-				<input v-model="form.addrDetail" class="item-inp" name="addrDetail" type="text" placeholder="请输入详细地址" />
-			</view>
-			<view class="form-item">
-				<text class="require-tip">*</text>
-				<input v-model="form.contactPhone" class="item-inp" name="contactPhone" type="number" maxlength="11" placeholder="请输入手机号,该号码会作为系统登录账号" />
-			</view>
-			<view class="form-item">
-				<text class="require-tip">*</text>
-				<input v-model="form.verifyCode" class="item-inp" name="verifyCode" type="number" maxlength="6" placeholder="请输入手机验证码" />
-				<button class="getcode-btn" :disabled="isDisable" @click="getCodeValidate">{{nowVal}}</button>
-			</view>
-			<view class="form-item">
-				<input v-model="form.introPhone" class="item-inp" name="introPhone" type="number" maxlength="11" placeholder="请输入推荐人手机" />
-			</view>
-			<view class="form-btn-con">
-				<button class="form-btn" form-type="submit">提交</button>
-				<text class="apply-btn" @click="goLogin">已有账号?去登录</text>
-			</view>
-		</form>
-		<!-- 图文验证码 -->
-		<uni-popup ref="imageTxtPopup" type="center">
-			<!-- type值 用于区分applyImageTxt申请试用   forgetImageTxt忘记密码 -->
-			<popup-con type="applyImageTxt" title="图文验证码" :popBtn="popBtn" :changeImg="changeImg" @captchaImg="captchaImg"></popup-con>
-		</uni-popup>
-		<view class="authUserYs">
-			<checkbox-group @change="authuserChange">
-				<label>
-					<checkbox value="true" :checked="isAuthuserYs" class="login-form-checkbox" />
-					注册代表同意<text @click="toYsPage()">章鱼车管家用户隐私政策</text>
-				</label>
-			</checkbox-group>
-		</view>
-	</view>
-</template>
-
-<script>
-	import { isvalidPhone } from '@/libs/validate.js'
-	import Address from '@/components/address.vue'
-	import uniPopup from '@/components/uni-popup/uni-popup.vue'
-	import popupCon from '@/components/uni-popup/popup-con.vue'
-	import { clzConfirm } from '@/libs/tools.js'
-	import { sendVerifyCode, apply, validateUser } from '@/api/user.js'
-	
-	export default{
-		components: {
-			Address,
-			uniPopup,
-			popupCon
-		},
-		data(){
-			return{
-				form: {
-					name: '',
-					orgType: '',
-					addrProvince: '',
-					addrCity: '',
-					addrDistrict: '',
-					addrDetail: '',
-					contactPhone: '',
-					introPhone: '',
-					verifyCode: ''
-				},
-				nowVal: '获取验证码',  //  按钮显示内容
-				count: '',  //  当前秒数
-				timer: null,  //  倒计时
-				isDisable: false,  //  是否禁止获取验证码
-				areaInfo: '',  //  省市区
-				areaIdArr: [],  //  省市区id数组
-				popBtn: [],  //  name为操作按钮名称,color为操作按钮颜色值
-				changeImg: false,  //  是否重新更换图形验证码
-				randomCode: '',  //  图片验证码随机码
-				isAuthuserYs: false // 是否同意隐私政策
-			}
-		},
-		mounted() {
-			this.isAuthuserYs = this.$store.state.vuex_isUsrAuthYs
-		},
-		methods: {
-			//  表单提交
-			formSubmit(){
-				//  表单校验
-				if(this.form.name == ''){
-					uni.showToast({icon: 'none',title: '请输入企业名称'})
-					return
-				}
-				//  省市区
-				if(this.areaIdArr.length == 0){
-					uni.showToast({icon: 'none',title: '请选择省市区'})
-					return
-				}
-				if(this.form.contactPhone == ''){
-					uni.showToast({icon: 'none',title: '请输入手机号码'})
-					return
-				}
-				if(!isvalidPhone(this.form.contactPhone)){
-				  uni.showToast({icon: 'none',title: '请输入正确的手机号码'})
-				  return
-				}
-				if(this.form.verifyCode == ''){
-					uni.showToast({icon: 'none',title: '请输入验证码'})
-					return
-				}
-				if(this.randomCode == ''){
-					uni.showToast({icon: 'none',title: '请输入正确的手机验证码'})
-					return
-				}
-				if(!this.isAuthuserYs){
-					uni.showToast({icon: 'none',title: '请同意并阅读用户隐私政策'})
-					return
-				}
-				let obj = this.form
-				obj.addrProvince = this.areaIdArr[0]  //  省id
-				obj.addrCity = this.areaIdArr[1]  //  市id
-				obj.addrDistrict = this.areaIdArr[2]  //  区id
-				obj.random = this.randomCode  //  图片验证码随机码
-				//  申请试用
-				apply(obj).then(res => {
-					console.log(res)
-					if(res.status == 200){
-						clzConfirm({
-						    title: '提示',
-						    content: '资料已提交成功,客服会在3个工作日内同您联系。请保持电话畅通,谢谢!',
-							showCancel: false,
-							success: function (ret) {
-						        if (ret.confirm||ret.index==0) {
-									uni.reLaunch({
-										url: '/pages/index'
-									})
-						        }
-						    }
-						})
-					}else{
-						uni.showToast({icon: 'none',title: res.message})
-					}
-				})
-			},
-			//  获取验证码
-			getCodeValidate(){
-				if(this.form.contactPhone){
-					if(!isvalidPhone(this.form.contactPhone)){
-						uni.showToast({icon: 'none',title: '请输入正确的手机号码'})
-						return
-					}else{
-						//  校验手机号是否注册过
-						validateUser({phone: this.form.contactPhone}).then(res => {
-							if(res.status == 200){
-								//  图文验证码
-								this.$refs.imageTxtPopup.open()
-							}else{
-								uni.showToast({icon: 'none',title: res.message})
-							}
-						})
-					}
-				}else{
-					uni.showToast({icon: 'none',title: '请先输入手机号'})
-				}
-			},
-			//  图文验证码
-			captchaImg(code, nowRandomCode){
-				this.captchaVerify(code, nowRandomCode)
-			},
-			//  验证图片验证码
-			captchaVerify(code, nowRandomCode){
-				const _this = this
-				let obj = {}
-				obj.contactPhone = this.form.contactPhone
-				obj.random = nowRandomCode
-				obj.captcha = code
-				//  短信验证码
-				sendVerifyCode(obj).then(res => {
-					console.log(JSON.stringify(res))
-					if(res.status == 200){  //  验证码输入正确
-						_this.randomCode = nowRandomCode  //  图片验证码随机码
-						//  关闭   图形验证码 弹框
-						_this.$refs.imageTxtPopup.close()
-						//  开启倒计时
-						this.getCodeFun()
-						uni.showToast({icon: 'none',title: '验证码发送成功'})
-					}else {  //  验证码输入错误
-						_this.randomCode = ''
-						//  切换验证码重新校验
-						_this.changeImg = false
-						_this.$nextTick(function(){
-							_this.changeImg = true
-						})
-						uni.showToast({icon: 'none',title: res.message})
-					}
-				})
-			},
-			//  开始倒计时
-			getCodeFun(){
-				const TIME_COUNT = 60
-				if (!this.timer) {
-				  this.count = TIME_COUNT
-				  this.timer = setInterval(() => {
-				    if (this.count > 0 && this.count <= TIME_COUNT) {
-				      this.count--
-				      this.nowVal = this.count + 's后重发'
-				      this.isDisable = true
-				    } else {
-				      this.nowVal = '重新获取验证码'
-				      clearInterval(this.timer)
-				      this.timer = null
-				      this.isDisable = false
-				    }
-				  }, 1000)
-				}
-			},
-			//  选择省区市
-			areaConfirm(e) {
-				console.log('已选择的省市区', e)
-				this.areaInfo = e
-				this.areaIdArr = [ e.provinceCode, e.cityCode, e.areaCode ]
-			},
-			openAddress(){
-				//  省市区  回显     参数为省市区id数组
-				this.$refs.applyAddress.open(this.areaIdArr)
-			},
-			//  去登录
-			goLogin(){
-				uni.navigateTo({
-				    url: '/pages/login/login'
-				})
-			},
-			// 隐私
-			authuserChange(e){
-				this.isAuthuserYs = e.detail.value.length > 0
-				this.$u.vuex('vuex_isUsrAuthYs', this.isAuthuserYs)
-			},
-			toYsPage(){
-				uni.navigateTo({
-					url:'/pages/login/userAuthYs'
-				})
-			}
-		}
-	}
-</script>
-<style scoped lang="scss">
-	@import './login.scss';
-	.apply-wrap .login-form{
-		padding-top: 80upx;
-	}
-	.getcode-btn {
-		background-color: #298bf2 !important;
-		color: #fff !important;
-		border: none !important;
-	}
-</style>

+ 5 - 4
pages/login/login.scss

@@ -5,9 +5,9 @@
 	box-sizing: border-box;
 	.logo{
 		display: block;
-		width: 300upx;
-		height: 106upx;
-		padding-top: 200upx;
+		width: 150upx;
+		height: 150upx;
+		padding-top: 120upx;
 		margin: 0 auto;
 	}
 	.login-form{
@@ -54,7 +54,8 @@
 				display: block;
 				line-height: 84upx;
 				margin: 0 auto;
-				background-color: #298bf2;
+				background-color: #2ab4e5;
+				// background-color: #298bf2;
 				color: #fff;
 			}
 			uni-button.form-btn:after{

+ 51 - 100
pages/login/login.vue

@@ -1,11 +1,11 @@
 <template>
 	<view class="login-wrap">
-		<view v-if="!buildType" style="text-align: center;color: #999999;padding-top: 40px;">{{ envTips }}</view>
-		<image src="../../static/logo-h.png" class="logo"></image>
+		<!-- <view v-if="!buildType" style="text-align: center;color: #999999;padding-top: 40px;">{{ envTips }}</view> -->
+		<image src="../../static/logo.jpg" class="logo"></image>
 		<form class="login-form" @submit="formSubmit">
 			<view class="form-item">
 				<u-icon size="34" color="#999" name="account"></u-icon>
-				<input v-model="form.username" class="item-inp" name="username" type="number" maxlength="11" placeholder="请输入用户名" />
+				<input v-model="form.loginName" class="item-inp" name="loginName" type="text" maxlength="30" placeholder="请输入用户名" />
 			</view>
 			<view class="form-item">
 				<u-icon size="34" color="#999" name="lock"></u-icon>
@@ -13,28 +13,16 @@
 			</view>
 			<view class="flex-box" style="margin-top: 60upx;">
 				<view class="remember-pass">
-					<checkbox-group @change="rememberChange">
-						<label>
-							<checkbox value="true" :checked="isRemember" class="login-form-checkbox" />
-							<text>记住密码</text>
-						</label>
-					</checkbox-group>
+					<u-checkbox v-model="isRemember" value="true" :size="30" :label-size="26" active-color="#2ab4e5" class="login-form-checkbox" @change="rememberChange">记住密码</u-checkbox>
 				</view>
-				<!-- <view class="forget-pass" @click="forgetPass">忘记密码</view> -->
 			</view>
 			<view class="form-btn-con">
 				<button class="form-btn" form-type="submit">登录</button>
-				<!-- <text class="apply-btn" @click="applyTrial">还没有账号?马上申请试用</text> -->
 			</view>
 		</form>
 		<view class="authUserYs">
-			<checkbox-group @change="authuserChange">
-				<label>
-					<checkbox value="true" :checked="isAuthuserYs" class="login-form-checkbox" />
-					登录代表同意
-					<text @click="toYsPage()">章鱼车管家用户协议及隐私保护政策</text>
-				</label>
-			</checkbox-group>
+			<u-checkbox v-model="isAuthuserYs" value="true" :size="30" :label-size="26" active-color="#2ab4e5" class="login-form-checkbox" @change="authuserChange">登录代表同意</u-checkbox>
+			<text @click="toYsPage()" style="vertical-align: text-top;font-size: 26rpx;text-decoration: underline;">乐色助手用户协议及隐私保护政策</text>
 		</view>
 	</view>
 </template>
@@ -49,91 +37,52 @@ export default {
 	data() {
 		return {
 			form: {
-				username: this.$store.state.vuex_user.account,
+				loginName: this.$store.state.vuex_user.account,
 				password: this.$store.state.vuex_user.password
 			},
 			isRemember: true, //  是否记住密码
-			isAuthuserYs: false, // 是否同意隐私政策
+			isAuthuserYs: true, // 是否同意隐私政策
 			envTips: '',
-			buildType: ''
+			buildType: '',
 		};
 	},
 	mounted() {
-		this.isRemember = this.$store.state.vuex_isRemember;
-		this.isAuthuserYs = this.$store.state.vuex_isUsrAuthYs;
+		this.isRemember = this.$store.state.vuex_isRemember || true;
+		this.isAuthuserYs = this.$store.state.vuex_isUsrAuthYs || true;
 		this.envTips = getApp().globalData.envTips;
 		this.buildType = getApp().globalData.buildType;
 	},
 	onShow() {
-		//#ifdef APP-PLUS
-		  uni.getSystemInfo({
-			  success:(res) => {
-				  console.log(res)
-				  //检测当前平台,如果是安卓则启动安卓更新  
-				  if(res.platform=="android"){  
-					  // 获取最新版本信息
-					  plus.runtime.getProperty(plus.runtime.appid,(wgtinfo)=>{
-					  	getApp().globalData.version = wgtinfo
-					  	this.AndroidCheckUpdate()
-					  })
-				  }  
-			  }  
-		  })
-		//#endif
 	},
 	methods: {
-		// 安卓版本更新
-		AndroidCheckUpdate(){
-			let _this = this
-			getSysVersion().then(ret => {
-				if(ret.status == 200){
-					this.$store.state.vuex_versionInfo = ret.data
-					let currTimeStamp = new Date(ret.data.publicDate).getTime();
-					// 判断缓存时间
-					uni.getStorage({
-						key: 'tip_version_update_time',
-						success: function (res) {
-							let lastTimeStamp = res.data;
-							//定义提醒的时间间隔,避免烦人的一直提示,一个小时:36000;一天:60*60*1000*24
-							let tipTimeLength = 60*60*1000*3;
-							// 强制更新
-							if(ret.data.forceUpgrade == 1){
-								tipTimeLength = 0
-								//进行版本型号的比对 以及下载更新请求
-								checkVersionToLoadUpdate(ret.data,0,market);
-							}else{
-								if((lastTimeStamp+tipTimeLength) <= currTimeStamp){
-									//重新设置时间戳
-									setStorageForAppVersion(currTimeStamp);
-									//进行版本型号的比对 以及下载更新请求
-									checkVersionToLoadUpdate(ret.data,0,market);
-								}
-							}
-						},
-						fail:function(res){
-							setStorageForAppVersion(currTimeStamp);
-						}
-					});
-				}
+		//  获取微信login  code
+		getWechatCode(){
+			const _this = this
+			wx.login({
+			  success (res) {
+			    if (res.code) {
+					//发起网络请求
+					let formData = JSON.parse(JSON.stringify(_this.form))
+					formData.code = res.code
+					_this.submitForm(formData)
+			    } else {
+					console.log('登录失败,点击“登录”重试!' + res.errMsg)
+			    }
+			  }
 			})
 		},
-		// 过滤权限code
-		fiterAuthCode(data) {
-			data.permCodes = data.permCodes.filter(item => item.indexOf('_mobile') > 0);
-			return data;
-		},
 		//  表单提交
 		formSubmit() {
 			const _this = this;
 			//  表单校验
-			if (_this.form.username == '') {
+			if (_this.form.loginName == '') {
 				uni.showToast({ icon: 'none', title: '请输入用户名' });
 				return;
 			}
-			if (!isvalidPhone(_this.form.username)) {
-				uni.showToast({ icon: 'none', title: '请输入正确的手机号码' });
-				return;
-			}
+			// if (!isvalidPhone(_this.form.loginName)) {
+			// 	uni.showToast({ icon: 'none', title: '请输入正确的手机号码' });
+			// 	return;
+			// }
 			if (_this.form.password == '') {
 				uni.showToast({ icon: 'none', title: '请输入密码' });
 				return;
@@ -149,24 +98,32 @@ export default {
 			uni.showLoading({
 				title: '正在登录...'
 			});
+			// #ifdef MP-WEIXIN
+				//  获取微信login   code
+				this.getWechatCode()
+			// #endif
+			// #ifndef MP-WEIXIN
+				this.submitForm(_this.form)
+			// #endif
+		},
+		submitForm(formData){
+			const _this = this;
 			//  登录
-			login(_this.form).then(ret => {
+			login(formData).then(res => {
 				uni.hideLoading();
-				let res = ret.data ? ret.data : ret;
 				if (res.status == 200) {
-					_this.$u.vuex('vuex_token', 'Bearer ' + res.access_token);
-					_this.$u.vuex('vuex_userData', _this.fiterAuthCode(res.auth_user));
-					getApp().globalData.token = 'Bearer ' + res.access_token;
+					_this.$u.vuex('vuex_token', res.data);
+					getApp().globalData.token = res.data;
 					//登录成功将用户名密码存储到用户本地
 					if (_this.isRemember) {
 						//用户勾选“记住密码”
-						_this.$u.vuex('vuex_user.account', _this.form.username);
+						_this.$u.vuex('vuex_user.account', _this.form.loginName);
 						_this.$u.vuex('vuex_user.password', _this.form.password);
 					} else {
 						//用户没有勾选“记住密码”
 						_this.$u.vuex('vuex_user.account', '');
 						_this.$u.vuex('vuex_user.password', '');
-						_this.form.username = '';
+						_this.form.loginName = '';
 						_this.form.password = '';
 					}
 					uni.setStorageSync('loginTimeOut', 'NO');
@@ -178,34 +135,28 @@ export default {
 		},
 		toMain() {
 			// 跳转到首页
-			uni.redirectTo({
-				url: '/pages/index'
-			});
-		},
-		//  申请试用
-		applyTrial() {
-			uni.navigateTo({
-				url: '/pages/login/apply-trial'
+			uni.switchTab({
+				url: '/pages/index/index'
 			});
 		},
 		//  忘记密码
 		forgetPass() {
 			uni.navigateTo({
-				url: '/pages/login/forget-pass?username=' + this.form.username
+				url: '/pages/login/forget-pass?username=' + this.form.loginName
 			});
 		},
 		//  判断是否记住密码
 		rememberChange(e) {
-			this.isRemember = e.detail.value.length > 0;
+			this.isRemember = e.value;
 		},
 		// 隐私
 		authuserChange(e) {
-			this.isAuthuserYs = e.detail.value.length > 0;
+			this.isAuthuserYs = e.value;
 			this.$u.vuex('vuex_isUsrAuthYs', this.isAuthuserYs);
 		},
 		toYsPage() {
 			uni.navigateTo({
-				url: '/pages/login/userAuthYs'
+				url: '/pages/agreement/agreement'
 			});
 		}
 	}

+ 3 - 6
pages/userCenter/aboutUs.vue

@@ -2,14 +2,11 @@
 	<view class="container">
 		<view class="logoContent">
 			<view class="logoBorder">
-				<!-- <image class="logoImg" src="/static/logo-us.png"></image> -->
+				<image class="logoImg" src="/static/logo.jpg"></image>
 			</view>
-			<view>章鱼车管家信息管理平台</view>
 		</view>
 		<view class="textContent">
-			<view>陕西山海高科信息技术有限公司专注于汽车服务行业,成立于古城西安,是一家以先进云端互联网技术驱动的公司,致力于通过saas云门店管理系统为汽车综修厂、社区店以及大量的中小门店赋能。以解决汽车维修、美容、保养等业务中发生的一系列问题。</view>
-			<view>章鱼车管家设计了一套完善的降本增效方案,在引流获客、员工提成、营销活动、财务报表、数据分析等方面获得客户一致认可。</view>
-			<view>山海高科将通过持续的科技成果转化为推动汽后市场发展提供动力,帮助更多服务终端、供应链企业、主机厂商、银行以及保险等汽车后市场参与方转型升级。</view>
+			<view>智享亿家作为中国出色的垃圾分类专家和平台,致力于改变中国社区环保现状,通过多年的耕耘和积累,打造的城市垃圾分类一体化智能解决方案已获得咸阳、西安航天等多地市的环保垃圾处理资格,并成为全国住建部在咸阳市的环保模范单位。</view>
 		</view>
 	</view>
 </template>
@@ -36,7 +33,7 @@
 				display: inline-block;
 				position: relative;
 				.logoImg{
-					width:135rpx;
+					width:180rpx;
 					height:180rpx;
 					position: absolute;
 					top:0;

+ 13 - 11
pages/userCenter/changePwd.vue

@@ -5,7 +5,7 @@
 			<view class="input-group">
 				<view class="input-row border">
 					<text class="title">原密码:</text>
-					<m-input class="m-input"  type="password"  displayable v-model="formCustom.oldPwd" placeholder="请输入原密码"></m-input>
+					<m-input class="m-input" :maxlength="30"  type="password"  displayable v-model="formCustom.oldPwd" placeholder="请输入原密码"></m-input>
 				</view>
 				<view class="input-row">
 					<text class="title">新密码:</text>
@@ -19,12 +19,8 @@
 		</view>
 		<!-- 消息提醒弹窗 -->
 		<view class="form-footer-btn">
-			<button @click="handleReset" type="info">
-				重置
-			</button>
-			<button @click="handleSubmit" :loading="loading" type="primary">
-				保存
-			</button>
+			<u-button size="medium" hover-class="none" @click="handleReset">重置</u-button>
+			<u-button size="medium" hover-class="none" :loading="loading" :custom-style="customBtnStyle" @click="handleSubmit">保存</u-button>
 		</view>
 	</view>
 </template>
@@ -44,7 +40,12 @@
 				  passwdCheck: '',
 				  oldPwd: ''
 				},
-				loading: false
+				loading: false,
+				customBtnStyle: {  //  自定义按钮样式
+					borderColor: '#2ab4e5',
+					backgroundColor: '#2ab4e5',
+					color: '#fff'
+				},
 			}
 		},
 		methods:{
@@ -103,7 +104,7 @@
 					console.log(res)
 					this.messageInfo(res.message)
 					if(res.status == 200){
-						this.$store.commit("$closeWebsocket")
+						// this.$store.commit("$closeWebsocket")
 						this.$store.state.vuex_token = ''
 						this.$store.state.vuex_userData = ''
 						uni.setStorageSync('setStatusIndexFunc', 0)
@@ -151,6 +152,7 @@
 				border-radius: 10rpx;
 				line-height: 32px;
 				display: flex;
+				align-items: center;
 				.title{
 					width:140rpx;
 					display: inline-block;
@@ -175,9 +177,9 @@
 			bottom: 10rpx;
 		}
 		.form-footer-btn{
-			margin: 50upx;
+			margin: 140upx 50upx 0;
 			display: flex;
-			justify-content: center;
+			justify-content: space-between;
 		}
 		.form-footer-btn uni-button{
 			width: 50%;

+ 20 - 10
pages/userCenter/index.vue

@@ -3,18 +3,20 @@
 		<!-- 头部 -->
 		<view class="user-head">
 			<view class="user-photo">
-				<u-image width="130rpx" height="130rpx" shape="circle" :src="userAvatarUrl"></u-image>
+				<open-data type="userAvatarUrl" class="avatar"></open-data>
 			</view>
 			<view class="user-info">
-				<text class="user-name">userName</text>
-				<text class="user-phone">15778787878</text>
+				<text class="user-name">{{userInfoData.name || ''}}</text>
+				<text class="user-phone">{{userInfoData.phone || ''}}</text>
 			</view>
 		</view>
 		<!-- 列表 -->
 		<view class="user-list">
 			<u-cell-group>
-				<u-cell-item icon="file-text" icon-size="40" :icon-style="{color:'#ffaa00'}" index="0" @click="toPage" title="服务协议及隐私政策"></u-cell-item>
-				<u-cell-item icon="info-circle" icon-size="38" :icon-style="{color:'#55aa00'}" index="1" @click="toPage" title="关于我们"></u-cell-item>
+				<!-- <u-cell-item icon="search" icon-size="36" :icon-style="{color:'#ff0000'}" index="0" @click="toPage" title="用户乐豆查询及核销"></u-cell-item> -->
+				<u-cell-item icon="info-circle" icon-size="38" :icon-style="{color:'#55aa00'}" index="2" @click="toPage" title="关于我们"></u-cell-item>
+				<u-cell-item icon="file-text" icon-size="40" :icon-style="{color:'#ffaa00'}" index="1" @click="toPage" title="服务协议及隐私政策"></u-cell-item>
+				<u-cell-item icon="lock" icon-size="38" :icon-style="{color:'#00aaff'}" index="3" @click="toPage" title="修改密码"></u-cell-item>
 			</u-cell-group>
 		</view>
 		<!-- 退出 -->
@@ -32,12 +34,14 @@
 				quitButton: {
 					borderRadius:'100rpx',
 					fontSize:'30rpx',
-					background: '#01c9b2'
+					background: '#2ab4e5'
 				},
+				userInfoData: null,  //  用户信息
 				userAvatarUrl: ''  //  用户头像
 			};
 		},
 		onShow() {
+			this.userInfoData = this.$store.state.vuex_userData
 		},
 		onLoad() {
 		},
@@ -45,8 +49,10 @@
 			// 打开对应的页面
 			toPage(index){
 				let pageUrl=[
+					'/pages/userCenter/leDouQuery',
 					'/pages/agreement/agreement?fromPage=usercenter',
-					'/pages/userCenter/aboutUs'
+					'/pages/userCenter/aboutUs',
+					'/pages/userCenter/changePwd'
 					]
 				uni.navigateTo({
 					url: pageUrl[index]
@@ -80,9 +86,9 @@
 				       getApp().globalData.token = ''
 				       _this.$u.vuex('vuex_token','')
 					   // 关闭socket
-					   _this.$store.commit("$closeWebsocket")
+					   // _this.$store.commit("$closeWebsocket")
 				        uni.reLaunch({
-				        	url: '/pages/index/index'
+				        	url: '/pages/login/login'
 				        })
 				      })
 				    }
@@ -97,13 +103,17 @@
 	.user-content{
 		width: 100%;
 		.user-head{
-			background: #01c9b2;
+			background: #2ab4e5;
 			display: flex;
 			align-items: center;
 			padding: 35rpx 55rpx;
 			.user-photo{
 				flex-shrink: 0;
 				margin-right: 5rpx;
+				width: 130rpx;
+				height: 130rpx;
+				border-radius: 50%;
+				overflow: hidden;
 			}
 			.user-info{
 				flex-grow: 1;

+ 101 - 0
pages/userCenter/leDouQuery.vue

@@ -0,0 +1,101 @@
+<template>
+	<view class="query-content">
+		<view class="query-input">
+			<u-input v-model="queryWord" :border="true" :maxlength="11" placeholder="请输入完整手机号码查询" type="number"/>
+			<view class="query-button">
+				<u-button shape="circle" @click="queryData" type="primary">查询</u-button>
+			</view>
+		</view>
+		<view class="query-result">
+			<u-gap height="20" bg-color="#f8f8f8"></u-gap>
+			<view class="result-list" v-if="result">
+				<view class="result-title">
+					<view>
+						<u-icon name="account-fill" color="#666" size="28"></u-icon>
+						<text>{{result.customerRoleDictValue}}</text>
+					</view>
+					<view v-if="result.customerRole == 1 && result.state == 1">
+						<u-button @click="hexiao" type="warning" size="mini">乐豆核销</u-button>
+					</view>
+				</view>
+				<view class="result-info">
+					<u-cell-group>
+						<u-cell-item :arrow="false" title="注册时间" :value="result.registerTime"></u-cell-item>
+						<u-cell-item :arrow="false" title="用户手机" :value="result.mobile"></u-cell-item>
+						<u-cell-item :arrow="false" title="乐豆余额" :value-style="{color:'red'}" :value="result.currentGold||'0'">
+						</u-cell-item>
+					</u-cell-group>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import { queryldByMobile } from '@/api/officialPartnerGoldLog.js'
+	export default{
+		data() {
+			return {
+				queryWord: '',
+				result: null
+			}
+		},
+		methods: {
+			queryData(){
+				if(this.queryWord.length == 11){
+					queryldByMobile({mobile:this.queryWord}).then(res => {
+						console.log(res)
+						if(res.status == 200){
+							this.result = res.data
+						}else{
+							this.result = null
+						}
+					})
+				}else{
+					uni.showToast({
+						icon: 'none',
+						title: '请输入完整的手机号'
+					})
+				}
+			},
+			hexiao() {
+				if(this.result.currentGold>0){
+					uni.navigateTo({
+						url: "/pages/ledouHexiao/ledouHexiao?item="+ encodeURIComponent(JSON.stringify(this.result))
+					})
+				}else{
+					uni.showToast({
+						icon: 'none',
+						title: '此用户的乐豆余额为0'
+					})
+				}
+			}
+		},
+	}
+</script>
+
+<style lang="less">
+	.query-content{
+		width: 100%;
+		display: flex;
+		flex-direction: column;
+		.query-input{
+			padding: 20rpx 60rpx;
+			background: #FFFFFF;
+		}
+		.query-button{
+			padding: 20rpx 0;
+		}
+		.query-result{
+			flex-grow: 1;
+		}
+		.result-title{
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			background: #fff;
+			padding: 25rpx 30rpx;
+			border-bottom: 1rpx solid #eee;
+		}
+	}
+</style>

BIN
static/filter.png


BIN
static/ledou.png


BIN
static/logo-h.png


BIN
static/logo.jpg


BIN
static/tabbar/home-active.png


BIN
static/tabbar/home.png


BIN
static/tabbar/record-active.png


BIN
static/tabbar/record.png


BIN
static/tabbar/shop-active.png


BIN
static/tabbar/shop.png


BIN
static/tabbar/user-active.png


BIN
static/tabbar/user.png


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.