zhangdan hace 4 años
padre
commit
ee760c3168
Se han modificado 100 ficheros con 7051 adiciones y 2511 borrados
  1. 8 7
      App.vue
  2. 0 53
      api/cleared.js
  3. 29 0
      api/data.js
  4. 35 0
      api/index.js
  5. 8 2
      api/login.js
  6. 0 67
      api/unclear.js
  7. 7 117
      api/user.js
  8. 443 0
      components/address.vue
  9. 721 0
      components/almost-lottery/almost-lottery.vue
  10. 5 6
      components/m-input.vue
  11. 0 142
      components/uni-navbar/uni-navbar.vue
  12. 178 0
      components/uni-numbers-box/uni-numbers-box.vue
  13. 122 0
      components/uni-popup/image-txt-popup.vue
  14. 22 0
      components/uni-popup/message.js
  15. 96 0
      components/uni-popup/popup-con.vue
  16. 25 0
      components/uni-popup/popup.js
  17. 244 0
      components/uni-popup/uni-popup-dialog.vue
  18. 116 0
      components/uni-popup/uni-popup-message.vue
  19. 165 0
      components/uni-popup/uni-popup-share.vue
  20. 295 0
      components/uni-popup/uni-popup.vue
  21. 279 0
      components/uni-transition/uni-transition.vue
  22. 0 0
      components/w-picker/areadata/areadata.js
  23. 742 0
      components/w-picker/date-picker.vue
  24. 345 0
      components/w-picker/half-picker.vue
  25. 274 0
      components/w-picker/linkage-picker.vue
  26. 344 0
      components/w-picker/range-picker.vue
  27. 183 0
      components/w-picker/region-picker.vue
  28. 129 0
      components/w-picker/selector-picker.vue
  29. 250 0
      components/w-picker/shortterm-picker.vue
  30. 218 0
      components/w-picker/time-picker.vue
  31. 26 0
      components/w-picker/w-picker.css
  32. 341 0
      components/w-picker/w-picker.vue
  33. 6 21
      libs/axios.js
  34. 95 0
      libs/getDate.js
  35. 0 0
      libs/qqmap-wx-jssdk.min.js
  36. 41 0
      libs/tools.js
  37. 1 29
      main.js
  38. 4 4
      manifest.json
  39. 47 4
      package-lock.json
  40. 8 4
      package.json
  41. 26 46
      pages.json
  42. 2 2
      pages/agreement/agreement.vue
  43. 0 345
      pages/cleared/chooseNetwork.vue
  44. 0 213
      pages/cleared/details.vue
  45. 0 175
      pages/cleared/index.vue
  46. 0 253
      pages/cleared/network.vue
  47. 326 0
      pages/index/addData.vue
  48. 306 302
      pages/index/index.vue
  49. 0 225
      pages/index/map.vue
  50. 62 60
      pages/index/searchModal.vue
  51. 0 229
      pages/login/forget-pass.vue
  52. 12 1
      pages/login/login.scss
  53. 121 64
      pages/login/login.vue
  54. 79 0
      pages/login/loginPw.scss
  55. 27 8
      pages/login/phoneLogin.vue
  56. 0 66
      pages/login/userAuthYs.vue
  57. 62 0
      pages/userCenter/aboutUs.vue
  58. 36 12
      pages/userCenter/changePwd.vue
  59. 140 54
      pages/userCenter/index.vue
  60. BIN
      static/GLASS.png
  61. BIN
      static/HARM.png
  62. BIN
      static/METAL.png
  63. BIN
      static/MET_PLA.png
  64. BIN
      static/PAPER.png
  65. BIN
      static/PLASTIC.png
  66. BIN
      static/RECYCLING.png
  67. BIN
      static/camera.png
  68. BIN
      static/edit.png
  69. BIN
      static/filter.png
  70. BIN
      static/full-bg.png
  71. BIN
      static/imgError.png
  72. BIN
      static/index/chuyu.png
  73. BIN
      static/index/jianzhu.png
  74. BIN
      static/index/logo-active.png
  75. BIN
      static/index/logo.png
  76. BIN
      static/index/other.png
  77. BIN
      static/ledou.png
  78. BIN
      static/loading.gif
  79. BIN
      static/login_icon.png
  80. BIN
      static/login_icon_logo.png
  81. BIN
      static/login_slogan.png
  82. BIN
      static/logo.jpg
  83. BIN
      static/logo.png
  84. BIN
      static/map-icon.png
  85. BIN
      static/md-big-pic.png
  86. BIN
      static/pop-bg.png
  87. BIN
      static/store-s.png
  88. BIN
      static/store.png
  89. BIN
      static/tabbar/cleared-active.png
  90. BIN
      static/tabbar/cleared.png
  91. BIN
      static/tabbar/home-active.png
  92. BIN
      static/tabbar/home.png
  93. BIN
      static/tabbar/shop-active.png
  94. BIN
      static/tabbar/shop.png
  95. BIN
      static/tabbar/unclean-active.png
  96. BIN
      static/tabbar/unclean.png
  97. BIN
      static/tabbar/user-active.png
  98. BIN
      static/tabbar/user.png
  99. BIN
      static/user_icon_number.png
  100. BIN
      static/user_icon_password.png

+ 8 - 7
App.vue

@@ -1,7 +1,9 @@
 <script>
-	const uat_URL = 'https://driver.test.sxzxyj.net/gc-driver/' // 预发布
-	// const uat_URL = 'http://192.168.16.103:8304/gc-driver/' // 本地
-	const pro_URL = 'https://driver.sxzxyj.net/gc-driver/'  // 生产
+	// const uat_domain = 'https://gather.test.sxzxyj.net' // 预发布
+	const uat_domain = 'http://192.168.16.217:8305' // 本地
+	const pro_domain = 'https://gather.zyucgj.cn' // 生产
+	const uat_URL = uat_domain+'/gc-gather/' // 预发布
+	const pro_URL = pro_domain+'/gc-gather/'  // 生产
 	const buildType = 1 // 打包环境对应类型,1 生产 0 预发布
 	const buildURL = buildType ? pro_URL : uat_URL // 打包后实际对应的url
 	const envText = ['预发布环境','生产环境']
@@ -9,6 +11,7 @@
 	console.log(process.env.NODE_ENV)
 	export default {
 		globalData: {  
+			baseDomain: process.env.NODE_ENV == 'development' ? uat_domain : pro_domain,
 			baseUrl: process.env.NODE_ENV == 'development' ? uat_URL : buildURL,
 			token: '',
 			version: '', // 当前版本号
@@ -44,9 +47,7 @@
 		display: flex;
 		background-color: #F8F8F8;
 	}
-	/* 登录页是否记住密码多选框样式 */
-	uni-checkbox.login-form-checkbox .uni-checkbox-input{
-		width: 24upx !important;
-		height: 24upx !important;
+	.content {
+		padding: 20upx;
 	}
 </style>

+ 0 - 53
api/cleared.js

@@ -1,53 +0,0 @@
-import axios from '@/libs/axios.js'
-
-// 全部待清运网点列表
-export const waitToCleanList = params => {
-	let url = `cleanStation/waitToCleanList/${params.pageNo}/${params.pageSize}`
-	delete params.pageNo
-	delete params.pageSize
-	return axios.request({
-		url: url,
-		method: 'post',
-		data: params
-	})
-}
-
-// 网点设备列表信息
-export const stationDevice = params => {
-  return axios.request({
-    url: `device/queryWaitCleanDeviceByStationNo/${params.stationNo}`,
-    method: 'get',
-  })
-}
-
-//  网点信息
-export const getWaitToCleanDetailHeader = params => {
-  return axios.request({
-    url: `station/findById/${params.stationNo}`,
-    method: 'get',
-  })
-}
-
-// 已清运列表
-export const getAlreadyCleanList = params => {
-	let url = `cleanLog/getAlreadyCleanList/${params.pageNo}/${params.pageSize}`
-	delete params.pageNo
-	delete params.pageSize
-	return axios.request({
-		url: url,
-		method: 'post',
-		data: params
-	})
-}
-
-// 已清运网点设备列表信息
-export const getAlreadyCleanDetails = params => {
-	let url = `cleanLog/getAlreadyCleanDetails/${params.pageNo}/${params.pageSize}`
-	delete params.pageNo
-	delete params.pageSize
-	return axios.request({
-		url: url,
-		method: 'post',
-		data: params
-	})
-}

+ 29 - 0
api/data.js

@@ -5,4 +5,33 @@ export const getLookUpDatas = (params) => {
     url: `lookup/findByLookup/${params.type}`,
     method: 'get'
   })
+}
+// 开箱操作
+export const openDevice = (params) => {
+  return axios.request({
+    url: `device/ctl/open`,
+    method: 'post',
+	data: params
+  })
+}
+//查询省
+export const  getProvince = () => {
+  return axios.request({
+    url: `area/PROVINCE`,
+    method: 'get'
+  })
+}
+//查询市
+export const  getCityByPro = params => {
+  return axios.request({
+    url: `area/CITY/${params.id}`,
+    method: 'get'
+  })
+}
+//查询区
+export const  getDistrictByCity = params => {
+  return axios.request({
+    url: `area/DISTRICT/${params.id}`,
+    method: 'get'
+  })
 }

+ 35 - 0
api/index.js

@@ -0,0 +1,35 @@
+import axios from '@/libs/axios.js'
+// 新增采集信息
+export const gatherList = params => {
+  return axios.request({
+    url: `gather/query/${params.pageNo}/${params.pageSize}`,
+    method: 'post',
+	data: params
+  })
+}
+
+// 查询采集信息详情
+export const gatherDetail = (params) => {
+  return axios.request({
+    url: `gather/findById/${params.id}`,
+    method: 'get',
+  })
+}
+
+// 采集信息总计
+export const gatherTotal = (params) => {
+  return axios.request({
+    url: `gather/sumByOperator`,
+    method: 'post',
+	data: params
+  })
+}
+
+// 保存采集信息详情
+export const gatherSave = (params) => {
+  return axios.request({
+    url: `gather/save`,
+    method: 'post',
+	data:params
+  })
+}

+ 8 - 2
api/login.js

@@ -36,8 +36,14 @@ export const checkLogin = () => {
 // 获取登录用户信息
 export const getUserInfo = params => {
   return axios.request({
-    url: `customer/getDetail`,
-    data: params,
+    url: `user/userInfo`,
     method: 'get'
   })
 };
+export const loginPhone = params => {
+  return axios.request({
+    url: `loginPhone`,
+    method: 'post',
+	data: params
+  },true)
+};

+ 0 - 67
api/unclear.js

@@ -1,67 +0,0 @@
-import axios from '@/libs/axios.js'
-
-// 个人待清运列表
-export const getSelfCleanTaskList = params => {
-	let url = `cleanStation/getSelfCleanTaskList/${params.pageNo}/${params.pageSize}`
-	delete params.pageNo
-	delete params.pageSize
-	return axios.request({
-		url: url,
-		method: 'post',
-		data: params
-	})
-}
-
-// 个人待清运列表详情
-export const getSelfCleanTaskDetails = params => {
-  return axios.request({
-    url: `cleanDevice/getSelfCleanTaskDetails`,
-    method: 'post',
-	data: params
-  })
-}
-
-// 新增个人待清运
-export const cleanStationAdd = params => {
-  return axios.request({
-    url: `cleanStation/addCleanTask`,
-    method: 'post',
-	data: params
-  })
-}
-
-// 移除个人待清运
-export const cleanStationRemove = params => {
-  return axios.request({
-    url: `cleanStation/removeCleanTask/${params.stationNo}`,
-    method: 'post',
-	data: params
-  })
-}
-
-// 扫码清运
-export const cleanDevice = params => {
-  return axios.request({
-    url: `cleanDevice/clean`,
-    method: 'post',
-	data: params
-  })
-}
-
-// 清运路线
-export const getCleanWay = params => {
-  return axios.request({
-    url: `cleanStation/getCleanWay`,
-    method: 'post',
-	data: params
-  })
-}
-
-//  扫码获取网点信息
-export const getDeviceMsg = params => {
-  return axios.request({
-    url: `cleanDevice/getDeviceMsg`,
-    method: 'post',
-	data: params
-  })
-}

+ 7 - 117
api/user.js

@@ -1,34 +1,9 @@
 import axios from '@/libs/axios.js'
-
-//  axios.request()  第二个参数若为true则表示不传token
-
-// 手机号登录
-export const loginPhone = (params) => {
-  return axios.request({
-    url: 'loginPhone',
-    data: params,
-    method: 'post'
-  }, true)
-}
-// 微信授权登录
-export const login = (params) => {
-  return axios.request({
-    url: 'login',
-    data: params,
-    method: 'post'
-  }, true)
-}
-//  校验手机号是否注册
-export const validateUser = params => {
-  return axios.request({
-    url: `org/apply/validateUser/${params.phone}`,
-    method: 'get'
-  }, true)
-}
+ 
 // 获取图片验证码
 export const getCaptcha = randomCode => {
   return axios.request({
-    url: `org/apply/getCaptcha/${randomCode}`,
+    url: `captcha/create/${randomCode}`,
     method: 'get',
     responseType: 'blob',
   }, true)
@@ -36,33 +11,12 @@ export const getCaptcha = randomCode => {
 // 发送短信验证码
 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',
+    url: 'sendVerifiCode',
     method: 'post',
     data: params
   }, true)
 }
-// 获取门店名称
-export const getStore = (token) => {
-  return axios.request({
-    url: 'getStore',
-    method: 'get'
-  })
-}
-// 登出
-export const logout = () => {
-  return axios.request({
-    url: 'logout',
-    method: 'get'
-  })
-}
+
 // 修改密码
 export const changePwd = params => {
   return axios.request({
@@ -74,75 +28,11 @@ export const changePwd = params => {
     }
   }).then(res => res)
 } 
-//  忘记密码 校验手机号是否注册过
-export const memberGetByMobile = params => {
-  return axios.request({
-    url: 'member/getByMobile',
-    method: 'post',
-    data: params
-  }, true)
-}
-//  忘记密码 获取图片验证码
-export const memberCaptcha = randomCode => {
-  return axios.request({
-    url: `member/captcha/create/${randomCode}`,
-    method: 'get',
-    responseType: 'blob'
-  }, true)
-}
-//  忘记密码 发送短信验证码
-export const memberVerifyCode = params => {
-  return axios.request({
-    url: 'member/sendVerifyCode',
-    method: 'post',
-    data: params
-  }, true)
-}
-//  忘记密码 修改密码
-export const memberChangePwd = params => {
-  return axios.request({
-    url: 'member/changePwd',
-    method: 'post',
-    data: params
-  }, true)
-}
-//  忘记密码 校验短信验证码是否正确
-export const memberValidateVerifyCode = params => {
-  return axios.request({
-    url: 'member/validateVerifyCode',
-    method: 'post',
-    data: params
-  }, true)
-}
-// 获取通知消息未读数
-export const getUnreadCount = params => {
-  return axios.request({
-    url: 'noticeUser/queryNotReadCount',
-    method: 'post'
-  })
-}
-// 设置已读消息
-export const hasRead = params => {
-  return axios.request({
-    url: `noticeUser/setRead/${params.msg_id}`,
-    method: 'get'
-  })
-}
-// 查询所有消息
-export const getMessage = params => {
-  let url = `noticeUser/queryLike/${params.pageNo}/${params.pageSize}`
-  delete params.pageNo
-  delete params.pageSize
+// 手机号登录 校验用户账号状态
+export const checkCustomerState = params => { 
+  let url = `checkCustomerState/${params.phone}`
   return axios.request({
     url: url,
-    data: params,
-    method: 'post'
-  })
-}
-// 获取用户信息
-export const getUserInfo = params => {
-  return axios.request({
-    url: `user/userInfo`,
     method: 'get'
   })
 }

+ 443 - 0
components/address.vue

@@ -0,0 +1,443 @@
+<template>
+	<view class="simple-address" v-if="showPopup">
+		<!-- 遮罩层 -->
+		<view
+			class="simple-address-mask"
+			v-if="maskClick"
+			:class="[ani + '-mask', animation ? 'mask-ani' : '']"
+			:style="{
+				'background-color': maskBgColor
+			}"
+			@tap="hideMask(true)"
+		></view>
+		
+		<!-- 省市区 -->
+		<view class="simple-address-content simple-address--fixed" :class="[type, ani + '-content', animation ? 'content-ani' : '']">
+			<view class="simple-address__header">
+				<view class="simple-address__header-btn-box" @click="pickerCancel">
+					<text class="simple-address__header-text" :style="{ color: cancelColor, fontSize: btnFontSize }">取消</text>
+				</view>
+				<view class="simple-address__header-btn-box" @click="pickerConfirm">
+					<text class="simple-address__header-text" :style="{ color: confirmColor, fontSize: btnFontSize }">确定</text>
+				</view>
+			</view>
+			<view class="simple-address__box">
+				<picker-view class="simple-address-view" :value="pickerValue" @change="pickerChange">
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.name }}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in provinceDataList" :key="index">{{ item.name }}</text>
+						<!-- #endif -->
+					</picker-view-column>
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.name }}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in cityDataList" :key="index">{{ item.name }}</text>
+						<!-- #endif -->
+					</picker-view-column>
+					<picker-view-column>
+						<!-- #ifndef APP-NVUE -->
+						<view class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.name }}</view>
+						<!-- #endif -->
+						<!-- #ifdef APP-NVUE -->
+						<text class="picker-item" :style="{ fontSize: fontSize }" v-for="(item, index) in areaDataList" :key="index">{{ item.name }}</text>
+						<!-- #endif -->
+					</picker-view-column>
+				</picker-view>
+			</view>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+	import { getProvince, getCityByPro, getDistrictByCity } from '@/api/data.js'
+	export default{
+		name: 'Address',
+		props: {
+			// 是否允许点击遮罩层关闭
+			maskClick: {
+				type: Boolean,
+				default: true
+			},
+			// 是否开启动画
+			animation: {
+				type: Boolean,
+				default: true
+			},
+			//  遮罩层背景颜色
+			maskBgColor: {
+				type: String,
+				default: 'rgba(0, 0, 0, 0.4)' //背景颜色 rgba(0, 0, 0, 0.4) 为空则调用 uni.scss
+			},
+			/* 弹出层类型,可选值;  暂时只支持底部弹出
+					bottom:底部弹出层
+				*/
+			type: {
+				type: String,
+				default: 'bottom'
+			},
+			cancelColor: {
+				type: String,
+				default: '' // 取消按钮颜色
+			},
+			confirmColor: {
+				type: String,
+				default: '' // 确认按钮颜色
+			},
+			fontSize: {
+				type: String,
+				default: '28rpx' // picker-item字体大小
+			},
+			btnFontSize: {
+				type: String,
+				default: '' // 按钮的字体大小
+			},
+		},
+		data(){
+			return{
+				showPopup: false,  //  是否显示省市区选择
+				ani: '',
+				pickerValue: [0, 0, 0],  //  默认值下标
+				pickerId: [],  //  省市区默认值id
+				provinceDataList: [],  //  省数据列表
+				cityDataList: [],  //  市数据列表
+				areaDataList: [],  //  区数据列表
+				isFirst: false,  //  是否首次进入组件
+			}
+		},
+		methods: {
+			//  初始化
+			init(){
+				this.provinceDataList = []
+				this.cityDataList = []
+				this.areaDataList = []
+				this.isFirst = false
+			},
+			//  点击遮罩层关闭选择省市区
+			hideMask() {
+				this._$emit('onCancel')
+				this.close()
+			},
+			//  打开省市区picker
+			open(idArr) {
+				//  初始化数据
+				this.init()
+				this.pickerId = idArr
+				//  idArr 省市区默认id
+				if(this.pickerId && this.pickerId.length > 0){
+					//  获取省下拉
+					this.getProvinceList(idArr)
+				}else{
+					//  获取省下拉
+					this.getProvinceList()
+				}
+				this.showPopup = true
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.ani = 'simple-' + this.type
+					}, 100)
+				});
+			},
+			//  关闭省市区picker
+			close(type) {
+				if (!this.maskClick && type) return
+				this.ani = ''
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this.showPopup = false
+					}, 300)
+				})
+			},
+			//  取消按钮
+			pickerCancel() {
+				this._$emit('onCancel')
+				this.close()
+			},
+			//  确定按钮
+			pickerConfirm() {
+				this._$emit('onConfirm')
+				if(!this.isFirst){
+					//  首次
+					this.isFirst = true
+				}
+				this.close()
+			},
+			//  省市区  change
+			pickerChange(e) {
+				const _this = this
+				let changePickerValue = e.detail.value
+				
+				if (this.pickerValue[0] !== changePickerValue[0]) {
+					if(this.pickerId && this.pickerId.length > 0 && this.isFirst){
+						//  获取市下拉
+						this.getCityList(this.pickerId[0], this.pickerId)
+					}else{
+						// 第一级发生滚动,省 change重置市区下拉数据
+						this.getCityList(this.provinceDataList[changePickerValue[0]].id)
+						changePickerValue[1] = 0
+						changePickerValue[2] = 0
+					}
+				} else if (this.pickerValue[1] !== changePickerValue[1]) {
+					if(this.pickerId && this.pickerId.length > 0 && this.isFirst){
+						//  获取市下拉
+						this.getAreaList(this.pickerId[1], this.pickerId)
+					}else{
+						// 第二级滚动,市 change重置区县下拉数据
+						this.getAreaList(this.cityDataList[changePickerValue[1]].id)
+						changePickerValue[2] = 0
+					}
+				}
+				this.pickerValue = changePickerValue
+				//  setTimeout解决由于省市区接口请求数据有延缓导致获值报错
+				setTimeout(()=>{
+					_this._$emit('onChange')
+				},1000)
+			},
+			_$emit(emitName) {
+				let pickObj = {
+					label: this._getLabel(),
+					value: this.pickerValue,
+					cityCode: this._getCityCode(),
+					areaCode: this._getAreaCode(),
+					provinceCode: this._getProvinceCode(),
+					labelArr: this._getLabel().split('-')
+				}
+				this.$emit(emitName, pickObj)
+			},
+			_getLabel() {
+				//  name报错未发现页面影响(由于省市区接口请求数据延缓)
+				let pcikerLabel =
+					this.provinceDataList[this.pickerValue[0]].name + '-' + this.cityDataList[this.pickerValue[1]].name + '-' + this.areaDataList[this.pickerValue[2]].name
+				return pcikerLabel
+			},
+			_getCityCode() {
+				return this.cityDataList[this.pickerValue[1]].id
+			},
+			_getProvinceCode() {
+				return this.provinceDataList[this.pickerValue[0]].id
+			},
+			_getAreaCode() {
+				return this.areaDataList[this.pickerValue[2]].id
+			},
+			//  获取省下拉数据
+			getProvinceList(idArr){
+				const _this = this
+				getProvince().then(res => {
+				  if (res.code == 200 || res.status == 204 || res.status == 200) {
+				    _this.provinceDataList = res.data || []  //  省下拉数据
+					//  判断是否有默认值
+					if(idArr){
+						_this.getCityList(idArr[0], idArr)
+						_this.getAreaIndArr(idArr)
+					}else{
+						//  默认省数据第一条下的市下拉数据
+						_this.getCityList(_this.provinceDataList[0].id)
+					}
+					
+				  } else {
+				    _this.provinceDataList = []
+				  }
+				})
+			},
+			// 获取城市列表
+			getCityList (val, idArr) {
+				const _this = this
+				_this.cityDataList = []
+				_this.areaDataList = []
+				if (val != null && val != '') {
+					getCityByPro({id: val}).then(res => {
+						if (res.code == 200 || res.status == 204 || res.status == 200) {
+							_this.cityDataList = res.data || []  //  市下拉数据
+							//  判断是否有默认值
+							if(idArr){
+								_this.getAreaList(idArr[1], idArr)
+								_this.getAreaIndArr(idArr)
+							}else{
+								//  默认市数据第一条下的区县下拉数据
+								_this.getAreaList(_this.cityDataList[0].id)
+							}
+						} else {
+							_this.cityDataList = []
+						}
+					})
+				}
+			},
+			// 获取区县列表
+			getAreaList (val, idArr) {
+				const _this = this
+				this.areaDataList = []
+				if (val != null && val != '') {
+					getDistrictByCity({id: val}).then(res => {
+						if (res.code == 200 || res.status == 204 || res.status == 200) {
+							_this.areaDataList = res.data || []
+							//  判断是否有默认值
+							if(idArr){ _this.getAreaIndArr(idArr) }
+						} else {
+							_this.areaDataList = []
+						}
+					})
+				}
+			},
+			//  根据id 获取省市区 下标值
+			getAreaIndArr(idArr){
+				const _this = this
+				const provinceInd = _this.provinceDataList.findIndex(res => res['id'] == idArr[0])
+				const cityInd = _this.cityDataList.findIndex(res => res['id'] == idArr[1])
+				const districtInd = _this.areaDataList.findIndex(res => res['id'] == idArr[2])
+				setTimeout(()=>{
+					_this.pickerValue = [provinceInd, cityInd, districtInd]
+				},100)
+				// console.log(_this.pickerValue,'_this.pickerValue')
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+.simple-address {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: column;
+}
+
+.simple-address-mask {
+	position: fixed;
+	bottom: 0;
+	top: 0;
+	left: 0;
+	right: 0;
+
+	transition-property: opacity;
+	transition-duration: 0.3s;
+	opacity: 0;
+	/* #ifndef APP-NVUE */
+	z-index: 99999;
+	/* #endif */
+}
+
+.mask-ani {
+	transition-property: opacity;
+	transition-duration: 0.2s;
+}
+
+.simple-bottom-mask {
+	opacity: 1;
+}
+
+.simple-center-mask {
+	opacity: 1;
+}
+
+.simple-address--fixed {
+	position: fixed;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	width: 100%;
+	transition-property: transform;
+	transition-duration: 0.3s;
+	transform: translateY(460rpx);
+	/* #ifndef APP-NVUE */
+	z-index: 999999;
+	/* #endif */
+}
+
+.simple-address-content {
+	background-color: #ffffff;
+}
+
+.simple-content-bottom {
+	bottom: 0;
+	left: 0;
+	right: 0;
+	transform: translateY(500rpx);
+}
+
+.content-ani {
+	transition-property: transform, opacity;
+	transition-duration: 0.2s;
+}
+
+.simple-bottom-content {
+	transform: translateY(0);
+}
+
+.simple-center-content {
+	transform: scale(1);
+	opacity: 1;
+}
+
+.simple-address__header {
+	position: relative;
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	flex-wrap: nowrap;
+	justify-content: space-between;
+	border-bottom-color: #f2f2f2;
+	border-bottom-style: solid;
+	border-bottom-width: 1rpx;
+}
+
+.simple-address--fixed-top {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	justify-content: space-between;
+	border-top-color: $uni-border-color;
+	border-top-style: solid;
+	border-top-width: 1rpx;
+}
+
+.simple-address__header-btn-box {
+	/* #ifndef APP-NVUE */
+	display: flex;
+	/* #endif */
+	flex-direction: row;
+	align-items: center;
+	justify-content: center;
+	height: 70rpx;
+}
+
+.simple-address__header-text {
+	text-align: center;
+	font-size: $uni-font-size-base;
+	color: #1aad19;
+	line-height: 70rpx;
+	padding-left: 40rpx;
+	padding-right: 40rpx;
+}
+
+.simple-address__box {
+	position: relative;
+}
+
+.simple-address-view {
+	position: relative;
+	bottom: 0;
+	left: 0;
+	/* #ifndef APP-NVUE */
+	width: 100%;
+	/* #endif */
+	/* #ifdef APP-NVUE */
+	width: 750rpx;
+	/* #endif */
+	height: 408rpx;
+	background-color: rgba(255, 255, 255, 1);
+}
+
+.picker-item {
+	text-align: center;
+	line-height: 70rpx;
+	text-overflow: ellipsis;
+	font-size: 28rpx;
+}
+</style>

+ 721 - 0
components/almost-lottery/almost-lottery.vue

@@ -0,0 +1,721 @@
+<template>
+  <view class="almost-lottery" :style="{ width: canvasWidth + 40 + 'px', height: canvasHeight + 40 + 'px'}">
+    <view class="almost-lottery__wrap" :style="{width: canvasWidth + canvasMarginTotal + 'px', height: canvasHeight + canvasMarginTotal + 'px'}">
+      <!-- #ifdef MP-ALIPAY -->
+      <canvas :class="className" :id="canvasId" :width="canvasWidth" :height="canvasHeight" :style="{
+         width: canvasWidth + 'px',
+         height: canvasHeight + 'px'
+       }" />
+      <!-- #endif -->
+      <!-- #ifndef MP-ALIPAY -->
+      <canvas :class="className" :canvas-id="canvasId" :width="canvasWidth" :height="canvasHeight" :style="{
+         width: canvasWidth + 'px',
+         height: canvasHeight + 'px'
+       }" />
+      <!-- #endif -->
+      <image class="canvas-img" :src="lotteryImg" :style="{
+         width: canvasWidth + canvasMarginTotal + 'px',
+         height: canvasHeight + canvasMarginTotal + 'px',
+         transform: `rotate(${canvasAngle + targetAngle}deg)`,
+         transitionDuration: `${transitionDuration}s`
+       }"
+        v-if="lotteryImg"></image>
+      <view class="almost-lottery__action" :style="{
+         width: actionSize + 'px',
+         height: actionSize + 'px'
+       }" @click="handleActionStart"></view>
+      <!-- 为了兼容 app 端 ctx.measureText 所需的标签 -->
+      <text class="almost-lottery__measureText">{{ measureText }}</text>
+    </view>
+  </view>
+</template>
+
+<script>
+	import { pathToBase64 } from '@/almost-utils/image-tools.js'
+	import { getStore, setStore, clearStore, downloadFile } from '@/almost-utils/almost-utils.js'
+  export default {
+    name: 'AlmostLottery',
+    props: {
+      // canvas 宽度
+      canvasWidth: {
+        type: Number,
+        default: 240
+      },
+      // canvas 高度
+      canvasHeight: {
+        type: Number,
+        default: 240
+      },
+      // 奖品列表
+      prizeList: {
+        type: Array,
+        required: true,
+        validator: (value) => {
+          return value.length > 1
+        }
+      },
+      // 中奖奖品在列表中的下标
+      prizeIndex: {
+        type: Number,
+        required: true
+      },
+      // 奖品区块对应背景颜色
+      colors: {
+        type: Array,
+        default: () => [
+          '#FFFFFF',
+          '#FFE9AA'
+        ]
+      },
+      // 旋转动画时间 单位s
+      duration: {
+        type: Number,
+        default: 8
+      },
+      // 旋转的圈数
+      ringCount: {
+        type: Number,
+        default: 8
+      },
+      // 指针位置
+      pointerPosition: {
+        type: String,
+        default: 'edge',
+        validator: (value) => {
+          return value === 'edge' || value === 'middle'
+        }
+      },
+      // 字体颜色
+      fontColor: {
+        type: String,
+        default: '#C30B29'
+      },
+      // 文字的大小
+      fontSize: {
+        type: Number,
+        default: 12
+      },
+      // 奖品文字多行情况下的行高
+      lineHeight: {
+        type: Number,
+        default: 16
+      },
+      // 奖品名称所对应的 key 值
+      strKey: {
+        type: String,
+        default: 'name'
+      },
+      // 奖品文字总长度限制
+      strMaxLen: {
+        type: Number,
+        default: 12
+      },
+      // 奖品文字多行情况下第一行文字长度
+      strLineLen: {
+        type: Number,
+        default: 6
+      },
+      // 奖品图片的宽
+      imageWidth: {
+        type: Number,
+        default: 30
+      },
+      // 奖品图片的高
+      imageHeight: {
+        type: Number,
+        default: 30
+      },
+			// 转盘绘制成功的提示
+			successMsg: {
+				type: String,
+				default: '奖品准备就绪,快来参与抽奖吧'
+			},
+			// 转盘绘制失败的提示
+			failMsg: {
+				type: String,
+				default: '奖品仍在准备中,请稍后再来...'
+			},
+			// 是否开启画板的缓存
+			canvasCached: {
+				type: Boolean,
+				default: true
+			},
+			// 内圈与外圈的间距
+			canvasMargin: {
+        type: Number,
+        default: 5
+      }
+    },
+    data() {
+      return {
+        // 画板className
+        className: 'almost-lottery__canvas',
+        // 画板标识
+        canvasId: 'almostLotteryCanvas',
+        // 画板导出的图片
+        lotteryImg: '',
+        // 旋转到奖品目标需要的角度
+        targetAngle: 0,
+        // 旋转动画时间 单位 s
+        transitionDuration: 0,
+        // 是否正在旋转
+        isRotate: false,
+        // 当前停留在那个奖品的序号
+        stayIndex: 0,
+        // 当前中奖奖品的序号
+        targetIndex: 0,
+				// 是否存在可用的缓存转盘图
+				isCacheImg: false,
+				oldLotteryImg: '',
+        // 解决 app 不支持 measureText 的问题
+				// app 已在 2.9.3 的版本中提供了对 measureText 的支持,将在后续版本逐渐稳定后移除相关兼容代码
+        measureText: ''
+      }
+    },
+    computed: {
+      // 根据奖品列表计算 canvas 旋转角度
+      canvasAngle() {
+        let prizeCount = this.prizeList.length
+        let prizeClip = 360 / prizeCount
+        let result = 0
+
+        let diffNum = 90 / prizeClip
+        if (this.pointerPosition === 'edge') {
+          result = -(prizeClip * diffNum)
+        } else {
+          result = -(prizeClip * diffNum + prizeClip / 2)
+        }
+        return result
+      },
+      // 外圆的半径
+      outsideRadius() {
+        return this.canvasWidth / 2
+      },
+      // 内圆的半径
+      insideRadius() {
+        return 20
+      },
+      // 字体的半径
+      textRadius() {
+        return this.fontSize / 2
+      },
+      // 根据画板的宽度计算奖品文字与中心点的距离
+      textDistance() {
+        const textZeroY = Math.round(this.outsideRadius - (this.insideRadius / 2))
+        return textZeroY - this.textRadius
+      },
+      // 设备像素密度
+      pixelRatio() {
+        return uni.getSystemInfoSync().pixelRatio
+      },
+			// 内圈与外圈的距离
+			canvasMarginTotal () {
+				let diffNum = 5
+				let margin = this.canvasMargin * 2
+				if (this.canvasWidth > 240) {
+					return -(this.canvasWidth / 240 * 2) - margin
+				} else if (this.canvasWidth < 240) {
+					return diffNum + (this.canvasWidth / 240 * 2) - margin
+				} else {
+					return diffNum - margin
+				}
+			},
+			// 抽奖按钮的宽高
+			actionSize () {
+				return this.canvasWidth / 2.4
+			}
+    },
+    watch: {
+      // 监听获奖序号的变动
+      prizeIndex(newVal, oldVal) {
+        if (newVal > -1) {
+          this.targetIndex = newVal
+          this.onRotateStart()
+        } else {
+          console.info('旋转结束,prizeIndex 已重置')
+        }
+      }
+    },
+    methods: {
+	  resetAngle(){
+		  let prizeCount = this.prizeList.length
+		  let prizeClip = 360 / prizeCount
+		  this.targetAngle = this.targetAngle - prizeClip/2
+	  },
+      // 开始旋转
+      onRotateStart() {
+        if (this.isRotate) return
+        this.isRotate = true
+        // 奖品总数
+        let prizeCount = this.prizeList.length
+        let baseAngle = 360 / prizeCount
+        let angles = 0
+        if (this.targetAngle === 0) {
+          // 第一次旋转
+          // 因为第一个奖品是从0°开始的,即水平向右方向
+          // 第一次旋转角度 = 270度 - (停留的序号-目标序号) * 每个奖品区间角度 - 每个奖品区间角度的一半 - canvas自身旋转的度数
+          angles = (270 - (this.targetIndex - this.stayIndex) * baseAngle - baseAngle / 2) - this.canvasAngle
+        } else {
+          // 后续旋转
+          // 后续继续旋转 就只需要计算停留的位置与目标位置的角度
+          angles = -(this.targetIndex - this.stayIndex) * baseAngle
+        }
+        // 更新目前序号
+        this.stayIndex = this.targetIndex
+        // 转 8 圈,圈数越多,转的越快
+        this.targetAngle += angles + 360 * this.ringCount
+
+        // 计算转盘结束的时间,预加一些延迟确保转盘停止后触发结束事件
+        let endTime = this.transitionDuration * 1000 + 100
+        let endTimer = setTimeout(() => {
+          clearTimeout(endTimer)
+          endTimer = null
+
+          this.isRotate = false
+          this.$emit('draw-end')
+        }, endTime)
+
+        let resetPrizeTimer = setTimeout(() => {
+          clearTimeout(resetPrizeTimer)
+          resetPrizeTimer = null
+
+          // 每次抽奖结束后都要重置父级附件的 prizeIndex
+          this.$emit('reset-index')
+        }, endTime + 50)
+      },
+      // 点击 开始抽奖 按钮
+      handleActionStart() {
+        this.$emit('draw-start')
+      },
+      // 渲染转盘
+      async onCreateCanvas() {
+        // 获取 canvas 画布
+        const canvasId = this.canvasId
+        const ctx = uni.createCanvasContext(canvasId, this)
+
+        // canvas 的宽高
+        let canvasW = this.canvasWidth
+        let canvasH = this.canvasHeight
+
+        // 根据奖品个数计算 角度
+        let prizeCount = this.prizeList.length
+        let baseAngle = Math.PI * 2 / prizeCount
+
+        // 设置描边颜色
+        ctx.setStrokeStyle('#FFBE04')
+
+        // 设置字体和字号
+        // #ifndef MP
+        let fontFamily =
+          '-apple-system, BlinkMacSystemFont, \'PingFang SC\', \'Helvetica Neue\', STHeiti, \'Microsoft Yahei\', Tahoma, Simsun, sans-serif'
+        ctx.font = `${this.fontSize}px ${fontFamily}`
+        // #endif
+        // #ifdef MP
+        ctx.setFontSize(this.fontSize)
+        // #endif
+
+        // 注意,开始画的位置是从0°角的位置开始画的。也就是水平向右的方向。
+        // 画具体内容
+        for (let i = 0; i < prizeCount; i++) {
+					let prizeItem = this.prizeList[i]
+          // 当前角度
+          let angle = i * baseAngle
+
+          // 保存当前画布的状态
+          ctx.save()
+
+          // 开始画内容
+          ctx.beginPath()
+
+          // 开始画圆弧
+          // x => 圆弧对应的圆心横坐标 x
+          // y => 圆弧对应的圆心横坐标 y
+          // radius => 圆弧的半径大小
+          // startAngle => 圆弧开始的角度,单位是弧度
+          // endAngle => 圆弧结束的角度,单位是弧度
+          // anticlockwise(可选) => 绘制方向,true 为逆时针,false 为顺时针
+          ctx.arc(canvasW * 0.5, canvasH * 0.5, this.outsideRadius, angle, angle + baseAngle, false)
+          ctx.arc(canvasW * 0.5, canvasH * 0.5, this.insideRadius, angle + baseAngle, angle, true)
+
+          // 开始链接线条
+          ctx.stroke()
+          // 每个奖品区块背景填充颜色
+          if (this.colors.length === 2) {
+            ctx.setFillStyle(this.colors[i % 2])
+          } else {
+            ctx.setFillStyle(this.colors[i])
+          }
+          // 填充颜色
+          ctx.fill()
+
+          // 开始绘制奖品内容
+          // 重新映射画布上的 (0,0) 位置
+          let translateX = canvasW * 0.5 + Math.cos(angle + baseAngle / 2) * this.textDistance
+          let translateY = canvasH * 0.5 + Math.sin(angle + baseAngle / 2) * this.textDistance
+          ctx.translate(translateX, translateY)
+
+          // 绘制奖品名称
+          ctx.setFillStyle(this.fontColor)
+          let rewardName = this.strLimit(prizeItem[this.strKey])
+
+          // rotate方法旋转当前的绘图,因为文字是和当前扇形中心线垂直的
+          ctx.rotate(angle + (baseAngle / 2) + (Math.PI / 2))
+
+          // 设置文本位置并处理换行
+          // 是否需要换行
+          let isLineBreak = rewardName.length > this.strLineLen
+          let textOffsetX = this.fontSize === 12 ? 0 : this.textRadius
+          if (isLineBreak) {
+            // 获得多行文本数组
+            rewardName = rewardName.substring(0, this.strLineLen) + ',' + rewardName.substring(this.strLineLen)
+            let rewardNames = rewardName.split(',')
+
+            // 循环文本数组,计算每一行的文本宽度
+            for (let j = 0; j < rewardNames.length; j++) {
+              if (ctx.measureText && ctx.measureText(rewardNames[j]).width) {
+                // 文本的宽度信息
+                let tempStrSize = ctx.measureText(rewardNames[j])
+                ctx.fillText(rewardNames[j], -(tempStrSize.width / 2 + textOffsetX), j * this.lineHeight)
+              } else {
+                this.measureText = rewardNames[j]
+
+                // 等待页面重新渲染
+                await this.$nextTick()
+
+                let textWidth = await this.getTextWidth()
+
+                ctx.fillText(rewardNames[j], -(textWidth / 2 + textOffsetX), j * this.lineHeight)
+                // console.log(rewardNames[j], textWidth, i)
+              }
+            }
+          } else {
+            if (ctx.measureText && ctx.measureText(rewardName).width) {
+              // 文本的宽度信息
+              let tempStrSize = ctx.measureText(rewardName)
+              ctx.fillText(rewardName, -(tempStrSize.width / 2 + textOffsetX), 0)
+            } else {
+              this.measureText = rewardName
+
+              // 等待页面重新渲染
+              await this.$nextTick()
+
+              let textWidth = await this.getTextWidth()
+              ctx.fillText(rewardName, -(textWidth / 2 + textOffsetX), 0)
+            }
+          }
+
+          // 绘制奖品图片
+          if (prizeItem.prizeImage) {
+						// App-Android平台 系统 webview 更新到 Chrome84+ 后 canvas 组件绘制本地图像 uni.canvasToTempFilePath 会报错
+						// 统一将图片处理成 base64
+						// https://ask.dcloud.net.cn/question/103303
+						let reg = /^(https|http)/g
+						// 处理远程图片
+						if (reg.test(prizeItem.prizeImage)) {
+							console.warn('###当前数据列表中的奖品图片为网络图片,开始下载图片...###')
+							let res = await downloadFile(prizeItem.prizeImage)
+							console.log('处理远程图片', res)
+							if (res.ok) {
+								let tempFilePath = res.tempFilePath
+								// #ifndef MP
+								prizeItem.prizeImage = await pathToBase64(tempFilePath)
+								// #endif
+								// #ifdef MP
+								prizeItem.prizeImage = tempFilePath
+								// #endif
+							}
+						} else {
+							// #ifndef MP
+							prizeItem.prizeImage = await pathToBase64(prizeItem.prizeImage)
+							// #endif
+						}
+						
+            ctx.drawImage(prizeItem.prizeImage, -(this.imageWidth / 2), canvasW / 10, this.imageWidth, this.imageHeight)
+          }
+
+          ctx.restore()
+        }
+
+        // 保存绘图并导出图片
+        ctx.draw(true, () => {
+          let drawTimer = setTimeout(() => {
+            clearTimeout(drawTimer)
+            drawTimer = null
+
+            // #ifdef MP-ALIPAY
+            ctx.toTempFilePath({
+              destWidth: this.canvasWidth * this.pixelRatio,
+              destHeight: this.canvasHeight * this.pixelRatio,
+              success: (res) => {
+                // console.log(res.apFilePath)
+                this.handlePrizeImg({
+									ok: true,
+									data: res.apFilePath,
+									msg: '画布导出生成图片成功'
+								})
+              },
+							fail: (err) => {
+                this.handlePrizeImg({
+									ok: false,
+									data: err,
+									msg: '画布导出生成图片失败'
+								})
+							}
+            })
+            // #endif
+            // #ifndef MP-ALIPAY
+            uni.canvasToTempFilePath({
+              destWidth: this.canvasWidth * this.pixelRatio,
+              destHeight: this.canvasHeight * this.pixelRatio,
+              canvasId: this.canvasId,
+              success: (res) => {
+                // 在 H5 平台下,tempFilePath 为 base64
+                // console.log(res.tempFilePath)
+                this.handlePrizeImg({
+									ok: true,
+									data: res.tempFilePath,
+									msg: '画布导出生成图片成功'
+								})
+              },
+							fail: (err) => {
+                this.handlePrizeImg({
+									ok: false,
+									data: err,
+									msg: '画布导出生成图片失败'
+								})
+							}
+            }, this)
+            // #endif
+          }, 500)
+        })
+      },
+      // 处理导出的图片
+      handlePrizeImg(res) {
+				if (res.ok) {
+					let data = res.data
+					
+					if (!this.canvasCached) {
+						this.lotteryImg = data
+						this.handlePrizeImgSuc(res)
+						return
+					}
+					
+					// #ifndef H5
+					if (this.isCacheImg) {
+						uni.getSavedFileList({
+							success: (sucRes) => {
+								let fileList = sucRes.fileList
+								// console.log('getSavedFileList Cached', fileList)
+								
+								let cached = false
+								for (let i = 0; i < fileList.length; i++) {
+									let item = fileList[i]
+									if (item.filePath === data) {
+										cached = true
+										this.lotteryImg = data
+										
+										console.info('经查,本地缓存中存在转盘图可用,本次将不再绘制转盘')
+										this.handlePrizeImgSuc(res)
+										break
+									}
+								}
+								
+								if (!cached) {
+									console.info('经查,本地缓存中存在转盘图不可用,需要重新初始化转盘绘制')
+									this.initCanvasDraw()
+								}
+							},
+							fail: (err) => {
+								this.initCanvasDraw()
+							}
+						})
+					} else {
+						uni.saveFile({
+							tempFilePath: data,
+							success: (sucRes) => {
+								let filePath = sucRes.savedFilePath
+								// console.log('saveFile', filePath)
+								setStore('lotteryImg', filePath)
+								this.lotteryImg = filePath
+								this.handlePrizeImgSuc({
+									ok: true,
+									data: filePath,
+									msg: '画布导出生成图片成功'
+								})
+							},
+							fail: (err) => {
+								this.handlePrizeImg({
+									ok: false,
+									data: err,
+									msg: '画布导出生成图片失败'
+								})
+							}
+						})
+					}
+					// #endif
+					// #ifdef H5
+					console.info('当前为 H5 端,直接使用导出的/缓存中的 base64 图')
+					setStore('lotteryImg', data)
+					this.lotteryImg = data
+					this.handlePrizeImgSuc(res)
+					// #endif
+				} else {
+					console.error('处理导出的图片失败', res)
+					uni.hideLoading()
+					// #ifdef H5
+					console.error('###当前为 H5 端,下载网络图片需要后端配置允许跨域###')
+					// #endif
+					// #ifdef MP
+					console.error('###当前为小程序端,下载网络图片需要配置域名白名单###')
+					// #endif
+				}
+      },
+			// 处理图片完成
+			handlePrizeImgSuc (res) {
+				uni.hideLoading()
+				this.$emit('finish', {
+					ok: res.ok,
+					data: res.data,
+					msg: res.ok ? this.successMsg : this.failMsg
+				})
+			},
+      // 兼容 app 端不支持 ctx.measureText
+      // 已知问题:初始绘制时,低端安卓机 平均耗时 2s
+      getTextWidth() {
+        return new Promise((resolve, reject) => {
+          uni.createSelectorQuery().in(this).select('.almost-lottery__measureText').fields({
+            size: true,
+          }, (res) => {
+            resolve(res.width)
+          }).exec()
+        })
+      },
+      // 处理文字溢出
+      strLimit(value) {
+        let maxLength = this.strMaxLen
+        if (!value || !maxLength) return value
+        return value.length > maxLength ? value.slice(0, maxLength - 1) + '...' : value
+      },
+			// 检查本地缓存中是否存在转盘图
+			checkCacheImg () {
+				console.log('检查本地缓存中是否存在转盘图')
+				// 检查是否已有缓存的转盘图
+				// 检查是否与本次奖品数据相同
+				this.oldLotteryImg = getStore('lotteryImg')
+				let oldPrizeList = getStore('prizeList')
+				let newPrizeList = JSON.stringify(this.prizeList)
+				if (this.oldLotteryImg) {
+					if (oldPrizeList === newPrizeList) {
+						console.log(`经查,本地缓存中存在转盘图 => ${this.oldLotteryImg}`)
+						this.isCacheImg = true
+						
+						console.log('需要继续判断这张缓存图是否可用')
+						this.handlePrizeImg({
+							ok: true,
+							data: this.oldLotteryImg,
+							msg: '画布导出生成图片成功'
+						})
+						return
+					}
+				}
+				
+				console.log('经查,本地缓存中不存在转盘图')
+				this.initCanvasDraw()
+			},
+      // 初始化绘制
+      initCanvasDraw () {
+				console.log('开始初始化转盘绘制')
+				this.isCacheImg = false
+				this.lotteryImg = ''
+				clearStore('lotteryImg')
+        setStore('prizeList', this.prizeList)
+        this.onCreateCanvas()
+      }
+    },
+    mounted() {
+      this.$nextTick(() => {
+        let stoTimer = setTimeout(() => {
+          clearTimeout(stoTimer)
+          stoTimer = null
+					
+					if (this.canvasCached) {
+						this.checkCacheImg()
+					} else {
+						this.onCreateCanvas()
+					}
+          this.transitionDuration = this.duration
+        }, 50)
+      })
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+  $lotteryBgUrl: '~static/almost-lottery/almost-lottery__bg';
+  $actionBgUrl: '~static/almost-lottery/almost-lottery__action';
+
+  .almost-lottery {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    margin: 0 auto;
+    background-repeat: no-repeat;
+    background-position: center center;
+    background-size: contain;
+    background-image: url($lotteryBgUrl + ".png");
+
+    @media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) {
+      background-image: url($lotteryBgUrl + "2x.png");
+    }
+
+    @media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3) {
+      background-image: url($lotteryBgUrl + "3x.png");
+    }
+  }
+	
+	.almost-lottery__wrap {
+    position: relative;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+	}
+
+  .almost-lottery__canvas {
+    position: absolute;
+    left: -9999px;
+    opacity: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+
+  .almost-lottery__action {
+    position: absolute;
+    background-repeat: no-repeat;
+    background-position: center center;
+    background-size: contain;
+    background-image: url($actionBgUrl + ".png");
+
+    @media (-webkit-min-device-pixel-ratio: 2), (min-device-pixel-ratio: 2) {
+      background-image: url($actionBgUrl + "2x.png");
+    }
+
+    @media (-webkit-min-device-pixel-ratio: 3), (min-device-pixel-ratio: 3) {
+      background-image: url($actionBgUrl + "3x.png");
+    }
+  }
+
+  .almost-lottery__measureText {
+    position: absolute;
+    left: 0;
+    top: 0;
+    white-space: nowrap;
+    font-size: 12px;
+    opacity: 0;
+  }
+
+  .canvas-img {
+		display: block;
+    transition: transform cubic-bezier(.34, .12, .05, .95);
+  }
+</style>

+ 5 - 6
components/m-input.vue

@@ -6,8 +6,10 @@
 		<view v-if="clearable&&!displayable&&value.length" class="m-input-icon">
 			<uni-icons color="#666666" type="clear" @click="clear"></uni-icons>
 		</view>
-		<view v-if="displayable" class="m-input-icon">
-			<uni-icons :style="{color:showPassword?'#666666':'#cccccc'}" type="eye" @click="display"></uni-icons>
+		<view v-if="displayable" class="m-input-icon" @click="display">
+			<u-icon v-show="showPassword" name="eye-fill" size="30"></u-icon>
+			<u-icon v-show="!showPassword" name="eye-off" size="30"></u-icon>
+			<!-- <uni-icons :style="{color:showPassword?'#666666':'#cccccc'}" type="eye" @click="display"></uni-icons> -->
 		</view>
 	</view>
 </template>
@@ -105,7 +107,6 @@
 		/* width: 100%; */
 		flex: 1;
 		padding: 0 10px;
-		margin-top: 20rpx;
 	}
 
 	.m-input-input {
@@ -117,9 +118,7 @@
 	}
 
 	.m-input-icon {
-		width: 20px;
-		font-size: 20px;
-		line-height: 20px;
 		color: #666666;
+		padding: 10upx 20upx;
 	}
 </style>

+ 0 - 142
components/uni-navbar/uni-navbar.vue

@@ -1,142 +0,0 @@
-<template>
-	<view class="navbar custom-class" :style="{ 'height': navHeight+'px' }">
-	  <view class="navbar-action-wrap navbar-action-group row item-center" :style="{'top': navTop+'px'}">
-			<view v-if="isBack" class="navbar-action_item" @tap="navBack">
-				<u-icon name="arrow-left" color="#2979ff" size="28"></u-icon>
-			</view>
-			<view v-if="isMap" class="navbar-action_item last map-bar" @tap="toMap">
-				<u-image class="map-icon" width="24rpx" height="36rpx" src="/static/map-icon.png"></u-image>
-				<view class="item-label">清运地图</view>
-			</view>
-	  </view>
-	  <view class='navbar-title' :style="{'top': navTop+'px'}">
-	    {{pageName}}
-	  </view>
-	</view>
-</template>
-
-<script>
-	export default {
-		props: {
-			pageName: String,
-			showNav:{
-			  type: Boolean,
-			  value: true
-			},
-			bgColor: {
-			  type: String,
-			  value: '#fff'
-			},
-			isBack: {
-				type: Boolean,
-				value: false
-			},
-			isMap: {
-				type: Boolean,
-				value: false
-			}
-		},
-		mounted() {
-			let menuButtonObject = wx.getMenuButtonBoundingClientRect()
-			const _this = this
-			wx.getSystemInfo({
-			  success (res) {
-				let statusBarHeight = res.statusBarHeight,
-				navTop = menuButtonObject.top,//胶囊按钮与顶部的距离
-				navHeight = statusBarHeight + menuButtonObject.height + (menuButtonObject.top - statusBarHeight)*2;//导航高度
-				_this.navHeight = navHeight;
-				_this.navTop = navTop;
-				_this.windowHeight = res.windowHeight;
-			  }
-			})
-		},
-		data() {
-			return {
-				navHeight: '',
-				navTop: '',
-				windowHeight: ''
-			}
-		},
-		methods: {
-			//回退
-			navBack: function () {
-				uni.navigateBack({
-				  delta: 1
-				})      
-			},
-			//配送地图
-			toMap: function () {
-				uni.navigateTo({
-					url: '/pages/index/map'
-				})
-			}
-		}
-	}
-</script>
-
-<style lang="scss" scoped>
-	.navbar {
-	  width: 100%;
-	  overflow: hidden;
-	  position: relative;
-	  top: 0;
-	  left: 0;
-	  z-index: 10;
-	  flex-shrink: 0;
-	  .navbar-action-wrap {
-	    display: -webkit-flex;
-	    display: flex;
-	    -webkit-box-align: center;
-	    -ms-flex-align: center;
-	    -webkit-align-items: center;
-	    align-items: center;
-	    position: absolute;
-	    left: 10px;
-	    z-index: 11;
-	    line-height: 1;
-	    padding-top: 8px;
-	    padding-bottom: 4px;
-	  }
-	  .navbar-action-group {
-	    overflow: hidden;
-		.navbar-action_item {
-		  border-right: 1px solid #f0f0f0;
-		  color: #333;
-		}
-		.last {
-		  border-right: none;
-		}
-		.map-bar{
-			text-align: center;
-			.map-icon{
-				display: inline-block;
-				margin-right: 10rpx;
-			}
-			.item-label{
-				display: inline-block;
-				font-size: 24rpx;
-				vertical-align: text-top;
-				color: #07c160;
-			}
-		}
-	  }
-	  .navbar-title {
-	    width: 100%;
-	    box-sizing: border-box;
-	    padding-left: 115px;
-	    padding-right: 115px;
-	    height: 32px;
-	    line-height: 32px;
-	    text-align: center;
-	    position: absolute;
-	    left: 0;
-	    z-index: 10;
-	    color: #333;
-	    font-size: 16px;
-	    font-weight: bold;
-	    text-overflow: ellipsis;
-	    overflow: hidden;
-	    white-space: nowrap;
-	  }
-	}
-</style>

+ 178 - 0
components/uni-numbers-box/uni-numbers-box.vue

@@ -0,0 +1,178 @@
+<template>
+	<view class="uni-numbox">
+		<view @click="_calcValue('minus')" class="uni-numbox__minus">
+			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }">-</text>
+		</view>
+		<input :disabled="disabled" @blur="_onBlur" class="uni-numbox__value" type="number" v-model="inputValue" />
+		<view @click="_calcValue('plus')" class="uni-numbox__plus">
+			<text class="uni-numbox--text" :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }">+</text>
+		</view>
+	</view>
+</template>
+<script>
+	export default {
+		name: "UniNumbersBox",
+		props: {
+			index:{
+				type: String,
+				default: ''
+			},
+			value: {
+				type: [Number, String],
+				default: 1
+			},
+			min: {
+				type: Number,
+				default: 0
+			},
+			max: {
+				type: Number,
+				default: 100
+			},
+			step: {
+				type: Number,
+				default: 1
+			},
+			disabled: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				inputValue: this.value
+			};
+		},
+		watch: {
+			value(newVal,oldVal) {
+				console.log(newVal,oldVal,'000')
+				this.inputValue = +newVal;
+			},
+			inputValue(newVal, oldVal) {
+				if (+newVal !== +oldVal && this.max >= +newVal && this.min <= +newVal) {
+					this.$emit("change", newVal, this.index);
+				}
+			}
+		},
+		created() {
+			this.inputValue = +this.value;
+		},
+		methods: {
+			_calcValue(type) {
+				if (this.disabled) {
+					return;
+				}
+				const scale = this._getDecimalScale();
+				let value = this.inputValue * scale;
+				let step = this.step * scale;
+				if (type === "minus") {
+					value -= step;
+					if (value < this.min) {
+						return;
+					}
+					if(value > this.max){
+						value = this.max
+					}
+				} else if (type === "plus") {
+					value += step;
+					if (value > this.max) {
+						return;
+					}
+					if(value < this.min){
+						value = this.min
+					}
+				}
+
+				this.inputValue = String(value / scale);
+				this.$emit('input',this.inputValue)
+			},
+			_getDecimalScale() {
+				let scale = 1;
+				// 浮点型
+				if (~~this.step !== this.step) {
+					scale = Math.pow(10, (this.step + "").split(".")[1].length);
+				}
+				return scale;
+			},
+			_onBlur(event) {
+				let value = event.detail.value;
+				if (!value) {
+					this.inputValue = this.min;
+				}
+				value = +value;
+				if (value > this.max) {
+					value = this.max;
+				} else if (value < this.min) {
+					value = this.min;
+				}
+				this.inputValue = value;
+				this.$emit('input',this.inputValue)
+			},
+		}
+	};
+</script>
+<style lang="scss" scoped>
+	$box-height: 30px;
+	/* #ifdef APP-NVUE */
+	$box-line-height: 30px;
+	/* #endif */
+	$box-line-height: 26px;
+	$box-width: 30px;
+
+	.uni-numbox {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		width: 120px;
+	}
+
+	.uni-numbox__value {
+		background-color: $uni-bg-color;
+		width: 40px;
+		height: $box-height;
+		line-height: $box-height;
+		text-align: center;
+		font-size: $uni-font-size-lg;
+		margin: 0 10px;
+	}
+
+	.uni-numbox__minus {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		width: $box-width;
+		height: $box-height;
+		line-height: $box-height;
+		font-size: 20px;
+		color: $uni-text-color;
+		background-color: $uni-bg-color-grey;
+		border-radius: $box-width;
+	}
+
+	.uni-numbox__plus {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		width: $box-width;
+		height: $box-height;
+		line-height: $box-height;
+		background-color: $uni-bg-color-grey;
+		border-radius: $box-width;
+	}
+
+	.uni-numbox--text {
+		font-size: 36rpx;
+		color: $uni-text-color;
+	}
+
+	.uni-numbox--disabled {
+		color: $uni-text-color-disable;
+	}
+</style>

+ 122 - 0
components/uni-popup/image-txt-popup.vue

