zhengkaixin 3 hete
commit
728d9caf4d
100 módosított fájl, 14489 hozzáadás és 0 törlés
  1. 112 0
      App.vue
  2. 7 0
      README.md
  3. 84 0
      apis/common.js
  4. 5 0
      apis/index.js
  5. 98 0
      apis/pagejs/deviceTab.js
  6. 111 0
      apis/pagejs/index.js
  7. 35 0
      apis/pagejs/pagejsIndex.js
  8. 65 0
      apis/pagejs/pagesTask.js
  9. 21 0
      apis/pagejs/pagesTeam.js
  10. 35 0
      apis/pagejs/user.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. BIN
      assets/font/jptime.otf
  26. 22 0
      assets/icon/icon.vue
  27. BIN
      assets/img/circleCopy1@1x.png
  28. BIN
      assets/img/daohuang.png
  29. 6 0
      assets/img/deviceTab/index2-1.svg
  30. BIN
      assets/img/deviceTab/index3-2.png
  31. BIN
      assets/img/index/na-1.png
  32. BIN
      assets/img/index/na-2.png
  33. BIN
      assets/img/index/na-3.png
  34. BIN
      assets/img/logo/logo.png
  35. BIN
      assets/img/success.png
  36. 6 0
      assets/img/tabbarImg/item1a.svg
  37. 6 0
      assets/img/tabbarImg/item1b.svg
  38. 6 0
      assets/img/tabbarImg/item2a.svg
  39. 6 0
      assets/img/tabbarImg/item2b.svg
  40. 6 0
      assets/img/tabbarImg/item3a.svg
  41. 6 0
      assets/img/tabbarImg/item3b.svg
  42. 6 0
      assets/img/tabbarImg/item4a.svg
  43. 6 0
      assets/img/tabbarImg/item4b.svg
  44. BIN
      assets/img/taskstatus/status1.png
  45. BIN
      assets/img/taskstatus/status2.png
  46. BIN
      assets/img/taskstatus/status3.png
  47. BIN
      assets/img/topspan/span1.png
  48. BIN
      assets/img/topspan/span2.png
  49. BIN
      assets/img/topspan/span3.png
  50. BIN
      assets/img/topspan/span4.png
  51. BIN
      assets/img/topspan/span5.png
  52. BIN
      assets/img/暂无数据-缺省页.png
  53. BIN
      assets/img/默认头像.png
  54. 34 0
      assets/js/font.js
  55. 48 0
      components/JPcontent.vue
  56. 205 0
      components/Map-equipment.vue
  57. 167 0
      components/ShareServer.vue
  58. 81 0
      components/Tabbar.vue
  59. 153 0
      components/bobo-router/README.md
  60. 362 0
      components/bobo-router/bobo-router.js
  61. 64 0
      components/bobo-router/index.js
  62. 227 0
      components/limeClipper/README.md
  63. 19 0
      components/limeClipper/images/photo.svg
  64. 15 0
      components/limeClipper/images/rotate.svg
  65. 160 0
      components/limeClipper/index.css
  66. 816 0
      components/limeClipper/limeClipper.vue
  67. 244 0
      components/limeClipper/utils.js
  68. 28 0
      config/.env.dev.js
  69. 42 0
      config/.env.js
  70. 21 0
      config/.env.prod.js
  71. 17 0
      config/.env.test.js
  72. 20 0
      index.html
  73. 117 0
      main.js
  74. 92 0
      manifest.json
  75. 55 0
      package.json
  76. 189 0
      pages.json
  77. 2179 0
      pages/index/demo.vue
  78. 780 0
      pages/index/index.vue
  79. 1793 0
      pages/lockTab/dataLock.vue
  80. 304 0
      pages/lockTab/listLock.vue
  81. 227 0
      pages/login/login.vue
  82. 107 0
      pages/myTab/abnormalInfo.vue
  83. 273 0
      pages/myTab/abnormalList.vue
  84. 227 0
      pages/myTab/as-components/limeClipper/README.md
  85. 19 0
      pages/myTab/as-components/limeClipper/images/photo.svg
  86. 15 0
      pages/myTab/as-components/limeClipper/images/rotate.svg
  87. 160 0
      pages/myTab/as-components/limeClipper/index.css
  88. 818 0
      pages/myTab/as-components/limeClipper/limeClipper.vue
  89. 244 0
      pages/myTab/as-components/limeClipper/utils.js
  90. 103 0
      pages/myTab/changePassword.vue
  91. 198 0
      pages/myTab/changePhone.vue
  92. 38 0
      pages/myTab/cropImage.vue
  93. 153 0
      pages/myTab/customerService.vue
  94. 446 0
      pages/myTab/dataUser.vue
  95. 146 0
      pages/myTab/feedbackList.vue
  96. 130 0
      pages/myTab/feedbackSubmit.vue
  97. 304 0
      pages/myTab/index.vue
  98. 215 0
      pages/myTab/myMessage.vue
  99. 92 0
      pages/myTab/setting.vue
  100. 332 0
      pages/task/addTask.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>

+ 7 - 0
README.md

@@ -0,0 +1,7 @@
+
+[](https://modao.cc/proto/0IatAHTQs9utzggeat2cRV/sharing?view_mode=inspect&screen=rbpU6730lGqv3KI4h)
+
+
+[](https://zbyj.hbjp.com.cn/floorlock-portal)
+
+ 

+ 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'
+ 

+ 98 - 0
apis/pagejs/deviceTab.js

@@ -0,0 +1,98 @@
+import requestWhite from '@/apis/utils/requestWhite'
+
+export function add(data) {
+ 	return requestWhite({
+ 		method: 'post',
+ 		data: data,
+ 		url: '/mobile/application/add'
+ 	})
+}
+
+export function errList(data) {
+	var url='/mobile/floorlockError/errList';
+	return requestWhite({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+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 findFloorLock(data) {
+	var url='/mobile/floorlock/findFloorLock';
+	
+	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
+	})
+}

+ 111 - 0
apis/pagejs/index.js

@@ -0,0 +1,111 @@
+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';
+	if(!data){
+		data={}
+	}
+	data.roleName='XJ'
+	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
+	})
+}

+ 35 - 0
apis/pagejs/pagejsIndex.js

@@ -0,0 +1,35 @@
+import request from '@/apis/utils/request'
+
+
+export function errList(data) {
+	var url='/mobile/floorlockError/errList';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+export function findByOpenId(data) {
+	var url='/mobile/sysUser/findByOpenId';
+	 
+	if(!data){
+		data={}
+	}
+	data.roleName='XJ'
+	return request({
+		method: 'get',
+		data: data,
+		url: url
+	})
+}
+
+
+export function floorStatus(data) {
+	var url='/mobile/inspection/floorStatus';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}

+ 65 - 0
apis/pagejs/pagesTask.js

@@ -0,0 +1,65 @@
+
+
+import request from '@/apis/utils/request'
+
+
+export function errList(data) {
+	var url='/mobile/floorlockError/errList';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+
+export function findFloorLock(data) {
+	var url='/mobile/floorlock/findFloorLock';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+
+
+export function addErr(data) {
+	var url='/mobile/floorlockError/addErr';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+
+
+export function errDetails(data) {
+	var url='/mobile/floorlockError/errDetails';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+export function updateErr(data) {
+	var url='/mobile/floorlockError/updateErr';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+
+export function findByCatalogName(data) {
+	var url='/mobile/dataDictionary/findByCatalogName';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+

+ 21 - 0
apis/pagejs/pagesTeam.js

@@ -0,0 +1,21 @@
+
+import request from '@/apis/utils/request'
+
+
+export function userList(data) {
+	var url='/mobile/sysUser/userList';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}
+
+export function adduser(data) {
+	var url='/mobile/sysUser/adduser';
+	return request({
+		method: 'post',
+		data: data,
+		url: url
+	})
+}

+ 35 - 0
apis/pagejs/user.js

@@ -0,0 +1,35 @@
+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';
+	 
+	if(!data){
+		data={}
+	}
+	data.roleName='XJ'
+	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
+	})
+}

+ 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,
+				roleName:'XJ'
+		}
+		 
+		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,
+			roleName:'XJ'
+				
+		}
+		
+		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
+}

BIN
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>

BIN
assets/img/circleCopy1@1x.png


BIN
assets/img/daohuang.png


+ 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>

BIN
assets/img/deviceTab/index3-2.png


BIN
assets/img/index/na-1.png


BIN
assets/img/index/na-2.png


BIN
assets/img/index/na-3.png


BIN
assets/img/logo/logo.png


BIN
assets/img/success.png


+ 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>

BIN
assets/img/taskstatus/status1.png


BIN
assets/img/taskstatus/status2.png


BIN
assets/img/taskstatus/status3.png


BIN
assets/img/topspan/span1.png


BIN
assets/img/topspan/span2.png


BIN
assets/img/topspan/span3.png


BIN
assets/img/topspan/span4.png


BIN
assets/img/topspan/span5.png


BIN
assets/img/暂无数据-缺省页.png


BIN
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
+	};
+}

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

@@ -0,0 +1,28 @@
+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",
+	openId:"oRGjz7DZM-rK3MpkjV6_VnoUhLI0",
+	
+	
+	//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;

+ 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"
+				}
+			}
+		}
+	}
+}

+ 189 - 0
pages.json

@@ -0,0 +1,189 @@
+{
+
+	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTitleText": ""
+			}
+		},
+
+		{
+			"path": "pages/login/login",
+			"style": {
+				"navigationBarTitleText": "",
+				"enablePullDownRefresh": false
+			}
+		},
+		{
+			"path" : "pages/task/addTask",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+	
+	
+		{
+			"path" : "pages/task/maintenanceTaks",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+	
+		{
+			"path" : "pages/lockTab/dataLock",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		
+		
+		{
+			"path" : "pages/myTab/index",
+			"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/task/selectLock",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/task/listTask",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/lockTab/listLock",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/team/teamList",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/team/teamAdd",
+			"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": {}
+}

+ 2179 - 0
pages/index/demo.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>

+ 780 - 0
pages/index/index.vue

@@ -0,0 +1,780 @@
+<template>
+	<view>
+		<u-navbar v-show="false" title="首页" title-color="#101010"></u-navbar>
+		<view class="back-blue">
+			<view class="back-color">
+
+			</view>
+		</view>
+		<view class="main_top">
+			<view class="main_top1">
+				<view class="logo_img">
+					<image class="img" src="@/assets/img/logo/logo.png" mode=""></image>
+				</view>
+				<view class="logo_text">
+					<view class="logo_text1">
+						智泊e家
+
+					</view>
+					<view class="logo_text2">
+						巡检端
+					</view>
+				</view>
+			</view>
+			<view class="main_top2">
+				<!-- 消息提醒位置 -->
+			</view>
+		</view>
+		<view class="main_navigation panel"  >
+			<view class="item-na end" @click="gotoUrl('/pages/task/addTask')">
+				<view class="na-img">
+					<image class="img" src="@/assets/img/index/na-1.png" mode=""></image>
+				</view>
+				<view class="na-text ">
+					故障上报
+				</view>
+			</view>
+			<view class="item-na-b"  v-if="isAdmin"  >
+
+			</view>
+			<view class="item-na end"   @click="gotoUrl('/pages/team/teamList')" v-if="isAdmin"  >
+				<view class="na-img">
+					<image class="img" src="@/assets/img/index/na-3.png" mode=""></image>
+				</view>
+				<view class="na-text">
+					团队管理
+				</view>
+			</view>
+			
+			<view class="item-na-b"  >
+			
+			</view>
+			
+			<view class="item-na end"   @click="gotoUrl('/pages/task/listTask')"   >
+				<view class="na-img">
+					<image class="img" src="@/assets/img/index/na-2.png" mode=""></image>
+				</view>
+				<view class="na-text">
+					故障记录
+				</view>
+			</view>
+			
+			
+		</view>
+		<view class="main_statuspanel panel">
+			<view class="top-main">
+				<view class="title-main">
+					地锁状态
+
+				</view>
+				<view class="goto-main"  @click="gotoUrl('/pages/lockTab/listLock')">
+					查看详情
+					<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+				</view>
+			</view>
+			<view class="body">
+				<view class="pie">
+					<view id="body1pie1" class="body1pie">
+
+					</view>
+					<view  class="body2pie" v-if="datafloorStatus.totalNum">
+						<view class="v1">{{datafloorStatus.totalNum}}</view>
+						<view class="v2">地锁:套</view>
+					</view>
+				</view>
+				<view class="item-list">
+					<view class="item-status">
+						<view class="num">
+							{{datafloorStatus.normalNum}}
+						</view>
+						<view class="statusN">
+							<view class="statusC status1">
+
+							</view>
+							<view class="statusT">
+								在线
+							</view>
+						</view>
+					</view>
+					<view class="item-status">
+						<view class="num">
+							{{datafloorStatus.errorNum}}
+						</view>
+						<view class="statusN">
+							<view class="statusC status2">
+
+							</view>
+							<view class="statusT">
+								故障
+
+							</view>
+						</view>
+					</view>
+					<view class="item-status">
+						<view class="num">
+							{{datafloorStatus.loseNum}}
+						</view>
+						<view class="statusN">
+							<view class="statusC status3">
+
+							</view>
+							<view class="statusT">
+								离线
+
+							</view>
+						</view>
+					</view>
+					<view class="item-status" >
+						<view class="num">
+							0
+						</view>
+						<view class="statusN">
+							<view class="statusC status4">
+
+							</view>
+							<view class="statusT">
+								维护
+
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+		<view class="main_list1 ">
+			
+			<u-tabs :list="tabslist"
+			 style="   width: 50%;"
+			 :current="current" @change="change"></u-tabs>
+			 
+			<view class="list"  >
+				<view class="item" 
+				 v-for="(item,index) in dataerrList" 
+				 @click="gotoUrl('/pages/task/maintenanceTaks?id='+item.id)"
+				 :key="index">
+					<view class="icon">
+						
+						<image class="img" v-if="item.errorCodeImage" :src="item.errorCodeImage" mode=""></image>
+						
+						<image class="img" v-else src="@/assets/img/taskstatus/status3.png" mode=""></image>
+					</view>
+					<view class="body">
+						<view class="line1">
+							<view class="title">
+								<span  v-if="item.type" :class="'typeN typeN'+item.type">
+									{{item.typeN}}
+								</span>
+								{{item.errorCodeText}}
+
+							</view>
+							<view class="status " :class="'status'+item.status">
+								{{item.statusN}}
+
+							</view>
+						</view>
+						
+						<view class="line2">
+							<view class="value">
+								{{item.createTime}}<span style="color: red;" v-if="isToday(item.createTime)">(今日)</span>
+
+							</view>
+							<view class="value">
+								{{item.parkingName}} 
+
+							</view>
+						</view>
+						<view class="errorDesc" v-if="item.errorDesc">
+							描述:{{item.errorDesc}}
+							
+						</view>
+
+					</view>
+					<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+				</view>
+				
+				<u-divider color="#F44336" 
+				 :isnone="dataerrRecordsTotal==0" nonetext="暂无数据"
+				 v-if="dataerrRecordsTotal>5&&current==0"
+				 @click="gotoUrl('/pages/task/listTask?status='+tabslist[current].code)"  >故障记录{{dataerrRecordsTotal}}条,点击查看更多</u-divider>
+				 <u-divider color="#CFD2D5"  v-else
+				 
+				 :isnone="dataerrRecordsTotal==0" nonetext="暂无数据"
+				  @click="gotoUrl('/pages/task/listTask?status='+tabslist[current].code)"  >查看详情</u-divider>
+				  
+				
+			</view>
+
+		</view>
+
+
+
+		 
+		
+		<tabbar :current="0"></tabbar>
+		
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/pagejsIndex.js'
+	
+	import * as echarts from 'echarts';
+	import Tabbar from '@/components/Tabbar.vue'
+
+import {
+	
+		newDate
+	} from '@/apis/utils'
+	export default {
+		components: {
+			Tabbar,
+			
+		},
+		data() {
+			return {
+				echartsList: {},
+				isReadyfloorStatus:false,
+				datafloorStatus:{},
+				roleList:[],
+				isReadyerrList:false,
+				dataerrList:[],
+				dataerrRecordsTotal:0,
+				tabslist:[
+					{
+						name: '待处理',
+						code:"geterrList0"
+						
+					}, {
+						name: '已处理',
+						code:"geterrList1"
+					}
+				],
+				current:0,
+			};
+		},
+		onLoad() {
+			this.roleList=this.jphelp.getPersonInfoPlus().roleList
+		},
+		onShow() {
+			this.roleList=this.jphelp.getPersonInfoPlus().roleList
+			if(this.isReadyfloorStatus){
+				this.getfloorStatus()
+			}
+			if(this.isReadyerrList){
+				this.geterrList()
+			}
+			
+		},
+		computed:{
+				isAdmin(){
+					if(this.roleList){
+						var i =this.roleList.findIndex(item=>{
+							return item.name=='XJADMIN'
+						})
+						if(i!=-1){
+								return true
+						}
+					}
+					return false
+				}
+		},
+		onReady() {
+			this.geterrList()
+			this.getfloorStatus()
+			//this.getbody1pie1()
+			this.query()
+		},
+		methods: {
+			change(e){
+				this.current=e
+				
+				this.dataerrList =[]
+				
+				this.geterrList()
+			},
+			
+			isToday(dateStr) {
+			    // 将传入的日期字符串转换为Date对象
+			    const targetDate = newDate(dateStr);
+			    // 获取当前日期
+			    const today = new Date();
+			
+			    // 比较年份、月份和日期是否相等
+			    return (
+			        targetDate.getFullYear() === today.getFullYear() &&
+			        targetDate.getMonth() === today.getMonth() &&
+			        targetDate.getDate() === today.getDate()
+			    );
+			},
+			query(){
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				
+				API.findByOpenId({
+					noerror:true,
+					openId: this.jphelp.getOpenId(),
+				 
+				
+				}).then((response) => {
+					uni.hideLoading();
+					if(response.message){
+						uni.hideLoading();
+						
+					}else{
+						this.loginset(response)
+						
+						 
+					}
+					this.roleList=this.jphelp.getPersonInfoPlus().roleList
+					
+					
+				
+				}).catch(error => {
+					
+					uni.hideLoading();
+					
+				})
+			},
+			geterrList(){
+				var status=0
+				var code=this.tabslist[this.current].code
+				if(code=="geterrList0"){
+					status=0
+				}
+				if(code=="geterrList1"){
+					status=1
+				}
+				API.errList({
+					pageIndex:1,
+					pageSize:5,
+					status:status,
+				}).then((response) => {
+					this.dataerrList=response.data.data
+					this.dataerrRecordsTotal=response.data.recordsTotal
+					this.isReadyerrList=true
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				
+				})
+			},
+			getfloorStatus(){
+				
+				API.floorStatus().then((response) => {
+					var obj=response.data;
+					var sz=['totalNum','normalNum','errorNum','loseNum']
+					var bl=false
+					for(var i in sz){
+						if(obj[sz[i]]!=this.datafloorStatus[sz[i]]){
+							bl=true
+							this.datafloorStatus=obj
+						}
+					}
+					
+					this.isReadyfloorStatus=true
+					if(bl){
+						this.getbody1pie1()
+					}
+					
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				
+				})
+			},
+			getbody1pie1() {
+				var key = "body1pie1"
+				var myChart = this.echartsList[key];
+				if (!myChart) {
+					myChart = echarts.init(document.getElementById(key), null, {
+						width: uni.upx2px(88 * 2),
+						height: uni.upx2px(88 * 2)
+					})
+
+				}
+				myChart.clear()
+				var option = {
+				  
+					series: [{
+						silent: true,
+						type: 'pie',
+						radius: ['80%', '100%'],
+						label: {
+							show: false,
+						},
+
+						data: [{
+								value: this.datafloorStatus.normalNum,
+								itemStyle: {
+									color: 'rgba(0, 185, 98, 1)'
+								}
+							},
+							{
+									value: this.datafloorStatus.loseNum,
+									itemStyle: {
+										color: 'rgba(153, 153, 153, 1)'
+									}
+								},
+							{
+								value: this.datafloorStatus.errorNum,
+								itemStyle: {
+									color: 'rgba(255, 123, 0, 1)'
+								}
+							}
+						]
+					}],
+					grid: {
+						top: 0,
+						left: 0,
+						right: 0,
+						bottom: 0,
+						containLabel: true
+					},
+
+				}
+				myChart.setOption(option);
+				console.log(option)
+				this.echartsList[key] = myChart;
+			}
+		}
+	}
+</script>
+<style>
+	page{
+		background-color: #FFFFFF;
+	}
+</style>
+<style lang="scss">
+	.back-blue {
+		height: 0px;
+
+		.back-color {
+			height: 656rpx;
+			background: linear-gradient(180deg, rgba(22, 119, 255, 1) 53%, rgba(203, 234, 255, 0) 100%);
+
+		}
+	}
+
+	.top-main {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+
+		.title-main {
+			color: rgba(51, 51, 51, 1);
+			font-size: 32rpx;
+			font-weight: bold;
+		}
+
+		.goto-main {
+			color: rgba(131, 131, 131, 1);
+			font-size: 24rpx;
+		}
+	}
+
+	.panel,
+	.main_top {
+		margin: 0 32rpx;
+	}
+
+	.panel {
+		border-radius: 8px;
+		background-color: rgba(255, 255, 255, 1);
+		box-shadow: 0px 4px 8px 0px rgba(22, 119, 255, 0.1);
+	}
+
+	.main_top {
+		margin-top: 32rpx;
+		display: flex;
+		justify-content: space-between;
+
+		.main_top1 {
+			display: flex;
+			align-items: center;
+
+			.logo_img {
+				.img {
+					border-radius: 8px;
+					width: 96rpx;
+					height: 96rpx;
+				}
+
+				margin-right: 16rpx;
+			}
+
+			.logo_text {
+				color: #fff;
+
+				.logo_text1 {
+					font-size: 20px;
+				}
+
+				.logo_text2 {
+					font-size: 16px;
+
+				}
+			}
+		}
+
+		.main_top2 {}
+	}
+
+	.main_navigation {
+		margin-top: 32rpx;
+		display: flex;
+		justify-content: space-around;
+		align-items: center;
+		padding: 24rpx 0 20rpx 0;
+
+		.item-na-b {
+			border-left: 1px solid rgba(187, 187, 187, 0.43);
+			height: 70rpx;
+		}
+
+		.item-na {
+			width: 32%;
+			text-align: center;
+
+			.na-img {
+				display: flex;
+				justify-content: center;
+
+				.img {
+					width: 80rpx;
+					height: 80rpx;
+				}
+			}
+		}
+	}
+
+	.main_statuspanel {
+		margin-top: 24rpx;
+		padding: 24rpx;
+		.body2pie{
+			    position: relative;
+			    top: -140rpx;
+			    height: 0px;
+			    left: 0px;
+				width: 176rpx;
+				text-align: center;
+				.v1{
+					color: rgba(16,16,16,1);
+					font-size: 48rpx;
+					font-weight: bold;
+				}
+				.v2{
+					color: rgba(119,119,119,1);
+					font-size: 24rpx;
+				}
+		}
+		.body {
+			display: flex;
+			padding: 24rpx;
+
+			.item-list {
+				margin-left: 48rpx;
+				display: flex;
+				width: 100%;
+				flex-wrap: wrap;
+
+				.item-status {
+					width: 50%;
+
+					.num {
+						color: rgba(51, 51, 51, 1);
+						font-size: 36rpx;
+						font-weight: bold;
+					}
+				}
+
+				.statusN {
+					display: flex;
+					align-items: center;
+
+					.statusC {
+						margin-right: 8rpx;
+						width: 16rpx;
+						height: 16rpx;
+						background-color: rgba(153, 153, 153, 1);
+					}
+
+					.status1 {
+						background-color: rgba(0, 185, 98, 1);
+					}
+
+					.status2 {
+						background-color: rgba(255, 123, 0, 1);
+					}
+
+					.status3 {
+						background-color: rgba(153, 153, 153, 1);
+					}
+
+					.status4 {
+						background-color: rgba(129, 97, 255, 1);
+					}
+				}
+
+			}
+		}
+	}
+
+	.main_list1 {
+		margin-top: 24rpx;
+		padding: 24rpx;
+		padding-bottom: 36rpx;
+		.list-body{
+			padding: 24rpx 0;
+			.item {
+				border-bottom: 1px solid rgba(232, 232, 232, 1);
+			}
+			.title {
+				display: flex;
+				    justify-content: space-between;
+					.name{
+						color: rgba(51,51,51,1);
+						font-size: 32rpx;
+						font-weight: bold;
+					}
+					.status{
+						
+					}
+					.statusN1{
+						
+					}
+					.statusN2{
+						
+					}
+					.statusN3{
+						
+					}
+			}
+			.body{
+				    display: flex;
+					color: rgba(51,51,51,1);
+					font-size: 28rpx;
+				.name{
+					width: 150rpx;
+				}
+				.value{
+					
+				}
+			}
+		}
+		
+		
+		.list {
+			//padding: 24rpx 0;
+
+			.item {
+				display: flex;
+				border-bottom: 1px solid rgba(232, 232, 232, 1);
+				padding: 12rpx 0;
+				margin: 12rpx 0;
+
+				.img {
+					width: 72rpx;
+					height: 72rpx;
+
+				}
+
+				.body {
+					margin: 0 12rpx;
+					width: 100%;
+
+					.line1,
+					.line2 {
+
+						display: flex;
+						justify-content: space-between;
+					}
+					.line2 {
+						color: rgba(119,119,119,1);
+						font-size: 24rpx;
+						margin-top: 8rpx;
+					}
+					.line1 {
+						.typeN{
+							font-size: 24rpx;
+							margin-right: 8rpx;
+							display: flex;
+							align-items: center;
+								border-radius: 4px;
+								padding: 2px 8rpx;
+								color: #fff;
+								font-weight: 400;
+						}
+						.typeN1{
+							background-color:#1677ff;
+							//border: 1px solid #1677ff;
+						}
+						.typeN2{
+							background-color:#19be6b;
+							//border: 1px solid #19be6b;
+							 
+						}
+						.title {
+							display: flex;
+							color: rgba(51, 51, 51, 1);
+							font-size: 28rpx;
+							font-weight: bold;
+						}
+
+						.status {
+							background-color:  rgba(255, 61, 0, 1);
+							font-size: 24rpx;
+							color:#fff;
+							padding: 2rpx 8rpx;
+							//border-radius: 4px;
+
+						}
+						
+						.status0 {
+							background-color:  rgba(255, 61, 0, 1);
+							
+						}
+						.status1 {
+							background-color:  #007aff;
+							
+						}
+
+						.status2 {
+							background-color:  #ff9900;
+							
+						}
+
+						.status3 {
+							background-color:  #19be6b;
+							
+						}
+
+						.status4 {
+							border: 1px solid rgba(255, 61, 0, 1);
+							color: rgba(255, 61, 0, 1);
+						}
+					}
+					
+					.errorDesc{
+						margin: 8rpx 0;
+						 width: 480rpx;
+						     color: #777777;
+						     font-size: 24rpx;
+						 overflow: hidden;
+						    text-overflow: ellipsis;
+						    white-space: nowrap; /* 禁止换行,强制单行 */
+					}
+				}
+			}
+
+			// .item:not(:last-child) {
+			//   border-bottom:1px solid rgba(232,232,232,1);
+			// }
+		}
+	}
+</style>

+ 1793 - 0
pages/lockTab/dataLock.vue

@@ -0,0 +1,1793 @@
+<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">
+								{{floorlockInfo.name}}
+							</view>
+							<view class="item-tags">
+								<view class="tag tag1" :class="'typeN typeN'+floorlockInfo.type">
+									{{floorlockInfo.typeN}}
+
+								</view>
+								<!-- <view class="tag" :class="'statusN statusN'+floorlockInfo.status">
+									{{floorlockInfo.statusN}}
+							
+								</view>
+								<view class="tag" :class="'lockStatusN lockStatusN'+floorlockInfo.lockStatus">
+									{{floorlockInfo.lockStatusN}}
+								</view> -->
+							</view>
+						</view>
+						<view class="line">
+							编号:{{floorlockInfo.lockNo}}
+						</view>
+						<view class="line" style="    color: #909399;">
+							更新时间:{{floorlockInfo.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="floorlockInfo.parkingStatus==1" style="color: #1677FF;">有车</span>
+						<span v-else-if="floorlockInfo.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="floorlockInfo.lockStatus==4||floorlockInfo.lockStatus==0">
+							错误</span>
+						<span v-else-if="floorlockInfo.lockStatus==1" style="color: #1677FF;">升起</span>
+						<span v-else-if="floorlockInfo.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="floorlockInfo.batteryLevel">{{floorlockInfo.batteryLevel}}V</span>
+						<span v-else>未知</span>
+					</view>
+					<view class="item-span">
+						<img src="@/assets/img/topspan/span4.png">
+						<span>网络</span>
+
+						<span v-if="floorlockInfo.status==1" style="color: #00B962;">在线</span>
+						<span v-else-if="floorlockInfo.status==0" style="color: red">离线</span>
+
+
+					</view>
+
+					<view class="item-span">
+						<img src="@/assets/img/topspan/span5.png">
+						<span>雷达</span>
+
+
+						<span v-if="floorlockInfo.radarStatus==0" style="color: #00B962;">正常</span>
+						<span v-else-if="floorlockInfo.radarStatus==1" style="color: red">故障</span>
+
+
+					</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>
+
+
+
+
+
+
+			<!-- 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="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" v-show="listShow" @click="listShow=false">
+							展开<u-icon name="arrow-down" size="32" color="#AAAAAA"></u-icon>
+						</view>
+						<view class="check-all" v-if="!listShow" @click="listShow=true">
+							收起<u-icon name="arrow-up" size="32" color="#AAAAAA"></u-icon>
+						</view>
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body8">
+						<view class="body8main">
+
+							<view class="table">
+
+
+
+								<view class="row">
+									<view class="name">地锁管理者</view>
+									<view class="value">
+										{{floorlockInfo.contacts?floorlockInfo.contacts:floorlockInfo.administrator}}
+									</view>
+								</view>
+								<view class="row" v-if="floorlockInfo.contacts&&floorlockInfo.contactPhone">
+									<view class="name">联系电话</view>
+									<view class="value">{{floorlockInfo.contactPhone}}</view>
+								</view>
+
+
+
+								<view class="row">
+									<view class="name">地锁型号</view>
+									<view class="value">{{infotext(floorlockInfo.model)}}</view>
+								</view>
+
+
+								<view class="row">
+									<view class="name">出厂编号</view>
+									<view class="value">{{infotext(floorlockInfo.factoryNumber)}}</view>
+								</view>
+								<template v-if="!listShow">
+									<view class="row">
+										<view class="name">固件版号</view>
+										<view class="value">{{infotext(floorlockInfo.solidVersion)}}</view>
+									</view>
+									<view class="row">
+										<view class="name">防护等级</view>
+										<view class="value">{{infotext(floorlockInfo.protectionGrade)}}</view>
+									</view>
+
+
+
+									<view class="row">
+										<view class="name">生产日期</view>
+										<view class="value">{{infotext(floorlockInfo.manufactureDate)}}</view>
+									</view>
+
+									<view class="row">
+										<view class="name">标准依据</view>
+										<view class="value">{{infotext(floorlockInfo.standardBasis)}}</view>
+									</view>
+									<view class="row">
+										<view class="name">联网卡号</view>
+										<view class="value">{{infotext(floorlockInfo.internetCard)}}</view>
+									</view>
+									<view class="row">
+										<view class="name">有效期至</view>
+										<view class="value">
+											{{floorlockInfo.cardExpirationDate?floorlockInfo.cardExpirationDate.split(' ')[0]:''}}
+										</view>
+									</view>
+									<view class="row" v-if="floorlockInfo.tariffStandard">
+										<view class="name">资费标准</view>
+										<view class="value">{{infotext(floorlockInfo.tariffStandard)}}元/月</view>
+									</view>
+									<view class="row">
+										<view class="name">地锁启动时间</view>
+										<view class="value">{{infotext(floorlockInfo.activationTime)}}</view>
+									</view>
+									<view class="row" v-if="floorlockInfo.shelfLife">
+										<view class="name">地锁质保期</view>
+										<view class="value">{{infotext(floorlockInfo.shelfLife)}}年</view>
+									</view>
+								</template>
+
+							</view>
+
+
+						</view>
+
+					</jpContent>
+				</view>
+			</view>
+
+			<view class="statistics main_list1 panel">
+
+
+				<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/task/listTask?lockId='+floorlockInfo.id+'&lockName='+floorlockInfo.name)">
+							查看详情
+							<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+						</view>
+
+
+					</view>
+
+				</view>
+
+				<view class="contentBody">
+					<jpContent :status="jpContentMap.body9">
+						<view class="body9main">
+
+							<view class="list">
+								<view class="item" v-for="(item,index) in dataerrList"
+									@click="gotoUrl('/pages/task/maintenanceTaks?id='+item.id)" :key="index">
+									<view class="icon">
+
+										<image class="img" v-if="item.errorCodeImage" :src="item.errorCodeImage"
+											mode=""></image>
+
+										<image class="img" v-else src="@/assets/img/taskstatus/status3.png" mode="">
+										</image>
+									</view>
+									<view class="body">
+										<view class="line1">
+											<view class="line1title">
+												{{item.errorCodeText}}
+
+											</view>
+											<view class="status " :class="'status'+item.status">
+												{{item.statusN}}
+
+											</view>
+										</view>
+
+										<view class="line2">
+											<view class="value">
+												{{item.createTime}}
+
+											</view>
+											<view class="value">
+												{{item.parkingName}}
+
+											</view>
+										</view>
+										<view class="errorDesc" v-if="item.errorDesc">
+											描述:{{item.errorDesc}}
+
+										</view>
+
+									</view>
+									<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+								</view>
+
+								<u-divider color="#F44336" v-if="dataerrRecordsTotal>3"
+									@click="gotoUrl('/pages/task/listTask?lockId='+floorlockInfo.id+'&lockName='+floorlockInfo.name)">故障记录{{dataerrRecordsTotal}}条,点击查看更多</u-divider>
+
+							</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: "",
+				dataerrList: [],
+				dataerrRecordsTotal: 0,
+				isReadyfloorStatus: false,
+
+				floorlockInfo: {},
+				echartsList: {},
+				lockUsageRateData: {},
+				body2data: {
+					query: {},
+					vue: {
+						queryN: "",
+						show: false,
+						params: {
+							year: true,
+							month: true,
+							day: false,
+							hour: false,
+							minute: false,
+							second: false
+						}
+					},
+					data: {}
+				},
+				listShow: true,
+				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){
+
+			// }
+
+
+		},
+		onShow() {
+
+
+			if (this.isReadyerrList) {
+				this.geterrList()
+			}
+
+		},
+		methods: {
+			geterrList() {
+			this.jpContentMap.body9 = 0
+				API.errList({
+					pageIndex: 1,
+					pageSize: 3,
+					status: 0,
+					lockId:this.id
+				}).then((response) => {
+					this.dataerrList = response.data.data
+					this.dataerrRecordsTotal = response.data.recordsTotal
+					this.isReadyerrList = true
+					if(this.dataerrRecordsTotal ){
+						this.jpContentMap.body9 = 2
+					}else{
+						this.jpContentMap.body9 = 1
+					}
+					
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+
+				})
+			},
+			infotext(text) {
+				if (text) {
+					return text
+				} else {
+					return ""
+				}
+			},
+			durationShow() {
+				if (this.lockUsageRateData.duration) {
+					var m = this.lockUsageRateData.duration % 60
+					var h = parseInt(this.lockUsageRateData.duration / 60)
+					if (h > 0) {
+						if (h > 24) {
+							var day = parseInt(h / 24)
+							h = h % 24
+							var px = uni.upx2px(12 * 2)
+							if (day > 100) {
+								return `${day}<span style='font-size: ${px}px;'>天</span>`
+							} else {
+								return `${day}<span style='font-size: ${px}px;'>天</span>${h}h`
+							}
+
+						} else {
+							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.geterrList()
+				//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.floorlockInfo = res.data.floorlockInfo
+					this.title = this.floorlockInfo.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;
+
+			/* 奇数行 */
+		}
+
+		.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;
+
+
+			}
+
+			.table_td1 {
+				width: 30%;
+			}
+
+			.table_td2 {
+				width: 30%;
+			}
+
+			.table_td3 {
+				width: 30%;
+			}
+
+			.table_td4 {
+				width: 10%;
+			}
+
+			/* 隔行变色: 偶数行设置背景色 */
+			.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;
+				/* 奇数行 */
+			}
+
+		}
+
+	}
+
+	.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;
+		
+		padding-top: 16rpx;
+		margin-top: 16rpx;
+
+		.item-span {
+			white-space: pre;
+			display: flex;
+			align-items: center;
+			margin-top: 4rpx;
+			width: 33%;
+			font-size: 28rpx;
+
+			span {
+				margin: 0 8rpx;
+			}
+
+			img {
+				width: 28rpx;
+				height: 28rpx;
+			}
+		}
+
+		.lockStatusX1 {
+			color: #00B962;
+		}
+
+		.lockStatusX2 {
+			color: #1677FF;
+		}
+
+		.statusX1 {
+			color: #00B962;
+		}
+
+		.statusX2 {
+			color: #1677FF;
+		}
+	}
+
+
+	.main_list1 {
+		margin-top: 24rpx;
+		padding: 24rpx;
+
+		.list-body {
+			padding: 24rpx 0;
+
+			.item {
+				border-bottom: 1px solid rgba(232, 232, 232, 1);
+			}
+
+			.title {
+				display: flex;
+				justify-content: space-between;
+
+				.name {
+					color: rgba(51, 51, 51, 1);
+					font-size: 32rpx;
+					font-weight: bold;
+				}
+
+				.status {}
+
+				.statusN1 {}
+
+				.statusN2 {}
+
+				.statusN3 {}
+			}
+
+			.body {
+				display: flex;
+				color: rgba(51, 51, 51, 1);
+				font-size: 28rpx;
+
+				.name {
+					width: 150rpx;
+				}
+
+				.value {}
+			}
+		}
+
+
+		.list {
+			//padding: 24rpx 0;
+
+			.item {
+				display: flex;
+				border-bottom: 1px solid rgba(232, 232, 232, 1);
+				padding: 12rpx 0;
+				margin: 12rpx 0;
+
+				.img {
+					width: 72rpx;
+					height: 72rpx;
+
+				}
+
+				.body {
+					margin: 0 12rpx;
+					width: 100%;
+
+					.line1,
+					.line2 {
+
+						display: flex;
+						justify-content: space-between;
+					}
+
+					.line2 {
+						color: rgba(119, 119, 119, 1);
+						font-size: 24rpx;
+						margin-top: 8rpx;
+					}
+
+					.line1 {
+						.line1title {
+							color: rgba(51, 51, 51, 1);
+							font-size: 28rpx;
+							font-weight: bold;
+						}
+
+						.status {
+							background-color: rgba(255, 61, 0, 1);
+							font-size: 24rpx;
+							color: #fff;
+							padding: 2rpx 8rpx;
+							//border-radius: 4px;
+
+						}
+
+						.status0 {
+							background-color: rgba(255, 61, 0, 1);
+
+						}
+
+						.status1 {
+							background-color: #007aff;
+
+						}
+
+						.status2 {
+							background-color: #ff9900;
+
+						}
+
+						.status3 {
+							background-color: #19be6b;
+
+						}
+
+						.status4 {
+							border: 1px solid rgba(255, 61, 0, 1);
+							color: rgba(255, 61, 0, 1);
+						}
+					}
+
+					.errorDesc {
+						margin: 8rpx 0;
+						width: 480rpx;
+						color: #777777;
+						font-size: 24rpx;
+						overflow: hidden;
+						text-overflow: ellipsis;
+						white-space: nowrap;
+						/* 禁止换行,强制单行 */
+					}
+				}
+			}
+
+			// .item:not(:last-child) {
+			//   border-bottom:1px solid rgba(232,232,232,1);
+			// }
+		}
+	}
+</style>

+ 304 - 0
pages/lockTab/listLock.vue

@@ -0,0 +1,304 @@
+<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/lockTab/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>
+			
+			<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.findFloorLock(this.listForm).then((res) => {
+					var list=[]
+					
+					if (this.listForm.pageIndex == 1) {
+						list = res.data.data;
+					} else {
+						list = [
+							...list,
+							...res.data.floorlockInfoList
+						];
+					}
+					this.list = res.data.floorlockInfoList
+					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>

+ 227 - 0
pages/login/login.vue

@@ -0,0 +1,227 @@
+<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,
+					roleName:'XJ',
+					//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>

+ 244 - 0
pages/myTab/as-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
+	};
+}

+ 103 - 0
pages/myTab/changePassword.vue

@@ -0,0 +1,103 @@
+<template>
+	<view>
+		<u-navbar title="修改密码" title-color="#101010"></u-navbar>
+		<view class="main">
+			<view class="original-password">
+				<text>原密码	</text><u-input  v-model="form.oldPassword" style="padding: 0 0 0 20px" class="password-input" type="password"  placeholder="填写原密码" :password-icon="true" />
+			</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>
+		<!-- 确认修改 -->
+		<button class="confirm" @click="changePassword">确认修改</button>
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/user.js'
+	
+	export default {
+		data() {
+			return {
+				form: {
+					oldPassword: '',
+					password: '',
+				},
+			}
+		},
+		methods: {
+			changePassword(){
+				
+				if (!this.form.oldPassword) {
+					uni.showToast({
+						title: "请输入原密码",
+						icon: "none"
+					})
+					return
+				}
+				
+				if (!this.form.password) {
+					uni.showToast({
+						title: "请输入新密码",
+						icon: "none"
+					})
+					return
+				}
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				API.changePassword(this.form).then((response) => {
+					uni.hideLoading();
+					this.form.password=""
+					this.form.oldPassword=""
+					uni.showModal({
+						title:"提示",
+						content:"密码修改成功!",
+						showCancel:false
+					})
+					
+				}).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;
+		}
+	}
+  // 确认修改
+  .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>

+ 198 - 0
pages/myTab/changePhone.vue

@@ -0,0 +1,198 @@
+<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>
+			<u-verification-code :seconds="sendMsgSecond" ref="uCode" @change="codeChange" @end="end" @start="start"
+				change-text="(Xs)">
+			</u-verification-code>
+		</view>
+		<!-- 确认修改 -->
+		<button class="confirm" @click="changePhone">确认修改</button>
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/user.js'
+	
+	import {
+		checkPhone
+	} from '@/apis/utils'
+	
+	export default {
+		data() {
+			return {
+				form: {
+					telephone: '',
+					verifyCode: '',
+				},
+				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: {
+			
+			changePhone() {
+				
+				var checkPhoneResult = checkPhone(this.form.telephone);
+				
+				if (!this.form.telephone || checkPhoneResult != true) {
+					uni.showToast({
+						title: checkPhoneResult,
+						icon: "none"
+					})
+					return;
+				}
+				if (!this.form.verifyCode) {
+					uni.showToast({
+						title: "请输入验证码",
+						icon: "none"
+					})
+					return
+				}
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+			
+				
+			
+				API.changePhone(this.form).then((response) => {
+					uni.hideLoading();
+					
+					this.carhelp.logoff()
+					uni.redirectTo({
+						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>

+ 38 - 0
pages/myTab/cropImage.vue

@@ -0,0 +1,38 @@
+<template>
+	<view class="content" >
+		<limeClipper :width="options.width" :scale-ratio="2" :is-lock-width="false" :is-lock-height="false" :height="options.height" :image-url="path"  
+			@success="successFn" @cancel="cancel"  />
+	</view>
+</template>
+<script>
+import limeClipper from '@/pages/myTab/as-components/limeClipper/limeClipper.vue';
+export default {
+	components: {limeClipper},
+	data() {return {path: '',options:{"width":600,"height":600}}},
+	onLoad({path,options}) {
+		this.path = path
+		//('path-path-path-path',path);
+		if(options){
+			this.options = JSON.parse(options)
+		}
+	},
+	methods:{
+		successFn(e){
+			this.getOpenerEventChannel().emit('success',e.url)
+			uni.navigateBack()
+		},
+		cancel(){
+			uni.navigateBack()
+		}
+	}
+}
+</script>
+
+<style>
+	.box{
+		width: 400rpx;
+	}
+	.mt{
+		margin-top: -10px;
+	}
+</style>

+ 153 - 0
pages/myTab/customerService.vue

@@ -0,0 +1,153 @@
+<template>
+	<view>
+		<u-navbar title="联系客服" title-color="#101010"></u-navbar>
+		<u-divider :isnone="queryList.length==0" nonetext="没有找到相关内容" border-color="#CFD2D5">已经到底了</u-divider>
+		<view class="background" v-if="false">
+			<view class="common-problem">
+				<view class="headline">
+					常见问题
+				</view>
+				<!-- 标签 -->
+				<view class="tabs">
+					<u-tabs :list="list" font-size="28" :is-scroll="false" :current="current" @change="change"></u-tabs>
+				</view>
+				<!-- 问题 -->
+				<view class="problems">
+					<u-collapse accordion="false">
+						<u-collapse-item :title="item.head" v-for="(item, index) in itemList" :open="item.open" :key="index">
+							{{item.body}}
+						</u-collapse-item>
+					</u-collapse>
+				</view>
+			</view>
+		</view>
+
+		<u-modal v-model="openModalBl" @confirm="confirmPhone" confirm-text="拨打电话" confirm-color="#606266"
+			:show-cancel-button="true" ref="uModal" :asyncClose="true" title="客服电话" :content="content"
+			:content-style="{fontSize: '24px',color: '#101010'}"></u-modal>
+
+		<!-- 底部 -->
+		<view class="bottom">
+			<button class="service" @click="openModalBl=true">
+				<view>
+					<u-icon name="server-fill"></u-icon>
+				</view>
+				客服电话(7:00-24:00)
+			</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				content: "400-8899-619",
+				
+				openModalBl: false,
+				queryList: [],
+				list: [{
+					name: '软件使用'
+				}, {
+					name: '地锁状态及参数'
+				}, {
+					name: '工单相关',
+
+				}],
+				itemList: [{
+					head: "常见问题1",
+					body: "只要我们正确择取一个合适的参照物乃至稍降一格去看待他人,值得赏识的东西便会扑面而来",
+					open: true,
+
+				}, {
+					head: "常见问题2",
+					body: "学会欣赏,实际是一种积极生活的态度,是生活的调味品,会在欣赏中发现生活的美",
+					open: false,
+				}, {
+					head: "常见问题3",
+					body: "但是据说雕刻大卫像所用的这块大理石,曾被多位雕刻家批评得一无是处,有些人认为这块大理石采凿得不好,有些人嫌它的纹路不够美",
+					open: false,
+				}],
+				current: 0
+			}
+		},
+		methods: {
+			confirmPhone() {
+				this.openModalBl = false;
+				uni.makePhoneCall({
+					phoneNumber: this.content //仅为示例
+				});
+			},
+			change(index) {
+				this.current = index;
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.background {
+		position: relative;
+		height: 200px;
+		background: linear-gradient(180deg, rgba(203, 234, 255, 1) 0%, rgba(203, 234, 255, 0) 100%);
+
+		.common-problem {
+			position: absolute;
+			top: 24rpx;
+			left: 32rpx;
+			right: 32rpx;
+			background-color: #fff;
+			border-radius: 8px;
+			padding: 40rpx 32rpx;
+
+			.headline {
+				color: rgba(16, 16, 16, 1);
+				font-size: 36rpx;
+			}
+
+			// 标签
+			.tabs {
+				border-top: 1px solid rgba(232, 232, 232, 1);
+				margin-top: 28rpx;
+				width: 522rpx;
+
+				::v-deep.u-tab-item {
+
+					font-size: 24rpx !important;
+				}
+			}
+
+			.problems {
+				margin-top: 8rpx;
+			}
+		}
+	}
+
+	// 底部
+	.bottom {
+		background-color: #fff;
+		position: fixed;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		padding: 24rpx 32rpx;
+
+		.service {
+			display: flex;
+			justify-content: center;
+			align-items: center;
+
+			color: rgba(255, 255, 255, 1);
+			font-size: 32rpx;
+			border-radius: 50px;
+			background: linear-gradient(-88.46deg, rgba(34, 109, 198, 1) 2.59%, rgba(9, 158, 237, 1) 97.02%);
+		}
+
+		.img {
+			width: 40rpx;
+			height: 40rpx;
+			vertical-align: middle;
+			margin-right: 16rpx;
+		}
+	}
+</style>

+ 446 - 0
pages/myTab/dataUser.vue

@@ -0,0 +1,446 @@
+<template>
+	<view class="jpmain  ">
+		<u-navbar title="个人信息" title-color="#101010"></u-navbar>
+		
+		<u-popup v-model="showMessage" mode="bottom" border-radius="30" >
+			<view class="showMessage">
+				<view class="title">用户昵称</view>
+				<view class="body">
+					<u-input :customStyle="customStyle"
+					placeholder="请填写用户昵称"
+					  v-model="nickName"></u-input>
+				</view>
+				<view class="botton">
+					<u-button @click="showMessage=false"  style="width: 35%;"   shape="square" >取消</u-button>
+					
+					<u-button  @click="updateName" style="width: 60%;" type="primary"  shape="square" >确认</u-button>
+				</view>
+			</view>
+		</u-popup>
+		<u-keyboard ref="uKeyboard"  @change="valChange" @backspace="backspace"
+		:tips="carNumber?carNumber:'请输入车牌号'" @confirm="updateCarNumber()"
+		mode="car" v-model="showCarNumber"  :abc="abc" ></u-keyboard>
+		
+		
+		
+		
+		
+
+		<view class="body">
+			<view class="page">
+			
+				<view class="page-content">
+					<view class="item">
+						<view class="title">
+							头像
+						</view>
+						<view class="goto "  @click="uploadPhoto" >
+							<view class="photo">
+								
+								<img class="img" :src="userInfo.headImg" v-if="userInfo.headImg"  alt="">
+							</view>
+							
+							
+							<u-icon name="arrow-right"  style="margin-left: 8rpx;"  size="24" color="#BBBBBB"></u-icon>
+						</view>
+					</view>
+				
+				</view>
+			</view>
+			
+			<view class="page">
+
+				<view class="page-content">
+					<!-- <view class="item">
+						<view class="title">
+							用户昵称
+
+						</view>
+						<view class="goto" @click="showMessage=true,nickName=userInfo.nickName">
+							{{userInfo.nickName?userInfo.nickName:'未设置'}}
+							<u-icon name="arrow-right" style="margin-left: 8rpx;" size="24" color="#BBBBBB"></u-icon>
+						</view>
+					</view> -->
+					<view class="item">
+						<view class="title">
+							车牌号
+					
+						</view>
+						<view class="goto" @click="carNumberBtn">
+							{{userInfo.carNumber?userInfo.carNumber:'未设置'}}
+							<u-icon name="arrow-right" style="margin-left: 8rpx;" size="24" color="#BBBBBB"></u-icon>
+						</view>
+					</view>
+					<!-- <view class="item">
+						<view class="title">
+							手机号码
+						</view>
+						<view class="goto">
+							{{userInfo.phone}}
+						</view>
+					</view> -->
+				</view>
+			</view>
+			
+			<view class="page" @click="signOut">
+			
+				<view class="button">
+					退出账号
+				
+				</view>
+			</view>
+			
+			
+			<u-modal v-model="show1" @confirm="confirm" confirm-color="#FF3D00" :show-cancel-button="true" ref="uModal"
+				:asyncClose="true" title="退出账号" content="是否退出当前账号?" :content-style="{color: '#333333'}"></u-modal>
+			
+
+		</view>
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/index.js'
+	
+	export default {
+		components: {
+			
+		},
+		data() {
+			return {
+				userInfo:{
+					phone:"",
+					headImg:"",
+					carNumber:"",
+				},
+				showMessage:false,
+				showCarNumber:false,
+				carNumber:"",
+				nickName:"",
+				abc:false,
+				show1:false,
+				customStyle: {
+					"border-radius": "50px",
+					"background-color": 'rgba(242, 244, 246, 1)',
+					padding: "5px 20px",
+					margin: "5px 0 ",
+					
+				},
+				
+			}
+		},
+		onLoad() {
+			this.userInfo = this.jphelp.getPersonInfo()	
+		},
+		onReady() {
+			this.$refs.refLogin.findByOpenId()
+			
+		},
+		methods: {
+			signOut() {
+				this.show1 = true;
+			},
+			confirm() {
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				userApi.logout().then((res) => {
+					uni.hideLoading();
+					this.show1 = false;
+					this.jphelp.logoff()
+					uni.redirectTo({
+						url: '/pages/login/login'
+					})
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			},
+			carNumberBtn(){
+				 
+					this.showCarNumber=1;
+					this.carNumber=this.userInfo.carNumber;
+					if(!this.carNumber){
+						this.carNumber=""
+					}
+					this.valInit(1)
+			},
+		
+			valInit(bl){
+				if(bl){
+					this.abc=this.carNumber.length>0
+				}else{
+					if(this.carNumber.length==1&&this.abc==false){
+						this.abc=true
+					}
+					if(this.carNumber.length==0&&this.abc==true){
+						this.abc=false
+					}
+				}
+				
+			},
+			valChange(val){
+				
+				if(this.carNumber.length>=8){
+					return
+				}
+				this.carNumber+=val
+				this.valInit()
+				this.$forceUpdate()
+			},
+			backspace(){
+				//
+				var value=this.carNumber
+				if(value.length){
+					value = value.substr(0, value.length - 1);
+					
+				}
+				this.carNumber=value
+				this.valInit()
+				
+			
+			},
+			updateCarNumber(){
+				this.userInfo.carNumber=this.carNumber
+				this.showCarNumber=false;
+				this.updatePersonInformation()
+			},
+			
+			updateName(){
+				if(this.nickName){
+					this.userInfo.nickName=this.nickName
+					this.showMessage=false;
+					this.updatePersonInformation()
+				}else{
+					this.showMessage=true;
+					uni.showToast({
+						title: "用户昵称不能为空",
+						icon: "none"
+					})	
+				}
+				
+			},
+			updatePersonInformation(){
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				if(!this.userInfo.nickName){
+					this.userInfo.nickName=""
+				}
+				if(!this.userInfo.headImg){
+					this.userInfo.headImg=""
+				}
+				if(!this.userInfo.carNumber){
+					this.userInfo.carNumber=""
+				}
+				var obj={
+					nickName:this.userInfo.nickName,
+					headImg:this.userInfo.headImg,
+					carNumber:this.userInfo.carNumber,
+				}
+				
+				API.updatePersonInformation(obj).then((res) => {
+					
+					uni.hideLoading();
+					this.$refs.refLogin.findByOpenId()
+				}).catch(error => {
+				
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})		
+				})
+			},
+			findByOpenId(res){
+				this.userInfo = this.jphelp.getPersonInfo()	
+				
+			},
+			saveRecordConfirmMethod(fileData) {
+			
+				var token = this.jphelp.getToken()
+			
+				uni.uploadFile({
+					url: process.jphelp.BASE_URL + "uploadPicture", //仅为示例,非真实的接口地址
+					filePath:fileData,
+					header: {
+						'Authorization': token,
+						//'Content-Type': 'multipart/form-data',
+						'X-Requested-With': 'XMLHttpRequest',
+						//	'content-type': 'multipart/form-data'
+					},
+					name: 'photoFile',
+					formData: {
+						subFolder: "headimg"
+					},
+					success: (uploadFileRes) => {
+						
+						
+						var obj = JSON.parse(uploadFileRes.data)
+						//.log(obj);
+						//this.src = obj.data;
+						this.userInfo.headImg=obj.data;
+						this.updatePersonInformation();
+						// uni.hideLoading();
+					}
+				});
+			},
+			uploadPhoto() {
+				let _self = this;
+			
+				const crop = {
+					quality: 100,
+					width: 600,
+					height: 600,
+					resize: true
+				};
+			
+				// 上传图片
+				uni.chooseImage({
+					count: 1,
+					crop,
+					success: async (res) => {
+						//(res);
+						let tempFile = res.tempFiles[0];
+			
+						var filePath = res.tempFilePaths[0]
+			
+						let fileData = await new Promise((callback) => {
+							uni.navigateTo({
+								url: './cropImage?path=' + filePath +
+									`&options=${JSON.stringify(crop)}`,
+								animationType: "fade-in",
+								events: {
+									success: url => {
+										callback(url)
+									}
+								}
+							});
+						})
+			
+						this.saveRecordConfirmMethod(fileData);
+			
+			
+			
+			
+					}
+				});
+			},
+		}
+	}
+</script>
+<style>
+	page {
+		background-color: rgba(242, 244, 246, 1);
+	}
+</style>
+<style scoped lang="scss">
+	/* styles.css */
+	.showMessage{
+		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;
+		}
+		
+		
+		.title{
+			color: rgba(16,16,16,1);
+			font-size: 36rpx;
+			margin-top: 32rpx;
+			
+			font-weight: bold;
+		}
+		.body{
+			color: rgba(16,16,16,1);
+			font-size: 32rpx;
+			padding-bottom: 66rpx;
+		}
+		.botton{
+			    display: flex;
+				justify-content: space-between;
+		}
+	}
+
+	.body {
+		padding: 32rpx;
+	}
+
+
+
+	
+
+	.page {
+
+		border-radius: 16rpx;
+		background-color: rgba(255, 255, 255, 1);
+		color: rgba(16, 16, 16, 1);
+
+		padding:0 32rpx;
+		margin-bottom: 32rpx;
+		font-size: 32rpx;
+		color: rgb(16, 16, 16);
+
+		
+
+		.page-content {
+			.item:not(:last-child) {
+			  border-bottom:1px solid rgba(232,232,232,1);
+			}
+			.item {
+				padding: 32rpx 0;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+				font-size: 32rpx;
+				.title {
+					display: flex;
+					justify-content: space-between;
+					display: flex;
+					align-items: center;
+					color: rgba(51,51,51,1);
+					
+					
+				}
+				.goto{
+					display: flex;
+					align-items: center;
+					color: rgba(119,119,119,1);
+					
+				}
+				.photo {
+					border-radius: 50px;
+					background-color: rgba(229, 229, 229, 1);
+					height: 80rpx;
+					width: 80rpx;
+					overflow: hidden;
+					  
+					.img {
+						width: 100%;
+						height: 100%;
+					}
+				}
+			}
+		}
+
+
+		.button{
+			text-align: center;
+			color: red;
+			    padding: 32rpx 0;
+		}
+	}
+</style>

+ 146 - 0
pages/myTab/feedbackList.vue

@@ -0,0 +1,146 @@
+<template>
+	<view>
+		<u-navbar title="反馈记录" title-color="#101010"></u-navbar>
+		<view class="record" v-if="0">
+			<view class="title">
+				<view class="classify">
+					功能异常
+				</view>
+				<view class="date">
+					2024-02-04 20:00:00
+				</view>
+			</view>
+			<view class="content">
+				在使用用电监控APP时,发现数据刷新偶有延迟,实时性不足;电量消耗统计与实际存在偏差,准确性有待提升。影响用户体验,建议优化性能并校准数据准确性。
+			</view>
+			
+			<view class="picture">
+				<!-- <image class="img" src="../../assets/img/feedbackPic.png"  mode=""></image> -->
+			</view>
+		</view>
+		<u-divider :isnone="list.length==0" nonetext="没有找到相关内容" border-color="#CFD2D5">已经到底了</u-divider>
+		
+		<!-- 底部 -->
+		<view class="bottom" v-if='0'>
+			<button class="fill-in">填写反馈</button>
+		</view>
+	</view>
+</template>
+
+<script>
+	
+	export default {
+	
+		data() {
+			return {
+				title: "场站列表",
+				list: [],
+				listForm: {
+					pageIndex: 1,
+					pageSize: 20,
+					recordsTotal: 1,
+				},
+				
+			};
+		},
+		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 lang="scss" scoped>
+	.record{
+		margin-top: 24rpx;
+		background-color: #fff;
+		padding: 32rpx;
+		.title{
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			.classify{
+				color: rgba(22,119,255,1);
+				font-size: 32rpx;
+			}
+			.date{
+				color: rgba(119,119,119,1);
+			}
+		}
+		.content{
+			color: rgba(51,51,51,1);
+			line-height: 44rpx;
+			margin-top: 16rpx;
+		}
+		.picture{
+			margin-top:24rpx;
+			display: flex;
+			justify-content: space-between;
+			.img{
+				width: 144rpx;
+				height: 144rpx;
+				border-radius: 4px;
+			}
+		}
+	}
+	// 底部
+	.bottom{
+		position: fixed;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		background-color: #fff;
+		padding: 20rpx 32rpx;
+		.fill-in{
+			
+			line-height: 80rpx;
+			border-radius: 4px;
+			background-color: rgba(22,119,255,1);
+			color: rgba(255,255,255,1);
+			font-size: 32rpx;
+		}
+	}
+
+</style>

+ 130 - 0
pages/myTab/feedbackSubmit.vue

@@ -0,0 +1,130 @@
+<template>
+	<view>
+		<u-navbar title="意见反馈" title-color="#101010"></u-navbar>
+		<view class="main">
+			<view class="title">
+				<text>*</text>请选择反馈问题类型:
+			</view>
+			<!-- 类型 -->
+			<view class="classify">
+				<view class="classify-item item-checked">
+					功能异常
+				</view>
+				<view class="classify-item">
+					产品建议
+				</view>
+				<view class="classify-item">
+					安全问题
+				</view>
+				<view class="classify-item">
+					其他问题
+				</view>
+			</view>
+		</view>
+		<!-- 问题描述 -->
+		  <view class="main">
+		  	<view class="title">
+		  		问题描述(必填)
+		  	</view>
+			<view class="textarea">
+				<textarea placeholder="请填写15字以上描述,以便我们更好地为您提供帮助~" ></textarea>
+			</view>
+		  </view>
+		  <!-- 上传照片 -->
+		  <view class="main">
+		  	<view class="title">
+		  		上传图片(最多3张)
+		  	</view>
+			<view class="upload">
+					<u-upload  width="144" height="144" :action="action" :file-list="fileList" max-count="3" ></u-upload>
+			</view>
+		  </view>
+		  <!-- 底部 -->
+		  <view class="bottom">
+		  	<button class="submit">提交反馈</button>
+		  </view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				
+			}
+		},
+		methods: {
+			
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	.main{
+		background-color: #fff;
+		padding: 32rpx;
+		margin-bottom: 24rpx;
+		.title{
+			color: rgb(16,16,16);
+			font-size: 32rpx;
+			font-weight: bold;
+			text{
+				color: rgba(255,0,9,1);
+			}
+		}
+		// 类型
+		.classify{
+			display: flex;
+			align-items: center;
+			flex-wrap: wrap;
+			margin-top: 24rpx;
+			.classify-item{
+				padding:0 16rpx;
+				line-height: 66rpx;
+				margin-right: 16rpx;
+				margin-bottom: 16rpx;
+				border-radius: 4px;
+				background-color: rgba(255,255,255,1);
+				color: rgba(16, 16, 16, 1);
+				text-align: center;
+				border: 1px solid rgba(216,223,232,1);
+			}
+			.item-checked{
+				background-color: rgba(22,119,255,1);
+				color: rgba(255,255,255,1);
+			}
+		}
+		.textarea{
+			margin-top: 24rpx;
+			uni-textarea{
+				width: 100%;
+				height: 200rpx;
+			}
+			::v-deep.uni-textarea-placeholder{
+				color: #b2b2b2;
+				font-size: 32rpx;
+			}
+		}
+		.upload{
+			margin-top: 24rpx;
+		}
+	}
+	// 底部
+	.bottom{
+		position: fixed;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		background-color: #fff;
+		padding: 20rpx 32rpx;
+		.submit{
+			
+			line-height: 80rpx;
+			border-radius: 4px;
+			background-color: rgba(22,119,255,1);
+			color: rgba(255,255,255,1);
+			font-size: 32rpx;
+		}
+	}
+
+</style>

+ 304 - 0
pages/myTab/index.vue

@@ -0,0 +1,304 @@
+<template>
+	<view>
+		<view class="gradient-header">
+			<view class="jpback">
+		
+			</view>
+		</view>
+		
+		<view class="body">
+		
+			<view class="page-top" >
+		
+				<view class="name">
+					<view class="photo">
+						<img class="img" :src="userInfo.headImg" v-if="userInfo.headImg" alt="">
+						<img class="img" src="@/assets/img/默认头像.png" v-else alt="">
+						
+						
+					</view>
+					<view class="text">
+						<view class="text1">{{userInfo.realName}}</view>
+						<view class="text2">{{userInfo.userName}}</view>
+					</view>
+				</view>
+				<view class="value">
+					<!-- <u-icon name="arrow-right" size="24" color="#fff"></u-icon> -->
+				</view>
+			</view>
+			<view class="page" v-if="0">
+				<view class="page-main">
+		
+					<view class="item"   @click="gotoUrl('/pages/mylock/myLock')" 
+					v-if="userInfoPlus&&userInfoPlus.myAllList" >
+						<view class="name">{{userInfoPlus.myAllList.length}}</view>
+						<view class="value">地锁</view>
+					</view>
+					<view class="item2">
+		
+					</view>
+					<view class="item"  @click="gotoUrl('/pages/mylock/myWhite')"  >
+						<view class="name">{{whiteNum}}</view>
+						<view class="value">白名单</view>
+					</view>
+		
+				</view>
+			</view>
+			<view class="page">
+		
+				<view class="page-content">
+					<view class="item" @click="gotoUrl('/pages/myTab/myMessage')" >
+						<view class="title">
+							<!-- <img class="img" src="@/assets/img/myTab/icon1.svg" alt=""> -->
+							<u-icon size="40" :marginLeft="12"  label-size="32"  name="chat" label="我的消息" ></u-icon>
+							
+						</view>
+						<view class="goto">
+							<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+						</view>
+					</view>
+					<view class="item" @click="gotoUrl('/pages/myTab/feedbackList')" >
+						<view class="title">
+							
+							<u-icon name="email"  size="40"  label-size="32"  :marginLeft="12" label="意见反馈"></u-icon>
+							
+						</view>
+						<view class="goto">
+							<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+						</view>
+					</view>
+					<view class="item" @click="gotoUrl('/pages/myTab/customerService')" >
+						<view class="title">
+						
+						<u-icon name="server-fill"  size="40"  label-size="32"  :marginLeft="12" label="客服热线"></u-icon>
+							
+						</view>
+						<view class="goto">
+							<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+						</view>
+					</view>
+					<view class="item" @click="gotoUrl('/pages/myTab/abnormalList')" >
+						<view class="title">
+						
+						<u-icon name="error-circle"  size="40" label-size="32" :marginLeft="12" label="异常告警"></u-icon>
+							
+						</view>
+						<view class="goto">
+							<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+						</view>
+					</view>
+					
+				</view>
+				</view>
+				<view class="page" @click="signOut">
+				
+					<view class="button">
+						退出账号
+					
+					</view>
+				</view>
+				
+				<u-modal v-model="show1" @confirm="confirm" confirm-color="#FF3D00" :show-cancel-button="true" ref="uModal"
+					:asyncClose="true" title="退出账号" content="是否退出当前账号?" :content-style="{color: '#333333'}"></u-modal>
+				
+				
+		
+		</view>
+		<tabbar :current="3"></tabbar>
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/user.js'
+	
+	import Tabbar from '@/components/Tabbar.vue'
+	export default {
+		components: {
+			Tabbar
+		},
+		data() {
+			return {
+				show1:false,
+				isReady:false,
+				userInfo:{},
+				userInfoPlus:{
+					whiteList:[],
+					myAllList:[]
+				},
+				whiteNum:0,
+			};
+		},
+		onLoad() {
+			this.userInfo=this.jphelp.getPersonInfo()
+			console.log(this.userInfo)
+		},
+		methods:{
+			signOut() {
+				this.show1 = true;
+			},
+			confirm() {
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				API.logout().then((res) => {
+					uni.hideLoading();
+					this.show1 = false;
+					this.jphelp.logoff()
+					uni.redirectTo({
+						url: '/pages/login/login'
+					})
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			},
+		}
+	}
+</script>
+
+<style lang="scss">
+	page {
+		background-color: rgba(242, 244, 246, 1);
+	}
+	.body {
+		padding: 32rpx;
+	}
+	
+	.gradient-header {
+		height: 0px;
+	}
+	
+	.jpback {
+		height: 268rpx;
+		background: linear-gradient(180deg, rgba(22, 119, 255, 1) 20%, rgba(121, 177, 255, 1) 100%);
+	}
+	
+	.page-top {
+	
+		color: #fff;
+		display: flex;
+		justify-content: space-between;
+		margin: 48rpx 0;
+	
+		.name {
+	
+			display: flex;
+			align-items: flex-end;
+	
+			.photo {
+				border-radius: 50px;
+				background-color: rgba(229, 229, 229, 1);
+				height: 100rpx;
+				width: 100rpx;
+				overflow: hidden;
+	
+				.img {
+					width: 100%;
+					height: 100%;
+				}
+			}
+	
+			.text {
+				margin-left: 24rpx;
+	
+				.text1 {
+					font-weight: bold;
+					font-size: 40rpx;
+				}
+	
+				.text2 {
+	
+					font-size: 32rpx;
+	
+				}
+			}
+	
+		}
+	
+		.value {
+			margin-top: 24rpx;
+			font-size: 40rpx;
+			font-weight: bold;
+			color: #333333;
+		}
+	}
+	
+	.page {
+	
+		border-radius: 16rpx;
+		background-color: rgba(255, 255, 255, 1);
+		color: rgba(16, 16, 16, 1);
+	
+		padding:0 32rpx;
+		margin-bottom: 32rpx;
+		font-size: 32rpx;
+		color: rgb(16, 16, 16);
+	
+		.page-main {
+			display: flex;
+			justify-content: space-around;
+			align-items: center;
+			padding:24rpx;
+			.item {
+				.name {
+					font-size: 56rpx;
+					color: #333333;
+					font-weight: bold;
+				}
+	
+				.value {
+					color: rgba(146, 146, 176, 1);
+					font-size: 32rpx;
+				}
+	
+				display: flex;
+				flex-direction: column;
+				align-items: center;
+	
+	
+			}
+	
+			.item2 {
+				border-right: 1px solid rgba(187, 187, 187, 0.43);
+				height: 70rpx;
+			}
+	
+		}
+	
+		.page-content {
+			.item:not(:last-child) {
+			  border-bottom:1px solid rgba(232,232,232,1);
+			}
+			.item {
+				padding: 46rpx 0;
+				display: flex;
+				justify-content: space-between;
+				align-items: center;
+	
+				.title {
+					display: flex;
+					justify-content: space-between;
+					display: flex;
+					align-items: center;
+					color: rgba(51,51,51,1);
+					.img {
+						width: 32rpx;
+						height: 32rpx;
+						
+						margin-right: 16rpx;
+					}
+				}
+			}
+		}
+	
+		.button{
+			text-align: center;
+			color: red;
+			    padding: 32rpx 0;
+		}
+	
+	}
+</style>

+ 215 - 0
pages/myTab/myMessage.vue

@@ -0,0 +1,215 @@
+<template>
+	<view>
+		<u-navbar title="我的消息" ></u-navbar>
+		<view class="main"  v-if="0">
+			<view class="line">
+				<view class="imgc img1">
+					<img class="img" src="@/assets/img/myTab/message1.svg">
+				</view>
+				<view class="text">
+					<view class="info"> 
+						<view class="title">
+							故障告警
+
+						</view>
+						<view class="date">
+							02-02
+
+						</view>
+					</view>
+					<view class="message">
+						A01车位地锁于2025-02-02 23:00:01离线断网...
+
+					</view>
+				</view>
+			</view>
+			<view class="line">
+				<view class="imgc img2">
+					<img class="img" src="@/assets/img/myTab/message2.svg">
+				</view>
+				<view class="text">
+					<view class="info"> 
+						<view class="title">
+							故障告警
+			
+						</view>
+						<view class="date">
+							02-02
+			
+						</view>
+					</view>
+					<view class="message">
+						A01车位地锁于2025-02-02 23:00:01离线断网...
+			
+					</view>
+				</view>
+			</view>
+			<view class="line">
+				<view class="imgc img3">
+					<img class="img" src="@/assets/img/myTab/message3.svg">
+				</view>
+				<view class="text">
+					<view class="info"> 
+						<view class="title">
+							故障告警
+			
+						</view>
+						<view class="date">
+							02-02
+			
+						</view>
+					</view>
+					<view class="message">
+						A01车位地锁于2025-02-02 23:00:01离线断网...
+			
+					</view>
+				</view>
+			</view>
+			<view class="line">
+				<view class="imgc img4">
+					<img class="img" src="@/assets/img/myTab/message4.svg">
+				</view>
+				<view class="text">
+					<view class="info"> 
+						<view class="title">
+							故障告警
+			
+						</view>
+						<view class="date">
+							02-02
+			
+						</view>
+					</view>
+					<view class="message">
+						A01车位地锁于2025-02-02 23:00:01离线断网...
+			
+					</view>
+				</view>
+			</view>
+			
+		</view>
+		<u-divider :isnone="list.length==0" nonetext="没有找到相关内容" border-color="#CFD2D5">已经到底了</u-divider>
+		
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				list: [],
+				listForm: {
+					pageIndex: 1,
+					pageSize: 20,
+					recordsTotal: 1,
+				},
+			};
+		},
+		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 lang="scss">
+	.main{
+		
+		.line{
+			background-color: rgba(255,255,255,1);
+			border-top: 1px solid  rgba(232,232,232,1);
+			    display: flex;
+			    align-items: center;
+				padding:16px;
+				
+				.text{
+					  .info{
+						  display: flex;
+						  justify-content: space-between;
+						  .title{
+						  
+						  	color: rgba(16,16,16,1);
+						  	font-size: 16px;
+						  font-weight: bold;
+						  }
+						  .date{
+						  	color: rgb(140,140,140);
+						  	font-size: 12px;
+						  }
+						  margin-bottom:  4px;
+					  } 
+					
+				}
+				.message{
+					color: rgba(51,51,51,1);
+					font-size: 12px;
+				}
+				.imgc{
+					display: flex;
+					align-items: center;
+					    justify-content: center;
+					border-radius: 12px;
+					margin-right: 8px;
+					width: 48px;
+					height: 48px;
+					.img{
+						width: 28px;
+						height: 28px;
+					}
+					
+
+				}
+				.img1{
+					background: linear-gradient(180.29deg, rgba(255,214,125,1) 0.9%,rgba(255,150,0,1) 100.4%);
+				}
+				.img2{
+				background: linear-gradient(180.29deg, rgba(255,124,112,1) 0.9%,rgba(255,79,63,1) 100.4%);}
+				.img3{
+				background: linear-gradient(179.2deg, rgba(168,178,238,1) 6.28%,rgba(123,123,240,1) 96.94%);}
+				.img4{
+				background: linear-gradient(180deg, rgba(121,172,255,1) 0%,rgba(57,132,255,1) 100%);}
+		}
+	}
+</style>

+ 92 - 0
pages/myTab/setting.vue

@@ -0,0 +1,92 @@
+<template>
+	<view>
+		<u-navbar title="设置" title-color="#101010"></u-navbar>
+		<u-cell-group>
+			<!-- <u-cell-item title="个人信息" @click="gotoUrl('/pages/mine/personInfos')"></u-cell-item> -->
+			<u-cell-item title="修改密码" @click="gotoUrl('/pages/mine/changePassword')"></u-cell-item>
+			<u-cell-item title="修改手机号" :value="personInfo.phone" @click="gotoUrl('/pages/mine/changePhone')"></u-cell-item>
+			<u-cell-item title="注销账号" @click="gotoUrl('/pages/mine/cancelAccount')"></u-cell-item>
+		</u-cell-group>
+
+		<view class="exit" @click="signOut">
+			退出账号
+		</view>
+
+		<u-modal v-model="show1" @confirm="confirm" confirm-color="#FF3D00" :show-cancel-button="true" ref="uModal"
+			:asyncClose="true" title="退出账号" content="是否退出当前账号?" :content-style="{color: '#333333'}"></u-modal>
+
+	</view>
+
+
+</template>
+
+<script>
+	import * as userApi from '@/apis/pagejs/user.js'
+	// import * as API from '@/apis/pagejs/index.js'
+
+	export default {
+		data() {
+			return {
+				personInfo: {},
+				show1: false,
+			}
+		},
+		onLoad() {
+			if(this.carhelp.getPersonInfoPlus()) {
+				var data = this.carhelp.getPersonInfoPlus();
+				this.personInfo = data.regUser;
+				if(this.personInfo.phone != null) {
+					var phone = this.personInfo.phone;
+					phone = phone.slice(0,3) + '****' + phone.slice(-4);
+					this.personInfo.phone = phone;
+				}
+			}
+			//this.homePage()
+		},
+		methods: {
+			signOut() {
+				this.show1 = true;
+			},
+			confirm() {
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				userApi.logout().then((res) => {
+					uni.hideLoading();
+					this.show1 = false;
+					this.carhelp.logoff()
+					uni.redirectTo({
+						url: '/pages/login/login'
+					})
+				}).catch(error => {
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss" scoped>
+	::v-deep.u-cell_title {
+		color: rgba(51, 51, 51, 1);
+	}
+
+	::v-deep.u-cell__value {
+		color: #777777;
+	}
+
+	;
+
+	.exit {
+		background-color: #fff;
+		margin: 24rpx 0 0 0;
+		text-align: center;
+		line-height: 96rpx;
+		color: rgba(238, 49, 56, 1);
+		font-size: 32rpx;
+	}
+</style>

+ 332 - 0
pages/task/addTask.vue

@@ -0,0 +1,332 @@
+<template>
+	<view  class="jpmain  " >
+			<u-navbar  title="故障上报" title-color="#101010"></u-navbar>
+			
+			<view class="list" >
+				<view class="item"  >
+					<view class="name">
+						<span>*</span>选择地锁
+				
+					</view>
+					<view class="value"  @click="gotoSelectLock()">
+						<view :style="taskInfo.lockId?'':'color:#BBB'"
+						>{{taskInfo.lockId?lockName:'选择需要上报的地锁'}}</view>
+						<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+					</view>
+				</view>
+				<view class="item">
+					<view class="name">
+						地锁编号
+				
+					</view>
+					<view class="value">
+						<view :style="taskInfo.lockId?'':'color:#BBB'"
+						>{{taskInfo.lockId?lockNo:'选择需要上报的地锁'}}</view>
+					</view>
+				</view>
+				 
+			</view>
+			<view class="list" >
+				<view class="item"  >
+					<view class="name">
+						<span>*</span>故障类型
+				
+					</view>
+					<view class="value" @click="selectTaskInfoCodeBtn">
+						<view :style="taskInfo.code?'':'color:#BBB'"
+						>{{taskInfo.code?codeN:'请选择故障类型'}}</view>
+						<u-icon name="arrow-right" size="24" color="#BBBBBB"></u-icon>
+					</view>
+				</view>
+				<view class="item item-plus"  >
+					<view class="name">
+						问题描述
+				
+					</view>
+					<view class="value" >
+						<textarea placeholder="请简单描述处理内容" 
+						v-model="taskInfo.desc" placeholder-class="textareaclass"
+						class="textarea"></textarea>
+					</view>
+				</view>
+				<view class="item item-plus"  >
+					<view class="name">
+						上传图片
+				
+					</view>
+					<view class="value" >
+						<u-upload name="photoFile"
+								ref="uUpload"
+								 :form-data="formData" :header="header" :action="action"
+								  :file-list="listPic" ></u-upload>
+					</view>
+				</view>
+			</view>
+			
+			<u-select v-model="selectTaskInfoCode"  :default-value="selectTaskInfoCodeValue"
+			value-name="value" label-name="name" @confirm="selectTaskInfoCodeConfirm"
+			:list="codeList"></u-select>
+			
+			<view class="floating-button">
+				<view class="button"  @click="submit" >
+					
+					提交
+				</view>
+				
+			</view>
+	</view>
+</template>
+
+<script>
+	import * as API from '@/apis/pagejs/pagesTask.js'
+	
+	export default {
+		data() {
+			return {
+				listPic: [],
+				action:"",
+				formData:{
+					
+				},
+				header:{
+					
+				},
+				codeN:"",
+				selectTaskInfoCode:false,
+				selectTaskInfoCodeValue:[0],
+				lockNo:"",
+				lockName:"",
+				
+				taskInfo:{
+					lockId:"",
+					code:"",
+					desc:"",
+					images:"",
+					
+				},
+				codeList:[]
+			};
+		},
+		onLoad() {
+			this.action=process.jphelp.BASE_URL+"uploadPicture"
+			this.formData.subFolder="/floorlock/inspection/addTask"
+			var token=this.jphelp.getToken()
+			
+			this.header={
+					
+				'Authorization':token
+			}
+			this.findByCatalogName({
+				catalogName:'设备故障类型'
+			},"codeList")
+		},
+		methods:{
+			submit(){
+				if(!this.taskInfo.lockId){
+					uni.showToast({
+						title:"选择需要上报的地锁"
+					})
+					 return
+				}
+				if(!this.taskInfo.code){
+					uni.showToast({
+						title:"请选择故障类型"
+					})
+					 return
+				}
+				
+				let files = [];
+				// 通过filter,筛选出上传进度为100的文件(因为某些上传失败的文件,进度值不为100,这个是可选的操作)
+				files = this.$refs.uUpload.lists.filter(val => {
+					return val.progress == 100;
+				})
+				// 如果您不需要进行太多的处理,直接如下即可
+					// files = this.$refs.uUpload.lists;
+				
+				//(files);
+					
+				var imgUrl=files.map(item=>{
+					return item.response.data;
+				})
+				//(imgUrl);
+				this.taskInfo.images = imgUrl.join(',');
+				
+				
+				
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				
+				API.addErr(this.taskInfo).then((res) => {
+					
+					uni.showModal({
+						title: '提示',
+						showCancel: false,
+						content: "上报成功",
+						success: res1 => {
+							if (res1.confirm) {
+								uni.navigateBack()
+							} else if (res1.cancel) {
+								//('用户点击取消');
+							}
+						}
+					})
+				
+					uni.hideLoading();
+				
+				}).catch(error => {
+				
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+				
+				
+			},
+			findByCatalogName(obj,listName){
+				uni.showLoading({
+					title: "加载中",
+					mask: true,
+				})
+				
+				API.findByCatalogName(obj).then((res) => {
+					
+					var arr = res.data.dataDictionaryList
+					
+					this[listName] = arr
+				
+					uni.hideLoading();
+				
+				}).catch(error => {
+				
+					uni.hideLoading();
+					uni.showToast({
+						title: error,
+						icon: "none"
+					})
+				})
+				
+			},
+			
+			selectTaskInfoCodeConfirm(e){
+				console.log(e)
+				this.codeN=e[0].label
+				this.taskInfo.code=e[0].value
+			},
+			selectTaskInfoCodeBtn(){
+				if(this.taskInfo.code){
+					//this.selectTaskInfoCodeValue=[parseInt(this.bindInfo.type)-1]
+					var i =this.codeList.findIndex(item=>{
+						return item.value==this.taskInfo.code
+					})
+					this.selectTaskInfoCodeValue=[i]
+				}
+				this.selectTaskInfoCode=true;
+			},
+			gotoSelectLock(){
+				uni.navigateTo({
+				  url: '/pages/task/selectLock',
+				  events: {
+				    // 为指定事件添加一个监听器,获取被打开页面传送到当前页面的数据
+				    acceptDataFromOpenerPage: (item)=>{
+						console.log(item)
+						this.taskInfo.lockId=item.item.id
+						this.lockName=item.item.name
+						this.lockNo=item.item.lockNo
+						this.$forceUpdate()
+						
+				    },
+				 
+				  }
+				 
+				})
+			}
+		}
+	}
+</script>
+
+<style lang="scss">
+	.jpmain{padding-bottom: 120rpx;}
+.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: 24rpx;
+			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;
+						
+					}
+					.textarea{
+						background-color: rgba(241,242,245,1);
+						width: 100%;
+						border-radius: 4px;
+					}
+					
+			}
+		}
+		.item-plus{
+			flex-direction: column;
+			.value,.name{
+				   width: 100%;
+			}
+			.name{
+				    padding-bottom: 32rpx;
+			}
+		}
+	}
+	
+	.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;
+			}
+	}
+	
+	.textareaclass{
+		padding:16rpx
+	}
+</style>

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott