浏览代码

巡检端初始化

zhengkaixin 1 月之前
当前提交
45e11ee7ff
共有 100 个文件被更改,包括 13015 次插入0 次删除
  1. 112 0
      App.vue
  2. 15 0
      README.md
  3. 84 0
      apis/common.js
  4. 5 0
      apis/index.js
  5. 77 0
      apis/pagejs/deviceTab.js
  6. 108 0
      apis/pagejs/index.js
  7. 23 0
      apis/pagejs/record.js
  8. 91 0
      apis/pagejs/user-old.js
  9. 31 0
      apis/pagejs/user.js
  10. 1 0
      apis/pagejs/userTab.js
  11. 20 0
      apis/utils/AMap.js
  12. 31 0
      apis/utils/alipay.js
  13. 439 0
      apis/utils/index.js
  14. 114 0
      apis/utils/init.js
  15. 45 0
      apis/utils/initALI.js
  16. 98 0
      apis/utils/mixin.js
  17. 93 0
      apis/utils/request.js
  18. 70 0
      apis/utils/requestSon.js
  19. 75 0
      apis/utils/requestWhite.js
  20. 241 0
      apis/utils/wxJsApi.js
  21. 52 0
      apis/utils/wxpay.js
  22. 76 0
      apis/weixin.js
  23. 0 0
      assets/css/style.css
  24. 7 0
      assets/font/jptime.css
  25. 二进制
      assets/font/jptime.otf
  26. 22 0
      assets/icon/icon.vue
  27. 3 0
      assets/img/button/lock.svg
  28. 二进制
      assets/img/circleCopy1@1x.png
  29. 3 0
      assets/img/deviceTab/index1-1.svg
  30. 6 0
      assets/img/deviceTab/index2-1.svg
  31. 6 0
      assets/img/deviceTab/index2-2.svg
  32. 6 0
      assets/img/deviceTab/index2-3.svg
  33. 二进制
      assets/img/deviceTab/index3-1.png
  34. 二进制
      assets/img/deviceTab/index3-2.png
  35. 3 0
      assets/img/index/pie1-1.svg
  36. 6 0
      assets/img/index/pie1-2.svg
  37. 6 0
      assets/img/index/pie1-3.svg
  38. 二进制
      assets/img/logo/logo.png
  39. 3 0
      assets/img/myTab/icon1.svg
  40. 6 0
      assets/img/myTab/message1.svg
  41. 6 0
      assets/img/myTab/message2.svg
  42. 6 0
      assets/img/myTab/message3.svg
  43. 6 0
      assets/img/myTab/message4.svg
  44. 6 0
      assets/img/tabbarImg/item1a.svg
  45. 6 0
      assets/img/tabbarImg/item1b.svg
  46. 6 0
      assets/img/tabbarImg/item2a.svg
  47. 6 0
      assets/img/tabbarImg/item2b.svg
  48. 6 0
      assets/img/tabbarImg/item3a.svg
  49. 6 0
      assets/img/tabbarImg/item3b.svg
  50. 6 0
      assets/img/tabbarImg/item4a.svg
  51. 6 0
      assets/img/tabbarImg/item4b.svg
  52. 二进制
      assets/img/topspan/span1.png
  53. 二进制
      assets/img/topspan/span2.png
  54. 二进制
      assets/img/topspan/span3.png
  55. 二进制
      assets/img/topspan/span4.png
  56. 二进制
      assets/img/topspan/span5.png
  57. 6 0
      assets/img/userTab/index1-1.svg
  58. 6 0
      assets/img/userTab/index1-2.svg
  59. 二进制
      assets/img/暂无数据-缺省页.png
  60. 二进制
      assets/img/默认头像.png
  61. 34 0
      assets/js/font.js
  62. 48 0
      components/JPcontent.vue
  63. 205 0
      components/Map-equipment.vue
  64. 167 0
      components/ShareServer.vue
  65. 81 0
      components/Tabbar.vue
  66. 153 0
      components/bobo-router/README.md
  67. 362 0
      components/bobo-router/bobo-router.js
  68. 64 0
      components/bobo-router/index.js
  69. 227 0
      components/limeClipper/README.md
  70. 19 0
      components/limeClipper/images/photo.svg
  71. 15 0
      components/limeClipper/images/rotate.svg
  72. 160 0
      components/limeClipper/index.css
  73. 816 0
      components/limeClipper/limeClipper.vue
  74. 244 0
      components/limeClipper/utils.js
  75. 26 0
      config/.env.dev.js
  76. 42 0
      config/.env.js
  77. 21 0
      config/.env.prod.js
  78. 24 0
      config/.env.prodv4.js
  79. 17 0
      config/.env.test.js
  80. 20 0
      index.html
  81. 117 0
      main.js
  82. 92 0
      manifest.json
  83. 55 0
      package.json
  84. 210 0
      pages.json
  85. 439 0
      pages/deviceTab/bindLock.vue
  86. 123 0
      pages/deviceTab/bindLockStatus.vue
  87. 1799 0
      pages/deviceTab/dataLock.vue
  88. 324 0
      pages/deviceTab/deviceList.vue
  89. 153 0
      pages/deviceTab/index.vue
  90. 651 0
      pages/deviceTab/infoLock.vue
  91. 2179 0
      pages/index/index.vue
  92. 227 0
      pages/login/findBackPassword.vue
  93. 226 0
      pages/login/login.vue
  94. 107 0
      pages/myTab/abnormalInfo.vue
  95. 273 0
      pages/myTab/abnormalList.vue
  96. 227 0
      pages/myTab/as-components/limeClipper/README.md
  97. 19 0
      pages/myTab/as-components/limeClipper/images/photo.svg
  98. 15 0
      pages/myTab/as-components/limeClipper/images/rotate.svg
  99. 160 0
      pages/myTab/as-components/limeClipper/index.css
  100. 818 0
      pages/myTab/as-components/limeClipper/limeClipper.vue

+ 112 - 0
App.vue

@@ -0,0 +1,112 @@
+<style lang="scss">
+	/* 注意要写在第一行,同时给style标签加入lang="scss"属性 */
+	@import "@/uni_modules/uview-ui/index.scss";
+	//@import '@/assets/font/font.css';
+	
+</style>
+<script>
+	
+	import './config/.env.js'
+	import './assets/js/font.js'
+	export default {
+		onLaunch: function() {
+			console.log('App Launch')
+				
+		},
+		 
+		onShow: function() {
+			
+			console.log('App Show ---- App Show')
+		},
+		onHide: function() {
+			console.log('App Hide  -- App Hide  -App Hide')
+		}
+	}
+</script>
+
+<style lang="scss">
+	
+	html, body {
+	  background-color:#F2F4F6;
+	  margin: 0;
+	  padding: 0;
+	}
+	// 导航
+	.navbar-c{
+		background-color: #fff;
+		height: 88rpx;
+		line-height: 88rpx;
+		padding: 0 24rpx;
+		display: flex;
+		align-items: center;
+		position: sticky;
+		left: 0;
+		right: 0;
+		top: 0;
+		z-index: 99999;
+		.back{
+			.img{
+				width: 48rpx;
+				height: 48rpx;
+				vertical-align: middle;
+			}
+		}
+		
+		.title{
+			color: rgb(16,16,16);
+			font-size: 36rpx;
+			    flex: 1;
+			    position: absolute;
+			    left: 0;
+			    right: 0;
+			    text-align: center;
+			    flex-shrink: 0;
+			
+			.img{
+				width: 32rpx;
+				height: 32rpx;
+				vertical-align: middle;
+				margin-left: 8rpx;
+			}
+		}
+		.right{
+			display: flex;
+			align-items: center;
+			margin-left: auto;
+			font-size: 32rpx;
+			color: rgba(16,16,16,1);
+			.img{
+				width: 32rpx;
+				height: 32rpx;
+				margin-right: 4rpx;
+			}
+		}
+	}
+	// 导航栏标题文字
+	.u-title {
+		font-size: 36rpx !important
+	}
+	::v-deep.uicon-nav-back{
+	 
+		font-weight: bold !important;
+		font-size: 36rpx !important
+	}
+	#__vconsole{
+		z-index: 99999;
+		position: absolute;
+	}
+	.slot{
+		color: rgba(16,16,16,1);
+		font-size: 32rpx;
+		margin-right: 32rpx;
+	}
+	.uni-icon-success-no-circle:before {
+	    content: "" !important ;
+		display: none;
+	}
+	.uni-toast .uni-toast__content{
+		margin: -10px 1px 10px 1px;
+	}
+	
+	
+</style>

+ 15 - 0
README.md

@@ -0,0 +1,15 @@
+[](https://modao.cc/proto/s1QFMhkss7n1emgHHRAr0E/sharing?view_mode=read_only)
+
+
+[](https://zbyj.hbjp.com.cn/floorlock-portal)
+
+companyInfoStatusList
+
+parkingRecordList
+parkingRecordDetails
+
+lockDetails
+operateFloorlock 地锁操作
+
+mobile/sysUser/regUserList
+/mobile/sysUser/regUserDetails

+ 84 - 0
apis/common.js

@@ -0,0 +1,84 @@
+import request from '@/apis/utils/request'
+ 
+import Qs from 'qs';
+
+export function uploadPicture(formData) {
+	return request({
+		url: '/uploadPicture',
+		header:{
+			   'Content-Type': 'application/x-www-form-urlencoded'
+
+		},
+		data: formData,
+		method: 'post',
+		
+	})
+}
+
+
+export function getBannerInfo(formData) {
+	return request({
+		url: '/mobile/bannerInfo/getBannerInfo',
+		data: formData,
+		method: 'post',
+		
+	})
+}
+export function readMessageNum() {
+	return request({
+		url: '/mobile/messageApi/readMessageNum',
+		//data: formData,
+		method: 'post',
+		
+	})
+}
+
+export function getScreenList(formData) {
+	return request({
+		url: '/mobile/recruitmentApi/getScreenList',
+		data: formData,
+		method: 'post',
+		
+	})
+}
+
+//字典表
+export function getData(id) {
+	return request({
+		url: '/sys/dataDictionary/queryChildrenApi',
+		data: {
+			parentId:id
+		},
+		method: 'post',
+		timeout: 60000,
+	})
+}
+//上传图片
+export function upload(formData) {
+	return request({
+		url: '/mobile/jobUserApi/upload',
+		data: formData,
+		method: 'post',
+		
+	})
+}
+
+//上传图片
+export function uploadBase64(formData) {
+	var localData = formData.photoFile?formData.photoFile:formData.photoBase64Data;
+	
+	if (localData.indexOf('data:image') != 0) {
+	    //判断是否有这样的头部
+	    localData = 'data:image/jpeg;base64,' + localData
+	}
+	formData.photoBase64Data = localData.replace(/\r|\n/g, '').replace('data:image/jgp', 'data:image/jpeg')
+	
+	
+	return request({
+		url: '/mobile/jobUserApi/uploadBase64',
+		data: formData,
+		method: 'post',
+		timeout: 60000,
+	})
+}
+

+ 5 - 0
apis/index.js

@@ -0,0 +1,5 @@
+import request from '@/apis/utils/request.js';
+import requestWhite from '@/apis/utils/requestWhite.js';
+import Qs from 'qs';
+ import  jphelp from '@/apis/utils/mixin.js'
+ 

+ 77 - 0
apis/pagejs/deviceTab.js

@@ -0,0 +1,77 @@
+import requestWhite from '@/apis/utils/requestWhite'
+
+export function add(data) {
+ 	return requestWhite({
+ 		method: 'post',
+ 		data: data,
+ 		url: '/mobile/application/add'
+ 	})
+}
+export function bindStatusByNo(data) {
+ 	return requestWhite({
+ 		method: 'post',
+ 		data: data,
+ 		url: '/mobile/application/bindStatusByNo'
+ 	})
+}
+
+export function companyInfoStatusList(data) {
+	var url='/mobile/sysUser/companyInfoStatusList';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function floorlockList(data) {
+	var url='/mobile/sysUser/floorlockList';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+
+export function parkingList(data) {
+	var url='/mobile/sysUser/parkingList';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+
+export function lockDetails(data) {
+	var url='/mobile/sysUser/lockDetails';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+export function operateFloorlock(data) {
+	var url='/mobile/sysUser/operateFloorlock';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function lockUsageRate(data) {
+	var url='/mobile/sysUser/lockUsageRate';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}

+ 108 - 0
apis/pagejs/index.js

@@ -0,0 +1,108 @@
+import request from '@/apis/utils/request'
+import requestWhite from '@/apis/utils/requestWhite'
+
+import jphelp from '@/apis/utils/mixin.js'
+
+
+export function findByOpenId(data) {
+	var url='/mobile/sysUser/findByOpenId';
+	
+	return requestWhite({
+		method: 'get',
+		data: data,
+		url: url
+	})
+}
+
+
+export function companyInfoList(data) {
+	var url='/mobile/sysUser/companyInfoList';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function parkingList(data) {
+	var url='/mobile/sysUser/parkingList';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function parkingRecordList(data) {
+	var url='/mobile/sysUser/parkingRecordList';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+
+export function floorStatus(data) {
+	var url='/mobile/sysUser/floorStatus';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function floorlockList(data) {
+	var url='/mobile/sysUser/floorlockList';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function occupancyByTime(data) {
+	var url='/mobile/sysUser/occupancyByTime';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function occupancyByDay(data) {
+	var url='/mobile/sysUser/occupancyByDay';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+
+export function occupancyByTimeBar(data) {
+	var url='/mobile/sysUser/occupancyByTimeBar';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function durationDistribution(data) {
+	var url='/mobile/sysUser/durationDistribution';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}

+ 23 - 0
apis/pagejs/record.js

@@ -0,0 +1,23 @@
+import requestWhite from '@/apis/utils/requestWhite'
+
+
+
+export function parkingRecordList(data) {
+	var url='/mobile/sysUser/parkingRecordList';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function parkingRecordDetails(data) {
+	var url='/mobile/sysUser/parkingRecordDetails';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}

+ 91 - 0
apis/pagejs/user-old.js

@@ -0,0 +1,91 @@
+import request from '@/apis/utils/request'
+import requestWhite from '@/apis/utils/requestWhite'
+import jphelp from '@/apis/utils/mixin.js'
+
+export function changePassword(data) {
+	var url = '/mobile/employeeUser/changePassword';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+
+export function changePhone(data) {
+	var url = '/mobile/employeeUser/changePhone';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+export function getVerifyCode(data) {
+	var url = '/mobile/employeeUser/getVerifyCode';
+	return requestWhite({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+export function logout(data) {
+	var url = '/mobile/employeeUser/logout';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+export function validateCode(data) {
+	var url = '/mobile/employeeUser/validateCode';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+export function personalCenter(data) {
+	var url = '/mobile/employee/personalCenter';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+
+
+export function findByOpenId(data) {
+	var url = '/mobile/sysUser/findByOpenId';
+	
+	return requestWhite({
+		method: 'get',
+		data: data,
+		url: url
+	})
+}
+
+
+
+export function login(data) {
+	var url = '/mobile/employeeUser/login';
+	
+	return requestWhite({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+
+
+export function retrievePassword(data) {
+	var url = '/mobile/employeeUser/retrievePassword';
+	return requestWhite({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}

+ 31 - 0
apis/pagejs/user.js

@@ -0,0 +1,31 @@
+import requestWhite from '@/apis/utils/requestWhite'
+export function login(data) {
+	var url='/mobile/sysUser/login';
+	
+	return requestWhite({
+		method: 'POST',
+		data: data,
+		url: url
+	})
+}
+
+export function findByOpenId(data) {
+	var url='/mobile/sysUser/findByOpenId';
+	
+	return requestWhite({
+		method: 'get',
+		data: data,
+		url: url
+	})
+}
+
+
+export function logout(data) {
+	var url='/mobile/sysUser/logout';
+	
+	return requestWhite({
+		method: 'get',
+		data: data,
+		url: url
+	})
+}

+ 1 - 0
apis/pagejs/userTab.js

@@ -0,0 +1 @@
+import requestWhite from '@/apis/utils/requestWhite'

+ 20 - 0
apis/utils/AMap.js

@@ -0,0 +1,20 @@
+export default function MapLoader() {
+
+	return new Promise((resolve, reject) => {
+		 
+		if (window.AMap) {
+			resolve(window.AMap)
+		} else {
+//			console.log("map")
+			var script = document.createElement('script')
+			script.type = 'text/javascript'
+			script.async = true
+			script.src = 'https://webapi.amap.com/maps?v=1.4.15&callback=initAMap&key=de735ff06aec63f6bc109c9fb805fc3d'
+			script.onerror = reject
+			document.head.appendChild(script)
+		}
+		window.initAMap = () => {
+			resolve(window.AMap)
+		}
+	})
+}

+ 31 - 0
apis/utils/alipay.js

@@ -0,0 +1,31 @@
+function onBridgeReady(params) {
+	AlipayJSBridge.call("tradePay", {
+		tradeNO: params.tradeNo,
+	}, function(result) {
+		if (result.resultCode == '9000') {
+			location.href = params.succUrl
+		} else {
+			location.href = params.cancelUrl;
+		}
+		//alert(JSON.stringify(result));
+	});
+}
+
+export const aliPayJs = (params) => {
+	if (typeof window.WeixinJSBridge === 'undefined') {
+		if (document.addEventListener) {
+			document.addEventListener('AlipayJSBridgeReady', function() {
+				onBridgeReady(params)
+			}, false)
+		} else if (document.attachEvent) {
+			document.attachEvent('AlipayJSBridgeReady', function() {
+				onBridgeReady(params)
+			})
+			document.attachEvent('AlipayJSBridgeReady', function() {
+				onBridgeReady(params)
+			})
+		}
+	} else {
+		onBridgeReady(params)
+	}
+}

+ 439 - 0
apis/utils/index.js

@@ -0,0 +1,439 @@
+export const currentTimeStamp = () => new Date().getTime()
+
+export const unixTimeStamp = (val) => new Date(val).getTime()
+
+export const nextMonth=(year,month,day,bl)=>{
+	if(day){
+		
+	}else{
+		day="01"
+	}
+	var str=""
+	if(month==12){
+		str= (parseInt(year) +1)+"-01-"+day
+	}else{
+		str= year+"-"+(parseInt(month) +1)+"-"+day
+	}
+	if(bl){
+		var now= newDate(str);
+		return parseUnixTime(new Date(now.getTime()-1000*60*60*24),'{y}-{m}-{d}')	
+	}
+}
+
+// export const nextDay=(year,month,day)=>{
+// 	var now= new Date(year+"-"+month+"-"+day);
+// 	return parseUnixTime(new Date(now.getTime()+1000*60*60*24),'{y}-{m}-{d}')
+	
+// }
+
+// 苹果手机时间显示bug 
+export const newDate = (date) => {
+	var time=null;
+	if (date) {
+		var reg=new RegExp('-','gi')
+		time=new Date(date.replace(reg,'/'));	
+	}
+	return time
+}
+
+//今天多少天之前的时间
+export const beforeTimeStamp = (dayCount,date) => {
+	
+	if (date) {
+		var dd = new Date(date);
+	} else {
+		var dd = new Date();
+	}
+	dd.setDate(dd.getDate() - dayCount)
+	let time = dd.getTime()
+	return time
+}
+
+//今天多少天之后的时间
+export const afterTimeStamp = (dayCount, date) => {
+	if (date) {
+		var dd = new Date(date);
+	} else {
+		var dd = new Date();
+	}
+	dd.setDate(dd.getDate() + dayCount)
+	let time = dd.getTime()
+	return time
+}
+
+//今天多少年之后的时间
+export const afterYearTimeStamp = (yearCount, date) => {
+	if (date) {
+		var dd = new Date(date);
+	} else {
+		var dd = new Date();
+	}
+	dd.setFullYear(dd.getFullYear() + yearCount)
+	let time = dd.getTime()
+	return time
+}
+
+//计算某日期距当前的时间秒数
+export const secondsDistance = (date) => {
+	var now = new Date().getTime();
+	date = new Date(date).getTime();
+	var seconds = parseInt((now - date) / 1000);
+	return seconds;
+}
+
+//计算两个时间的相差天数
+export const daysDistance = (date1, date2) => {
+	date1 = Date.parse(date1);
+	date2 = Date.parse(date2);
+	var ms = date2 - date1;
+	ms = ms < 0 ? 0 : ms;
+	var days = parseInt(Math.floor(ms / (24 * 3600 * 1000)));
+	return days;
+}
+//计算两个时间的相差小时数
+export const hourDistanceArr = (date1, date2) => {
+	if (!date1 || !date2) {
+		return '-';
+	}
+	date1 = Date.parse(date1);
+	date2 = Date.parse(date2);
+	var ms = date2 - date1;
+	ms = ms < 0 ? 0 : ms;
+	ms = ms / 1000; //s
+	var Hour = parseInt(Math.floor(ms / (60 * 60)));
+	var Fen = parseInt(Math.floor(ms % (60 * 60) / 60));
+	var s = parseInt(Math.floor(ms % (60)));
+	//600000
+	return [Hour, Fen, s]
+}
+//计算两个时间的相差小时数
+export const hourDistance = (date1, date2,days) => {
+	if (!date1 || !date2) {
+		return '-';
+	}
+	date1 = Date.parse(date1);
+	date2 = Date.parse(date2);
+	var ms = date2 - date1;
+	var day = parseInt(Math.floor(ms / (24 * 3600 * 1000)));
+	
+	ms = ms < 0 ? 0 : ms;
+	ms = ms / 1000; //s
+	
+	var Hour = parseInt(Math.floor(ms / (60 * 60)));
+	var Fen = parseInt(Math.floor(ms % (60 * 60) / 60));
+	var s = parseInt(Math.floor(ms % (60)));
+	//600000
+	var str=""
+	if(days){
+		if(day){
+			str+=(day + '天' )
+		}
+		Hour=Hour%24
+	}
+	if(Hour){
+		str+=(Hour + '小时' )
+	}
+	if(Fen){
+		str+=(Fen + '分钟' )
+	}
+	if(s){
+		str+=(s + '秒' )
+	}
+	return str;
+}
+
+export const parseUnixTime = (time, cFormat) => {
+	if (arguments.length === 0) {
+		return null
+	}
+	const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}'
+	let date
+	if (typeof time === 'object') {
+		date = time
+	} else {
+		if (('' + time).length === 10) time = parseInt(time) * 1000
+		date = new Date(time)
+	}
+	const formatObj = {
+		y: date.getFullYear(),
+		m: date.getMonth() + 1,
+		d: date.getDate(),
+		h: date.getHours(),
+		i: date.getMinutes(),
+		s: date.getSeconds(),
+		a: date.getDay()
+	}
+	const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+		let value = formatObj[key]
+		if (key === 'a') return ['一', '二', '三', '四', '五', '六', '日'][value - 1]
+		if (result.length > 0 && value < 10) {
+			value = '0' + value
+		}
+		return value || 0
+	})
+
+	return time_str
+}
+
+//微信获取code
+export const getWeixinRedirectURI = (appid, url) =>
+	`https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${encodeURIComponent(url)}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`
+
+ 
+//支付宝获取code
+export const getAlipayRedirectURI = (appid, url) =>
+	`https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=${appid}&scope=auth_base&redirect_uri=${encodeURIComponent(url)}`
+
+
+//获取链接的?参数
+export const getUrlParam = (name) => {
+	var k =window.location.href.indexOf("?"+name+"=");
+	if(k==-1){
+		 k =window.location.href.indexOf("&"+name+"=");
+		 if(k==-1){
+			 return  ""
+		 }
+	}
+	var reg = new RegExp(name + "=([^&]*)(&|$)");
+	var r = window.location.href.match(reg);
+	var strValue = "";
+	if (r != null) {
+		strValue = decodeURIComponent(r[1]);
+	}
+	return strValue;
+}
+
+
+//将base64图片码转file
+export const dataUrlToFile = (dataurl, filename) => {
+	var arr = dataurl.split(','),
+		mime = arr[0].match(/:(.*?);/)[1],
+		bstr = atob(arr[1]),
+		n = bstr.length,
+		u8arr = new Uint8Array(n);
+	while (n--) {
+		u8arr[n] = bstr.charCodeAt(n);
+	}
+	return new File([u8arr], filename, {
+		type: mime
+	});
+}
+
+//将canvas转换为image的src
+export const convertCanvasToImage = (canvas) => {
+	return canvas.toDataURL("image/png");;
+}
+
+//验证身份证
+export const checkIdCard = (value) => {
+	var identNumber = value;
+
+	if (identNumber != null) {
+		identNumber = (identNumber + "").toUpperCase();
+	}
+
+	if (!(/(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(identNumber))) {
+		return '身份证格式错误';
+	}
+	//身份证号码为15位或者18位,15位时全为数字,18位前17位为数字,最后一位是校验位,可能为数字或字符X。  
+	if (!(/(^\d{15}$)|(^\d{17}([0-9]|X)$)/.test(identNumber))) {
+		return '身份证格式错误';
+	}
+	//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
+	//下面分别分析出生日期和校验位
+	var len, re;
+	len = identNumber.length;
+	//判断18位身份证号码,现在在国家统一身份证为18位。
+	if (len == 18) {
+		re = new RegExp(/^(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)$/);
+		var arrSplit = identNumber.match(re);
+
+
+		//检查生日日期是否正确
+		var dtmBirth = new Date(arrSplit[2] + "/" + arrSplit[3] + "/" + arrSplit[4]);
+		var bGoodDay;
+		bGoodDay = (dtmBirth.getFullYear() == Number(arrSplit[2])) && ((dtmBirth.getMonth() + 1) == Number(arrSplit[3])) &&
+			(dtmBirth.getDate() == Number(arrSplit[4]));
+		if (!bGoodDay) {
+			return '身份证号码日期不匹配';
+		} else {
+			//检验18位身份证的校验码是否正确。
+			//校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
+			var valnum;
+			var arrInt = new Array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
+			var arrCh = new Array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
+			var nTemp = 0,
+				i;
+			for (i = 0; i < 17; i++) {
+				nTemp += identNumber.substr(i, 1) * arrInt[i];
+			}
+			valnum = arrCh[nTemp % 11];
+			if (valnum != identNumber.substr(17, 1)) {
+				return '身份证号码校验位不正确';
+			}
+			return true;
+		}
+	} else {
+		return '身份证号码位数不足';
+	}
+}
+
+// 字符串截取 包含对中文处理,str需截取字符串,start开始截取位置,n截取长度
+export const substrMb = (str, start, n) => {
+	if (str.replace(/[\u4e00-\u9fa5]/g, '**').length <= n) {
+		return str;
+	}
+	let len = 0;
+	let tmpStr = '';
+	for (let i = start; i < str.length; i++) { // 遍历字符串
+		if (/[\u4e00-\u9fa5]/.test(str[i])) { // 中文 长度为两字节
+			len += 2;
+		} else {
+			len += 1;
+		}
+		if (len > n) {
+			break;
+		} else {
+			tmpStr += str[i];
+		}
+	}
+	return tmpStr;
+}
+
+//验证手机号
+export const checkPhone = (value) => {
+	if (!value) {
+		return '手机号不能为空';
+	} else {
+		const reg = /^1[3-9]\d{9}$/
+		var result = reg.test(value);
+
+		if (result) {
+			return true;
+		} else {
+			return '请输入正确的手机号';
+		}
+	}
+};
+
+//验证社会信用代码
+export const checkCreditCode = (value) => {
+	if (!value) {
+		return '社会信用代码不能为空';
+	} else {
+		const reg = /^[^_IOZSVa-z\W]{2}\d{6}[^_IOZSVa-z\W]{10}$/g
+		var result = reg.test(value);
+
+		if (result) {
+			return true;
+		} else {
+			return '不是有效的统一社会信用编码';
+		}
+	}
+};
+
+//是否为微信浏览器
+export const isWeiXin = () => {
+	return /MicroMessenger/.test(window.navigator.userAgent)
+}
+
+//获取当前根链接
+export const getBaseUrl = () => {
+	return window.location.href.split("#")[0]
+}
+
+//获取指定日期是否在指定时间之间
+export const inDateBetwen = (d, d1, d2) => {
+	//如果时间格式是正确的,那下面这一步转化时间格式就可以不用了
+	var dateBegin = new Date(d1.replace(/-/g, "/")); //将-转化为/,使用new Date
+	var dateEnd = new Date(d2.replace(/-/g, "/")); //将-转化为/,使用new Date
+	//var dateBegin = new Date(d1);//将-转化为/,使用new Date
+	//var dateEnd = new Date(d2);//将-转化为/,使用new Date
+	var dateNow = new Date(d.replace(/-/g, "/")); //获取当前时间
+
+	var beginDiff = dateNow.getTime() - dateBegin.getTime(); //时间差的毫秒数       
+	var beginDayDiff = Math.floor(beginDiff / (24 * 3600 * 1000)); //计算出相差天数
+
+	var endDiff = dateEnd.getTime() - dateNow.getTime(); //时间差的毫秒数
+	var endDayDiff = Math.floor(endDiff / (24 * 3600 * 1000)); //计算出相差天数       
+	if (endDayDiff < 0) {
+		//已过期
+		return false
+	}
+	if (beginDayDiff < 0) {
+		//没到开始时间
+		return false;
+	}
+	return true;
+}
+
+//type为字符串类型,有两种选择,"s"代表开始,"e"代表结束,dates为数字类型,不传或0代表本周,-1代表上周,1代表下周
+export const getWeekTime = (type, dates) => {
+	var now = new Date();
+	var nowTime = now.getTime();
+	var day = now.getDay();
+	var longTime = 24 * 60 * 60 * 1000;
+	var n = longTime * 7 * (dates || 0);
+	if (type == "s") {
+		var dd = nowTime - (day) * longTime + n;
+	};
+	if (type == "e") {
+		var dd = nowTime + (7 - day - 1) * longTime + n;
+	};
+	dd = new Date(dd);
+	var y = dd.getFullYear();
+	var m = dd.getMonth() + 1;
+	var d = dd.getDate();
+	m = m < 10 ? "0" + m : m;
+	d = d < 10 ? "0" + d : d;
+	var day = y + "-" + m + "-" + d;
+	return day;
+}
+
+export const getDiffDate = (stime, etime) => {
+	//初始化日期列表,数组
+	var diffdate = new Array();
+	var i = 0;
+	//开始日期小于等于结束日期,并循环
+	while (stime <= etime) {
+		diffdate[i] = stime;
+
+		//获取开始日期时间戳
+		var stime_ts = new Date(stime).getTime();
+ 
+		//增加一天时间戳后的日期
+		var next_date = stime_ts + (24 * 60 * 60 * 1000);
+
+		//拼接年月日,这里的月份会返回(0-11),所以要+1
+		var next_dates_y = new Date(next_date).getFullYear() + '-';
+		var next_dates_m = (new Date(next_date).getMonth() + 1 < 10) ? '0' + (new Date(next_date).getMonth() + 1) + '-' : (
+			new Date(next_date).getMonth() + 1) + '-';
+		var next_dates_d = (new Date(next_date).getDate() < 10) ? '0' + new Date(next_date).getDate() : new Date(next_date).getDate();
+
+		stime = next_dates_y + next_dates_m + next_dates_d;
+
+		//增加数组key
+		i++;
+	}
+	return diffdate;
+}
+
+export const isJSON = (str) => {
+	if (typeof str == 'string') {
+		try {
+			var obj = JSON.parse(str);
+			if (typeof obj == 'object' && obj) {
+				return true;
+			} else {
+				return false;
+			}
+		} catch (e) {
+			console.log('error:' + str + '!!!' + e);
+			return false;
+		}
+	}
+}
+
+
+
+

+ 114 - 0
apis/utils/init.js

@@ -0,0 +1,114 @@
+import jphelp from '@/apis/utils/mixin.js'
+
+import * as API_WeiXin from '@/apis/weixin.js'
+
+import {
+	getUrlParam,
+	getWeixinRedirectURI,
+	isWeiXin
+} from '@/apis/utils'
+var checkOpenId = true; //是否需要获取openId
+var openId = jphelp.getOpenId();
+ var app = {
+
+	init: function() {
+
+		
+		if (isWeiXin() || (process.env.NODE_ENV === "development")) {
+
+			if (checkOpenId) {
+				 if (!openId) {
+					this.getOpenId();
+
+				} else {
+					this.getPersion(openId)
+				}
+			}
+		} else {
+			var NODE_NAME = process.env['NODE_NAME']
+			if (NODE_NAME == "production") {
+				alert("请使用微信打开本页面")
+			}
+		}
+
+
+
+	},
+	
+	getPersion(thisopenId) {
+		console.log("init")
+		var tdate = new Date(+new Date() + 8 * 3600 * 1000).toJSON().substr(0, 15).replace("T", " ")
+		var token_tdate = jphelp.get("token_tdate"); //每10分钟存储一次token
+
+		if (token_tdate && token_tdate == tdate) {
+			return
+		}
+
+		var loginurl = "/mobile/sysUser/findByOpenId"
+	
+		var data= {
+				openId:thisopenId,
+				
+		}
+		 
+		uni.request({
+			method: 'get',
+			url: process.jphelp.BASE_URL + loginurl,
+			data: data,
+			header: {
+				'Content-Type': 'application/x-www-form-urlencoded',
+				'X-Requested-With': 'XMLHttpRequest',
+				//'Authorization':token
+			}
+		}).then((response) => {
+			let [error, res] = response;
+
+			if (res.data.code == 200 && res.data.result) {
+ 
+				var token = res ? res.data.data.token : '';
+				
+				
+			
+				jphelp.setPersonInfo(res.data.data.user);
+				jphelp.setPersonInfoPlus(res.data.data)
+				jphelp.setToken(token);
+
+			} else {
+				jphelp.logoff();
+			}
+		}).catch(error => {
+
+
+		})
+	},
+	getOpenId() {
+		if (process.env.NODE_ENV === "development"){
+			jphelp.setOpenId(process.jphelp.openId)
+			location.reload();
+			return
+		}
+		const code = getUrlParam('code');
+		var openId = jphelp.getOpenId()
+		if (!openId) {
+			if (!code) {
+				var url = document.URL;
+				var getUrl = getWeixinRedirectURI(process.jphelp.VUE_APP_WXAPPID, url);
+
+				window.location.href = getUrl;
+			} else {
+
+				API_WeiXin.getDataByCode(code).then(response => {
+
+					jphelp.setOpenId(response.data.openid)
+					openId = response.data.openid;
+					jphelp.set("xpgj_wx_user_info", response.data)
+
+					location.reload();
+				}).catch(error => {
+					console.log(error);
+				});
+			}
+		}
+	}
+}
+module.exports = app

+ 45 - 0
apis/utils/initALI.js

@@ -0,0 +1,45 @@
+import jphelp from '@/apis/utils/mixin.js'
+import * as API_WeiXin from '@/apis/weixin.js'
+
+import {
+	getUrlParam,
+	getAlipayRedirectURI,
+ 
+} from '@/apis/utils'
+var checkOpenId = true; //是否需要获取openId
+var openId = jphelp.getOpenIdALI();
+
+var app = {
+	init: function() {
+		 
+		if (!openId) {
+			this.getOpenId();
+		} 
+		
+		
+	},
+	
+	getOpenId() {
+		
+		const code = getUrlParam('auth_code');
+		var openId= jphelp.getOpenIdALI()
+		
+		if (!openId) {
+			if (!code) {
+				
+				var authUrl = document.URL//.replace('pages/parking/search', 'pages/parking/auth');
+				window.location.href = getAlipayRedirectURI(process.jphelp.VUE_APP_ALIAPPID, authUrl );
+			} else {
+				
+				API_WeiXin.getDataByCodeALI(code).then(response => {
+					
+					jphelp.setOpenIdALI(response.data.openid)
+					 location.reload();
+				}).catch(error => {
+					console.log(error);
+				});
+			}
+		}
+	}
+}
+module.exports = app

+ 98 - 0
apis/utils/mixin.js

@@ -0,0 +1,98 @@
+var prefix = 'jp-floorlock-manage-' + process.jphelp.NODE_ENV + '_';
+
+var app = {
+
+	getGzDate: (key) => {
+		var tdate = new Date().toJSON().substr(0, 10).replace("T", " ")
+		var date = uni.getStorageSync(prefix + "is_gz_date")
+
+		if (tdate == date) {
+			return false
+		} else {
+			return true;
+		}
+
+	},
+
+
+	setGzDate: () => uni.setStorageSync(prefix + "is_gz_date", new Date().toJSON().substr(0, 10).replace("T", " ")),
+
+
+
+
+	getPrefix: () => prefix,
+	get: key => uni.getStorageSync(prefix + key),
+
+	set: (key, value) => uni.setStorageSync(prefix + key, value),
+	remove: key => uni.removeStorageSync(prefix + key),
+	setConfig: (value) => uni.setStorageSync(prefix + '_config_$', value),
+	getConfig: () => {
+		var config = uni.getStorageSync(prefix + '_config_$')
+		var configure = {}
+		if (config) {
+			for (var i in config) {
+				var con = config[i];
+				configure[con.key] = con.value
+			}
+		}
+		return configure;
+	},
+
+	setConfigMessage: (value) => uni.setStorageSync(prefix + '_config_tips_$', value),
+	getConfigMessage: () => {
+		var config = uni.getStorageSync(prefix + '_config_tips_$')
+		if (!config) {
+			config = []
+		}
+		return config;
+	},
+
+	logoff: () => {
+		uni.removeStorageSync(prefix + 'token_tdate')
+		uni.removeStorageSync(prefix + 'token')
+		uni.removeStorageSync(prefix + 'personInfo');
+		uni.removeStorageSync(prefix + 'personInfoPlus');
+		//	uni.removeStorageSync(prefix + 'getElderModeClass');
+		//uni.removeStorageSync(prefix+'wx_openId');
+
+	},
+
+	getPersonInfo: () => {
+		return uni.getStorageSync(prefix + 'personInfo')
+	},
+	getPersonInfoPlus: () => {
+		return uni.getStorageSync(prefix + 'personInfoPlus')
+	},
+	signOut: () => uni.removeStorageSync(prefix + 'personInfo'),
+	getOpenId: () => uni.getStorageSync(prefix + 'wx_openId' + process.jphelp.VUE_APP_WXAPPID),
+	setOpenId: (value) => uni.setStorageSync(prefix + 'wx_openId' + process.jphelp.VUE_APP_WXAPPID, value),
+
+	getOpenIdALI: () => uni.getStorageSync(prefix + 'ali_openId' + process.jphelp.VUE_APP_WXAPPID),
+	setOpenIdALI: (value) => uni.setStorageSync(prefix + 'ali_openId' + process.jphelp.VUE_APP_WXAPPID, value),
+
+	getUserInfo: () => {
+		return uni.getStorageSync(prefix + 'xpgj_wx_user_info')
+	},
+
+	setPersonInfo: (value) => uni.setStorageSync(prefix + 'personInfo', value),
+	setPersonInfoPlus: (value) => uni.setStorageSync(prefix + 'personInfoPlus', value),
+
+	setUserInfo: (value) => uni.setStorageSync(prefix + 'xpgj_wx_user_info', value),
+
+	getToken: (options) => {
+		//不同权限 ,不同token
+
+		return uni.getStorageSync(prefix + 'token')
+	},
+	setToken: (value) => {
+		uni.setStorageSync(prefix + 'token', value)
+
+		if (value) {
+			var tdate = new Date(+new Date() + 8 * 3600 * 1000).toJSON().substr(0, 15).replace("T", " ")
+			uni.setStorageSync(prefix + 'token_tdate', tdate)
+		}
+	},
+
+}
+
+module.exports = app

+ 93 - 0
apis/utils/request.js

@@ -0,0 +1,93 @@
+import  jphelp from '@/apis/utils/mixin.js'
+import requestSon from './requestSon.js';
+
+
+const request = (options) => {
+	//记录请求次数和响应次数
+	var tdate=new Date( +new Date() + 8 * 3600 * 1000 ).toJSON().substr(0,15).replace("T"," ")
+	var token_tdate=jphelp.get("token_tdate");//每10分钟存储一次token
+	
+	var token=jphelp.getToken(options);
+	
+	 if(token_tdate&&token_tdate==tdate){
+	 	return requestSon(options);
+	 }
+	 var openId=jphelp.getOpenId()
+	 
+	var  urlindex="/wechat/findUserInfo"
+	var k=options.url.indexOf(urlindex)==-1;
+	
+	 if(!openId&&k){
+		 return
+	 }
+	if(!k){
+		return requestSon(options);
+	}
+	
+	return new Promise((resolve, reject) => {
+		 var loginurl="/mobile/sysUser/findByOpenId"
+		 var data= {
+				openId:openId,
+			
+				
+		}
+		
+		uni.request({
+			method:'get',
+			url: process.jphelp.BASE_URL + loginurl,
+			data:data,
+			
+			header: {
+				'Content-Type': 'application/x-www-form-urlencoded',
+				'X-Requested-With': 'XMLHttpRequest',
+				//'Authorization':token
+			}
+		}).then((response) => {
+ 			let [error, res] = response;
+			
+			
+			if (res.data.code == 200&&res.data.result) {
+				
+				var token = res ? res.data.data.token : '';
+				
+				jphelp.setPersonInfo(res.data.data.user);
+				jphelp.setPersonInfoPlus(res.data.data)
+			
+				options.token=token
+				
+				var isson= requestSon(options)
+				
+				resolve(isson);
+				 
+			} else  if(res.data.code == 415||(res.data.code == 200&&!res.data.result)||res.data.code == 400){
+				
+				//var url=window.location.href.split("#")[1]
+			
+				console.log("没有免登陆 ----------------"+options.url)
+				//var url="/pages/login/index?message=请登录&back="+ url+"&phone="+options.data.phone
+				var thisurl='/pages/login/login';
+				
+				if(options&&options.data&&options.data.jpcode){
+					thisurl+="?jpcode="+options.data.jpcode
+				}
+				jphelp.signOut()
+				uni.redirectTo({
+					url: thisurl
+				})
+				
+				
+				
+			 
+				
+			}else{
+		
+				reject(res.data.message)
+			}
+		}).catch(error => {
+			
+			let [err, res] = error;
+			reject(err)
+		})
+	});
+}
+export default request

+ 70 - 0
apis/utils/requestSon.js

@@ -0,0 +1,70 @@
+import  jphelp from '@/apis/utils/mixin.js'
+
+//记录请求次数和响应次数
+let reqCount = 0,
+	resCount = 0;
+var baseUrl=process.jphelp.BASE_URL;
+
+if (process.env.NODE_ENV === "development") {
+	//baseUrl="http://192.168.33.230:8086/jp-employment-server";
+}
+const request = (options) => {
+	var token=jphelp.getToken(options);
+	
+	reqCount++;
+	 
+	return new Promise((resolve, reject) => {
+		//如果特殊链接需要传入token
+		if(options&&options.token){
+			token=options.token;
+		}
+		uni.request({
+			method: options.method?options.method:'get',
+			url: baseUrl + options.url,
+			data: options.data,
+			
+			header: options.header?{
+				...options.header,
+				'Authorization':token
+			}:{
+				'Content-Type': 'application/x-www-form-urlencoded',
+				'X-Requested-With': 'XMLHttpRequest',
+				'Authorization':token
+			}
+		}).then((response) => {
+			//for(var t = Date.now(); Date.now() - t <= 2000;);
+			
+			resCount++
+			//防止连续请求多个接口时loading闪现
+			let [error, res] = response;
+			
+			
+			if (res.data.code == 415&&res.data.message=='请先注册信息') {
+				console.log("请先注册信息请先注册信息")
+				jphelp.signOut()
+				// uni.redirectTo({
+				// 	url: 'pages/login/index'
+				// })
+				return;
+			}
+			
+			if (res.data.code != 200) {
+				reject(res.data.message)
+			} else {
+				if(!res.data.result){
+					
+					reject(res.data.message);
+				}else{
+					resolve(res.data);
+				}
+			
+			}
+		}).catch(error => {
+			resCount++
+		
+			let [err, res] = error;
+			reject(err)
+		})
+	});
+}
+export default request

+ 75 - 0
apis/utils/requestWhite.js

@@ -0,0 +1,75 @@
+import  jphelp from '@/apis/utils/mixin.js'
+
+//记录请求次数和响应次数
+let reqCount = 0,
+	resCount = 0;
+//var token=jphelp.getToken();
+var baseUrl=process.jphelp.BASE_URL;
+
+if (process.env.NODE_ENV === "development") {
+	//baseUrl="http://192.168.33.90:8086/jp-employment-server";
+}
+const request = (options) => {
+	var token=jphelp.getToken(options);
+	
+	reqCount++;
+	 
+	return new Promise((resolve, reject) => {
+		//如果特殊链接需要传入token
+		if(options&&options.token){
+			token=options.token;
+		}
+		uni.request({
+			method: options.method?options.method:'get',
+			url: baseUrl + options.url,
+			data: options.data,
+			header: options.header?{
+				...options.header,
+				'Authorization':token
+			}:{
+				'Content-Type': 'application/x-www-form-urlencoded',
+				'X-Requested-With': 'XMLHttpRequest',
+				'Authorization':token
+			}
+		}).then((response) => {
+			//for(var t = Date.now(); Date.now() - t <= 2000;);
+			
+			resCount++
+			//防止连续请求多个接口时loading闪现
+			let [error, res] = response;
+			
+			if (res.data.code == 415&&res.data.message=='请先注册信息') {
+				jphelp.signOut()
+				uni.redirectTo({
+					url: '/pages/login/login'
+				})
+				return;
+			}
+			
+			if (res.data.code != 200) {
+				reject(res.data.message)
+			} else {
+				
+				if(options.data&&options.data.noerror){
+					resolve(res.data);
+				}else{
+					if(!res.data.result){
+						uni.showToast({
+							title: res.data.message,
+							position:'bottom'
+						})
+					}
+					resolve(res.data);
+				}
+				
+			
+			}
+		}).catch(error => {
+			resCount++
+		
+			let [err, res] = error;
+			reject(err)
+		})
+	});
+}
+export default request

+ 241 - 0
apis/utils/wxJsApi.js

@@ -0,0 +1,241 @@
+import wx from 'weixin-js-sdk'
+import * as API_WeiXin from '@/apis/weixin.js'
+import * as API_Common from '@/apis/common.js'
+
+import Qs from 'qs';
+import request from './request.js'
+export function addSysLog(message) {
+
+	return request({
+		url: '/mobile/sysLogApi/submit',
+		data: Qs.stringify({
+			message: JSON.stringify(message)
+		}),
+		method: 'post',
+	})
+}
+//获取微信配置
+export function getWxConfig(jsApiList) {
+	var jsApiList = jsApiList || ['chooseImage', 'getLocalImgData', 'scanQRCode','openLocation'];
+	 
+	let promise = (jsApiList => {
+		return new Promise((resolve, reject) => {
+//			console.log(jsApiList);
+			API_WeiXin.getConfig().then(response => {
+				var wxconfig = response.data.wxConfig;
+			
+				wx.config({
+					debug: false, // 开启调试模式,
+					appId: wxconfig.appId, // 必填,企业号的唯一标识,此处填写企业号corpid
+					timestamp: wxconfig.timestamp, // 必填,生成签名的时间戳
+					nonceStr: wxconfig.nonceStr, // 必填,生成签名的随机串
+					signature: wxconfig.signature, // 必填,签名,见附录1
+					jsApiList: jsApiList, // 必填,需要使用的JS接口列表,所有JS接口列表见附录2
+					openTagList:['wx-open-subscribe']
+				});
+				wx.ready(function() {
+					resolve(response.data);
+				})
+				wx.error(function(res) {
+					reject('微信api配置出错');
+				});
+			}).catch(error => {
+				//mui.toast(error);
+				reject(error);
+			})
+		})
+	})(jsApiList)
+
+	return promise;
+}
+
+//选择图片,多图上传和单图上传的回调处理不一样
+export function chooseImage(count,islocalId) {
+	var count = count || 1;
+	let promise = new Promise((resolve, reject) => {
+		wx.chooseImage({
+			count: count,
+			sizeType: ['compressed'],
+			sourceType: ['album', 'camera'],
+			success: function(res) {
+				 
+				var localIds = res.localIds;
+				
+				if(islocalId){
+					
+					resolve(localIds);
+				}else{
+					if (count == 1) {
+						wx.getLocalImgData({
+							localId: localIds[0],
+							success: function(res) {
+								resolve(res);
+							}
+						});
+					} else {
+						resolve(localIds);
+					}
+				}
+				
+			}
+		});
+	});
+	return promise;
+}
+
+
+
+
+//获取图片,用于多图上传时的递归处理
+export function getLocalImgData(localId, fun) {
+	wx.getLocalImgData({
+		localId: localId,
+		success: function(res) {
+			fun(res);
+		}
+	});
+}
+
+//上传图片
+export function uploadPic(imgBase64) {
+	let promise = new Promise((resolve, reject) => {
+		var formData = new FormData();
+		formData.append('photoName', '1.jpg');
+		formData.append('photoBase64Data', imgBase64);
+
+	
+		API_Common.uploadBase64(formData).then(response => {
+			resolve(response);
+		}).catch(error => {
+			//mui.toast(error);
+			reject(error);
+		})
+	});
+	return promise;
+}
+
+//获取坐标
+export function getLocation() {
+	if(process.env.NODE_ENV === "development" && process.jphelp.SIMPLE_RUN){
+		
+		let promise =new Promise((resolve, reject) => {
+			var obj= {
+			longitude:112.28541,
+			latitude:30.308354,
+			errMsg:"getLocation:ok"
+			}
+			resolve(obj);
+		})
+		return promise
+	}
+	let promise = new Promise((resolve, reject) => {
+		
+		wx.ready(function() {
+			wx.getLocation({
+				type: 'gcj02', // 默认为wgs84的gps坐标,可传入'gcj02'
+				success: function(res) {
+					resolve(res);
+				},
+				faile: function(res) {
+					reject(res);
+				},
+				fail: function(res) {
+					if (res.errMsg == 'getLocation:timeout') {
+						
+						res="定位超时,请检查是否开启'定位'"
+					} else if (res.errMsg == 'getLocation:ERROR_NETWORK') {
+						//mui.alert("网络异常");
+						res="定位超时,请检查是否开启'定位'"
+					} else if (res.errMsg == 'getLocation:ERROR_NOCELL&WIFI_LOCATIONSWITCHOFF') {
+						res="没开启系统定位"
+						//mui.alert("没开启系统定位");
+					} else if (res.errMsg == 'getLocation:system permission denied') {
+						res="未给微信位置授权"
+						//mui.alert("未给微信位置授权");
+					} else if (res.errMsg == 'getLocation:location permission') {
+						res="未给微信位置授权"
+						//mui.alert("未给微信位置授权");
+					} else if (res.errMsg == 'getLocation:auth denied') {
+						res="用户在小程序中未授权"
+						//mui.alert("用户在小程序中未授权");
+					} else if (res.errMsg == 'getLocation:fail authorize no response') {
+						res="用户在小程序中未授权"
+						//mui.alert("用户在小程序中未授权");
+					} else if (res.errMsg == 'getLocation:gps closed') {
+						res="用户已取消定位"
+						//mui.alert("用户已取消定位");
+					}
+					reject(res);
+				},
+				complete() {}
+			})
+		})
+	})
+	return promise;
+}
+
+//扫描二维码
+//扫描二维码
+export function scanQRCode(needResult,obj,sz) {
+	var scanTypeList=["qrCode"];
+	
+	if(sz){
+		scanTypeList=sz
+	}
+	let promise = new Promise((resolve, reject) => {
+		wx.scanQRCode({
+			needResult: needResult,
+			scanType: scanTypeList,
+			success: function(res) {
+				var url = res.resultStr;
+				resolve(url);
+			},
+			faile: function(res) {
+				reject(res);
+			},
+			
+			fail: function(res) {
+
+				reject(res);
+			},
+			complete() {
+				if(obj){
+					obj.showLoading(false)	
+				}
+			}
+		})
+	});
+	return promise;
+}
+
+export function requestSubscribeMessage(sz) {
+	 
+	let promise = new Promise((resolve, reject) => {
+		wx.ready(function() {
+			wx.requestSubscribeMessage({
+			
+			tmplIds: sz,
+			
+				success(res) { 
+						resolve(res);
+				}
+				
+			})
+		})
+		
+
+	});
+	return promise;
+}
+
+
+
+
+//扫描二维码
+export function openLocation(obj) {
+ 
+	let promise = new Promise((resolve, reject) => {
+		wx.openLocation(obj)
+	});
+	return promise;
+}

+ 52 - 0
apis/utils/wxpay.js

@@ -0,0 +1,52 @@
+ 
+function onBridgeReady(params) {
+	console.log("onBridgeReady+"+new Date().getTime())
+	
+	uni.showLoading({
+		mask:true,title:'加载中...'
+	})
+	//记录要回跳的url
+	window.WeixinJSBridge.invoke(
+		'getBrandWCPayRequest', {
+			'appId': params.appId, // 公众号名称,由商户传入
+			'timeStamp': params.timeStamp, // 时间戳,自1970年以来的秒数
+			'nonceStr': params.nonceStr, // 随机串
+			'package': params.package,
+			'signType': params.signType, // 微信签名方式:
+			'paySign': params.paySign // 微信签名
+		},
+		(res) => {
+			//alert(JSON.stringify(res)); // 支付取消会执行 支付成功不会
+			if (res.err_msg == 'get_brand_wcpay_request:ok') {
+				//alert("支付成功") // 不会执行
+				//window.location.href = params.url
+			} else if (res.err_msg == "get_brand_wcpay_request:cancel") {
+				//alert("支付取消") // 会执行
+				 uni.hideLoading();
+			} else {
+				 uni.hideLoading();
+			}
+		}
+	)
+}
+
+export const wxPayJs = (params) => {
+	console.log("wxPayJs+"+new Date().getTime())
+	
+	if (typeof window.WeixinJSBridge === 'undefined') {
+		if (document.addEventListener) {
+			document.addEventListener('WeixinJSBridgeReady', function() {
+				onBridgeReady(params)
+			}, false)
+		} else if (document.attachEvent) {
+			document.attachEvent('WeixinJSBridgeReady', function() {
+				onBridgeReady(params)
+			})
+			document.attachEvent('onWeixinJSBridgeReady', function() {
+				onBridgeReady(params)
+			})
+		}
+	} else {
+		onBridgeReady(params)
+	}
+}

+ 76 - 0
apis/weixin.js

@@ -0,0 +1,76 @@
+import request from '@/apis/utils/request'
+import requestWhite from '@/apis/utils/requestWhite.js';
+// import requestAli from '../utils/requestParking.js';
+ 
+import Qs from 'qs';
+
+//微信支付
+export function wxpay(data) {
+	
+	if(data&&!data.recordId){
+		data.recordId=''
+	}
+	return request({
+		url: '/wxPay/wxJsapiPay',
+		data: data,
+		method: 'post',
+	})
+}
+
+
+
+export function alpay(data) {
+	if(data&&!data.recordId){
+		data.recordId=''
+	}
+	return request({
+		url: '/aliPay/tradePrecreatePay',
+		data: data,
+		method: 'post',
+	})
+}
+
+//根据code换取openid
+export function getDataByCode(code) {
+	return request({
+		url: '/wechat/findUserInfo/' + code,
+		params: {},
+		method: 'get',
+	})
+}
+
+// export function getDataByCodeALI(code) {
+// 	return requestAli({
+// 		url: '/aliPay/findUserInfo/' + code,
+// 		params: {},
+// 		method: 'get',
+// 	})
+// }
+
+
+//获得配置
+export function getConfig() {
+	return requestWhite({
+		url: '/wechat/getConfig',
+		data: {
+			url: window.location.href.split('#')[0]
+		},
+		method: 'get',
+	})
+}
+
+export function checkSubscribe(data) {
+	return requestWhite({
+		url: '/wechat/checkSubscribe',
+		data: data,
+		method: 'post',
+	})
+}
+
+export function addPoint(data) {
+	return request({
+		url: '/mobile/points/addPoint',
+		data: data,
+		method: 'post',
+	})
+}

+ 0 - 0
assets/css/style.css


+ 7 - 0
assets/font/jptime.css

@@ -0,0 +1,7 @@
+@font-face {
+	font-family: "JPTIME";
+	src:url("@/assets/font/jptime.otf");
+}
+.JPTIME {
+    font-family: JPTIME
+}

二进制
assets/font/jptime.otf


+ 22 - 0
assets/icon/icon.vue

@@ -0,0 +1,22 @@
+<template>
+	<view>
+		
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		methods: {
+			
+		}
+	}
+</script>
+
+<style>
+
+</style>

文件差异内容过多而无法显示
+ 3 - 0
assets/img/button/lock.svg


二进制
assets/img/circleCopy1@1x.png


文件差异内容过多而无法显示
+ 3 - 0
assets/img/deviceTab/index1-1.svg


+ 6 - 0
assets/img/deviceTab/index2-1.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1092 1024" width="24" height="23" style="" filter="none">
+    
+    <g>
+    <path d="M546.133333 68.266667c306.449067 0 450.3552 235.383467 477.866667 443.733333h-84.650667a36.864 36.864 0 0 1-35.2256-26.112C848.6912 306.0736 729.361067 216.1664 546.133333 216.1664c-183.227733 0-302.557867 89.9072-357.9904 269.7216A36.864 36.864 0 0 1 152.917333 512H68.266667C95.778133 303.616 239.684267 68.266667 546.133333 68.266667z" fill="rgba(22,119,255,1)" p-id="3768" stroke="none"></path><path d="M546.133333 34.133333C227.771733 34.133333 34.133333 292.795733 34.133333 591.633067v150.9376C34.133333 822.613333 98.986667 887.466667 179.029333 887.466667h734.208C993.28 887.466667 1058.133333 822.613333 1058.133333 742.570667v-150.9376C1058.133333 292.795733 864.494933 34.133333 546.133333 34.133333z m0 68.266667c275.6608 0 443.733333 224.529067 443.733334 489.233067v150.9376A76.629333 76.629333 0 0 1 913.237333 819.2H179.029333A76.629333 76.629333 0 0 1 102.4 742.570667v-150.9376C102.4 326.929067 270.472533 102.4 546.133333 102.4z" fill="rgba(22,119,255,1)" p-id="3769" stroke="none"></path><path d="M170.666667 775.304533l0.170666-1.809066c6.075733-30.856533 165.410133-55.7056 363.383467-56.661334h23.620267c201.9328 0.955733 363.758933 26.760533 363.758933 58.4704v156.0576C921.6 963.652267 753.493333 989.866667 546.133333 989.866667s-375.466667-26.2144-375.466666-58.504534v-156.0576z" fill="rgba(22,119,255,1)" p-id="3770" stroke="none"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/deviceTab/index2-2.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="20" height="20" style="" filter="none">
+    
+    <g>
+    <path d="M20 4h8v6.667h-2.667v-4h-5.333v-2.667zM12 4v2.667h-5.333v4h-2.667v-6.667h8zM20 28v-2.667h5.333v-4h2.667v6.667h-8zM12 28h-8v-6.667h2.667v4h5.333v2.667zM4 14.667h24v2.667h-24v-2.667z" fill="rgba(255,255,255,1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/deviceTab/index2-3.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="20" height="20" style="" filter="none">
+    
+    <g>
+    <path d="M20 4h8v6.667h-2.667v-4h-5.333v-2.667zM12 4v2.667h-5.333v4h-2.667v-6.667h8zM20 28v-2.667h5.333v-4h2.667v6.667h-8zM12 28h-8v-6.667h2.667v4h5.333v2.667zM4 14.667h24v2.667h-24v-2.667z" fill="rgba(22,119,255,1)"></path>
+    </g>
+  </svg>

二进制
assets/img/deviceTab/index3-1.png


二进制
assets/img/deviceTab/index3-2.png


文件差异内容过多而无法显示
+ 3 - 0
assets/img/index/pie1-1.svg


+ 6 - 0
assets/img/index/pie1-2.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 1092 1024" width="20" height="18.76" style="" filter="none">
+    
+    <g>
+    <path d="M546.133333 68.266667c306.449067 0 450.3552 235.383467 477.866667 443.733333h-84.650667a36.864 36.864 0 0 1-35.2256-26.112C848.6912 306.0736 729.361067 216.1664 546.133333 216.1664c-183.227733 0-302.557867 89.9072-357.9904 269.7216A36.864 36.864 0 0 1 152.917333 512H68.266667C95.778133 303.616 239.684267 68.266667 546.133333 68.266667z" fill="rgba(153,153,153,1)" p-id="3768" stroke="none"></path><path d="M546.133333 34.133333C227.771733 34.133333 34.133333 292.795733 34.133333 591.633067v150.9376C34.133333 822.613333 98.986667 887.466667 179.029333 887.466667h734.208C993.28 887.466667 1058.133333 822.613333 1058.133333 742.570667v-150.9376C1058.133333 292.795733 864.494933 34.133333 546.133333 34.133333z m0 68.266667c275.6608 0 443.733333 224.529067 443.733334 489.233067v150.9376A76.629333 76.629333 0 0 1 913.237333 819.2H179.029333A76.629333 76.629333 0 0 1 102.4 742.570667v-150.9376C102.4 326.929067 270.472533 102.4 546.133333 102.4z" fill="rgba(153,153,153,1)" p-id="3769" stroke="none"></path><path d="M170.666667 775.304533l0.170666-1.809066c6.075733-30.856533 165.410133-55.7056 363.383467-56.661334h23.620267c201.9328 0.955733 363.758933 26.760533 363.758933 58.4704v156.0576C921.6 963.652267 753.493333 989.866667 546.133333 989.866667s-375.466667-26.2144-375.466666-58.504534v-156.0576z" fill="rgba(153,153,153,1)" p-id="3770" stroke="none"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/index/pie1-3.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="20" height="20" style="" filter="none">
+    
+    <g>
+    <path d="M16 14.667c3.682 0 6.667 2.985 6.667 6.667v0 8h-13.333v-8c0-3.682 2.985-6.667 6.667-6.667v0zM7.051 18.675c-0.2 0.649-0.334 1.401-0.372 2.178l-0.001 0.022-0.011 0.459v8h-4v-6c0-0 0-0.001 0-0.001 0-2.398 1.809-4.374 4.137-4.637l0.021-0.002 0.227-0.019zM24.949 18.675c2.453 0.154 4.384 2.181 4.384 4.659v6h-4v-8c0-0.924-0.133-1.816-0.384-2.659zM7.333 10.667c1.841 0 3.333 1.492 3.333 3.333s-1.492 3.333-3.333 3.333v0c-1.841 0-3.333-1.492-3.333-3.333s1.492-3.333 3.333-3.333v0zM24.667 10.667c1.841 0 3.333 1.492 3.333 3.333s-1.492 3.333-3.333 3.333v0c-1.841 0-3.333-1.492-3.333-3.333s1.492-3.333 3.333-3.333v0zM16 2.667c2.946 0 5.333 2.388 5.333 5.333s-2.388 5.333-5.333 5.333v0c-2.946 0-5.333-2.388-5.333-5.333s2.388-5.333 5.333-5.333v0z" fill="rgba(161,165,169,1)"></path>
+    </g>
+  </svg>

二进制
assets/img/logo/logo.png


文件差异内容过多而无法显示
+ 3 - 0
assets/img/myTab/icon1.svg


+ 6 - 0
assets/img/myTab/message1.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 448 512" width="28" height="28" style="" filter="drop-shadow(0px 2px 4px rgba(182,77,0,1))">
+    <defs><linearGradient id="ik4s6tsjUdxagOcJvyZKGs1" x1="0" x2="100%" y1="0" y2="0" gradientTransform="matrix(6.123233995736766e-17, 1, -1, 6.123233995736766e-17, 224, 0)" gradientUnits="userSpaceOnUse"><stop stop-color="#ffffff" stop-opacity="1" offset="0.4"></stop><stop stop-color="#ffffff" stop-opacity="0.6" offset="1"></stop></linearGradient></defs>
+    <g>
+    <path d="M224 512c35.32 0 63.97-28.65 63.97-64H160.03c0 35.35 28.65 64 63.97 64zm215.39-149.71c-19.32-20.76-55.47-51.99-55.47-154.29 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84C118.56 68.1 64.08 130.3 64.08 208c0 102.3-36.15 133.53-55.47 154.29-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h383.8c19.12 0 32-15.6 32.1-32 .05-7.55-2.61-15.27-8.61-21.71z" fill="url(#ik4s6tsjUdxagOcJvyZKGs1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/myTab/message2.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 576 512" width="28" height="28" style="" filter="drop-shadow(0px 2px 4px rgba(192,0,0,0.5))">
+    <defs><linearGradient id="ik4s6tsjUdxagObx6rg0UP1" x1="0" x2="100%" y1="0" y2="0" gradientTransform="matrix(6.123233995736766e-17, 1, -1, 6.123233995736766e-17, 288, 0)" gradientUnits="userSpaceOnUse"><stop stop-color="#ffffff" stop-opacity="1" offset="0.4"></stop><stop stop-color="#ffffff" stop-opacity="0.6" offset="1"></stop></linearGradient></defs>
+    <g>
+    <path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z" fill="url(#ik4s6tsjUdxagObx6rg0UP1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/myTab/message3.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="28" height="28" style="" filter="drop-shadow(0px 2px 4px rgba(52,0,255,0.75))">
+    <defs><linearGradient id="ik4s6tsjUdxagOcKiQJsp01" x1="0" x2="100%" y1="0" y2="0" gradientTransform="matrix(6.123233995736766e-17, 1, -1, 6.123233995736766e-17, 12, 0)" gradientUnits="userSpaceOnUse"><stop stop-color="#ffffff" stop-opacity="1" offset="0.4"></stop><stop stop-color="#ffffff" stop-opacity="0.6" offset="1"></stop></linearGradient></defs>
+    <g>
+    <path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm4.2 14.2L11 13V7h1.5v5.2l4.5 2.7-.8 1.3z" fill="url(#ik4s6tsjUdxagOcKiQJsp01)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/myTab/message4.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 48 48" width="28" height="28" style="" filter="drop-shadow(0px 2px 4px rgba(24,90,198,1))">
+    <defs><linearGradient id="ik4s6tsjUdxagOc7MeTnlC1" x1="0" x2="100%" y1="0" y2="0" gradientTransform="matrix(6.123233995736766e-17, 1, -1, 6.123233995736766e-17, 24, 0)" gradientUnits="userSpaceOnUse"><stop stop-color="#ffffff" stop-opacity="1" offset="0.4"></stop><stop stop-color="#ffffff" stop-opacity="0.6" offset="1"></stop></linearGradient></defs>
+    <g>
+    <rect width="48" height="48" fill="url(#ik4s6tsjUdxagOc7MeTnlC1)" fill-opacity="0.01" stroke="none"></rect><rect x="4" y="4" width="40" height="40" rx="2" fill="none" stroke="url(#ik4s6tsjUdxagOc7MeTnlC1)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></rect><path d="M4 14H44" stroke="url(#ik4s6tsjUdxagOc7MeTnlC1)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path><line x1="4" y1="11" x2="4" y2="23" stroke="url(#ik4s6tsjUdxagOc7MeTnlC1)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></line><line x1="44" y1="11" x2="44" y2="23" stroke="url(#ik4s6tsjUdxagOc7MeTnlC1)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></line><path fill-rule="evenodd" clip-rule="evenodd" d="M28 22V36H36V22H28Z" stroke="url(#ik4s6tsjUdxagOc7MeTnlC1)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path><path d="M12 22H20V36H12" stroke="url(#ik4s6tsjUdxagOc7MeTnlC1)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path><path d="M20 29H14" stroke="url(#ik4s6tsjUdxagOc7MeTnlC1)" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" fill="none"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/tabbarImg/item1a.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="72" height="72" style="" filter="none">
+    
+    <g>
+    <path d="M12 24h-6.667v-10.667h6.667v10.667zM20 24h-6.667v-16h6.667v16zM28 24h-6.667v-21.333h6.667v21.333zM29.333 29.333h-25.333v-2.667h25.333v2.667z" fill="rgba(22,119,255,1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/tabbarImg/item1b.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="72" height="72" style="" filter="none">
+    
+    <g>
+    <path d="M12 24h-6.667v-10.667h6.667v10.667zM20 24h-6.667v-16h6.667v16zM28 24h-6.667v-21.333h6.667v21.333zM29.333 29.333h-25.333v-2.667h25.333v2.667z" fill="rgba(153,153,153,1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/tabbarImg/item2a.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="72" height="72" style="" filter="none">
+    
+    <g>
+    <path d="M4 4h10.667v10.667h-10.667v-10.667zM4 17.333h10.667v10.667h-10.667v-10.667zM17.333 4h10.667v10.667h-10.667v-10.667zM17.333 17.333h10.667v10.667h-10.667v-10.667z" fill="rgba(22,119,255,1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/tabbarImg/item2b.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="72" height="72" style="" filter="none">
+    
+    <g>
+    <path d="M4 4h10.667v10.667h-10.667v-10.667zM4 17.333h10.667v10.667h-10.667v-10.667zM17.333 4h10.667v10.667h-10.667v-10.667zM17.333 17.333h10.667v10.667h-10.667v-10.667z" fill="rgba(153,153,153,1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/tabbarImg/item3a.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="72" height="72" style="" filter="none">
+    
+    <g>
+    <path d="M16.552 6.667h11.448c0.736 0 1.333 0.597 1.333 1.333v0 18.667c0 0.736-0.597 1.333-1.333 1.333v0h-24c-0.736 0-1.333-0.597-1.333-1.333v0-21.333c0-0.736 0.597-1.333 1.333-1.333v0h9.885l2.667 2.667zM16 17.333c1.841 0 3.333-1.492 3.333-3.333s-1.492-3.333-3.333-3.333v0c-1.841 0-3.333 1.492-3.333 3.333s1.492 3.333 3.333 3.333v0zM10.667 24h10.667c0-2.946-2.388-5.333-5.333-5.333s-5.333 2.388-5.333 5.333v0z" fill="rgba(22,119,255,1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/tabbarImg/item3b.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="72" height="72" style="" filter="none">
+    
+    <g>
+    <path d="M16.552 6.667h11.448c0.736 0 1.333 0.597 1.333 1.333v0 18.667c0 0.736-0.597 1.333-1.333 1.333v0h-24c-0.736 0-1.333-0.597-1.333-1.333v0-21.333c0-0.736 0.597-1.333 1.333-1.333v0h9.885l2.667 2.667zM16 17.333c1.841 0 3.333-1.492 3.333-3.333s-1.492-3.333-3.333-3.333v0c-1.841 0-3.333 1.492-3.333 3.333s1.492 3.333 3.333 3.333v0zM10.667 24h10.667c0-2.946-2.388-5.333-5.333-5.333s-5.333 2.388-5.333 5.333v0z" fill="rgba(153,153,153,1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/tabbarImg/item4a.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="72" height="72" style="" filter="none">
+    
+    <g>
+    <path d="M26.667 29.333h-21.333v-2.667c0-3.682 2.985-6.667 6.667-6.667v0h8c3.682 0 6.667 2.985 6.667 6.667v0 2.667zM16 17.333c-4.418 0-8-3.582-8-8s3.582-8 8-8v0c4.418 0 8 3.582 8 8s-3.582 8-8 8v0z" fill="rgba(22,119,255,1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/tabbarImg/item4b.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32" width="72" height="72" style="" filter="none">
+    
+    <g>
+    <path d="M26.667 29.333h-21.333v-2.667c0-3.682 2.985-6.667 6.667-6.667v0h8c3.682 0 6.667 2.985 6.667 6.667v0 2.667zM16 17.333c-4.418 0-8-3.582-8-8s3.582-8 8-8v0c4.418 0 8 3.582 8 8s-3.582 8-8 8v0z" fill="rgba(153,153,153,1)"></path>
+    </g>
+  </svg>

二进制
assets/img/topspan/span1.png


二进制
assets/img/topspan/span2.png


二进制
assets/img/topspan/span3.png


二进制
assets/img/topspan/span4.png


二进制
assets/img/topspan/span5.png


+ 6 - 0
assets/img/userTab/index1-1.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="16" height="16" style="" filter="none">
+    
+    <g>
+    <path d="M6.62 10.79a15.15 15.15 0 0 0 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z" fill="rgba(22,119,255,1)"></path>
+    </g>
+  </svg>

+ 6 - 0
assets/img/userTab/index1-2.svg

@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 24 24" width="16" height="16" style="" filter="none">
+    
+    <g>
+    <path d="M18.92 5.01C18.72 4.42 18.16 4 17.5 4h-11c-.66 0-1.21.42-1.42 1.01L3 11v8c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-1h12v1c0 .55.45 1 1 1h1c.55 0 1-.45 1-1v-8l-2.08-5.99zM6.5 15c-.83 0-1.5-.67-1.5-1.5S5.67 12 6.5 12s1.5.67 1.5 1.5S7.33 15 6.5 15zm11 0c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5zM5 10l1.5-4.5h11L19 10H5z" fill="rgba(0,185,98,1)"></path>
+    </g>
+  </svg>

二进制
assets/img/暂无数据-缺省页.png


二进制
assets/img/默认头像.png


+ 34 - 0
assets/js/font.js

@@ -0,0 +1,34 @@
+(function() {
+	
+		window.addEventListener('resize', () => {
+			if (document.activeElement.tagName == 'INPUT') {                      
+			window.setTimeout(() => { 
+				document.activeElement.scrollIntoViewIfNeeded();            
+			}, 100);        
+		}
+		})
+		
+				if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") {
+					handleFontSize();
+				} else {
+					if (document.addEventListener) {
+						document.addEventListener("WeixinJSBridgeReady", handleFontSize, false);
+					} else if (document.attachEvent) {
+						document.attachEvent("WeixinJSBridgeReady", handleFontSize);
+						document.attachEvent("onWeixinJSBridgeReady", handleFontSize);
+					}
+				}
+
+				function handleFontSize() {
+					/*设置网页字体为默认大小*/
+					WeixinJSBridge.invoke('setFontSizeCallback', {
+						'fontSize': 0
+					});
+					/*重写设置网页字体大小的事件*/
+					WeixinJSBridge.on('menu:setfont', function() {
+						WeixinJSBridge.invoke('setFontSizeCallback', {
+							'fontSize': 0
+						});
+					});
+				}
+			})();

+ 48 - 0
components/JPcontent.vue

@@ -0,0 +1,48 @@
+<template>
+	<view class="contentBody"  >
+		<view v-show="status==0" style="display: flex;justify-content: center;margin: 40px 0;" >
+			
+			<view class="uni-toast" style="display: flex;font-size: 60rpx;    color: rgb(192, 196, 204);" >
+				<i class="uni-icon_toast uni-loading"
+			style="
+			    width: 80rpx;
+			    height: 80rpx;
+				
+			"
+			></i><p class="uni-toast__content">  </p>加载中...</view>
+		</view>
+		<view v-show="status==1">
+			<view style=" margin-top: 60rpx; margin-bottom: 0rpx;">
+				<u-empty  text="无记录" mode="search"></u-empty>
+				
+			</view>
+				
+		</view>
+		<view v-show="status==2">
+			<slot ></slot>
+		</view>
+		
+	</view>
+</template>
+
+<script>
+
+	export default {
+		name:"contentBody",
+		props:{
+			status: {
+				type: Number,
+				default: 0
+			},
+		},
+		data() {
+			return {
+				
+			};
+		}
+	}
+</script>
+
+<style>
+
+</style>

+ 205 - 0
components/Map-equipment.vue

@@ -0,0 +1,205 @@
+<template>
+	<view>
+		<view id="container" :style="myStyle"></view>
+
+	</view>
+</template>
+
+<script>
+	let _self;
+
+	function mapMovestart(e) {
+		//'movestart')
+	}
+
+	function mapMove(e) {
+		//		//'mapMove')
+	}
+
+	function mapMoveend(e) {
+		//let _self = e;
+		let pos = _self.logMapInfo();
+
+		_self.$emit('onMoveEnd', pos);
+		//'mapMoveend')
+	}
+
+
+	import MapLoader from '@/apis/utils/AMap'
+
+	export default {
+		name: "Map-equipment",
+		data() {
+			return {
+				AMap: null,
+				mapcharger: null,
+				myStyle: "width: 100%; height: 1200rpx;",
+				longitude: 112.276527,
+				latitude: 30.306427,
+				iconList: []
+
+			};
+		},
+		methods: {
+			setList(sz) {
+				if (this.AMap == null) {
+					return
+				}
+				for (var i in this.iconList) {
+					if (this.iconList[i].marker) {
+						this.iconList[i].marker.setMap(null);
+					}
+					this.mapcharger.remove(this.iconList[i]);
+				}
+				this.iconList = []
+				for (var i in sz) {
+					var ob = sz[i];
+					this.addIcon(ob);
+
+				}
+
+			},
+			iconTemp1(marker, pos) {
+				var classId = ""
+				if (pos.status == 1) {
+					classId = "location1"
+				}
+				if (pos.status == 2) {
+					classId = "location2"
+				}
+				//初始化原点模板
+				var img = require("@/assets/img/antFill-alert Copy 1.svg")
+
+				var content = `<div class='${classId} ${pos.name}'><img src='${img}'/><div   class="corner"></div></div>`;
+
+				marker.setContent(content)
+				marker.setzIndex(900);
+			},
+			iconTemp2(marker, pos) {
+				//展开原点模板
+				var classId = "location2"
+				var statusName = pos.online ? '在线' : '离线';
+
+				var img1 = require("@/assets/img/antFill-alert.svg")
+				var img2 = require("@/assets/img/antFill-alert(2).svg")
+
+				var content = `<div class='${classId} ${pos.name}'>
+				<div  class="icon2-left" ><img src='${img1}'/></div>
+				
+				<div   class="icon2-right">
+					<div  class="corner2" ></div>
+					<div  class="corner2-top" >${pos.name}</div>
+					<div  class="corner2-bottom" ><img class="img2" src='${img2}'/>${statusName}</div>
+				</div>
+				</div>`;
+
+				marker.setContent(content)
+				marker.setzIndex(920);
+			},
+			addIcon(pos) {
+				let marker = new AMap.Marker({
+					content: '',
+					position: [pos.longitude, pos.latitude],
+					//offset: new AMap.Pixel(-20, -40),
+					offset: new AMap.Pixel(0, 0), //设置点标记偏移量
+					anchor: 'bottom-center',
+					zIndex: 900,
+					showPositionPoint: true,
+					autoRotation: true,
+				});
+				this.iconTemp1(marker, pos)
+				marker.setMap(this.mapcharger);
+				this.myEmit("charger", marker, pos)
+				this.iconList.push({
+					marker: marker,
+					info: pos
+				});
+
+			},
+			updateIcon(obj) {
+				if (this.iconList.length == 0) {
+					return
+				}
+				let index = this.iconList.findIndex(item => item.info.id == obj.id);
+				console.log("updateIcon", index)
+				for (var i in this.iconList) {
+					var marker = this.iconList[i].marker
+					var pos = this.iconList[i].info
+
+					this.iconTemp1(marker, pos)
+				}
+				var pos = this.iconList[index].info
+				var marker = this.iconList[index].marker
+				this.iconTemp2(marker, pos)
+			},
+			myEmit(type, ob1, obj) {
+				var _this = this;
+				console.log("myEmit")
+				AMap.event.addListener(ob1, 'click', function(e) {
+					console.log("myEmit2", type, ob1, obj)
+					_this.$emit('clickMap', {
+						type: type,
+						obj: obj
+					})
+				})
+
+			},
+			setMyStyle(s) {
+				this.myStyle = s;
+			},
+			logMapInfo() {
+				var posCenter = this.mapcharger.getCenter();
+				//			  //'center'+JSON.stringify(posCenter));
+				var limitBounds = this.mapcharger.getBounds();
+				let pos = {
+					center: posCenter,
+					bounds: limitBounds
+				};
+				return pos;
+			},
+			init() {
+				_self = this;
+				var _this = this;
+				MapLoader().then(AMap => {
+					this.AMap = AMap;
+					_this.mapcharger && _this.mapcharger.destroy();
+					_this.mapcharger = new AMap.Map("container", {
+						resizeEnable: true,
+						dragEnable: true,
+						center: [this.longitude, this.latitude],
+						zoom: 13
+					});
+					_this.mapcharger.setMapStyle('amap://styles/f9b17f73bb4576ab1894c29fe9d03c6c');
+
+					_this.$emit('onload')
+					//_this.addPosition();
+					_this.listenMove();
+
+				})
+
+			},
+			listenMove() {
+				var _this = this;
+
+				_this.mapcharger.on('movestart', mapMovestart);
+				_this.mapcharger.on('mapmove', mapMove);
+				_this.mapcharger.on('moveend', mapMoveend);
+
+			},
+
+		}
+
+	}
+</script>
+
+<style scoped>
+	/*去除下标*/
+	::v-deep.amap-logo {
+		display: none !important;
+	}
+
+	::v-deep.amap-copyright {
+		opacity: 0;
+		font-size: 1px;
+	}
+</style>

+ 167 - 0
components/ShareServer.vue

@@ -0,0 +1,167 @@
+<template>
+	<view></view>
+</template>
+
+<script>
+
+	import wx from 'weixin-js-sdk'
+	import * as API_WeiXin from '@/apis/weixin'
+
+	export default {
+		name: 'Share',
+		props: {
+			 
+		},
+		data() {
+			return {
+				id:'',
+				title:'',
+				url:'',
+				isLoading: false,
+				nowItem: {
+					shareTitle: '',
+					shareImg: '',
+					shareDescription: ''
+				}
+			}
+		},
+		created() {},
+		methods: {
+			 addPoint(){
+				 if(this.id){
+					 API_WeiXin.addPoint({
+					 					 id:this.id,
+					 					 pointCode:"70007"
+					 }).then(response => {
+					 		//("积分添加成功")
+							uni.showToast({
+								title: "分享成功",
+								icon: "none"
+							})
+									 
+					 })
+				 }
+				 
+			 },
+			
+			//获取微信jssdk配置信息
+			get_wx_config() {
+				
+				
+				API_WeiXin.getConfig(window.location.href.split("#")[0]).then(response => {
+					
+					
+					var wxconfig = response.data.wxConfig;
+					
+					//(wxconfig.nonceStr)
+					//this.wxConfig = wxconfig;
+				
+					wx.config({
+						debug: false, // 开启调试模式,
+						appId: wxconfig.appId, // 必填,企业号的唯一标识,此处填写企业号corpid
+						timestamp: wxconfig.timestamp, // 必填,生成签名的时间戳
+						nonceStr: wxconfig.nonceStr, // 必填,生成签名的随机串
+						signature: wxconfig.signature, // 必填,签名,见附录1
+						jsApiList: ['onMenuShareTimeline', 'onMenuShareAppMessage', 
+						'onMenuShareQQ', 'onMenuShareQZone'] ,// 必填,需要使用的JS接口列表,所有JS接口列表见附录2
+						//'checkJsApi',,'updateAppMessageShareData','updateTimelineShareData'
+					});
+					
+						//("aaa")
+					//this.wxShare()
+				}).catch(error => {
+					//(error)
+						//("errorerror")
+				})
+			},
+			setUrl(url){
+				this.url=url;
+			},
+			setTitle(text,id){
+				this.title=text;
+				this.id=id;
+				this.wxShare() 
+				
+			},
+			//微信分享自定义
+			wxShare() {
+				var userInfo=this.jphelp.getPersonInfo()
+				var img=require("@/assets/img/logo.png")
+				
+				var title=this.title
+			//	var desc=
+				let joinUrl = this.url;
+				//(img);
+				//(title);
+				//(joinUrl);
+				var _this = this;
+				
+				wx.ready(function() {
+					
+					
+					// wx.updateTimelineShareData({
+					// 	title: title,
+					// //	desc:desc ,
+					// 	link: joinUrl,
+					// 	 imgUrl: img,
+					// 	success: function() {
+					// 		if(userInfo){
+					// 			//_this.addPoint()
+					// 		}
+					// 		// 设置成功
+					// 		_this.$emit("wxShare",null);
+					// 	}
+					// })
+					// wx.updateAppMessageShareData({
+					// 	title: title,
+					// //	desc:desc ,
+					// 	link: joinUrl,
+					// 	 imgUrl: img,
+					// 	success: function() {
+					// 		if(userInfo){
+					// 			//_this.addPoint()
+					// 		}
+					// 		// 设置成功
+					// 		_this.$emit("wxShare",null);
+					// 	}
+					// })
+					wx.onMenuShareAppMessage({
+						title: title,
+					 	desc:"[电管家]" ,
+						link: joinUrl,
+						 imgUrl: img,
+						success: function() {
+							//('111')
+							if(userInfo){
+								_this.addPoint()
+							}
+							// 设置成功
+							_this.$emit("wxShare",null);
+						}
+					})
+					wx.onMenuShareTimeline({
+						title: title,
+						desc:"[电管家]" ,
+						link: joinUrl,
+						 imgUrl: img,
+						success: function() {
+								//('222')
+							if(userInfo){
+								_this.addPoint()
+							}
+							// 设置成功
+							_this.$emit("wxShare",null);
+						}
+					})
+				});
+			}
+		},
+		mounted() {
+			this.url=window.location.href;
+			this.get_wx_config();
+		},
+	}
+</script>
+
+<style>
+</style>

+ 81 - 0
components/Tabbar.vue

@@ -0,0 +1,81 @@
+<template>
+	<view>
+		<u-tabbar v-model="myCurrent" :list="tabbarList"  inactive-color="#ADB8C2" active-color="#5098FF">
+		</u-tabbar>
+
+	</view>
+</template>
+
+<script>
+	var img1=require('@/assets/img/tabbarImg/item1a.svg')
+	var img2=require('@/assets/img/tabbarImg/item1b.svg')
+	var img3=require('@/assets/img/tabbarImg/item2a.svg') 
+	var img4=require('@/assets/img/tabbarImg/item2b.svg')
+	var img5=require('@/assets/img/tabbarImg/item3a.svg')
+	var img6=require('@/assets/img/tabbarImg/item3b.svg')
+	var img7=require('@/assets/img/tabbarImg/item4a.svg')
+	var img8=require('@/assets/img/tabbarImg/item4b.svg')
+	
+	
+	export default {
+		name: "Tabbar",
+		props: {
+			current: 0,
+			elderStatus: false
+		},
+		data() {
+			return {
+				oldindex: this.current,
+				myCurrent: this.current,
+				tabbarList: [{
+
+						iconPath: img2,
+						selectedIconPath: img1,
+						text: '主页 ',
+						pagePath: "/pages/index/index",
+					},
+					 {
+					 	iconPath: img4,
+					 	selectedIconPath: img3,
+					 	text: '地锁',
+					 	pagePath: "/pages/deviceTab/index",
+					 	
+					 },
+					// {
+					// 	iconPath: img6,
+					// 	selectedIconPath: img5,
+					// 	text: '用户',
+					// 	pagePath: "/pages/userTab/index",
+						
+					// },
+					
+					{
+						iconPath: img8,
+						selectedIconPath: img7,
+
+						text: '我的',
+						pagePath: "/pages/myTab/index",
+					}
+				],
+			};
+
+		},
+		methods: {
+			
+			
+
+		},
+		mounted() {
+
+		},
+		destroyed() {
+
+		}
+
+
+	}
+</script>
+
+<style>
+
+</style>

+ 153 - 0
components/bobo-router/README.md

@@ -0,0 +1,153 @@
+# bobo-router
+
+bobo-router 是一个基于uni-app框架的路由拦截插件,本项目借鉴了[uni-simple-router](https://github.com/SilurianYang/uni-simple-router)的思路,并对其进行简化,简化的原因是因为自己比较懒,不想每次新增页面就定义两遍路由表,所以`bobo-router`的特点就是纯粹的路由拦截,不再**定义两遍路由表**。
+
+当然,由于不再定义路由表,也损失了一些能力,比如不能使用命名路由,不能在路由表中自定义路由元信息等。
+
+> 本人不是大神,插件可能会存在各种各样的问题,望大家谨慎使用,并多多担待。
+
+## 安装
+
+下载插件后,在`main.js`中导入即可。
+
+```js
+// main.js
+
+import router from './utils/bobo-router'
+```
+
+## 基本使用
+
+同`uni-simple-router`一样,项目中的路由跳转要全部弃用`uni.navigateTo()`这样的系统跳转方法,转而使用插件提供的`this.$Router.push()`这样的方法。
+
+```js
+// *.vue
+
+// 跳转页面,保留当前页到页面栈,等同于 uni.navigateTo()
+this.$Router.push({
+	page: '/pages/index/index',
+	params: {}
+})
+
+// 跳转页面,替换当前页到页面栈,等同于 uni.redirectTo()
+this.$Router.replace({
+	page: '/pages/index/index',
+	params: {}
+})
+
+// 跳转页面,清空页面栈,等同于 uni.reLaunch()
+this.$Router.replaceAll({
+	page: '/pages/index/index',
+	params: {}
+})
+
+// 跳转 Tabbar,等同于 uni.switchTab()
+this.$Router.pushTab({
+	page: '/pages/index/index',
+	params: {}
+})
+```
+
+> Tips: 
+> 如果不需要传递参数,可以直接使用 this.$Router.push('/pages/index/index')
+
+> 注意:
+> pushTab传递的参数可通过this.$Route.params获取,但h5页面刷新之后就会丢失数据
+
+## 路由拦截
+
+支持路由前置守卫和路由后置守卫,并且提供一个路由跳转失败的回调,可以重写以实现自己的逻辑。
+
+在`bobo-router/index.js`中添加自己的拦截逻辑。
+
+```js
+// ./utils/bobo-router/index.js
+
+// 路由全局拦截器 在这里处理登录、授权等相关操作
+router.beforeEach(function(to, from, next) {
+	console.log('前置守卫')
+	// to.page不存在表示此次路由跳转仅为了执行路由守卫,若不需处理则直接放行,就不会执行任何路由操作了
+	if (from.page === '/pages/plugin/routers/r3' && !to.page) {
+	// 测试小程序跳转
+	// if (from.page === '/pages/index/index' && !to.page) {
+		next({page: '/pages/plugin/routers/r4', params: {
+			message: '我是从路由3刷新跳过来的'
+		}, method: 'redirectTo'})
+	} else {
+		next()
+	}
+})
+
+// 路由后置拦截器 在这里处理用户高频操作信息
+router.afterEach(function (to, from) {
+	console.log('后置守卫')
+})
+
+// 路由跳转出错处理
+router.onError(function(e) {
+	console.log('错误:', e.message || '路由跳转失败')
+})
+```
+
+参数解释:
+
+**to**:目标路由信息,包含`method`路由跳转方式、`page`页面地址和`params`页面参数
+
+> 注:在进入应用的第一个页面或h5刷新页面后会执行路由前置守卫,此时 to 中的属性均为 undefined
+
+**from**:当前路由信息,包含`page`页面地址和`params`页面参数
+
+**next**:下一步操作
+
+- `next(false)` 中断路由跳转
+- `next('/pages/index/index')` 执行指定页面的路由前置守卫,若当前操作指定过跳转方式,则使用该跳转方式,否则使用默认的push进行跳转
+- `next({page:'/pages/index/index',params:{},method:''})` 执行指定页面的路由前置守卫,method传入跳转方式,也可以不指定,效果同直接传入页面地址
+- `next()` 放行 执行跳转操作
+
+## 参数解析
+
+使用本插件的方法去跳转路由,会将对象的第一级属性转换到URL中,深层对象则转为json串放在对应的属性中。
+
+例如:
+
+```js
+// 转换前对象
+{
+	num: 19,
+	numStr: '19',
+	testParams: true,
+	deepObj: {
+		str: 'hahaha'
+	},
+	ignoreFun: function() {
+		console.log('i\'m hide.')
+	},
+	testUndefined: undefined,
+	testNull: null
+}
+
+// 转换后URL
+?num=19&numStr=19&testParams=true&deepObj=%7B"str"%3A"hahaha"%7D&testUndefined=&testNull=
+```
+
+如果要获取当前路由信息,可通过`this.$Route`获取。
+
+```js
+{
+    "path": "/pages/plugin/router?num=19&numStr=19&testParams=true&deepObj={\"str\":\"hahaha\"}&testUndefined=&testNull=",
+    "params": {
+        "num": 19,
+        "numStr": "19",
+        "testParams": true,
+        "deepObj": {
+            "str": "hahaha"
+        },
+        "testNull": null
+    },
+    "page": "/pages/plugin/router",
+    "pageTitle": "路由拦截插件"
+}
+```
+
+> 页面标题 pageTitle 是在页面中的 data(){}代码块中定义了之后才能正常显示,且只能在onload生命周期之后使用。
+> h5端则不需要定义pageTitle,插件可直接获取当前网页标题。

+ 362 - 0
components/bobo-router/bobo-router.js

@@ -0,0 +1,362 @@
+class Router {
+	constructor(arg) {
+		if (arg && arg.constructor !== Object) {
+			return console.error(`Routing configuration must be an Object`)
+		}
+		Router.$root = this;
+	}
+
+	// 路由跳转方法映射
+	routeMap = {
+		push: 'navigateTo',
+		replace: 'redirectTo',
+		replaceAll: 'reLaunch',
+		pushTab: 'switchTab'
+	}
+
+	/**
+	 * 执行路由跳转
+	 */
+	_pushTo() {
+		return new Promise((resolve, reject) => {
+			let {
+				page,
+				params,
+				method
+			} = this.tempRoute
+			// 对首次进入页面执行路由守卫时如果放行,method page params都为空 此时应该直接中断流程,无需抛出异常
+			if (!method && !page && !params) {
+				return
+			}
+
+			let urlParams = '?'
+			if (!page) {
+				reject(new Error('参数page未填写'))
+				return
+			} else if (params && typeof(params) === 'object') {
+				// 处理参数,转换为url字符串
+				Object.keys(params).forEach(k => {
+					// 深度对象转为json字符串(包含数组)
+					if (typeof(params[k]) === 'object') {
+						if (params[k]) {
+							const json = JSON.stringify(params[k])
+							urlParams += `${k}=${json}&`
+						} else {
+							urlParams += `${k}=&`
+						}
+					} else if (typeof(params[k]) === 'number' || typeof(params[k]) === 'string' || typeof(params[k]) ===
+						'boolean') {
+						// 基础值直接写入
+						urlParams += `${k}=${params[k]}&`
+					} else if (typeof(params[k]) === 'undefined') {
+						urlParams += `${k}=&`
+					}
+				})
+			}
+
+			// 参数组装
+			if (urlParams.length === 1) {
+				urlParams = ''
+			} else {
+				urlParams = urlParams.substr(0, urlParams.length - 1)
+			}
+
+			// 设置路由跳转方式
+			if (!method) {
+				method = 'navigateTo'
+			}
+			if (this.routeMap[method]) {
+				method = this.routeMap[method]
+			}
+
+			// 调用系统跳转方法
+			uni[method]({
+				url: page + urlParams,
+				success: () => {
+					// 执行路由后置守卫
+					if (this._afterEach && typeof(this._afterEach) === 'function') {
+						this._afterEach.call(this, this.tempRoute, this.route)
+					}
+
+					// 更新路由信息
+					this.route = {
+						path: page + urlParams,
+						params: params || {},
+						page
+					}
+					this.tempRoute = null
+					resolve()
+				},
+				fail: (e) => {
+					reject(new Error('路由跳转失败!'))
+				}
+			})
+		})
+	}
+
+	/**动态的导航到一个新 URL 保留浏览历史
+	 * navigateTo
+	 * @param {Object} rule
+	 */
+	push(arg) {
+		const rule = {
+			method: 'navigateTo'
+		}
+		if (typeof(arg) === 'string') {
+			rule.page = arg
+		} else if (typeof(arg) === 'object') {
+			rule.page = arg.page
+			rule.params = arg.params
+		}
+		this.next(rule)
+	}
+
+	/**动态的导航到一个新 URL 关闭当前页面,跳转到的某个页面。
+	 * redirectTo
+	 * @param {Object} rule
+	 */
+	replace(arg) {
+		const rule = {
+			method: 'redirectTo'
+		}
+		if (typeof(arg) === 'string') {
+			rule.page = arg
+		} else if (typeof(arg) === 'object') {
+			rule.page = arg.page
+			rule.params = arg.params
+		}
+		this.next(rule)
+	}
+
+	/**动态的导航到一个新 URL 关闭所有页面,打开到应用内的某个页面
+	 * 	reLaunch
+	 * @param {Object} rule
+	 */
+	replaceAll(arg) {
+		const rule = {
+			method: 'reLaunch'
+		}
+		if (typeof(arg) === 'string') {
+			rule.page = arg
+		} else if (typeof(arg) === 'object') {
+			rule.page = arg.page
+			rule.params = arg.params
+		}
+		this.next(rule)
+	}
+
+	/** 跳转Tabbar
+	 * 	switchTab
+	 * @param {Object} rule
+	 */
+	pushTab(arg) {
+		const rule = {
+			method: 'switchTab'
+		}
+		if (typeof(arg) === 'string') {
+			rule.page = arg
+		} else if (typeof(arg) === 'object') {
+			rule.page = arg.page
+			rule.params = arg.params
+		}
+		this.next(rule)
+	}
+
+
+	/**
+	 * 返回到指定层级页面上
+	 */
+	back(delta = 1) {
+		// 返回上级
+		if (delta.constructor != Number) {
+			this._errorHandler(new Error('返回层级参数必须是一个Number类型且必须大于0:'))
+			return
+		}
+		uni.navigateBack({
+			delta
+		})
+	}
+
+	/**
+	 * 分发路由
+	 * @param {Object} args
+	 */
+	_next() {
+		return new Promise((resolve, reject) => {
+			if (this._beforeEach && typeof(this._beforeEach) === 'function') {
+				// 需要传给守卫 to from next
+				this._beforeEach.call(this, this.tempRoute, this.route, resolve)
+			} else {
+				this._pushTo().catch(e => {
+					reject(e)
+				})
+			}
+		})
+	}
+
+	next(args) {
+		if (args) {
+			// 保存临时数据
+			if (typeof(args) === 'object') {
+				this.tempRoute = {
+					// 第一次调用next一定存在method,后续循环调用可能不会存在,不存在时使用上次缓存的method
+					method: args.method || this.tempRoute.method,
+					page: args.page,
+					params: args.params
+				}
+			} else if (typeof(args) === 'string') {
+				this.tempRoute = {
+					page: args
+				}
+			} else if (!args) {
+				// 中断路由 args = false
+				this.tempRoute = null
+				return
+			}
+
+			if (!this.route) {
+				this.route = {
+					page: '/' + getCurrentPages()[0].route
+				}
+			}
+
+			this._next().then(args => {
+				this.next(args)
+			}).catch(e => {
+				this.tempRoute = null
+				this._errorHandler(e)
+			})
+		} else {
+			this._pushTo().catch(e => {
+				this.tempRoute = null
+				this._errorHandler(e)
+			})
+		}
+	}
+
+	/**
+	 * 应用启动时执行一次路由检查(前置守卫,若通过则不做事情)
+	 */
+	doBeforeHooks() {
+		this.tempRoute = {}
+		this.next({})
+	}
+
+	// 设置路由前置/后置守卫
+	beforeEach(fn) {
+		this._beforeEach = fn
+	}
+	afterEach(fn) {
+		this._afterEach = fn
+	}
+	// 设置路由跳转错误处理
+	onError(fn) {
+		if (fn && typeof(fn) === 'function') {
+			this._errorHandler = fn
+		}
+	}
+
+	// 获取当前路由信息
+	getCurrentRoute() {
+		return this.route
+	}
+
+}
+
+// 路由对象属性定义
+Router.$root = null
+// 当前路由内容
+Router.route = null
+// 临时路由信息
+Router.tempRoute = null
+// 路由前置后置守卫
+Router._beforeEach = null
+Router._afterEach = null
+// 路由跳转错误处理
+Router._errorHandler = function(e) {
+	console.error(e)
+}
+
+Router.install = function(Vue) {
+	Vue.mixin({
+		onLaunch: function() {},
+		onLoad: function(props) {
+			// 首次进入页面时,缓存中不存在当前路由信息,需要初始化路由信息
+			if (!Router.$root.getCurrentRoute()) {
+				const rt = {
+					params: {},
+					page: '/' + getCurrentPages()[0].route
+				}
+				if (props) {
+					Object.keys(props).forEach(k => {
+						// url转的对象全部都是字符串,需要识别其中的对象和基本数据类型
+						try {
+							const obj = JSON.parse(props[k])
+							if (typeof(obj) === 'string') {
+								// 只有字符串还会是字符串,数字、布尔、数组均会转换为正常类型
+								rt.params[k] = props[k]
+							} else {
+								rt.params[k] = obj
+							}
+						} catch (e) {
+							rt.params[k] = props[k]
+						}
+					})
+				}
+				Router.$root.route = rt
+
+				// 执行路由前置守卫
+				Router.$root.doBeforeHooks()
+			}
+
+			// 自动获取页面标题(app端可能获取不到)
+			const pages = getCurrentPages()
+			let pageTitle = pages[pages.length - 1].pageTitle
+			// #ifdef H5
+			if (!pageTitle) {
+				pageTitle = document.title
+			}
+			// #endif
+			Router.$root.route.pageTitle = pageTitle
+		},
+
+		onShow() {
+			if (!getCurrentPages().length) {
+				return
+			}
+			// 获取当前路由信息
+			const pages = getCurrentPages()
+			const page = pages[pages.length - 1]
+			let pageTitle = page.pageTitle
+			const rt = {
+				params: {},
+				page: '/' + page.route,
+			}
+			if (!pageTitle) {
+				// #ifdef H5
+				rt.pageTitle = document.title
+				// #endif
+			} else {
+				rt.pageTitle = pageTitle
+			}
+			
+			const route = Router.$root.route
+			// 若当前页面地址不等于缓存中地址,则更新缓存路由信息
+			if (!route || route.page !== rt.page) {
+				Router.$root.route = rt
+			}
+		}
+	})
+	Object.defineProperty(Vue.prototype, "$Router", {
+		get: function() {
+			return Router.$root
+		}
+	})
+	Object.defineProperty(Vue.prototype, "$Route", {
+		get: function() {
+			return Router.$root.getCurrentRoute()
+		}
+	})
+}
+
+export default Router

+ 64 - 0
components/bobo-router/index.js

@@ -0,0 +1,64 @@
+ 
+// import  jphelp from '@/utils/mixin.js'
+
+import Vue from 'vue'
+//  先运行yarn  初始化
+import uniCrazyRouter from "uni-crazy-router";
+Vue.use(uniCrazyRouter)
+//** 有bug, 第一次直接敲链接访问, 是访问bobo-router 前置守卫
+//**  后续操作,访问的是 uniCrazyRouter的前置守卫
+
+
+uniCrazyRouter.beforeEach(async (to, from, next) => {
+
+
+	routerBeforeEach(to, from, next);
+	
+})
+
+uniCrazyRouter.afterEach((to, from) => {
+	// 逻辑代码
+	console.log("afterEach")
+
+})
+
+uniCrazyRouter['on' + 'Error']((to, from) => {
+	// 逻辑代码
+	console.log("Error+start")
+	console.log(to)
+	console.log(from)
+	console.log("Error+end")
+	
+})
+
+import Router from './bobo-router'
+import jphelp from '@/apis/utils/mixin.js'
+
+//Vue.use(Router)
+
+// 路由配置 页面中全部使用this.$Router来操作路由,以实现路由的全局管理
+const router = new Router()
+
+// 路由全局拦截器 在这里处理登录、授权等相关操作
+router.beforeEach(function(to, from, next) {
+	
+	
+	routerBeforeEach(to, from, next);
+
+})
+ 
+
+function routerBeforeEach(to, from, next) {
+	next();
+}
+// 路由后置拦截器
+router.afterEach(function(to, from) {
+	console.log('后置守卫')
+})
+
+// 路由跳转出错处理
+router.onError(function(e) {
+	console.log('错误:', e.message || '路由跳转失败')
+})
+
+export default router

+ 227 - 0
components/limeClipper/README.md

@@ -0,0 +1,227 @@
+> 插件来源:[https://ext.dcloud.net.cn/plugin?id=3594](https://ext.dcloud.net.cn/plugin?id=3594)
+##### 以下是作者写的插件介绍:
+
+# Clipper 图片裁剪
+> uniapp 图片裁剪,可用于图片头像等裁剪处理
+> [查看更多](http://liangei.gitee.io/limeui/#/clipper) <br>
+> Q群:458377637
+
+
+## 平台兼容
+
+| H5  | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
+| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- |
+| √   | √          | √         | 未测       | √          | √      | √   |
+
+
+## 代码演示
+### 基本用法
+`@success` 事件点击 👉 **确定** 后会返回生成的图片信息,包含 `url`、`width`、`height`
+
+```html
+<image :src="url" v-if="url" mode="widthFix"></image>
+<l-clipper v-if="show" @success="url = $event.url; show = false" @cancel="show = false"  ></l-clipper>
+<button @tap="show = true">裁剪</button>
+```
+
+```js
+// 非uni_modules引入
+import lClipper from '@/components/lime-clipper/'
+// uni_modules引入
+import lClipper from '@/uni_modules/lime-clipper/components/lime-clipper/'
+export default {
+	components: {lClipper},
+    data() {
+        return {
+            show: false,
+			url: '',
+        }
+    }
+}
+```
+
+
+### 传入图片
+`image-url`可传入**相对路径**、**临时路径**、**本地路径**、**网络图片**<br>
+
+* **当为网络地址时**
+* H5:👉 需要解决跨域问题。 <br>
+* 小程序:👉 需要配置 downloadFile 域名 <br>
+
+
+```html
+<image :src="url" v-if="url" mode="widthFix"></image>
+<l-clipper v-if="show" :image-url="imageUrl"  @success="url = $event.url; show = false" @cancel="show = false"  ></l-clipper>
+<button @tap="show = true">裁剪</button>
+```
+
+```js
+export default {
+	components: {lClipper},
+    data() {
+        return {
+			imageUrl: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/97205/26/1142/87801/5dbac55aEf795d962/48a4d7a63ff80b8b.jpg',
+            show: false,
+			url: '',
+        }
+    }
+}
+```
+
+
+### 确定按钮颜色
+样式变量名:`--l-clipper-confirm-color`
+可放到全局样式的 `page` 里或节点的 `style`
+```html
+<l-clipper class="clipper" style="--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)"  ></l-clipper>
+```
+```css
+// css 中为组件设置 CSS 变量
+.clipper {
+	--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
+}
+// 全局
+page {
+	--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
+}
+```
+
+
+### 使用插槽
+共五个插槽 `cancel` 取消按钮、 `photo` 选择图片按钮、 `rotate` 旋转按钮、 `confirm` 确定按钮和默认插槽。
+
+```html
+<image :src="url" v-if="url" mode="widthFix"></image>
+<l-clipper 
+	v-if="show" 
+	:isLockWidth="isLockWidth"
+	:isLockHeight="isLockHeight"
+	:isLockRatio="isLockRatio"
+	:isLimitMove="isLimitMove"
+	:isDisableScale="isDisableScale"
+	:isDisableRotate="isDisableRotate"
+	:isShowCancelBtn="isShowCancelBtn"
+	:isShowPhotoBtn="isShowPhotoBtn"
+	:isShowRotateBtn="isShowRotateBtn"
+	:isShowConfirmBtn="isShowConfirmBtn"
+	@success="url = $event.url; show = false" 
+	@cancel="show = false" >
+	<!-- 四个基本按钮插槽 -->
+	<view slot="cancel">取消</view>
+	<view slot="photo">选择图片</view>
+	<view slot="rotate">旋转</view>
+	<view slot="confirm">确定</view>
+	<!-- 默认插槽 -->
+	<view class="tools">
+		<view>显示取消按钮
+			<switch :checked="isShowCancelBtn" @change="isShowCancelBtn = $event.target.value" ></switch>
+		</view>
+		<view>显示选择图片按钮
+			<switch :checked="isShowPhotoBtn" @change="isShowPhotoBtn = $event.target.value" ></switch>
+		</view>
+		<view>显示旋转按钮
+			<switch :checked="isShowRotateBtn" @change="isShowRotateBtn = $event.target.value" ></switch>
+		</view>
+		<view>显示确定按钮
+			<switch :checked="isShowConfirmBtn" @change="isShowConfirmBtn = $event.target.value" ></switch>
+		</view>
+		<view>锁定裁剪框宽度
+			<switch :checked="isLockWidth" @change="isLockWidth = $event.target.value" ></switch>
+		</view>
+		<view>锁定裁剪框高度
+			<switch :checked="isLockHeight" @change="isLockHeight = $event.target.value" ></switch>
+		</view>
+		<view>锁定裁剪框比例
+			<switch :checked="isLockRatio" @change="isLockRatio = $event.target.value" ></switch>
+		</view>
+		<view>限制移动范围
+			<switch :checked="isLimitMove" @change="isLimitMove = $event.target.value" ></switch>
+		</view>
+		<view>禁止缩放
+			<switch :checked="isDisableScale" @change="isDisableScale = $event.target.value" ></switch>
+		</view>
+		<view>禁止旋转
+			<switch :checked="isDisableRotate" @change="isDisableRotate = $event.target.value" ></switch>
+		</view>
+	</view>
+</l-clipper>
+<button @tap="show = true">裁剪</button>
+```
+
+```js
+export default {
+	components: {lClipper},
+    data() {
+        return {
+            show: false,
+            url: '',
+            isLockWidth: false,
+            isLockHeight: false,
+            isLockRatio: true,
+            isLimitMove: false,
+            isDisableScale: false,
+            isDisableRotate: false,
+            isShowCancelBtn: true,
+            isShowPhotoBtn: true,
+            isShowRotateBtn: true,
+            isShowConfirmBtn: true
+        }
+    }
+}
+```
+
+
+## API
+
+### Props
+
+| 参数           | 说明         | 类型             | 默认值       |
+| ------------- | ------------ | ---------------- | ------------ |
+| image-url     | 图片路径     | <em>string</em>   |              |
+| quality       | 图片的质量,取值范围为 [0, 1],不在范围内时当作1处理   | <em>number</em>  |    `1`      |
+| source       | `{album: '从相册中选择'}`key为图片来源类型,value为选项说明   | <em>Object</em>  |         |
+| width | 裁剪框宽度,单位为 `rpx` | <em>number</em> | `400`      |
+| height | 裁剪框高度 | <em>number</em> | `400`      |
+| min-width | 裁剪框最小宽度 | <em>number</em> | `200`      |
+| min-height |裁剪框最小高度 | <em>number</em> | `200`  |
+| max-width | 裁剪框最大宽度 | <em>number</em> | `600`  |
+| max-height | 裁剪框最大宽度 | <em>number</em> | `600`  |
+| min-ratio | 图片最小缩放比 | <em>number</em> | `0.5`  |
+| max-ratio | 图片最大缩放比 | <em>number</em> | `2`  |
+| rotate-angle | 旋转按钮每次旋转的角度 | <em>number</em> | `90`  |
+| scale-ratio | 生成图片相对于裁剪框的比例, **比例越高生成图片越清晰**	 | <em>number</em> | `1`  |
+| is-lock-width | 是否锁定裁剪框宽度 | <em>boolean</em> | `false`  |
+| is-lock-height | 是否锁定裁剪框高度上 | <em>boolean</em> | `false`  |
+| is-lock-ratio | 是否锁定裁剪框比例 | <em>boolean</em> | `true`  |
+| is-disable-scale | 是否禁止缩放 | <em>boolean</em> | `false`  |
+| is-disable-rotate | 是否禁止旋转 | <em>boolean</em> | `false`  |
+| is-limit-move | 是否限制移动范围 | <em>boolean</em> | `false`  |
+| is-show-photo-btn | 是否显示选择图片按钮 | <em>boolean</em> | `true`  |
+| is-show-rotate-btn | 是否显示转按钮 | <em>boolean</em> | `true`  |
+| is-show-confirm-btn | 是否显示确定按钮 | <em>boolean</em> | `true`  |
+| is-show-cancel-btn | 是否显示关闭按钮 | <em>boolean</em> | `true`  |
+
+
+
+### 事件 Events
+
+| 事件名  | 说明         | 回调           |
+| ------- | ------------ | -------------- |
+| success | 生成图片成功 | {`width`, `height`, `url`} |
+| fail | 生成图片失败 | `error` |
+| cancel | 关闭 | `false` |
+| ready   | 图片加载完成 | {`width`, `height`, `path`, `orientation`, `type`} |
+| change | 图片大小改变时触发 | {`width`, `height`} |
+| rotate | 图片旋转时触发 | `angle` |
+
+## 常见问题
+> 1、H5端使用网络图片需要解决跨域问题。<br>
+> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!<br>
+> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签`<IMG/>`<br>
+> 4、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。<br>
+> 5、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。<br>
+
+
+## 打赏
+如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。<br>
+![输入图片说明](https://images.gitee.com/uploads/images/2020/1122/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg")

+ 19 - 0
components/limeClipper/images/photo.svg

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#606060;}
+	.st1{fill:none;stroke:#FFFFFF;stroke-width:2.4306;stroke-miterlimit:10;}
+	.st2{fill:#FFFFFF;}
+</style>
+<g>
+	<path class="st2" d="M11.6,11c0.4,0.4,0.6,0.9,0.6,1.5c0,0.6-0.2,1.1-0.6,1.4c-0.4,0.4-0.9,0.6-1.5,0.6c-0.6,0-1.1-0.2-1.5-0.6
+		c-0.4-0.4-0.6-0.9-0.6-1.4s0.2-1.1,0.6-1.5c0.4-0.4,0.9-0.6,1.5-0.6C10.8,10.4,11.2,10.6,11.6,11z M24.6,18.4V6.7H5.4v12l1.8-1.8
+		c0.3-0.3,0.6-0.4,1-0.4c0.4,0,0.7,0.1,1,0.4l1.8,1.8l5.8-7c0.3-0.3,0.6-0.5,1.1-0.5c0.4,0,0.8,0.2,1.1,0.5
+		C18.8,11.6,24.6,18.4,24.6,18.4z M25.6,5.7C25.9,6,26,6.3,26,6.7v16.1c0,0.4-0.1,0.7-0.4,1c-0.3,0.3-0.6,0.4-1,0.4H5.4
+		c-0.4,0-0.7-0.1-1-0.4c-0.3-0.3-0.4-0.6-0.4-1V6.7c0-0.4,0.1-0.7,0.4-1c0.3-0.3,0.6-0.4,1-0.4h19.3C25,5.3,25.3,5.4,25.6,5.7z"/>
+	<path class="st1" d="M24.3,21.5H5.7c-0.2,0-0.3-0.2-0.3-0.3V7c0-0.2,0.2-0.3,0.3-0.3h18.6c0.2,0,0.3,0.2,0.3,0.3v14.2
+		C24.6,21.3,24.5,21.5,24.3,21.5z"/>
+</g>
+</svg>

+ 15 - 0
components/limeClipper/images/rotate.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="30px" height="30px" viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:none;stroke:#FFFFFF;stroke-width:2.4306;stroke-miterlimit:10;}
+	.st1{fill:#FFFFFF;}
+</style>
+<g>
+	<path class="st0" d="M17.1,24.2h-12c-0.2,0-0.3-0.2-0.3-0.3v-9.3c0-0.2,0.2-0.3,0.3-0.3h12c0.2,0,0.3,0.2,0.3,0.3v9.3
+		C17.5,24.1,17.3,24.2,17.1,24.2z"/>
+	<path class="st0" d="M16.6,5.4c4.8,0,8.7,3.9,8.7,8.7"/>
+	<polyline class="st0" points="19.3,10.1 14.9,5.6 19.3,1.2 	"/>
+</g>
+</svg>

+ 160 - 0
components/limeClipper/index.css

@@ -0,0 +1,160 @@
+.flex-auto {
+  flex: auto;
+}
+.bg-transparent {
+  background-color: rgba(0,0,0,0.9);
+  transition-duration: 0.35s;
+}
+.l-clipper {
+  width: 100vw;
+  height: calc(100vh - var(--window-top));
+  background-color: rgba(0,0,0,0.9);
+  position: fixed;
+  top: var(--window-top);
+  left: 0;
+  z-index: 1;
+}
+.l-clipper-mask {
+  position: relative;
+  z-index: 2;
+  pointer-events: none;
+}
+.l-clipper__content {
+  pointer-events: none;
+  position: absolute;
+  border: 1rpx solid rgba(255,255,255,0.3);
+  box-sizing: border-box;
+  box-shadow: rgba(0,0,0,0.5) 0 0 0 80vh;
+  background: transparent;
+}
+.l-clipper__content::before,
+.l-clipper__content::after {
+  content: '';
+  position: absolute;
+  border: 1rpx dashed rgba(255,255,255,0.3);
+}
+.l-clipper__content::before {
+  width: 100%;
+  top: 33.33%;
+  height: 33.33%;
+  border-left: none;
+  border-right: none;
+}
+.l-clipper__content::after {
+  width: 33.33%;
+  left: 33.33%;
+  height: 100%;
+  border-top: none;
+  border-bottom: none;
+}
+.l-clipper__edge {
+  position: absolute;
+  width: 34rpx;
+  height: 34rpx;
+  border: 6rpx solid #fff;
+  pointer-events: auto;
+}
+.l-clipper__edge::before {
+  content: '';
+  position: absolute;
+  width: 40rpx;
+  height: 40rpx;
+  background-color: transparent;
+}
+.l-clipper__edge:nth-child(1) {
+  left: -6rpx;
+  top: -6rpx;
+  border-bottom-width: 0 !important;
+  border-right-width: 0 !important;
+}
+.l-clipper__edge:nth-child(1):before {
+  top: -50%;
+  left: -50%;
+}
+.l-clipper__edge:nth-child(2) {
+  right: -6rpx;
+  top: -6rpx;
+  border-bottom-width: 0 !important;
+  border-left-width: 0 !important;
+}
+.l-clipper__edge:nth-child(2):before {
+  top: -50%;
+  left: 50%;
+}
+.l-clipper__edge:nth-child(3) {
+  left: -6rpx;
+  bottom: -6rpx;
+  border-top-width: 0 !important;
+  border-right-width: 0 !important;
+}
+.l-clipper__edge:nth-child(3):before {
+  bottom: -50%;
+  left: -50%;
+}
+.l-clipper__edge:nth-child(4) {
+  right: -6rpx;
+  bottom: -6rpx;
+  border-top-width: 0 !important;
+  border-left-width: 0 !important;
+}
+.l-clipper__edge:nth-child(4):before {
+  bottom: -50%;
+  left: 50%;
+}
+.l-clipper-image {
+  width: 100%;
+  border-style: none;
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1;
+  -webkit-backface-visibility: hidden;
+  backface-visibility: hidden;
+  transform-origin: center;
+}
+.l-clipper-canvas {
+  position: fixed;
+  z-index: 10;
+  left: -200vw;
+  top: -200vw;
+  pointer-events: none;
+}
+.l-clipper-tools {
+  position: fixed;
+  left: 0;
+  bottom: 10px;
+  width: 100%;
+  z-index: 99;
+  color: #fff;
+}
+.l-clipper-tools__btns {
+  font-weight: bold;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  padding: 20rpx 40rpx;
+  box-sizing: border-box;
+}
+.l-clipper-tools__btns .cancel {
+  width: 112rpx;
+  height: 60rpx;
+  text-align: center;
+  line-height: 60rpx;
+}
+.l-clipper-tools__btns .confirm {
+  width: 112rpx;
+  height: 60rpx;
+  line-height: 60rpx;
+  background-color: #07c160;
+  border-radius: 6rpx;
+  text-align: center;
+}
+.l-clipper-tools__btns image {
+  display: block;
+  width: 60rpx;
+  height: 60rpx;
+}
+.l-clipper-tools__btns {
+  flex-direction: row;
+}

+ 816 - 0
components/limeClipper/limeClipper.vue

@@ -0,0 +1,816 @@
+<template>
+	<view class="l-clipper" :class="{open: value}" disable-scroll :style="'z-index: ' + zIndex + ';' + customStyle">
+		<view class="l-clipper-mask" @touchstart.stop.prevent="clipTouchStart" @touchmove.stop.prevent="clipTouchMove" @touchend.stop.prevent="clipTouchEnd">
+			<view class="l-clipper__content" :style="clipStyle"><view class="l-clipper__edge" v-for="(item, index) in [0, 0, 0, 0]" :key="index"></view></view>
+		</view>
+		<image
+			class="l-clipper-image"
+			@error="imageLoad"
+			@load="imageLoad"
+			@touchstart.stop.prevent="imageTouchStart"
+			@touchmove.stop.prevent="imageTouchMove"
+			@touchend.stop.prevent="imageTouchEnd"
+			:src="image"
+			:mode="imageWidth == 'auto' ? 'widthFix' : ''"
+			v-if="image"
+			:style="imageStyle"
+		/>
+		<canvas
+			:canvas-id="canvasId"
+			id="l-clipper"
+			disable-scroll
+			:style="'width: ' + canvasWidth * scaleRatio + 'px; height:' + canvasHeight * scaleRatio + 'px;'"
+			class="l-clipper-canvas"
+		></canvas>
+		<view class="l-clipper-tools">
+			<view class="l-clipper-tools__btns">
+				<view v-if="isShowCancelBtn" @tap="cancel">
+					<slot name="cancel" v-if="$slots.cancel" />
+					<view v-else class="cancel">取消</view>
+				</view>
+				<view v-if="isShowPhotoBtn" @tap="uploadImage">
+					<slot name="photo" v-if="$slots.photo" />
+					<image v-else src="@/static/limeClipper/photo.svg" />
+				</view>
+				<view v-if="isShowRotateBtn" @tap="rotate">
+					<slot name="rotate" v-if="$slots.rotate" />
+					<image v-else src="@/static/limeClipper/rotate.svg" data-type="inverse" />
+				</view>
+				<view v-if="isShowConfirmBtn" @tap="confirm">
+					<slot name="confirm" v-if="$slots.confirm" />
+					<view v-else class="confirm">确定</view>
+				</view>
+			</view>
+			<slot></slot>
+		</view>
+	</view>
+</template>
+
+<script>
+import { determineDirection, calcImageOffset, calcImageScale, calcImageSize, calcPythagoreanTheorem, clipTouchMoveOfCalculate, imageTouchMoveOfCalcOffset } from './utils';
+const cache = {}
+export default {
+	// version: '0.6.3',
+	name: 'l-clipper',
+	props: {
+		value: {
+			type: Boolean,
+			default: true
+		},
+		// #ifdef MP-WEIXIN
+		type: {
+			type: String,
+			default: '2d'
+		},
+		// #endif
+		customStyle: {
+			type: String,
+		},
+		canvasId: {
+			type: String,
+			default: 'l-clipper'
+		},
+		zIndex: {
+			type: Number,
+			default: 99
+		},
+		imageUrl: {
+			type: String
+		},
+		fileType: {
+			type: String,
+			default: 'png'
+		},
+		quality: {
+			type: Number,
+			default: 1
+		},
+		width: {
+			type: Number,
+			default: 400
+		},
+		height: {
+			type: Number,
+			default: 400
+		},
+		minWidth: {
+			type: Number,
+			default: 200
+		},
+		maxWidth: {
+			type: Number,
+			default: 600
+		},
+		minHeight: {
+			type: Number,
+			default: 200
+		},
+		maxHeight: {
+			type: Number,
+			default: 600
+		},
+		isLockWidth: {
+			type: Boolean,
+			default: false
+		},
+		isLockHeight: {
+			type: Boolean,
+			default: false
+		},
+		isLockRatio: {
+			type: Boolean,
+			default: true
+		},
+		scaleRatio: {
+			type: Number,
+			default: 1
+		},
+		minRatio: {
+			type: Number,
+			default: 0.5
+		},
+		maxRatio: {
+			type: Number,
+			default: 2
+		},
+		isDisableScale: {
+			type: Boolean,
+			default: false
+		},
+		isDisableRotate: {
+			type: Boolean,
+			default: false
+		},
+		isLimitMove: {
+			type: Boolean,
+			default: false
+		},
+		isShowPhotoBtn: {
+			type: Boolean,
+			default: true
+		},
+		isShowRotateBtn: {
+			type: Boolean,
+			default: true
+		},
+		isShowConfirmBtn: {
+			type: Boolean,
+			default: true
+		},
+		isShowCancelBtn: {
+			type: Boolean,
+			default: true
+		},
+		rotateAngle: {
+			type: Number,
+			default: 90
+		},
+		source: {
+			type: Object,
+			default: () => ({
+					album: '从相册中选择',
+					camera: '拍照',
+					// #ifdef MP-WEIXIN
+					message: '从微信中选择'
+					// #endif
+				})
+		}
+	},
+	data() {
+		return {
+			canvasWidth: 0,
+			canvasHeight: 0,
+			clipX: 0,
+			clipY: 0,
+			clipWidth: 0,
+			clipHeight: 0,
+			animation: false,
+			imageWidth: 0,
+			imageHeight: 0,
+			imageTop: 0,
+			imageLeft: 0,
+			scale: 1,
+			angle: 0,
+			image: this.imageUrl,
+			sysinfo: {},
+			throttleTimer: null,
+			throttleFlag: true,
+			timeClipCenter: null,
+			flagClipTouch: false,
+			flagEndTouch: false,
+			clipStart: {},
+			animationTimer: null,
+			touchRelative: [{x: 0,y: 0}],
+			hypotenuseLength: 0,
+			ctx: null
+		};
+	},
+	computed: {
+		clipStyle() {
+			const {clipWidth, clipHeight, clipY, clipX, animation} = this
+			return  `
+			width: ${clipWidth}px;
+			height:${clipHeight}px;
+			transition-property: ${animation ? '' : 'background'};
+			left: ${clipX}px;
+			top: ${clipY}px
+			`
+		},
+		imageStyle() {
+			const {imageWidth, imageHeight, imageLeft, imageTop, animation, scale, angle} = this
+			return `
+				width: ${imageWidth ? imageWidth + 'px' : 'auto'};
+				height: ${imageHeight ? imageHeight + 'px' : 'auto'};
+				transform: translate3d(${imageLeft - imageWidth / 2}px, ${imageTop - imageHeight / 2}px, 0) scale(${scale}) rotate(${angle}deg);
+				transition-duration: ${animation ? 0.35 : 0}s
+			`
+		},
+		clipSize() {
+			const { clipWidth, clipHeight } = this;
+			return { clipWidth, clipHeight };
+		},
+		clipPoint() {
+			const { clipY, clipX } = this;
+			return { clipY, clipX };
+		}
+	},
+	watch: {
+		value(val) {
+			if(!val) {
+				this.animation = 0
+				this.angle = 0
+			} else {
+				if(this.imageUrl) {
+					const {imageWidth, imageHeight, imageLeft, imageTop, scale, clipX, clipY, clipWidth, clipHeight, path} = cache?.[this.imageUrl] || {}
+					if(path != this.image) {
+						this.image = this.imageUrl;
+					} else {
+						this.setDiffData({imageWidth, imageHeight, imageLeft, imageTop, scale, clipX, clipY, clipWidth, clipHeight})
+					}
+					
+				}
+				
+			}
+		},
+		imageUrl(url) {
+			this.image = url
+		},
+		image:{
+			handler: async function(url) {
+				this.getImageInfo(url)
+			},
+			// immediate: true,
+		},
+		clipSize({ widthVal, heightVal }) {
+			let { minWidth, minHeight } = this;
+			minWidth = minWidth / 2;
+			minHeight = minHeight / 2;
+			if (widthVal < minWidth) {
+				this.setDiffData({clipWidth: minWidth})
+			}
+			if (heightVal < minHeight) {
+				this.setDiffData({clipHeight: minHeight})
+			}
+			this.calcClipSize();
+		},
+		angle(val) {
+			this.animation = true;
+			this.moveStop();
+			const { isLimitMove } = this;
+			if (isLimitMove && val % 90) {
+				this.setDiffData({
+					angle: Math.round(val / 90) * 90
+				})
+			}
+			this.imgMarginDetectionScale();
+		},
+		animation(val) {
+			clearTimeout(this.animationTimer);
+			if (val) {
+				let animationTimer = setTimeout(() => {
+					this.setDiffData({
+						animation: false
+					})
+				}, 260);
+				this.setDiffData({animationTimer})
+				this.animationTimer = animationTimer;
+			}
+		},
+		isLimitMove(val) {
+			if (val) {
+				if (this.angle % 90) {
+					this.setDiffData({
+						angle : Math.round(this.angle / 90) * 90
+					})
+				}
+				this.imgMarginDetectionScale();
+			}
+		},
+		clipPoint() {
+			this.cutDetectionPosition();
+		},
+		width(width, oWidth) {
+			if (width !== oWidth) {
+				this.setDiffData({
+					clipWidth:  width / 2
+				})
+			}
+		},
+		height(height, oHeight) {
+			if (height !== oHeight) {
+				this.setDiffData({
+					clipHeight:  height / 2
+				})
+			}
+		}
+	},
+	mounted() {
+		const sysinfo = uni.getSystemInfoSync();
+		this.sysinfo = sysinfo;
+		this.setClipInfo();
+		if(this.image) {
+			this.getImageInfo(this.image)
+		}
+		this.setClipCenter();
+		this.calcClipSize();
+		this.cutDetectionPosition();
+	},
+	methods: {
+		setDiffData(data) {
+			Object.keys(data).forEach(key => {
+			  if (this[key] !== data[key]) {
+				this[key] = data[key];
+			  }
+			});
+		},
+		getImageInfo(url) {
+			if (!url) return;
+			if(this.value) {
+				uni.showLoading({
+					title: '请稍候...',
+					mask: true
+				});
+			}
+			uni.getImageInfo({
+				src: url,
+				success: res => {
+					this.imgComputeSize(res.width, res.height);
+					this.image = res.path;
+					if (this.isLimitMove) {
+						this.imgMarginDetectionScale();
+						this.$emit('ready', res);
+					}
+					const {imageWidth, imageHeight, imageLeft, imageTop, scale, clipX, clipY, clipWidth, clipHeight} = this
+					cache[url] = Object.assign(res, {imageWidth, imageHeight, imageLeft, imageTop, scale, clipX, clipY, clipWidth, clipHeight});
+				},
+				fail: (err) => {
+					this.imgComputeSize();
+					if (this.isLimitMove) {
+						this.imgMarginDetectionScale();
+					}
+				}
+			});
+			
+		},
+		setClipInfo() {
+			const { width, height, sysinfo, canvasId } = this;
+			const clipWidth = width / 2;
+			const clipHeight = height / 2;
+			const clipY = (sysinfo.windowHeight - clipHeight) / 2;
+			const clipX = (sysinfo.windowWidth - clipWidth) / 2;
+			const imageLeft = sysinfo.windowWidth / 2;
+			const imageTop = sysinfo.windowHeight / 2;
+			this.ctx = uni.createCanvasContext(canvasId, this);
+			this.clipWidth = clipWidth;
+			this.clipHeight = clipHeight;
+			this.clipX = clipX;
+			this.clipY = clipY;
+			this.canvasHeight = clipHeight;
+			this.canvasWidth = clipWidth;
+			this.imageLeft = imageLeft;
+			this.imageTop = imageTop;
+		},
+		setClipCenter() {
+			const { sysInfo, clipHeight, clipWidth, imageTop, imageLeft } = this;
+			let sys = sysInfo || uni.getSystemInfoSync();
+			let clipY = (sys.windowHeight - clipHeight) * 0.5;
+			let clipX = (sys.windowWidth - clipWidth) * 0.5;
+			this.imageTop = imageTop - this.clipY + clipY;
+			this.imageLeft = imageLeft - this.clipX + clipX;
+			this.clipY = clipY;
+			this.clipX = clipX;
+		},
+		calcClipSize() {
+			const { clipHeight, clipWidth, sysinfo, clipX, clipY } = this;
+			if (clipWidth > sysinfo.windowWidth) {
+				this.setDiffData({
+					clipWidth:  sysinfo.windowWidth
+				})
+			} else if (clipWidth + clipX > sysinfo.windowWidth) {
+				this.setDiffData({
+					clipX: sysinfo.windowWidth - clipX
+				})
+			}
+			if (clipHeight > sysinfo.windowHeight) {
+				this.setDiffData({
+					clipHeight: sysinfo.windowHeight
+				})
+			} else if (clipHeight + clipY > sysinfo.windowHeight) {
+				this.clipY = sysinfo.windowHeight - clipY;
+				this.setDiffData({
+					clipY: sysinfo.windowHeight - clipY
+				})
+			}
+		},
+		cutDetectionPosition() {
+			const { clipX, clipY, sysinfo, clipHeight, clipWidth } = this;
+			let cutDetectionPositionTop = () => {
+					if (clipY < 0) {
+						this.setDiffData({clipY: 0})
+					}
+					if (clipY > sysinfo.windowHeight - clipHeight) {
+						this.setDiffData({clipY: sysinfo.windowHeight - clipHeight})
+					}
+				},
+				cutDetectionPositionLeft = () => {
+					if (clipX < 0) {
+						this.setDiffData({clipX: 0})
+					}
+					if (clipX > sysinfo.windowWidth - clipWidth) {
+						this.setDiffData({clipX: sysinfo.windowWidth - clipWidth})
+					}
+				};
+			if (clipY === null && clipX === null) {
+				let newClipY = (sysinfo.windowHeight - clipHeight) * 0.5;
+				let newClipX = (sysinfo.windowWidth - clipWidth) * 0.5;
+				this.setDiffData({
+					clipX: newClipX,
+					clipY: newClipY
+				})
+			} else if (clipY !== null && clipX !== null) {
+				cutDetectionPositionTop();
+				cutDetectionPositionLeft();
+			} else if (clipY !== null && clipX === null) {
+				cutDetectionPositionTop();
+				this.setDiffData({
+					clipX: (sysinfo.windowWidth - clipWidth) / 2
+				})
+			} else if (clipY === null && clipX !== null) {
+				cutDetectionPositionLeft();
+				this.setDiffData({
+					clipY: (sysinfo.windowHeight - clipHeight) / 2
+				})
+			}
+		},
+		imgComputeSize(width, height) {
+			const { imageWidth, imageHeight } = calcImageSize(width, height, this);
+			this.imageWidth = imageWidth;
+			this.imageHeight = imageHeight;
+		},
+		imgMarginDetectionScale(scale) {
+			if (!this.isLimitMove) return;
+			const currentScale = calcImageScale(this, scale);
+			this.imgMarginDetectionPosition(currentScale);
+		},
+		imgMarginDetectionPosition(scale) {
+			if (!this.isLimitMove) return;
+			const { scale: currentScale, left, top } = calcImageOffset(this, scale);
+			this.setDiffData({
+				imageLeft: left,
+				imageTop: top,
+				scale: currentScale
+			})
+		},
+		throttle() {
+			this.setDiffData({
+				throttleFlag: true
+			})
+		},
+		moveDuring() {
+			clearTimeout(this.timeClipCenter);
+		},
+		moveStop() {
+			clearTimeout(this.timeClipCenter);
+			const timeClipCenter = setTimeout(() => {
+				if (!this.animation) {
+					this.setDiffData({animation: true})
+				}
+				this.setClipCenter();
+			}, 800);
+			this.setDiffData({timeClipCenter})
+		},
+		clipTouchStart(event) {
+			// #ifdef H5
+			event.preventDefault()
+			// #endif
+			if (!this.image) {
+				uni.showToast({
+					title: '请选择图片',
+					icon: 'none'
+				});
+				return;
+			}
+			const currentX = event.touches[0].clientX;
+			const currentY = event.touches[0].clientY;
+			const { clipX, clipY, clipWidth, clipHeight } = this;
+			const corner = determineDirection(clipX, clipY, clipWidth, clipHeight, currentX, currentY);
+			this.moveDuring();
+			if(!corner) {return}
+			this.clipStart = {
+				width: clipWidth,
+				height: clipHeight,
+				x: currentX,
+				y: currentY,
+				clipY,
+				clipX,
+				corner
+			};
+			this.flagClipTouch = true;
+			this.flagEndTouch = true;
+		},
+		clipTouchMove(event) {
+			// #ifdef H5
+			event.stopPropagation()
+			event.preventDefault()
+			// #endif
+			if (!this.image) {
+				uni.showToast({
+					title: '请选择图片',
+					icon: 'none'
+				});
+				return;
+			}
+			// 只针对单指点击做处理
+			if (event.touches.length !== 1) {
+				return;
+				
+			}
+			const { flagClipTouch, throttleFlag } = this;
+			if (flagClipTouch && throttleFlag) {
+				const { isLockRatio, isLockHeight, isLockWidth } = this;
+				if (isLockRatio && (isLockWidth || isLockHeight)) return;
+				this.setDiffData({
+					throttleFlag: false
+				})
+				this.throttle();
+				const clipData = clipTouchMoveOfCalculate(this, event);
+				if(clipData) {
+					const { width, height, clipX, clipY } = clipData;
+					if (!isLockWidth && !isLockHeight) {
+						this.setDiffData({
+							clipWidth: width,
+							clipHeight: height,
+							clipX,
+							clipY
+						})
+					} else if (!isLockWidth) {
+						this.setDiffData({
+							clipWidth: width,
+							clipX
+						})
+					} else if (!isLockHeight) {
+						this.setDiffData({
+							clipHeight: height,
+							clipY
+						})
+					}
+					this.imgMarginDetectionScale();
+				}
+
+			}
+		},
+		clipTouchEnd() {
+			this.moveStop();
+			this.flagClipTouch = false;
+		},
+		imageTouchStart(e) {
+			// #ifdef H5
+			event.preventDefault()
+			// #endif
+			this.flagEndTouch = false;
+			const { imageLeft, imageTop } = this;
+			const clientXForLeft = e.touches[0].clientX;
+			const clientYForLeft = e.touches[0].clientY;
+
+			let touchRelative = [];
+			if (e.touches.length === 1) {
+				touchRelative[0] = {
+					x: clientXForLeft - imageLeft,
+					y: clientYForLeft - imageTop
+				};
+				this.touchRelative = touchRelative;
+			} else {
+				const clientXForRight = e.touches[1].clientX;
+				const clientYForRight = e.touches[1].clientY;
+				let width = Math.abs(clientXForLeft - clientXForRight);
+				let height = Math.abs(clientYForLeft - clientYForRight);
+				const hypotenuseLength = calcPythagoreanTheorem(width, height);
+
+				touchRelative = [
+					{
+						x: clientXForLeft - imageLeft,
+						y: clientYForLeft - imageTop
+					},
+					{
+						x: clientXForRight - imageLeft,
+						y: clientYForRight - imageTop
+					}
+				];
+				this.touchRelative = touchRelative;
+				this.hypotenuseLength = hypotenuseLength;
+			}
+		},
+		imageTouchMove(e) {
+			// #ifdef H5
+			event.preventDefault()
+			// #endif
+			const { flagEndTouch, throttleFlag } = this;
+			if (flagEndTouch || !throttleFlag) return;
+			const clientXForLeft = e.touches[0].clientX;
+			const clientYForLeft = e.touches[0].clientY;
+			this.setDiffData({throttleFlag: false})
+			this.throttle();
+			this.moveDuring();
+			if (e.touches.length === 1) {
+				const { left: imageLeft, top:  imageTop} = imageTouchMoveOfCalcOffset(this, clientXForLeft, clientYForLeft);
+				this.setDiffData({
+					imageLeft,
+					imageTop
+				})
+				this.imgMarginDetectionPosition();
+			} else {
+				const clientXForRight = e.touches[1].clientX;
+				const clientYForRight = e.touches[1].clientY;
+				let width = Math.abs(clientXForLeft - clientXForRight),
+					height = Math.abs(clientYForLeft - clientYForRight),
+					hypotenuse = calcPythagoreanTheorem(width, height),
+					scale = this.scale * (hypotenuse / this.hypotenuseLength);
+				if (this.isDisableScale) {
+
+					scale = 1;
+				} else {
+					scale = scale <= this.minRatio ? this.minRatio : scale;
+					scale = scale >= this.maxRatio ? this.maxRatio : scale;
+					this.$emit('change', {
+						width: this.imageWidth * scale,
+						height: this.imageHeight * scale
+					});
+				}
+
+				this.imgMarginDetectionScale(scale);
+				this.hypotenuseLength = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
+				this.scale = scale;
+			}
+		},
+		imageTouchEnd() {
+			this.setDiffData({
+				flagEndTouch: true
+			})
+			this.moveStop();
+		},
+		uploadImage() {
+			const itemList = Object.entries(this.source)
+			const sizeType = ['original', 'compressed']
+			const success = ({tempFilePaths:a, tempFiles: b}) => {
+				this.image = a ? a[0] : b[0].path
+			};
+			const _uploadImage = (type) => {
+				if(type !== 'message') {
+					uni.chooseImage({
+						count: 1,
+						sizeType,
+						sourceType: [type],
+						success
+					});
+				}
+				// #ifdef MP-WEIXIN
+				if(type == 'message') {
+					wx.chooseMessageFile({
+					  count: 1,
+					  type: 'image',
+					  success
+					})
+				}
+				// #endif
+			}
+			if(itemList.length > 1) {
+				uni.showActionSheet({
+					itemList: itemList.map(v => v[1]),
+					success: ({tapIndex: i}) => {
+						_uploadImage(itemList[i][0])
+					}
+				})
+			} else {
+				_uploadImage(itemList[0][0])
+			}
+		},
+		imageReset() {
+			const sys = this.sysinfo || uni.getSystemInfoSync();
+			this.scale = 1;
+			this.angle = 0;
+			this.imageTop = sys.windowHeight / 2;
+			this.imageLeft = sys.windowWidth / 2;
+		},
+		imageLoad(e) {
+			this.imageReset();
+			uni.hideLoading();
+			this.$emit('ready', e.detail);
+		},
+		rotate(event) {
+			if (this.isDisableRotate) return;
+			if (!this.image) {
+				uni.showToast({
+					title: '请选择图片',
+					icon: 'none'
+				});
+				return;
+			}
+			const { rotateAngle } = this;
+			const originAngle = this.angle
+			const type = event.currentTarget.dataset.type;
+			if (type === 'along') {
+				this.angle = originAngle + rotateAngle
+			} else {
+				this.angle = originAngle - rotateAngle
+			}
+			this.$emit('rotate', this.angle);
+		},
+		confirm() {
+			if (!this.image) {
+				uni.showToast({
+					title: '请选择图片',
+					icon: 'none'
+				});
+				return;
+			}
+			uni.showLoading({
+				title: '加载中'
+			});
+			const { canvasHeight, canvasWidth, clipHeight, clipWidth, ctx, scale, imageLeft, imageTop, clipX, clipY, angle, scaleRatio: dpr, image, quality, fileType, type: imageType, canvasId } = this;
+			const draw = () => {
+				const imageWidth = this.imageWidth * scale * dpr;
+				const imageHeight = this.imageHeight * scale * dpr;
+				const xpos = imageLeft - clipX;
+				const ypos = imageTop - clipY;
+				ctx.translate(xpos * dpr, ypos * dpr);
+				ctx.rotate((angle * Math.PI) / 180);
+				ctx.drawImage(image, -imageWidth / 2, -imageHeight / 2, imageWidth, imageHeight);
+				ctx.draw(false, () => {
+					const width = clipWidth * dpr
+					const height = clipHeight * dpr
+					let params = {
+						x: 0,
+						y: 0,
+						width,
+						height,
+						destWidth: width,
+						destHeight: height,
+						canvasId: canvasId,
+						fileType,
+						quality,
+						success: (res) => {
+							data.url = res.tempFilePath;
+							uni.hideLoading();
+							this.$emit('success', data);
+							this.$emit('input', false)
+						},
+						fail: (error) => {
+							console.error('error', error)
+							this.$emit('fail', error);
+							this.$emit('input', false)
+						}
+					};
+
+					let data = {
+						url: '',
+						width,
+						height
+					};
+					uni.canvasToTempFilePath(params, this)
+				});
+			};
+
+			if (canvasWidth !== clipWidth || canvasHeight !== clipHeight) {
+				this.canvasWidth = clipWidth;
+				this.canvasHeight = clipHeight;
+				ctx.draw();
+				this.$nextTick(() => {
+					setTimeout(() => {
+						draw();
+					}, 100);
+				})
+			} else {
+				draw();
+			}
+		},
+		cancel() {
+			this.$emit('cancel', false)
+			this.$emit('input', false)
+		},
+	}
+};
+</script>
+
+<style scoped>
+@import './index'
+</style>

+ 244 - 0
components/limeClipper/utils.js

@@ -0,0 +1,244 @@
+/**
+ * 判断手指触摸位置
+ */
+export function determineDirection(clipX, clipY, clipWidth, clipHeight, currentX, currentY) {
+	/*
+	 * (右下>>1 右上>>2 左上>>3 左下>>4)
+	 */
+	let corner;
+	/**
+	 * 思路:(利用直角坐标系)
+	 *  1.找出裁剪框中心点
+	 *  2.如点击坐标在上方点与左方点区域内,则点击为左上角
+	 *  3.如点击坐标在下方点与右方点区域内,则点击为右下角
+	 *  4.其他角同理
+	 */
+	const mainPoint = [clipX + clipWidth / 2, clipY + clipHeight / 2]; // 中心点
+	const currentPoint = [currentX, currentY]; // 触摸点
+
+	if (currentPoint[0] <= mainPoint[0] && currentPoint[1] <= mainPoint[1]) {
+		corner = 3; // 左上
+	} else if (currentPoint[0] >= mainPoint[0] && currentPoint[1] <= mainPoint[1]) {
+		corner = 2; // 右上
+	} else if (currentPoint[0] <= mainPoint[0] && currentPoint[1] >= mainPoint[1]) {
+		corner = 4; // 左下
+	} else if (currentPoint[0] >= mainPoint[0] && currentPoint[1] >= mainPoint[1]) {
+		corner = 1; // 右下
+	}
+
+	return corner;
+}
+
+/**
+ * 图片边缘检测检测时,计算图片偏移量
+ */
+export function calcImageOffset(data, scale) {
+	let left = data.imageLeft;
+	let top = data.imageTop;
+	scale = scale || data.scale;
+	
+	let imageWidth = data.imageWidth;
+	  let imageHeight = data.imageHeight;
+	  if ((data.angle / 90) % 2) {
+	    imageWidth = data.imageHeight;
+	    imageHeight = data.imageWidth;
+	  }
+	  const {
+	      clipX,
+	      clipWidth,
+	      clipY,
+	      clipHeight
+	    } = data;
+
+	// 当前图片宽度/高度
+	const currentImageSize = (size) => (size * scale) / 2;
+	const currentImageWidth = currentImageSize(imageWidth);
+	const currentImageHeight = currentImageSize(imageHeight);
+
+	left = clipX + currentImageWidth >= left ? left : clipX + currentImageWidth;
+	left = clipX + clipWidth - currentImageWidth <= left ? left : clipX + clipWidth - currentImageWidth;
+	top = clipY + currentImageHeight >= top ? top : clipY + currentImageHeight;
+	top = clipY + clipHeight - currentImageHeight <= top ? top : clipY + clipHeight - currentImageHeight;
+	return {
+		left,
+		top,
+		scale
+	};
+}
+
+/**
+ * 图片边缘检测时,计算图片缩放比例
+ */
+export function calcImageScale(data, scale) {
+	scale = scale || data.scale;
+	let {
+		imageWidth,
+		imageHeight,
+		clipWidth,
+		clipHeight,
+		angle
+	} = data
+	if ((angle / 90) % 2) {
+		imageWidth = imageHeight;
+		imageHeight = imageWidth;
+	}
+	if (imageWidth * scale < clipWidth) {
+		scale = clipWidth / imageWidth;
+	}
+	if (imageHeight * scale < clipHeight) {
+		scale = Math.max(scale, clipHeight / imageHeight);
+	}
+	return scale;
+}
+
+/**
+ * 计算图片尺寸
+ */
+export function calcImageSize(width, height, data) {
+	let imageWidth = width,
+		imageHeight = height;
+	let {
+		clipWidth,
+		clipHeight,
+		sysinfo,
+		width: originWidth,
+		height: originHeight
+	} = data
+	if (imageWidth && imageHeight) {
+		if (imageWidth / imageHeight > (clipWidth || originWidth) / (clipWidth || originHeight)) {
+			imageHeight = clipHeight || originHeight;
+			imageWidth = (width / height) * imageHeight;
+		} else {
+			imageWidth = clipWidth || originWidth;
+			imageHeight = (height / width) * imageWidth;
+		}
+	} else {
+		let sys = sysinfo || uni.getSystemInfoSync();
+		imageWidth = sys.windowWidth;
+		imageHeight = 0;
+	}
+	return {
+		imageWidth,
+		imageHeight
+	};
+}
+
+/**
+ * 勾股定理求斜边
+ */
+export function calcPythagoreanTheorem(width, height) {
+	return Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
+}
+
+/**
+ * 拖动裁剪框时计算
+ */
+export function clipTouchMoveOfCalculate(data, event) {
+	const clientX = event.touches[0].clientX;
+	const clientY = event.touches[0].clientY;
+
+	let {
+		clipWidth,
+		clipHeight,
+		clipY: oldClipY,
+		clipX: oldClipX,
+		clipStart,
+		isLockRatio,
+		maxWidth,
+		minWidth,
+		maxHeight,
+		minHeight
+	} = data;
+	maxWidth = maxWidth / 2;
+	minWidth = minWidth / 2;
+	minHeight = minHeight / 2;
+	maxHeight = maxHeight / 2;
+
+	let width = clipWidth,
+		height = clipHeight,
+		clipY = oldClipY,
+		clipX = oldClipX,
+		// 获取裁剪框实际宽度/高度
+		// 如果大于最大值则使用最大值
+		// 如果小于最小值则使用最小值
+		sizecorrect = () => {
+			width = width <= maxWidth ? (width >= minWidth ? width : minWidth) : maxWidth;
+			height = height <= maxHeight ? (height >= minHeight ? height : minHeight) : maxHeight;
+		},
+		sizeinspect = () => {
+			sizecorrect();
+			if ((width > maxWidth || width < minWidth || height > maxHeight || height < minHeight) && isLockRatio) {
+				return false;
+			} else {
+				return true;
+			}
+		};
+	//if (clipStart.corner) {
+	height = clipStart.height + (clipStart.corner > 1 && clipStart.corner < 4 ? 1 : -1) * (clipStart.y - clientY);
+	//}
+	switch (clipStart.corner) {
+		case 1:
+			width = clipStart.width - clipStart.x + clientX;
+			if (isLockRatio) {
+				height = width / (clipWidth / clipHeight);
+			}
+			if (!sizeinspect()) return;
+			break;
+		case 2:
+			width = clipStart.width - clipStart.x + clientX;
+			if (isLockRatio) {
+				height = width / (clipWidth / clipHeight);
+			}
+			if (!sizeinspect()) {
+				return;
+			} else {
+				clipY = clipStart.clipY - (height - clipStart.height);
+			}
+
+			break;
+		case 3:
+			width = clipStart.width + clipStart.x - clientX;
+			if (isLockRatio) {
+				height = width / (clipWidth / clipHeight);
+			}
+			if (!sizeinspect()) {
+				return;
+			} else {
+				clipY = clipStart.clipY - (height - clipStart.height);
+				clipX = clipStart.clipX - (width - clipStart.width);
+			}
+
+			break;
+		case 4:
+			width = clipStart.width + clipStart.x - clientX;
+			if (isLockRatio) {
+				height = width / (clipWidth / clipHeight);
+			}
+			if (!sizeinspect()) {
+				return;
+			} else {
+				clipX = clipStart.clipX - (width - clipStart.width);
+			}
+			break;
+		default:
+			break;
+	}
+	return {
+		width,
+		height,
+		clipX,
+		clipY
+	};
+}
+
+/**
+ * 单指拖动图片计算偏移
+ */
+export function imageTouchMoveOfCalcOffset(data, clientXForLeft, clientYForLeft) {
+	let left = clientXForLeft - data.touchRelative[0].x,
+		top = clientYForLeft - data.touchRelative[0].y;
+	return {
+		left,
+		top
+	};
+}

+ 26 - 0
config/.env.dev.js

@@ -0,0 +1,26 @@
+const UNI_APP = {  
+	ProjectName :"智泊e家",
+	//BASE_URL: 'http://36.134.122.108/railroad-server/',
+
+	
+	BASE_URL: 'https://youdian-test.hbjp.com.cn/floorlock-server/',
+	//##https://youdian-test.hbjp.com.cn/floorlock-portal/#/home
+	
+	//BASE_URL:"https://zbyj.hbjp.com.cn/floorlock-server/",
+	//BASE_URL: 'https://dgj.jzrccs.com/electric-manager-api/',
+	
+	//BASE_URL:'http://192.168.77.162:8081/electric-manager-api/', //sz
+	
+	NODE_ENV :"dev",
+	SIMPLE_RUN:true,// 无视权限控制跳转页面   , 用于样式人员快速访问各种功能 ,快速测试等
+
+
+	openId:"oRGjz7GpSbld27nUK9Q6V6jvXMJo",
+	
+	//appid
+	VUE_APP_WXAPPID:"wxa9f555dc92a1cbfc",
+	VUE_APP_ALIAPPID:"2021003131641247",
+	
+}  
+
+module.exports = UNI_APP;

+ 42 - 0
config/.env.js

@@ -0,0 +1,42 @@
+import {
+	getUrlParam,
+	getWeixinRedirectURI,
+	isWeiXin
+} from '@/apis/utils'
+(
+
+function() {  
+    const NODE_ENV = 'dev'; // dev:开发环境 | test:测试环境  
+    let ENV_VAR = null;  
+	 
+	var NODE_NAME=  process.env['NODE_NAME']
+	console.log(NODE_NAME)
+    if (process.env.NODE_ENV === "development") {  
+
+        if (NODE_ENV === 'dev') {  
+            ENV_VAR = require('./.env.dev.js');  
+        } else if (NODE_ENV === 'test') {  
+			ENV_VAR = require('./.env.test.js'); 
+        } else{
+			 ENV_VAR = require('./.env.dev.js');  
+		}
+		
+    } else if (process.env.NODE_ENV === "production") {  
+		if(NODE_NAME=="test"){
+			ENV_VAR = require('./.env.test.js'); 
+		}else if(NODE_NAME=="production"){
+			ENV_VAR = require('./.env.prod.js');
+		} else  {  
+			ENV_VAR = require('./.env.prod.js');  
+		} 
+      
+    }  
+	
+
+    if (ENV_VAR) {  
+		process.jphelp = {};  
+        for (let key in ENV_VAR) {  
+			process.jphelp[key] = ENV_VAR[key];			
+        }  
+    }  
+})();

+ 21 - 0
config/.env.prod.js

@@ -0,0 +1,21 @@
+const UNI_APP = {  	
+	ProjectName :"智泊e家",
+	//BASE_URL: 'http://36.134.122.108/railroad-server/',
+	BASE_URL: 'https://youdian-test.hbjp.com.cn/floorlock-server/',
+	BASE_URL:"https://zbyj.hbjp.com.cn/floorlock-server/",
+	//BASE_URL: 'https://dgj.jzrccs.com/electric-manager-api/',
+	
+	NODE_ENV :"prod",
+	SIMPLE_RUN:false,
+	openId:"oHjCawigqi8SEAwutwkQ-VEgdp3k",//测试用openId
+	//openId:"123456",
+	//appid
+	VUE_APP_WXAPPID:"wxa9f555dc92a1cbfc",
+
+	BACK_URL:"https://yjwg.hbjp.com.cn/index/#/master/",
+	
+
+	VUE_APP_ALIAPPID:"2021003131641247",
+}  
+
+module.exports = UNI_APP;

+ 24 - 0
config/.env.prodv4.js

@@ -0,0 +1,24 @@
+const UNI_APP = {  	
+	ProjectName :"壹家物管运管大厅",
+	//BASE_URL: 'http://36.134.122.108/railroad-server/',
+
+	//BASE_URL: 'https://dgj.jzrccs.com/electric-manager-api/',
+	BASE_URL: 'https://youdian-test.hbjp.com.cn/floorlock-server/',
+	
+	
+	NODE_ENV :"prodv4",
+	SIMPLE_RUN:false,
+	openId:"oHjCawigqi8SEAwutwkQ-VEgdp3k",//测试用openId
+	//openId:"123456",
+	openId:"oLowyuOJvTszgk96C0f8j0XfcEXg",//zkx
+	
+	//appid
+	VUE_APP_WXAPPID:"wx0b3c41a903053808",
+
+	BACK_URL:"https://yjwg.hbjp.com.cn/index/#/master/",
+	
+
+	VUE_APP_ALIAPPID:"2021003131641247",
+}  
+
+module.exports = UNI_APP;

+ 17 - 0
config/.env.test.js

@@ -0,0 +1,17 @@
+const UNI_APP = {  
+	ProjectName :"智泊e家",
+	//BASE_URL: 'http://36.134.122.108/railroad-server/',
+	BASE_URL: 'https://youdian-test.hbjp.com.cn/electric-manager-api/', //test
+	BASE_URL: 'https://dgj.hbjp.com.cn/electric-manager-api/',
+	NODE_ENV :"test",
+	SIMPLE_RUN:false,
+	BACK_URL:"https://xpgj.hbjp.com.cn/prod/jp-property-platform-test/index/#/master/",
+	
+	//appid
+	VUE_APP_WXAPPID:"wx0b3c41a903053808",
+	VUE_APP_ALIAPPID:"2021003131641247",
+	
+	
+}  
+
+module.exports = UNI_APP;

+ 20 - 0
index.html

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

+ 117 - 0
main.js

@@ -0,0 +1,117 @@
+import App from './App'
+import Vue from 'vue'
+import getOpenId from './apis/utils/init.js'
+import getALIOpenId from './apis/utils/initALI.js'
+//import './assets/font/font/font.css'
+var IS_WEIXIN = /MicroMessenger/.test(window.navigator.userAgent)
+var IS_ALI = /AlipayClient/.test(window.navigator.userAgent)
+
+if (IS_ALI) {
+
+	getALIOpenId.init()
+} else {
+	getOpenId.init()
+}
+
+import mixin from './apis/utils/mixin.js'
+ 
+Vue.prototype.jphelp = mixin
+ window.wx = {}
+ import Vconsole from 'vconsole'
+//import uView from "uview-ui";
+import uView from '@/uni_modules/uview-ui'
+import router from '@/components/bobo-router'
+
+Vue.use(uView);
+
+
+Vue.mixin({
+	
+	updated: function() {
+		
+	},
+	onReady() {
+
+
+	},
+	onLoad(option) {
+		if (option.test == 'test') {
+			let vConsole = new Vconsole()
+		}
+		
+		var ProjectName=process.jphelp.ProjectName;
+		if(process.jphelp.NODE_ENV=='dev'||process.jphelp.NODE_ENV=='test'){
+			  ProjectName+='('+process.jphelp.NODE_ENV+')';				 
+		}
+		
+		uni.setNavigationBarTitle({
+		   		title:ProjectName
+		}) 
+		
+		
+		this.personInfo=this.jphelp.getPersonInfo();
+		
+
+	},
+	methods: {
+		loginset(response){
+			
+			var token = response ? response.data.token : '';
+			this.jphelp.setToken(token);
+			this.jphelp.setPersonInfo(response.data.user);
+			this.jphelp.setPersonInfoPlus(response.data)
+			
+			//this.gotoUrl("pages/user/index")
+			
+		},
+		jpAmount(amount){
+			if(amount){
+				return amount.toFixed(2)
+			}else{
+				return "0.00"
+			}
+		},
+		substrDate(date){
+			if(date){
+				return date.substr(0,11)
+			}
+			return ''
+		},
+		
+		gotoUrl(url) {
+			
+			var mod =  {}
+			mod.clickUrl = url
+			
+			 if (mod.clickUrl == null) {
+			
+			} else if (mod.clickUrl.indexOf('http') == 0) {
+			
+				window.location = mod.clickUrl  ;
+			}  else if (mod.clickUrl.indexOf('#/') == 0) {
+				if (mod.clickUrl.indexOf("?") == -1) {
+					mod.clickUrl += '?';
+				}
+				var url = mod.clickUrl.split("#")[1]
+				//window.location = mod.clickUrl;
+				uni.navigateTo({
+					url: url 
+				})
+			} else if (mod.clickUrl == '#' || mod.clickUrl == '') {
+			
+			} else {
+				uni.navigateTo({
+					url: mod.clickUrl 
+				})
+			}
+		}
+	}
+})
+
+
+Vue.config.productionTip = false
+App.mpType = 'app'
+const app = new Vue({
+	...App
+})
+app.$mount()

+ 92 - 0
manifest.json

@@ -0,0 +1,92 @@
+{
+    "name" : "jp-housekeep-electric",
+    "appid" : "__UNI__EE89CB4",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueStyleCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {
+            "Share" : {}
+        },
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {
+                "share" : {
+                    "weixin" : {
+                        "appid" : "wx1052afafacae1c63",
+                        "UniversalLinks" : ""
+                    }
+                }
+            }
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "",
+        "setting" : {
+            "urlCheck" : false
+        },
+        "usingComponents" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    },
+    "vueVersion" : "2",
+    "h5" : {
+        "devServer" : {
+            "port" : 8080,
+            "https" : false,
+            "disableHostCheck" : true
+        },
+        "router" : {
+            "base" : "./"
+        },
+        "title" : "加载中..."
+    }
+}

+ 55 - 0
package.json

@@ -0,0 +1,55 @@
+{
+	"dependencies": {
+		"compression-webpack-plugin": "^8.0.1",
+		"echarts": "^5.3.2",
+
+		"npm": "^10.4.0",
+		"qrcodejs2": "0.0.2",
+
+		"vconsole": "^3.4.0",
+		"vue-cli": "^2.9.6",
+		"vue-cropper": "^0.5.6",
+		"vuex": "^3.6.2",
+		"weixin-js-sdk": "^1.6.0"
+	},
+	"devDependencies": {
+		"@vue/cli-plugin-babel": "^4.0.0",
+		"@vue/cli-plugin-eslint": "^4.0.0",
+		"@vue/cli-service": "^4.0.0",
+		"babel-eslint": "^10.0.3",
+		"eslint": "^5.16.0",
+		"eslint-plugin-vue": "^5.0.0",
+		"sass": "^1.85",
+		"sass-loader": "^11.0.1",
+		"uni-crazy-router": "0.0.31",
+		"vue-template-compiler": "^2.6.10"
+	},
+	"uni-app": {
+		"scripts": {
+			"test-platform": {
+				"title": "test",
+				"BROWSER": "Chrome",
+				"env": {
+					"UNI_PLATFORM": "h5",
+					"NODE_NAME": "test"
+				},
+				"define": {
+					"CUSTOM-CONST": true,
+					"NODE_NAME_T": "test"
+				}
+			},
+			"production-platform": {
+				"title": "production",
+				"BROWSER": "Chrome",
+				"env": {
+					"UNI_PLATFORM": "h5",
+					"NODE_NAME": "production"
+				},
+				"define": {
+					"CUSTOM-CONST": true,
+					"NODE_NAME_T": "production"
+				}
+			}
+		}
+	}
+}

+ 210 - 0
pages.json

@@ -0,0 +1,210 @@
+{
+
+	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTitleText": ""
+			}
+		},
+
+		{
+			"path": "pages/login/login",
+			"style": {
+				"navigationBarTitleText": "",
+				"enablePullDownRefresh": false
+			}
+		},
+		{
+			"path" : "pages/deviceTab/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/userTab/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/index",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/login/findBackPassword",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/deviceTab/deviceList",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/deviceTab/bindLock",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/deviceTab/bindLockStatus",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/deviceTab/infoLock",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/deviceTab/dataLock",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/userTab/dataUser",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/myMessage",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/abnormalList",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/abnormalInfo",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/feedbackList",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/feedbackSubmit",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/customerService",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/changePassword",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/changePhone",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/dataUser",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/setting",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/myTab/cropImage",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/record/parkingRecord",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/record/parkingInfo",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		}
+
+
+		
+
+	],
+
+
+
+"tabBar": {
+		
+		"list": [{
+			"pagePath": "pages/index/index"
+			
+		}, {
+			"pagePath": "pages/deviceTab/index"
+			
+		},{
+			"pagePath": "pages/userTab/index"
+			
+		}, {
+			"pagePath": "pages/myTab/index"
+			
+		}]
+	},
+
+	"globalStyle": {
+		"navigationStyle": "custom", // 隐藏系统导航栏
+		"navigationBarTitleText": "智泊e家",
+		"enablePullDownRefresh": false
+	},
+	"uniIdRouter": {}
+}

+ 439 - 0
pages/deviceTab/bindLock.vue

@@ -0,0 +1,439 @@
+<template>
+	
+	<view class="jpmain  ">
+		<u-navbar  title="绑定地锁"  ></u-navbar>
+		<u-picker mode="selector"
+		 v-model="isswitchshow" 
+		 :range="columns" range-key="label"
+		  :default-selector="columnsindex"
+		   @confirm="switchBtn" ></u-picker>
+		
+	
+			<view class="list" @click="gotoscan">
+				<view class="item">
+					<view class="name">
+						<span>*</span>地锁编号
+
+					</view>
+					<view class="value">
+						<view>{{bindInfo.lockNo?bindInfo.lockNo:'请扫码识别地锁'}}</view>
+						<view><img class="img" src="@/assets/img/deviceTab/index2-3.svg" alt=""></view>
+					</view>
+				</view>
+			</view>
+
+			<view class="list">
+				<view class="item">
+					<view class="name">
+						<span>*</span>用户名
+
+					</view>
+					<view class="value">
+						<input v-model="bindInfo.name" placeholder="请填写用户真实姓名" />
+					</view>
+				</view>
+				<view class="item">
+					<view class="name">
+						<span>*</span>联系电话
+
+					</view>
+					<view class="value">
+						<input v-model="bindInfo.phone" placeholder="请填写用户联系电话" />
+					</view>
+				</view>
+			</view>
+
+			<view class="list">
+				<!-- <view class="item" >
+					<view class="name">
+						所属停车场
+
+					</view>
+					<view class="value" @click="isswitchshowBtn">
+						<view>{{bindInfo.parkingIdN?bindInfo.parkingIdN:'请选择所属停车场'}}</view>
+						<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+					</view>
+				</view> -->
+				<view class="item" v-if="bindInfo.lockNo">
+					<view class="name">
+						车位类型
+
+
+					</view>
+					<view class="value">
+						<view>{{bindInfo.typeN}}</view>
+						<!-- <u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon> -->
+					</view>
+				</view>
+				<view class="item">
+					<view class="name">
+						<span>*</span>车位编号
+
+
+					</view>
+					<view class="value">
+						<input placeholder="如1号车位" v-model="bindInfo.parkingNumber" />
+					</view>
+				</view>
+				<view class="item">
+					<view class="name">
+						位置描述
+
+					</view>
+					<view class="value">
+						<input placeholder="请描述车位位置信息" />
+					</view>
+				</view>
+			<view class="floating-button">
+				<view class="button"  @click="submit" >
+					
+					提交绑定
+				</view>
+				
+			</view>
+
+		</view>
+	</view>
+</template>
+
+<script>
+
+	import * as API from '@/apis/pagejs/deviceTab.js'
+	
+	import * as WxJsApi from '@/apis/utils/wxJsApi.js'
+	export default {
+		data() {
+			return {
+				current: 0,
+				
+				columnsindex:[0],
+				bindInfo:{
+					name:"",
+					phone:"",
+					lockNo:"",
+					type:"",
+					remark:""
+				},
+				isswitchshow:false,
+				allList:[],
+				numList: [{
+					name: '绑定地锁'
+				}, {
+					name: '等待审核'
+				}, {
+					name: '完成绑定'
+				}],
+			};
+		},
+		onLoad(op) {
+			this.bindInfo.parkingId=op.parkingId
+			this.userInfo = this.jphelp.getPersonInfo()
+			this.bindInfo.phone=this.userInfo.phone
+		},
+		onReady() {
+				WxJsApi.getWxConfig([ 'scanQRCode']).then((res) => {
+					// //(res)
+				}).catch(error => {
+					//(res)
+				})
+		},
+		computed:{
+			columns(){
+				var sz=[]
+				for(var i in this.allList){
+					var obj=this.allList[i]
+					
+					
+					sz.push({
+						value:obj.id,
+						label:obj.name
+					})
+				}
+				
+				return sz
+			}
+		},
+		methods:{
+			switchBtn(e){
+				this.columnsindex=[e[0]]
+				var obj=this.columns[e[0]]
+				this.bindInfo.parkingId=obj.value
+				this.bindInfo.parkingIdN=obj.label
+			},
+			isswitchshowBtn(){
+				if(this.allList.length){
+					this.isswitchshow=true
+				}else{
+					this.getParkingList()
+				}
+				
+			},
+			getParkingList() {
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				var obj = {
+					pageIndex: 1,
+					pageSize: 900,
+					type:"bindLock"
+					
+				}
+				
+				API.parkingList(obj).then((res) => {
+			
+					this.allList = res.data.data
+					this.isswitchshow=true
+					uni.hideLoading();
+			
+				}).catch(error => {
+			
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+			
+				})
+			},
+			submit(){
+				
+				if(!this.bindInfo.lockNo){
+					uni.showToast({
+						title: "请扫码识别地锁",
+						icon: "none"
+					})
+					return
+				}
+				
+				if(!this.bindInfo.name){
+					uni.showToast({
+						title: "请填写用户真实姓名",
+						icon: "none"
+					})
+					return
+				}
+				if(!this.bindInfo.phone){
+					uni.showToast({
+						title: "请填写用户联系电话",
+						icon: "none"
+					})
+					return
+				}
+			
+				
+				
+				if(!this.bindInfo.parkingNumber){
+					uni.showToast({
+						title: "请填写车位编号",
+						icon: "none"
+					})
+					return
+				}
+				
+				
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				API.add( this.bindInfo ).then((res) => {
+				
+					
+					uni.hideLoading();
+					uni.showModal({
+						title: '提示',
+						showCancel: false,
+						content: "操作成功",
+						success: res1 => {
+							if (res1.confirm) {
+								uni.navigateBack()
+							} else if (res1.cancel) {
+								//('用户点击取消');
+							}
+						}
+					})
+					const eventChannel = this.getOpenerEventChannel();
+					
+					eventChannel.emit('acceptDataFromOpenerPage', { data: 'data from starter page' })
+							 
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			},
+			gotoscanMP(){
+				// 允许从相机和相册扫码
+				var _this=this
+				uni.scanCode({
+					success: function (res) {
+						console.log('条码类型:' + res.scanType);
+						console.log('条码内容:' + res.result);
+						_this.getscan(res.result)
+					}
+				});
+			},
+			gotoscan() {
+				
+				// // #ifdef H5
+				// 
+				// // #endif
+				
+				// // #ifdef MP-WEIXIN
+					
+				// 		this.gotoscanMP()
+				// // #endif
+				if (process.env.NODE_ENV === "development"){
+						this.gotoscanH5()
+				}else{
+					WxJsApi.scanQRCode(1).then(res => {
+						var url=res;
+						this.getscan(url)
+					}).catch(error => {
+					
+					})
+				}
+				
+					
+			},
+			getscan(val) {
+			 	
+			 	
+			 	uni.showLoading({
+			 		title: "加载中",
+			 		mask: true,
+			 	})
+			 	API.bindStatusByNo({
+			 		lockNo: val,
+			 
+			 	}).then((res) => {
+			 		uni.hideLoading();
+			 		if (res.data.openBind||1) {
+			 			
+			 			var nowscan=res.data.floorlockInfoList;
+						if(nowscan&&nowscan.length){
+							this.bindInfo.lockNo=nowscan[0].lockNo
+							this.bindInfo.type=nowscan[0].type
+							this.bindInfo.typeN=nowscan[0].typeN
+						}
+						
+			 			uni.showToast({
+			 				title: "扫码成功",
+			 				icon: "none"
+			 			})
+			 
+			 
+			 		} else {
+			 			uni.showToast({
+			 				title: "当前地锁不可绑定",
+			 				icon: "none"
+			 			})
+						
+			 		}
+			 
+			 	}).catch(error => {
+			 		uni.showToast({
+			 			title: error,
+			 			icon: "none"
+			 		})
+			 	})
+			 },
+			gotoscanH5() {
+				console.log('111')
+				
+				var _this = this;
+				uni.showModal({
+					title: '提示',
+					editable: true,
+					//content: '这是一个模态弹窗',
+					success: function(res) {
+						if (res.confirm) {
+							_this.getscan(res.content)
+						} else if (res.cancel) {
+							console.log('用户点击取消');
+						}
+					}
+				});
+			
+			
+			},
+		}
+	}
+</script>
+<style>
+	page {
+		background-color: rgba(242, 244, 246, 1);
+	}
+</style>
+<style lang="scss" scoped>
+	 
+
+	.body {
+		padding: 32rpx;
+	}
+	.list{
+		background-color: rgba(255,255,255,1);
+		
+		margin: 20rpx 0;
+		.item:not(:last-child) {
+		  border-bottom:1px solid rgba(232,232,232,1);
+		}
+		.item{
+			padding: 32rpx;
+			display: flex;
+			    justify-content: space-between;
+			.name{
+				    width: 40%;
+					font-size: 32rpx;
+					color: #777777;
+					span{
+						color:red
+					}
+					white-space: pre;
+			}
+			.value{
+				font-size: 32rpx;
+				    width: 60%;
+				display: flex;
+				    justify-content: space-between;
+					input::placeholder{
+						color:#AAAAAA;
+					}
+					.img{
+						width: 40rpx;
+						height: 40rpx;
+						
+					}
+			}
+		}
+	}
+	.uni-input-placeholder{
+		color:#AAAAAA;
+	}
+	
+	.floating-button {
+		position: fixed; 
+		  bottom: 0;    /* 距离底部 20px */
+		    width: 100%;
+			 display: flex;
+			  height: 120rpx;
+			    justify-content: center;
+			background-color: rgba(255,255,255,1);
+			.button{
+				margin-top: 24rpx;
+				border-radius: 50px;
+			 height: 80rpx;
+				width: 80%;
+				display: flex;
+				    align-items: center;
+				    justify-content: center;
+					padding:12rpx;
+					
+					background-color: rgba(22,119,255,1);
+					color: rgba(255,255,255,1);
+					font-size: 36rpx;
+			}
+	}
+	
+</style>

+ 123 - 0
pages/deviceTab/bindLockStatus.vue

@@ -0,0 +1,123 @@
+<template>
+	<view class="jpmain  ">
+		<view class="body">
+			<u-steps :list="numList" mode="number" :current="current" un-active-color="#999999"></u-steps>
+		</view>
+		<view class="data">
+<!-- 			<u-icon name="clock-fill" color="#1677FF" size="128"></u-icon>-->
+			<u-icon name="checkmark-circle-fill" color="#00B962" size="128"></u-icon>
+			<view class="t1">等待审核中</view>
+			<view class="t2">绑定申请已提交,等待后台审核完成建站</view>
+		</view>
+		<view class="floating-button" @click="goBack()">
+			<view class="button button2">
+				返回
+			</view>
+
+		</view>
+
+	</view>
+	</view>
+</template>
+
+<script >
+	import * as API from '@/apis/pagejs/index.js'
+	
+	export default {
+		data() {
+			return {
+				bindInfo:{},
+				current: 1,
+				numList: [{
+					name: '绑定地锁'
+				}, {
+					name: '等待审核'
+				}, {
+					name: '完成绑定'
+				}],
+			};
+		},
+		onLoad(op) {
+			this.id=op.id
+			this.getInfo()
+		},
+		methods:{
+			goBack(){
+				uni.navigateBack()
+			},
+			getInfo(){
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				API.details( {
+					id:this.id
+				} ).then((res) => {
+					this.bindInfo=res.data.applicationRecord;
+					if(this.bindInfo.status==0){
+						this.current= 1
+					}
+					if(this.bindInfo.status==1){
+						this.current= 2
+					}
+					uni.hideLoading();
+					
+							 
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	
+	.body {
+		padding: 32rpx;
+		background-color: rgba(242, 244, 246, 1);
+	}
+	.data{
+		text-align: center;
+		padding-top:120rpx;
+		.t1{
+			color: #101010;
+			font-weight: bold;
+			margin-top: 40rpx;
+			font-size: 40rpx;
+
+		}
+		.t2{
+			margin-top: 8rpx;
+			color: rgba(119,119,119,1);
+			font-size: 24rpx;
+		}
+	}
+
+
+	.floating-button {
+		padding-top:120rpx;
+	text-align: center;
+		.button {
+			    margin: 0 auto;
+			
+			border-radius: 50px;
+			height: 80rpx;
+			width: 80%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			padding: 12rpx;
+
+			background-color: rgba(22, 119, 255, 1);
+			color: rgba(255, 255, 255, 1);
+			font-size: 36rpx;
+		}
+		.button2{
+			background-color:  #00B962
+		}
+	}
+</style>

+ 1799 - 0
pages/deviceTab/dataLock.vue

@@ -0,0 +1,1799 @@
+<template>
+	<view>
+		<u-navbar :title="title" :backIconColor="'#ffffff'" title-color="#ffffff"
+			:background="backgroundObj"></u-navbar>
+		<view class="gradient-header">
+			<view class="jpback">
+
+			</view>
+		</view>
+		<u-picker title="日期选择" :maskCloseAble="true" v-model="body0data.tabsFrom.show" :defaultTime="body0data.tabsFrom.showIndex+'-1'" 
+			mode="time" :params="body0data.tabsFrom.params"  @confirm="selector2confirm" @cancel="selector2cancel"
+			>
+		</u-picker>
+		
+		<view class="main">
+			<view class="statistics ">
+				<view class="data1">
+					<view class="item">
+						<view class="line">
+							<view class="name">
+								{{info.name}}
+							</view>
+							<view class="item-tags">
+								<view class="tag tag1" :class="'typeN typeN'+info.type">
+									{{info.typeN}}
+							
+								</view>
+								<!-- <view class="tag" :class="'statusN statusN'+info.status">
+									{{info.statusN}}
+							
+								</view>
+								<view class="tag" :class="'lockStatusN lockStatusN'+info.lockStatus">
+									{{info.lockStatusN}}
+								</view> -->
+							</view>
+						</view>
+						<view class="line">
+							编号:{{info.lockNo}}
+						</view>
+						<view class="line" style="    color: #909399;">
+							更新时间:{{info.lastOnlineTime}}
+						</view>
+					</view>
+					<view class="value" v-if="0">
+						<u-button type="primary" size="mini" shape="circle">
+							<img class="img" src="@/assets/img/button/lock.svg" alt="">
+							降锁
+						</u-button>
+					</view>
+				</view>
+				
+				<view class="top-span">
+					<view class="item-span">
+						<img src="@/assets/img/topspan/span1.png">
+						<span>车位</span>
+						<span v-if="info.parkingStatus==1" style="color: #1677FF;" >有车</span>
+						<span v-else-if="info.parkingStatus==0" style="color: #00B962;" >无车</span>
+					</view>
+					<view class="item-span">
+						<img src="@/assets/img/topspan/span2.png">
+						<span>地锁</span>
+						<span  style="color: red;"
+						v-if="info.lockStatus==4||info.lockStatus==0">
+						错误</span>
+						<span v-else-if="info.lockStatus==1" style="color: #1677FF;"  >升起</span>
+						<span v-else-if="info.lockStatus==2" style="color: #00B962;"  >降落</span>
+						<span v-else   >其他</span>
+						
+					</view>
+					
+					<view class="item-span">
+						<img src="@/assets/img/topspan/span3.png">
+						<span>电压</span>
+						<span v-if="info.batteryLevel">{{info.batteryLevel}}V</span>
+						<span v-else>未知</span>
+					</view>
+					<view class="item-span">
+						<img src="@/assets/img/topspan/span4.png">
+						<span>网络</span>
+						
+						<span v-if="info.status==1" style="color: #00B962;" >在线</span>
+						<span v-else-if="info.status==0" style="color: red" >离线</span>
+						
+						
+					</view>
+					
+					<view class="item-span">
+						<img src="@/assets/img/topspan/span5.png">
+						<span>雷达</span>
+						
+						
+						<span v-if="info.radarStatus==0" style="color: #00B962;" >正常</span>
+						<span v-else-if="info.radarStatus==1" style="color: red" >故障</span>
+						
+						
+					</view>
+				</view>
+			</view>
+			<view class=" no_statistics">
+				<view class="data2">
+					<view class="top">
+						<view class="item">
+							<view class="name">
+								停车时长
+							</view>
+							<view class="value">
+								{{durationShow()}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="name">
+								使用率
+							</view>
+							<view class="value" v-if="lockUsageRateData&&lockUsageRateData.usageRate">
+								{{lockUsageRateData.usageRate=='∞'?'/':lockUsageRateData.usageRate+'%'}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="name">
+								异常次数
+							</view>
+							<view class="value">
+								0
+							</view>
+						</view>
+					</view>
+					<view class="body">
+						<u-radio-group v-model="radiovalue" @change="radioGroupChange">
+							<u-radio @change="radioChange" v-for="(item, index) in radiolist" :key="index"
+								:name="item.value">
+								{{item.name}}
+							</u-radio>
+						</u-radio-group>
+					</view>
+				</view>
+			</view>
+			
+			<u-picker v-model="body2data.vue.show" :params="body2data.vue.params" :default-time="body2data.query.startTime"
+				@confirm="body2dataconfirm" mode="time"></u-picker>
+			
+			
+			<view class="statistics ">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>车位平均占用率(%)</view>
+						<view class="tag" @click="body2data.vue.show=true">{{body2data.vue.queryN}}<u-icon
+								name="arrow-down"></u-icon></view>
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body2">
+						<view class="body2lineChart">
+
+							<view id="body2line1" class="body2line">
+
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics " v-if="0">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>地锁历史异常状态</view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body1">
+						<view class="body1pieChart">
+
+							<view id="body1pie1" class="body1pie">
+
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics ">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>高频使用时段分布</view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body3">
+						<view class="body3barChart">
+
+							<view id="body3bar1" class="body3bar">
+
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics ">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>用户停留时长分群特征</view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body4">
+						<view class="body4pieChart">
+
+							<view id="body4pie1" class="body4pie">
+
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics " v-if="0">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>高频使用用户TOP</view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body5">
+						<view class="body5data">
+							<view class="line">
+								<view class="data">
+									<view class="item">
+										王二
+									</view>
+									<view class="value">
+										鄂DDT1268
+
+									</view>
+									<view class="value">
+										28次
+
+									</view>
+								</view>
+								<view class="goto">
+									<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+								</view>
+							</view>
+							<view class="line">
+								<view class="data">
+									<view class="item">
+										王三
+									</view>
+									<view class="value">
+										鄂DDT1268
+
+									</view>
+									<view class="value">
+										8次
+
+									</view>
+								</view>
+								<view class="goto">
+									<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+								</view>
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+			<!-- end-->
+
+			<view class="statistics " v-if="0">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>白名单用户清单</view>
+						<view class="check-all">查看全部<u-icon name="arrow-right"></u-icon></view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body7">
+						<view class="body7data">
+							<view class="line">
+
+								<view class="value">
+									用户姓名
+								</view>
+								<view class="value">
+									车主身份
+
+								</view>
+								<view class="value">
+									使用次数
+
+								</view>
+
+							</view>
+							<view class="line">
+
+								<view class="value">
+									孙培军
+								</view>
+								<view class="value">
+									车位所有人
+
+								</view>
+								<view class="value">
+									22
+
+								</view>
+
+							</view>
+							<view class="line">
+
+								<view class="value">
+									刘洋
+								</view>
+								<view class="value">
+									白名单用户
+
+								</view>
+								<view class="value">
+									11
+
+								</view>
+
+							</view>
+
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+			<!-- end-->
+			<view class="statistics " v-if="0" >
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>车位异常记录</view>
+
+						<view class="check-all">查看全部<u-icon name="arrow-right"></u-icon></view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody" >
+					<jpContent :status="jpContentMap.body6">
+						<view class="body6main">
+							<view class="line" v-for="(item,index) in abnormalRecordsList" :key="index">
+								<view class="abnormal-item">
+									<!-- @click="gotoUrl('/pages/abnormal/abnormalAlarmDetails?id='+item.id)"
+								 -->
+									<view class="item-title">
+
+										<view class="name">
+											<span v-if="item.level==1" class="level level1 ">一级</span>
+											<span v-if="item.level==2" class="level level2">二级</span>
+
+											{{item.content}}
+										</view>
+										<view class="date"
+											style="display: flex;    justify-content: space-between;margin-top: 4rpx;">
+											<view>{{item.title}}</view>
+											<view>{{item.createTime}}</view>
+
+										</view>
+									</view>
+
+								</view>
+								<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+			<!-- end-->
+			
+			<view class="body8data-popup">
+			<u-popup v-model="body8data.popup" mode="bottom" height="80%"  border-radius="12">
+				<view class="content">
+					<view class="headline">
+						地锁信息
+					</view>
+					<view class="infos">
+						<view class="item">
+							<view class="item-title">
+								地锁名称
+							</view>
+							<view class="item-value">
+								{{info.name}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								地锁管理者
+							</view>
+							<view class="item-value">
+								{{info.administrator}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								车位类型
+							</view>
+							<view class="item-value">
+								{{info.typeN}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								地锁状态
+							</view>
+							<view class="item-value">
+								{{info.lockStatusN}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								地锁型号
+							</view>
+							<view class="item-value">
+								{{info.model}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								出厂编号
+							</view>
+							<view class="item-value">
+								<span>{{info.factoryNumber}}</span>
+								
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								固件版号
+							</view>
+							<view class="item-value">
+								{{info.solidVersion}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								防护等级
+							</view>
+							<view class="item-value">
+								{{info.protectionGrade}}
+							</view>
+						</view>
+						
+						<view class="item">
+							<view class="item-title">
+								生产日期
+							</view>
+							<view class="item-value">
+								{{info.manufactureDate}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								标准依据
+							</view>
+							<view class="item-value">
+								{{info.enablingTime}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								联网卡号
+							</view>
+							<view class="item-value">
+								{{info.standardBasis}}
+							</view>
+						</view>
+						<view class="item" v-if="info.tariffStandard">
+							<view class="item-title">
+								资费标准
+							</view>
+							<view class="item-value">
+								{{info.tariffStandard}}元/月
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								地锁启动时间
+							</view>
+							<view class="item-value">
+								{{info.activationTime}}
+							</view>
+						</view>
+						<view class="item">
+							<view class="item-title">
+								地锁质保期
+							</view>
+							<view class="item-value">
+								{{info.shelfLife}}年
+							</view>
+						</view>
+						
+						
+					
+					</view>
+					<button class="get" @click="body8data.popup=false">知道了</button>
+				</view>
+			</u-popup>
+			</view>
+			<view class="statistics ">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>地锁信息</view>
+
+						<view class="check-all" @click="body8data.popup=true" >查看全部<u-icon name="arrow-right"></u-icon></view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body8">
+						<view class="body8main">
+							<view class="line">
+								<view class="value">
+									地锁型号
+
+								</view>
+								<view class="value">
+									出厂编号
+
+								</view>
+								<view class="value">
+									固件版号
+
+
+								</view>
+
+
+							</view>
+							<view class="line">
+								<view class="value">
+									{{info.model}}
+
+								</view>
+								<view class="value">
+									{{info.factoryNumber}}
+
+
+								</view>
+								<view class="value">
+									{{info.solidVersion}}
+
+
+								</view>
+
+
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+			<!-- end-->
+			<u-divider border-color="#CFD2D5">已经到底了</u-divider>
+
+		</view>
+
+	</view>
+</template>
+
+<script>
+	import jpContent from '@/components/JPcontent.vue'
+	import * as echarts from 'echarts';
+	import * as API from '@/apis/pagejs/deviceTab.js'
+	import * as API_index from '@/apis/pagejs/index.js'
+	import {
+		parseUnixTime,
+		beforeTimeStamp,
+		newDate
+	} from '@/apis/utils'
+	
+	export default {
+		components: {
+
+			jpContent
+		},
+		data() {
+			return {
+				id:"",
+				info:{},
+				echartsList: {},
+				lockUsageRateData:{},
+				body2data: {
+					query: {},
+					vue: {
+						queryN: "",
+						show: false,
+						params: {
+							year: true,
+							month: true,
+							day: false,
+							hour: false,
+							minute: false,
+							second: false
+						}
+					},
+					data: {}
+				},
+				body0data: {
+					query: {},
+					data: {},
+					tabsFrom:{
+						show:false,
+						showIndex:"",
+						params:{
+							year: true,
+							month: true,
+							day: false,
+							hour: false,
+							minute: false,
+							second: false
+						}
+					}
+				
+				},
+				body4data: {
+					query: {},
+					data: {}
+				},
+				body8data: {
+					query: {},
+					data: {},
+					popup:false,
+				},
+				body3data: {
+					query: {},
+					data: {}
+				},
+				jpContentMap: {
+					body1: 2,
+					body2: 2,
+					body3: 2,
+					body4: 2,
+					body5: 2,
+					body6: 2,
+					body7: 2,
+					body8: 2,
+					body9: 2,
+					body10: 2,
+				},
+				title: "",
+				backgroundObj: {
+					background: '#307AF6'
+				},
+				radiovalue: "1",
+				radiolist: [{
+						name: '上月',
+						value: "3"
+					},
+					{
+						name: '当月',
+						value: "1"
+					},
+					{
+						name: '今日',
+						value: "2"
+					}, {
+						name: '当年',
+
+						value: "4"
+					}, {
+						name: '合计',
+
+						value: "5"
+					},
+					{
+						name: '指定月份',
+						value: "0"
+					}
+				],
+				abnormalRecordsList: [{
+						level: 1,
+						content: "1111111",
+						title: "11",
+						createTime: "123:123"
+					},
+					{
+						level: 2,
+						content: "1111111",
+						title: "11",
+						createTime: "123:123"
+					}
+				],
+			};
+		},
+		onLoad(op) {
+			if(op.id){
+				this.id=op.id
+				this.init();
+			}
+			this.body0data.tabsFrom.showIndex=new Date().getFullYear()+'-'+(new Date().getMonth()+1)
+		},
+		onReady() {
+			// if(this.id){
+				
+			// }
+			
+		},
+		methods: {
+			
+			durationShow(){
+				if(this.lockUsageRateData.duration){
+					var m=this.lockUsageRateData.duration%60
+					var h=parseInt(this.lockUsageRateData.duration/60)
+					if(h>0){
+						return `${h}h${m}m`
+					}else{
+						return `${m}m`
+					}
+				}else{
+					return '0m'
+				}
+			},
+			radioChange(e) {
+				// console.log(e);
+			},
+			// 选中任一radio时,由radio-group触发
+			selector2confirm(e){
+				var time=e.year + "-" + e.month
+				this.radiolist[5].name=e.year + "年" + e.month+"月"
+				this.body0data.tabsFrom.showIndex=time
+				this.getLockUsageRate()
+			},
+			selector2cancel(){
+				this.radiovalue= "1"
+				this.radiolist[5].name="指定月份"
+				this.getLockUsageRate()
+			},
+			radioGroupChange(e) {
+				 console.log(e);
+				if(e==0){
+					this.body0data.tabsFrom.show=true
+				}else{
+					this.radiolist[5].name="指定月份"
+					this.getLockUsageRate()
+				}
+				
+			},
+			init() {
+				this.getInfo()
+				this.getLockUsageRate()
+				this.occupancyByTime(1)
+				//this.getbody1()
+				//this.getbody2()
+				this.occupancyByTimeBar(1);
+				//this.getbody3()
+				//this.getbody4()
+				this.durationDistribution()
+			},
+			occupancyByTime(init) {
+				if (init) {
+					var date = new Date();
+			
+					this.body2data.vue.queryN = date.getFullYear() + "年" + (date.getMonth() + 1) + '月';
+					this.body2data.query.startTime = date.getFullYear() + "-" + (date.getMonth() + 1) + "-1"
+			
+					var endOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0)
+					this.body2data.query.endTime = parseUnixTime(endOfMonth, '{y}-{m}-{d}')
+			
+				}
+				this.jpContentMap.body2 = 0
+				this.body2data.query.floorId = this.id
+				
+				API_index.occupancyByTime(
+					this.body2data.query
+				).then((response) => {
+					this.body2data.data = [
+						...response.data.locksTimeList,
+						//	...response.data.locksTimeList,
+					];
+			
+					if (this.body2data.data.length == 0) {
+						this.jpContentMap.body2 = 1
+			
+			
+					} else {
+						this.jpContentMap.body2 = 2
+			
+						this.getbody2()
+			
+			
+					}
+			
+			
+			
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+			
+				})
+			},
+			body2dataconfirm(e) {
+			
+				var date = new Date(e.year + "-" + e.month + "-1");
+				this.body2data.vue.queryN = date.getFullYear() + "年" + (date.getMonth() + 1) + '月';
+				this.body2data.query.startTime = date.getFullYear() + "-" + (date.getMonth() + 1) + "-1"
+			
+				var endOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0)
+				this.body2data.query.endTime = parseUnixTime(endOfMonth, '{y}-{m}-{d}')
+			
+				this.occupancyByTime()
+			},
+			getLockUsageRate(){
+				var obj = {
+					floorId: this.id,
+					queryType:this.radiovalue
+				}
+				if(this.radiovalue==0){
+					obj.queryMonth=this.body0data.tabsFrom.showIndex
+				}
+				API.lockUsageRate(obj).then((res) => {
+					this.lockUsageRateData=res.data
+					
+				}).catch(error => {
+							
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			},
+			durationDistribution() {
+				this.jpContentMap.body4 = 0
+			
+				var date = new Date();
+				//test
+				//this.body4data.query.startTime = date.getFullYear() + "-" + (date.getMonth() + 1) + "-1"
+			
+				var endOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0)
+			//	this.body4data.query.endTime = parseUnixTime(endOfMonth, '{y}-{m}-{d}')
+			
+			
+				this.body4data.query.floorId = this.id
+				API_index.durationDistribution(
+					this.body4data.query
+				).then((response) => {
+					this.body4data.data = response.data.distribution;
+			
+					if (this.body4data.data.length == 0) {
+						this.jpContentMap.body4 = 1
+			
+					} else {
+						this.jpContentMap.body4 = 2
+						//this.getbody3()
+						this.getbody4()
+					}
+			
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+			
+				})
+			},
+			getInfo(){
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				var obj = {
+					id: this.id
+				}
+				this.jpContentMap.body8	=0		
+				API.lockDetails(obj).then((res) => {
+					this.info = res.data.floorlockInfo
+					this.title	=this.info.parkingName
+					uni.hideLoading();
+					this.jpContentMap.body8	=2
+					//this.getWhiteList()
+				}).catch(error => {
+							
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			},
+			getbody1() {
+				var key = "body1pie1"
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(300 * 2),
+						height: uni.upx2px(170 * 2)
+					})
+
+				}
+				myChart.clear()
+
+
+				var option = {
+
+					grid: {
+						top: 20,
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					series: [{
+
+						type: 'pie',
+						radius: ['80%', '50%'],
+						radius: [35, 50],
+						data: [{
+								itemStyle: {
+									color: "#EB3C31"
+								},
+								value: 1048,
+								name: '0.5小时\n20%',
+
+							},
+							{
+								itemStyle: {
+									color: "#EF8132"
+								},
+
+								value: 735,
+								name: '2小时\n10%'
+							},
+							{
+								itemStyle: {
+									color: "#929292"
+								},
+								value: 580,
+								name: '2-6小时\n30%'
+							},
+
+
+						]
+
+					}]
+				};
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+			getbody4() {
+				var key = "body4pie1"
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(300 * 2),
+						height: uni.upx2px(170 * 2)
+					})
+
+				}
+				myChart.clear()
+				var dataApi = this.body4data.data;
+				
+				var data = []
+				var num = 0
+				var sum = 0
+				Object.keys(dataApi).forEach(key1 => {
+					num += dataApi[key1]
+				});
+				var i = 0
+				Object.keys(dataApi).forEach(key1 => {
+					var value = dataApi[key1]
+					if(value!=0){
+						var obj = {
+							value: value,
+							name: key1
+						}
+					
+						if (num != 0) {
+							var valueInt = parseInt(value / num * 100)
+							if (valueInt == 0 && value != 0) {
+								valueInt = 1
+							}
+							sum += valueInt;
+					
+							if (i == Object.keys(dataApi).length - 1) {
+								if (sum != 100) {
+									valueInt += (100 - sum)
+								}
+							}
+							obj.name += '\n' + (valueInt) + '%'
+						}
+						data.push(obj)
+					}
+					i++;
+				});
+
+				var option = {
+
+					grid: {
+						top: 20,
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					series: [{
+
+						type: 'pie',
+						radius: ['80%', '50%'],
+						radius: [45, 60],
+						data: data
+						
+					}]
+				};
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+			occupancyByTimeBar(init) {
+				if (init) {
+					var date = new Date();
+					//test
+					//this.body3data.query.startTime = date.getFullYear() + "-" + (date.getMonth() + 1) + "-1"
+			
+					var endOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0)
+					//this.body3data.query.endTime = parseUnixTime(endOfMonth, '{y}-{m}-{d}')
+			
+				}
+				this.jpContentMap.body3 = 0
+				
+				this.body3data.query.floorId = this.id
+				API_index.occupancyByTimeBar(
+					this.body3data.query
+				).then((response) => {
+					this.body3data.data = [
+						...response.data.locksTimeList,
+						//	...response.data.locksTimeList,
+					];
+			
+					if (this.body3data.data.length == 0) {
+						this.jpContentMap.body3 = 1
+			
+					} else {
+						this.jpContentMap.body3 = 2
+						this.getbody3()
+			
+					}
+			
+			
+			
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+			
+				})
+			},
+			getbody3() {
+				var key = "body3bar1"
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(300 * 2),
+						height: uni.upx2px(170 * 2)
+					})
+
+				}
+				var dataApi = this.body3data.data;
+				
+				myChart.clear()
+
+				var data1 = []
+				var data2 = [] //useDays
+				var i = 0
+				dataApi[0].timeUseList.forEach(item => {
+				
+					Object.keys(item).forEach(key1 => {
+				
+						data1.push(key1 + '点')
+						var num = 0
+				
+						dataApi.forEach(item2 => {
+							num += item2.timeUseList[i][key1].useDays
+				
+						})
+						data2.push(num)
+					});
+					i += 1
+				
+				})
+				
+				var axisLabel = {
+					rotate: 40,
+					interval: 0,
+					textStyle: {
+						color: "#333"
+					}
+				}
+				if (data1.length < 7) {
+					axisLabel = {
+						interval: 0,
+						textStyle: {
+							color: "#333"
+						},
+					}
+				} else {
+					axisLabel.interval = 0;
+				}
+				var option = {
+					xAxis: {
+						type: 'category',
+						data: data1,
+						axisLabel: axisLabel,
+					},
+					tooltip: {
+						trigger: 'axis',
+						axisPointer: {
+							type: 'shadow'
+						},
+						formatter: function(params) {
+							var result = params[0].name + '<br/>';
+							for (var i = 0; i < params.length; i++) {
+								result += params[i].marker+ ' ' + params[i].value + '次<br/>';
+							}
+							return result;
+						}
+					},
+					yAxis: {
+						type: 'value'
+					},
+					grid: {
+						top: 20,
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					series: [{
+						itemStyle: {
+							color: "#5A88E5"
+						},
+							data: data2,
+						type: 'bar'
+					}]
+				};
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+			getbody2() {
+				var key = "body2line1"
+				var myChart = this.echartsList[key];
+				var dataApi = this.body2data.data;
+				
+				var head = 20 * (parseInt(dataApi.length / 4)) + 20
+				
+				
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(300 * 2),
+						height: uni.upx2px((170 + head) * 2)
+					})
+				
+				}
+				myChart.clear()
+				
+				var data1 = []
+				var series = [];
+				
+				dataApi.forEach(item => {
+				
+					var obj = {
+						name: item.lockName,
+						areaStyle: {},
+						itemStyle: {
+							color: "#BBD4FB"
+						},
+						label: {
+							show: true,
+							position: 'top',
+								color: "#307AF6"
+						},
+						data: [],
+						type: 'line'
+					}
+					if (dataApi.length == 1) {
+						obj.label.color = "#307AF6"
+						obj.areaStyle = {}
+						obj.itemStyle = {
+							color: "#BBD4FB"
+						}
+					}
+				
+					item.timeUseList.forEach(item2 => {
+						Object.keys(item2).forEach(key1 => {
+				
+							obj.data.push(item2[key1].useRate)
+						});
+					})
+					series.push(obj)
+				})
+				dataApi[0].timeUseList.forEach(item => {
+				
+					Object.keys(item).forEach(key1 => {
+						data1.push(key1)
+				
+					});
+				
+				})
+				var axisLabel = {
+					rotate: 40,
+					interval: 0,
+					textStyle: {
+						color: "#333"
+					}
+				}
+				if (data1.length < 7) {
+					axisLabel = {
+						interval: 0,
+						textStyle: {
+							color: "#333"
+						},
+					}
+				} else {
+					axisLabel.interval = 0;
+				}
+				var option = {
+					xAxis: {
+						type: 'category',
+						data: data1,
+						axisLabel: axisLabel,
+					},
+					tooltip: {
+						trigger: 'axis',
+						axisPointer: {
+							type: 'shadow'
+						},
+						
+						formatter: function(params) {
+							var result = params[0].name + '点<br/>';
+							for (var i = 0; i < params.length; i++) {
+								result += params[i].marker+params[i].seriesName + ': ' + params[i].value + '%<br/>';
+							}
+							return result;
+						}
+					},
+					yAxis: {
+						type: 'value'
+					},
+					grid: {
+						top: (20 + head),
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					series: series,
+					 
+				};
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	.gradient-header {
+		height: 0px;
+	}
+
+	.jpback {
+		height: 268rpx;
+		background: linear-gradient(180deg, rgba(22, 119, 255, 1) 20%, rgba(121, 177, 255, 1) 100%);
+	}
+
+	.main {
+
+		padding: 32rpx;
+
+		.no_statistics {
+			margin-bottom: 24rpx;
+		}
+
+		.statistics {
+			border-radius: 8px;
+			background-color: rgba(255, 255, 255, 1);
+			box-shadow: 0px 1px 6px 0px rgba(0, 59, 142, 0.05);
+			margin-bottom: 24rpx;
+			padding: 40rpx;
+
+			.title {
+				display: flex;
+				align-items: center;
+				margin-bottom: 32rpx;
+				font-weight: bold;
+
+				.img {
+					width: 36rpx;
+					height: 36rpx;
+					vertical-align: middle;
+					border-radius: 999px;
+
+				}
+
+				.change {
+					display: flex;
+					align-items: center;
+
+					.change-img {
+						width: 32rpx;
+						height: 32rpx;
+						vertical-align: middle;
+					}
+
+					text {
+
+						margin-left: 8rpx;
+					}
+				}
+
+
+				.text {
+					color: rgba(16, 16, 16, 1);
+					font-size: 36rpx;
+					margin-left: 16rpx;
+					display: flex;
+					justify-content: space-between;
+					align-items: center;
+					width: 100%;
+
+					.tag {
+						border-radius: 4px;
+						border: 1px solid rgba(187, 187, 187, 1);
+						color: rgba(51, 51, 51, 1);
+
+						font-size: 24rpx;
+						padding: 1px 8rpx;
+						margin-left: 8rpx;
+					}
+
+				}
+
+				.change {
+					margin-left: 16rpx;
+					font-size: 24rpx;
+					color: #838383;
+
+				}
+
+				.check-all {
+					margin-left: auto;
+					color: rgba(131, 131, 131, 1);
+					font-size: 24rpx;
+				}
+			}
+		}
+	}
+
+	.data1 {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.item {
+			.line{
+				    display: flex;
+				    align-items: center;
+			}
+			.name {
+				color: rgba(51, 51, 51, 1);
+				font-size: 36rpx;
+				font-weight: bold;
+				margin-right: 8rpx;
+			}
+
+			.item-tags {
+				display: flex;
+
+				.tag {
+					border-radius: 4px;
+
+					background-color: rgba(39, 177, 72, 1);
+					color: rgba(255, 255, 255, 1);
+					font-size: 24rpx;
+					padding: 2rpx 8rpx;
+					margin-right: 8rpx;
+				}
+
+				.typeN1 {
+					background-color: rgba(22, 119, 255, 1);
+				}
+				.typeN2{
+					background-color: #8161ff;
+																				 background-color: #8161ff;
+				}
+				.statusN{
+					background-color:#838383
+				}
+				.lockStatusN {
+				
+					background-color: rgba(153, 153, 153, 1);
+				}
+				
+				.lockStatusN2 {
+					background-color: #03A9F4
+				}
+				
+			}
+		}
+
+		.value {
+			.img {
+				margin-right: 8rpx;
+				width: 32rpx;
+				height: 32rpx;
+			}
+		}
+	}
+
+	.data2 {
+		height: 336rpx;
+		padding: 32rpx;
+		border-radius: 12px;
+		background: linear-gradient(180deg, rgba(222, 222, 222, 1) 3%, rgba(255, 255, 255, 1) 5%, rgba(232, 232, 232, 1) 56%, rgba(255, 255, 255, 1) 59%, rgba(236, 236, 236, 1) 95%, rgba(215, 215, 215, 1) 98%);
+
+		.top {
+			background-repeat: round;
+			background-image: url('@/assets/img/deviceTab/index3-2.png');
+			display: flex;
+			justify-content: space-around;
+			text-align: center;
+			height: 152rpx;
+			align-items: center;
+
+			.item {
+				.name {
+					color: rgba(16, 16, 16, 1);
+					font-size: 32rpx;
+				}
+
+				.value {
+					color: rgba(16, 16, 16, 1);
+					font-size: 48rpx;
+					font-weight: bold;
+				}
+			}
+		}
+
+		.body {
+			padding: 16rpx;
+		}
+	}
+
+	.body5data {
+		.line {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.data {
+				display: flex;
+				width: 80%;
+				justify-content: space-between;
+
+				.item {
+					color: rgba(51, 51, 51, 1);
+					font-size: 16px;
+				}
+
+				.value {
+					color: rgba(119, 119, 119, 1);
+					font-size: 16px;
+				}
+			}
+		}
+	}
+
+	.body7data {
+		.line {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.value {
+				width: 33%;
+				padding: 16rpx;
+				color: rgba(51, 51, 51, 1);
+
+
+			}
+
+			.value:nth-child(3) {
+
+				text-align: center;
+
+			}
+		}
+
+		/* 隔行变色: 偶数行设置背景色 */
+		.line:nth-child(odd) {
+			background-color: #F2F2F2;
+			/* 偶数行 */
+		}
+
+		.line:nth-child(even) {
+			background-color: #FFFFFF
+				/* 奇数行 */
+		}
+
+	}
+
+	.body8main {
+		.line {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+
+			.value {
+				width: 33%;
+				padding: 16rpx;
+
+				text-align: center;
+				
+				overflow: hidden;
+				white-space: nowrap;
+				text-overflow: ellipsis;
+			}
+
+		}
+
+		/* 隔行变色: 偶数行设置背景色 */
+		.line:nth-child(odd) {
+			color: rgba(119, 119, 119, 1);
+			font-size: 14px;
+			/* 偶数行 */
+		}
+
+		.line:nth-child(even) {
+			color: rgba(16, 16, 16, 1);
+			font-size: 16px;
+
+			/* 奇数行 */
+		}
+
+	}
+
+	.body6main {
+		.line {
+			display: flex;
+			justify-content: space-between;
+		}
+
+		.abnormal-item:last-of-type {
+			border-bottom: none !important;
+			padding-bottom: 0;
+		}
+
+		.abnormal-item {
+			width: 100%;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 16rpx;
+			border-bottom: 1px solid rgba(245, 245, 245, 1);
+
+
+			.item-title {
+				.level {
+					color: #fff;
+
+					border-radius: 8rpx;
+					font-weight: 400;
+					padding: 4rpx 8rpx;
+					font-size: 22rpx;
+					margin-right: 2px;
+				}
+
+				.level1 {
+					background: red;
+				}
+
+				.level2 {
+					background-color: rgba(255, 123, 0, 1);
+				}
+
+				color: rgba(51, 51, 51, 1);
+				width: 100%;
+
+				.img {
+					width: 32rpx;
+					height: 32rpx;
+					margin-right: 8rpx;
+				}
+
+				.name {
+					color: rgba(51, 51, 51, 1);
+					font-weight: bold;
+					overflow: hidden;
+					white-space: nowrap;
+					text-overflow: ellipsis;
+				}
+
+				.date {
+					color: rgba(119, 119, 119, 1);
+					font-size: 24rpx;
+				}
+			}
+
+			.item-value {
+				text-align: right;
+				display: flex;
+				align-items: center;
+
+				.more {
+					margin-left: 8rpx;
+				}
+
+				.value1 {
+					font-weight: bold;
+					color: rgba(51, 51, 51, 1);
+				}
+
+				.value2 {
+					color: rgba(119, 119, 119, 1);
+					font-size: 24rpx;
+				}
+			}
+		}
+	}
+	
+	// 地锁信息弹窗
+	.body8data-popup {
+	
+		.content {
+	
+			padding: 32rpx;
+	
+			.headline {
+				color: rgba(16, 16, 16, 1);
+				font-size: 36rpx;
+				text-align: center;
+				font-weight: bold;
+				margin-bottom: 24rpx;
+			}
+	
+			.infos {
+				//padding-bottom: 100rpx;
+	
+				.item:last-of-type {
+					border: none;
+				}
+	
+				.item {
+					display: flex;
+					align-items: center;
+	
+					//line-height: 48rpx;
+					padding: 20rpx 0;
+					border-bottom: 1px solid #cccccc;
+	
+					.item-title {
+						color: rgba(51, 51, 51, 1);
+						width: 200rpx;
+					}
+	
+					.item-value {
+						color: #666666;
+						flex: 1;
+						margin-left: 16rpx;
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+						
+						.img{
+							width: 32rpx;
+							height: 32rpx;
+							transform: rotate(90deg);
+							margin-left: 96rpx;
+						}
+					}
+				}
+	
+			}
+	
+			.get {
+				height: 80rpx;
+				line-height: 80rpx;
+				border-radius: 4px;
+				background-color: rgba(22, 119, 255, 1);
+				color: rgba(255, 255, 255, 1);
+				font-size: 32rpx;
+			}
+		}
+	}
+	
+	.top-span{
+		border-top: 1px solid rgba(245, 245, 245, 1);
+		display: flex;
+		flex-wrap: wrap;
+		justify-content: space-between;
+		padding-top: 16rpx;
+		margin-top: 16rpx;
+		.item-span{
+			white-space: pre;
+			    display: flex;
+			    align-items: center;
+				   margin-top: 4rpx;
+				width: 30%;
+				 font-size: 28rpx;
+				 span{
+					 margin: 0 8rpx;
+				 }
+
+			img{
+				width: 28rpx;
+				height: 28rpx;
+			}
+		}
+		
+		.lockStatusX1{
+			color: #00B962;
+		}
+		.lockStatusX2{
+			color: #1677FF;
+		}
+		
+		.statusX1{
+			color: #00B962;
+		}
+		.statusX2{
+			color: #1677FF;
+		}
+	}
+</style>

+ 324 - 0
pages/deviceTab/deviceList.vue

@@ -0,0 +1,324 @@
+<template>
+	<view>
+		<u-navbar  title="地锁列表"  ></u-navbar>
+		<view class="main">
+			<view class="tabs" v-if="0">
+				<u-picker  v-model="tabsFrom.show1"
+				  :default-selector="[tabsFrom.show1Index]"
+				 mode="selector" :range="tabsFrom.selector1"  range-key="label" @confirm="selector1confirm" ></u-picker>
+				<u-picker-select title="日期选择" v-model="tabsFrom.show2"
+				 :defaultTime="tabsFrom.show2Index" :endYear="endYear"
+				 mode="time" :params="params"  @confirm="selector2confirm" @reset="selector2reset" ></u-picker-select>
+				
+				<view class="tabsItem" @click="tabsFrom.show1=!tabsFrom.show1">{{tabsFrom.show1Text}} <u-icon name="arrow-up"
+						v-if="tabsFrom.show1"></u-icon><u-icon v-else name="arrow-down"></u-icon></view>
+				<view class="tabsItem" @click="tabsFrom.show2=!tabsFrom.show2">{{tabsFrom.show2Text}} <u-icon name="arrow-up"
+						v-if="tabsFrom.show2"></u-icon><u-icon v-else name="arrow-down"></u-icon></view>
+						
+				<view class="tabsItem" @click="tabsFrom.show3=!tabsFrom.show3">{{tabsFrom.show3Text}} <u-icon name="arrow-up"
+						v-if="tabsFrom.show3"></u-icon><u-icon v-else name="arrow-down"></u-icon></view>
+			</view>
+			
+			<view class="list">
+				<view class="line"   v-for="(item,i) in list" :key="i"
+				 @click="gotoUrl('/pages/deviceTab/dataLock?id='+item.id)" >
+					<view class="body">
+						<view class="imgclass">
+							<image class="img" src="@/assets/img/deviceTab/index2-1.svg" mode=""></image>
+						</view>
+						<view class="item">
+							<view class="name">
+								<view class="text">{{item.name}}</view>
+								<view class="tag" :class="'type'+item.type">{{item.typeN}}</view>
+							</view>
+							<view class="value">
+								{{item.parkingName}}
+							</view>
+						</view>
+					</view>
+					<view class="goto">
+						<view class="dian" :class="'status'+item.status"></view>
+						<view  class="text" :class="'statusText'+item.status" >{{item.status==1?'在线':'离线'}}</view>
+						<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+					</view>
+				</view>
+				
+			<!-- 	<view class="line">
+					<view class="body">
+						<view class="imgclass">
+							<image class="img" src="@/assets/img/deviceTab/index2-1.svg" mode=""></image>
+						</view>
+						<view class="item">
+							<view class="name">
+								<view class="text">软件园</view>
+								<view class="tag">私人车位</view>
+							</view>
+							<view class="value">
+								占用9<span>/</span>
+								占用9<span>/</span>
+								共9台
+							</view>
+						</view>
+					</view>
+					<view class="goto">
+						<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+					</view>
+				</view> -->
+				
+			</view>
+			
+			<view class="floating-button" 
+			  @click="gotoBind" v-if="0" >
+				<view class="button">
+					<img class="img" src="@/assets/img/deviceTab/index2-2.svg" alt="">
+			
+					绑定新地锁
+				</view>
+			
+			</view>
+			
+			
+		</view>
+		<u-divider :isnone="list.length==0" nonetext="没有找到相关内容" border-color="#CFD2D5">已经到底了</u-divider>
+		
+		
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/deviceTab.js'
+	
+	
+	export default {
+		
+		data() {
+			return {
+				list:[],
+				listForm:{
+					pageIndex: 1,
+					pageSize: 20,
+					recordsTotal: 1,
+				},
+				title:"场站列表",
+				tabsFrom: {
+					show1: false,
+					show1Index:0,
+					show2Index:'',
+					show2: false,
+					show1Text: "全部场站",
+					show2Text: "全部类型",
+					show3Text: "全部状态",
+					selector1:[
+						{
+								label: '全部类型',
+								value: '',
+							},
+						{
+								label: '线上充值',
+								value: '1',
+							},
+							{
+								label: '线下充值',
+								value: '2',
+							},
+					]
+				},
+			};
+		},
+		onLoad(op) {
+			if(op.companyId){
+				this.listForm.companyId=op.companyId
+			}
+			if(op.parkingId){
+				this.listForm.parkingId=op.parkingId
+			}
+			this.getList()
+		},
+		onReachBottom() {
+			if (this.list.length < this.listForm.recordsTotal) {
+				this.myLoadmore();
+			}
+		},
+		methods: {
+			gotoBind(){
+				uni.navigateTo({
+				  url: '/pages/deviceTab/bindLock?parkingId='+this.listForm.parkingId,
+				  events: {
+				    // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
+				    acceptDataFromOpenerPage: (item)=>{
+						
+						this.getList(1)
+				    },
+				 
+				  }
+				  // ,
+				  // success: function(res) {
+				  //   // 通过eventChannel向被打开页面传送数据
+				  //  
+				  // }
+				})
+			},
+			myLoadmore(){
+				this.listForm.pageIndex += 1;
+				this.getList()
+			},
+			getList(bl) {
+				if(bl){
+					this.listForm.pageIndex = 1
+				}
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+							 
+				API.floorlockList(this.listForm).then((res) => {
+					var list=[]
+					
+					if (this.listForm.pageIndex == 1) {
+						list = res.data.data;
+					} else {
+						list = [
+							...list,
+							...res.data.data
+						];
+					}
+					this.list = res.data.data
+					uni.hideLoading();
+				
+				}).catch(error => {
+				
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			},
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.main{
+		background-color: #fff;
+		.line{
+			    display: flex;
+			    justify-content: space-between;
+				    align-items: center;
+					padding: 32rpx;
+					border-bottom: 1px solid rgba(245,245,245,1);
+				.goto{
+					display: flex;
+					    align-items: center;
+						.dian{
+							width: 16rpx;
+							height: 16rpx;
+							 border-radius: 50px;
+							background-color: rgba(184,184,184,1);
+							 margin-right: 16rpx;
+						}
+						.status1{
+							background-color: #4CAF50;
+							color:#4CAF50;
+						}
+						.statusText1{
+							
+							color:#4CAF50;
+						}
+						.text{
+							 margin-right: 16rpx;
+							 font-size: 24rpx;
+
+						}
+				}
+				.body{
+					 display: flex;
+					     align-items: center;
+						 
+						 .imgclass{
+						 							     display: flex;
+						 							     align-items: center;
+						 							     justify-content: center;
+						 							width: 72rpx;
+						 							height: 72rpx;
+						 							     border-radius: 4px;
+						 							     background-color: rgba(219,234,255,1);
+						 }
+						 .item{
+						 							    margin-left: 16rpx;
+						 								
+						 								 .name{
+						 									 color: rgba(51,51,51,1);
+						 									 font-size: 28rpx;
+															 display: flex;
+															 align-items: center;
+															 .tag{
+																border-radius: 4px;
+																background-color: rgba(22,119,255,1);
+																color: rgba(255,255,255,1);
+																font-size: 22rpx;
+																padding:1px 8rpx;
+																margin-left: 8rpx;
+															 }
+															 .type2{
+																 background-color: #8161ff;
+															 }
+						 								 }
+						 								 .value{
+						 								 	color: rgba(119,119,119,1);
+						 								 	font-size: 24rpx;
+						 											
+						 								 }
+						 }
+						
+				}
+		}
+		.img{
+			width: 48rpx;
+			height: 48rpx;
+		}
+	}
+	
+	.tabs{
+		border-bottom: 1px solid rgba(232,232,232,1);
+		height: 96rpx;
+		line-height: 96rpx;
+		background-color: #fff;
+		border-top: 1px solid rgba(241,241,241,1);
+		display: flex;
+		justify-content: space-around;
+		.tabsItem{
+			color: rgba(51,51,51,1);
+			font-size: 14px;
+
+		}
+		
+	}
+	
+	.floating-button {
+		position: fixed;
+		bottom: 120rpx;
+		width: 100%;
+		display: flex;
+	
+		justify-content: center;
+	
+		.button {
+			border-radius: 50px;
+			background-color: rgba(49, 51, 52, 1);
+			color: rgba(255, 255, 255, 1);
+			font-size: 28rpx;
+			width: 240rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			padding: 12rpx;
+	
+			.img {
+				width: 40rpx;
+				height: 40rpx;
+				margin-right: 8rpx;
+			}
+		}
+	}
+</style>

+ 153 - 0
pages/deviceTab/index.vue

@@ -0,0 +1,153 @@
+<template>
+	<view>
+		<u-navbar  :title="title" :is-back="0" ></u-navbar>
+		<view class="main">
+			<view class="list">
+				<view class="line"  v-for="(item,i) in list" :key="i"
+				  @click="gotoUrl('/pages/deviceTab/deviceList?parkingId='+item.id)" >
+					<view class="body">
+						<view class="imgclass">
+							<image class="img" src="@/assets/img/deviceTab/index1-1.svg" mode=""></image>
+						</view>
+						<view class="item">
+							<view class="name">
+								{{item.name}}
+							</view>
+							<view class="value"  >
+							
+								<span>空闲{{item.idleNum}} / 共{{item.totalNum}}台</span>
+								<!-- <span>{{item.contacts}}</span> -->
+								<span>{{item.openStatusN}}</span>
+							</view>
+						</view>
+					</view>
+					<view class="goto">
+						<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+					</view>
+				</view>
+				
+				
+				
+			</view>
+		</view>
+		<u-divider  :isnone="list.length==0" nonetext="没有找到相关内容" border-color="#CFD2D5">已经到底了</u-divider>
+		
+		<tabbar :current="1"></tabbar>
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/deviceTab.js'
+	
+	import Tabbar from '@/components/Tabbar.vue'
+	export default {
+		components: {
+			Tabbar
+		},
+		data() {
+			return {
+				title:"场站列表",
+				list:[],
+				listForm:{
+					pageIndex: 1,
+					pageSize: 20,
+					recordsTotal: 1,
+				},
+			};
+		},
+		onLoad() {
+			this.getList()
+		},
+		onReachBottom() {
+			if (this.list.length < this.listForm.recordsTotal) {
+				this.myLoadmore();
+			}
+		},
+		methods: {
+			
+			myLoadmore(){
+				this.listForm.pageIndex += 1;
+				this.getList()
+			},
+			getList() {
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+							 
+				API.parkingList(this.listForm).then((res) => {
+					
+					var list=this.list 
+					
+					if (this.listForm.pageIndex == 1) {
+						list = res.data.parkingInfoList;
+					} else {
+						list = [
+							...list,
+							...res.data.parkingInfoList
+						];
+					}
+					this.list=list
+					uni.hideLoading();
+				
+				}).catch(error => {
+				
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			},
+			
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.main{
+		background-color: #fff;
+		.line{
+			    display: flex;
+			    justify-content: space-between;
+				    align-items: center;
+					padding: 32rpx;
+					border-bottom: 1px solid rgba(245,245,245,1);
+					
+				.body{
+					 display: flex;
+					     align-items: center;
+						 
+						 .imgclass{
+						 							     display: flex;
+						 							     align-items: center;
+						 							     justify-content: center;
+						 							width: 72rpx;
+						 							height: 72rpx;
+						 							     border-radius: 4px;
+						 							     background-color: rgba(219,234,255,1);
+						 }
+						 .item{
+						 							    margin-left: 16rpx;
+						 								
+						 								 .name{
+						 									 color: rgba(51,51,51,1);
+						 									 font-size: 28rpx;
+						 								 }
+						 								 .value{
+						 								 	color: rgba(119,119,119,1);
+						 								 	font-size: 24rpx;
+						 											 span{
+						 												  margin-right: 16rpx;
+						 											 }
+						 								 }
+						 }
+						
+				}
+		}
+		.img{
+			width: 48rpx;
+			height: 48rpx;
+		}
+	}
+</style>

+ 651 - 0
pages/deviceTab/infoLock.vue

@@ -0,0 +1,651 @@
+<template>
+	<view class="jpmain  ">
+		<view class="gradient-header">
+			<view class="jpback">
+
+			</view>
+		</view>
+		<view class="body">
+			<view class="page-top">
+				<!-- <view class="text1">地锁名称</view> -->
+				<!-- @click="gotoUrl('/pages/mylock/editLock?id='+id)" -->
+				<view class="text2"   >{{
+					floorlockInfo.name
+				}}<!-- <u-icon name="edit-pen" size="32" color="#FFFFFF"></u-icon> -->
+				</view>
+			</view>
+			<view class="page">
+				<view class="info-title">
+					<view class="name">地锁信息</view>
+					<view class="value">
+						<view class="pack-up" v-show="listShow" @click="listShow=false">
+							收起<u-icon name="arrow-up" size="32" color="#AAAAAA"></u-icon>
+						</view>
+						<view class="pack-up" v-if="!listShow" @click="listShow=true">
+							展开<u-icon name="arrow-down" size="32" color="#AAAAAA"></u-icon>
+						</view>
+					</view>
+				</view>
+				<view class="table">
+					<view class="row">
+						<view class="name">地锁型号</view>
+						<view class="value">{{floorlockInfo.model}}</view>
+					</view>
+
+
+					<view class="row">
+						<view class="name">出厂编号</view>
+						<view class="value">{{floorlockInfo.factoryNumber}}</view>
+					</view>
+					<template v-if="!listShow">
+						<view class="row">
+							<view class="name">固件版号</view>
+							<view class="value">{{floorlockInfo.solidVersion}}</view>
+						</view>
+						<view class="row">
+							<view class="name">防护等级</view>
+							<view class="value">{{floorlockInfo.protectionGrade}}</view>
+						</view>
+
+						<view class="row"  v-if="0">
+							<view class="name">输入电压</view>
+							<view class="value">{{floorlockInfo.inputVoltage}}</view>
+						</view>
+						<view class="row" v-if="0">
+							<view class="name">输出电压</view>
+							<view class="value">{{floorlockInfo.outputVoltage}}</view>
+						</view>
+
+						<view class="row"  v-if="0">
+							<view class="name">输出电流</view>
+							<view class="value">{{floorlockInfo.outputCurrent}}</view>
+						</view>
+						<view class="row"  v-if="0">
+							<view class="name">输出功率</view>
+							<view class="value">{{floorlockInfo.outputPower}}</view>
+						</view>
+
+						<view class="row">
+							<view class="name">生产日期</view>
+							<view class="value">{{floorlockInfo.manufactureDate}}</view>
+						</view>
+
+						<view class="row">
+							<view class="name">标准依据</view>
+							<view class="value">{{floorlockInfo.standardBasis}}</view>
+						</view>
+						<view class="row">
+							<view class="name">联网卡号</view>
+							<view class="value">{{floorlockInfo.internetCard}}</view>
+						</view>
+						<view class="row"  v-if="floorlockInfo.tariffStandard">
+							<view class="name">资费标准</view>
+							<view class="value">{{floorlockInfo.tariffStandard}}元/月</view>
+						</view>
+						<view class="row">
+							<view class="name">地锁启动时间</view>
+							<view class="value">{{floorlockInfo.activationTime}}</view>
+						</view>
+						<view class="row"  v-if="floorlockInfo.shelfLife">
+							<view class="name">地锁质保期</view>
+							<view class="value">{{floorlockInfo.shelfLife}}年</view>
+						</view>
+					</template>
+
+				</view>
+			</view>
+			<view class="page">
+				<view class="info-title">
+					<view class="name">联网信息</view>
+					<view class="value">
+
+					</view>
+				</view>
+				<view class="table">
+					<view class="row">
+						<view class="name">联网卡号</view>
+						<view class="value">{{floorlockInfo.internetCard}}</view>
+					</view>
+					<view class="row">
+						<view class="name">有效期至</view>
+						<view class="value">{{floorlockInfo.cardExpirationDate?floorlockInfo.cardExpirationDate.split(' ')[0]:''}}
+
+						</view>
+
+					</view>
+					<view class="tips"  v-if="floorlockInfo.tariffStandard">
+						<u-icon style="    margin-top: 2px;" size="30" name="info-circle"></u-icon>
+						<view>
+							地锁内含物联网卡,此卡随地锁出厂时赠送三年免费使用时长,三年后将按{{floorlockInfo.tariffStandard}}元/月资费标准收取费用。
+
+						</view>
+
+					</view>
+				</view>
+			</view>
+			<view class="page">
+				<view class="info-title">
+					<view class="name">充电白名单<span class="span">({{whiteList.length}}/3)</span></view>
+					<view class="value" @click="addUser()">
+						<u-icon style="    margin-top: 2px;" size="30" name="plus"></u-icon> 添加
+					</view>
+				</view>
+				<view class="table">
+					<view class="table_v">
+						<view class="table_tr">
+							<view class="table_td">姓名</view>
+							<view class="table_td">手机号</view>
+							<view class="table_td">车牌号</view>
+							<view class="table_td">操作</view>
+						</view>
+						<view class="table_tr" v-for="(item,i) in whiteList" :key="i">
+							<view class="table_td">{{item.nickName}}</view>
+							<view class="table_td">{{item.phone}}</view>
+							<view class="table_td">{{item.carNumber==0?'':item.carNumber}}</view>
+							<view class="table_td" style="color:#1677FF;white-space: pre;" @click="editUser(item)">修改</view>
+						</view>
+
+					</view>
+
+				</view>
+			</view>
+		</view>
+
+		<u-popup v-model="popupShow" mode="bottom" :closeable="true" border-radius="30">
+			<view class="popup-screen">
+
+						<u-keyboard ref="uKeyboard"  @change="valChange" @backspace="backspace"
+						:tips="vipUser.carNumber?vipUser.carNumber:'请输入车牌号'"
+						mode="car" v-model="carshow"  :abc="abc" ></u-keyboard>
+
+
+				<view class="popup-title">{{vipUser.id?'修改':'添加'}}白名单信息</view>
+				<view style="padding: 4px;">白名单车主姓名<span style="color: red;">*</span></view>
+				<u-input :customStyle="customStyle" v-model="vipUser.nickName" placeholder="白名单车主姓名(必填)"></u-input>
+				<view style="padding: 4px;">白名单车主手机号码<span style="color: red;">*</span></view>
+				<u-input :customStyle="customStyle" type="number" v-model="vipUser.phone"
+					placeholder="白名单车主手机号码(必填)"></u-input>
+				<view style="padding: 4px;">白名单车主车牌号</view>
+				<!-- 						<u-input :customStyle="customStyle" v-model="vipUser.carNumber" placeholder="白名单车主车牌号"></u-input> -->
+
+				<view class="carNumber"  @click="carshow=true,valInit(1)"
+				:class="{
+								'carNumber1':!vipUser.carNumber
+							}">
+					{{vipUser.carNumber?vipUser.carNumber:'白名单车主车牌号'}}
+				</view>
+				<view v-if="vipUser.id" style="display: flex;">
+					<u-button type="info" style="margin-top: 10px;width: 49%;" shape="circle"
+						@click="delUser()">删除</u-button>
+					<u-button type="success" style="margin-top: 10px;width: 49%;" shape="circle"
+						@click="submitUser()">保存</u-button>
+				</view>
+				<view v-else>
+
+					<u-button type="success" style="margin-top: 10px;" shape="circle"
+						@click="submitUser()">保存</u-button>
+				</view>
+
+
+			</view>
+		</u-popup>
+		<u-modal v-model="delShow" @confirm="confirmDelete" confirm-color="#fa3534" :show-cancel-button="true"
+			ref="uModal" title="删除白名单用户" content="是否删除当前白名单用户?" confirm-text="删除"></u-modal>
+
+		<view class="floating-button">
+			<view class="button" @click="gotoUrl('/pages/deviceTab/dataLock?id='+id)" >
+
+				查看地锁
+			</view>
+
+		</view>
+
+
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/index.js'
+
+	export default {
+		data() {
+			return {
+				id: "",
+				floorlockInfo: {},
+				listShow: true,
+				popupShow: false,
+				customStyle: {
+					"border-radius": "50px",
+					"background-color": 'rgba(242, 244, 246, 1)',
+					padding: "5px 20px",
+					margin: "5px 0 ",
+					
+				},
+				abc:false,
+				whiteList: [],
+				vipUser: {},
+				delShow: false,
+				obj: {},
+				carshow: false,
+			};
+		},
+		onLoad(op) {
+			this.id = op.id
+			this.getFloorlockDetails()
+
+		},
+		methods: {
+			valInit(bl){
+				if(bl){
+					this.abc=this.vipUser.carNumber.length>0
+				}else{
+					if(this.vipUser.carNumber.length==1&&this.abc==false){
+						this.abc=true
+					}
+					if(this.vipUser.carNumber.length==0&&this.abc==true){
+						this.abc=false
+					}
+				}
+				
+			},
+			valChange(val){
+				
+				if(this.vipUser.carNumber.length>=8){
+					return
+				}
+				this.vipUser.carNumber+=val
+				this.valInit()
+				this.$forceUpdate()
+			},
+			backspace(){
+				//
+				var value=this.vipUser.carNumber
+				if(value.length){
+					value = value.substr(0, value.length - 1);
+					
+				}
+				this.vipUser.carNumber=value
+				this.valInit()
+				
+
+			},
+			getFloorlockDetails() {
+
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				var obj = {
+					id: this.id
+				}
+
+				API.floorlockDetails(obj).then((res) => {
+					this.floorlockInfo = res.data.floorlockInfo
+
+					uni.hideLoading();
+					this.getWhiteList()
+				}).catch(error => {
+
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			},
+			getWhiteList(bl) {
+
+				if (bl) {
+					uni.showLoading({
+						title: "加载中",
+						mask: true,
+					})
+				}
+				API.whiteList({
+					floorlockId: this.id
+				}).then((res) => {
+					this.whiteList = res.data.whiteList
+
+					if (bl) {
+						uni.hideLoading()
+						uni.showToast({
+							title: "操作成功"
+						})
+					}
+
+
+
+
+				}).catch(error => {
+
+					uni.showToast({
+						title: error
+					})
+				})
+
+
+			},
+			submitUser() {
+				if (!this.vipUser.nickName) {
+					uni.showToast({
+						title: "请填写白名单车主姓名"
+					})
+					return
+				}
+				if (!this.vipUser.phone) {
+					uni.showToast({
+						title: "请填写白名单车主手机号码"
+					})
+					return
+				}
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				this.vipUser.name = this.vipUser.nickName
+				API.addWhite(this.vipUser).then((res) => {
+					//this.obj = res.data
+					uni.hideLoading()
+
+					this.delShow = false
+					this.popupShow = false
+					this.getWhiteList(1)
+
+				}).catch(error => {
+
+					uni.showToast({
+						title: error
+					})
+				})
+
+
+			},
+			confirmDelete() {
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				API.deleteWhite({
+					id: this.vipUser.id
+				}).then((res) => {
+					//this.obj = res.data
+					uni.hideLoading()
+					this.delShow = false
+					this.popupShow = false
+					uni.showToast({
+						title: "操作成功"
+					})
+					this.getWhiteList(1)
+
+				}).catch(error => {
+
+					uni.showToast({
+						title: error
+					})
+				})
+			},
+			delUser() {
+				this.delShow = true;
+			},
+			editUser(item) {
+				this.popupShow = true;
+				this.vipUser = item;
+				this.vipUser.nickName = item.nickName
+
+
+				this.vipUser.floorlockId = this.id
+				if (this.vipUser.carNumber == 0) {
+					this.vipUser.carNumber = ''
+				}
+			},
+			addUser() {
+				if (this.whiteList.length >= 3) {
+					uni.showToast({
+						title: "添加白名单用户已达到上限"
+					})
+					return
+				}
+				this.popupShow = true;
+				this.vipUser = {
+					carNumber:""
+				}
+
+				this.vipUser.floorlockId = this.id
+
+			},
+
+
+		}
+	}
+</script>
+<style>
+	page {
+		background-color: rgba(242, 244, 246, 1);
+	}
+</style>
+<style lang="scss" scoped>
+	.gradient-header {
+		height: 0px;
+	}
+
+	.jpback {
+		height: 360rpx;
+		background: linear-gradient(180deg, rgba(22, 119, 255, 1) 11%, rgba(242, 244, 246, 1) 100%);
+	}
+
+	.body {
+		padding: 32rpx 32rpx 120rpx 32px;
+		//padding-bottom: ;
+	}
+
+	.page-top {
+		color: rgba(255, 255, 255, 1);
+		margin: 48rpx 0;
+
+		.text1 {
+			font-size: 36rpx;
+			margin-bottom: 12rpx;
+		}
+
+		.text2 {
+			font-size: 40rpx;
+
+		}
+	}
+
+	.page {
+		border-radius: 16rpx;
+		background-color: rgba(255, 255, 255, 1);
+		color: rgba(16, 16, 16, 1);
+
+		padding: 32rpx;
+		margin-bottom: 32rpx;
+		font-size: 32rpx;
+		color: rgb(16, 16, 16);
+
+		.info-title {
+			display: flex;
+			justify-content: space-between;
+			padding-bottom: 24rpx;
+
+			.name {
+				font-size: 36rpx;
+				color: rgba(51, 51, 51, 1);
+				font-weight: bold;
+
+				.span {
+					font-weight: 400;
+					font-size: 28rpx;
+					color: rgba(119, 119, 119, 1);
+				}
+			}
+
+			.value {
+				font-size: 28rpx;
+				color: rgba(119, 119, 119, 1);
+			}
+		}
+
+		.pack-up {
+
+
+			color: rgba(119, 119, 119, 100);
+		}
+
+		.tips {
+			margin-top: 12rpx;
+			display: flex;
+			align-items: flex-start;
+			font-size: 24rpx;
+		}
+
+		.table {
+			.table_v {
+				width: 100%;
+			}
+			.table_tr {
+				
+				 display: flex;
+				justify-content: space-between;
+			}
+
+			.row {
+				display: flex;
+				align-items: center;
+				height: 72rpx;
+				font-size: 28rpx;
+				padding: 0 24rpx;
+
+				.name {
+					width: 240rpx;
+				}
+
+			}
+
+			.table_td {
+
+				height: 72rpx;
+				font-size: 28rpx;
+				    display: flex;
+				    align-items: center;
+
+
+			}
+
+			/* 隔行变色: 偶数行设置背景色 */
+			.row:nth-child(odd) {
+				background-color: #f9f9f9;
+				/* 偶数行 */
+			}
+
+			.table_tr:nth-child(odd) {
+				background-color: #f9f9f9;
+				/* 偶数行 */
+			}
+
+			.row:nth-child(even) {
+				background-color: #ffffff;
+				/* 奇数行 */
+			}
+
+			.table_tr:nth-child(even) {
+				background-color: #ffffff;
+				/* 奇数行 */
+			}
+
+		}
+	}
+::v-deep.u-keyboard-grids-btn:nth-child(15){
+			background-color: red;
+		}
+	.popup-screen {
+		padding: 40rpx 40rpx 60rpx 40rpx;
+		.carNumber {
+			background-color: #F2F4F6;
+			padding: 5px 20px;
+			margin: 5px 0 15px 0;
+			height: 90rpx;
+			display: flex;
+			align-items: center;
+			border-radius: 50px;
+			
+		}
+		.carNumber1{
+			color: #bcbcbc;
+		}
+		
+
+		
+
+		.popup-title {
+			font-size: 36rpx;
+			color: rgba(51, 51, 51, 1);
+			font-weight: bold;
+			padding-bottom: 10px;
+		}
+
+		.cardList {
+			display: flex;
+			justify-content: space-evenly;
+
+			.cardInfo {
+				display: flex;
+				flex-direction: column;
+				justify-content: center;
+				width: 160rpx;
+				height: 160rpx;
+				border-radius: 8px;
+				background-color: rgba(255, 255, 255, 1);
+				text-align: center;
+				border: 1px solid rgba(187, 187, 187, 1);
+
+				.name {
+					color: rgba(16, 16, 16, 1);
+					font-size: 28rpx;
+				}
+
+				.price {
+					color: rgba(16, 16, 16, 1);
+					font-size: 48rpx;
+					font-weight: bold;
+				}
+			}
+
+			.cardInfoCk {
+				background-color: rgba(225, 247, 237, 1);
+				border: 1px solid rgba(0, 185, 98, 1);
+
+				.price {
+					color: rgba(0, 161, 85, 1);
+
+				}
+			}
+		}
+	}
+
+	.floating-button {
+		position: fixed;
+		bottom: 0;
+		/* 距离底部 20px */
+		width: 100%;
+		display: flex;
+		height: 120rpx;
+		justify-content: center;
+		background-color: rgba(255, 255, 255, 1);
+
+		.button {
+			margin-top: 24rpx;
+			border-radius: 50px;
+			height: 80rpx;
+			width: 80%;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			padding: 12rpx;
+
+			background-color: rgba(22, 119, 255, 1);
+			color: rgba(255, 255, 255, 1);
+			font-size: 36rpx;
+		}
+	}
+</style>

+ 2179 - 0
pages/index/index.vue

@@ -0,0 +1,2179 @@
+<template>
+	<view>
+		<u-navbar v-show="false" title="首页" title-color="#101010"></u-navbar>
+
+		<u-picker v-model="body2data.vue.show" :params="body2data.vue.params" :default-time="body2data.query.startTime"
+			@confirm="body2dataconfirm" mode="time"></u-picker>
+
+		<!-- <u-picker v-model="body5data.vue.show" :default-time="body5data.query.queryDate" :params="body5data.vue.params"
+			@confirm="body5dataconfirm" mode="time"></u-picker> -->
+			
+			<u-calendar v-model="body5data.vue.show" mode="date" @change="body5dataconfirm"></u-calendar>
+
+
+		<view class="navbar">
+			智泊e家 运管端
+
+		</view>
+		<view class="tabs-box">
+
+			<u-picker-jp v-model="showselect1" range-key="name" :num="3" @confirm="showselect1confirm"
+				:range="companyList"></u-picker-jp>
+
+			<template v-if="companyListTabs.length>2">
+				<u-tabs ref="tabs" :list="companyListTabs" bg-color="#1677ff" :current="current1" inactive-color="#fff"
+					@change="utabsChange1" item-width="180" height="70" gutter="10" active-color="#fff"></u-tabs>
+				<view class="tabs-box-other" v-if="companyList.length>3" @click="utabsChange1other">
+					更多
+				</view>
+			</template>
+
+		</view>
+
+		<view class="main">
+
+			<u-picker-jp v-model="showselect2" range-key="name" :num='3' @confirm="showselect2confirm"
+				:range="parkingList"></u-picker-jp>
+
+			<view class="tabs-box2" v-show="parkingListTabs.length>2">
+				<u-tabs ref="tabs2" gutter="10" :list="parkingListTabs" :current="current2" @change="utabsChange2"
+					item-width="180" bg-color="#f2f4f6" height="70"></u-tabs>
+				<view v-if="parkingList.length>3" class="tabs-box-other" @click="utabsChange2other">
+					更多
+				</view>
+			</view>
+
+			<view class="statistics ">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						综合统计
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body1">
+						<view class="body1pie-table">
+							<view class="tr">
+								<view class="td td1">
+									<view id="body1pie1" class="body1pie">
+
+									</view>
+								</view>
+								<view class="td td2">
+									<view class="td td3">
+										<view class="td td4">空闲<span
+												class="body1pie-num color53B56B">{{body1data.data.idleNum}}</span>台
+										</view>
+										<view class="td td4">占用<span
+												class="body1pie-num colorAAAAAA">{{body1data.data.useNum}}</span>台
+										</view>
+									</view>
+									<view class="td td3">
+
+										<view class="td td4">公共车位<span
+												class="body1pie-num colorEF8132">{{body1data.data.publicNum}}</span>台
+										</view>
+										<view class="td td4">私家车位<span
+												class="body1pie-num colorDC4441">{{body1data.data.privateNum}}</span>台
+										</view>
+									</view>
+								</view>
+
+							</view>
+
+							<view class="tr">
+								<view class="td td1">
+									<view id="body1pie2" class="body1pie">
+
+									</view>
+								</view>
+								<view class="td td2">
+									<view class="td td3">
+
+										<view class="td td4">正常<span
+												class="body1pie-num color53B56B">{{body1data.data.normalNum}}</span>台
+										</view>
+										<view class="td td4">离线<span
+												class="body1pie-num colorAAAAAA">{{body1data.data.loseNum}}</span>台
+										</view>
+									</view>
+									<view class="td td3">
+
+										<view class="td td4">故障<span
+												class="body1pie-num colorEF8132">{{body1data.data.errorNum}}</span>台
+										</view>
+										<view class="td td4" v-if="0">低电量<span
+												class="body1pie-num colorDC4441">5</span>台</view>
+									</view>
+								</view>
+							</view>
+
+							<view class="tr" v-if="0">
+								<view class="td td1">
+									<view id="body1pie3" class="body1pie">
+
+									</view>
+								</view>
+								<view class="td td2">
+									<view class="td td3">
+
+										<view class="td td4">管理员<span class="body1pie-num color307AF6">5</span>人</view>
+										<view class="td td4">白名单<span class="body1pie-num color53B56B">5</span>人</view>
+									</view>
+									<view class="td td3">
+
+										<view class="td td4">游客<span class="body1pie-num colorEF8375">5</span>人次</view>
+										<view class="td td4"></view>
+									</view>
+								</view>
+
+							</view>
+
+
+						</view>
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics " v-show="1||companyId">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>地锁列表</view>
+			
+						<view class="check-all" @click="gotoDeviceList()">查看全部<u-icon name="arrow-right"></u-icon>
+						</view>
+			
+					</view>
+			
+				</view>
+			
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body7">
+						<view class="body7main">
+							<view class="line" v-for="(item,index) in equipmentList"
+								@click="gotoUrl('/pages/deviceTab/dataLock?id='+item.id)" :key="index">
+								<view class="item">
+									<!-- 
+								 -->
+									<view class="item-title">
+										
+										<view class="item-name">
+											{{item.name}}
+										</view>
+										<view class="item-tags">
+											<view class="tag  " :class="'tag'+item.type">
+												{{item.typeN}}
+													
+											</view>
+											
+											<view class="tag" :class="'lockStatus lockStatus'+item.lockStatus">
+												{{item.lockStatusN}}
+											</view>
+										</view>
+									</view>
+									<view class="item-body">
+										<span>编号:{{item.lockNo}}</span> <span v-if="item.batteryLevel" style="    margin-left: 16rpx;">电压:{{item.batteryLevel}}V</span>
+									</view>
+			
+								</view>
+								<view class="goto">
+									<view  :class="'statusN statusN'+item.status">
+										{{item.status==1?'在线':'离线'}}
+											
+									</view>
+									<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+								</view>
+								
+							</view>
+							<u-divider border-color="#CFD2D5" @click="gotoDeviceList()"
+								v-if="equipmentList.length==10">最多显示10条,点击查看更多</u-divider>
+			
+						</view>
+			
+			
+			
+					</jpContent>
+				</view>
+			</view>
+			
+			<view class="statistics " v-show="1||companyId">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>停车记录</view>
+			
+						<view class="check-all" @click="gotoUrl('/pages/record/parkingRecord?compamyId='+companyId+'&parkingId='+parkingId)">查看全部<u-icon name="arrow-right"></u-icon>
+						</view>
+			
+					</view>
+			
+				</view>
+			
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body8">
+						<view class="body8main">
+							<view class="line" v-for="(item,index) in parkingRecord"
+								@click="gotoUrl('/pages/record/parkingInfo?id='+item.id)" :key="index">
+								
+								<view class="data">
+									
+									<view class="view3">
+										<u-icon name="clock"></u-icon>
+										{{showTime(item.startTime)}}
+										<template v-if="item.status!=0">
+											{{item.endTime?'-'+showTime(item.endTime):'-当前'}}
+										</template>
+										
+									</view>
+									<view class="view1">
+										{{item.parkingName}} {{item.lockName}}
+									</view>
+								</view>
+								<view class="goto " :class="'status'+item.status">
+									{{item.status==2?getTime(item):''}}
+									{{item.status==1?'使用中':''}}
+									{{item.status==0?'启动中':''}}
+								
+									<u-icon name="arrow-right" size="24" style="margin-left: 8rpx;" color="#BBBBBB"></u-icon>
+								
+								</view>
+								
+								
+							</view>
+							<u-divider border-color="#CFD2D5" @click="gotoUrl('/pages/record/parkingRecord?compamyId='+companyId+'&parkingId='+parkingId)"
+								v-if="parkingRecord.length==5">最多显示5条,点击查看更多</u-divider>
+			
+						</view>
+			
+			
+			
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics ">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>时空矩阵图</view>
+
+						<view class="tag" @click="body5data.vue.show=true">{{body5data.vue.queryN}}<u-icon
+								name="arrow-down"></u-icon></view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body5">
+						<view class="body5main">
+
+							<view id="body5echart" class="body5class">
+
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics " v-show="companyId">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>车位异常记录</view>
+
+						<view class="check-all" @click="gotoUrl('/pages/myTab/abnormalList?companyId='+companyId)">
+							查看全部<u-icon name="arrow-right"></u-icon></view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body6">
+						<view class="body6main">
+							<view class="line" v-for="(item,index) in abnormalRecordsList" :key="index">
+								<view class="abnormal-item">
+									<!-- @click="gotoUrl('/pages/abnormal/abnormalAlarmDetails?id='+item.id)"
+								 -->
+									<view class="item-title">
+
+										<view class="name">
+											<span v-if="item.level==1" class="level level1 ">一级</span>
+											<span v-if="item.level==2" class="level level2">二级</span>
+
+											{{item.content}}
+										</view>
+										<view class="date"
+											style="display: flex;    justify-content: space-between;margin-top: 4rpx;">
+											<view>{{item.title}}</view>
+											<view>{{item.createTime}}</view>
+
+										</view>
+									</view>
+
+								</view>
+								<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics ">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>车位平均占用率(%)</view>
+						<view class="tag" @click="body2data.vue.show=true">{{body2data.vue.queryN}}<u-icon
+								name="arrow-down"></u-icon></view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body2">
+						<view class="body2lineChart">
+
+							<view id="body2line1" class="body2line">
+
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics ">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>高频使用时段分布</view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body3">
+						<view class="body3barChart">
+
+							<view id="body3bar1" class="body3bar">
+
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics ">
+				<view class="title">
+					<view class="icon">
+						<image class="img" src="@/assets/img/circleCopy1@1x.png" mode=""></image>
+					</view>
+					<view class="text">
+						<view>用户停留时长分群特征</view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body4">
+						<view class="body4pieChart">
+
+							<view id="body4pie1" class="body4pie">
+
+							</view>
+
+						</view>
+
+
+
+					</jpContent>
+				</view>
+			</view>
+
+
+			
+			<u-divider border-color="#CFD2D5">已经到底了</u-divider>
+
+		</view>
+		<tabbar :current="0"></tabbar>
+
+	</view>
+</template>
+
+<script>
+	import Tabbar from '@/components/Tabbar.vue'
+	import jpContent from '@/components/JPcontent.vue'
+	import * as echarts from 'echarts';
+
+	import * as API from '@/apis/pagejs/index.js'
+
+	import {
+		parseUnixTime,
+		beforeTimeStamp,
+		newDate
+	} from '@/apis/utils'
+
+
+	export default {
+		components: {
+			Tabbar,
+			jpContent
+		},
+		data() {
+			return {
+				current1: 0,
+				showselect1: false,
+				current2: 0,
+				showselect2: false,
+				isReady: false,
+				companyList: [],
+				parkingList: [],
+				//companyListIndex:0,
+				companyId: "",
+				parkingId: "",
+				echartsList: {},
+				parkingRecord:[],
+				equipmentList: [],
+				abnormalRecordsList: [{
+						level: 1,
+						content: "1111111",
+						title: "11",
+						createTime: "123:123"
+					},
+					{
+						level: 2,
+						content: "1111111",
+						title: "11",
+						createTime: "123:123"
+					}
+				],
+				body2data: {
+					query: {},
+					vue: {
+						queryN: "",
+						show: false,
+						params: {
+							year: true,
+							month: true,
+							day: false,
+							hour: false,
+							minute: false,
+							second: false
+						}
+					},
+					data: {}
+				},
+				body1data: {
+					query: {},
+					data: {},
+					data1: {}
+				},
+				body4data: {
+					query: {},
+					data: {}
+				},
+				body3data: {
+					query: {},
+					data: {}
+				},
+
+				body5data: {
+					query: {},
+					data: {},
+					vue: {
+						queryN: "",
+						show: false,
+						params: {
+							year: true,
+							month: true,
+							day: true,
+							hour: false,
+							minute: false,
+							second: false
+						}
+					},
+				},
+				jpContentMap: {
+					body1: 0,
+					body2: 0,
+					body3: 0,
+					body4: 0,
+					body5: 0,
+					body6: 1,
+					body7: 0,
+					body8: 0,
+					body9: 0,
+					body10: 0,
+				}
+			}
+		},
+		onLoad() {
+
+		},
+		onReady() {
+			this.getfindByOpenId();
+		},
+		computed: {
+			companyListTabs() {
+				var sz = []
+
+				if (this.companyList.length > 3) {
+					sz = [{
+						id: "",
+						name: '全部'
+					}]
+					sz.push(this.companyList[0])
+					sz.push(this.companyList[1])
+				} else {
+					sz = [{
+							id: "",
+							name: '全部'
+						},
+						...this.companyList
+					]
+				}
+
+				return sz
+			},
+			parkingListTabs() {
+				var sz = []
+				if (this.parkingList.length > 3) {
+					sz = [{
+						id: "",
+						name: '综合查询'
+					}]
+					sz.push(this.parkingList[0])
+					sz.push(this.parkingList[1])
+				} else {
+					sz = [{
+							id: "",
+							name: '综合查询'
+						},
+						...this.parkingList
+					]
+				}
+
+				return sz
+			},
+		},
+		methods: {
+			
+			showTime(time){
+					if(time){
+						return time.substr(5).replace('-','.')
+					}else{
+						return ''
+					}
+			},
+			getTime(item){
+				if(item.startTime&&item.endTime){
+					var stime=newDate(item.startTime)
+					var etime=newDate(item.endTime)
+					//etime=new Date()
+					var k=(etime.getTime()-stime.getTime())/1000/60
+					
+					var H=k/60
+					var fen=k%(60)
+					var str="";
+					if(k>60){
+						str+=parseInt(H)+'小时'
+					}
+					if(fen==0&&str!=''){
+						
+					}else{
+						str+=parseInt(fen)+'分钟'
+					}
+					return str
+				}else{
+					return '已完成'
+				}
+			},
+			
+			gotoDeviceList() {
+				if (this.parkingId) {
+					this.gotoUrl('/pages/deviceTab/deviceList?parkingId=' + this.parkingId)
+				} else {
+					
+					uni.switchTab({
+							url: '/pages/deviceTab/index'
+						})
+					
+				}
+			},
+			getfloorStatus() {
+				this.jpContentMap.body1 = 0
+
+				API.floorStatus({
+					companyId: this.companyId,
+					parkingId: this.parkingId
+				}).then((response) => {
+					this.body1data.data = response.data
+					uni.hideLoading();
+					this.jpContentMap.body1 = 2
+
+					this.getbody1pie1()
+					this.getbody1pie2()
+					this.getbody1pie3()
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+
+				})
+
+			},
+			getParkingRecordList() {
+				this.jpContentMap.body8 = 0
+			
+				API.parkingRecordList({
+					companyId: this.companyId,
+					parkingId: this.parkingId,
+					pageSize: 5
+				}).then((response) => {
+					
+					uni.hideLoading();
+					if (response.data.totalPage) {
+						this.jpContentMap.body8 = 2
+						this.parkingRecord = response.data.data
+					
+					} else {
+						this.jpContentMap.body8 = 1
+					}
+			
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+			
+				})
+			
+			},
+			getfloorlockList() {
+				this.jpContentMap.body7 = 0
+
+				API.floorlockList({
+					companyId: this.companyId,
+					parkingId: this.parkingId,
+					pageSize: 10
+				}).then((response) => {
+
+					uni.hideLoading();
+					if (response.data.totalPage) {
+						this.jpContentMap.body7 = 2
+						this.equipmentList = response.data.data
+					
+
+					} else {
+						this.jpContentMap.body7 = 1
+					}
+
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+
+				})
+			},
+			getApi1() {
+
+				if (this.companyId == "") {
+
+					this.getApi2()
+				} else {
+					this.parkingInfoList()
+				}
+
+			},
+			getApi2() {
+				this.getfloorStatus()
+				this.getfloorlockList()
+				this.occupancyByTime(1);
+				this.occupancyByTimeBar(1);
+				this.occupancyByDay(1);
+				this.durationDistribution();
+				this.getParkingRecordList()
+				if (this.parkingId == "") {
+
+				} else {
+
+				}
+			},
+			change1companyList(i) {
+				//this.companyListIndex=i
+				var companyId = ""
+
+				if (i == -1) {
+					if (this.companyId == companyId) {
+
+					} else {
+						this.companyId = ""
+						this.parkingList = [];
+						this.getApi1()
+					}
+				} else {
+					var item = this.companyList[i]
+					companyId = item.id
+					if (this.companyId == companyId) {
+
+					} else {
+						this.companyId = companyId
+
+						this.parkingId = "";
+						this.current2 = 0;
+						this.$refs.tabs2.showBar = true
+
+						this.getApi1()
+					}
+				}
+
+			},
+			change2parkingList(i) {
+
+				var parkingId = ""
+
+				if (i == -1) {
+
+					if (this.parkingId == parkingId) {
+
+					} else {
+						this.parkingId = "";
+						this.getApi2()
+
+					}
+				} else {
+					var item = this.parkingList[i]
+					parkingId = item.id
+					if (this.parkingId == parkingId) {
+
+					} else {
+						this.parkingId = parkingId;
+						this.getApi2()
+					}
+				}
+
+			},
+			showselect2confirm(e) {
+
+				this.change2parkingList(e[0])
+			},
+			utabsChange2other() {
+				this.$refs.tabs2.showBar = false
+				this.current2 = -1;
+				this.showselect2 = true;
+			},
+			utabsChange2(index) {
+				this.current2 = index;
+				this.change2parkingList(index - 1)
+				this.$refs.tabs2.showBar = true
+			},
+
+			showselect1confirm(e) {
+
+				this.change1companyList(e[0])
+			},
+
+			utabsChange1other() {
+				this.$refs.tabs.showBar = false
+				this.current1 = -1;
+				this.showselect1 = true;
+			},
+			utabsChange1(index) {
+				this.current1 = index;
+				this.change1companyList(index - 1)
+				this.$refs.tabs.showBar = true
+			},
+			parkingInfoList() {
+
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				this.parkingList = [];
+
+				API.parkingList({
+					companyId: this.companyId,
+					pageSize: 999
+				}).then((response) => {
+
+					uni.hideLoading();
+					var parkingInfoList = response.data.parkingInfoList
+					this.parkingList = [
+						...parkingInfoList,
+					];
+
+					if (this.parkingList.length == 1) {
+
+						this.change2parkingList(0)
+
+					} else {
+						this.change2parkingList(-1)
+						this.getApi2()
+					}
+
+					this.getfloorlockList()
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+
+				})
+			},
+			companyInfoList() {
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				this.companyList = [];
+
+				API.companyInfoList({
+
+				}).then((response) => {
+
+					uni.hideLoading();
+					var companyInfoList = response.data.companyInfoList
+					this.companyList = [
+						...companyInfoList,
+
+					];
+
+					if (this.companyList.length == 1) {
+						this.change1companyList(0)
+					} else {
+						this.change1companyList(-1)
+						this.getApi1()
+					}
+
+
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+
+				})
+			},
+			init() {
+				this.companyInfoList()
+
+				//this.occupancyByTime();
+
+				//this.getbody3()
+				//this.getbody4()
+
+				//this.getbody5()
+
+
+			},
+			body2dataconfirm(e) {
+
+				var date = new Date(e.year + "-" + e.month + "-1");
+				this.body2data.vue.queryN = date.getFullYear() + "年" + (date.getMonth() + 1) + '月';
+				this.body2data.query.startTime = date.getFullYear() + "-" + (date.getMonth() + 1) + "-1"
+
+				var endOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0)
+				this.body2data.query.endTime = parseUnixTime(endOfMonth, '{y}-{m}-{d}')
+
+				this.occupancyByTime()
+			},
+			body5dataconfirm(e) {
+				console.log(e)
+				var date = new Date(e.year + "-" + e.month + "-" + e.day);
+				this.body5data.query.queryDate = parseUnixTime(date, '{y}-{m}-{d}')
+				this.body5data.vue.queryN = parseUnixTime(date, '{y}年{m}月{d}日');
+
+				this.occupancyByDay()
+			},
+			occupancyByTimeBar(init) {
+				if (init) {
+					var date = new Date();
+					//test
+					//this.body3data.query.startTime = date.getFullYear() + "-" + (date.getMonth() + 1) + "-1"
+
+					var endOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0)
+					//this.body3data.query.endTime = parseUnixTime(endOfMonth, '{y}-{m}-{d}')
+
+				}
+				this.jpContentMap.body3 = 0
+				this.body3data.query.companyId = this.companyId
+				this.body3data.query.parkingId = this.parkingId
+				API.occupancyByTimeBar(
+					this.body3data.query
+				).then((response) => {
+					this.body3data.data = [
+						...response.data.locksTimeList,
+						//	...response.data.locksTimeList,
+					];
+
+					if (this.body3data.data.length == 0) {
+						this.jpContentMap.body3 = 1
+
+					} else {
+						this.jpContentMap.body3 = 2
+						this.getbody3()
+
+					}
+
+
+
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+
+				})
+			},
+			durationDistribution() {
+				this.jpContentMap.body4 = 0
+
+				var date = new Date();
+				//test
+				//this.body4data.query.startTime = date.getFullYear() + "-" + (date.getMonth() + 1) + "-1"
+
+				var endOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0)
+			//	this.body4data.query.endTime = parseUnixTime(endOfMonth, '{y}-{m}-{d}')
+
+
+
+				this.body4data.query.companyId = this.companyId
+				this.body4data.query.parkingId = this.parkingId
+				API.durationDistribution(
+					this.body4data.query
+				).then((response) => {
+					this.body4data.data = response.data.distribution;
+
+					if (this.body4data.data.length == 0) {
+						this.jpContentMap.body4 = 1
+
+					} else {
+						this.jpContentMap.body4 = 2
+						//this.getbody3()
+						this.getbody4()
+					}
+
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+
+				})
+			},
+			occupancyByDay(init) {
+				if (init) {
+					var date = new Date();
+
+					this.body5data.query.queryDate = parseUnixTime(date, '{y}-{m}-{d}')
+					this.body5data.vue.queryN = parseUnixTime(date, '{y}年{m}月{d}日');
+
+				}
+				this.jpContentMap.body5 = 0
+				this.body5data.query.companyId = this.companyId
+				this.body5data.query.parkingId = this.parkingId
+				API.occupancyByDay(
+					this.body5data.query
+				).then((response) => {
+					this.body5data.data = [
+						...response.data.locksTimeList,
+
+					];
+
+					if (this.body5data.data.length == 0) {
+						this.jpContentMap.body5 = 1
+
+					} else {
+						this.jpContentMap.body5 = 2
+						//this.getbody3()
+						this.getbody5()
+					}
+
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+
+				})
+			},
+			occupancyByTime(init) {
+				if (init) {
+					var date = new Date();
+
+					this.body2data.vue.queryN = date.getFullYear() + "年" + (date.getMonth() + 1) + '月';
+					this.body2data.query.startTime = date.getFullYear() + "-" + (date.getMonth() + 1) + "-1"
+
+					var endOfMonth = new Date(date.getFullYear(), date.getMonth() + 1, 0)
+					this.body2data.query.endTime = parseUnixTime(endOfMonth, '{y}-{m}-{d}')
+
+				}
+				this.jpContentMap.body2 = 0
+				this.body2data.query.companyId = this.companyId
+				this.body2data.query.parkingId = this.parkingId
+				API.occupancyByTime(
+					this.body2data.query
+				).then((response) => {
+					this.body2data.data = [
+						...response.data.locksTimeList,
+						//	...response.data.locksTimeList,
+					];
+
+					if (this.body2data.data.length == 0) {
+						this.jpContentMap.body2 = 1
+
+
+					} else {
+						this.jpContentMap.body2 = 2
+
+						this.getbody2()
+
+
+					}
+
+
+
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+
+				})
+			},
+			getbody5() {
+				// 颜色映射
+				var colorMap = [
+
+					'#FFA500',
+					'#00FF00',
+					'#F44336',
+					'#E91E63',
+					'#9C27B0',
+					'#673AB7',
+					'#3F51B5',
+					'#2196F3',
+					'#03A9F4',
+					'#00BCD4',
+					'#009688',
+					'#CDDC39',
+					'#FFEB3B',
+					'#FFC107',
+					'#FF9800',
+					'#FF5722',
+					'#795548',
+					'#607D8B'
+				];
+
+				var key = "body5echart"
+				var dataApi = this.body5data.data;
+
+				var head = 40 * (parseInt(dataApi.length / 4)) + 20
+				var body = 20 * (parseInt(dataApi.length))
+
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(300 * 2),
+						height: uni.upx2px((170 + head) * 2 + body)
+					})
+
+				}
+				myChart.clear()
+				var dataName = []
+				var dataTime = []
+				var series = []
+				var i = 0;
+				var isPush=false
+				dataApi.forEach(item => {
+
+					dataName.push(item.lockName)
+					var itemList = []
+					var j = 0
+					item.timeUseList.forEach(item2 => {
+
+						Object.keys(item2).forEach(key1 => {
+							console.log(item2[key1])
+							if (item2[key1]) {
+								var ob = [j, i, i]
+								itemList.push(ob)
+								isPush=true
+							} else {
+								// var ob=[j,i,i]
+								// itemList.push(ob)
+							}
+						});
+						j += 1;
+
+					})
+
+
+					var obj = {
+						tooltip: {
+							trigger: 'item',
+							axisPointer: {
+								type: 'shadow'
+							},
+							formatter: function(params) {
+								console.log(params)
+								var result = params.marker+params.name +'点<br/>' + params.seriesName  + ' 占用 ';
+								
+								return result;
+							}
+						},
+						//silent: true,
+						type: 'custom',
+						"name": item.lockName,
+						// tooltip: {
+						// 	//trigger: 'none',
+						// 	show: false
+						// },
+						itemStyle: {
+							color: colorMap[i % colorMap.length]
+						},
+						renderItem: function(params, api) {
+							var xIndex = api.value(0); // x轴索引
+							var yIndex = api.value(1); // y轴索引
+							var value = api.value(2); // 值
+
+							// 获取颜色
+							var color = colorMap[value % colorMap.length] || '#ffffff';
+
+							// 计算矩形的位置和大小
+							var x = api.coord([xIndex, yIndex])[0];
+							var y = api.coord([xIndex, yIndex])[1];
+							var width = api.size([1, 0])[0];
+							var height = api.size([0, 1])[1];
+
+							return {
+								type: 'rect',
+
+								shape: {
+									x: x - uni.upx2px(25),
+									y: y - uni.upx2px(20),
+									width: width,
+									height: 20,
+								},
+								style: {
+									fill: color
+								}
+							};
+						},
+
+					}
+					obj.data = itemList
+					series.push(obj)
+					i += 1;
+
+				})
+				dataApi[0].timeUseList.forEach(item => {
+
+					Object.keys(item).forEach(key1 => {
+						dataTime.push(key1)
+					});
+
+				})
+
+				var option = {
+					tooltip: {
+						trigger: 'axis',
+						axisPointer: {
+							type: 'shadow'
+						}
+					},
+					grid: {
+						top: 30 + head,
+						left: -10+(isPush?0:20),
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					legend: {
+						data: dataName
+					},
+					xAxis: {
+						type: 'category',
+						data: dataTime
+					},
+					yAxis: {
+						type: 'category',
+
+					},
+					series: series
+				};
+
+
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+			getbody4() {
+				var key = "body4pie1"
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(300 * 2),
+						height: uni.upx2px(170 * 2)
+					})
+
+				}
+				myChart.clear()
+				var dataApi = this.body4data.data;
+
+				var data = []
+				var num = 0
+				var sum = 0
+				Object.keys(dataApi).forEach(key1 => {
+					num += dataApi[key1]
+				});
+				var i = 0
+				Object.keys(dataApi).forEach(key1 => {
+					var value = dataApi[key1]
+					if(value!=0){
+						
+					
+						var obj = {
+							value: value,
+							name: key1
+						}
+
+						if (num != 0) {
+							var valueInt = parseInt(value / num * 100)
+							if (valueInt == 0 && value != 0) {
+								valueInt = 1
+							}
+							sum += valueInt;
+
+							if (i == Object.keys(dataApi).length - 1) {
+								if (sum != 100) {
+									valueInt += (100 - sum)
+								}
+							}
+							obj.name += '\n' + (valueInt) + '%'
+						}
+						data.push(obj)
+					}
+					i++;
+				});
+
+
+
+				var option = {
+					
+					grid: {
+						top: 20,
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					series: [{
+
+						type: 'pie',
+						radius: ['80%', '50%'],
+						radius: [45, 60],
+						data: data
+
+					}]
+				};
+				console.log(option)
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+			getbody3() {
+				var key = "body3bar1"
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(300 * 2),
+						height: uni.upx2px(170 * 2)
+					})
+
+				}
+				var dataApi = this.body3data.data;
+
+				myChart.clear()
+
+				var data1 = []
+				var data2 = [] //useDays
+				var i = 0
+				dataApi[0].timeUseList.forEach(item => {
+
+					Object.keys(item).forEach(key1 => {
+
+						data1.push(key1 + '点')
+						var num = 0
+
+						dataApi.forEach(item2 => {
+							num += item2.timeUseList[i][key1].useDays
+
+						})
+						data2.push(num)
+					});
+					i += 1
+
+				})
+
+				var axisLabel = {
+					rotate: 40,
+					interval: 0,
+					textStyle: {
+						color: "#333"
+					}
+				}
+				if (data1.length < 7) {
+					axisLabel = {
+						interval: 0,
+						textStyle: {
+							color: "#333"
+						},
+					}
+				} else {
+					axisLabel.interval = 0;
+				}
+				var option = {
+					xAxis: {
+						type: 'category',
+						data: data1,
+						axisLabel: axisLabel,
+					},
+					tooltip: {
+						trigger: 'axis',
+						axisPointer: {
+							type: 'shadow'
+						},
+						formatter: function(params) {
+							var result = params[0].name + '<br/>';
+							for (var i = 0; i < params.length; i++) {
+								result += params[i].marker+ ' ' + params[i].value + '次<br/>';
+							}
+							return result;
+						}
+					},
+					yAxis: {
+						type: 'value'
+					},
+					grid: {
+						top: 20,
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					series: [{
+						itemStyle: {
+							color: "#5A88E5"
+						},
+						data: data2,
+						type: 'bar'
+					}]
+				};
+
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+			getbody2() {
+				var key = "body2line1"
+				var myChart = this.echartsList[key];
+				var dataApi = this.body2data.data;
+
+				var head = 20 * (parseInt(dataApi.length / 4)) + 20
+
+
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(300 * 2),
+						height: uni.upx2px((170 + head) * 2)
+					})
+
+				}
+				myChart.clear()
+
+				var data1 = []
+				var series = [];
+
+				dataApi.forEach(item => {
+
+					var obj = {
+						name: item.lockName,
+						//areaStyle: {},
+						// itemStyle: {
+						// 	color: "#BBD4FB"
+						// },
+						label: {
+							show: true,
+							position: 'top',
+							//	color: "#307AF6"
+						},
+						data: [],
+						type: 'line'
+					}
+					if (dataApi.length == 1) {
+						obj.label.color = "#307AF6"
+						obj.areaStyle = {}
+						obj.itemStyle = {
+							color: "#BBD4FB"
+						}
+					}
+
+					item.timeUseList.forEach(item2 => {
+						Object.keys(item2).forEach(key1 => {
+
+							obj.data.push(item2[key1].useRate)
+						});
+					})
+					series.push(obj)
+				})
+				dataApi[0].timeUseList.forEach(item => {
+
+					Object.keys(item).forEach(key1 => {
+						data1.push(key1)
+
+					});
+
+				})
+
+				var axisLabel = {
+					rotate: 40,
+					interval: 0,
+					textStyle: {
+						color: "#333"
+					}
+				}
+				if (data1.length < 7) {
+					axisLabel = {
+						interval: 0,
+						textStyle: {
+							color: "#333"
+						},
+					}
+				} else {
+					axisLabel.interval = 0;
+				}
+				var option = {
+					legend: {},
+					xAxis: {
+						type: 'category',
+						data: data1,
+						axisLabel: axisLabel,
+					},
+					tooltip: {
+						trigger: 'axis',
+						axisPointer: {
+							type: 'shadow'
+						},
+
+						formatter: function(params) {
+							var result = params[0].name + '点<br/>';
+							for (var i = 0; i < params.length; i++) {
+								result += params[i].marker+params[i].seriesName + ': ' + params[i].value + '%<br/>';
+							}
+							return result;
+						}
+					},
+					yAxis: {
+						type: 'value'
+					},
+					grid: {
+						top: (20 + head),
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					series: series
+				};
+
+
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+			getbody1pie1() {
+				var img = require("@/assets/img/index/pie1-1.svg")
+				var key = "body1pie1"
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(88),
+						height: uni.upx2px(88)
+					})
+
+				}
+				myChart.clear()
+				var option = {
+
+					series: [{
+						silent: true,
+						type: 'pie',
+						radius: ['70%', '100%'],
+						label: {
+							show: false,
+						},
+
+						data: [{
+								value: this.body1data.data.useNum,
+								itemStyle: {
+									color: '#AAAAAA'
+								}
+							},
+							{
+								value: this.body1data.data.idleNum,
+								itemStyle: {
+									color: '#53B56B'
+								}
+							}
+						]
+					}],
+					grid: {
+						top: 0,
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					graphic: [{
+						type: 'image',
+						id: 'logo',
+						left: 'center',
+						top: 'center',
+						style: {
+							image: img, // 图片路径
+							width: uni.upx2px(40),
+							height: uni.upx2px(40)
+						}
+					}]
+				}
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+			getbody1pie2() {
+				var img = require("@/assets/img/index/pie1-2.svg")
+
+				var key = "body1pie2"
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(88),
+						height: uni.upx2px(88)
+					})
+
+				}
+				myChart.clear()
+				var option = {
+
+					series: [{
+						silent: true,
+						type: 'pie',
+						radius: ['70%', '100%'],
+						label: {
+							show: false,
+						},
+
+						data: [{
+								value: this.body1data.data.loseNum,
+								itemStyle: {
+									color: '#AAAAAA'
+								}
+							},
+							{
+								value: this.body1data.data.normalNum,
+								itemStyle: {
+									color: '#53B56B'
+								}
+							},
+							{
+								value: this.body1data.data.errorNum,
+								itemStyle: {
+									color: '#EF8132'
+								}
+							}
+							//, {
+							// 	value: 735,
+							// 	itemStyle: {
+							// 		color: '#DC4441'
+							// 	}
+							// }
+						]
+					}],
+					grid: {
+						top: 0,
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					graphic: [{
+						type: 'image',
+						id: 'logo',
+						left: 'center',
+						top: 'center',
+						style: {
+							image: img, // 图片路径
+							width: uni.upx2px(40),
+							height: uni.upx2px(40)
+						}
+					}]
+				}
+
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+			getbody1pie3() {
+				var img = require("@/assets/img/index/pie1-3.svg")
+
+				var key = "body1pie3"
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(88),
+						height: uni.upx2px(88)
+					})
+
+				}
+				myChart.clear()
+				var option = {
+
+					series: [{
+						type: 'pie',
+						silent: true, // 禁用交互效果
+
+						radius: ['70%', '100%'],
+						label: {
+							show: false,
+						},
+
+						data: [{
+								value: 735,
+								itemStyle: {
+									color: '#53B56B'
+								}
+							},
+							{
+								value: 735,
+								itemStyle: {
+									color: '#EF8375'
+								}
+							},
+							{
+								value: 735,
+								itemStyle: {
+									color: '#307AF6'
+								}
+							}
+						]
+					}],
+					grid: {
+						top: 0,
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+					graphic: [{
+						type: 'image',
+						id: 'logo',
+						left: 'center',
+						top: 'center',
+						style: {
+							image: img, // 图片路径
+							width: uni.upx2px(40),
+							height: uni.upx2px(40)
+						}
+					}]
+				}
+				myChart.setOption(option);
+				this.echartsList[key] = myChart;
+			},
+
+			getfindByOpenId() {
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				API.findByOpenId({
+					openId: this.jphelp.getOpenId(),
+				}).then((response) => {
+
+					uni.hideLoading();
+					this.isReady = true;
+					this.loginset(response)
+					try {
+						this.init()
+					} catch (e) {
+
+						uni.showToast({
+							title: e,
+							icon: "none"
+						})
+					}
+
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+					uni.redirectTo({
+						url: '/pages/login/login'
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.color307AF6 {
+		color: #307AF6
+	}
+
+	.color53B56B {
+		color: #53B56B
+	}
+
+	.colorAAAAAA {
+		color: #AAAAAA
+	}
+
+	.colorEF8132 {
+		color: #EF8132
+	}
+
+	.colorDC4441 {
+		color: #DC4441
+	}
+
+	.colorEF8375 {
+		color: #EF8375
+	}
+
+	.body1pie-table {
+		color: rgba(51, 51, 51, 1);
+		font-size: 32rpx;
+		font-weight: bold;
+
+		.tr {
+			.td1 {
+				padding-right: 24rpx;
+			}
+
+			display: flex;
+			margin-bottom: 40rpx;
+
+			.td2 {
+
+				width: 100%;
+
+				.td3 {
+					display: flex;
+
+					.td4 {
+						width: 120px;
+					}
+				}
+			}
+		}
+
+		// td{
+		// 	padding-right: 24rpx;
+
+		// }
+		.body1pie {}
+
+		.body1pie-num {
+			margin: 0 8rpx;
+		}
+	}
+
+	// 导航栏
+	.navbar {
+
+		box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.15);
+		background-color: rgba(22, 119, 255, 1);
+		color: #fff;
+		line-height: 88rpx;
+		display: flex;
+		justify-content: space-between;
+		align-items: center;
+		padding: 0 32rpx;
+		color: rgba(255, 255, 255, 1);
+		font-size: 36rpx;
+		position: fixed;
+		left: 0;
+		right: 0;
+		top: 0;
+		z-index: 999999;
+		font-weight: bold;
+
+	}
+
+	.main {
+		border-radius: 16px 16px 0px 0px;
+		background: linear-gradient(180deg, rgba(242, 244, 246, 1) 61%, rgba(255, 255, 255, 0) 100%);
+		margin-top: -24rpx;
+		padding: 32rpx;
+
+		.statistics {
+			border-radius: 8px;
+			background-color: rgba(255, 255, 255, 1);
+			box-shadow: 0px 1px 6px 0px rgba(0, 59, 142, 0.05);
+			margin-bottom: 24rpx;
+			padding: 40rpx;
+
+			.title {
+				display: flex;
+				align-items: center;
+				margin-bottom: 32rpx;
+				font-weight: bold;
+
+				.img {
+					width: 36rpx;
+					height: 36rpx;
+					vertical-align: middle;
+					border-radius: 999px;
+
+				}
+
+				.change {
+					display: flex;
+					align-items: center;
+
+					.change-img {
+						width: 32rpx;
+						height: 32rpx;
+						vertical-align: middle;
+					}
+
+					text {
+
+						margin-left: 8rpx;
+					}
+				}
+
+
+				.text {
+					color: rgba(16, 16, 16, 1);
+					font-size: 36rpx;
+					margin-left: 16rpx;
+					display: flex;
+					justify-content: space-between;
+					align-items: center;
+					width: 100%;
+
+					.tag {
+						border-radius: 4px;
+						border: 1px solid rgba(187, 187, 187, 1);
+						color: rgba(51, 51, 51, 1);
+
+						font-size: 24rpx;
+						padding: 1px 8rpx;
+						margin-left: 8rpx;
+					}
+
+				}
+
+				.change {
+					margin-left: 16rpx;
+					font-size: 24rpx;
+					color: #838383;
+
+				}
+
+				.check-all {
+					margin-left: auto;
+					color: rgba(131, 131, 131, 1);
+					font-size: 24rpx;
+					font-weight: 400;
+				}
+			}
+		}
+
+		.statistics-end {
+			padding-bottom: 0;
+		}
+	}
+
+	.tabs-box2 {
+		margin-bottom: 8rpx;
+		padding-right: 16rpx;
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.tabs-box-other {
+			padding-bottom: 12rpx;
+
+		}
+	}
+
+	.tabs-box {
+		padding: 42rpx 0;
+		margin-top: 66rpx;
+		padding-right: 32rpx;
+		background-color: rgba(22, 119, 255, 1);
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.tabs {
+			width: 97%;
+		}
+
+		.more {
+			padding-right: 12rpx;
+		}
+
+		.tabs-box-other {
+			padding-bottom: 12rpx;
+			height: 80rpx;
+			line-height: 70rpx;
+			font-size: 30rpx;
+			color: rgb(255, 255, 255);
+		}
+
+	}
+
+	.body6main {
+		.line {
+			display: flex;
+			justify-content: space-between;
+		}
+
+		.abnormal-item:last-of-type {
+			border-bottom: none !important;
+			padding-bottom: 0;
+		}
+
+		.abnormal-item {
+			width: 100%;
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 16rpx;
+			border-bottom: 1px solid rgba(245, 245, 245, 1);
+
+
+			.item-title {
+				.level {
+					color: #fff;
+
+					border-radius: 8rpx;
+					font-weight: 400;
+					padding: 4rpx 8rpx;
+					font-size: 22rpx;
+					margin-right: 2px;
+				}
+
+				.level1 {
+					background: red;
+				}
+
+				.level2 {
+					background-color: rgba(255, 123, 0, 1);
+				}
+
+				color: rgba(51, 51, 51, 1);
+				width: 100%;
+
+				.img {
+					width: 32rpx;
+					height: 32rpx;
+					margin-right: 8rpx;
+				}
+
+				.name {
+					color: rgba(51, 51, 51, 1);
+					font-weight: bold;
+					overflow: hidden;
+					white-space: nowrap;
+					text-overflow: ellipsis;
+				}
+
+				.date {
+					color: rgba(119, 119, 119, 1);
+					font-size: 24rpx;
+				}
+			}
+
+			.item-value {
+				text-align: right;
+				display: flex;
+				align-items: center;
+
+				.more {
+					margin-left: 8rpx;
+				}
+
+				.value1 {
+					font-weight: bold;
+					color: rgba(51, 51, 51, 1);
+				}
+
+				.value2 {
+					color: rgba(119, 119, 119, 1);
+					font-size: 24rpx;
+				}
+			}
+		}
+	}
+
+	.body7main {
+		border-radius: 4px;
+		background-color: rgba(245, 245, 245, 1);
+		padding: 32rpx;
+
+		.line {
+			display: flex;
+			display: flex;
+			justify-content: space-between;
+			margin-bottom: 24rpx;
+			.goto{
+				    display: flex;
+				    align-items: center;
+			}
+			.item-body{
+				font-size: 24rpx;
+			}
+			
+			.item-title {
+				color: rgba(51, 51, 51, 1);
+				font-size: 28rpx;
+				    display: flex;
+				    align-items: center;
+					.item-name{
+						margin-right: 8rpx;
+						font-size: 32rpx;
+						font-weight: bold;
+					}
+			}
+			.statusN{
+				border-radius: 4px;
+				font-size: 24rpx;
+				padding: 2rpx 8rpx;
+				margin-right: 8rpx;
+			}
+			.statusN1 {
+				
+				color: rgba(0,185,98,1);
+				border: 1px solid rgba(0,185,98,1);
+			
+			}
+			
+			.statusN0 {
+				color: rgba(51,51,51,1);
+				border: 1px solid rgba(119,119,119,1);
+			
+			}
+			.item-tags {
+				display: flex;
+
+				.tag {
+					border-radius: 4px;
+					white-space: pre;
+					background-color: rgba(39, 177, 72, 1);
+					color: rgba(255, 255, 255, 1);
+					font-size: 20rpx;
+					padding: 2rpx 8rpx;
+					margin-right: 8rpx;
+				}
+
+				.tag1 {
+					background-color: rgba(22, 119, 255, 1);
+				}
+
+				.tag2 {
+					background-color: rgba(129, 97, 255, 1);
+				}
+
+				
+
+				.lockStatus {
+
+					background-color: rgba(153, 153, 153, 1);
+				}
+
+				.lockStatus2 {
+					background-color: #03A9F4
+				}
+			}
+		}
+	}
+	
+	
+	.body8main{
+		
+		.line{
+			    display: flex;
+			    justify-content: space-between;
+			    align-items: center;
+				background: #fff;
+				padding:16rpx 0rpx;
+				border-top: 1px solid rgba(232,232,232,1);
+				.data{
+					.view1{
+						color: rgba(16,16,16,1);
+						font-size: 32rpx;
+						font-weight: bold;
+					}
+					.view3{
+						color: rgba(119,119,119,1);
+						font-size: 28rpx;
+					}
+				}
+				.goto{
+					display: flex;
+					font-size: 32rpx;
+	
+				}
+				.status1{
+					color:#FF5100 
+				}
+				.status2{
+					color: rgba(22,119,255,1);
+	 
+				}
+			
+		}
+		.line:first-child{
+			border-top: 0px ;
+			    padding-top: 0px;
+		}
+	}
+</style>

+ 227 - 0
pages/login/findBackPassword.vue

@@ -0,0 +1,227 @@
+<template>
+	<view>
+		<u-navbar title="找回密码" title-color="#101010"></u-navbar>
+		<view class="main">
+			<view class="original-password">
+				<text>手机号码</text><u-input  v-model="form.telephone" style="padding: 0 0 0 20px"  maxlength="11" type="number"  placeholder="请填写手机号"  />
+			</view>
+			<view class="new-password">
+				<text>验证码</text><u-input  v-model="form.verifyCode" style="padding: 0 0 0 20px" maxlength="6" type="number"  placeholder="6位验证码"  />
+				<text class="verification-code" :style="isCodeTipsColor ? 'color: #999999;' : ''" @click="getCode" >{{codeTips}}</text>
+			</view>
+			<view class="new-password">
+				<text>新密码</text><u-input  v-model="form.password" style="padding: 0 0 0 20px" class="password-input" type="password"  placeholder="创建6-16位组合新密码" :password-icon="true" />
+			</view>
+		</view>
+		<u-verification-code :seconds="sendMsgSecond" ref="uCode" @change="codeChange" @end="end" @start="start"
+			change-text="(Xs)">
+		</u-verification-code>
+		<!-- 确认修改 -->
+		<button class="confirm"  @click="retrievePassword" >提交</button>
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/user.js'
+	import {
+		checkPhone
+	} from '@/apis/utils'
+	export default {
+		data() {
+			return {
+				form: {
+					verifyCode:"",
+					telephone: '',
+					password: '',
+				},
+				isSendMsgIng: false,
+				isCodeTipsColor: false,
+				sendMsgSecond: 60,
+				codeTips: '',
+			}
+		},
+		onReady() {
+			var time = this.carhelp.get("getvcodetime");
+			if (time) {
+				//this.$refs.uCode.start();
+				var nowtime = new Date().getTime()
+				var differ = (nowtime - time) / 1000
+				if (differ < 2 * 60) {
+					this.sendMsgSecond = 2 * 60 - parseInt(differ)
+					this.isSendMsgIng = true;
+					this.$refs.uCode.start();
+					this.isCodeTipsColor = true;
+				}
+			}
+		},
+		methods: {
+			retrievePassword(){
+				
+				var checkPhoneResult = checkPhone(this.form.telephone);
+				
+				if (!this.form.telephone || checkPhoneResult != true) {
+					uni.showToast({
+						title: checkPhoneResult,
+						icon: "none"
+					})
+					return;
+				}
+				
+				if (!this.form.telephone) {
+					uni.showToast({
+						title: "请输入手机号",
+						icon: "none"
+					})
+					return
+				}
+				if (!this.form.verifyCode) {
+					uni.showToast({
+						title: "请输入验证码",
+						icon: "none"
+					})
+					return
+				}
+				if (!this.form.password) {
+					uni.showToast({
+						title: "请输入新密码",
+						icon: "none"
+					})
+					return
+				}
+				if (this.form.password.length<6||this.form.password.length>16) {
+					uni.showToast({
+						title: "请输入6-16位组合新密码",
+						icon: "none"
+					})
+					return
+				}
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				API.retrievePassword(this.form).then((response) => {
+					uni.hideLoading();
+					// this.form.password=""
+					// this.form.oldPassword=""
+					uni.showModal({
+						title:"提示",
+						content:"密码修改成功!",
+						showCancel:false,
+						success() {
+							uni.reLaunch({
+								url:"/pages/login/login"
+							})
+						}
+					})
+					
+					
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+				
+			},
+			codeChange(text) {
+				this.codeTips = text;
+			},
+			//倒计时
+			end() {
+				this.sendMsgSecond = 60;
+				this.isSendMsgIng = false;
+				this.isCodeTipsColor = false;
+			},
+			// 获取验证码
+			getCode() {
+				if (this.$refs.uCode.canGetCode) {} else {
+					uni.showToast({
+						title: '倒计时结束后再发送',
+						icon: "none"
+					})
+					return
+				}
+			
+				var checkPhoneResult = checkPhone(this.form.telephone);
+			
+				if (checkPhoneResult !== true) {
+					uni.showToast({
+						icon: "none",
+						title: checkPhoneResult,
+					})
+					return;
+				}
+				this.$refs.uCode.start();
+				this.isCodeTipsColor = true;
+			},
+			start() {
+				if (!this.isSendMsgIng) {
+					uni.showLoading({
+						title: "加载中",
+						mask: true,
+					})
+					API.getVerifyCode(this.form).then((response) => {
+						uni.hideLoading();
+						this.carhelp.set("getvcodetime", new Date().getTime());
+			
+						if (!"") {
+							//倒计时
+							uni.showToast({
+								icon: "none",
+								title: "发送成功"
+							})
+						} else {
+							uni.showToast({
+								icon: "none",
+								title: "您的验证码已经发送[5分钟有效],请勿重复点击"
+							})
+						}
+					}).catch(error => {
+						uni.showToast({
+							title: error,
+							icon: "none"
+						})
+					})
+				}
+			},
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.main{
+		background-color: #fff;
+		margin-top: 24rpx;
+		.original-password,.new-password{
+			line-height: 96rpx;
+			padding:0 32rpx;
+			display: flex;
+			align-items: center;
+			border-bottom: 1px solid rgba(221,221,221,1);
+			::v-deep .u-input__input{
+				height: 96rpx;
+			}
+			
+		}
+		text{
+			display: inline-block;
+			width: 128rpx;
+			color: rgba(51,51,51,1);
+			font-size: 32rpx;
+		}
+		.verification-code{
+			width: 160rpx;
+			color: rgba(22,119,255,1);
+			font-size: 32rpx;
+		}
+	}
+  // 确认修改
+  .confirm{
+	  border-radius: 8px;
+	  background-color: rgba(22,119,255,1);
+	  color: rgba(255,255,255,1);
+	  font-size: 32rpx;
+	  line-height: 88rpx;
+	  margin: 24rpx 32rpx;
+  }
+</style>

+ 226 - 0
pages/login/login.vue

@@ -0,0 +1,226 @@
+<template >
+	<view>
+		<view class="logo">
+			<image class="img" src="@/assets/img/logo/logo.png" mode=""></image>
+			
+		</view>
+		<view  class="logoText">
+			<view>智泊e家</view>
+			<view>运管端</view>
+			
+			
+
+		</view>
+		<!-- 手机号/密码 -->
+		<view class="input-box">
+			
+			<u-input  v-model="userName"  style="padding: 0 20px" class="tel-input" type="text"  placeholder="请输入账号" />
+		
+			<u-input  v-model="password" style="padding: 0 20px" class="password-input" type="password"  placeholder="请输入密码" :password-icon="true" />
+
+		</view>
+		
+		 <button class="login-disable" :class="{
+			 login:password.length&&userName.length
+		 }" @click="submit" >登录</button>
+		 
+		 <view class="reset" v-if="0" @click="gotoUrl('/pages/login/findBackPassword')" >
+		 	忘记密码? <span style="color:#387aea ;">点击找回</span>
+		 </view>
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/user.js'
+	import {
+		checkPhone
+	} from '@/apis/utils'
+	export default {
+		data() {
+			return {
+				userName:"",
+				password:"",
+			}
+		},
+		onLoad(){
+			
+			this.query()
+		},
+		methods: {
+			
+			query(){
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				
+				API.findByOpenId({
+					noerror:true,
+					openId: this.jphelp.getOpenId(),
+				 
+				
+				}).then((response) => {
+					
+					if(response.message){
+						uni.hideLoading();
+						if(response.message=='没有权限'){
+							
+							uni.showModal({
+								title:"提示",
+								showCancel:false,
+								content:"没有权限"
+							})
+						}
+					}else{
+						this.loginset(response)
+						
+						uni.switchTab({
+							url: '/pages/index/index'
+						})
+					}
+					
+					
+				
+				}).catch(error => {
+					
+					uni.hideLoading();
+					
+				})
+			},
+			submit(){
+				if(!(this.userName.length&&this.password.length)){
+					return
+				}
+				// var checkPhoneResult = checkPhone(this.phone);
+					
+				// if (checkPhoneResult !== true) {
+				// 	uni.showToast({
+				// 		icon: "none",
+				// 		title: checkPhoneResult,
+						
+				// 	})
+				// 	return;
+				// }
+				
+				if(!this.password.length){
+					uni.showToast({
+						icon: "none",
+						title: "请输入密码"
+					})
+					return
+				}
+				
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				
+				API.login({
+					password:this.password,
+					userName:this.userName,
+					openId: this.jphelp.getOpenId(),
+					noerror:true,
+					//type:2,
+				}).then((response) => {
+					
+					if(response.message){
+						uni.hideLoading();
+						if(response.message=='没有权限'){
+							
+							uni.showModal({
+								title:"提示",
+								showCancel:false,
+								content:"没有权限"
+							})
+						}else{
+							uni.showToast({
+								icon: "none",
+								title: response.message?response.message:"登录失败"
+							})
+						}
+					}else{
+						this.loginset(response)
+						
+						uni.switchTab({
+							url: '/pages/index/index'
+						})
+						
+					}
+				
+				}).catch(error => {
+					uni.hideLoading();
+					uni.showToast({
+						icon: "none",
+						title: error?error:"登录失败"
+					})
+				})
+				
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	
+	
+	page{
+		background-color: #fff;
+		padding-top: 160rpx;
+	}
+	.logoText{
+		text-align: center;
+		width: 160rpx;
+		margin: 0 auto;
+		line-height: 46rpx;
+		color: rgba(16,16,16,1);
+		font-size: 32rpx;
+		margin-top: 20rpx;
+	}
+	.logo{
+		margin: 0 auto;
+		//width: 160rpx;
+		
+		border-radius: 16px;
+		//background: linear-gradient(180deg, rgba(31,85,255,1) 0%,rgba(39,171,255,1) 100%);
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		.img{
+			
+			width: 144rpx;
+			height: 144rpx;
+			border-radius: 16px;
+		}
+	}
+
+.input-box{
+	padding: 0 58rpx;
+	margin-top: 112rpx;
+	.tel-input,.password-input{
+		 display: flex;align-items: center;
+		border-radius: 50px;
+		background-color: rgba(248,248,248,1);
+		color: rgba(16,16,16,1);
+		height: 100rpx;
+		line-height: 100rpx;
+		padding: 0 48rpx;
+		margin-bottom: 40rpx;
+	}
+	
+}
+
+.login-disable{
+	margin: 80rpx 56rpx 40rpx;
+	border-radius: 100rpx;
+	background-color: rgba(223,223,223,1);
+	color: rgba(255, 255, 255, 1);
+}
+.login{
+	background-color: rgba(27,119,251,1);
+}
+
+.reset{
+	color: rgba(119,119,119,1);
+	text-align: center;
+}
+</style>

+ 107 - 0
pages/myTab/abnormalInfo.vue

@@ -0,0 +1,107 @@
+<template>
+	<view>
+		<u-navbar title="异常告警记录"></u-navbar>
+		<view class="main">
+			<view class="line line1">
+				<view class="name">
+					告警单号:A100001
+
+				</view>
+				<view class="value value1">
+					电量过低
+				</view>
+			</view>
+			
+			<view class="line">
+				<view class="name">
+					告警地锁
+
+			
+				</view>
+				<view class="value">
+					荆鹏软件园-A01
+
+				</view>
+			</view>
+			<view class="line">
+				<view class="name">
+					告警内容
+
+			
+				</view>
+				<view class="value value2">
+					电量过低 <20%
+
+				</view>
+			</view>
+			<view class="line">
+				<view class="name">
+					地址
+
+			
+				</view>
+				<view class="value">
+					沙市区江津东路附155号
+
+				</view>
+			</view>
+			<view class="line">
+				<view class="name">
+					告警时间
+			
+				</view>
+				<view class="value">
+					2024-02-04 20:00:00
+
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		methods: {
+			
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.main{
+		background-color: rgba(255,255,255,1);
+		.line1{
+			box-shadow: 0px 2px 2px 0px rgba(0,0,0,0.1);
+		}
+		.line{
+			    display: flex;
+			    justify-content: space-between;
+			padding:11px 16px;
+			color: rgba(51,51,51,1);
+			font-size: 16px;
+			border-bottom: 1px solid rgba(242,242,242,1);
+			.value{
+				color: rgba(16,16,16,1);
+
+			}
+			.value1{
+				border-radius: 4px;
+				background-color: rgba(255,255,255,1);
+				color: rgba(255,61,0,1);
+				border: 1px solid rgba(255,61,0,1);
+				padding: 2px;
+				font-size: 12px;
+			
+			}
+			.value2{
+				color: rgba(255,61,0,1);
+
+			}
+		}
+	}
+</style>

+ 273 - 0
pages/myTab/abnormalList.vue

@@ -0,0 +1,273 @@
+<template>
+	<view>
+		<u-navbar title="异常告警记录"></u-navbar>
+		<view class="main">
+			<view class="tabs">
+				<u-picker v-model="tabsFrom.show1" :default-selector="[tabsFrom.show1Index]" mode="selector"
+					:range="tabsFrom.selector1" range-key="label" @confirm="selector1confirm"></u-picker>
+				<u-picker-select title="日期选择" v-model="tabsFrom.show2" :defaultTime="tabsFrom.show2Index"
+					:endYear="endYear" mode="time" :params="params" @confirm="selector2confirm"
+					@reset="selector2reset"></u-picker-select>
+
+				<view class="tabsItem" @click="tabsFrom.show1=!tabsFrom.show1">{{tabsFrom.show1Text}} <u-icon
+						name="arrow-up" v-if="tabsFrom.show1"></u-icon><u-icon v-else name="arrow-down"></u-icon></view>
+				<view class="tabsItem" @click="tabsFrom.show2=!tabsFrom.show2">{{tabsFrom.show2Text}} <u-icon
+						name="arrow-up" v-if="tabsFrom.show2"></u-icon><u-icon v-else name="arrow-down"></u-icon></view>
+
+				<view class="tabsItem" @click="tabsFrom.show3=!tabsFrom.show3">{{tabsFrom.show3Text}} <u-icon
+						name="arrow-up" v-if="tabsFrom.show3"></u-icon><u-icon v-else name="arrow-down"></u-icon></view>
+			</view>
+
+			<view class="list" v-if="0">
+				<view class="line" @click="gotoUrl('/pages/myTab/abnormalInfo?id=1')">
+					<view class="body">
+						<view class="imgclass">
+							<image class="img" src="@/assets/img/deviceTab/index2-1.svg" mode=""></image>
+						</view>
+						<view class="item">
+							<view class="name">
+								<view class="text1">软件园</view>
+								<view class="text2">私人车位</view>
+							</view>
+							<view class="value">
+								<view class="text1">2024-02-14 09:00:01</view>
+								<view class="text2">私人车位</view>
+							</view>
+						</view>
+					</view>
+					<view class="goto">
+
+						<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+					</view>
+				</view>
+				<view class="line" @click="gotoUrl('/pages/myTab/abnormalInfo?id=1')">
+					<view class="body">
+						<view class="imgclass">
+							<image class="img" src="@/assets/img/deviceTab/index2-1.svg" mode=""></image>
+						</view>
+						<view class="item">
+							<view class="name">
+								<view class="text1">软件园</view>
+								<view class="text2">私人车位</view>
+							</view>
+							<view class="value">
+								<view class="text1">软件园</view>
+								<view class="text2">私人车位</view>
+							</view>
+						</view>
+					</view>
+					<view class="goto">
+
+						<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+					</view>
+				</view>
+
+
+
+			</view>
+
+
+
+		</view>
+		<u-divider :isnone="list.length==0" nonetext="没有找到相关内容" border-color="#CFD2D5">已经到底了</u-divider>
+
+
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/deviceTab.js'
+
+
+	export default {
+
+		data() {
+			return {
+				title: "场站列表",
+				list: [],
+				listForm: {
+					pageIndex: 1,
+					pageSize: 20,
+					recordsTotal: 1,
+				},
+				tabsFrom: {
+					show1: false,
+					show1Index: 0,
+					show2Index: '',
+					show2: false,
+					show1Text: "全部场站",
+					show2Text: "全部类型",
+					show3Text: "全部状态",
+					selector1: [{
+							label: '全部类型',
+							value: '',
+						},
+						{
+							label: '线上充值',
+							value: '1',
+						},
+						{
+							label: '线下充值',
+							value: '2',
+						},
+					]
+				},
+			};
+		},
+		onLoad(op) {
+
+			this.getList()
+		},
+		onReachBottom() {
+			if (this.list.length < this.listForm.recordsTotal) {
+				this.myLoadmore();
+			}
+		},
+		methods: {
+
+			myLoadmore() {
+				this.listForm.pageIndex += 1;
+				this.getList()
+			},
+			getList() {
+				return
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+
+				API.floorlockList(this.listForm).then((res) => {
+					var list = []
+
+					if (this.listForm.pageIndex == 1) {
+						list = res.data.data;
+					} else {
+						list = [
+							...list,
+							...res.data.data
+						];
+					}
+					this.list = res.data.data
+					uni.hideLoading();
+
+				}).catch(error => {
+
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			},
+		}
+	}
+</script>
+
+<style scoped lang="scss">
+	.main {
+		background-color: #fff;
+
+		.line {
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			padding: 32rpx;
+			border-bottom: 1px solid rgba(245, 245, 245, 1);
+
+			.goto {
+				margin-left: 16rpx;
+			}
+
+			.body {
+				display: flex;
+				align-items: center;
+				width: 100%;
+
+				.imgclass {
+					display: flex;
+					align-items: center;
+					justify-content: center;
+					width: 72rpx;
+					height: 72rpx;
+					border-radius: 4px;
+					background-color: rgba(219, 234, 255, 1);
+				}
+
+				.item {
+					margin-left: 16rpx;
+					width: 100%;
+
+					.name {
+						color: rgba(51, 51, 51, 1);
+						font-weight: bold;
+
+						font-size: 28rpx;
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+
+					}
+
+					.value {
+						color: rgba(119, 119, 119, 1);
+						font-size: 24rpx;
+						display: flex;
+						align-items: center;
+						justify-content: space-between;
+
+					}
+				}
+
+			}
+		}
+
+		.img {
+			width: 48rpx;
+			height: 48rpx;
+		}
+	}
+
+	.tabs {
+		border-bottom: 1px solid rgba(232, 232, 232, 1);
+		height: 96rpx;
+		line-height: 96rpx;
+		background-color: #fff;
+		border-top: 1px solid rgba(241, 241, 241, 1);
+		display: flex;
+		justify-content: space-around;
+
+		.tabsItem {
+			color: rgba(51, 51, 51, 1);
+			font-size: 14px;
+
+		}
+
+	}
+
+	.floating-button {
+		position: fixed;
+		bottom: 120rpx;
+		width: 100%;
+		display: flex;
+
+		justify-content: center;
+
+		.button {
+			border-radius: 50px;
+			background-color: rgba(49, 51, 52, 1);
+			color: rgba(255, 255, 255, 1);
+			font-size: 28rpx;
+			width: 240rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			padding: 12rpx;
+
+			.img {
+				width: 40rpx;
+				height: 40rpx;
+				margin-right: 8rpx;
+			}
+		}
+	}
+</style>

+ 227 - 0
pages/myTab/as-components/limeClipper/README.md

@@ -0,0 +1,227 @@
+> 插件来源:[https://ext.dcloud.net.cn/plugin?id=3594](https://ext.dcloud.net.cn/plugin?id=3594)
+##### 以下是作者写的插件介绍:
+
+# Clipper 图片裁剪
+> uniapp 图片裁剪,可用于图片头像等裁剪处理
+> [查看更多](http://liangei.gitee.io/limeui/#/clipper) <br>
+> Q群:458377637
+
+
+## 平台兼容
+
+| H5  | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App |
+| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- |
+| √   | √          | √         | 未测       | √          | √      | √   |
+
+
+## 代码演示
+### 基本用法
+`@success` 事件点击 👉 **确定** 后会返回生成的图片信息,包含 `url`、`width`、`height`
+
+```html
+<image :src="url" v-if="url" mode="widthFix"></image>
+<l-clipper v-if="show" @success="url = $event.url; show = false" @cancel="show = false"  ></l-clipper>
+<button @tap="show = true">裁剪</button>
+```
+
+```js
+// 非uni_modules引入
+import lClipper from '@/components/lime-clipper/'
+// uni_modules引入
+import lClipper from '@/uni_modules/lime-clipper/components/lime-clipper/'
+export default {
+	components: {lClipper},
+    data() {
+        return {
+            show: false,
+			url: '',
+        }
+    }
+}
+```
+
+
+### 传入图片
+`image-url`可传入**相对路径**、**临时路径**、**本地路径**、**网络图片**<br>
+
+* **当为网络地址时**
+* H5:👉 需要解决跨域问题。 <br>
+* 小程序:👉 需要配置 downloadFile 域名 <br>
+
+
+```html
+<image :src="url" v-if="url" mode="widthFix"></image>
+<l-clipper v-if="show" :image-url="imageUrl"  @success="url = $event.url; show = false" @cancel="show = false"  ></l-clipper>
+<button @tap="show = true">裁剪</button>
+```
+
+```js
+export default {
+	components: {lClipper},
+    data() {
+        return {
+			imageUrl: 'https://img12.360buyimg.com/pop/s1180x940_jfs/t1/97205/26/1142/87801/5dbac55aEf795d962/48a4d7a63ff80b8b.jpg',
+            show: false,
+			url: '',
+        }
+    }
+}
+```
+
+
+### 确定按钮颜色
+样式变量名:`--l-clipper-confirm-color`
+可放到全局样式的 `page` 里或节点的 `style`
+```html
+<l-clipper class="clipper" style="--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)"  ></l-clipper>
+```
+```css
+// css 中为组件设置 CSS 变量
+.clipper {
+	--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
+}
+// 全局
+page {
+	--l-clipper-confirm-color: linear-gradient(to right, #ff6034, #ee0a24)
+}
+```
+
+
+### 使用插槽
+共五个插槽 `cancel` 取消按钮、 `photo` 选择图片按钮、 `rotate` 旋转按钮、 `confirm` 确定按钮和默认插槽。
+
+```html
+<image :src="url" v-if="url" mode="widthFix"></image>
+<l-clipper 
+	v-if="show" 
+	:isLockWidth="isLockWidth"
+	:isLockHeight="isLockHeight"
+	:isLockRatio="isLockRatio"
+	:isLimitMove="isLimitMove"
+	:isDisableScale="isDisableScale"
+	:isDisableRotate="isDisableRotate"
+	:isShowCancelBtn="isShowCancelBtn"
+	:isShowPhotoBtn="isShowPhotoBtn"
+	:isShowRotateBtn="isShowRotateBtn"
+	:isShowConfirmBtn="isShowConfirmBtn"
+	@success="url = $event.url; show = false" 
+	@cancel="show = false" >
+	<!-- 四个基本按钮插槽 -->
+	<view slot="cancel">取消</view>
+	<view slot="photo">选择图片</view>
+	<view slot="rotate">旋转</view>
+	<view slot="confirm">确定</view>
+	<!-- 默认插槽 -->
+	<view class="tools">
+		<view>显示取消按钮
+			<switch :checked="isShowCancelBtn" @change="isShowCancelBtn = $event.target.value" ></switch>
+		</view>
+		<view>显示选择图片按钮
+			<switch :checked="isShowPhotoBtn" @change="isShowPhotoBtn = $event.target.value" ></switch>
+		</view>
+		<view>显示旋转按钮
+			<switch :checked="isShowRotateBtn" @change="isShowRotateBtn = $event.target.value" ></switch>
+		</view>
+		<view>显示确定按钮
+			<switch :checked="isShowConfirmBtn" @change="isShowConfirmBtn = $event.target.value" ></switch>
+		</view>
+		<view>锁定裁剪框宽度
+			<switch :checked="isLockWidth" @change="isLockWidth = $event.target.value" ></switch>
+		</view>
+		<view>锁定裁剪框高度
+			<switch :checked="isLockHeight" @change="isLockHeight = $event.target.value" ></switch>
+		</view>
+		<view>锁定裁剪框比例
+			<switch :checked="isLockRatio" @change="isLockRatio = $event.target.value" ></switch>
+		</view>
+		<view>限制移动范围
+			<switch :checked="isLimitMove" @change="isLimitMove = $event.target.value" ></switch>
+		</view>
+		<view>禁止缩放
+			<switch :checked="isDisableScale" @change="isDisableScale = $event.target.value" ></switch>
+		</view>
+		<view>禁止旋转
+			<switch :checked="isDisableRotate" @change="isDisableRotate = $event.target.value" ></switch>
+		</view>
+	</view>
+</l-clipper>
+<button @tap="show = true">裁剪</button>
+```
+
+```js
+export default {
+	components: {lClipper},
+    data() {
+        return {
+            show: false,
+            url: '',
+            isLockWidth: false,
+            isLockHeight: false,
+            isLockRatio: true,
+            isLimitMove: false,
+            isDisableScale: false,
+            isDisableRotate: false,
+            isShowCancelBtn: true,
+            isShowPhotoBtn: true,
+            isShowRotateBtn: true,
+            isShowConfirmBtn: true
+        }
+    }
+}
+```
+
+
+## API
+
+### Props
+
+| 参数           | 说明         | 类型             | 默认值       |
+| ------------- | ------------ | ---------------- | ------------ |
+| image-url     | 图片路径     | <em>string</em>   |              |
+| quality       | 图片的质量,取值范围为 [0, 1],不在范围内时当作1处理   | <em>number</em>  |    `1`      |
+| source       | `{album: '从相册中选择'}`key为图片来源类型,value为选项说明   | <em>Object</em>  |         |
+| width | 裁剪框宽度,单位为 `rpx` | <em>number</em> | `400`      |
+| height | 裁剪框高度 | <em>number</em> | `400`      |
+| min-width | 裁剪框最小宽度 | <em>number</em> | `200`      |
+| min-height |裁剪框最小高度 | <em>number</em> | `200`  |
+| max-width | 裁剪框最大宽度 | <em>number</em> | `600`  |
+| max-height | 裁剪框最大宽度 | <em>number</em> | `600`  |
+| min-ratio | 图片最小缩放比 | <em>number</em> | `0.5`  |
+| max-ratio | 图片最大缩放比 | <em>number</em> | `2`  |
+| rotate-angle | 旋转按钮每次旋转的角度 | <em>number</em> | `90`  |
+| scale-ratio | 生成图片相对于裁剪框的比例, **比例越高生成图片越清晰**	 | <em>number</em> | `1`  |
+| is-lock-width | 是否锁定裁剪框宽度 | <em>boolean</em> | `false`  |
+| is-lock-height | 是否锁定裁剪框高度上 | <em>boolean</em> | `false`  |
+| is-lock-ratio | 是否锁定裁剪框比例 | <em>boolean</em> | `true`  |
+| is-disable-scale | 是否禁止缩放 | <em>boolean</em> | `false`  |
+| is-disable-rotate | 是否禁止旋转 | <em>boolean</em> | `false`  |
+| is-limit-move | 是否限制移动范围 | <em>boolean</em> | `false`  |
+| is-show-photo-btn | 是否显示选择图片按钮 | <em>boolean</em> | `true`  |
+| is-show-rotate-btn | 是否显示转按钮 | <em>boolean</em> | `true`  |
+| is-show-confirm-btn | 是否显示确定按钮 | <em>boolean</em> | `true`  |
+| is-show-cancel-btn | 是否显示关闭按钮 | <em>boolean</em> | `true`  |
+
+
+
+### 事件 Events
+
+| 事件名  | 说明         | 回调           |
+| ------- | ------------ | -------------- |
+| success | 生成图片成功 | {`width`, `height`, `url`} |
+| fail | 生成图片失败 | `error` |
+| cancel | 关闭 | `false` |
+| ready   | 图片加载完成 | {`width`, `height`, `path`, `orientation`, `type`} |
+| change | 图片大小改变时触发 | {`width`, `height`} |
+| rotate | 图片旋转时触发 | `angle` |
+
+## 常见问题
+> 1、H5端使用网络图片需要解决跨域问题。<br>
+> 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配!<br>
+> 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签`<IMG/>`<br>
+> 4、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。<br>
+> 5、APP端无成功反馈、也无失败反馈时,请更新基座和HBX。<br>
+
+
+## 打赏
+如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。<br>
+![输入图片说明](https://images.gitee.com/uploads/images/2020/1122/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg")

+ 19 - 0
pages/myTab/as-components/limeClipper/images/photo.svg

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:#606060;}
+	.st1{fill:none;stroke:#FFFFFF;stroke-width:2.4306;stroke-miterlimit:10;}
+	.st2{fill:#FFFFFF;}
+</style>
+<g>
+	<path class="st2" d="M11.6,11c0.4,0.4,0.6,0.9,0.6,1.5c0,0.6-0.2,1.1-0.6,1.4c-0.4,0.4-0.9,0.6-1.5,0.6c-0.6,0-1.1-0.2-1.5-0.6
+		c-0.4-0.4-0.6-0.9-0.6-1.4s0.2-1.1,0.6-1.5c0.4-0.4,0.9-0.6,1.5-0.6C10.8,10.4,11.2,10.6,11.6,11z M24.6,18.4V6.7H5.4v12l1.8-1.8
+		c0.3-0.3,0.6-0.4,1-0.4c0.4,0,0.7,0.1,1,0.4l1.8,1.8l5.8-7c0.3-0.3,0.6-0.5,1.1-0.5c0.4,0,0.8,0.2,1.1,0.5
+		C18.8,11.6,24.6,18.4,24.6,18.4z M25.6,5.7C25.9,6,26,6.3,26,6.7v16.1c0,0.4-0.1,0.7-0.4,1c-0.3,0.3-0.6,0.4-1,0.4H5.4
+		c-0.4,0-0.7-0.1-1-0.4c-0.3-0.3-0.4-0.6-0.4-1V6.7c0-0.4,0.1-0.7,0.4-1c0.3-0.3,0.6-0.4,1-0.4h19.3C25,5.3,25.3,5.4,25.6,5.7z"/>
+	<path class="st1" d="M24.3,21.5H5.7c-0.2,0-0.3-0.2-0.3-0.3V7c0-0.2,0.2-0.3,0.3-0.3h18.6c0.2,0,0.3,0.2,0.3,0.3v14.2
+		C24.6,21.3,24.5,21.5,24.3,21.5z"/>
+</g>
+</svg>

+ 15 - 0
pages/myTab/as-components/limeClipper/images/rotate.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="图层_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 width="30px" height="30px" viewBox="0 0 30 30" style="enable-background:new 0 0 30 30;" xml:space="preserve">
+<style type="text/css">
+	.st0{fill:none;stroke:#FFFFFF;stroke-width:2.4306;stroke-miterlimit:10;}
+	.st1{fill:#FFFFFF;}
+</style>
+<g>
+	<path class="st0" d="M17.1,24.2h-12c-0.2,0-0.3-0.2-0.3-0.3v-9.3c0-0.2,0.2-0.3,0.3-0.3h12c0.2,0,0.3,0.2,0.3,0.3v9.3
+		C17.5,24.1,17.3,24.2,17.1,24.2z"/>
+	<path class="st0" d="M16.6,5.4c4.8,0,8.7,3.9,8.7,8.7"/>
+	<polyline class="st0" points="19.3,10.1 14.9,5.6 19.3,1.2 	"/>
+</g>
+</svg>

+ 160 - 0
pages/myTab/as-components/limeClipper/index.css

@@ -0,0 +1,160 @@
+.flex-auto {
+  flex: auto;
+}
+.bg-transparent {
+  background-color: rgba(0,0,0,0.9);
+  transition-duration: 0.35s;
+}
+.l-clipper {
+  width: 100vw;
+  height: calc(100vh - var(--window-top));
+  background-color: rgba(0,0,0,0.9);
+  position: fixed;
+  top: var(--window-top);
+  left: 0;
+  z-index: 1;
+}
+.l-clipper-mask {
+  position: relative;
+  z-index: 2;
+  pointer-events: none;
+}
+.l-clipper__content {
+  pointer-events: none;
+  position: absolute;
+  border: 1rpx solid rgba(255,255,255,0.3);
+  box-sizing: border-box;
+  box-shadow: rgba(0,0,0,0.5) 0 0 0 80vh;
+  background: transparent;
+}
+.l-clipper__content::before,
+.l-clipper__content::after {
+  content: '';
+  position: absolute;
+  border: 1rpx dashed rgba(255,255,255,0.3);
+}
+.l-clipper__content::before {
+  width: 100%;
+  top: 33.33%;
+  height: 33.33%;
+  border-left: none;
+  border-right: none;
+}
+.l-clipper__content::after {
+  width: 33.33%;
+  left: 33.33%;
+  height: 100%;
+  border-top: none;
+  border-bottom: none;
+}
+.l-clipper__edge {
+  position: absolute;
+  width: 34rpx;
+  height: 34rpx;
+  border: 6rpx solid #fff;
+  pointer-events: auto;
+}
+.l-clipper__edge::before {
+  content: '';
+  position: absolute;
+  width: 40rpx;
+  height: 40rpx;
+  background-color: transparent;
+}
+.l-clipper__edge:nth-child(1) {
+  left: -6rpx;
+  top: -6rpx;
+  border-bottom-width: 0 !important;
+  border-right-width: 0 !important;
+}
+.l-clipper__edge:nth-child(1):before {
+  top: -50%;
+  left: -50%;
+}
+.l-clipper__edge:nth-child(2) {
+  right: -6rpx;
+  top: -6rpx;
+  border-bottom-width: 0 !important;
+  border-left-width: 0 !important;
+}
+.l-clipper__edge:nth-child(2):before {
+  top: -50%;
+  left: 50%;
+}
+.l-clipper__edge:nth-child(3) {
+  left: -6rpx;
+  bottom: -6rpx;
+  border-top-width: 0 !important;
+  border-right-width: 0 !important;
+}
+.l-clipper__edge:nth-child(3):before {
+  bottom: -50%;
+  left: -50%;
+}
+.l-clipper__edge:nth-child(4) {
+  right: -6rpx;
+  bottom: -6rpx;
+  border-top-width: 0 !important;
+  border-left-width: 0 !important;
+}
+.l-clipper__edge:nth-child(4):before {
+  bottom: -50%;
+  left: 50%;
+}
+.l-clipper-image {
+  width: 100%;
+  border-style: none;
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1;
+  -webkit-backface-visibility: hidden;
+  backface-visibility: hidden;
+  transform-origin: center;
+}
+.l-clipper-canvas {
+  position: fixed;
+  z-index: 10;
+  left: -200vw;
+  top: -200vw;
+  pointer-events: none;
+}
+.l-clipper-tools {
+  position: fixed;
+  left: 0;
+  bottom: 10px;
+  width: 100%;
+  z-index: 99;
+  color: #fff;
+}
+.l-clipper-tools__btns {
+  font-weight: bold;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 100%;
+  padding: 20rpx 40rpx;
+  box-sizing: border-box;
+}
+.l-clipper-tools__btns .cancel {
+  width: 112rpx;
+  height: 60rpx;
+  text-align: center;
+  line-height: 60rpx;
+}
+.l-clipper-tools__btns .confirm {
+  width: 112rpx;
+  height: 60rpx;
+  line-height: 60rpx;
+  background-color: #07c160;
+  border-radius: 6rpx;
+  text-align: center;
+}
+.l-clipper-tools__btns image {
+  display: block;
+  width: 60rpx;
+  height: 60rpx;
+}
+.l-clipper-tools__btns {
+  flex-direction: row;
+}

+ 818 - 0
pages/myTab/as-components/limeClipper/limeClipper.vue

@@ -0,0 +1,818 @@
+<template>
+	<view class="l-clipper" :class="{open: value}" disable-scroll :style="'z-index: ' + zIndex + ';' + customStyle">
+		<view class="l-clipper-mask" @touchstart.stop.prevent="clipTouchStart" @touchmove.stop.prevent="clipTouchMove" @touchend.stop.prevent="clipTouchEnd">
+			<view class="l-clipper__content" :style="clipStyle"><view class="l-clipper__edge" v-for="(item, index) in [0, 0, 0, 0]" :key="index"></view></view>
+		</view>
+		<image
+			class="l-clipper-image"
+			@error="imageLoad"
+			@load="imageLoad"
+			@touchstart.stop.prevent="imageTouchStart"
+			@touchmove.stop.prevent="imageTouchMove"
+			@touchend.stop.prevent="imageTouchEnd"
+			:src="image"
+			:mode="imageWidth == 'auto' ? 'widthFix' : ''"
+			v-if="image"
+			:style="imageStyle"
+		/>
+		<canvas
+			:canvas-id="canvasId"
+			id="l-clipper"
+			disable-scroll
+			:style="'width: ' + canvasWidth * scaleRatio + 'px; height:' + canvasHeight * scaleRatio + 'px;'"
+			class="l-clipper-canvas"
+		></canvas>
+		<view class="l-clipper-tools">
+			<view class="l-clipper-tools__btns">
+				<view v-if="isShowCancelBtn" @tap="cancel">
+					<slot name="cancel" v-if="$slots.cancel" />
+					<view v-else class="cancel">取消</view>
+				</view>
+				<view v-if="isShowPhotoBtn" @tap="uploadImage">
+					<slot name="photo" v-if="$slots.photo" />
+					<image v-else src="@/static/limeClipper/photo.svg" />
+				</view>
+				<view v-if="isShowRotateBtn" @tap="rotate">
+					<slot name="rotate" v-if="$slots.rotate" />
+					<image v-else src="@/static/limeClipper/rotate.svg" data-type="inverse" />
+				</view>
+				<view v-if="isShowConfirmBtn" @tap="confirm">
+					<slot name="confirm" v-if="$slots.confirm" />
+					<view v-else class="confirm">确定</view>
+				</view>
+			</view>
+			<slot></slot>
+		</view>
+	</view>
+</template>
+
+<script>
+import { determineDirection, calcImageOffset, calcImageScale, calcImageSize, calcPythagoreanTheorem, clipTouchMoveOfCalculate, imageTouchMoveOfCalcOffset } from './utils';
+const cache = {}
+export default {
+	// version: '0.6.3',
+	name: 'l-clipper',
+	props: {
+		value: {
+			type: Boolean,
+			default: true
+		},
+		// #ifdef MP-WEIXIN
+		type: {
+			type: String,
+			default: '2d'
+		},
+		// #endif
+		customStyle: {
+			type: String,
+		},
+		canvasId: {
+			type: String,
+			default: 'l-clipper'
+		},
+		zIndex: {
+			type: Number,
+			default: 99
+		},
+		imageUrl: {
+			type: String
+		},
+		fileType: {
+			type: String,
+			default: 'png'
+		},
+		quality: {
+			type: Number,
+			default: 1
+		},
+		width: {
+			type: Number,
+			default: 400
+		},
+		height: {
+			type: Number,
+			default: 400
+		},
+		minWidth: {
+			type: Number,
+			default: 200
+		},
+		maxWidth: {
+			type: Number,
+			default: 600
+		},
+		minHeight: {
+			type: Number,
+			default: 200
+		},
+		maxHeight: {
+			type: Number,
+			default: 600
+		},
+		isLockWidth: {
+			type: Boolean,
+			default: false
+		},
+		isLockHeight: {
+			type: Boolean,
+			default: false
+		},
+		isLockRatio: {
+			type: Boolean,
+			default: true
+		},
+		scaleRatio: {
+			type: Number,
+			default: 1
+		},
+		minRatio: {
+			type: Number,
+			default: 0.5
+		},
+		maxRatio: {
+			type: Number,
+			default: 2
+		},
+		isDisableScale: {
+			type: Boolean,
+			default: false
+		},
+		isDisableRotate: {
+			type: Boolean,
+			default: false
+		},
+		isLimitMove: {
+			type: Boolean,
+			default: false
+		},
+		isShowPhotoBtn: {
+			type: Boolean,
+			default: true
+		},
+		isShowRotateBtn: {
+			type: Boolean,
+			default: true
+		},
+		isShowConfirmBtn: {
+			type: Boolean,
+			default: true
+		},
+		isShowCancelBtn: {
+			type: Boolean,
+			default: true
+		},
+		rotateAngle: {
+			type: Number,
+			default: 90
+		},
+		source: {
+			type: Object,
+			default: () => ({
+					album: '从相册中选择',
+					camera: '拍照',
+					// #ifdef MP-WEIXIN
+					message: '从微信中选择'
+					// #endif
+				})
+		}
+	},
+	data() {
+		return {
+			canvasWidth: 0,
+			canvasHeight: 0,
+			clipX: 0,
+			clipY: 0,
+			clipWidth: 0,
+			clipHeight: 0,
+			animation: false,
+			imageWidth: 0,
+			imageHeight: 0,
+			imageTop: 0,
+			imageLeft: 0,
+			scale: 1,
+			angle: 0,
+			image: this.imageUrl,
+			sysinfo: {},
+			throttleTimer: null,
+			throttleFlag: true,
+			timeClipCenter: null,
+			flagClipTouch: false,
+			flagEndTouch: false,
+			clipStart: {},
+			animationTimer: null,
+			touchRelative: [{x: 0,y: 0}],
+			hypotenuseLength: 0,
+			ctx: null
+		};
+	},
+	computed: {
+		clipStyle() {
+			const {clipWidth, clipHeight, clipY, clipX, animation} = this
+			return  `
+			width: ${clipWidth}px;
+			height:${clipHeight}px;
+			transition-property: ${animation ? '' : 'background'};
+			left: ${clipX}px;
+			top: ${clipY}px
+			`
+		},
+		imageStyle() {
+			const {imageWidth, imageHeight, imageLeft, imageTop, animation, scale, angle} = this
+			return `
+				width: ${imageWidth ? imageWidth + 'px' : 'auto'};
+				height: ${imageHeight ? imageHeight + 'px' : 'auto'};
+				transform: translate3d(${imageLeft - imageWidth / 2}px, ${imageTop - imageHeight / 2}px, 0) scale(${scale}) rotate(${angle}deg);
+				transition-duration: ${animation ? 0.35 : 0}s
+			`
+		},
+		clipSize() {
+			const { clipWidth, clipHeight } = this;
+			return { clipWidth, clipHeight };
+		},
+		clipPoint() {
+			const { clipY, clipX } = this;
+			return { clipY, clipX };
+		}
+	},
+	watch: {
+		value(val) {
+			if(!val) {
+				this.animation = 0
+				this.angle = 0
+			} else {
+				if(this.imageUrl) {
+					const {imageWidth, imageHeight, imageLeft, imageTop, scale, clipX, clipY, clipWidth, clipHeight, path} = cache?.[this.imageUrl] || {}
+					if(path != this.image) {
+						this.image = this.imageUrl;
+					} else {
+						this.setDiffData({imageWidth, imageHeight, imageLeft, imageTop, scale, clipX, clipY, clipWidth, clipHeight})
+					}
+					
+				}
+				
+			}
+		},
+		imageUrl(url) {
+			this.image = url
+		},
+		image:{
+			handler: async function(url) {
+				this.getImageInfo(url)
+			},
+			// immediate: true,
+		},
+		clipSize({ widthVal, heightVal }) {
+			let { minWidth, minHeight } = this;
+			minWidth = minWidth / 2;
+			minHeight = minHeight / 2;
+			if (widthVal < minWidth) {
+				this.setDiffData({clipWidth: minWidth})
+			}
+			if (heightVal < minHeight) {
+				this.setDiffData({clipHeight: minHeight})
+			}
+			this.calcClipSize();
+		},
+		angle(val) {
+			this.animation = true;
+			this.moveStop();
+			const { isLimitMove } = this;
+			if (isLimitMove && val % 90) {
+				this.setDiffData({
+					angle: Math.round(val / 90) * 90
+				})
+			}
+			this.imgMarginDetectionScale();
+		},
+		animation(val) {
+			clearTimeout(this.animationTimer);
+			if (val) {
+				let animationTimer = setTimeout(() => {
+					this.setDiffData({
+						animation: false
+					})
+				}, 260);
+				this.setDiffData({animationTimer})
+				this.animationTimer = animationTimer;
+			}
+		},
+		isLimitMove(val) {
+			if (val) {
+				if (this.angle % 90) {
+					this.setDiffData({
+						angle : Math.round(this.angle / 90) * 90
+					})
+				}
+				this.imgMarginDetectionScale();
+			}
+		},
+		clipPoint() {
+			this.cutDetectionPosition();
+		},
+		width(width, oWidth) {
+			if (width !== oWidth) {
+				this.setDiffData({
+					clipWidth:  width / 2
+				})
+			}
+		},
+		height(height, oHeight) {
+			if (height !== oHeight) {
+				this.setDiffData({
+					clipHeight:  height / 2
+				})
+			}
+		}
+	},
+	mounted() {
+		const sysinfo = uni.getSystemInfoSync();
+		this.sysinfo = sysinfo;
+		this.setClipInfo();
+		if(this.image) {
+			this.getImageInfo(this.image)
+		}
+		this.setClipCenter();
+		this.calcClipSize();
+		this.cutDetectionPosition();
+	},
+	methods: {
+		setDiffData(data) {
+			Object.keys(data).forEach(key => {
+			  if (this[key] !== data[key]) {
+				this[key] = data[key];
+			  }
+			});
+		},
+		getImageInfo(url) {
+			if (!url) return;
+			if(this.value) {
+				uni.showLoading({
+					title: '请稍候...',
+					mask: true
+				});
+			}
+			uni.getImageInfo({
+				src: url,
+				success: res => {
+					this.imgComputeSize(res.width, res.height);
+					this.image = res.path;
+					if (this.isLimitMove) {
+						this.imgMarginDetectionScale();
+						this.$emit('ready', res);
+					}
+					const {imageWidth, imageHeight, imageLeft, imageTop, scale, clipX, clipY, clipWidth, clipHeight} = this
+					cache[url] = Object.assign(res, {imageWidth, imageHeight, imageLeft, imageTop, scale, clipX, clipY, clipWidth, clipHeight});
+				},
+				fail: (err) => {
+					this.imgComputeSize();
+					if (this.isLimitMove) {
+						this.imgMarginDetectionScale();
+					}
+				}
+			});
+			
+		},
+		setClipInfo() {
+			const { width, height, sysinfo, canvasId } = this;
+			const clipWidth = width / 2;
+			const clipHeight = height / 2;
+			const clipY = (sysinfo.windowHeight - clipHeight) / 2;
+			const clipX = (sysinfo.windowWidth - clipWidth) / 2;
+			const imageLeft = sysinfo.windowWidth / 2;
+			const imageTop = sysinfo.windowHeight / 2;
+			this.ctx = uni.createCanvasContext(canvasId, this);
+			this.clipWidth = clipWidth;
+			this.clipHeight = clipHeight;
+			this.clipX = clipX;
+			this.clipY = clipY;
+			this.canvasHeight = clipHeight;
+			this.canvasWidth = clipWidth;
+			this.imageLeft = imageLeft;
+			this.imageTop = imageTop;
+		},
+		setClipCenter() {
+			const { sysInfo, clipHeight, clipWidth, imageTop, imageLeft } = this;
+			let sys = sysInfo || uni.getSystemInfoSync();
+			let clipY = (sys.windowHeight - clipHeight) * 0.5;
+			let clipX = (sys.windowWidth - clipWidth) * 0.5;
+			this.imageTop = imageTop - this.clipY + clipY;
+			this.imageLeft = imageLeft - this.clipX + clipX;
+			this.clipY = clipY;
+			this.clipX = clipX;
+		},
+		calcClipSize() {
+			const { clipHeight, clipWidth, sysinfo, clipX, clipY } = this;
+			if (clipWidth > sysinfo.windowWidth) {
+				this.setDiffData({
+					clipWidth:  sysinfo.windowWidth
+				})
+			} else if (clipWidth + clipX > sysinfo.windowWidth) {
+				this.setDiffData({
+					clipX: sysinfo.windowWidth - clipX
+				})
+			}
+			if (clipHeight > sysinfo.windowHeight) {
+				this.setDiffData({
+					clipHeight: sysinfo.windowHeight
+				})
+			} else if (clipHeight + clipY > sysinfo.windowHeight) {
+				this.clipY = sysinfo.windowHeight - clipY;
+				this.setDiffData({
+					clipY: sysinfo.windowHeight - clipY
+				})
+			}
+		},
+		cutDetectionPosition() {
+			const { clipX, clipY, sysinfo, clipHeight, clipWidth } = this;
+			let cutDetectionPositionTop = () => {
+					if (clipY < 0) {
+						this.setDiffData({clipY: 0})
+					}
+					if (clipY > sysinfo.windowHeight - clipHeight) {
+						this.setDiffData({clipY: sysinfo.windowHeight - clipHeight})
+					}
+				},
+				cutDetectionPositionLeft = () => {
+					if (clipX < 0) {
+						this.setDiffData({clipX: 0})
+					}
+					if (clipX > sysinfo.windowWidth - clipWidth) {
+						this.setDiffData({clipX: sysinfo.windowWidth - clipWidth})
+					}
+				};
+			if (clipY === null && clipX === null) {
+				let newClipY = (sysinfo.windowHeight - clipHeight) * 0.5;
+				let newClipX = (sysinfo.windowWidth - clipWidth) * 0.5;
+				this.setDiffData({
+					clipX: newClipX,
+					clipY: newClipY
+				})
+			} else if (clipY !== null && clipX !== null) {
+				cutDetectionPositionTop();
+				cutDetectionPositionLeft();
+			} else if (clipY !== null && clipX === null) {
+				cutDetectionPositionTop();
+				this.setDiffData({
+					clipX: (sysinfo.windowWidth - clipWidth) / 2
+				})
+			} else if (clipY === null && clipX !== null) {
+				cutDetectionPositionLeft();
+				this.setDiffData({
+					clipY: (sysinfo.windowHeight - clipHeight) / 2
+				})
+			}
+		},
+		imgComputeSize(width, height) {
+			const { imageWidth, imageHeight } = calcImageSize(width, height, this);
+			this.imageWidth = imageWidth;
+			this.imageHeight = imageHeight;
+		},
+		imgMarginDetectionScale(scale) {
+			if (!this.isLimitMove) return;
+			const currentScale = calcImageScale(this, scale);
+			this.imgMarginDetectionPosition(currentScale);
+		},
+		imgMarginDetectionPosition(scale) {
+			if (!this.isLimitMove) return;
+			const { scale: currentScale, left, top } = calcImageOffset(this, scale);
+			this.setDiffData({
+				imageLeft: left,
+				imageTop: top,
+				scale: currentScale
+			})
+		},
+		throttle() {
+			this.setDiffData({
+				throttleFlag: true
+			})
+		},
+		moveDuring() {
+			clearTimeout(this.timeClipCenter);
+		},
+		moveStop() {
+			clearTimeout(this.timeClipCenter);
+			const timeClipCenter = setTimeout(() => {
+				if (!this.animation) {
+					this.setDiffData({animation: true})
+				}
+				this.setClipCenter();
+			}, 800);
+			this.setDiffData({timeClipCenter})
+		},
+		clipTouchStart(event) {
+			// #ifdef H5
+			event.preventDefault()
+			// #endif
+			if (!this.image) {
+				uni.showToast({icon: 'none',
+					title: '请选择图片',
+				
+				});
+				return;
+			}
+			const currentX = event.touches[0].clientX;
+			const currentY = event.touches[0].clientY;
+			const { clipX, clipY, clipWidth, clipHeight } = this;
+			const corner = determineDirection(clipX, clipY, clipWidth, clipHeight, currentX, currentY);
+			this.moveDuring();
+			if(!corner) {return}
+			this.clipStart = {
+				width: clipWidth,
+				height: clipHeight,
+				x: currentX,
+				y: currentY,
+				clipY,
+				clipX,
+				corner
+			};
+			this.flagClipTouch = true;
+			this.flagEndTouch = true;
+		},
+		clipTouchMove(event) {
+			// #ifdef H5
+			event.stopPropagation()
+			event.preventDefault()
+			// #endif
+			if (!this.image) {
+				uni.showToast({icon: 'none',
+					title: '请选择图片',
+					 
+				});
+				return;
+			}
+			// 只针对单指点击做处理
+			if (event.touches.length !== 1) {
+				return;
+				
+			}
+			const { flagClipTouch, throttleFlag } = this;
+			if (flagClipTouch && throttleFlag) {
+				const { isLockRatio, isLockHeight, isLockWidth } = this;
+				if (isLockRatio && (isLockWidth || isLockHeight)) return;
+				this.setDiffData({
+					throttleFlag: false
+				})
+				this.throttle();
+				const clipData = clipTouchMoveOfCalculate(this, event);
+				if(clipData) {
+					const { width, height, clipX, clipY } = clipData;
+					if (!isLockWidth && !isLockHeight) {
+						this.setDiffData({
+							clipWidth: width,
+							clipHeight: height,
+							clipX,
+							clipY
+						})
+					} else if (!isLockWidth) {
+						this.setDiffData({
+							clipWidth: width,
+							clipX
+						})
+					} else if (!isLockHeight) {
+						this.setDiffData({
+							clipHeight: height,
+							clipY
+						})
+					}
+					this.imgMarginDetectionScale();
+				}
+
+			}
+		},
+		clipTouchEnd() {
+			this.moveStop();
+			this.flagClipTouch = false;
+		},
+		imageTouchStart(e) {
+			// #ifdef H5
+			event.preventDefault()
+			// #endif
+			this.flagEndTouch = false;
+			const { imageLeft, imageTop } = this;
+			const clientXForLeft = e.touches[0].clientX;
+			const clientYForLeft = e.touches[0].clientY;
+
+			let touchRelative = [];
+			if (e.touches.length === 1) {
+				touchRelative[0] = {
+					x: clientXForLeft - imageLeft,
+					y: clientYForLeft - imageTop
+				};
+				this.touchRelative = touchRelative;
+			} else {
+				const clientXForRight = e.touches[1].clientX;
+				const clientYForRight = e.touches[1].clientY;
+				let width = Math.abs(clientXForLeft - clientXForRight);
+				let height = Math.abs(clientYForLeft - clientYForRight);
+				const hypotenuseLength = calcPythagoreanTheorem(width, height);
+
+				touchRelative = [
+					{
+						x: clientXForLeft - imageLeft,
+						y: clientYForLeft - imageTop
+					},
+					{
+						x: clientXForRight - imageLeft,
+						y: clientYForRight - imageTop
+					}
+				];
+				this.touchRelative = touchRelative;
+				this.hypotenuseLength = hypotenuseLength;
+			}
+		},
+		imageTouchMove(e) {
+			// #ifdef H5
+			event.preventDefault()
+			// #endif
+			const { flagEndTouch, throttleFlag } = this;
+			if (flagEndTouch || !throttleFlag) return;
+			const clientXForLeft = e.touches[0].clientX;
+			const clientYForLeft = e.touches[0].clientY;
+			this.setDiffData({throttleFlag: false})
+			this.throttle();
+			this.moveDuring();
+			if (e.touches.length === 1) {
+				const { left: imageLeft, top:  imageTop} = imageTouchMoveOfCalcOffset(this, clientXForLeft, clientYForLeft);
+				this.setDiffData({
+					imageLeft,
+					imageTop
+				})
+				this.imgMarginDetectionPosition();
+			} else {
+				const clientXForRight = e.touches[1].clientX;
+				const clientYForRight = e.touches[1].clientY;
+				let width = Math.abs(clientXForLeft - clientXForRight),
+					height = Math.abs(clientYForLeft - clientYForRight),
+					hypotenuse = calcPythagoreanTheorem(width, height),
+					scale = this.scale * (hypotenuse / this.hypotenuseLength);
+				if (this.isDisableScale) {
+
+					scale = 1;
+				} else {
+					scale = scale <= this.minRatio ? this.minRatio : scale;
+					scale = scale >= this.maxRatio ? this.maxRatio : scale;
+					this.$emit('change', {
+						width: this.imageWidth * scale,
+						height: this.imageHeight * scale
+					});
+				}
+
+				this.imgMarginDetectionScale(scale);
+				this.hypotenuseLength = Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2));
+				this.scale = scale;
+			}
+		},
+		imageTouchEnd() {
+			this.setDiffData({
+				flagEndTouch: true
+			})
+			this.moveStop();
+		},
+		uploadImage() {
+			
+			
+			const itemList = Object.entries(this.source)
+			const sizeType = ['original', 'compressed']
+			const success = ({tempFilePaths:a, tempFiles: b}) => {
+				this.image = a ? a[0] : b[0].path
+			};
+			const _uploadImage = (type) => {
+				if(type !== 'message') {
+					uni.chooseImage({
+						count: 1,
+						sizeType,
+						sourceType: [type],
+						success
+					});
+				}
+				// #ifdef MP-WEIXIN
+				if(type == 'message') {
+					wx.chooseMessageFile({
+					  count: 1,
+					  type: 'image',
+					  success
+					})
+				}
+				// #endif
+			}
+			if(itemList.length > 1) {
+				uni.showActionSheet({
+					itemList: itemList.map(v => v[1]),
+					success: ({tapIndex: i}) => {
+						_uploadImage(itemList[i][0])
+					}
+				})
+			} else {
+				_uploadImage(itemList[0][0])
+			}
+		},
+		imageReset() {
+			const sys = this.sysinfo || uni.getSystemInfoSync();
+			this.scale = 1;
+			this.angle = 0;
+			this.imageTop = sys.windowHeight / 2;
+			this.imageLeft = sys.windowWidth / 2;
+		},
+		imageLoad(e) {
+			this.imageReset();
+			uni.hideLoading();
+			this.$emit('ready', e.detail);
+		},
+		rotate(event) {
+			if (this.isDisableRotate) return;
+			if (!this.image) {
+				uni.showToast({icon: 'none',
+					title: '请选择图片',
+					 
+				});
+				return;
+			}
+			const { rotateAngle } = this;
+			const originAngle = this.angle
+			const type = event.currentTarget.dataset.type;
+			if (type === 'along') {
+				this.angle = originAngle + rotateAngle
+			} else {
+				this.angle = originAngle - rotateAngle
+			}
+			this.$emit('rotate', this.angle);
+		},
+		confirm() {
+			if (!this.image) {
+				uni.showToast({icon: 'none',
+					title: '请选择图片',
+					 
+				});
+				return;
+			}
+			uni.showLoading({
+				title: '加载中'
+			});
+			const { canvasHeight, canvasWidth, clipHeight, clipWidth, ctx, scale, imageLeft, imageTop, clipX, clipY, angle, scaleRatio: dpr, image, quality, fileType, type: imageType, canvasId } = this;
+			const draw = () => {
+				const imageWidth = this.imageWidth * scale * dpr;
+				const imageHeight = this.imageHeight * scale * dpr;
+				const xpos = imageLeft - clipX;
+				const ypos = imageTop - clipY;
+				ctx.translate(xpos * dpr, ypos * dpr);
+				ctx.rotate((angle * Math.PI) / 180);
+				ctx.drawImage(image, -imageWidth / 2, -imageHeight / 2, imageWidth, imageHeight);
+				ctx.draw(false, () => {
+					const width = clipWidth * dpr
+					const height = clipHeight * dpr
+					let params = {
+						x: 0,
+						y: 0,
+						width,
+						height,
+						destWidth: width,
+						destHeight: height,
+						canvasId: canvasId,
+						fileType,
+						quality,
+						success: (res) => {
+							data.url = res.tempFilePath;
+							uni.hideLoading();
+							this.$emit('success', data);
+							this.$emit('input', false)
+						},
+						fail: (error) => {
+							//.error('error', error)
+							this.$emit('fail', error);
+							this.$emit('input', false)
+						}
+					};
+
+					let data = {
+						url: '',
+						width,
+						height
+					};
+					uni.canvasToTempFilePath(params, this)
+				});
+			};
+
+			if (canvasWidth !== clipWidth || canvasHeight !== clipHeight) {
+				this.canvasWidth = clipWidth;
+				this.canvasHeight = clipHeight;
+				ctx.draw();
+				this.$nextTick(() => {
+					setTimeout(() => {
+						draw();
+					}, 100);
+				})
+			} else {
+				draw();
+			}
+		},
+		cancel() {
+			this.$emit('cancel', false)
+			this.$emit('input', false)
+		},
+	}
+};
+</script>
+
+<style scoped>
+@import './index'
+</style>

部分文件因为文件数量过多而无法显示