@@ -0,0 +1,122 @@
+<template>
+	<view class="image-txt-wrap">
+		<image :src="captchaBase" class="image" @click="getCode"></image>
+		<text class="tip-txt">* 点击图片即可切换验证码</text>
+		<input v-model="captcha" @input="inpChange" class="item-inp" name="captcha" type="text" maxlength="4" placeholder="请输入上方的图形验证码" />
+		<button :type="btnType" size="mini" class="popup-button-yz" @click="verify">验证</button>
+	</view>
+</template>
+
+<script>
+	import { getCaptcha } from '@/api/user.js'
+	export default{
+		name: 'ImageTxtPopup',
+		props: {
+			changeImg: {
+				type: Boolean,
+				default: false
+			},
+			//  applyImageTxt申请试用   forgetImageTxt忘记密码
+			type: {
+				type: String,
+				default: ''
+			},
+		},
+		watch: {
+			changeImg(newV, oldV){
+				if(newV === true){
+					this.getCode()
+				}
+			}
+		},
+		data(){
+			return{
+				captchaBase: '',  //  图片验证码base64
+				captcha: '',  //  图文验证码
+				nowRandomCode: '',  // 当前随机码
+				btnType: 'default',  //  验证按钮type
+			}
+		},
+		created() {
+			// this.getCode()
+		},
+		methods: {
+			//  获取验证码
+			getCode(){
+			  const _this = this
+			  //  6位随机数
+			  this.nowRandomCode = Math.random().toString().slice(-6)
+			  getCaptcha(this.nowRandomCode).then(res => {
+				// console.log(res.data)
+			    //  获取图片路径
+			    _this.captchaBase = 'data:image/png;base64,' + res.data
+			    // 显示图文验证码弹框
+			    _this.captcha = ''  //  清空图文输入内容
+			  })
+			},
+			//  验证码输入监听
+			inpChange(){
+				if(this.captcha.length == 4){
+					this.btnType = 'primary'
+				}else{
+					this.btnType = 'default'
+				}
+			},
+			//  验证
+			verify(){
+				if(!this.captcha){
+					uni.showToast({icon: 'none',title: '请输入上方的图形验证码'})
+					return
+				}else{
+					if(this.captcha.length != 4){
+						uni.showToast({icon: 'none',title: '请输入4位图形验证码'})
+						return
+					}
+					this.$emit('captchaImg', this.captcha, this.nowRandomCode)
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.image-txt-wrap{
+		line-height: 1.8;
+		.tip-txt{
+			display: block;
+			font-size: 24upx;
+			color: #999;
+			margin-bottom: 40upx;
+			text-align: center;
+		}
+		.item-inp{
+			background-color: #fff;
+			border: 2upx solid #dcdee2;
+			border-radius: 8upx;
+			color: #666;
+			display: inline-block;
+			font-size: 24upx;
+			height: 64upx;
+			line-height: 1.5;
+			padding: 8upx 14upx;
+			width: 100%;
+			box-sizing: border-box;
+		}
+		.image{
+			max-width: 100%;
+			width: 400upx;
+			height: 160upx;
+			margin: 30upx auto 20upx;
+			display: block;
+			img{
+				max-width: 100%;
+			}
+		}
+		.popup-button-yz{
+			display: block;
+			margin: 40upx auto 50upx;
+			width: 30%;
+			line-height: 2.8;
+		}
+	}
+</style>

+ 22 - 0
components/uni-popup/message.js

@@ -0,0 +1,22 @@
+export default {
+	created() {
+		if (this.type === 'message') {
+			// 不显示遮罩
+			this.maskShow = false 
+			// 获取子组件对象
+			this.childrenMsg = null
+		}
+	},
+	methods: {
+		customOpen() {
+			if (this.childrenMsg) {
+				this.childrenMsg.open()
+			}
+		},
+		customClose() {
+			if (this.childrenMsg) {
+				this.childrenMsg.close()
+			}
+		}
+	}
+}

+ 96 - 0
components/uni-popup/popup-con.vue

@@ -0,0 +1,96 @@
+<template>
+	<view class="popup-con">
+		<text class="popup-header">{{title}}</text>
+		<view class="popup-content">
+			<image-txt-popup :type="type" :changeImg="changeImg" @captchaImg="captchaImg"></image-txt-popup>
+		</view>
+		<view class="popup-footer">
+			<text class="popup-button" v-for="(item, index) in popBtn" :key="index" :style="{ color: item.color }">{{item.name}}</text>
+		</view>
+	</view>
+</template>
+
+<script>
+	import imageTxtPopup from '@/components/uni-popup/image-txt-popup.vue'
+	export default{
+		name: 'PopupCon',
+		props: {
+			//  applyImageTxt申请试用   forgetImageTxt忘记密码
+			type: {
+				type: String,
+				default: ''
+			},
+			title: {
+				type: String,
+				default: '标题'
+			},
+			//  操作按钮
+			popBtn: {
+				type: Array,
+				default: function (){
+				  return []
+				}
+			},
+			changeImg: {
+				type: Boolean,
+				default: false
+			}
+		},
+		components: {
+			imageTxtPopup
+		},
+		data(){
+			return{}
+		},
+		methods: {
+			captchaImg(captcha, nowRandomCode){
+				this.$emit('captchaImg', captcha, nowRandomCode)
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.popup-con{
+		box-sizing: border-box;
+		position: absolute;
+		top: 50%;
+		left: 50%;
+		transform: translate(-50%, -50%);
+		box-shadow: 0 8upx 24upx rgba(0,0,0,.15);
+		display: flex;
+		flex-direction: column;
+		padding: 30upx;
+		width: 600upx;
+		background-color: #fff;
+		border-radius: 20upx;
+		.popup-header{
+			margin-bottom: 20upx;
+			text-align: center;
+			font-weight: 700;
+			font-size: 32upx;
+			color: #333;
+			line-height: 1.8;
+		}
+		.popup-content{
+			font-size: 28upx;
+			color: #666;
+		}
+		.popup-footer{
+			display: flex;
+			flex-direction: row;
+			margin-top: 40upx;
+			.popup-button{
+				flex: 1;
+				text-align: center;
+				font-size: 28upx;
+				color: #3b4144;
+				line-height: 1.8;
+			}
+			.popup-confirm{
+				color: #57a3f3;
+			}
+		}
+	}
+	
+</style>

+ 25 - 0
components/uni-popup/popup.js

@@ -0,0 +1,25 @@
+import message from './message.js';
+// 定义 type 类型:弹出类型:top/bottom/center
+const config = {
+	// 顶部弹出
+	top:'top',
+	// 底部弹出
+	bottom:'bottom',
+	// 居中弹出
+	center:'center',
+	// 消息提示
+	message:'top',
+	// 对话框
+	dialog:'center',
+	// 分享
+	share:'bottom',
+}
+
+export default {
+	data(){
+		return {
+			config:config
+		}
+	},
+	mixins: [message],
+}

+ 244 - 0
components/uni-popup/uni-popup-dialog.vue

@@ -0,0 +1,244 @@
+<template>
+	<view class="uni-popup-dialog">
+		<view class="uni-dialog-title">
+			<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{title}}</text>
+		</view>
+		<view class="uni-dialog-content">
+			<text class="uni-dialog-content-text" v-if="mode === 'base'">{{content}}</text>
+			<input v-else class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholder" :focus="focus" >
+		</view>
+		<view class="uni-dialog-button-group">
+			<view class="uni-dialog-button" @click="close">
+				<text class="uni-dialog-button-text">取消</text>
+			</view>
+			<view class="uni-dialog-button uni-border-left" @click="onOk">
+				<text class="uni-dialog-button-text uni-button-color">确定</text>
+			</view>
+		</view>
+
+	</view>
+</template>
+
+<script>
+	/**
+	 * PopUp 弹出层-对话框样式
+	 * @description 弹出层-对话框样式
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} value input 模式下的默认值
+	 * @property {String} placeholder input 模式下输入提示
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} mode = [base|input] 模式、
+	 * 	@value base 基础对话框
+	 * 	@value input 可输入对话框
+	 * @property {String} content 对话框内容
+	 * @property {Boolean} beforeClose 是否拦截取消事件
+	 * @event {Function} confirm 点击确认按钮触发
+	 * @event {Function} close 点击取消按钮触发
+	 */
+
+	export default {
+		name: "uniPopupDialog",
+		props: {
+			value: {
+				type: [String, Number],
+				default: ''
+			},
+			placeholder: {
+				type: [String, Number],
+				default: '请输入内容'
+			},
+			/**
+			 * 对话框主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'error'
+			},
+			/**
+			 * 对话框模式 base/input
+			 */
+			mode: {
+				type: String,
+				default: 'base'
+			},
+			/**
+			 * 对话框标题
+			 */
+			title: {
+				type: String,
+				default: '提示'
+			},
+			/**
+			 * 对话框内容
+			 */
+			content: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 拦截取消事件 ,如果拦截取消事件,必须监听close事件,执行 done()
+			 */
+			beforeClose: {
+				type: Boolean,
+				default: false
+			}
+		},
+		data() {
+			return {
+				dialogType: 'error',
+				focus: false,
+				val: ""
+			}
+		},
+		inject: ['popup'],
+		watch: {
+			type(val) {
+				this.dialogType = val
+			},
+			mode(val) {
+				if (val === 'input') {
+					this.dialogType = 'info'
+				}
+			},
+			value(val) {
+				this.val = val
+			}
+		},
+		created() {
+			// 对话框遮罩不可点击
+			this.popup.mkclick = false
+			if (this.mode === 'input') {
+				this.dialogType = 'info'
+				this.val = this.value
+			} else {
+				this.dialogType = this.type
+			}
+		},
+		mounted() {
+			this.focus = true
+		},
+		methods: {
+			/**
+			 * 点击确认按钮
+			 */
+			onOk() {
+				this.$emit('confirm', () => {
+					this.popup.close()
+					if (this.mode === 'input') this.val = this.value
+				}, this.mode === 'input' ? this.val : '')
+			},
+			/**
+			 * 点击取消按钮
+			 */
+			close() {
+				if (this.beforeClose) {
+					this.$emit('close', () => {
+						this.popup.close()
+					})
+					return
+				}
+				this.popup.close()
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.uni-popup-dialog {
+		width: 300px;
+		border-radius: 15px;
+		background-color: #fff;
+	}
+
+	.uni-dialog-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		padding-top: 15px;
+		padding-bottom: 5px;
+	}
+
+	.uni-dialog-title-text {
+		font-size: 16px;
+		font-weight: 500;
+	}
+
+	.uni-dialog-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		padding: 5px 15px 15px 15px;
+	}
+
+	.uni-dialog-content-text {
+		font-size: 14px;
+		color: #222;
+	}
+
+	.uni-dialog-button-group {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		border-top-color: #f5f5f5;
+		border-top-style: solid;
+		border-top-width: 1px;
+	}
+
+	.uni-dialog-button {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+
+		flex: 1;
+		flex-direction: row;
+		justify-content: center;
+		align-items: center;
+		height: 45px;
+	}
+
+	.uni-border-left {
+		border-left-color: #f0f0f0;
+		border-left-style: solid;
+		border-left-width: 1px;
+	}
+
+	.uni-dialog-button-text {
+		font-size: 14px;
+		color:#A6A6A6
+	}
+
+	.uni-button-color {
+		color: #0DC55F;
+	}
+
+	.uni-dialog-input {
+		flex: 1;
+		font-size: 14px;
+	}
+
+	.uni-popup__success {
+		color: $uni-color-success;
+	}
+
+	.uni-popup__warn {
+		color: $uni-color-warning;
+	}
+
+	.uni-popup__error {
+		color: $uni-color-error;
+	}
+
+	.uni-popup__info {
+		color: #909399;
+	}
+</style>

+ 116 - 0
components/uni-popup/uni-popup-message.vue

@@ -0,0 +1,116 @@
+<template>
+	<view class="uni-popup-message" :class="'uni-popup__'+[type]">
+		<text class="uni-popup-message-text" :class="'uni-popup__'+[type]+'-text'">{{message}}</text>
+	</view>
+</template>
+
+<script>
+	
+	/**
+	 * PopUp 弹出层-消息提示
+	 * @description 弹出层-消息提示
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} type = [success|warning|info|error] 主题样式
+	 *  @value success 成功
+	 * 	@value warning 提示
+	 * 	@value info 消息
+	 * 	@value error 错误
+	 * @property {String} message 消息提示文字
+	 * @property {String} duration 显示时间,设置为 0 则不会自动关闭
+	 */
+	
+	export default {
+		name: 'UniPopupMessage',
+		props: {
+			/**
+			 * 主题 success/warning/info/error	  默认 success
+			 */
+			type: {
+				type: String,
+				default: 'success'
+			},
+			/**
+			 * 消息文字
+			 */
+			message: {
+				type: String,
+				default: ''
+			},
+			/**
+			 * 显示时间,设置为 0 则不会自动关闭
+			 */
+			duration: {
+				type: Number,
+				default: 3000
+			}
+		},
+		inject: ['popup'],
+		data() {
+			return {}
+		},
+		created() {
+			this.popup.childrenMsg = this
+		},
+		methods: {
+			open() {
+				if (this.duration === 0) return
+				clearTimeout(this.popuptimer)
+				this.popuptimer = setTimeout(() => {
+					this.popup.close()
+				}, this.duration)
+			},
+			close() {
+				clearTimeout(this.popuptimer)
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup-message {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		background-color: #e1f3d8;
+		padding: 10px 15px;
+		border-color: #eee;
+		border-style: solid;
+		border-width: 1px;
+	}
+	.uni-popup-message-text {
+		font-size: 14px;
+		padding: 0;
+	}
+
+	.uni-popup__success {
+		background-color: #e1f3d8;
+	}
+
+	.uni-popup__success-text {
+		color: #67C23A;
+	}
+
+	.uni-popup__warn {
+		background-color: #faecd8;
+	}
+
+	.uni-popup__warn-text {
+		color: #E6A23C;
+	}
+
+	.uni-popup__error {
+		background-color: #fde2e2;
+	}
+
+	.uni-popup__error-text {
+		color: #F56C6C;
+	}
+
+	.uni-popup__info {
+		background-color: #F2F6FC;
+	}
+
+	.uni-popup__info-text {
+		color: #909399;
+	}
+</style>

+ 165 - 0
components/uni-popup/uni-popup-share.vue

@@ -0,0 +1,165 @@
+<template>
+	<view class="uni-popup-share">
+		<view class="uni-share-title"><text class="uni-share-title-text">{{title}}</text></view>
+		<view class="uni-share-content">
+			<view class="uni-share-content-box">
+				<view class="uni-share-content-item" v-for="(item,index) in bottomData" :key="index" @click.stop="select(item,index)">
+					<image class="uni-share-image" :src="item.icon" mode="aspectFill"></image>
+					<text class="uni-share-text">{{item.text}}</text>
+				</view>
+
+			</view>
+		</view>
+		<view class="uni-share-button-box">
+			<button class="uni-share-button" @click="close">取消</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		name: 'UniPopupShare',
+		props: {
+			title: {
+				type: String,
+				default: '分享到'
+			}
+		},
+		inject: ['popup'],
+		data() {
+			return {
+				bottomData: [{
+						text: '微信',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-2.png',
+						name: 'wx'
+					},
+					{
+						text: '支付宝',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-8.png',
+						name: 'wx'
+					},
+					{
+						text: 'QQ',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/gird-3.png',
+						name: 'qq'
+					},
+					{
+						text: '新浪',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-1.png',
+						name: 'sina'
+					},
+					{
+						text: '百度',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-7.png',
+						name: 'copy'
+					},
+					{
+						text: '其他',
+						icon: 'https://img-cdn-qiniu.dcloud.net.cn/uni-ui/grid-5.png',
+						name: 'more'
+					}
+				]
+			}
+		},
+		created() {},
+		methods: {
+			/**
+			 * 选择内容
+			 */
+			select(item, index) {
+				this.$emit('select', {
+					item,
+					index
+				}, () => {
+					this.popup.close()
+				})
+			},
+			/**
+			 * 关闭窗口
+			 */
+			close() {
+				this.popup.close()
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup-share {
+		background-color: #fff;
+	}
+	.uni-share-title {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+		height: 40px;
+	}
+	.uni-share-title-text {
+		font-size: 14px;
+		color: #666;
+	}
+	.uni-share-content {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		justify-content: center;
+		padding-top: 10px;
+	}
+	
+	.uni-share-content-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		flex-wrap: wrap;
+		width: 360px;
+	}
+	
+	.uni-share-content-item {
+		width: 90px;
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: column;
+		justify-content: center;
+		padding: 10px 0;
+		align-items: center;
+	}
+	
+	.uni-share-content-item:active {
+		background-color: #f5f5f5;
+	}
+	
+	.uni-share-image {
+		width: 30px;
+		height: 30px;
+	}
+	
+	.uni-share-text {
+		margin-top: 10px;
+		font-size: 14px;
+		color: #3B4144;
+	}
+	
+	.uni-share-button-box {
+		/* #ifndef APP-NVUE */
+		display: flex;
+		/* #endif */
+		flex-direction: row;
+		padding: 10px 15px;
+	}
+	
+	.uni-share-button {
+		flex: 1;
+		border-radius: 50px;
+		color: #666;
+		font-size: 16px;
+	}
+	
+	.uni-share-button::after {
+		border-radius: 50px;
+	}
+</style>

+ 295 - 0
components/uni-popup/uni-popup.vue

@@ -0,0 +1,295 @@
+<template>
+	<view v-if="showPopup" class="uni-popup" :class="[popupstyle]" @touchmove.stop.prevent="clear">
+		<uni-transition v-if="maskShow" :mode-class="['fade']" :styles="maskClass" :duration="duration" :show="showTrans"
+		 @click="onTap" />
+		<uni-transition :mode-class="ani" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
+			<view class="uni-popup__wrapper-box" @click.stop="clear">
+				<slot />
+			</view>
+		</uni-transition>
+	</view>
+</template>
+
+<script>
+	import uniTransition from '../uni-transition/uni-transition.vue'
+	import popup from './popup.js'
+	/**
+	 * PopUp 弹出层
+	 * @description 弹出层组件,为了解决遮罩弹层的问题
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=329
+	 * @property {String} type = [top|center|bottom] 弹出方式
+	 * 	@value top 顶部弹出
+	 * 	@value center 中间弹出
+	 * 	@value bottom 底部弹出
+	 * 	@value message 消息提示
+	 * 	@value dialog 对话框
+	 * 	@value share 底部分享示例
+	 * @property {Boolean} animation = [ture|false] 是否开启动画
+	 * @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
+	 * @event {Function} change 打开关闭弹窗触发,e={show: false}
+	 */
+
+	export default {
+		name: 'UniPopup',
+		components: {
+			uniTransition
+		},
+		props: {
+			// 开启动画
+			animation: {
+				type: Boolean,
+				default: true
+			},
+			// 弹出层类型,可选值,top: 顶部弹出层;bottom:底部弹出层;center:全屏弹出层
+			// message: 消息提示 ; dialog : 对话框
+			type: {
+				type: String,
+				default: 'center'
+			},
+			// maskClick
+			maskClick: {
+				type: Boolean,
+				default: true
+			}
+		},
+		provide() {
+			return {
+				popup: this
+			}
+		},
+		mixins: [popup],
+		watch: {
+			/**
+			 * 监听type类型
+			 */
+			type: {
+				handler: function(newVal) {
+					this[this.config[newVal]]()
+				},
+				immediate: true
+			},
+			/**
+			 * 监听遮罩是否可点击
+			 * @param {Object} val
+			 */
+			maskClick(val) {
+				this.mkclick = val
+				this.$emit("close")
+			}
+		},
+		data() {
+			return {
+				duration: 300,
+				ani: [],
+				showPopup: false,
+				showTrans: false,
+				maskClass: {
+					'position': 'fixed',
+					'bottom': 0,
+					'top': 0,
+					'left': 0,
+					'right': 0,
+					'backgroundColor': 'rgba(0, 0, 0, 0.4)'
+				},
+				transClass: {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+				},
+				maskShow: true,
+				mkclick: true,
+				popupstyle: 'top'
+			}
+		},
+		created() {
+			this.mkclick = this.maskClick
+			if (this.animation) {
+				this.duration = 300
+			} else {
+				this.duration = 0
+			}
+		},
+		methods: {
+			clear(e) {
+				// TODO nvue 取消冒泡
+				e.stopPropagation()
+			},
+			open() {
+				this.showPopup = true
+				this.$nextTick(() => {
+					new Promise(resolve => {
+						clearTimeout(this.timer)
+						this.timer = setTimeout(() => {
+							this.showTrans = true
+							// fixed by mehaotian 兼容 app 端
+							this.$nextTick(() => {
+								resolve();
+							})
+						}, 50);
+					}).then(res => {
+						// 自定义打开事件
+						clearTimeout(this.msgtimer)
+						this.msgtimer = setTimeout(() => {
+							this.customOpen && this.customOpen()
+						}, 100)
+						this.$emit('change', {
+							show: true,
+							type: this.type
+						})
+					})
+				})
+			},
+			close(type) {
+				this.showTrans = false
+				this.$nextTick(() => {
+					this.$emit('change', {
+						show: false,
+						type: this.type
+					})
+					clearTimeout(this.timer)
+					// 自定义关闭事件
+					this.customOpen && this.customClose()
+					this.timer = setTimeout(() => {
+						this.showPopup = false
+					}, 300)
+				})
+			},
+			onTap() {
+				if (!this.mkclick) return
+				this.close()
+			},
+			/**
+			 * 顶部弹出样式处理
+			 */
+			top() {
+				this.popupstyle = 'top'
+				this.ani = ['slide-top']
+				this.transClass = {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+				}
+			},
+			/**
+			 * 底部弹出样式处理
+			 */
+			bottom() {
+				this.popupstyle = 'bottom'
+				this.ani = ['slide-bottom']
+				this.transClass = {
+					'position': 'fixed',
+					'left': 0,
+					'right': 0,
+					'bottom': 0
+				}
+			},
+			/**
+			 * 中间弹出样式处理
+			 */
+			center() {
+				this.popupstyle = 'center'
+				this.ani = ['zoom-out', 'fade']
+				this.transClass = {
+					'position': 'fixed',
+					/* #ifndef APP-NVUE */
+					'display': 'flex',
+					'flexDirection': 'column',
+					/* #endif */
+					'bottom': 0,
+					'left': 0,
+					'right': 0,
+					'top': 0,
+					'justifyContent': 'center',
+					'alignItems': 'center'
+				}
+			}
+		}
+	}
+</script>
+<style lang="scss" scoped>
+	.uni-popup {
+		position: fixed;
+		/* #ifndef APP-NVUE */
+		z-index: 99;
+		/* #endif */
+	}
+
+	.uni-popup__mask {
+		position: absolute;
+		top: 0;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		background-color: $uni-bg-color-mask;
+		opacity: 0;
+	}
+
+	.mask-ani {
+		transition-property: opacity;
+		transition-duration: 0.2s;
+	}
+
+	.uni-top-mask {
+		opacity: 1;
+	}
+
+	.uni-bottom-mask {
+		opacity: 1;
+	}
+
+	.uni-center-mask {
+		opacity: 1;
+	}
+
+	.uni-popup__wrapper {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		position: absolute;
+	}
+
+	.top {
+		/* #ifdef H5 */
+		top: var(--window-top);
+		/* #endif */
+		/* #ifndef H5 */
+		top: 0;
+		/* #endif */
+	}
+
+	.bottom {
+		bottom: 0;
+	}
+
+	.uni-popup__wrapper-box {
+		/* #ifndef APP-NVUE */
+		display: block;
+		/* #endif */
+		position: relative;
+		/* iphonex 等安全区设置,底部安全区适配 */
+		/* #ifndef APP-NVUE */
+		padding-bottom: constant(safe-area-inset-bottom);
+		padding-bottom: env(safe-area-inset-bottom);
+		/* #endif */
+	}
+
+	.content-ani {
+		// transition: transform 0.3s;
+		transition-property: transform, opacity;
+		transition-duration: 0.2s;
+	}
+
+
+	.uni-top-content {
+		transform: translateY(0);
+	}
+
+	.uni-bottom-content {
+		transform: translateY(0);
+	}
+
+	.uni-center-content {
+		transform: scale(1);
+		opacity: 1;
+	}
+</style>

+ 279 - 0
components/uni-transition/uni-transition.vue

@@ -0,0 +1,279 @@
+<template>
+	<view v-if="isShow" ref="ani" class="uni-transition" :class="[ani.in]" :style="'transform:' +transform+';'+stylesObject"
+	 @click="change">
+		 <slot></slot>
+	</view>
+</template>
+
+<script>
+	// #ifdef APP-NVUE
+	const animation = uni.requireNativePlugin('animation');
+	// #endif
+	/**
+	 * Transition 过渡动画
+	 * @description 简单过渡动画组件
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=985
+	 * @property {Boolean} show = [false|true] 控制组件显示或隐藏
+     * @property {Array} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
+     *  @value fade 渐隐渐出过渡
+     *  @value slide-top 由上至下过渡
+     *  @value slide-right 由右至左过渡
+     *  @value slide-bottom 由下至上过渡
+     *  @value slide-left 由左至右过渡
+     *  @value zoom-in 由小到大过渡
+     *  @value zoom-out 由大到小过渡
+	 * @property {Number} duration 过渡动画持续时间
+	 * @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
+	 */
+	export default {
+		name: 'uniTransition',
+		props: {
+			show: {
+				type: Boolean,
+				default: false
+			},
+			modeClass: {
+				type: Array,
+				default () {
+					return []
+				}
+			},
+			duration: {
+				type: Number,
+				default: 300
+			},
+			styles: {
+				type: Object,
+				default () {
+					return {}
+				}
+			}
+		},
+		data() {
+			return {
+				isShow: false,
+				transform: '',
+				ani: { in: '',
+					active: ''
+				}
+			};
+		},
+		watch: {
+			show: {
+				handler(newVal) {
+					if (newVal) {
+						this.open()
+					} else {
+						this.close()
+					}
+				},
+				immediate: true
+			}
+		},
+		computed: {
+			stylesObject() {
+				let styles = {
+					...this.styles,
+					'transition-duration': this.duration / 1000 + 's'
+				}
+				let transfrom = ''
+				for (let i in styles) {
+					let line = this.toLine(i)
+					transfrom += line + ':' + styles[i] + ';'
+				}
+				return transfrom
+			}
+		},
+		created() {
+			// this.timer = null
+			// this.nextTick = (time = 50) => new Promise(resolve => {
+			// 	clearTimeout(this.timer)
+			// 	this.timer = setTimeout(resolve, time)
+			// 	return this.timer
+			// });
+		},
+		methods: {
+			change() {
+				this.$emit('click', {
+					detail: this.isShow
+				})
+			},
+			open() {
+				clearTimeout(this.timer)
+				this.isShow = true
+				this.transform = ''
+				this.ani.in = ''
+				for (let i in this.getTranfrom(false)) {
+					if (i === 'opacity') {
+						this.ani.in = 'fade-in'
+					} else {
+						this.transform += `${this.getTranfrom(false)[i]} `
+					}
+				}
+				this.$nextTick(() => {
+					setTimeout(() => {
+						this._animation(true)
+					}, 50)
+				})
+
+			},
+			close(type) {
+				clearTimeout(this.timer)
+				this._animation(false)
+			},
+			_animation(type) {
+				let styles = this.getTranfrom(type)
+				// #ifdef APP-NVUE
+				if(!this.$refs['ani']) return
+				animation.transition(this.$refs['ani'].ref, {
+					styles,
+					duration: this.duration, //ms
+					timingFunction: 'ease',
+					needLayout: false,
+					delay: 0 //ms
+				}, () => {
+					if (!type) {
+						this.isShow = false
+					}
+					this.$emit('change', {
+						detail: this.isShow
+					})
+				})
+				// #endif
+				// #ifndef APP-NVUE
+				this.transform = ''
+				for (let i in styles) {
+					if (i === 'opacity') {
+						this.ani.in = `fade-${type?'out':'in'}`
+					} else {
+						this.transform += `${styles[i]} `
+					}
+				}
+				this.timer = setTimeout(() => {
+					if (!type) {
+						this.isShow = false
+					}
+					this.$emit('change', {
+						detail: this.isShow
+					})
+
+				}, this.duration)
+				// #endif
+
+			},
+			getTranfrom(type) {
+				let styles = {
+					transform: ''
+				}
+				this.modeClass.forEach((mode) => {
+					switch (mode) {
+						case 'fade':
+							styles.opacity = type ? 1 : 0
+							break;
+						case 'slide-top':
+							styles.transform += `translateY(${type?'0':'-100%'}) `
+							break;
+						case 'slide-right':
+							styles.transform += `translateX(${type?'0':'100%'}) `
+							break;
+						case 'slide-bottom':
+							styles.transform += `translateY(${type?'0':'100%'}) `
+							break;
+						case 'slide-left':
+							styles.transform += `translateX(${type?'0':'-100%'}) `
+							break;
+						case 'zoom-in':
+							styles.transform += `scale(${type?1:0.8}) `
+							break;
+						case 'zoom-out':
+							styles.transform += `scale(${type?1:1.2}) `
+							break;
+					}
+				})
+				return styles
+			},
+			_modeClassArr(type) {
+				let mode = this.modeClass
+				if (typeof(mode) !== "string") {
+					let modestr = ''
+					mode.forEach((item) => {
+						modestr += (item + '-' + type + ',')
+					})
+					return modestr.substr(0, modestr.length - 1)
+				} else {
+					return mode + '-' + type
+				}
+			},
+			// getEl(el) {
+			// 	console.log(el || el.ref || null);
+			// 	return el || el.ref || null
+			// },
+			toLine(name) {
+				return name.replace(/([A-Z])/g, "-$1").toLowerCase();
+			}
+		}
+	}
+</script>
+
+<style>
+	.uni-transition {
+		transition-timing-function: ease;
+		transition-duration: 0.3s;
+		transition-property: transform, opacity;
+	}
+
+	.fade-in {
+		opacity: 0;
+	}
+
+	.fade-active {
+		opacity: 1;
+	}
+
+	.slide-top-in {
+		/* transition-property: transform, opacity; */
+		transform: translateY(-100%);
+	}
+
+	.slide-top-active {
+		transform: translateY(0);
+		/* opacity: 1; */
+	}
+
+	.slide-right-in {
+		transform: translateX(100%);
+	}
+
+	.slide-right-active {
+		transform: translateX(0);
+	}
+
+	.slide-bottom-in {
+		transform: translateY(100%);
+	}
+
+	.slide-bottom-active {
+		transform: translateY(0);
+	}
+
+	.slide-left-in {
+		transform: translateX(-100%);
+	}
+
+	.slide-left-active {
+		transform: translateX(0);
+		opacity: 1;
+	}
+
+	.zoom-in-in {
+		transform: scale(0.8);
+	}
+
+	.zoom-out-active {
+		transform: scale(1);
+	}
+
+	.zoom-out-in {
+		transform: scale(1.2);
+	}
+</style>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 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>

+ 6 - 21
libs/axios.js

@@ -21,6 +21,7 @@ const request = (opts, hasToken) => {
 	let promise = new Promise(function(resolve, reject) {
 		uni.request(DefaultOpts).then(
 			(res) => {
+				console.log(res,'pppp')
 				if(res[0]&&res[0].errMsg.indexOf('request:fail')>=0){
 					resolve({
 						status: 6000,
@@ -37,27 +38,11 @@ const request = (opts, hasToken) => {
 					resolve(ret)
 				}else{
 					if(ret.status != '401'){
-						setTimeout(()=>{  //  通过延时避免uni.hideLoading()关闭加载中状态时同时关闭提示信息
-							uni.showToast({
-								icon:'none',
-								title: ret.message,
-								mask: true,
-								duration: 5000 
-							})
-						}, 1000)
-					}else{
-						setTimeout(()=>{
-							uni.showToast({
-								icon:'none',
-								title: '未登录或登录已过期,请重新登录',
-								duration: 5000 
-							})
-						}, 500)
-						setTimeout(function() {
-						  const currentRoute = getRoutePath()
-						  const url = `/pages/login/login?lanuch=${currentRoute.lanuch}&path=` + encodeURIComponent(currentRoute.url)
-						  uni.redirectTo({ url })
-						}, 1000);
+						uni.showToast({
+							icon:'none',
+							title: ret.message,
+							mask: true
+						})
 					}
 					resolve(ret)
 				}

+ 95 - 0
libs/getDate.js

@@ -0,0 +1,95 @@
+// 引入 moment 时间插件
+import moment from 'moment'
+// 获取今日/昨日/本周/上周/本月/上月 时间
+export default {
+  // 获取今日的开始结束时间
+  getToday () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().startOf('day').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取昨日的开始结束时间
+  getYesterday () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().add(-1, 'days').startOf('day').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().add(-1, 'days').endOf('day').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  //  近7天
+  getRecentday () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment().subtract('days', 6).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取当前周的开始到当天结束时间
+  getCurrWeekDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().week(moment().week()).startOf('week').add('days').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取上一周的开始结束时间
+  getLastWeekDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().week(moment().week() - 1).startOf('week').add('days').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().week(moment().week() - 1).endOf('week').add('days').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取当前月的开始到当天结束时间
+  getCurrMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month()).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取上一个月的开始结束时间
+  getLastMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month() - 1).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().month(moment().month() - 1).endOf('month').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取上2个月的开始结束时间
+  getLastTwoMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month() - 2).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().month(moment().month() - 2).endOf('month').valueOf()).format('YYYY-MM-DD')
+    return obj
+  },
+  // 获取近3个月到今天的开始结束时间
+  getThreeMonthDays () {
+    const obj = {
+      starttime: '',
+      endtime: ''
+    }
+    obj.starttime = moment(moment().month(moment().month() - 2).startOf('month').valueOf()).format('YYYY-MM-DD')
+    obj.endtime = moment(moment().valueOf()).format('YYYY-MM-DD')
+    return obj
+  }
+}

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 0
libs/qqmap-wx-jssdk.min.js


+ 41 - 0
libs/tools.js

@@ -24,6 +24,47 @@ export function parseQueryString(url) {
     }
     return obj;
 }
+// 保存图片到阿里云
+export const saveImgToAliOss = function(src,callback){
+	console.log(src,getApp().globalData.baseUrl,'getApp().globalData.baseUrl')
+	const authorization = getApp().globalData.token
+	uni.uploadFile({
+		url: getApp().globalData.baseUrl + 'upload/', //自行修改各自的对应的接口 
+		filePath: src,
+		name: 'file',
+		header: {'X-AUTH-TOKEN':authorization},
+		success: (uploadFileRes) => {
+			if (uploadFileRes) {
+				let res = JSON.parse(uploadFileRes.data);
+				callback(res)
+			}
+			uni.showToast({
+				icon: 'none',
+				title: uploadFileRes ? '保存图片成功' : '保存图片失败'
+			})
+		},
+		fail:(error) => {
+			console.log(error)
+		}
+	});
+}
+// 小数点后两位
+export const numberToFixed = function (val, num, max) {
+  let maxNums = max || 100000000
+  let _value = val + ''
+  _value = _value.replace(/[^\d.]/g, '')// 清楚数字和.以外的字数
+  _value = _value.replace(/^\./g, '')
+  _value = _value.replace(/\.{2,}/g, '')// 保留第一个,清楚多余的
+
+  if (num == 1)_value = _value.replace(/^(\-)*(\d+)\.(\d).*$/, '$1$2.$3')
+  else if (num == 3)_value = _value.replace(/^(\-)*(\d+)\.(\d\d\d).*$/, '$1$2.$3')
+  else if (num == 4)_value = _value.replace(/^(\-)*(\d+)\.(\d\d\d\d).*$/, '$1$2.$3')
+  else if (num == 5)_value = _value.replace(/^(\-)*(\d+)\.(\d\d\d\d\d).*$/, '$1$2.$3')
+  else if (num == 0)_value = _value.indexOf('.') >= 0 ? _value.split('.')[0] : _value
+  else _value = _value.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3')
+  // console.log(_value,maxNums,Number(_value)>Number(maxNums),'_value')
+  return Number(_value)>Number(maxNums) ? maxNums : _value
+}
 
 
   

+ 1 - 29
main.js

@@ -9,35 +9,7 @@ Vue.use(uView)
 
 let vuexStore = require("@/store/$u.mixin.js")
 Vue.mixin(vuexStore)
-/*
-* 提示信息
-*/ 
-Vue.prototype.toashMsg = function (title) {
-	title = title == undefined ? "系统繁忙" : title;
-	uni.showToast({
-		title:title,
-		icon:'none',
-		duration: 2000
-	})
-}
-/**
- * 权限检查
- */
-Vue.prototype.$hasPermissions = function (value) {
- let isExist = false;
- let permissionsStr = store.state.vuex_userData.permCodes;
- // console.log(permissionsStr,'permissionsStr')
- if (permissionsStr == undefined || permissionsStr == null) {
-  return false;
- }
- let has = permissionsStr.find(item => {
-   return item == value
- })
- if (has) {
-  isExist = true;
- }
- return isExist;
-}
+
 const app = new Vue({
 	store,
     ...App

+ 4 - 4
manifest.json

@@ -1,7 +1,7 @@
 {
-    "name" : "乐色管家清运端",
-    "appid" : "__UNI__D3A9765",
-    "description" : "乐色管家清运端小程序",
+    "name" : "乐色超人(骑手端)",
+    "appid" : "__UNI__778E110",
+    "description" : "乐色超人(骑手端)小程序",
     "versionName" : "1.0.0",
     "versionCode" : "100",
     "transformPx" : false,
@@ -57,7 +57,7 @@
     "quickapp" : {},
     /* 小程序特有相关 */
     "mp-weixin" : {
-        "appid" : "wxd38fd339f957b425",
+        "appid" : "wxc0af8df4c4a03f3f",
         "setting" : {
             "urlCheck" : false,
             "es6" : true,

+ 47 - 4
package-lock.json

@@ -1,13 +1,56 @@
 {
-  "name": "zxyj-cust-mini-html",
+  "name": "zxyj-rider-mini-html",
   "version": "1.0.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
+    "charenc": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+      "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
+    },
+    "crypt": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+      "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
+    },
+    "extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+    },
+    "md5": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
+      "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
+      "requires": {
+        "charenc": "0.0.2",
+        "crypt": "0.0.2",
+        "is-buffer": "~1.1.6"
+      }
+    },
+    "moment": {
+      "version": "2.29.1",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+      "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ=="
+    },
     "uview-ui": {
-      "version": "1.7.8",
-      "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.7.8.tgz",
-      "integrity": "sha512-9mc3FbpvN7knmmdBmlGv9eF6us16co/bvTPrFEsS8QrSo9AZyrFyET9KHIdESwURP79jv1SLtR01VEb3HGSN8A=="
+      "version": "1.7.9",
+      "resolved": "https://registry.npmjs.org/uview-ui/-/uview-ui-1.7.9.tgz",
+      "integrity": "sha512-YSZvz69Yt/7qoJohc9+tWVQsb4fUiE30OnvTZhUA0H+SkxhQXK6MgNsmL/lZ7RVqFLwawQBzDths2ReluvFOcA=="
+    },
+    "weapp-qrcode": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/weapp-qrcode/-/weapp-qrcode-1.0.0.tgz",
+      "integrity": "sha512-4sa3W0rGDVJ9QaeZpAKlAuUxVyjhDwiUqHyGK/jJMsRMXnhb4yO8qWU/pZruMo+iT5J6CraS67lDMFb1VY+RaA==",
+      "requires": {
+        "extend": "^3.0.2"
+      }
     }
   }
 }

+ 8 - 4
package.json

@@ -1,5 +1,5 @@
 {
-  "name": "zxyj-cust-mini-html",
+  "name": "zxyj-rider-mini-html",
   "version": "1.0.0",
   "description": "",
   "main": "main.js",
@@ -8,12 +8,16 @@
   },
   "repository": {
     "type": "git",
-    "url": "http://git.chelingzhu.com/chelingzhu-web/zxyj-cust-mini-html.git"
+    "url": "http://git.chelingzhu.com/chelingzhu-web/zxyj-rider-mini-html.git"
   },
   "keywords": [],
   "author": "",
   "license": "ISC",
   "dependencies": {
-    "uview-ui": "^1.7.7"
-  }
+    "md5": "^2.3.0",
+    "moment": "^2.29.1",
+    "uview-ui": "^1.7.9",
+    "weapp-qrcode": "^1.0.0"
+  },
+  "devDependencies": {}
 }

+ 26 - 46
pages.json

@@ -4,68 +4,48 @@
 	},
 	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
 		{
-			"path": "pages/index/index", // 待清运
+			"path": "pages/index/index", // 首页
 			"style": {
-				"navigationBarTitleText": "待清运清单",
-				"enablePullDownRefresh": false,
-				"navigationStyle": "custom"
-			}
-		},
-		{
-			"path": "pages/login/login",
-			"style": {
-				"navigationBarTitleText": "登录"
-			}
-		},
-		{
-			"path": "pages/login/pwLogin",
-			"style": {
-				"navigationBarTitleText": "密码登录"
-			}
-		},
-		{
-			"path": "pages/index/map",
-			"style": {
-				"navigationBarTitleText": "清运地图"
+				"navigationBarTitleText": "乐色超人",
+				"enablePullDownRefresh": false
 			}
 		},
 		{
-			"path": "pages/cleared/chooseNetwork",
+			"path": "pages/index/addData",
 			"style": {
-				"navigationBarTitleText": "待清运网点"
+				"navigationBarTitleText": "垃圾数据录入"
 			}
 		},
 		{
-			"path": "pages/cleared/network",
+			"path": "pages/login/login",
 			"style": {
-				"navigationBarTitleText": "网点详情"
+				"navigationBarTitleText": "授权登录"
 			}
 		},
 		{
-			"path": "pages/cleared/index", // 已清运
+			"path": "pages/login/phoneLogin",
 			"style": {
-				"navigationBarTitleText": "已清运",
-				"enablePullDownRefresh": false
+				"navigationBarTitleText": "手机号登录"
 			}
 		},
 		{
-			"path": "pages/cleared/details", // 已清运详情
+			"path": "pages/userCenter/index",
 			"style": {
-				"navigationBarTitleText": "详情"
+				"navigationBarTitleText": "个人中心",
+				"navigationBarBackgroundColor": "#0DC55F",
+				"navigationBarTextStyle": "white"
 			}
 		},
 		{
-			"path": "pages/userCenter/index",
+			"path": "pages/userCenter/aboutUs",
 			"style": {
-				"navigationBarTitleText": "个人中心",
-				"navigationBarBackgroundColor": "#01c9b2",
-				"navigationBarTextStyle": "white"
+				"navigationBarTitleText": "关于我们"
 			}
 		},
 		{
 			"path": "pages/agreement/agreement",
 			"style": {
-				"navigationBarTitleText": "注意事项及服务协议"
+				"navigationBarTitleText": "用户协议及隐私政策"
 			}
 		},
 		{
@@ -88,22 +68,22 @@
 	},
 	"tabBar": {
 		"color": "#7A7E83",
-		"selectedColor": "#01c9b2",
+		"selectedColor": "##0DC55F",
 		"backgroundColor": "#ffffff",
 		"fontSize": "14px",
 		"list": [
 		{
 			"pagePath": "pages/index/index",
-			"iconPath": "static/tabbar/unclean.png",
-			"selectedIconPath": "static/tabbar/unclean-active.png",
-			"text": "待清运"
-		},
-		{
-			"pagePath": "pages/cleared/index",
-			"iconPath": "static/tabbar/cleared.png",
-			"selectedIconPath": "static/tabbar/cleared-active.png",
-			"text": "已清运"
+			"iconPath": "static/index/logo.png",
+			"selectedIconPath": "static/index/logo-active.png",
+			"text": "首页"
 		},
+		 {
+		 	"pagePath": "pages/index/index",
+		 	"iconPath": "static/index/logo.png",
+		 	"selectedIconPath": "static/index/logo-active.png",
+		 	"text": "订单"
+		 },
 		{
 			"pagePath": "pages/userCenter/index",
 			"iconPath": "static/tabbar/user.png",

+ 2 - 2
pages/agreement/agreement.vue

@@ -2,10 +2,10 @@
 	<view class="content">
 		<view class="page-content">
 			<view class="page-care agreement">
-				<view class="title">-乐色管家清运端用户服务协议(声明)-</view>
+				<view class="title">-分类垃圾录入端用户服务协议(声明)-</view>
 				<view class="xy-cons">
 					<view class="MsoNormal">
-						“乐色管家清运端用户小程序”(以下简称“用户小程序”)由陕西智享亿家环保科技有限公司(以下简称“本公司”)提供。用户在登录用户小程序时,均被视为已经仔细阅读本条款并完全同意。凡以任何方式登录本用户小程序,包括但不限于接受用户小程序服务、直接或间接使用本用户小程序资料、第三方链接等,均被视为自愿接受本用户小程序相关声明和用户服务协议的约束。
+						“分类垃圾录入端用户小程序”(以下简称“用户小程序”)由陕西智享亿家环保科技有限公司(以下简称“本公司”)提供。用户在登录用户小程序时,均被视为已经仔细阅读本条款并完全同意。凡以任何方式登录本用户小程序,包括但不限于接受用户小程序服务、直接或间接使用本用户小程序资料、第三方链接等,均被视为自愿接受本用户小程序相关声明和用户服务协议的约束。
 					</view>
 					<view class="MsoNormal">
 						一、用户小程序使用

+ 0 - 345
pages/cleared/chooseNetwork.vue

@@ -1,345 +0,0 @@
-<template>
-	<view class="choose-network-container">
-		<!-- 筛选弹框 -->
-		<search-modal v-if="openScreen" :visible="openScreen" :defaultParams="searchForm" @refresh="refresh" @close="openScreen=false"></search-modal>
-		<view class="choose-network-header">
-			<view class="checked-all">
-				<u-checkbox
-					v-if="listdata.length>0"
-					class="checked-all-c"
-					active-color="#01c9b2"
-					@change="checkedAll" 
-					v-model="isCheckedAll"
-					label-size="26"
-					name="checkedAll"
-				>全选</u-checkbox>
-			</view>
-			<view class="choose-checked" @tap="openScreen=true">
-				已选:<text>{{checkedList.length}}</text>
-				<image class="filter-icon" src="@/static/filter.png"></image>
-			</view>
-		</view>
-		<scroll-view class="scroll-con" scroll-y :scroll-top="scrollTop" @scrolltolower="onreachBottom">
-			<!-- 列表数据 -->
-			<u-checkbox-group class="cell-item-con">
-				<view class="cell-item" v-for="(item, index) in listdata" :key="index">
-					<view class="cell-item-c">
-						<u-checkbox
-							class="cell-item-checkbox"
-							@change="checkboxChange($event, index)"
-							active-color="#01c9b2"
-							v-model="item.checked"
-							:name="item.id">
-							<view class="cell-item-info">
-								<view class="cell-item-info-network">
-									{{item.stationName || '--'}}
-									<u-badge type="success" bgColor="#c90101" :count="item.unCleanNum" :offset="[-10,-32]" size="mini"></u-badge>
-								</view>
-								<view class="cell-item-info-weight">
-									<view class="cell-item-weight-bar">
-										{{ item.totalWeight }}kg
-										<u-badge class="badge" type="primary" bgColor="#01c9b2" count="总" :offset="[0,0]"></u-badge>
-									</view>
-									<view class="cell-item-weight-bar">
-										{{ item.maxWeight }}kg
-										<u-badge class="badge" type="warning" bgColor="#05695d" count="最大" :offset="[0,0]"></u-badge>
-									</view>
-								</view>
-							</view>
-						</u-checkbox>
-						<view class="details-con" @tap="goPage(item)">
-							<u-icon name="arrow-right" class="arrow-right" :size="28" color="#999"></u-icon>
-						</view>
-					</view>
-				</view>
-			</u-checkbox-group>
-			<u-empty class="nodata" :text="noDataText" v-if="listdata.length==0 && status!='loading'" mode="list"></u-empty>
-			<view class="loadmore" v-if="listdata.length!=0">
-				<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
-			</view>
-		</scroll-view>
-		<view class="footer-bar">
-			<u-button class="footer-handle-btn handle-btn" hover-class="none" :custom-style="btnStyle" shape="circle" @click="handleAdd" size="medium" type="primary">
-				<text>加入待清运清单</text>
-			</u-button>
-		</view>
-	</view>
-</template>
-
-<script>
-	import searchModal from '@/pages/cleared/searchModal.vue'
-	import { waitToCleanList } from '@/api/cleared.js'
-	import { cleanStationAdd } from '@/api/unclear.js'
-	export default{
-		components: { searchModal },
-		data(){
-			return{
-				listdata: [],
-				pageNo: 1,  //  当前页码
-				pageSize: 40,  //  每页条数
-				total: 0,  //  数据总条数
-				noDataText: '暂无数据',  //  列表请求状态提示语
-				status: 'loadmore',  //  加载中状态
-				scrollTop: 0,  //  滚动条位置
-				isCheckedAll: false,  //  全选状态
-				checkedNum: 0,  //  已选个数
-				checkedList: [],  //  已选清运网点
-				openScreen: false, //  是否打开筛选
-				searchForm: {
-					//  查询条件
-					stationName: '',  //  网点名称
-					orderType: 'max', // 排序方式
-				},
-				btnStyle: {  //  自定义按钮样式
-					borderColor: '#07c160',
-					backgroundColor: '#07c160',
-					width: '100%'
-				},
-			}
-		},
-		onShow() {
-			this.openScreen = false  //  关闭筛选框
-			this.refresh(this.searchForm)
-		},
-		methods: {
-			//  加入清运单
-			handleAdd(){
-				if(this.checkedList.length > 0){
-					uni.showLoading({
-						mask: true,
-					    title: '加载中'
-					})
-					cleanStationAdd({ stationNoList: this.checkedList }).then(res => {
-						uni.hideLoading()
-						if(res.status == 200){
-							uni.showToast({ icon:'none', title: res.message })
-							setTimeout(()=>{
-								uni.navigateBack()
-							}, 1000)
-						}else{
-							uni.showToast({ icon:'none', title: res.message })
-						}
-					})
-				}else{
-					uni.showToast({ icon:'none', title: '请勾选需清运的网点' })
-				}
-			},
-			// 选中某个复选框时,由checkbox时触发
-			checkboxChange(e,ind) {
-				this.listdata[ind].checked = e.value
-				let len = 0
-				this.checkedList = []
-				this.listdata.map(item => {
-					if(item.checked){
-						len++
-						this.checkedList.push(item.stationNo)
-					}
-				})
-				this.checkedNum = len
-			},
-			// 全选
-			checkedAll(e) {
-				this.isCheckedAll = e
-				let len = 0
-				this.checkedList = []
-				this.listdata.map(val => {
-					val.checked = e.value ? true : false
-					if(val.checked){
-						len++
-						this.checkedList.push(val.stationNo)
-					}
-				})
-				this.checkedNum = len
-			},
-			// 获取查询参数 刷新列表
-			refresh(params){
-				this.searchForm = params
-				this.listdata = []
-				this.total = 0
-				this.isCheckedAll = false
-				this.checkedList = []
-				this.searchHandle(1)
-			},
-			// 搜索查询
-			searchHandle (pageNo) {
-				uni.showLoading({
-					mask: true,
-				    title: '加载中'
-				})
-				this.status = "loading"
-				pageNo ? this.pageNo = pageNo : null,
-				waitToCleanList({
-					pageNo: this.pageNo,
-					pageSize: this.pageSize,
-					stationName: this.searchForm.stationName,
-					orderType: this.searchForm.orderType
-				}).then(res => {
-					uni.hideLoading()
-					if (res.status == 200) {
-						res.data.list.map(item => {
-							item.checked = false
-							item.totalWeight = item.totalWeight ? (item.totalWeight/1000).toFixed(3) : 0
-							item.maxWeight = item.maxWeight ? (item.maxWeight/1000).toFixed(3) : 0
-						})
-						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"
-				})
-			},
-			//  查看详情
-			goPage(record){
-				uni.navigateTo({
-				    url: '/pages/cleared/network?stationNo=' + record.stationNo
-				})
-			},
-			// scroll-view到底部加载更多
-			onreachBottom() {
-				if(this.listdata.length!=0 && this.listdata.length < this.total){
-					this.pageNo += 1
-					this.searchHandle()
-				}else{
-					uni.showToast({ title: '已经到底了', icon: 'none' })
-					this.status = "nomore"
-				}
-			}
-		}
-	}
-</script>
-
-<style lang="scss">
-	page{
-		height: 100%;
-	}
-	.choose-network-container {
-		width: 100%;
-		height: 100%;
-		display: flex;
-		flex-direction: column;
-		padding-top: 80rpx;
-		padding-bottom: 102rpx;
-		position: relative;
-		// 顶部固定
-		.choose-network-header{
-			position: fixed;
-			top: 0;
-			left: 0;
-			width: 100%;
-			display: flex;
-			justify-content: space-between;
-			align-items: center;
-			padding: 0 $uni-spacing-row-base;
-			box-sizing: border-box;
-			background-color: #fff;
-			line-height: 80rpx;
-			font-size: 26rpx;
-			.checked-all{
-				.checked-all-c{
-					font-size: 26rpx;
-				}
-			}
-			.choose-checked{
-				text{
-					color: red;
-				}
-				.filter-icon{
-					width: 36rpx;
-					height: 36rpx;
-					padding-left: 30rpx;
-					vertical-align: text-top;
-				}
-			}
-		}
-		//  列表
-		.scroll-con{
-			flex: 1;
-			overflow: auto;
-		}
-		//  列表样式
-		.cell-item-con{
-			.cell-item{
-				margin: $uni-spacing-col-base $uni-spacing-row-base;
-				background-color: #fff;
-				border-radius: $uni-border-radius-base;
-				color: $uni-text-color;
-				font-size: $uni-font-size-base;
-				box-shadow: 3rpx 3rpx 5rpx #eee;
-				padding: 20rpx 20rpx 20rpx 20rpx;
-				.cell-item-c{
-					display: flex;
-					justify-content: space-around;
-					align-items: center;
-					.cell-item-checkbox{
-						flex-grow: 1;
-						.cell-item-info{
-							margin-left: 4rpx;
-							padding: 10rpx 4px;
-							width: 67vw;
-							.cell-item-info-network{
-								word-break: break-all;
-								margin-bottom: 22rpx;
-								display: inline-block;
-								position: relative;
-							}
-							.cell-item-info-weight{
-								font-size: 24rpx;
-								display: flex;
-								align-items: center;
-								justify-content: space-between;
-								.cell-item-weight-bar{
-									position: relative;
-									display: inline-block;
-									padding-right: 50rpx;
-									&:nth-child(2){
-										padding-right: 76rpx;
-										margin-left: 30rpx;
-									}
-								}
-							}
-						}
-					}
-					.details-con{
-						flex-shrink: 0;
-						padding: 30rpx 0;
-						.arrow-right{
-							margin-left: 64rpx;
-						}
-					}
-					
-				}
-			}
-		}
-		.footer-bar{
-			width: 100%;
-			height: 102rpx;
-			padding: 0 10%;
-			position: fixed;
-			bottom: 0;
-			left: 0;
-			text-align: center;
-			.footer-handle-btn{
-				display: block;
-				.btn-icon{
-					margin-right: 10rpx;
-				}
-			}
-			.handle-btn{
-				margin-top: 18rpx;
-				margin-bottom: 20rpx;
-			}
-		}
-		.nodata{
-			padding-top: 400rpx;
-		}
-	}
-</style>

+ 0 - 213
pages/cleared/details.vue

@@ -1,213 +0,0 @@
-<template>
-	<view class="cleared-details-container">
-		<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">
-					<view class="cell-item-c">
-						<u-image class="cell-item-pic" src="/static/md-big-pic.png" width="100rpx" height="100rpx"></u-image>
-						<view class="cell-item-info">
-							<view class="cell-item-info-network">{{item.stationName || '--'}}</view>
-							<view class="cell-item-info-weight">清运总重量:<text>{{ (item.totalWeight/1000).toFixed(3) }}kg</text></view>
-						</view>
-					</view>
-					<u-grid :col="3" :hover-class="none">
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number blue">{{ item.clothes ? (item.clothes/1000).toFixed(3) : 0 }}</text>
-								<text class="cell-item-unit">kg</text>
-							</view>
-							<view class="cell-item-exp">废旧衣物</view>
-						</u-grid-item>
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number red">{{ item.plastic ? (item.plastic/1000).toFixed(3) : 0 }}</text>
-								<text class="cell-item-unit">kg</text>
-							</view>
-							<view class="cell-item-exp">废旧塑料</view>
-						</u-grid-item>
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number yellow">{{ item.metal ? (item.metal/1000).toFixed(3) : 0 }}</text>
-								<text class="cell-item-unit">kg</text>
-							</view>
-							<view class="cell-item-exp">废旧金属</view>
-						</u-grid-item>
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number green">{{ item.paper ? (item.paper/1000).toFixed(3) : 0 }}</text>
-								<text class="cell-item-unit">kg</text>
-							</view>
-							<view class="cell-item-exp">废旧纸张</view>
-						</u-grid-item>
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number yellow">{{ item.plaMet ? (item.plaMet/1000).toFixed(3) : 0 }}</text>
-								<text class="cell-item-unit">kg</text>
-							</view>
-							<view class="cell-item-exp">废旧金属/塑料</view>
-						</u-grid-item>
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number yellow">{{ item.glass ? (item.glass/1000).toFixed(3) : 0 }}</text>
-								<text class="cell-item-unit">kg</text>
-							</view>
-							<view class="cell-item-exp">废旧玻璃</view>
-						</u-grid-item>
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number yellow">{{ item.recycling ? (item.recycling/1000).toFixed(3) : 0 }}</text>
-								<text class="cell-item-unit">kg</text>
-							</view>
-							<view class="cell-item-exp">可回收物</view>
-						</u-grid-item>
-					</u-grid>
-				</view>
-			</view>
-			<u-empty class="nodata" :text="noDataText" v-if="listdata.length==0 && status!='loading'" mode="list"></u-empty>
-			<view class="loadmore" v-if="listdata.length!=0">
-				<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
-			</view>
-		</scroll-view>
-	</view>
-</template>
-
-<script>
-	import { getAlreadyCleanDetails } from '@/api/cleared.js'
-	export default{
-		data(){
-			return{
-				listdata: [],
-				pageNo: 1,  //  当前页码
-				pageSize: 10,  //  每页条数
-				total: 0,  //  数据总条数
-				noDataText: '暂无数据',  //  列表请求状态提示语
-				status: 'loadmore',  //  加载中状态
-				scrollTop: 0,  //  滚动条位置
-				createDate: ''  //  时间
-			}
-		},
-		onLoad(options) {
-			this.createDate = options.createDate
-		},
-		onShow() {
-			this.refresh()
-		},
-		methods: {
-			// 获取查询参数 刷新列表
-			refresh(){
-				this.listdata = []
-				this.total = 0
-				this.searchHandle(1)
-			},
-			// 搜索查询
-			searchHandle (pageNo) {
-				uni.showLoading({
-					mask: true,
-				    title: '加载中'
-				})
-				this.status = "loading"
-				pageNo ? this.pageNo = pageNo : null
-				getAlreadyCleanDetails({
-					pageNo: this.pageNo,
-					pageSize: this.pageSize,
-					createDate: this.createDate
-				}).then(res => {
-					uni.hideLoading()
-					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() {
-				if(this.listdata.length!=0 && this.listdata.length < this.total){
-					this.pageNo++
-					this.searchHandle()
-				}else{
-					uni.showToast({ title: '已经到底了', icon: 'none' })
-					this.status = "nomore"
-				}
-			}
-		}
-	}
-</script>
-
-<style lang="scss" scoped>
-	.cleared-details-container{
-		width: 100%;
-		//  列表
-		.scroll-con{
-			overflow: auto;
-			height: 100vh;
-		}
-		.cell-item-con{
-			.cell-item{
-				margin: $uni-spacing-col-base $uni-spacing-row-base;
-				background-color: #fff;
-				border-radius: $uni-border-radius-base;
-				color: $uni-text-color;
-				font-size: $uni-font-size-base;
-				box-shadow: 3rpx 3rpx 5rpx #eee;
-				.cell-item-c{
-					display: flex;
-					align-items: center;
-					padding: $uni-spacing-col-base $uni-spacing-row-base;
-					.cell-item-pic{
-						flex-shrink: 0;
-						margin-right: 20rpx;
-					}
-					.cell-item-info{
-						flex-grow: 1;
-						.cell-item-info-network{
-							word-break: break-all;
-							margin-bottom: 10rpx;
-						}
-						.cell-item-info-weight{
-							font-size: 26rpx;
-							text{
-								font-weight: bold;
-							}
-						}
-					}
-				}
-				.cell-item-main{
-					margin-bottom: 10rpx;
-					.cell-item-number{
-						margin-right: 5rpx;
-					}
-					.cell-item-unit{
-						font-size: 26rpx;
-					}
-					.blue {
-						color: #1890FF;
-					}
-					.green {
-						color: #16b50e;
-					}
-					.red {
-						color: red;
-					}
-					.yellow {
-						color: #ff9900;
-					}
-				}
-			}
-		}
-		.nodata{
-			padding-top: 400rpx;
-		}
-	}
-</style>

+ 0 - 175
pages/cleared/index.vue

@@ -1,175 +0,0 @@
-<template>
-	<view class="cleared-container">
-		<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" @tap="goPage(item)">
-					<view class="cell-item-c">
-						<view class="cell-item-date">{{ item.cleanDate.substr(0,10) }}</view>
-						<view class="cell-item-orderNum">
-							<u-icon name="arrow-right" :size="28" color="#999"></u-icon>
-						</view>
-					</view>
-					<u-grid :col="3" :hover-class="none">
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number blue">{{item.stationNum || 0}}</text>
-								<text class="cell-item-unit">个</text>
-							</view>
-							<view class="cell-item-exp">清运网点数</view>
-						</u-grid-item>
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number green">{{item.boxNum || 0}}</text>
-								<text class="cell-item-unit">个</text>
-							</view>
-							<view class="cell-item-exp">清运箱体数</view>
-						</u-grid-item>
-						<u-grid-item>
-							<view class="cell-item-main">
-								<text class="cell-item-number red">{{ (item.totalWeight/1000).toFixed(3) || 0 }}</text>
-								<text class="cell-item-unit">kg</text>
-							</view>
-							<view class="cell-item-exp">清运总重量</view>
-						</u-grid-item>
-					</u-grid>
-				</view>
-			</view>
-			<u-empty class="nodata" :text="noDataText" v-if="listdata.length==0 && status!='loading'" mode="list"></u-empty>
-			<view class="loadmore" v-if="listdata.length!=0">
-				<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
-			</view>
-		</scroll-view>
-	</view>
-</template>
-<script>
-	import { getAlreadyCleanList } from '@/api/cleared.js'
-	export default {
-		data() {
-			return {
-				listdata: [],
-				pageNo: 1,  //  当前页码
-				pageSize: 10,  //  每页条数
-				total: 0,  //  数据总条数
-				noDataText: '暂无数据',  //  列表请求状态提示语
-				status: 'loadmore',  //  加载中状态
-				scrollTop: 0,  //  滚动条位置
-			}
-		},
-		onShow() {
-			this.refresh()
-		},
-		methods:{
-			// 获取查询参数 刷新列表
-			refresh(){
-				this.listdata = []
-				this.total = 0
-				this.searchHandle(1)
-			},
-			// 搜索查询
-			searchHandle (pageNo) {
-				uni.showLoading({
-					mask: true,
-				    title: '加载中'
-				})
-				this.status = "loading"
-				pageNo ? this.pageNo = pageNo : null
-				getAlreadyCleanList({
-					pageNo: this.pageNo,
-					pageSize: this.pageSize,
-				}).then(res => {
-					uni.hideLoading()
-					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"
-				})
-			},
-			//  查看详情
-			goPage(row){
-				uni.navigateTo({
-				    url: '/pages/cleared/details?createDate='+row.cleanDate
-				})
-			},
-			// scroll-view到底部加载更多
-			onreachBottom() {
-				if(this.listdata.length!=0 && this.listdata.length < this.total){
-					this.pageNo++
-					this.searchHandle()
-				}else{
-					uni.showToast({ title: '已经到底了', icon: 'none' })
-					this.status = "nomore"
-				}
-			}
-		}
-	}
-</script>
-
-<style lang="scss">
-	page{
-		height: 100%;
-	}
-	.cleared-container {
-		width: 100%;
-		height: 100%;
-		display: flex;
-		flex-direction: column;
-		//  列表
-		.scroll-con{
-			flex: 1;
-			overflow: auto;
-		}
-		//  列表样式
-		.cell-item-con{
-			.cell-item{
-				margin: $uni-spacing-col-base $uni-spacing-row-base;
-				background-color: #fff;
-				border-radius: $uni-border-radius-base;
-				color: $uni-text-color;
-				font-size: $uni-font-size-base;
-				box-shadow: 3rpx 3rpx 5rpx #eee;
-				.cell-item-c{
-					display: flex;
-					justify-content: space-between;
-					padding: 24rpx $uni-spacing-row-base;
-					.cell-item-date{
-						color: $uni-text-color-grey;
-					}
-				}
-				.cell-item-main{
-					display: inline-block;
-					margin-bottom: 10rpx;
-					.cell-item-number{
-						margin-right: 5rpx;
-					}
-					.cell-item-unit{
-						font-size: 26rpx;
-					}
-					.blue {
-						color: #1890FF;
-					}
-					.green {
-						color: #16b50e;
-					}
-					.red {
-						color: red;
-					}
-				}
-			}
-		}
-		.nodata{
-			padding-top: 400rpx;
-		}
-	}
-</style>

+ 0 - 253
pages/cleared/network.vue

@@ -1,253 +0,0 @@
-<template>
-	<view class="content">
-		<map 
-		id="map" 
-		:latitude="lat" 
-		:longitude="lng" 
-		scale="18" 
-		show-compass 
-		show-location 
-		:markers="markers"
-		style="width: 100%; height:500rpx;">
-		</map>
-		<!-- 网点信息及设备 -->
-		<view class="details" v-if="stationData">
-			<view class="details-address">
-				<image src="/static/md-big-pic.png" class="store-pic"></image>
-				<view class="store-info">
-					<view>{{ stationData.name || '--' }}</view>
-					<view>{{ stationData.provinceName||'' }}{{ stationData.cityName||'' }}{{ stationData.districtName||'' }}{{ stationData.address||'' }}</view>
-					<view>
-						营业时间:
-						<text v-for="(tItem, tInd) in stationData.deliveryTimeRuleItemList" :key="tInd">
-							{{ tItem.openTime }} - {{ tItem.closeTime }}{{ tInd == stationData.deliveryTimeRuleItemList.length - 1 ? '' : ',' }}
-						</text>
-					</view>
-				</view>
-			</view>
-			<!-- 设备列表 -->
-			<view class="details-dev">
-				<view class="details-dev-box" v-for="item in deviceData" :key="item.id">
-					<view class="details-dev-title">设备编号:<text>{{ item.srcDeviceCode }}</text></view>
-					<view class="details-dev-cons">
-						<view class="dev-item" v-for="boxItem in item.deviceTypeBoxList" :key="boxItem.id">
-							<view class="item-pic-con">
-								<text v-if="boxItem.flag==1" class="full-sign">已满</text>
-								<u-image mode="aspectFit" height="80" width="80" :src="`/static/${boxItem.rubbishType}.png`" class="type-sign"></u-image>
-							</view>
-							<view class="dev-main">
-								<view>
-									{{ boxItem.rubbishTypeDictValue }}
-								</view>
-								<view class="rule-con">
-									{{ boxItem.boxCode | stockVal(item) }}
-								</view>
-							</view>
-						</view>
-					</view>
-				</view>
-				<u-empty v-if="deviceData.length==0" icon-size="60" text="暂无设备" mode="list" margin-top="120"></u-empty>
-			</view>
-		</view>
-	</view>
-</template>
-
-<script>
-	import { stationDevice, getWaitToCleanDetailHeader } from '@/api/cleared.js'
-	export default {
-		data() {
-			return {
-				stationNo: '',  //  网点编号
-				lat: '',
-				lng: '',
-				mapCtx: null, // 地图对象
-				markers: [], // 标注点
-				stationData: null,  //  网点信息
-				deviceData: [],  //  设备信息
-			};
-		},
-		filters: {
-			stockVal: function (val, obj) {  //  各个内置箱体的当前【库存量】
-				let num
-				if(val == 1){
-					num = obj.boxOne ? (obj.boxOne/1000).toFixed(3) : 0
-					return num + 'kg'
-				}else if(val == 2){
-					num = obj.boxTwo ? (obj.boxTwo/1000).toFixed(3) : 0
-					return num + 'kg'
-				}else if(val == 3){
-					num = obj.boxThree ? (obj.boxThree/1000).toFixed(3) : 0
-					return num + 'kg'
-				}else if(val == 4){
-					num = obj.boxFour ? (obj.boxFour/1000).toFixed(3) : 0
-					return num + 'kg'
-				}else if(val == 5){
-					num = obj.boxFive ? (obj.boxFive/1000).toFixed(3) : 0
-					return num + 'kg'
-				}
-			}
-		},
-		onLoad(options) {
-			this.stationNo = options.stationNo
-			this.getStation()  //  网点信息
-			this.getDevice()  //  设备信息
-			// 开启分享
-			uni.showShareMenu({
-				withShareTicket: true,
-				menus: ['shareAppMessage', 'shareTimeline']
-			})
-		},
-		methods: {
-			//  网点信息
-			getStation(){
-				getWaitToCleanDetailHeader({ stationNo: this.stationNo }).then(res => {
-					if(res.status == 200){
-						this.stationData = res.data
-						this.markers = []
-						this.markers.push({
-							latitude: res.data.lat,
-							longitude: res.data.lng,
-							width: 30,
-							height: 30,
-							iconPath: "/static/store.png"
-						})
-						this.lng = res.data.lng
-						this.lat = res.data.lat
-					}else{
-						this.stationData = null
-						this.markers = []
-						this.lng = ''
-						this.lat = ''
-					}
-				})
-			},
-			//  设备信息
-			getDevice(){
-				stationDevice({ stationNo: this.stationNo }).then(res => {
-					if(res.status == 200){
-						this.deviceData = res.data
-					}else{
-						this.deviceData = []
-					}
-				})
-			},
-			//  根据垃圾类型获取兑换规则
-			getRule(type){
-				let row = null
-				if(this.stationData.goldExRuleItemList){
-					row = this.stationData.goldExRuleItemList.find(item => item.rubbishType == type)
-				}
-				return { rubbishWeight: row.rubbishWeight || 0, goleNum: row.goleNum || 0 }
-			}
-		}
-	}
-</script>
-
-<style lang="scss">
-.content{
-	width: 100%;
-	padding: 0;
-	.details{
-		margin: 20upx;
-		.details-address{
-			display: flex;
-			align-items: center;
-			padding: 20upx;
-			background: #FFFFFF;
-			border-radius: 15upx;
-			box-shadow: 0upx 3upx 6upx #eee;
-			margin-bottom: 20upx;
-			.store-pic{
-				width: 120rpx;
-				height:120rpx;
-				margin-right: 20rpx;
-			}
-			.store-info{
-				>view{
-					font-size: 24upx;
-					padding: 5upx 0;
-					color: #666;
-					&:first-child{
-						font-weight: bold;
-						font-size: 30upx;
-						color: #333;
-					}
-				}
-			}
-		}
-		.details-dev{
-			.details-dev-box{
-				padding: 20upx 20upx 5upx;
-				background: #FFFFFF;
-				border-radius: 15upx;
-				box-shadow: 0upx 3upx 6upx #eee;
-				margin-bottom: 20upx;
-				.details-dev-title{
-					border-bottom: 1px solid #F8F8F8;
-					padding: 10upx 0 20upx;
-					text{
-						color: #666;
-					}
-				}
-				.details-dev-cons{
-					padding: 10upx 0;
-					display: flex;
-					flex-wrap: wrap;
-					.dev-item{
-						width: 50%;
-						display: flex;
-						align-items: center;
-						> view{
-							padding: 25upx 10upx 15upx 0;
-							&:last-child{
-								view{
-									display: flex;
-									align-items: center;
-									.u-tag{
-										margin-left: 10upx;
-									}
-								}
-							}
-						}
-						.item-pic-con{
-							position: relative;
-							padding-left: 30rpx;
-							.full-sign{
-								font-size: 24rpx;
-								padding: 4rpx 10rpx 14rpx;
-								color: #fff;
-								background: url('/static/full-bg.png') no-repeat;
-								background-size: 100% 100%;
-								transform: scale(0.8);
-								position: absolute;
-								left: 0;
-								top: 0;
-								width: 68rpx;
-								height: 55rpx;
-								z-index: 9;
-							}
-						}
-						.dev-main{
-							.rule-con{
-								color: #666;
-								font-size: 24upx;
-								.goleNum{
-									color: #eb0000;
-									font-size: 26rpx;
-									font-weight: bold;
-									margin-left: 4rpx;
-								}
-								.ld-pic{
-									width: 30rpx;
-									height: 30rpx;
-									margin-left: 6rpx;
-								}
-							}
-						}
-					}
-				}
-			}
-		}
-	}
-}
-</style>

+ 326 - 0
pages/index/addData.vue

@@ -0,0 +1,326 @@
+<template>
+	<view class="content">
+		<view>
+			<view class="form-data">
+				<u-form :model="form" ref="uForm" :label-width="140" :error-type="['toast']">
+						<u-form-item prop="gatherNum_other" label="其他垃圾:" >
+							<u-input :disabled="isView" @input="numberToFixed('gatherNum_other',0,999999)" type="number" placeholder="请输入" v-model="form.gatherNum_other" />
+							<text slot="right" style="color: #000000;">桶(约{{form.gatherNum_other*240}}kg)</text>
+						</u-form-item>
+						<u-form-item prop="gatherNum_chuyu" label="厨余垃圾:" >
+							<u-input :disabled="isView" @input="numberToFixed('gatherNum_chuyu',0,999999)" placeholder="请输入" type="number" v-model="form.gatherNum_chuyu" />
+							<text slot="right" style="color: #000000;">桶(约{{form.gatherNum_chuyu*240}}kg)</text>
+						</u-form-item>
+						<u-form-item prop="gatherNum_jianzhu" label="建筑垃圾:" >
+							<u-input :disabled="isView" @input="numberToFixed('gatherNum_jianzhu',2,999999)" placeholder="请输入" type="digit" v-model="form.gatherNum_jianzhu" />
+							<text slot="right" style="color: #000000;">吨(约{{form.gatherNum_jianzhu*1000}}kg)</text>
+						</u-form-item>
+				</u-form>
+			</view>
+			<view class="form-data remark">
+				<text>信息备注</text>
+				<textarea :disabled="isView" :auto-height="true" :maxlength="30" v-model="form.remarks" class="receiveAddress"/>
+			</view>
+			<view class="form-data qyImg">
+				<text>清运照片</text>
+				<view class="info-main">
+					<view v-if="photograph.length<3 && !isView" class="camera-btn">
+						<view @click="goPhotograph" class="photograph-camera">
+							<u-icon name="camera" color="#bfbfbf" size="60" ></u-icon>
+						</view>
+						<view >
+							(最多3张)
+						</view>
+						<view >
+							(每张最大不超过10M)
+						</view>
+					</view>
+					<view v-show="photograph.length" v-for="(item,index) in photograph" :key="index" class="photograph-con">
+						<u-icon v-show="!isView" name="close-circle-fill" color="#fa3534" size="50" class="close-circle-icon" @click="cancelPhotograph(index)"></u-icon>
+						<u-image width="100%" height="100%" :src="item" @click="previewPictures(item)"></u-image>
+					</view>
+				</view>
+			</view>
+			<u-button v-if="isView" @click="isView = false" class="submitBtn" type="waring" shape="circle">修改</u-button>
+			<u-button v-else @click="submit" :loading="loading" class="submitBtn" type="success" shape="circle">提交</u-button>
+			<uni-popup ref="openModal" type="center">
+				<uni-popup-dialog content="确认提交吗?" @confirm="onOk" :title="title"></uni-popup-dialog>
+			</uni-popup>
+		</view>
+	</view>
+</template>
+
+<script>
+	import uniPopup from '@/components/uni-popup/uni-popup.vue'
+	import uniPopupDialog from '@/components/uni-popup/uni-popup-dialog.vue'
+	import {gatherSave,gatherDetail} from '@/api/index.js'
+	import {numberToFixed,saveImgToAliOss} from '@/libs/tools.js'
+	export default {
+		components: {
+			uniPopup,uniPopupDialog
+		},
+		data() {
+			return {
+				title:'',
+				loading:false, // 提交按钮加载圈
+				photograph: [], //  图片路径
+				form: {
+					gatherNum_other: '', // 其它垃圾
+					gatherNum_chuyu: '', // 厨余垃圾
+					gatherNum_jianzhu: '', // 建筑垃圾
+					remarks: '' // 备注
+				},
+				isView: false ,// 是否是查看详情
+				itemId:''
+			};
+		},
+		onLoad(option) {
+			console.log(option,option.id,'ppppppppp')
+			// 查看
+			if(option && option.id){
+				this.isView = true
+				this.itemId=option.id
+				this.getDetailData()
+			}else {
+				console.log('--------新增')
+				this.photograph = []
+				this.form.remarks = ''
+				this.$refs.uForm.resetFields()
+			}
+		},
+		onUnload() {
+		},
+		methods: {
+			// 保留几位小数
+			numberToFixed: function (key, num, max) {
+			  let val = this.form[key]
+			  let ret = numberToFixed(val, num, max)
+			  this.$nextTick(() => {
+			  	this.form[key] = ret
+			  })
+			},
+			// 获取详情数据
+			getDetailData(){
+				gatherDetail({id:this.itemId}).then(res=>{
+					if(res.status==200){
+						console.log(res)
+						const a = res.data.gatherRubbishList.find(item=>item.rubbishType=='GATHER_BUILDING')
+						const b = res.data.gatherRubbishList.find(item=>item.rubbishType=='GATHER_OTHER')
+						const c = res.data.gatherRubbishList.find(item=>item.rubbishType=='GATHER_KITCHEN')
+						this.form.gatherNum_jianzhu= a ? a.gatherNum.toString() : '0'
+						this.form.gatherNum_chuyu= c ? c.gatherNum.toString() : '0'
+						this.form.gatherNum_other= b ? b.gatherNum.toString() : '0'
+						this.form.remarks=res.data.remarks
+						this.photograph=res.data.imageUrlList || []
+						console.log(this.form,'this.form')
+					}
+				})
+			},
+			// 拍照或从相册选图片
+			goPhotograph() {
+				uni.chooseImage({
+				    count: 1, //默认9
+				    sizeType: ['original', 'compressed'], //可以指定是原图还是压缩图,默认二者都有
+				    sourceType: ['album','camera'], //从相册选择
+				    success:  (res) =>{
+						console.log(res,'rrrrrrrrrrr')
+				        console.log(JSON.stringify(res.tempFilePaths));
+						console.log(this.photograph.length,'this.photograph')
+						if(res.tempFiles[0].size>10485760){
+							uni.showToast({
+								title: '图片过大无法上传!',
+								icon: 'none'
+							})
+							return
+						}
+						uni.showLoading({
+							title:'正在保存图片...',
+							mask: true
+						})
+						saveImgToAliOss(res.tempFilePaths[0],(ret)=>{
+							// console.log(ret,'----------ret')
+							this.photograph.push(ret.data)
+							// _this.photograph = ret.data
+							uni.hideLoading()
+						})
+				    }
+				});
+			},
+			//  预览图片
+			previewPictures(item) {
+				const photograph = [item];
+				uni.previewImage({
+					urls: photograph,
+				});
+			},
+			//  删除图片
+			cancelPhotograph(index) {
+				setTimeout(() => {
+					this.photograph.splice(index,1)
+				}, 500);
+			},
+			// 提交
+			submit(){
+				if((!this.form.gatherNum_other ||this.form.gatherNum_other==0)  && (!this.form.gatherNum_chuyu || this.form.gatherNum_chuyu==0) && (!this.form.gatherNum_jianzhu || this.form.gatherNum_jianzhu==0)) {
+					uni.showToast({
+						title: '请至少输入一项垃圾分类的数量!',
+						icon: 'none'
+					})
+					return false
+				} else {
+					this.$refs.openModal.open()
+				}
+			},
+			// 确认提交
+			onOk() {
+				this.$refs.openModal.close()
+				let params = {
+					rubbishEntityList: [],
+					imageUrlList: this.photograph,
+					remarks: this.form.remarks
+				}
+				if(this.itemId){
+					params.id=this.itemId
+				}
+				if(this.form.gatherNum_other) {
+					params.rubbishEntityList.push({
+						"rubbishType":"GATHER_OTHER",
+						"rubbishWeight": this.form.gatherNum_other*240,
+						"gatherNum": this.form.gatherNum_other,
+						"unit":"BUCKET"
+					})
+				}
+				if(this.form.gatherNum_chuyu) {
+					params.rubbishEntityList.push({
+						"rubbishType":"GATHER_KITCHEN",
+						"rubbishWeight": this.form.gatherNum_chuyu*240,
+						"gatherNum": this.form.gatherNum_chuyu,
+						"unit":"BUCKET"
+					})
+				}
+				if(this.form.gatherNum_jianzhu) {
+					params.rubbishEntityList.push({
+						"rubbishType":"GATHER_BUILDING",
+						"rubbishWeight": this.form.gatherNum_jianzhu*1000,
+						"gatherNum": this.form.gatherNum_jianzhu,
+						"unit":"TON"
+					})
+				}
+				this.loading=true
+				gatherSave(params).then(res=>{
+					if(res.status == 200) {
+						uni.showToast({
+							title: res.message,
+							icon: 'none'
+						})
+						setTimeout(()=>{
+							uni.navigateBack()
+						},300)
+					} else {
+						uni.showToast({
+							title: res.message,
+							icon: 'none'
+						})
+					}
+					this.loading= false
+				})
+			},
+			
+		},
+		// 必须要在onReady生命周期,因为onLoad生命周期组件可能尚未创建完毕
+		onReady() {
+			this.$refs.uForm.setRules(this.rules);
+		}
+	}
+</script>
+
+<style lang="scss">
+	.content{
+		width: 100%;
+		height: 100vh;
+		padding: 0;
+		background: #F5F5F5;
+		// .buttons{
+		// 	font-size: 32upx;
+		// 	display: block;
+		// 	height: 80upx;
+		// 	line-height: 80upx;
+		// 	margin: 0 auto;
+		// 	background-color: #0DC55F;
+		// 	color: #fff;
+		// 	border-radius: 50upx;
+		// }
+		.receiveAddress{
+			width: 100%;
+			line-height: 1.5em;
+			box-sizing: border-box;
+			font-style: normal;
+		}
+		.form-data{
+			padding: 0 40upx;
+			margin-bottom: 20upx;
+			background-color: #fff;
+		}
+		.remark{
+			padding: 40upx ;
+		}
+		.qyImg{
+			padding: 40upx ;
+		}
+		.info-main {
+			margin-top: 14upx;
+			border-radius: 12upx;
+			background-color: #fff;
+			display: flex;
+			.location-icon {
+				padding-left: 10upx;
+				vertical-align: sub;
+			}
+			.photograph-camera {
+				border: 2upx dashed #bfbfbf;
+				border-radius: 12upx;
+				width: 140upx;
+				height: 140upx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+			}
+			.camera-btn{
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+				color: #999999;
+				font-size: 24upx;
+			}
+			.photograph-con {
+				margin: 0 20upx;
+				width: 140upx;
+				height: 140upx;
+				text-align: center;
+				position: relative;
+				.photograph-icon {
+					display: inline-block;
+					padding-top: 48upx;
+				}
+				.close-circle-icon {
+					background-color: #fff;
+					border-radius: 50%;
+					position: absolute;
+					right: -23upx;
+					top: -23upx;
+					z-index: 9;
+				}
+			}
+		}
+		.submitBtn{
+			font-size: 32upx;
+			display: block;
+			width: 670upx;
+			height: 80upx;
+			line-height: 80upx;
+			margin: 0 auto;
+			color: #fff;
+			border-radius: 50upx;
+		}
+	}
+</style>

+ 306 - 302
pages/index/index.vue

@@ -1,209 +1,204 @@
 <template>
-	<view class="unclear-container">
-		<uni-navbar pageName="待清运清单" :isBack="false" :isMap="true"></uni-navbar>
-		<scroll-view class="scroll-con" scroll-y :scroll-top="scrollTop" @scrolltolower="onreachBottom">
+	<view class="content">
+		<view class="header">
+			<view @click="openSearch">
+				<text v-if="searchForm.beginDate">{{searchForm.beginDate}}至{{searchForm.endDate}}</text>
+				<text v-else>全部</text>
+				<!-- <u-icon name="arrow-right" color="#999999" size="28"></u-icon> -->
+				<u-image v-if="hasLogin" @click="openScreen=true" class="filter-img" width="36rpx" height="36rpx" src="/static/filter.png"></u-image>
+			</view>
+			<!-- 总计 -->
+			<view class="header-cont">
+				<view class="cont-item">
+					<text>其它垃圾</text>
+					<text v-if="!titleStatus" class="other">{{otherTotal}}kg</text>
+					<u-loading :show="titleStatus"></u-loading>
+				</view>
+				<view class="cont-item">
+					<text>厨余垃圾</text>
+					<text v-if="!titleStatus" class="chuyu">{{chuyuTotal}}kg</text>
+					<u-loading :show="titleStatus"></u-loading>
+				</view>
+				<view class="cont-item">
+					<text>建筑垃圾</text>
+					<text v-if="!titleStatus" class="jianzhu">{{jianzhuTotal}}kg</text>
+					<u-loading :show="titleStatus"></u-loading>
+				</view>
+			</view>
+		</view>
+		<scroll-view  class="scroll-con" :scroll-top="scrollTop" scroll-y @scrolltolower="onreachBottom">
 			<!-- 列表数据 -->
-			<view class="cell-item-con">
-				<view class="cell-item" v-for="(item, index) in listdata" :key="index">
-					<view class="cell-item-c" @tap="goPage(item)">
-						<view class="cell-item-info">
-							<view class="cell-item-info-network">
-								{{item.stationName || '--'}}
-								<u-badge type="success" bgColor="#c90101" :count="item.unCleanNum" :offset="[-10,-32]" size="mini"></u-badge>
-							</view>
-							<view class="cell-item-info-weight">
-								<view class="cell-item-weight-bar">
-									{{ item.totalWeight ? (item.totalWeight/1000).toFixed(3) : 0 }}kg
-									<u-badge class="badge" type="primary" bgColor="#01c9b2" count="总" :offset="[0,0]"></u-badge>
-								</view>
-								<view class="cell-item-weight-bar">
-									{{ item.maxWeight ? (item.maxWeight/1000).toFixed(3) : 0 }}kg
-									<u-badge class="badge" type="warning" bgColor="#05695d" count="最大" :offset="[0,0]"></u-badge>
-								</view>
-							</view>
-						</view>
-						<u-icon name="arrow-right" class="arrow-right" :size="28" color="#999"></u-icon>
+			<view class="cell-item" v-for="item in listdata">
+				<view class="cell-item-title" >
+					<view>
+						<text>{{item.createDate}}</text>
+					</view>
+					<view @click="intoPage(item)">
+						<span class="view">查看详情</span>
+						<u-icon name="arrow-right" color="#999999" size="28"></u-icon>
+					</view>
+				</view>
+				<view class="cell-item-cont">
+					<!-- 其他垃圾 -->
+					<view class="cont-item">
+						<u-image src="/static/index/other.png"></u-image>
+						<text>{{item.gatherOther? (item.gatherOther/1000).toFixed(3)/1 :0}}kg</text>
+					</view>
+					<!-- 厨余垃圾 -->
+					<view class="cont-item">
+						<u-image src="/static/index/chuyu.png"></u-image>
+						<text>{{item.gatherKitchen ? (item.gatherKitchen/1000).toFixed(3)/1 :0}}kg</text>
+					</view>
+					<!-- 建筑垃圾 -->
+					<view class="cont-item">
+						<u-image src="/static/index/jianzhu.png"></u-image>
+						<text>{{item.gatherBuilding ? (item.gatherBuilding/1000).toFixed(3)/1 :0}}kg</text>
 					</view>
-					<u-button size="mini" class="handle-btn" hover-class="none" :custom-style="customBtnStyle" @click="removeFun(item)">移除</u-button>
 				</view>
 			</view>
-			<u-empty class="nodata" :text="noDataText" v-if="listdata.length==0 && status!='loading'" mode="list"></u-empty>
-			<view class="loadmore" v-if="listdata.length!=0">
+			<view class="nodata" v-if="listdata.length==0 && status!='loading'">
+				<u-empty :text="noDataText" mode="list"></u-empty>
+			</view>
+			<view class="loadmore">
 				<u-loadmore v-if="total>pageSize || status=='loading'" :status="status" />
 			</view>
 		</scroll-view>
-		
-		<view class="footer-bar">
-			<u-button class="footer-handle-btn scan-btn" hover-class="none" :custom-style="scanBtnStyle" shape="circle" @click="clearingOutlets" size="medium" type="primary">
-				<u-icon name="scan" class="btn-icon" :size="28" color="#fff"></u-icon>
-				<text>扫码清运</text>
-			</u-button>
-			<u-button class="footer-handle-btn" hover-class="none" :custom-style="btnStyle" shape="circle" @click="openQuery" size="medium">
-				<u-icon name="plus" class="btn-icon" :size="28" color="#606266"></u-icon>
-				<text>增加清运网点</text>
-			</u-button>
+		<view @click="intoPage()" class="footer">
+			<!-- <u-icon name="edit-pen" size="30"></u-icon> -->
+			<text>垃圾数据录入</text>
 		</view>
-		<!-- 确认清运 -->
-		<u-popup v-model="messagePop" mode="center" class="custom-pop" length="80%" border-radius="14" :mask-close-able="false">
-			<view class="custom-con">
-				<view class="pop-title">提示</view>
-				<view class="pop-con">
-					<view class="pop-item">确认清运以下网点-设备内的可回收物?</view>
-					<view class="pop-item">{{networkData.stationName || ''}}</view>
-					<view class="pop-item">{{networkData.srcDeviceCode || ''}}</view>
-					<view class="form-con">
-						<u-form :model="form" ref="uForm">
-							<u-form-item label="备注" :border-bottom="false">
-								<u-input v-model="form.remarks" type="textarea" border />
-							</u-form-item>
-						</u-form>
-					</view>
-				</view>
-				<view class="btn-con">
-					<view class="handle-pop-btn cancel-btn" @click="cancelFun">取消</view>
-					<view class="handle-pop-btn submit-btn" @click="submitFun">确定</view>
-				</view>
-			</view>
-		</u-popup>
+		<!-- 筛选弹框 -->
+		<search-modal v-if="openScreen" :visible="openScreen" :defaultParams="searchForm" @refresh="refresh" @close="openScreen=false"></search-modal>
 	</view>
 </template>
+
 <script>
-	import { getSelfCleanTaskList, cleanDevice, cleanStationRemove, getDeviceMsg } from '@/api/unclear.js'
-	import { parseQueryString } from '@/libs/tools.js'
+	import searchModal from './searchModal.vue'
+	import {gatherList,gatherTotal} from '@/api/index.js'
+	import { checkLogin } from '@/api/login.js'
+	import moment from 'moment'
+	import getDate from '@/libs/getDate.js'
 	export default {
+		components: { searchModal },
 		data() {
 			return {
-				listdata: [],
+				hasLogin: false, // 是否登录
+				listdata: [], // 列表数据
+				otherTotal: 0, // 其它垃圾总和
+				jianzhuTotal: 0, // 建筑垃圾总和
+				chuyuTotal: 0, // 厨余垃圾总和
 				pageNo: 1,  //  当前页码
 				pageSize: 10,  //  每页条数
 				total: 0,  //  数据总条数
 				noDataText: '暂无数据',  //  列表请求状态提示语
 				status: 'loadmore',  //  加载中状态
-				customBtnStyle: {  //  自定义按钮样式
-					borderColor: '#01c9b2',
-					backgroundColor: '#01c9b2',
-					color: '#fff'
+				titleStatus: false,  //  顶部加载中状态
+				openScreen: false,  //  是否打开筛选
+				searchForm: {  //  查询条件
+					beginDate: getDate.getRecentday().starttime,  //  创建时间默认筛选近7天
+					endDate: getDate.getRecentday().endtime,  //  创建时间默认筛选近7天
 				},
 				scrollTop: 0,  //  滚动条位置
-				scanBtnStyle: {  //  自定义按钮样式
-					borderColor: '#07c160',
-					backgroundColor: '#07c160',
-					width: '100%'
-				},
-				btnStyle: {  //  自定义按钮样式
-					width: '100%'
-				},
-				form: {
-					remarks: ''  //  备注
-				},
-				boxData: null,  //  箱体二维码数据
-				messagePop: false,  //  确认清运
-				networkData: null  //  网点详情
 			}
 		},
-		onShow() {
-			this.pageNo = 1
-			this.refresh()
+		onLoad() {
+			this.checkUpdate()
+			// 开启分享
+			uni.showShareMenu({
+				withShareTicket: true,
+				menus: ['shareAppMessage', 'shareTimeline']
+			})
 		},
-		methods:{
-			//  是否可清运
-			clearingOutlets(){
-				if(this.listdata.length==0){
-					uni.showToast({ title: '请先选择待清运网点,再进行扫码清运', icon: 'none' })
-				}else{
-					this.openScan()
+		onUnload() {
+			
+		},
+		onShareAppMessage(res) {
+		},
+		onShareTimeline(res) {
+		},
+		onShow() {
+			checkLogin().then(res => {
+				this.hasLogin = res.status == 200
+				if(this.hasLogin){
+					this.pageInit()
+				} else {
+					this.noDataText = '您尚未登录或登录已过期,完成登录后可查看录入信息!'
 				}
+			})
+		},
+		methods: {
+			pageInit() {
+				this.pageNo = 1
+				this.pageSize = 10
+				this.total = 0
+				this.scrollTop = 0
+				this.otherTotal= 0 // 其它垃圾总和
+				this.jianzhuTotal= 0 // 建筑垃圾总和
+				this.chuyuTotal= 0 // 厨余垃圾总和
+				this.searchForm.beginDate = getDate.getRecentday().starttime
+				this.searchForm.endDate = getDate.getRecentday().endtime
+				console.log(this.searchForm,'this.searchForm')
+				this.searchHandle()
+				this.getTotal()
 			},
-			//  扫码清运
-			openScan(){
-				const _this = this
-				uni.scanCode({
-					success(e) {
-						console.log(e)
-						//  箱体二维码数据
-						// {
-						// 	charSet: "ISO8859-1"
-						// 	errMsg: "scanCode:ok"
-						// 	rawData: "aHR0cDovL3d3dy5zeHp4eWoubmV0L3dlYi9zdGF0aWMvcXJjb2RlL2Rvd25sb2FkLWFwcC5odG1sP2lkPTFiODM3M2JhLWNmMDAtNDU2NS04Y2ZkLTVmOGZlNTYwYmNmMiZ0eXBlPWR1c3RiaW4="
-						// 	result: "http://www.sxzxyj.net/web/static/qrcode/download-app.html?id=1b8373ba-cf00-4565-8cfd-5f8fe560bcf2&type=dustbin"
-						// 	scanType: "QR_CODE"
-						// }
-						if(e.scanType == 'QR_CODE'){
-							//  将箱体二维码数据e.result携带参数转换为json
-							_this.boxData = parseQueryString(e.result)
-							_this.getNetworkInfo()
-						}
-					},
-					fail(err) {
-						console.log(err)
-					}
-				})
-			},
-			//  扫码获取网点信息
-			getNetworkInfo(){
-				const _this = this
-				getDeviceMsg(_this.boxData).then(res => {
-					if(res.status == 200){
-						_this.networkData = res.data
-						_this.form.remarks = ''
-						_this.messagePop = true
-					}else{
-						_this.messagePop = false
-					}
-				})
-			},
-			//  取消清运
-			cancelFun(){
-				this.messagePop = false
-			},
-			//  确定清运
-			submitFun(){
-				const _this = this
-				uni.showLoading({
-					mask: true,
-				    title: '加载中'
-				})
-				let obj = {}
-				obj.deviceNo = (this.networkData && this.networkData.deviceNo) ? this.networkData.deviceNo : ''
-				obj.remarks = this.form.remarks
-				cleanDevice(obj).then(res => {
-					uni.hideLoading()
-					if(res.status == 200){
-						uni.showToast({ icon:'none', title: '清运成功,库存重量已重置为0' })
-						_this.messagePop = false
-						setTimeout(()=>{
-							_this.refresh()
-						},1000)
-					}else{
-						uni.showToast({ icon:'none', title: res.message })
-					}
-				})
+			// 检查更新
+			checkUpdate(){
+				if (uni.canIUse('getUpdateManager')) {
+				      const updateManager = uni.getUpdateManager()
+				      updateManager.onCheckForUpdate(function (res) {
+				        console.log('onCheckForUpdate====', res)
+				        // 请求完新版本信息的回调
+				        if (res.hasUpdate) {
+				          console.log('res.hasUpdate====')
+				          updateManager.onUpdateReady(function () {
+				            uni.showModal({
+				              title: '更新提示',
+				              content: '新版本已经准备好,是否重启应用?',
+				              success: function (res) {
+				                console.log('success====', res)
+				                // res: {errMsg: "showModal: ok", cancel: false, confirm: true}
+				                if (res.confirm) {
+				                  // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
+				                  updateManager.applyUpdate()
+				                }
+				              }
+				            })
+				          })
+				          updateManager.onUpdateFailed(function () {
+				            // 新的版本下载失败
+				            uni.showModal({
+				              title: '已经有新版本了哟~',
+				              content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~'
+				            })
+				          })
+				        }
+				      })
+				    }
 			},
-			//  增加清运网点
-			openQuery(){
-				uni.navigateTo({
-				    url: '/pages/cleared/chooseNetwork'
-				})
+			// 打开查询弹窗
+			openSearch(){
+				if(this.hasLogin){
+					this.openScreen = true
+				}
 			},
 			// 获取查询参数 刷新列表
-			refresh(){
+			refresh(params){
+				this.searchForm = params
 				this.listdata = []
 				this.total = 0
 				this.searchHandle(1)
+				this.getTotal()
 			},
 			// 搜索查询
 			searchHandle (pageNo) {
-				uni.showLoading({
-					mask: true,
-				    title: '加载中'
-				})
 				this.status = "loading"
 				pageNo ? this.pageNo = pageNo : null
-				getSelfCleanTaskList({
+				gatherList({
 					pageNo: this.pageNo,
-					pageSize: this.pageSize
+					pageSize: this.pageSize,
+					beginDate: this.searchForm.beginDate?moment(this.searchForm.beginDate).format('YYYY-MM-DD 00:00:00'):'',
+					endDate: this.searchForm.endDate ? moment(this.searchForm.endDate).format('YYYY-MM-DD 23:59:59'):'',
 				}).then(res => {
-					uni.hideLoading()
 					if (res.status == 200) {
 						if(this.pageNo>1){
 							this.listdata = this.listdata.concat(res.data.list || [])
@@ -221,174 +216,183 @@
 					this.status = "loadmore"
 				})
 			},
-			//  移除
-			removeFun(row){
-				const _this = this
-				uni.showModal({
-				  title: '提示',
-				  content: '确认移除该网点的清运单?',
-				  success(res) {
-				    if (res.confirm) {
-						uni.showLoading({
-							mask: true,
-						    title: '加载中'
-						})
-						cleanStationRemove({ stationNo: row.stationNo }).then(ret => {
-							uni.hideLoading()
-							if(ret.status == 200){
-								uni.showToast({ title: ret.message, icon: 'none' })
-								_this.searchHandle(1)
-							}
-						})
-				    }
-				  }
-				})
-			},
-			//  查看详情
-			goPage(row){
-				uni.navigateTo({
-				    url: '/pages/cleared/network?stationNo='+row.stationNo
-				})
-			},
 			// scroll-view到底部加载更多
 			onreachBottom() {
-				if(this.listdata.length!=0 && this.listdata.length < this.total){
-					this.pageNo++
+				console.log(111111)
+				if(this.listdata.length < this.total){
+					this.pageNo += 1
 					this.searchHandle()
 				}else{
 					uni.showToast({ title: '已经到底了', icon: 'none' })
 					this.status = "nomore"
 				}
+			},
+			// 总计
+			getTotal(){
+				this.titleStatus = true
+				gatherTotal({
+					beginDate: this.searchForm.beginDate?moment(this.searchForm.beginDate).format('YYYY-MM-DD 00:00:00'):'',
+					endDate: this.searchForm.endDate ? moment(this.searchForm.endDate).format('YYYY-MM-DD 23:59:59'):''}).then(res=>{
+						if(res.status==200){
+							const a = res.data.find(item=>item.rubbishType=='GATHER_BUILDING')
+							const b = res.data.find(item=>item.rubbishType=='GATHER_OTHER')
+							const c = res.data.find(item=>item.rubbishType=='GATHER_KITCHEN')
+							this.jianzhuTotal= a ? (a.rubbishWeight/1000).toFixed(3)/1 : '0'
+							this.chuyuTotal= c ? (c.rubbishWeight/1000).toFixed(3)/1 : '0'
+							this.otherTotal= b ? (b.rubbishWeight/1000).toFixed(3)/1 : '0'
+						}
+					console.log(res)
+					this.titleStatus = false
+				})
+			},
+			// 打开垃圾数据录入页面
+			intoPage(item) {
+				const flag=item ? item.gatherId : ''
+				console.log(flag,'---------hangid,;;;;')
+				let url = flag ? `/pages/index/addData?id=${flag}` : `/pages/index/addData`
+				// uni.navigateTo({
+				//     url: url
+				// })
+				if(!this.hasLogin){
+					uni.showModal({
+					  title: '提示',
+					  content: '您尚未登录或登录已过期,请登录后使用',
+					  success: (res)=> {
+					    if (res.confirm) {
+					     uni.navigateTo({
+					         url: '/pages/login/login'
+					     })
+					    } else if (res.cancel) {
+					      console.log('用户点击取消');
+					    }
+					  }
+					});
+				} else {
+					uni.navigateTo({
+					    url: url
+					})
+				}
 			}
 		}
 	}
 </script>
 
-<style lang="scss">
-	page{
-		height: 100%;
-	}
-	.unclear-container {
+<style lang="scss" scoped>
+	.content {
 		width: 100%;
-		height: 100%;
+		height: 100vh;
 		display: flex;
 		flex-direction: column;
-		padding-bottom: 204rpx;
-		//  列表
-		.scroll-con{
-			flex: 1;
-			overflow: auto;
-		}
-		//  列表样式
-		.cell-item-con{
-			.cell-item{
-				margin: $uni-spacing-col-base $uni-spacing-row-base;
-				background-color: #fff;
-				border-radius: $uni-border-radius-base;
-				color: $uni-text-color;
-				font-size: $uni-font-size-base;
-				box-shadow: 3rpx 3rpx 5rpx #eee;
-				padding: 40rpx 20rpx;
-				position: relative;
-				.cell-item-c{
+		justify-content: center;
+		align-items: center;
+		.header{
+			width: 100%;
+			background-color: #FFFFFF;
+			display: flex;
+			flex-direction: column;
+			border-radius: 15upx;
+			padding: 30upx;
+			box-shadow: 0upx 3upx 6upx #eee;
+			margin-bottom: 20upx;
+			:first-child {
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+			}
+			.header-cont{
+				margin-top: 20upx;
+				display: flex;
+				align-items: center;
+				justify-content: space-around;
+				.cont-item{
 					display: flex;
-					justify-content: space-around;
+					flex-direction: column;
 					align-items: center;
-					.cell-item-info{
-						flex-grow: 1;
-						.cell-item-info-network{
-							word-break: break-all;
-							margin-bottom: 26rpx;
-							display: inline-block;
-							position: relative;
-						}
-						.cell-item-info-weight{
-							font-size: 24rpx;
-							display: flex;
-							align-items: center;
-							justify-content: space-between;
-							.cell-item-weight-bar{
-								position: relative;
-								display: inline-block;
-								padding-right: 50rpx;
-								&:nth-child(2){
-									padding-right: 76rpx;
-								}
-							}
-						}
+					text{
+						line-height: 50upx;
 					}
-					.arrow-right{
-						flex-shrink: 0;
-						margin-left: 80rpx;
+					text:last-child{
+						font-weight: 600;
+						font-size: 28upx;
 					}
 				}
-				.handle-btn{
-					position: absolute;
-					right: $uni-spacing-row-sm;
-					top: $uni-spacing-col-sm;
+				.other{
+					color: #FB1E1E;
 				}
-			}
-		}
-		.footer-bar{
-			width: 100%;
-			height: 204rpx;
-			padding: 0 10%;
-			position: fixed;
-			bottom: 0;
-			left: 0;
-			text-align: center;
-			.footer-handle-btn{
-				display: block;
-				.btn-icon{
-					margin-right: 10rpx;
+				.chuyu{
+					color: #FCAE53;
+				}
+				.jianzhu{
+					color: #4EACFA;
 				}
 			}
-			.scan-btn{
-				margin-top: 24rpx;
-				margin-bottom: 20rpx;
+			.filter-img{
+				padding: 10upx;
 			}
 		}
-		// 弹框样式
-		.custom-pop{
-			.custom-con{
-				text-align: center;
-				background: url(/static/pop-bg.png) no-repeat;
-				background-size: 100% 100%;
-				font-size: 30rpx;
-				color: #5a5a5a;
-				line-height: 54rpx;
-				.pop-title{
-					padding: 20rpx 0;
-					color: #fff;
-					font-weight: bold;
-				}
-				.pop-con{
-					padding: 80rpx 0 40rpx;
-					.pop-item{
-						padding: 0 20rpx;
-					}
-					.form-con{
-						padding: 10rpx 30rpx;
+		.scroll-con{
+			flex: 1;
+			width: 100%;
+			-webkit-box-flex:1;
+			-webkit-flex:1;
+			-ms-flex:1;
+			overflow: auto;
+			.cell-item{
+				width: 100%;
+				background-color: #fff;
+				border-radius: 15upx;
+				// padding: 20upx;
+				box-shadow: 0upx 3upx 6upx #eee;
+				.cell-item-title{
+					padding: 20upx 20upx 10upx;
+					width: 100%;
+					display: flex;
+					justify-content: space-between;
+					// border-bottom: 1px solid #e6e6e6;
+					.view{
+						color: #999999;
+						margin-right: 12upx;
 					}
 				}
-				.btn-con{
-					border-top: 1rpx solid rgba(213,213,213,0.8);
-					.handle-pop-btn{
-						padding: 20rpx 0;
-						width: 50%;
-						display: inline-block;
-					}
-					.cancel-btn{
-						border-right: 1rpx solid rgba(213,213,213,0.8);
+				.cell-item-cont{
+					width: 100%;
+					display: flex;
+					justify-content: space-between;
+					padding: 20upx;
+					margin-bottom: 20upx;
+					.cont-item{
+						display: flex;
+						flex-direction: column;
+						align-items: center;
+						width: 33%;
+						// border-right: 1px solid #e6e6e6;
+						:first-child {
+							width: 120upx;
+							height: 120upx;
+							margin-bottom: 20upx;
+						}
 					}
-					.submit-btn{
-						color: #16d1bc;
+					:last-child {
+						border: none;
 					}
 				}
 			}
 		}
-		.nodata{
-			padding-top: 400rpx;
+		.footer{
+			z-index: 9999;
+			// position: absolute;
+			// bottom: 30upx;
+			// margin: 20upx;
+			width: 95%;
+			height: 80upx;
+			background-color: #0DC55F;
+			opacity: 1;
+			border-radius: 50upx;
+			color: #fff;
+			font-size: 30rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
 		}
 	}
 </style>

+ 0 - 225
pages/index/map.vue

@@ -1,225 +0,0 @@
-<template>
-	<view class="map-container">
-		<map
-			id="map"
-			:latitude="latitude"
-			:longitude="longitude"
-			scale="12"
-			show-compass
-			show-location
-			:markers="markers"
-			:polyline="polyline"
-			@markertap="markertap"
-			style="width: 100%; height:100%;">
-		</map>
-	</view>
-</template>
-
-<script>
-	import { getCleanWay } from '@/api/unclear.js'
-	var QQMapWX = require('@/libs/qqmap-wx-jssdk.min.js')
-	var qqmapsdk
-	export default{
-		data(){
-			return{
-				latitude: null,  //  纬度
-				longitude: null,  //  经度
-				markers: [],  //  所有网点标注点
-				distanceMark: [],  //  按距离计算远近后的网点标注点
-				polyline: null,  //  路线
-			}
-		},
-		onLoad() {
-			// 实例化API核心类
-			qqmapsdk = new QQMapWX({
-				key: 'FRCBZ-IDZWW-FGDRR-O3SQM-ZW5C2-LRBDM'
-			})
-		},
-		onShow() {
-			this.getLocation()
-		},
-		methods: {
-			//  获取当前位置
-			getLocation(){
-				const _this = this
-				uni.getLocation({
-				    type: 'gcj02',
-				    success: function (res) {
-						_this.latitude = res.latitude  //  纬度
-						_this.longitude = res.longitude  //  经度
-						_this.getCleanWay()  //  获取个人待清运清单
-				    }
-				})
-			},
-			// 标注点信息
-			getCleanWay(){
-				getCleanWay({ lng: this.longitude, lat: this.latitude }).then(res => {
-					if(res.status == 200){
-						this.markers = []
-						res.data.map((item, index) => {
-							if(item.lat && item.lng){  //  经纬度为空的错误数据,网点信息不在地图上显示
-								this.markers.push({
-									id: index+1,
-									latitude: item.lat,
-									longitude: item.lng,
-									width: '60rpx',
-									height: '60rpx',
-									iconPath: '/static/store.png',
-									label: {
-										content: item.stationName || '--',
-										bgColor: '#fff',
-									}
-								})
-							}
-						})
-						if(this.markers.length>0){
-							this.onCalculateDistance()  //  计算距离
-						}
-					}
-				})
-			},
-			//  将所有标注点与当前位置进行距离计算
-			onCalculateDistance(){
-				const _this = this
-				const startPos = { latitude: _this.latitude, longitude: _this.longitude }
-				let destPos = []
-				_this.markers.map(item => {
-					destPos.push({ latitude: item.latitude, longitude: item.longitude })
-				})
-				//调用距离计算接口
-				qqmapsdk.calculateDistance({
-					mode: 'driving', //可选值:'driving'(驾车)、'walking'(步行),不填默认:'walking',可不填
-					//from参数不填默认当前地址
-					//获取表单提交的经纬度并设置from和to参数(示例为string格式)
-					from: startPos, //若起点有数据则采用起点坐标,若为空默认当前地址
-					to: destPos, //终点坐标
-					success: function(res) {//成功后的回调
-					  var res = res.result
-					  _this.distanceMark = []
-					  for (var i = 0; i < res.elements.length; i++) {
-						//  将距离值加入标注点信息中
-						_this.distanceMark.push({
-							latitude: res.elements[i].to.lat,
-							longitude: res.elements[i].to.lng,
-							distance: res.elements[i].distance
-						})
-					  }
-					  //  数组升序排序
-					  _this.distanceMark.sort(_this.compare( 'distance', true ))
-					  _this.onDirection()  //  路线规划
-					},
-					fail: function(error) {
-					  console.error(error)
-					},
-					complete: function(res) {
-					  // console.log(res)
-					}
-				})
-			},
-			//  数组排序
-			compare(property, desc){
-				return function (a, b) {
-					var value1 = a[property]
-					var value2 = b[property]
-					if(desc==true){  // 升序排列
-						return value1 - value2
-					}else{  // 降序排列
-						return value2 - value1
-					}
-				}
-			},
-			//  路线规划
-			onDirection(){
-				const _this = this
-				_this.polyline = []
-				//  将所有标注点都按距离进行路线规划
-				var position = null
-				position = [
-					{ latitude: _this.latitude, longitude: _this.longitude },
-					{ latitude: _this.distanceMark[0].latitude, longitude: _this.distanceMark[0].longitude }
-				]
-				_this.getDirection(position, 0)
-			},
-			//  路线规划
-			getDirection(position, ind){
-				const _this = this
-				qqmapsdk.direction({
-					mode: 'driving',//可选值:'driving'(驾车)、'walking'(步行)、'bicycling'(骑行),不填默认:'driving',可不填
-					//from参数不填默认当前地址
-					from: {
-						latitude: position[0].latitude,
-						longitude: position[0].longitude
-					},
-					to: {
-						latitude: position[1].latitude,
-						longitude: position[1].longitude
-					}, 
-					policy: 'LEAST_TIME,NAV_POINT_FIRST',
-					success: function (res) {
-						var ret = res
-						var coors = ret.result.routes[0].polyline, pl = []
-						//坐标解压(返回的点串坐标,通过前向差分进行压缩)
-						var kr = 1000000
-						for (var i = 2; i < coors.length; i++) {
-						  coors[i] = Number(coors[i - 2]) + Number(coors[i]) / kr;
-						}
-						//将解压后的坐标放入点串数组pl中
-						for (var i = 0; i < coors.length; i += 2) {
-						  pl.push({ latitude: coors[i], longitude: coors[i + 1] })
-						}
-						//设置polyline属性,将路线显示出来,将解压坐标第一个数据作为起点
-						_this.polyline.push({
-							points: pl,
-							arrowLine: true,
-							width: 8,
-							color: '#07c160'
-						})
-					},
-					fail: function (error) {
-						console.error(error)
-					},
-					complete: function (res) {
-						// 腾讯地图使用限制
-						// 为了保证我们的服务稳定,我们对每个key的每个服务接口的调用量做了如下限制:
-						// 日调用量:1万次 / Key
-						// 并发数:5次 / key / 秒
-						
-						//  递归调用避免并发限制
-						if(ind < _this.distanceMark.length-1){
-							let pos = [
-								{ latitude: _this.distanceMark[ind].latitude, longitude: _this.distanceMark[ind].longitude },
-								{ latitude: _this.distanceMark[ind+1].latitude, longitude: _this.distanceMark[ind+1].longitude }
-							]
-							let subInd = ind
-							subInd++
-							setTimeout(()=>{
-								_this.getDirection(pos, subInd)
-							},300)
-						}
-					}
-				})
-			},
-			//  点击标注点,调用第三方地图查看规划路线
-			markertap(e){
-				this.markers.map(item => {
-					if(item.id == e.detail.markerId){
-						uni.openLocation({
-							latitude: item.latitude,
-							longitude: item.longitude,
-							success: function () {
-								
-							}
-						})
-					}
-				})
-			}
-		}
-	}
-</script>
-
-<style lang="scss" scoped>
-	.map-container {
-		width: 100%;
-		height: 100vh;
-	}
-</style>

+ 62 - 60
pages/cleared/searchModal.vue → pages/index/searchModal.vue

@@ -4,9 +4,9 @@
 		<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="stationName" class="form-item"><u-input v-model="form.stationName" :maxlength="30" placeholder="请输入网点名称" /></u-form-item>
-				<u-form-item label="排序方式:" prop="orderType" class="form-item">
-					<view @tap="openSort=true" :style="{color: form.orderType?null:'#c0c4cc'}">{{orderTypeName}}</view>
+				<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>
 			<view class="uni-list-btns">
@@ -14,13 +14,24 @@
 				<u-button class="handle-btn" size="medium" hover-class="none" @click="resetForm">重置</u-button>
 			</view>
 		</u-popup>
-		<u-picker mode="selector" v-model="openSort" :default-selector="selectDefault" :range="list" range-key="dispName" @confirm="confirm"></u-picker>
+		<!-- 时间选择器 -->
+		<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>
+</template> 
 
 <script>
-import { getLookUpDatas } from '@/api/data.js'
+import wPicker from '@/components/w-picker/w-picker.vue'
 export default {
+	components: { wPicker },
 	props: {
 		visible: {
 			type: Boolean,
@@ -29,7 +40,7 @@ export default {
 		defaultParams: {  //  默认筛选条件
 			type: Object,
 			default: () => {
-				return {}
+				return {};
 			}
 		}
 	},
@@ -50,63 +61,60 @@ export default {
 	data() {
 		return {
 			customBtnStyle: {  //  自定义按钮样式
-				borderColor: '#07c160',
-				backgroundColor: '#07c160',
+				borderColor: '#2ab4e5',
+				backgroundColor: '#2ab4e5',
 				color: '#fff'
 			},
 			isShow: this.visible, // 显示隐藏
+			showPicker: false, // 是否显示时间弹窗
 			form: {
-				stationName: '',  //  套餐名称
-				orderType: '', // 客户手机
+				time: '', // 发起时间区间
+				customerMobile: '', // 门店名称
 			},
-			list: [],
-			openSort: false,  //  选择
-			orderTypeName: '请选择',
-			selectDefault: [0],  //  下拉默认选中项
+			beginDate: null, // 开始时间
+			endDate: null // 结束时间
 		};
 	},
 	mounted() {
 		this.init()
 	},
-	created() {
-		this.getLookUpDatas()
-	},
 	methods: {
-		//  获取数据字典
-		getLookUpDatas(){
-			getLookUpDatas({ type: 'WAIT_CLEAN_SORT_RULE' }).then(res => {
-				if(res.status == 200){
-					this.list = res.data || []
-					this.form.orderType = this.defaultParams.orderType ? this.defaultParams.orderType : ''
-					if(this.defaultParams.orderType){
-						this.list.map((item, index) => {
-							if(item.code == this.form.orderType){
-								this.orderTypeName = this.list[index].dispName
-								this.selectDefault[0] = index
-							}
-						})
-					}
-				}else{
-					this.list = []
-					this.form.orderType = ''
-					this.orderTypeName = '请选择'
-					this.selectDefault = [0]
-				}
-			})
-		},
 		//  初始化数据
 		init(){
-			this.form.stationName = this.defaultParams.stationName ? this.defaultParams.stationName : ''
+			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 = {
-				stationName: this.form.stationName,
-				orderType: this.form.orderType,
+				beginDate: this.beginDate,
+				endDate: this.endDate,
+				customerMobile: this.form.customerMobile,
 			};
 			this.$emit('refresh', params)
 			this.isShow = false
@@ -114,14 +122,8 @@ export default {
 		// 重置
 		resetForm() {
 			this.$refs.uForm.resetFields()
-			this.$emit('refresh', {orderType: 'max'})
+			this.$emit('refresh', {})
 			this.isShow = false
-		},
-		//  确定
-		confirm(v){
-			this.selectDefault = v
-			this.form.orderType = this.list[v[0]].code
-			this.orderTypeName = this.list[v[0]].dispName
 		}
 	}
 };
@@ -134,23 +136,23 @@ export default {
 .search-popup {
 	.search-title {
 		text-align: center;
-		padding: 18rpx 22rpx;
+		padding: 18upx 22upx;
 		color: #333;
 		border-bottom: 1px solid #eee;
 	}
 	.form-content {
 		display: block;
-		padding: 0 20rpx;
+		padding: 0 20upx;
 		box-sizing: content-box;
 		.status-item {
 			width: 30%;
 			text-align: center;
-			line-height: 60rpx;
+			line-height: 60upx;
 			background-color: #F8F8F8;
 			color: #333;
-			border-radius: 6rpx;
-			font-size: 24rpx;
-			margin: 0 10rpx;
+			border-radius: 6upx;
+			font-size: 24upx;
+			margin: 0 10upx;
 		}
 		.active {
 			background-color: #ffaa00;
@@ -163,7 +165,7 @@ export default {
 		}
 	}
 	.uni-list {
-		margin: 20rpx;
+		margin: 20upx;
 		.uni-list-cell {
 			display: flex;
 			align-items: center;
@@ -179,11 +181,11 @@ export default {
 	}
 	.uni-list-btns {
 		display: flex;
-		padding: 20rpx;
+		padding: 20upx;
 		margin-top: 200rpx;
 		.handle-btn {
-			font-size: 28rpx;
-			margin: 0 30rpx;
+			font-size: 28upx;
+			margin: 0 30upx;
 			width: 100%;
 			flex: 1;
 		}

+ 0 - 229
pages/login/forget-pass.vue

@@ -1,229 +0,0 @@
-<template>
-	<view class="forget-wrap">
-		<form class="login-form" @submit="formSubmit">
-			<view v-show="state == 0">
-				<view class="form-item">
-					<input v-model="form.phone" class="item-inp" name="phone" type="number" maxlength="11" placeholder="请输入登录手机号" />
-				</view>
-				<view class="form-item">
-					<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-btn-con">
-					<button class="form-btn" @click="goStep">下一步</button>
-				</view>
-			</view>
-			<view v-show="state == 1">
-				<view class="form-item">
-					<input v-model="form.password" class="item-inp" name="password" password type="text" maxlength="12" placeholder="请输入新密码" />
-				</view>
-				<view class="form-item">
-					<input v-model="form.passwords" class="item-inp" name="passwords" password type="text" maxlength="12" placeholder="请再次输入新密码" />
-				</view>
-				<view class="form-btn-con">
-					<button class="form-btn" form-type="submit">提交</button>
-				</view>
-			</view>
-		</form>
-		<!-- 图文验证码 -->
-		<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 { isvalidPhone } from '@/libs/validate.js'
-	import uniPopup from '@/components/uni-popup/uni-popup.vue'
-	import popupCon from '@/components/uni-popup/popup-con.vue'
-	import { memberVerifyCode, memberChangePwd, memberValidateVerifyCode, memberGetByMobile } from '@/api/user.js'
-	import { clzConfirm } from '@/libs/tools.js'
-	export default{
-		components: {
-			uniPopup,
-			popupCon
-		},
-		data(){
-			return{
-				state: 0,  //  忘记密码当前状态
-				form: {
-					phone: '',
-					verifyCode: '',
-					password: '',
-					passwords: ''
-				},
-				nowVal: '获取验证码',  //  按钮显示内容
-				count: '',  //  当前秒数
-				timer: null,  //  倒计时
-				isDisable: false,  //  是否禁止获取验证码
-				popBtn: [],  //  name为操作按钮名称,color为操作按钮颜色值
-				changeImg: false,  //  是否重新更换图形验证码
-				randomCode: '',  //  图片验证码随机码
-			}
-		},
-		onLoad(opts) {
-			if(opts.username){
-				this.form.phone = opts.username
-			}
-		},
-		methods: {
-			//  下一步
-			goStep(){
-				const _this = this
-				//  表单校验
-				if(this.form.phone == ''){
-					uni.showToast({icon: 'none',title: '请输入登录手机号'})
-					return
-				}
-				if(!isvalidPhone(this.form.phone)){
-				  uni.showToast({icon: 'none',title: '请输入正确的手机号码'})
-				  return
-				}
-				if(this.form.verifyCode == ''){
-					uni.showToast({icon: 'none',title: '请输入验证码'})
-					return
-				}
-				//  校验短信验证码是否正确
-				const obj = {}
-				obj.phone = _this.form.phone,
-				obj.random = _this.randomCode,  // 当前随机码
-				obj.verifyCode = _this.form.verifyCode
-				memberValidateVerifyCode(obj).then(res => {
-				  if(res.status == 200){
-				    _this.state = 1
-				  }else{
-					  uni.showToast({icon: 'none',title: res.message})
-				  }
-				})
-			},
-			//  表单提交
-			formSubmit(){
-				const _this = this
-				if(this.form.password == ''){
-					uni.showToast({icon: 'none',title: '请输入新密码'})
-					return
-				}
-				if(this.form.password.length < 6 || this.form.password.length > 12){
-					uni.showToast({icon: 'none',title: '请输入6-12位新密码'})
-					return
-				}
-				if(this.form.passwords == ''){
-					uni.showToast({icon: 'none',title: '请再次输入新密码'})
-					return
-				}
-				if(this.form.password != this.form.passwords){
-					uni.showToast({icon: 'none',title: '两次密码输入不一致'})
-					return
-				}
-				const obj = {}
-				obj.phone = _this.form.phone,
-				obj.random = _this.randomCode,  // 当前随机码
-				obj.verifyCode = _this.form.verifyCode,
-				obj.password = _this.form.password
-				memberChangePwd(obj).then(res => {
-					if(res.status == 200){
-						//  将修改后的账号密码  重新存储
-						_this.$u.vuex('vuex_user.account', _this.form.phone)
-						_this.$u.vuex('vuex_user.password', '')
-						clzConfirm({
-						    title: '提示',
-						    content: '修改成功',
-							confirmText: '去登录',
-							showCancel: false,
-							success: function (ret) {
-						        if (ret.confirm||ret.index==0) {
-									uni.reLaunch({
-										url: '/pages/login/login'
-									})
-						        }
-						    }
-						})
-					}
-				})
-			},
-			//  获取验证码
-			getCodeValidate(){
-				if(this.form.phone){
-					if(!isvalidPhone(this.form.phone)){
-						uni.showToast({icon: 'none',title: '请输入正确的手机号码'})
-						return
-					}else{
-						//  校验手机号是否注册过
-						memberGetByMobile({phone: this.form.phone}).then(res => {
-							if(res.status == 200){
-								//  图文验证码
-								this.$refs.imageTxtPopup.open()
-							}else{
-								uni.showToast({icon: 'none',title: res.message})
-							}
-						})
-					}
-				}else{
-					uni.showToast({icon: 'none',title: '请先输入手机号'})
-				}
-			},
-			//  开始倒计时
-			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)
-				}
-			},
-			//  图文验证码
-			captchaImg(code, nowRandomCode){
-				this.captchaVerify(code, nowRandomCode)
-			},
-			//  验证图片验证码
-			captchaVerify(code, nowRandomCode){
-				const _this = this
-				let obj = {}
-				obj.phone = this.form.phone
-				obj.random = nowRandomCode
-				obj.captcha = code
-				//  短信验证码
-				memberVerifyCode(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})
-					}
-				})
-			},
-		}
-	}
-</script>
-<style scoped lang="scss">
-	@import './login.scss';
-	.forget-wrap .login-form{
-		padding-top: 300upx;
-	}
-	.getcode-btn {
-		background-color: #298bf2 !important;
-		color: #fff !important;
-		border: none !important;
-	}
-</style>

+ 12 - 1
pages/login/login.scss

@@ -1,4 +1,4 @@
-.pw-login-wrap, .forget-wrap, .apply-wrap{
+.login-wrap, .forget-wrap, .apply-wrap{
 	background-color: #FFFFFF;
 	width: 100%;
 	height: 100vh;
@@ -71,4 +71,15 @@
 			}
 		}
 	}
+	
+	.authUserYs{
+		text-align: center;
+		position: absolute;
+		bottom: 5%;
+		width: 100%;
+		font-size: 24upx;
+		text{
+			color: #ff0000;
+		}
+	}
 }

+ 121 - 64
pages/login/login.vue

@@ -1,46 +1,57 @@
 <template>
-	<view class="login-content">
-		<view>
+	<view class="content">
+		<!-- <view> -->
 			<view>
-				<view class="logo">
-					<u-image src="/static/login_icon_logo" width="160" height="160" ></u-image>
+				<view class="logo-cont">
+					<u-image src="/static/login_icon.png" width="160" height="160" class="logo"></u-image>
+					<u-image src="/static/login_slogan.png" mode="aspectFit" width="286" height="36" class="logo_text"></u-image>
 				</view>
 				<view class="login-btns">
-					<u-button shape="circle" hover-class="none" :custom-style="wxButton" class="login-btn" type="success" :hair-line="false" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
+					<u-button shape="circle" :custom-style="wxButton" class="login-btn" type="success" :hair-line="false" open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">
 						微信授权登录
 					</u-button>
 					<u-gap height="30"></u-gap>
-					<u-button shape="circle" hover-class="none" :custom-style="phoneButton" class="login-btn" @click="pwLogin" type="primary">
+					<u-button shape="circle" :custom-style="phoneButton" class="login-btn phoneBtn" @click="phoneLogin" :hoverClass='none'>
 						账号密码登录
 					</u-button>
 				</view>
 			</view>
-		</view>
-		<view @click="toYs">登录即代表同意<text>隐私政策</text>和<text>服务条款</text></view>
+			<view class="nologin">
+				<u-button shape="circle" size="mini" plain lass="login-btn" @click="cansel" type="info">
+					暂不登录
+				</u-button>
+			</view>
+		<!-- </view> -->
+		<view @click="toYs" class="yszc">登录即代表同意<text class="yszc-text">服务协议及隐私保护政策</text></view>
 	</view>
 </template>
 
 <script>
-	import { login } from "@/api/login"
+	import {
+		login
+	} from "@/api/login"
 	export default {
 		components: {},
 		data() {
 			return {
 				path: '/pages/index/index',
-				lanuch: true,
+				lanuch: false,
 				code: '',
 				wxButton: {
-					background: '#07c160'
+					background: '#0DC55F'
 				},
 				phoneButton: {
-					background: '#00aaff'
+					background: '#fff',
+					color:'#000',
 				}
 			}
 		},
-		mounted() {},
 		onLoad(option) {
-			//  隐藏小房子
-			uni.hideHomeButton()
+			// 开启分享
+			uni.showShareMenu({
+				withShareTicket: true,
+				menus: ['shareAppMessage', 'shareTimeline']
+			})
 			// 为解决首次登录异常问题 进入页面先调微信登录获取code
 			this.wxLogin()
 			const {
@@ -73,33 +84,30 @@
 				if (!this.code) {
 					this.wxLogin()
 				} 
+				console.log(this.code, e)
 				if (e.target.errMsg === 'getPhoneNumber:ok') {
 					setTimeout(()=>{
-						login({
+						const params={
 							code: _this.code,
 							encryptedData: e.target.encryptedData,
-							iv: e.target.iv
-						}).then(res => {
+							iv: e.target.iv,
+						}
+						login(params).then(res => {
 							uni.hideLoading();
 							_this.code = ''
-							if (res.status == 200) {
+							console.log(res,_this.path, 'login data')
+							if (res.status == '200') {
 								getApp().globalData.token = res.data
 								_this.$u.vuex('vuex_token',res.data)
 								uni.$emit("getUserInfo")
 								if (_this.path === '/pages/index/index' || _this.lanuch) {
 									uni.reLaunch({
 										url: _this.path
-									})
+									});
 								} else {
-									if (_this.path === '/pages/cleared/index' || _this.path === '/pages/userCenter/index') {  //  tabbar页面
-										uni.switchTab({
-											url: _this.path
-										})
-									} else {
-										uni.redirectTo({
-											url: _this.path
-										})
-									}
+									uni.redirectTo({
+										url: _this.path
+									});
 								}
 							} else {
 								uni.showToast({
@@ -124,55 +132,104 @@
 				uni.login({
 					provider: 'weixin',
 					success(res) {
+						console.log(res.code)
 						_this.code = res.code
 					}
 				})
 			},
 			// 手机号登录
-			pwLogin () {
-			  wx.navigateTo({
-			    url: '/pages/login/pwLogin'
-			  })
+			phoneLogin () {
+				if(this.url){
+					wx.navigateTo({
+						url: '/pages/login/phoneLogin?path='+this.path+'&lanuch='+this.lanuch+'&encode='+this.url 
+					})
+				}else{
+					wx.navigateTo({
+						url: '/pages/login/phoneLogin?path='+this.path+'&lanuch='+this.lanuch
+					})
+				}
+			  
 			}
 		}
 	}
 </script>
 
-<style lang="scss" scoped>
-	.login-content {
+<style lang="scss">
+	.content{
 		width: 100%;
 		height: 100vh;
-		padding: 40upx;
-		display: flex;
-		flex-direction: column;
-		background-color: #fff;
-		> view{
+		padding:0 40upx;
+		margin: 0 auto;
+		.logo-cont{
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+		}
+		.logo{
+			display: inline-block;
+			margin:250upx 256upx 24upx;
+		}
+		.logo_text{
+			display: inline-block;
+			margin-bottom: 200upx;
+		}
+		.login-btn{
+			display: block;
+			width: 670upx;
+			height: 80upx;
+		}
+		.phoneBtn:active{
+			background: #fff ;
+			outline: none;
+		}
+		.nologin{
 			text-align: center;
-			&:first-child{
-				flex-grow: 1;
-				height: 80vh;
-				padding: 20% 10%;
-				display: flex;
-				flex-direction: column;
-				justify-content: space-between;
-			}
-			&:last-child{
-				font-size: 24upx;
-				text{
-					color: #07c160;
-				}
-			}
-			.logo{
-				text-align: center;
-				display: flex;
-				justify-content: center;
-			}
-			.login-btns{
-				padding: 60upx 0;
-				.login-btn{
-					margin: 30upx 0;
-				}
+			margin: 100upx 0 50upx 0;
+		}
+		.yszc{
+			font-size: 24upx;
+			text-align: center;
+			.yszc-text{
+				color:#07c160;
 			}
+			
 		}
 	}
+	// .content {
+	// 	width: 100%;
+	// 	height: 100%;
+	// 	padding: 40upx;
+	// 	display: flex;
+	// 	flex-direction: column;
+	// 	> view{
+	// 		text-align: center;
+	// 		&:first-child{
+	// 			flex-grow: 1;
+	// 			height: 80vh;
+	// 			padding: 20% 10%;
+	// 			display: flex;
+	// 			flex-direction: column;
+	// 			justify-content: space-between;
+	// 		}
+	// 		&:last-child{
+	// 			font-size: 24upx;
+	// 			text{
+	// 				color: #07c160;
+	// 			}
+	// 		}
+	// 		.logo{
+	// 			text-align: center;
+	// 			display: flex;
+	// 			justify-content: center;
+	// 		}
+	// 		.login-btns{
+	// 			// padding: 60upx 0;
+	// 			.login-btn{
+	// 				width: 670upx;
+	// 				height: 50upx;
+	// 				border-radius: 25upx;
+	// 			}
+	// 		}
+	// 	}
+	// }
 </style>

+ 79 - 0
pages/login/loginPw.scss

@@ -0,0 +1,79 @@
+.login-wrap, .forget-wrap, .apply-wrap{
+	background-color: #FFFFFF;
+	width: 100%;
+	height: 100vh;
+	box-sizing: border-box;
+	padding: 0 40upx;
+	.logo{
+		display: block;
+		margin: 0 auto;
+		padding: 200upx 256upx 60upx;
+	}
+	.login-form{
+		display: block;
+		.form-item{
+			margin-bottom: 20upx;
+			position: relative;
+			display: flex;
+			align-items: center;
+			border-bottom: 1upx solid #e5e5e5;
+			.require-tip{
+				position: absolute;
+				left: 0;
+				top: 26upx;
+				color: red;
+			}
+			.item-inp{
+				flex-grow: 1;
+			}
+			.item-inp, .item-picker{
+				font-size: 30upx;
+				padding: 20upx 20upx;
+			}
+			.getcode-btn{
+				position: absolute;
+				right: 20upx;
+				top: 0;
+				font-size: 24upx;
+				margin-top: 14upx;
+			}
+		}
+		.flex-box{
+			display: flex;
+			justify-content: space-between;
+			font-size: 26upx;
+		}
+		.form-btn-con{
+			margin-top: 100upx;
+			.form-btn{
+				font-size: 32upx;
+				display: block;
+				height: 80upx;
+				line-height: 80upx;
+				margin: 0 auto;
+				background-color: #0DC55F;
+				color: #fff;
+				border-radius: 50upx;
+			}
+			uni-button.form-btn:after{
+				border: none;
+			}
+			.apply-btn{
+				display: block;
+				text-align: center;
+				margin-top: 50upx;
+			}
+		}
+	}
+	
+	.authUserYs{
+		text-align: center;
+		position: absolute;
+		bottom: 5%;
+		width: 100%;
+		font-size: 24upx;
+		text{
+			color: #ff0000;
+		}
+	}
+}

+ 27 - 8
pages/login/pwLogin.vue → pages/login/phoneLogin.vue

@@ -1,32 +1,36 @@
 <template>
-	<view class="pw-login-wrap">
+	<view class="login-wrap">
 		<!-- <view v-if="!buildType" style="text-align: center;color: #999999;padding-top: 40px;">{{ envTips }}</view> -->
-		<view class="logo">
-			<u-image src="/static/logo.jpg" width="140" height="140" ></u-image>
-		</view>
+		<u-image src="/static/login_icon.png" width="160" height="160" class="logo"></u-image>
 		<form class="login-form" @submit="formSubmit">
 			<view class="form-item">
+				<u-image src="/static/user_icon_number.png" width="44" height="44" class="logo_user_icon"></u-image>
 				<input v-model="form.loginName" class="item-inp" name="loginName" type="text" maxlength="30" placeholder="请输入用户名" />
 			</view>
 			<view class="form-item">
+				<u-image src="/static/user_icon_password.png" width="44" height="44" class="logo_pwd_icon"></u-image>
 				<input v-model="form.password" class="item-inp" name="password" password type="text" maxlength="12" placeholder="请输入密码" />
 			</view>
-			<view class="flex-box" style="margin-top: 60upx;">
+			<view class="flex-box" style="margin-top: 40upx;">
 				<view class="remember-pass">
-					<u-checkbox v-model="isRemember" value="true" :size="30" :label-size="26" active-color="#07c160" class="login-form-checkbox" @change="rememberChange">记住密码</u-checkbox>
+					<u-checkbox shape="circle" v-model="isRemember" value="true" :size="30" :label-size="26" active-color="#0DC55F" class="login-form-checkbox" @change="rememberChange">记住密码</u-checkbox>
 				</view>
 			</view>
 			<view class="form-btn-con">
 				<button class="form-btn" form-type="submit">登录</button>
 			</view>
 		</form>
+		<!-- <view class="authUserYs">
+			<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>
 
 <script>
 import { checkVersionToLoadUpdate, setStorageForAppVersion,clzConfirm } from '@/libs/tools'
 import { isvalidPhone } from '@/libs/validate.js';
-import { loginPhone } from '@/api/user.js';
+import { loginPhone } from '@/api/login.js';
 import { getSysVersion } from '@/api/data.js'
 export default {
 	data() {
@@ -36,12 +40,14 @@ export default {
 				password: this.$store.state.vuex_user.password
 			},
 			isRemember: true, //  是否记住密码
+			isAuthuserYs: true, // 是否同意隐私政策
 			envTips: '',
 			buildType: '',
 		};
 	},
 	mounted() {
 		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;
 	},
@@ -72,6 +78,10 @@ export default {
 				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;
@@ -80,6 +90,10 @@ export default {
 				uni.showToast({ icon: 'none', title: '请输入6-12位密码' });
 				return;
 			}
+			if (!_this.isAuthuserYs) {
+				uni.showToast({ icon: 'none', title: '请同意并阅读用户隐私政策' });
+				return;
+			}
 			uni.showLoading({
 				title: '正在登录...'
 			});
@@ -134,6 +148,11 @@ export default {
 		rememberChange(e) {
 			this.isRemember = e.value;
 		},
+		// 隐私
+		authuserChange(e) {
+			this.isAuthuserYs = e.value;
+			this.$u.vuex('vuex_isUsrAuthYs', this.isAuthuserYs);
+		},
 		toYsPage() {
 			uni.navigateTo({
 				url: '/pages/agreement/agreement'
@@ -143,5 +162,5 @@ export default {
 };
 </script>
 <style scoped lang="scss">
-@import './login.scss';
+@import './loginPw.scss';
 </style>

+ 0 - 66
pages/login/userAuthYs.vue

@@ -1,66 +0,0 @@
-<template>
-	<view class="article">
-		<view>章鱼车管家尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的服务,本应用会按照本隐私权政策的规定使用和披露您的个人信息。但本应用将以高度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外,在未征得您事先许可的情况下,本应用不会将这些信息对外披露或向第三方提供。</view>
-		<view>本应用会不时更新本隐私权政策。 您在同意本应用服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私权政策属于本应用服务使用协议不可分割的一部分。</view>
-		<view>
-			<p>适用范围</p>
-			<p>(a) 在您注册本应用帐号时,您根据本应用要求提供的个人注册信息;</p>
-			<p>(b) 在您使用本应用网络服务,或访问本应用平台网页时,本应用自动接收并记录的您的浏览器和计算机上的信息,包括但不限于您的IP地址、浏览器的类型、使用的语言、访问日期和时间、软硬件特征信息及您需求的网页记录等数据;</p>
-			<p>(c) 本应用通过合法途径从商业伙伴处取得的用户个人数据。您了解并同意,以下信息不适用本隐私权政策:(a) 您在使用本应用平台提供的搜索服务时输入的关键字信息;</p>
-			<p>(b) 本应用收集到的您在本应用发布的有关信息数据,包括但不限于参与活动、成交信息及评价详情;</p>
-			<p>(c) 违反法律规定或违反本应用规则行为及本应用已对您采取的措施。</p>
-		</view>
-		<view>
-			<p>信息使用</p>
-			<p>(a) 本应用不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先得到您的许可,或该第三方和本应用(含本应用关联公司)单独或共同为您提供服务,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些资料。</p>
-			<p>(b) 本应用亦不允许任何第三方以任何手段收集、编辑、出售或者无偿传播您的个人信息。任何本应用平台用户如从事上述活动,一经发现,本应用有权立即终止与该用户的服务协议。</p>
-			<p>(c) 为服务用户的目的,本应用可能通过使用您的个人信息,向您提供您感兴趣的信息,包括但不限于向您发出产品和服务信息,或者与本应用合作伙伴共享信息以便他们向您发送有关其产品和服务的信息(后者需要您的事先同意)。</p>
-		</view>
-		<view>
-			<p>信息披露在如下情况下,本应用将依据您的个人意愿或法律的规定全部或部分的披露您的个人信息:</p>
-			<p>(a) 经您事先同意,向第三方披露;</p>
-			<p>(b) 为提供您所要求的产品和服务,而必须和第三方分享您的个人信息;</p>
-			<p>(c) 根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;</p>
-			<p>(d) 如您出现违反中国有关法律、法规或者本应用服务协议或相关规则的情况,需要向第三方披露;</p>
-			<p>(e) 如您是适格的知识产权投诉人并已提起投诉,应被投诉人要求,向被投诉人披露,以便双方处理可能的权利纠纷;</p>
-			<p>(f) 在本应用平台上创建的某一交易中,如交易任何一方履行或部分履行了交易义务并提出信息披露请求的,本应用有权决定向该用户提供其交易对方的联络方式等必要信息,以促成交易的完成或纠纷的解决。</p>
-			<p>(g) 其它本应用根据法律、法规或者网站政策认为合适的披露。</p>
-		</view>
-		<view><p>信息存储和交换本应用收集的有关您的信息和资料将保存在本应用及(或)其关联公司的服务器上,这些信息和资料可能传送至您所在国家、地区或本应用收集信息和资料所在地的境外并在境外被访问、存储和展示。</p></view>
-		<view>
-			<p>Cookie的使用</p>
-			<p>(a) 在您未拒绝接受cookies的情况下,本应用会在您的计算机上设定或取用cookies ,以便您能登录或使用依赖于cookies的本应用平台服务或功能。本应用使用cookies可为您提供更加周到的个性化服务,包括推广服务。</p>
-			<p>(b) 您有权选择接受或拒绝接受cookies。您可以通过修改浏览器设置的方式拒绝接受cookies。但如果您选择拒绝接受cookies,则您可能无法登录或使用依赖于cookies的本应用网络服务或功能。</p>
-			<p>(c) 通过本应用所设cookies所取得的有关信息,将适用本政策。</p>
-		</view>
-		<view>
-			<p>信息安全</p>
-			<p>(a) 本应用帐号均有安全保护功能,请妥善保管您的用户名及密码信息。本应用将通过对用户密码进行加密等安全措施确保您的信息不丢失,不被滥用和变造。尽管有前述安全措施,但同时也请您注意在信息网络上不存在“完善的安全措施”。</p>
-			<p>(b) 在使用本软件网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易对方披露自己的个人信息,如联络方式或者邮政地址。请您妥善保护自己的个人信息,仅在必要的情形下向他人提供。如您发现自己的个人信息泄密,请您立即联络本软件客服,以便本软件采取相应措施。</p>
-		</view>
-		<view>
-			<p>本隐私政策的更改</p>
-			<p>(a) 如果决定更改隐私政策,我们会在本政策中、本公司网站中以及我们认为适当的位置发布这些更改,以便您了解我们如何收集、使用您的个人信息,哪些人可以访问这些信息,以及在什么情况下我们会透露这些信息。</p>
-			<p>(b) 本公司保留随时修改本政策的权利,因此请经常查看。如对本政策作出重大更改,本公司会通过网站通知的形式告知。</p>
-		</view>
-    </view>
-</template>
-
-<script>
-</script>
-
-<style lang="scss">
-	.article{
-		 padding: 35upx 40upx;
-		 line-height: 46upx;
-		 >view{
-			 margin: 30upx 0;
-			 p{
-				 margin: 20upx 0;
-				 &:first-child{
-					 font-weight: bold;
-				 }
-			 }
-		 }
-	}
-</style>

+ 62 - 0
pages/userCenter/aboutUs.vue

@@ -0,0 +1,62 @@
+<template>
+	<view class="container">
+		<view class="logoContent">
+			<view class="logoBorder">
+				<image class="logoImg" src="/static/logo.jpg"></image>
+			</view>
+		</view>
+		<view class="textContent">
+			<view>智享亿家作为中国出色的垃圾分类专家和平台,致力于改变中国社区环保现状,通过多年的耕耘和积累,打造的城市垃圾分类一体化智能解决方案已获得咸阳、西安航天等多地市的环保垃圾处理资格,并成为全国住建部在咸阳市的环保模范单位。</view>
+		</view>
+	</view>
+</template>
+
+<script>
+</script>
+
+<style lang="less">
+	page{
+		background: #FFFFFF;
+	}
+	.container{
+		font-size: 32rpx;
+		padding:0 50rpx;
+		text-align: center;
+		color:#666;
+		.logoContent{
+			.logoBorder{
+				width:200rpx;
+				height:200rpx;
+				border:2px solid #eee;
+				border-radius: 20rpx;
+				margin:50rpx 0 15rpx 0;
+				display: inline-block;
+				position: relative;
+				.logoImg{
+					width:180rpx;
+					height:180rpx;
+					position: absolute;
+					top:0;
+					left:0;
+					right:0;
+					bottom:0;
+					margin:auto;
+				}
+			}
+		}
+		.textContent{
+			text-align: left;
+			margin-top: 30rpx;
+			font-size: 32rpx;
+			.tetxTitle{
+				margin-bottom: 10rpx;
+				font-size: 32rpx;
+			}
+			> view{
+				padding: 16upx 0;
+				line-height: 50upx;
+				text-indent: 60rpx;
+			}
+		}
+	}
+</style>

+ 36 - 12
pages/userCenter/changePwd.vue

@@ -5,29 +5,30 @@
 			<view class="input-group">
 				<view class="input-row border">
 					<text class="title">原密码:</text>
-					<m-input class="m-input" :maxlength="30"  type="password"  displayable v-model="formCustom.oldPwd" placeholder="请输入原密码"></m-input>
+					<m-input class="m-input" :maxlength="12" @input="getOldPwd" type="password"  displayable v-model="formCustom.oldPwd" placeholder="请输入原密码"></m-input>
 				</view>
 				<view class="input-row">
 					<text class="title">新密码:</text>
-					<m-input class="m-input" :maxlength="12" type="password" displayable v-model="formCustom.passwd" placeholder="请输入6-12位新密码"></m-input>
+					<m-input class="m-input" :maxlength="12" @input="getPasswd" type="password" displayable v-model="formCustom.passwd" placeholder="请输入6-12位新密码"></m-input>
 				</view>
 				<view class="input-row">
 					<text class="title">再次输入:</text>
-					<m-input class="m-input" :maxlength="12" type="password" displayable v-model="formCustom.passwdCheck" placeholder="请输入6-12位新密码"></m-input>
+					<m-input class="m-input" :maxlength="12" @input="getPasswdCheck" type="password" displayable v-model="formCustom.passwdCheck" placeholder="请输入6-12位新密码"></m-input>
 				</view>
 			</view>
 		</view>
-		<!-- 消息提醒弹窗 -->
+		<!-- 按钮 -->
 		<view class="form-footer-btn">
-			<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>
+			<u-button size="medium" hover-class="none" shape="circle" @click="handleReset">重置</u-button>
+			<u-button size="medium" hover-class="none" shape="circle" :loading="loading" :custom-style="customBtnStyle" @click="handleSubmit">保存</u-button>
 		</view>
 	</view>
 </template>
 
 <script>
 	import mInput from '../../components/m-input.vue'
-	import { changePwd, logout } from '@/api/user.js'
+	import { changePwd } from '@/api/user.js'
+	import { logout } from '@/api/login.js'
 	export default{
 		name:'changePwd',
 		components: {
@@ -42,8 +43,8 @@
 				},
 				loading: false,
 				customBtnStyle: {  //  自定义按钮样式
-					borderColor: '#07c160',
-					backgroundColor: '#07c160',
+					borderColor: '#0DC55F',
+					backgroundColor: '#0DC55F',
 					color: '#fff'
 				},
 			}
@@ -55,6 +56,31 @@
 					title: info
 				})
 			},
+			// 不能输入汉字
+			getOldPwd(val) {
+				console.log(val,'vvvvvvv')
+				 if (/[\u4E00-\u9FA5]/g.test(val)) {
+					this.$nextTick(() => {
+						this.formCustom.oldPwd = ''
+					})
+				}
+			},
+			getPasswd(val) {
+				console.log(val,'vvvvvvv')
+				 if (/[\u4E00-\u9FA5]/g.test(val)) {
+					this.$nextTick(() => {
+						this.formCustom.passwd = ''
+					})
+				}
+			},
+			getPasswdCheck(val) {
+				console.log(val,'vvvvvvv')
+				 if (/[\u4E00-\u9FA5]/g.test(val)) {
+					this.$nextTick(() => {
+						this.formCustom.passwdCheck = ''
+					})
+				}
+			},
 			handleSubmit(){
 				let _this = this
 				//非空判断密码长度判断
@@ -153,10 +179,8 @@
 				line-height: 32px;
 				display: flex;
 				align-items: center;
+				justify-content: space-between;
 				.title{
-					width:140rpx;
-					display: inline-block;
-					text-align: left;
 					color:#808080;
 				}
 			}

+ 140 - 54
pages/userCenter/index.vue

@@ -1,83 +1,137 @@
 <template>
 	<view class="user-content">
 		<!-- 头部 -->
-		<view class="user-head">
-			<view class="user-photo">
-				<open-data type="userAvatarUrl" class="avatar"></open-data>
+		<view class="user-head" >
+			<view>
+				<open-data type="userAvatarUrl" class="user-photo"></open-data>
+				<!-- <u-image v-show="!hasLogin" src="/static/logo.png" width="100" height="100"></u-image> -->
 			</view>
 			<view class="user-info">
-				<text class="user-name">{{userInfoData.name || ''}}</text>
-				<text class="user-phone">{{userInfoData.phone || ''}}</text>
+				<view v-if="hasLogin" class="user-info-item">{{userData.stationName || ''}}</view>
+				<view v-if="hasLogin" class="user-info-item">{{userData.gatherName||''}} {{userData.gatherPhone || ''}}</view>
+				<u-button v-else="!hasLogin" plain size="mini" shape="circle" @click="toLoginPage">立即登录</u-button>
 			</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="lock" icon-size="38" :icon-style="{color:'#00aaff'}" index="1" @click="toPage" title="修改密码"></u-cell-item>
+				<u-cell-item  v-if="hasLogin" icon="lock" icon-size="38" :icon-style="{color:'#00aaff'}" index="1" @click="toPage" title="修改密码"></u-cell-item>
+				<u-cell-item  icon="error-circle" icon-size="38" :icon-style="{color:'#aaaaff'}" :value="version" @click="checkUpdate" title="版本检查"></u-cell-item>
 			</u-cell-group>
 		</view>
-		<!-- 退出 -->
-		<view class="user-btn">
-			<u-button type="success" hover-class="none" :custom-style="quitButton" @click="quitSys" shape="circle">退出登录</u-button>
+		<view class="user-list quit">
+			<u-cell-group>
+				<u-cell-item  v-if="hasLogin" icon="minus-circle" icon-size="40" index="3" @click="quitSys" title="退出登录"></u-cell-item>
+			</u-cell-group>
 		</view>
 	</view>
 </template>
 
 <script>
-	import {logout} from '@/api/login.js'
-	import { getUserInfo } from '@/api/user.js'
+	import { checkLogin, getUserInfo, logout } from '@/api/login.js'
 	export default {
 		data() {
 			return {
-				quitButton: {
-					borderRadius:'100rpx',
-					fontSize:'30rpx',
-					background: '#01c9b2'
-				},
-				userInfoData: null,  //  用户信息
-				userAvatarUrl: ''  //  用户头像
+				hasLogin: false,
+				userData: {},
+				version: '1.0.0' // 小程序版本
 			};
 		},
 		onShow() {
-			this.getUserInfo()
+			checkLogin().then(res => {
+				this.hasLogin = res.status == 200
+				console.log(this.hasLogin,res,'this.hasLogin')
+				if(this.hasLogin){
+					this.getUserInfo()
+				}else{
+					// uni.navigateTo({
+					// 	url:"/pages/login/login"
+					// })
+				}
+			})
+		},
+		computed: {
+			user() {
+				return this.userData 
+			}
 		},
 		onLoad() {
+			// this.getVersion()
+			// 开启分享
+			uni.showShareMenu({
+				withShareTicket: true,
+				menus: ['shareAppMessage', 'shareTimeline']
+			})
 		},
 		methods:{
-			//  获取用户信息
+			// 获取当前小程序版本
+			getVersion(){
+				const accountInfo = uni.getAccountInfoSync();
+				this.version = accountInfo.miniProgram.version
+				console.log(accountInfo,accountInfo.miniProgram.appId,'ppppppppp'); // 小程序 appId
+			},
+			// 检查更新
+			checkUpdate(){
+				if (uni.canIUse('getUpdateManager')) {
+				      const updateManager = uni.getUpdateManager()
+				      updateManager.onCheckForUpdate(function (res) {
+				        console.log('onCheckForUpdate====', res)
+				        // 请求完新版本信息的回调
+				        if (res.hasUpdate) {
+				          console.log('res.hasUpdate====')
+				          updateManager.onUpdateReady(function () {
+				            uni.showModal({
+				              title: '更新提示',
+				              content: '新版本已经准备好,是否重启应用?',
+				              success: function (res) {
+				                console.log('success====', res)
+				                // res: {errMsg: "showModal: ok", cancel: false, confirm: true}
+				                if (res.confirm) {
+				                  // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
+				                  updateManager.applyUpdate()
+				                }
+				              }
+				            })
+				          })
+				          updateManager.onUpdateFailed(function () {
+				            // 新的版本下载失败
+				            uni.showModal({
+				              title: '已经有新版本了哟~',
+				              content: '新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~'
+				            })
+				          })
+				        } else {
+							uni.showToast({
+								title: '已是最新版本',
+								icon: 'none'
+							})
+						}
+				      })
+				    }
+			},
+			// 获取用户信息
 			getUserInfo(){
 				getUserInfo().then(res => {
+					console.log(res,'getUserInfo')
 					if(res.status == 200){
-						this.userInfoData = res.data
-					}else{
-						this.userInfoData = null
+						this.$u.vuex("vuex_userData",res.data)
+						this.userData = res.data
+						console.log(this.userData,'-----用户信息')
 					}
 				})
 			},
 			// 打开对应的页面
 			toPage(index){
+				console.log(index)
 				let pageUrl=[
 					'/pages/agreement/agreement?fromPage=usercenter',
-					'/pages/userCenter/changePwd'
+					'/pages/userCenter/changePwd',
 					]
 				uni.navigateTo({
 					url: pageUrl[index]
 				})
 			},
-			//  跳转
-			toUserPage(){
-				//  未登录跳转登录,已登录跳转用户信息页
-				uni.navigateTo({
-					url: '/pages/userCenter/userInfo/userInfo'
-				})
-			},
-			//  乐豆明细
-			toLdPage(){
-				uni.navigateTo({
-					url: '/pages/userCenter/ldDetailed'
-				})
-			},
 			// 退出登录
 			quitSys(){
 				let _this = this
@@ -86,9 +140,11 @@
 				  content: '您确定要退出登录吗?',
 				  success(res) {
 				    if (res.confirm) {
-				      logout({}).then(res => {
+				      logout().then(res => {
+					   console.log(res,'logout')
 				       getApp().globalData.token = ''
 				       _this.$u.vuex('vuex_token','')
+					   // 关闭socket
 				        uni.reLaunch({
 				        	url: '/pages/login/login'
 				        })
@@ -96,6 +152,12 @@
 				    }
 				  }
 				})
+			},
+			
+			toLoginPage(){
+				uni.navigateTo({
+					url: '/pages/login/login'
+				})
 			}
 		}
 	}
@@ -105,30 +167,51 @@
 	.user-content{
 		width: 100%;
 		.user-head{
-			background: #01c9b2;
+			background: #0DC55F;
 			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;
 				padding: 0 20rpx;
 				color: #FFFFFF;
-				.user-name{
-					display: block;
-					font-size: 30rpx;
-					margin-bottom: 20rpx;
+				.user-info-item{
+					margin: 10rpx 0;
+					:first-child{
+						font-size: 34upx;
+					}
+				}
+			}
+			.user-photo{
+				display: block;
+				width: 100rpx;
+				height: 100rpx;
+				border-radius: 50%;
+				overflow: hidden;
+			}
+		}
+		.my-ledou{
+			background: #FFFFFF;
+			border-radius: 15upx;
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			padding: 20upx;
+			margin: 20upx;
+			box-shadow: 0upx 3upx 6upx #eee;
+			.user-jifen{
+				display: flex;
+				align-items: center;
+				text{
+					font-size: 40upx;
+					font-weight: bold;
+					color: red;
 				}
-				.user-phone{
-					display: block;
-					font-size: 26rpx;
+				>view{
+					&:first-child{
+						display: flex;
+						align-items: center;
+					}
 				}
 			}
 		}
@@ -137,6 +220,9 @@
 			margin: 20upx;
 			overflow: hidden;
 			box-shadow: 0upx 3upx 6upx #eee;
+			.quit{
+				margin-top: 20upx;
+			}
 		}
 		.user-btn{
 			padding: 85rpx 200rpx;

BIN
static/GLASS.png


BIN
static/HARM.png


BIN
static/METAL.png


BIN
static/MET_PLA.png


BIN
static/PAPER.png


BIN
static/PLASTIC.png


BIN
static/RECYCLING.png


BIN
static/camera.png


BIN
static/edit.png


BIN
static/filter.png


BIN
static/full-bg.png


BIN
static/imgError.png


BIN
static/index/chuyu.png


BIN
static/index/jianzhu.png


BIN
static/index/logo-active.png


BIN
static/index/logo.png


BIN
static/index/other.png


BIN
static/ledou.png


BIN
static/loading.gif


BIN
static/login_icon.png


BIN
static/login_icon_logo.png


BIN
static/login_slogan.png


BIN
static/logo.jpg


BIN
static/logo.png


BIN
static/map-icon.png


BIN
static/md-big-pic.png


BIN
static/pop-bg.png


BIN
static/store-s.png


BIN
static/store.png


BIN
static/tabbar/cleared-active.png


BIN
static/tabbar/cleared.png


BIN
static/tabbar/home-active.png


BIN
static/tabbar/home.png


BIN
static/tabbar/shop-active.png


BIN
static/tabbar/shop.png


BIN
static/tabbar/unclean-active.png


BIN
static/tabbar/unclean.png


BIN
static/tabbar/user-active.png


BIN
static/tabbar/user.png


BIN
static/user_icon_number.png


BIN
static/user_icon_password.png


Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio