slambb преди 3 години
ревизия
358145f6f9
променени са 53 файла, в които са добавени 13226 реда и са изтрити 0 реда
  1. 30 0
      App.vue
  2. 22 0
      common/checker.js
  3. 236 0
      common/config.js
  4. 20 0
      index.html
  5. 37 0
      main.js
  6. 81 0
      manifest.json
  7. 40 0
      pages.json
  8. 50 0
      pages/game/game.vue
  9. 243 0
      pages/game/subGame/subGame.nvue
  10. 944 0
      pages/index/index.vue
  11. BIN
      static/devicesIcon/bandage.png
  12. BIN
      static/devicesIcon/handle.png
  13. BIN
      static/devicesIcon/hotman.png
  14. BIN
      static/devicesIcon/rope.png
  15. BIN
      static/devicesOther/boxingb.png
  16. BIN
      static/devicesOther/boxingw.png
  17. BIN
      static/devicesOther/deviceright.png
  18. BIN
      static/devicesOther/link.png
  19. BIN
      static/devicesOther/radio-b.png
  20. BIN
      static/devicesOther/radio-g.png
  21. BIN
      static/gameCloseW.png
  22. BIN
      static/logo.png
  23. 76 0
      uni.scss
  24. 36 0
      util/util-css/icon.css
  25. 451 0
      util/util-css/main-nvue.css
  26. 4606 0
      util/util-css/main.css
  27. 79 0
      util/util-js/AccAndOri.js
  28. 77 0
      util/util-js/Animation.js
  29. 147 0
      util/util-js/BLE.js
  30. 689 0
      util/util-js/EquipmentAction.js
  31. 373 0
      util/util-js/action/jump-0.1.js
  32. 279 0
      util/util-js/action/jump-0.2.js
  33. 378 0
      util/util-js/action/jump.js
  34. 57 0
      util/util-js/avatar.js
  35. 83 0
      util/util-js/city.js
  36. 89 0
      util/util-js/date.js
  37. 109 0
      util/util-js/devices.js
  38. 157 0
      util/util-js/effect/firework.js
  39. 10 0
      util/util-js/enum.js
  40. 17 0
      util/util-js/makeNumber.js
  41. 455 0
      util/util-js/o0.js
  42. 437 0
      util/util-js/o0Project.js
  43. 164 0
      util/util-js/o0ProjectRelease.js
  44. 255 0
      util/util-js/o0ProjectRelease0.1.js
  45. 52 0
      util/util-js/puchConfig.js
  46. 100 0
      util/util-js/requstUtil.js
  47. 26 0
      util/util-js/service.js
  48. 2099 0
      util/util-js/store.js
  49. 26 0
      util/util-js/util-data.js
  50. 9 0
      util/util-js/vconsole.min.js
  51. 150 0
      util/util-js/verify.js
  52. 37 0
      util/util-js/webSocket.js
  53. 0 0
      util/util-js/wxLogin.js

+ 30 - 0
App.vue

@@ -0,0 +1,30 @@
+<script>
+	export default {
+		onLaunch: function() {
+			console.log('App Launch')
+			// 锁住屏幕正方向
+			plus.screen.lockOrientation('portrait-primary');
+			// 屏幕常亮
+			// 下面这个打包要开启手机设置权限
+			plus.device.setWakelock(true);
+		},
+		onShow: function() {
+			console.log('App Show')
+		},
+		onHide: function() {
+			console.log('App Hide')
+		}
+	}
+</script>
+
+<style>
+	/*每个页面公共css */
+	// #ifndef APP-PLUS-NVUE
+	@import "util/util-css/main.css";
+	@import "util/util-css/icon.css";
+	// #endif
+	/* nvue 页面公共css */
+	// #ifdef APP-PLUS-NVUE 
+	@import "util/util-css/main-nvue.css";
+	// #endif 
+</style>

+ 22 - 0
common/checker.js

@@ -0,0 +1,22 @@
+module.exports = {
+	error:'',
+	isJSON : function (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;
+			}
+		}
+	},
+	isNumber : function (checkVal){
+		var reg = /^-?[1-9][0-9]?.?[0-9]*$/;
+		return reg.test(checkVal);
+	}
+}

+ 236 - 0
common/config.js

@@ -0,0 +1,236 @@
+//设置游戏列表的更新时间,超过这个时间,不显示出来
+//"2020-07-14"
+//************* ios 注意此时间设置,目前设置2021-01-24,暂时用于处理游戏显示 *************
+const endTime = "2021-03-01"
+//************* 默认的蓝牙设备刷新间隔 再config 设置 a:10ms,b:20ms*************
+const refreshRate = "a";
+//*******当前活动环境,需要和根据地址设置!!环境 dev,prd
+const active = "dev";
+//线上地址,腾讯云服务器
+// const host="https://www.9527fun.cn/api_prd"
+//测试地址,阿里云服务器
+const host = "https://www.9527fun.cn/api_dev"
+//本地测试地址
+// const host = "http://192.168.0.109:9090/api_dev"
+// const host = "http://192.168.0.112:9090/api_dev"
+// const host = "http://47.104.216.192:9090/api_dev"
+// const host = "http://121.4.103.151:9090/api_prd"
+// const host = "http://121.4.59.141:9090/api_dev"
+
+const URL = {
+	//验证token,获取服务器返回的信息
+	VERIFICATION: `${host}/program/Verification_Info`,
+	
+	/**
+	 * @deprecated since version 2.4.15
+	 */
+	SMSLOGIN: `${host}/program/SMS_login`,
+	//根据不同类型账号注册登录
+	SMSLOGINFROMTYPE: `${host}/program/SMS_login_from_type`,
+	
+	
+	/**
+	 * @deprecated since version 2.4.10
+	 */
+	//获取验证码
+	GETCODE: `${host}/program/getCode`,
+	/**
+	 * 新增 
+	 * 根据类型获取验证码,0:电话 和1:邮箱 
+	 */
+	GETCODEACCORDINGTYPE: `${host}/program/getCodeAccordingType`,
+
+	/**
+	 * 短信绑定手机号
+	 * @deprecated since version 2.4.10
+	 */
+	BINDPHONE: `${host}/program/SMS_bind_phone`,
+	//根据类型绑定手机号,0:电话 和1:邮箱 
+	BINDACCOUNT: `${host}/program/SMS_bind_account`,
+
+
+	// 解绑手机号
+	DELETEPHONE: `${host}/program/delete_phone`,
+	//绑定微信信息
+	BINDWXINFO: `${host}/program/bind_wx_info`,
+	/**
+	 * @deprecated since version 2.4.10
+	 */
+	//密码登录
+	PASSWORDlOGIN: `${host}/program/password_login`,
+	/**
+	 * 新增 
+	 * 根据类型使用密码登录,0:电话 和1:邮箱 
+	 */
+	LOGINPASSWORDBASEDONTHETYPE: `${host}/program/password_login_type`,
+	//根据验证码修改密码
+	MODIFYPASSWORDFROMSMS: `${host}/program/SMS_modify_password`,
+	//根据旧密码修改密码
+	MODIFYPASSWORDFROMACCOUNT: `${host}/program/modify_password_from_account`,
+	// 小程序用户登录
+	USERlOGINURL: `${host}/program/client_login`,
+	// 苹果用户登录
+	APPLElOGINURL: `${host}/program/client_apple_login`,
+	//android 端微信登录
+	ANDROIDLOGINURL: `${host}/program/client_wx_login`,
+	// 用户删除token
+	USERLOGINOUT: `${host}/program/delete_token`,
+	// 微信端解密信息接口
+	WXGETUSERINFO: `${host}/program/wx_getUserInfo`,
+
+	//添加前端设备的信息
+	ADDCLIENTINFO: `${host}/program/add_client_info`,
+
+	//获取version code 状态,用于处理特定信息显示
+	GETVERSIONCODE: `${host}/program/get_version_code_state`,
+
+	/**
+	 * 用户处理部分
+	 */
+	// 获取用户信息
+	USERINFOURL: `${host}/user_info/get`,
+	// 添加用户信息
+	USERINFOADD: `${host}/user_info/add`,
+	// 添加url 用户等信息
+	USERINFOADDAVATARINFO: `${host}/user_info/add_wx_avatar_info`,
+	// 添加apple用户信息
+	USERINFOAPPLEADD: `${host}/user_info/appleAdd`,
+
+	// 添加用户头像
+	USERINFOADDAVATAR: `${host}/user_info/add_avatar`,
+
+	//添加更新自身体重
+	USERADDWEIGHT: `${host}/user_info/add_weight`,
+
+	//获取钱包信息,对应gold 和 diamond
+	USERGETWALLETINFO: `${host}/user_info/get_user_wallets`,
+
+	//获取体重列表
+	USERGETWEIGHT: `${host}/user_info/get_weight`,
+
+	//添加修改计划信息
+	FITNESSPROGRAM: `${host}/fitness_program/add`,
+
+	FITNESSPROGRAMGET: `${host}/fitness_program/get`,
+
+	/**
+	 * 7-28 好友操作部分
+	 */
+	//获取体重列表
+	SEARCHFIRENDLIST: `${host}/user_info/friend_search_list`,
+	ADDFIRENDINFO: `${host}/user_info/friend_add`,
+	DELETEFIRENDINFO: `${host}/user_info/friend_delete`,
+	GETFRIENDLIST: `${host}/user_info/get_friend_list`,
+
+	/**
+	 * 20210902
+	 * 用户签到相关部分
+	 */
+	GETSIGNINLIST: `${host}/user_info/get_sign_in_list`,
+	USERSIGNIN: `${host}/user_info/user_sign_in`,
+
+	//游戏页面部分
+	//获取全部游戏
+	GAMELIST: `${host}/game/list`,
+	//获取游戏详情
+	GAMEDETAIL: `${host}/game/detail`,
+	//获取推荐列表
+	GAMERECOMMEND: `${host}/game/recommend_list`,
+	GAMERECOMMENDBYPLATFORM: `${host}/game/recommend_list_platform`,
+	//获取游戏类目
+	GAMECATEGORY: `${host}/game/game_category_list`,
+	//根据游戏类目获取游戏列表
+	GAMELIST_FROM_CATEGORY: `${host}/game/list_from_category`,
+	GAMELIST_FROM_CATEGORY_PLATFORM: `${host}/game/list_from_category_platform`,
+
+	//根据游戏显示获取游戏列表
+	GAMELIST_BY_RANKING_SHOW: `${host}/game/list_by_ranking_show`,
+	GAMELIST_BY_RANKING_SHOW_AND_PLATFORM: `${host}/game/list_by_ranking_show_and_platform`,
+
+	//收藏
+	//添加
+	FAVORITESADD: `${host}/favorites/add`,
+	//修改
+	FAVORITESMODIFY: `${host}/favorites/modify`,
+	//获取收藏 列表
+	FAVORITESGET: `${host}/favorites/get`,
+	FAVORITESGETBYPLATFORM: `${host}/favorites/get_by_platform`,
+	//添加 最近玩 列表
+	RECENTLYPLAYINGADD: `${host}/recently_playing/add`,
+	//获取 最近玩 列表
+	RECENTLYPLAYINGGET: `${host}/recently_playing/get`,
+	RECENTLYPLAYINGGETBYPLATFORM: `${host}/recently_playing/get_by_platform`,
+	//添加当前排行榜游戏,
+	MOTIFYRANKGAME: `${host}/ranking/add_rank_game`,
+	//获取排行榜里面的游戏
+	GETRANKGAME: `${host}/ranking/get_rank_game`,
+
+	//更新 排行榜
+	UPLOADRANKING: `${host}/ranking/upload`,
+	//获取 排行榜
+	GETRANKRANGR: `${host}/ranking/get_range`,
+
+	//获取 ai的随机信息
+	AIRANDOMINFO: `${host}/client_game/ai_random_info`,
+	//给webview 图片中转接口
+	TRANSFERPICTURE: `${host}/client_game/transfer_picture`,
+
+	//设备操作
+	//绑定二维码设备
+	DEVICEBIND: `${host}/device/bind`,
+	//获取绑定的设备
+	DEVICEBINDINGLIST: `${host}/device/binding_list`,
+
+	//绑定蓝牙设备
+	BLEBIND: `${host}/bluetooth/bind`,
+	//查看是否可以绑定此设备
+	BLEFINDHASBIND: `${host}/bluetooth/findHasBind`,
+	//获取绑定的设备
+	BLEBINDINGLIST: `${host}/bluetooth/binding_list`,
+
+	/**
+	 * 任务部分
+	 */
+	GETLEVELJUMPLIST: `${host}/level/getLevelJumpList`, //只获取levelJump列表,后续其他扩展新加
+	PASSTHELEVEL: `${host}/level/passTheLevel`, //通用处理过关操作
+	UNLOCKLEVEL: `${host}/level/unlockLevel`, //通用处理解锁关卡操作
+	GETLEVELLIST: `${host}/level/getLevelList`, //获取level列表,返回一个全类型
+
+	PKLEVELREWARD: `${host}/level/pkLevelReward`, //pk奖励
+
+	/**
+	 * 奖励,荣誉,金币,钻石等
+	 */
+	GETALLHONORS: `${host}/reward/getAllHonorList`, //获取全部荣誉
+
+	/**
+	 * fc 游戏接口
+	 */
+	//根据种类获取对应的分类菜单
+	FCCATEGORYBYTYPE: `${host}/FC/category_by_type`,
+
+	FCListByCategory: `${host}/FC/list_by_category`,
+
+
+	/**
+	 * ota
+	 */
+	GETOTA: `${host}/OTA/get_ota`,
+	/**
+	 * 版本更新信息
+	 */
+	APPVERSIONUPDATE: `${host}/app/version_update`,
+
+	/**
+	 * 上传反馈信息
+	 */
+	UPLOADFEEDBACK: `${host}/manager/upload_feedback`,
+}
+
+
+export default {
+	active,
+	URL,
+	endTime,
+	refreshRate
+}

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

+ 37 - 0
main.js

@@ -0,0 +1,37 @@
+import Vue from 'vue'
+import App from './App'
+
+var getStackTrace = function() {
+	var obj = {};
+	Error.captureStackTrace(obj, getStackTrace);
+	return obj.stack;
+};
+
+console.oldLog = console.log;
+console.log = function(str) {
+	uni.$emit("onLog", str);
+	//这里可以操作给服务器
+	console.oldLog(str);
+}
+
+
+
+
+import store from './util/util-js/store.js'
+import testWebSocket from './util/util-js/webSocket.js'
+
+
+Vue.config.productionTip = false
+
+Vue.prototype.$store = store
+
+Vue.prototype.$testWS = testWebSocket;
+
+
+App.mpType = 'app'
+
+const app = new Vue({
+	store,
+	...App
+})
+app.$mount()

+ 81 - 0
manifest.json

@@ -0,0 +1,81 @@
+{
+    "name" : "ProAdvanced_Tool",
+    "appid" : "__UNI__C5B9CC0",
+    "description" : "",
+    "versionName" : "1.0.2",
+    "versionCode" : 20220806,
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueStyleCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {
+            "Bluetooth" : {}
+        },
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
+                    "<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>",
+                    "<uses-permission android:name=\"android.permission.BLUETOOTH_PRIVILEGED\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>",
+                    "<uses-permission android:name=\"android.permission.BLUETOOTH\"/>",
+                    "<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {
+                "ad" : {}
+            }
+        }
+    },
+    /* 快应用特有相关 */
+    "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"
+}

+ 40 - 0
pages.json

@@ -0,0 +1,40 @@
+{
+	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTitleText": "uni-app"
+				
+			}
+		}
+	    ,{
+            "path" : "pages/game/game",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "",
+                "enablePullDownRefresh": false,
+				"app-plus": {
+					"titleNView": false,
+					"subNVues": [{
+						"id": "game",
+						"path": "pages/game/subGame/subGame",
+						"type": "popup",
+						"style": {
+							"width": "100%",
+							// "height": "50%",
+							"position": "absolute"
+						}
+					}]
+				}
+            }
+            
+        }
+    ],
+	"globalStyle": {
+		"navigationBarTextStyle": "black",
+		"navigationBarTitleText": "uni-app",
+		"navigationBarBackgroundColor": "#F8F8F8",
+		"backgroundColor": "#F8F8F8"
+	},
+	"uniIdRouter": {}
+}

+ 50 - 0
pages/game/game.vue

@@ -0,0 +1,50 @@
+<template>
+	<view>
+		<view class="content">
+		</view>
+	</view>
+</template>
+
+<script>
+	export default {
+		data() {
+			return {
+				bUnload: false
+			}
+		},
+		onLoad(op) {
+			/**
+			 * $on 之后要调用 $off,不然会重复绑定
+			 */
+			uni.$on("game-load", () => {
+				uni.$emit("setOnceGameOption", {});
+			});
+		
+			uni.$on("game-unload", (data) => {
+				if (!this.bUnload) {
+					this.bUnload = true;
+					uni.navigateBack({
+						delta: 1
+					})
+				}
+			});
+	
+		},
+		onUnload() {
+			//subview
+			uni.$off("game-load");
+			uni.$off("game-unload");
+		},
+		methods: {
+			
+		}
+	}
+</script>
+
+<style>
+	.content {
+		align-content: center;
+		height: 750rpx;
+		background-color: #F4F5F6;
+	}
+</style>

+ 243 - 0
pages/game/subGame/subGame.nvue

@@ -0,0 +1,243 @@
+<template>
+	<view>
+		<view class="web-view">
+			<web-view class="web-view-child" :src="'http://'+LocationGameUrl" ref="webview" @pagestart="onPageStart"
+				@onPostMessage="handlePostMessage" @error="onError"></web-view>
+		</view>
+
+		<view class="web-back" @click="navBack">
+			<image style="width: 40rpx;height: 40rpx;" src="/static/gameCloseW.png"></image>
+		</view>
+	</view>
+
+
+
+</template>
+
+<script>
+	var currentWebview;
+	var orientId = null,
+		accId = null;
+
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex';
+
+	export default {
+		computed: mapState(['LocationGameUrl']),
+		data() {
+			return {
+				url: '',
+				error: '',
+				PageStart: false, // 记录网页请求的加载状态,true 加载成功 false 加载失败
+				//当前选择的item
+				decodeItem: null,
+				bMyAttitudeListen: false,
+				count: 0,
+				startGame: false,
+				currentWebview: null,
+			}
+		},
+		onLoad() {
+			let _self = this;
+			var pages = getCurrentPages();
+			var page = pages[pages.length - 1];
+			currentWebview = page.$getAppWebview();
+			
+			//监听一次调用setOnceGameOption
+			console.log("子组件初始化");
+			uni.$once("setOnceGameOption", (option) => {
+				//http://192.168.1.12:7456
+				// if (option) {
+				// 	this.decodeItem = JSON.parse(decodeURIComponent(option));
+				// 	this.url = this.decodeItem.gameWebUrl;
+				// }
+			});
+			//子窗体onload 后获取父窗体的onload数据
+			uni.$emit("game-load");
+
+			uni.getCurrentSubNVue().addEventListener("hide", function() {
+				console.log("subNVue子窗体已隐藏!");
+				//通知游戏,页面退出
+				_self.sendMessage("onSubHide", {
+					msg: '退出页面'
+				});
+
+				uni.$off('updateBLEDeviceData', _self.gWatchBLEUpdate);
+				_self.$store.state.bGamePlaying = false;
+				uni.$emit("game-unload", {});
+
+
+			});
+			//*****注释蓝牙操作******
+			//监听物理返回按钮
+			plus.key.addEventListener('backbutton', () => {
+				this.navBack();
+			}, false);
+			// uni.$on("showGame", (option) => {
+			// 	this.onShow();
+			// });
+
+		},
+		onUnload() {
+			uni.$off('updateBLEDeviceData', this.gWatchBLEUpdate);
+			this.$store.state.bGamePlaying = false;
+			console.log("subNVue子窗体 onUnload!");
+			uni.$emit("game-unload");
+		},
+		methods: {
+			...mapMutations([]),
+			navBack() {
+				this.$store.state.bGamePlaying = false;
+				// uni.$off('updateBLEDeviceData', this.gWatchBLEUpdate);
+				uni.getCurrentSubNVue().hide('auto');
+			},
+			onShow() {
+				//设置store状态
+				this.$store.state.bGamePlaying = true;
+				// uni.$on('updateBLEDeviceData', this.gWatchBLEUpdate);
+				uni.getCurrentSubNVue().show('fade-in', 250, () => {});
+			},
+			//蓝牙断开连接时候
+			callbackCloseBLE() {
+				this.sendMessage("onDeviceClose", {
+					msg: '设备断开连接。'
+				});
+			},
+			//蓝牙状态回调
+			callbackBLEState(res) {
+				this.sendMessage("onDeviceState", res)
+			},
+			/**
+			 * 统一发送信息
+			 * @param {Object} gameData
+			 */
+			sendMessage(functionName, gameData) {
+				let data = {
+					"funName": functionName,
+					"gameData": gameData
+				}
+				if (!this.PageStart) {
+					console.warn("页面未初始化不能传消息", data);
+					return;
+				}
+				let initStr = JSON.stringify(data);
+				// console.log(initStr);
+				this.$refs.webview.evalJs("onWebViewMessage(" + initStr + ")");
+			},
+			handlePostMessage: function(postData) {
+				console.log("handlePostMessage得到参数", postData.detail);
+				let temp = postData.detail.data[0];
+				let gameData = temp.gameData;
+				if (temp.funName == "onStartAccAndGyro") {
+					this.bMyAttitudeListen = true;
+					this.count = 0;
+					//监听蓝牙回调
+					// uni.$off('updateBLEDeviceData', this.gWatchBLEUpdate);
+					// setTimeout(() => {
+					// 	uni.$on('updateBLEDeviceData', this.gWatchBLEUpdate);
+					// }, 500)
+					uni.$on('updateBLEDeviceData', this.gWatchBLEUpdate);
+				} else if (temp.funName == "onStopAccAndGyro") {
+					this.bMyAttitudeListen = false;
+					//监听蓝牙回调
+					uni.$off('updateBLEDeviceData', this.gWatchBLEUpdate);
+				}
+			},
+			onPageStart: function(e) {
+				// 监听页面加载成功
+				this.PageStart = true;
+				console.log("onPageStart==", e);
+				setTimeout(() => {
+					//加载成功后,显示
+					// uni.getCurrentSubNVue().show('fade-in', 250, () => {});
+					
+					this.onShow();
+				}, 100)
+			},
+			onPageFinish: function(e) {
+				console.log("onPageFinish==", e);
+			},
+			onError: function(e) {
+				// 监听页面加载错误
+				// this.error = this.url;
+				console.error(e);
+			},
+			gWatchBLEUpdate: function(data) {
+
+				//如果是模块外面触发,需要离线打包
+				// if (this.bMyAttitudeListen) {
+
+				// }
+				//添加计数
+				data.count = ++this.count;
+				this.sendMessage("updateAccAndGyro", data);
+			}
+		}
+	}
+</script>
+
+<style>
+	/* #ifdef APP-PLUS */
+	.web-view {
+		flex: 1;
+		flex-direction: column;
+		/* background-color: #007AFF; */
+	}
+
+	.web-view-child {
+		width: 750rpx;
+		flex: 1;
+	}
+
+	/* #endif */
+	/* #ifdef H5 */
+
+	.web-view {
+		display: flex;
+		flex-direction: column;
+		position: absolute;
+		bottom: 0;
+		top: 0;
+		left: 0;
+		right: 0;
+	}
+
+	.web-view-child {
+		position: relative;
+		width: 100%;
+		height: 100%;
+	}
+
+	/* #endif */
+
+
+	.sendMessage {
+		width: 300rpx;
+		position: fixed;
+		bottom: 100rpx;
+		left: 50rpx;
+	}
+
+	.web-back {
+		position: fixed;
+		top: 40px;
+		right: 20px;
+		width: 160rpx;
+		height: 80rpx;
+		border-radius: 45px;
+		/* border: 1px solid #FFFFFF; */
+		/* box-shadow: 0px 0px 1px #FFFFFF; */
+		background-color: rgba(0, 0, 0, 1);
+		opacity: 0.5;
+
+		/* #ifndef APP-PLUS-NVUE */
+		/* z-Index: 999; */
+		display: flex;
+		/* #endif */
+
+		justify-content: center;
+		align-items: center;
+	}
+</style>

+ 944 - 0
pages/index/index.vue

@@ -0,0 +1,944 @@
+<template>
+	<view>
+		<view style="height: 50px;"></view>
+		<view>
+			<view class="title">Cocos预览地址:{{LocationGameUrl}}</view>
+			<input class="uni-input" :value="LocationGameUrl" @input="onKeyInput" placeholder="输入cocos预览地址" />
+		</view>
+		<view class="card-view padding-top padding-bottom" v-for="(item,index) in devicesList" :key="index"
+			:id="'task_'+index" :class="item.bRatio?'hardware-border':''" :style="{'z-index': threeZIndex}">
+			<view class="flex justify-between align-center">
+				<view class="flex justify-start align-center">
+					<image style="margin-left: 20rpx; width: 200rpx;height: 120rpx;" :src="item.icon" mode="aspectFit">
+					</image>
+					<view style="width: 350rpx;margin-left: 10rpx;">
+						<view style="margin: 20rpx 0rpx; font-weight: bold; font-size: 18px; color: #565656;">
+							{{item.cname}}
+						</view>
+						<view style="font-size: 12px; white-space:pre-wrap;" class="make-text-bPurple">
+							{{item.describe}}{{item.bOldDevice?'(旧手柄)':''}}
+						</view>
+					</view>
+
+				</view>
+				<image style="margin-right: 60rpx; width: 60rpx;height: 60rpx;"
+					:src="item.bRatio?'/static/devicesOther/radio-b.png':'/static/devicesOther/radio-g.png'"
+					mode="aspectFit" @tap="_onRadio(item,$event)"></image>
+			</view>
+		</view>
+
+		<view v-if="currentItem" style="display: flex;flex-direction: row;">
+			<button style="margin: 10rpx;" type="primary" @click="B_OnSetMTU">MTU</button>
+			<button style="margin: 10rpx;" type="primary" @click="writeBLEValue('V')">版本</button>
+			<button style="margin: 10rpx;" type="primary" @click="writeBLEValue('M')">mac</button>
+		</view>
+		<view v-if="currentItem" style="display: flex;flex-direction: row;">
+			<button style="margin: 10rpx;" type="primary" @click="writeBLEValue('H')">开启高速</button>
+			<button style="margin: 10rpx;" type="primary" @click="writeBLEValue('h')">关闭高速</button>
+		</view>
+		<scroll-view class="text-box" scroll-y="true">
+			<scroll-view scroll-x="true">
+				<text selectable="true" style="background-color: greenyellow;">{{text}}</text>
+			</scroll-view>
+		</scroll-view>
+
+		<button type="warn" :disabled="extraLine.length<=0" @click="remove">
+			清除输入框数据
+		</button>
+		<button style="margin-top: 2px;" type="warn" :disabled="!currentItem" @click="onShowGame">
+			显示游戏
+		</button>
+
+		<button style="margin-top: 2px;" type="warn" @click="onEmit">
+			模拟发送
+		</button>
+
+		<!-- <button style="margin-top: 2px;" type="warn" @click="onClise">
+			close
+		</button> -->
+
+
+		<!-- <view class="content">
+		</view> -->
+	</view>
+
+
+</template>
+
+<script>
+	import config from '@/common/config.js';
+	import reqUtil from '@/util/util-js/requstUtil.js';
+	import ble from '@/util/util-js/BLE.js';
+
+	import {
+		mapState,
+		mapMutations
+	} from 'vuex';
+
+	export default {
+		computed: mapState(['bOpenBluetooth', 'bOpenSuccess', 'bListenAdapterStateChange', 'bListenDeviceFound',
+			'BLEConnectDevice', 'BLEGetServices', 'cIndex', 'bConnection', 'bVerifiedConnection', 'BLEInfoList',
+			'BLEDeviceShowList', 'finallyUseDevice', 'systemInfo', 'guideUnlockState', 'currentModeIndex',
+			"bListenerAccArray", 'LocationGameUrl','bGamePlaying'
+		]),
+		data() {
+			return {
+				// 设备列表
+				devicesList: [],
+				currentItem: null,
+				//设置一个旧的连接item
+				oldItem: null,
+				searchObj: null,
+				//设置搜索超时时间
+				searchTimeOut: null,
+				option: null,
+				saveObj: null,
+				//搜索提示定时器
+				searchMac: null,
+				//
+				getServicesTimeout: null,
+				writeMacTimeout: null,
+				//限制关闭连接
+				bLimitClose: false,
+
+				//是否需要检测发起的连接蓝牙是否匹配上
+				bTestBondConnect: true,
+				//是否显示
+				bShow: true,
+				//切换连接
+				bSwitch: false,
+
+				//提示
+				circular: false,
+				currentHeight: 0,
+				threeTipHeight: 0,
+				threeZIndex: 0,
+				currentIndex: 5,
+
+
+				//测试
+				text: '',
+				extraLine: [],
+
+				bShowGame: false,
+			}
+		},
+		onLoad(op) {
+			this.add("初始化");
+			uni.$on('retryConnectBLESuccess', this.onRetryConnectBLESuccess);
+			uni.$on('callbackCloseBLE', this.hardCallbackCloseBLE);
+			uni.$on('listenerBLE', this.onListenerBLE);
+			uni.$on('updateBLEDeviceData', this.callbackUpdateBLEData);
+
+			this.BLEInfoList.forEach((item, index, selfarr) => {
+				if (item.deviceType == 'BLEHandle' && item.usageMode == 'hotman') {
+					let item = Object.assign({}, selfarr[index], {
+						bOldDevice: false
+					});
+					this.devicesList.push(item);
+				}
+			})
+
+
+			//subview
+			/**
+			 * $on 之后要调用 $off,不然会重复绑定
+			 */
+			this.onGetLocationGameUrl();
+			
+
+			uni.$on("log", this.add)
+
+		},
+		onUnload() {
+			uni.$off('retryConnectBLESuccess', this.onRetryConnectBLESuccess);
+			uni.$off('callbackCloseBLE', this.hardCallbackCloseBLE);
+			uni.$off('listenerBLE', this.onListenerBLE);
+			uni.$off('updateBLEDeviceData', this.callbackUpdateBLEData);
+			//清除定时器
+			this.onClearTimeout();
+
+
+			uni.$off("log", this.add)
+
+		},
+		onShow() {
+			this.bShow = true;
+		},
+		onReady() {},
+		onHide() {
+			//如果蓝牙弹出匹配框,会触发onHide。这时候处理蓝牙连接流程检测应等onShow 时候,再检测
+			this.bShow = false;
+		},
+		methods: {
+			...mapMutations(['initAdapter', 'onCreateBLESuccess', 'onGetBLEDeviceServices', 'onOnlyCloseBLEConnection',
+				'onGetRSSITransDistance',
+				'addBLEDevice', 'onWriteBLEConnectionValue', 'deleteBLEDevice', 'B_GetBondedDevices',
+				'B_OpenBLESetting', 'setGuideUnlockState', 'switchLevelList', 'onSetLocationGameUrl',
+				'onGetLocationGameUrl', 'onTestEmit', 'B_CloseBLEConnection', 'B_OnSetMTU'
+			]),
+			onEmit() {
+				this.onTestEmit();
+			},
+			/**
+			 * 显示游戏
+			 */
+			onShowGame() {
+				// uni.$emit("showGame");
+				// this.bShowGame = true;
+				uni.navigateTo({
+					url:"../game/game"
+				})
+			},
+			//设备回调事件
+			callbackUpdateBLEData(data) {
+				//如果在监听状态时候隐藏页面,返回
+				// console.log(data)
+				// if (!this.bShow) return;
+				// this.add(JSON.stringify(data));
+				if (this.bGamePlaying) return;
+				let str = "";
+				for (let i = 0; i < data.length; i++) {
+					str +=
+						"ax:" + data[i].acc.ax + "\n" +
+						"ay:" + data[i].acc.ay + "\n" +
+						"az:" + data[i].acc.az + "\n" +
+						"gx:" + data[i].gyro.gx + "\n" +
+						"gy:" + data[i].gyro.gy + "\n" +
+						"gz:" + data[i].gyro.gz + "\n" +
+						"ms:" + data[i].ms + "\n" ;
+				}
+				this.text = str;
+				// this.text =
+				// 	"ax:" + data.acc.ax + "\n" +
+				// 	"ay:" + data.acc.ay + "\n" +
+				// 	"az:" + data.acc.az + "\n" +
+				// 	"gx:" + data.gyro.gx + "\n" +
+				// 	"gy:" + data.gyro.gy + "\n" +
+				// 	"gz:" + data.gyro.gz + "\n" +
+				// 	"ms:" + data.ms;
+				// if(this.bListenerAccArray)return;
+				// if (this.BLEConnectDevice.usageMode == "hotman") {
+				// 	this.gUpdateSandbagAlgorithm({
+				// 		data: data,
+				// 		callback: (res) => {
+				// 			if (res.type == 'hit') {
+				// 				console.log("hotman 打击:" + JSON.stringify(res));
+				// 			}
+				// 		}
+				// 	});
+				// } else if (this.BLEConnectDevice.usageMode == "general") {
+				// 	//这个是普通打击模式
+				// } else if (this.BLEConnectDevice.usageMode == "ropeSkipping") {
+				// 	this.onConvertDeviceData({
+				// 		data: data,
+				// 		callback: (outData) => {
+				// 			// this.outBLEData = {
+				// 			// 	acc: outData.convertAcc,
+				// 			// 	gyro: outData.convertGyro
+				// 			// }
+				// 			// console.log(JSON.stringify(outData),JSON.stringify(data));
+				// 			console.log("hotman 打击:" + JSON.stringify(outData))
+				// 			data.acc = outData.convertAcc;
+				// 			data.gyro = outData.convertGyro;
+				// 			//跳绳蓝牙反馈
+				// 		}
+				// 	});
+				// }
+			},
+
+			onClearTimeout() {
+				// 退出后,清除计时器
+				if (this.searchMac) {
+					clearTimeout(this.searchMac);
+					this.searchMac = null;
+				}
+				//servicesTimeout
+				if (this.getServicesTimeout) {
+					clearTimeout(this.getServicesTimeout);
+					this.getServicesTimeout = null;
+				}
+				//写入指令writeMacTimeout
+				if (this.writeMacTimeout) {
+					clearTimeout(this.writeMacTimeout);
+					this.writeMacTimeout = null;
+				}
+
+				if (this.searchTimeOut) {
+					clearTimeout(this.searchTimeOut);
+					this.searchTimeOut = null;
+				}
+			},
+			//监听回调
+			onListenerBLE(res) {
+				console.log('onListenerBLE:', res, this.saveObj);
+				this.add(res.value);
+				// if (res.type !== 'mac') return;
+				// //如果mac 回调了不用提示
+				// if (this.searchMac) {
+				// 	clearTimeout(this.searchMac);
+				// 	this.searchMac = null;
+				// }
+				// let _self = this;
+				// let mac = res.value;
+				// // console.log('mac =====', mac);
+				// //用返回的mac 判断,如果非法,则断开连接
+				// //就判断一下是否
+				// //测试
+				// // mac="BB:34:24:22:77:88";
+				// // mac="较è¾";
+				// //判断mac地址是否是合理的格式
+				// var tempMacRegExp =
+				// 	/[A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}:[A-Fa-f0-9]{2}/;
+				// if (!tempMacRegExp.test(mac)) {
+				// 	uni.hideToast();
+				// 	uni.showModal({
+				// 		title: '验证信息',
+				// 		content: '获取Mac地址失败,请重新连接。'
+				// 	})
+				// 	//关闭当前连接
+				// 	_self.onOnlyCloseBLEConnection({
+				// 		getSuccess: () => {
+				// 			_self.currentItem = null;
+				// 			_self.saveObj = null;
+				// 		}
+				// 	});
+				// 	return;
+				// }
+				// _self.saveObj = Object.assign({}, _self.saveObj, {
+				// 	deviceMac: mac,
+				// 	bOldDevice: false
+				// });
+				// _self.addBLEDevice(_self.saveObj);
+				// _self.ConnectionSuccess();
+			},
+			/**
+			 * 连接设备成功
+			 */
+			ConnectionSuccess() {
+				for (let i = 0; i < this.devicesList.length; i++) {
+					let eq = this.devicesList[i];
+					if (
+						(eq.ename.indexOf("mobilePhoneBandage") > -1 && this.BLEConnectDevice.id == 0) ||
+						(eq.ename.indexOf("hotman") > -1 && this.BLEConnectDevice.id == 1) ||
+						(eq.ename.indexOf("BLEHandle") > -1 && this.BLEConnectDevice.id == 2) ||
+						(eq.ename.indexOf("rope") > -1 && this.BLEConnectDevice.id == 3)) {
+
+						eq.bRatio = true;
+						this.currentItem = eq;
+						/**
+						 * 已验证的连接设置true
+						 */
+						// this.$store.state.bVerifiedConnection = true;
+						/**
+						 * 根据名字兼容旧设备
+						 */
+						// let _tempMac = this.saveObj.deviceMac.replace(/:/g, "");
+						// let _fourStr = _tempMac.substring(_tempMac.length - 4, _tempMac.length);
+						// console.log("格式化去掉冒号后mac:", _tempMac, "==", _fourStr);
+						// let _tempInt = ble.hex2int(_fourStr);
+						// console.log("格式化去掉冒号后_tempInt:", _tempInt);
+						// //这里判断旧设备,因为目前这批新设备,用的也是202012的名字,所以这里处理兼容旧设备就行了
+						// //用mac判断区分,一起有100个是旧设备,还有部分非标准的mac,根据后台字段判断
+						// //如果后台存在bOldDevice 字段,则根据字段判断是否是旧设备
+						// if (this.saveObj.name === "BGBox_202012" &&
+						// 	_tempInt <= 101 && _tempInt >= 0 || this.saveObj.bOldDevice) {
+						// 	this.$store.state.bOldDeviceType = true;
+						// 	eq.bOldDevice = true;
+						// 	console.log("旧设备:", this.$store.state.bOldDeviceType);
+						// } else {
+						// 	console.log("旧设备", this.$store.state.bOldDeviceType);
+						// 	eq.bOldDevice = false;
+						// }
+
+						uni.hideToast();
+					}
+				}
+			},
+			onCheckBondDevice() {
+				console.log("onCheckBondDevice", this.bTestBondConnect);
+				if (this.bTestBondConnect && this.bShow) {
+					/**
+					 * 假如手机没有匹配,断开连接
+					 */
+					console.log(2, this.finallyUseDevice);
+					this.B_GetBondedDevices({
+						deviceId: this.finallyUseDevice.deviceId,
+						success: (bondedDevice) => {
+							uni.hideToast();
+							if (bondedDevice == null) {
+								// if (plus.os.name == 'Android') 
+								{
+									//此问题 华为手机容易出现
+									//android手机已配对的设备 不存在,但是app 又直接连接成功了。提示,并且断开app连接
+									//1.关闭当前连接
+									this.onOnlyCloseBLEConnection({
+										getSuccess: () => {
+											this.currentItem.bRatio = false;
+											this.currentItem = null;
+											this.saveObj = null;
+										}
+									});
+									//2.跳转蓝牙设置
+									uni.showModal({
+										title: '蓝牙配对失败',
+										content: '请跳转后点击配对BGBox_2020,成功后手动跳转回哔蹦重新连接。',
+										success: (res) => {
+											if (res.confirm) {
+												this.B_OpenBLESetting();
+											}
+										}
+									})
+								}
+
+							}
+						}
+					});
+					this.bTestBondConnect = false;
+				} else {
+					uni.hideToast();
+				}
+			},
+			onRetryConnectBLESuccess() {
+				this.ConnectionSuccess();
+			},
+			hardCallbackCloseBLE() {
+
+				if (this.BLEConnectDevice == null && this.currentItem && !this.bSwitch) {
+					this.currentItem.bRatio = false;
+					this.currentItem = null;
+					this.saveObj = null;
+				}
+				//如果限制不走重连
+				if (this.bLimitClose) return;
+
+				console.log(this.currentItem, this.oldItem);
+				if (this.oldItem && this.currentItem && this.currentItem.id == this.oldItem.id) {
+					// this.$store.state.bConnection = false;
+					if (this.currentItem.bRatio) {
+						uni.showToast({
+							title: '设备断开连接!',
+							icon: 'none',
+							duration: 2000,
+							mask: true
+						})
+						this.currentItem.bRatio = false;
+						this.oldItem = null;
+						this.currentItem = null;
+						//断开连接
+						this.$store.state.bVerifiedConnection = false;
+					}
+				} else if (this.bConnection && this.BLEConnectDevice) {
+					//假如匹配过程中断开连接
+					this.$store.state.BLEConnectDevice = null;
+					this.$store.state.bConnection = false;
+					// uni.hideToast();
+					// console.log("//假如匹配过程中断开连接");
+					uni.showToast({
+						title: '连接失败,尝试重新连接。',
+						icon: 'none',
+						mask: true,
+						duration: 2000
+					})
+					if (this.getServicesTimeout) {
+						clearTimeout(this.getServicesTimeout);
+						this.getServicesTimeout = null;
+					}
+				}
+
+			},
+			/**
+			 * 开始查找设备
+			 * */
+			startBluetoothDeviceDiscovery() {
+				//在页面显示的时候判断是都已经初始化完成蓝牙适配器若成功,则开始查找设备
+				let _self = this;
+				if (_self.bOpenBluetooth) {
+					//1.第一步还是先进行设备搜索
+					_self.onCanStart();
+				} else {
+					_self.initAdapter(() => {
+						_self.startBluetoothDeviceDiscovery();
+					});
+				}
+			},
+			/**
+			 * 通过检测手机连接的设备进行连接,null 的话进行搜索操作
+			 */
+			onBondedDeviceConnect(data) {
+				let _self = this;
+				//获取手机本身已连接的硬件,
+				//示例
+				// {
+				// 	"deviceId": "C5:5C:19:04:00:30",
+				// 	"name": "BGBox_202012",
+				// 	"RSSI": -74,
+				// 	"localName": "BGBox_20201",
+				// 	"advertisServiceUUIDs": ["00001812-0000-1000-8000-00805F9B34FB", "0000FFF0-0000-1000-8000-00805F9B34FB"]
+				// }
+
+				console.log("onBoded ***************:", _self.finallyUseDevice);
+
+				_self.B_GetBondedDevices({
+					deviceId: _self.finallyUseDevice == null ? null : _self.finallyUseDevice.deviceId,
+					success: (bondedDevice) => {
+						console.log("bondedDevice:", bondedDevice);
+						//获取已和蓝牙连接的设备
+						if (bondedDevice != null) {
+							//如果用户匹配了对应的设备,直接用对应的设备来连接
+							let setDevice = {
+								"deviceId": bondedDevice.address,
+								"name": bondedDevice.name,
+								"RSSI": -74,
+								"localName": "",
+								"advertisServiceUUIDs": ["00001812-0000-1000-8000-00805F9B34FB",
+									"0000FFF0-0000-1000-8000-00805F9B34FB"
+								]
+							}
+
+							let obj = Object.assign({}, setDevice, _self.currentItem);
+							//finallyUserDevice 就是最后一次使用搜索到的设备信息
+							_self.saveObj = Object.assign({}, setDevice, {
+								id: _self.currentItem.id
+							});
+							uni.showToast({
+								title: '设备连接中...',
+								icon: 'loading',
+								duration: 10000,
+								mask: true
+							})
+							console.log("GetBondedDevices:::===", setDevice, _self.currentItem, obj);
+							// 先直连,然后判断版本
+							_self._onConnectDevice(obj);
+
+							//getBond后发起的连接,不需要检测了
+							_self.bTestBondConnect = false;
+						} else {
+							console.log("没有获取到绑定的设备");
+							uni.showToast({
+								title: '获取匹配设备失败',
+								icon: 'none',
+								mask: true
+							})
+						}
+					}
+				});
+			},
+			//开始搜索
+			onCanStart() {
+				let _self = this;
+				uni.showToast({
+					title: '设备连接中...',
+					icon: 'loading',
+					duration: 15000,
+					mask: true
+				})
+				// 1.已经搜索到的,根据蓝牙回调的mac 地址判断合法性。
+				uni.startBluetoothDevicesDiscovery({
+					allowDuplicatesKey: true,
+					success: res => {
+						// console.log("startBluetoothDevicesDiscovery:", res);
+
+						_self.bSwitch = false;
+						_self.onBluetoothDeviceFound();
+					},
+					fail: res => {
+						console.log("搜索失败!");
+						_self.initAdapter(() => {
+							_self.startBluetoothDeviceDiscovery();
+						});
+					}
+				});
+				// 2.没有搜索到的,一段时间后处理。比如手机已经连接了设备,但是app 里面搜索不到,也没记录使用过的。
+				if (_self.searchTimeOut) {
+					clearTimeout(_self.searchTimeOut);
+					_self.searchTimeOut = null;
+				}
+				//搜索一段时间后,停止搜索
+				if (plus.os.name == 'iOS') {
+					_self.searchTimeOut = setTimeout(() => {
+						_self.stopBluetoothDevicesDiscovery();
+						//搜索失败后,再检查是否和手机配对的设备连接
+						_self.onBondedDeviceConnect();
+					}, 4000)
+				} else {
+					_self.searchTimeOut = setTimeout(() => {
+						_self.stopBluetoothDevicesDiscovery();
+					}, 8000)
+				}
+
+			},
+			/**
+			 * 停止搜索蓝牙设备
+			 */
+			stopBluetoothDevicesDiscovery() {
+				uni.stopBluetoothDevicesDiscovery({
+					success: e => {
+						// console.log('停止搜索蓝牙设备:' + e.errMsg);
+					},
+					fail: e => {
+						console.log('停止搜索蓝牙设备失败,错误码:' + e.errCode);
+					}
+				});
+			},
+			/**
+			 * 发现外围设备
+			 */
+			onBluetoothDeviceFound() {
+				let _self = this;
+				_self.searchObj = null;
+				uni.onBluetoothDeviceFound(res => {
+					/**
+					 * 获取在蓝牙模块生效期间所有已发现的蓝牙设备。包括已经和本机处于连接状态的设备。
+					 */
+					// console.log("onBluetoothDeviceFound:", res);
+					res.devices.forEach(device => {
+						if (device.name.indexOf('PBox') > -1 || device.name.indexOf('BGBox') > -1 || device
+							.name.indexOf('Rope') > -1) {
+							//如果搜索的设备名 不是对应当前设备类型,过滤
+							// if (device.name.indexOf(_self.currentItem.deviceName) == -1) return;
+							if (_self.currentItem.deviceName.indexOf('PBox') == -1 &&
+								_self.currentItem.deviceName.indexOf('BGBox') == -1 &&
+								_self.currentItem.deviceName.indexOf('Rope') == -1
+							) return;
+							//寻找到对应设备时候,其余的返回
+							if (_self.searchObj) return;
+							_self.searchObj = device;
+							if (_self.searchTimeOut) {
+								clearTimeout(_self.searchTimeOut);
+								_self.searchTimeOut = null;
+							}
+							//currentItem 是mode 页面选中的item
+							let obj = Object.assign({}, device, _self.currentItem);
+
+							_self.saveObj = Object.assign({}, {
+								id: _self.currentItem.id
+							}, device);
+
+							// console.log(device, "****", obj, _self.saveObj, _self.currentItem)
+							// 先直连,然后判断版本
+							_self._onConnectDevice(obj);
+							_self.stopBluetoothDevicesDiscovery();
+						}
+					})
+
+				})
+			},
+
+			onBack() {
+				uni.navigateBack({
+					delta: 1
+				})
+			},
+
+			// 提示点击连接设备
+			_onConnectDevice(item) {
+				//servicesTimeout
+				if (this.getServicesTimeout) {
+					clearTimeout(this.getServicesTimeout);
+					this.getServicesTimeout = null;
+				}
+				//写入指令writeMacTimeout
+				if (this.writeMacTimeout) {
+					clearTimeout(this.writeMacTimeout);
+					this.writeMacTimeout = null;
+				}
+				// //如果已经连接,加上服务不存在,直接获取服务
+				// if (this.bConnection && this.BLEGetServices && this.BLEGetServices.length == 0) {
+				// 	console.log("***直接获取服务*******");
+				// 	this.onGetBLEDeviceServices({
+				// 		item: item,
+				// 		success: (res) => {
+				// 			console.log("*****getBLEDeviceServices************");
+				// 			//连接成功了,设置旧的item
+				// 			this.oldItem = this.currentItem;
+
+				// 			setTimeout(() => {
+				// 				this.saveObj = Object.assign({}, this
+				// 					.saveObj, {
+				// 						deviceMac: '',
+				// 						bOldDevice: false
+				// 					});
+				// 				this.addBLEDevice(this.saveObj);
+				// 				this.ConnectionSuccess();
+
+				// 			}, 2000)
+				// 			// uni.showToast({
+				// 			// 	title: '正在验证设备信息...',
+				// 			// 	icon: 'loading',
+				// 			// 	duration: 10000,
+				// 			// 	mask: true
+				// 			// })
+				// 			// // 初始化服务后,获取版本,判断
+				// 			// // 停止蓝牙加速计
+				// 			// this.writeMacTimeout = setTimeout(() => {
+				// 			// 	//todo 停止蓝牙加速计
+				// 			// 	// this.onWriteBLEConnectionValue({
+				// 			// 	// 	value: "4"
+				// 			// 	// });
+				// 			// 	// 发送获取mac
+				// 			// 	this.onWriteBLEConnectionValue({
+				// 			// 		value: "M"
+				// 			// 	});
+				// 			// 	if (this.searchMac) {
+				// 			// 		clearTimeout(this.searchMac);
+				// 			// 		this.searchMac = null;
+				// 			// 	}
+				// 			// 	this.searchMac = setTimeout(() => {
+				// 			// 		uni.hideToast();
+				// 			// 		uni.showModal({
+				// 			// 			title: '提示',
+				// 			// 			content: '检测设备失败。\r\n1.再次尝试连接。\r\n2.或者重启手柄(Reset键位也可)后再尝试连接'
+				// 			// 		})
+				// 			// 		this.onOnlyCloseBLEConnection({
+				// 			// 			getSuccess: () => {
+				// 			// 				if (this.currentItem)
+				// 			// 					this.currentItem.bRatio = false;
+
+				// 			// 				this.currentItem = null;
+				// 			// 			}
+				// 			// 		});
+				// 			// 	}, 6000)
+				// 			// }, 3000)
+
+				// 		}
+				// 	});
+				// 	return;
+				// }
+				//创建一个连接,需要对应close
+				this.onCreateBLESuccess({
+					item: item,
+					getSuccess: () => {
+						// console.log("****创建一个连接*******");
+						this.getServicesTimeout = setTimeout(() => {
+							this.onGetBLEDeviceServices({
+								item: item,
+								success: (res) => {
+									// console.log("******getBLEDeviceServices************", res);
+									//连接成功了,设置旧的item
+									this.oldItem = this.currentItem;
+									setTimeout(() => {
+										this.saveObj = Object.assign({}, this
+											.saveObj, {
+												deviceMac: '',
+												bOldDevice: false
+											});
+										this.addBLEDevice(this.saveObj);
+										this.ConnectionSuccess();
+
+									}, 2000)
+
+									// uni.showToast({
+									// 	title: '正在验证设备信息...',
+									// 	icon: 'loading',
+									// 	duration: 10000,
+									// 	mask: true
+									// })
+									// // 初始化服务后,获取版本,判断
+									// // 停止蓝牙加速计
+									// this.writeMacTimeout = setTimeout(() => {
+									// 	//todo 停止蓝牙加速计
+									// 	// this.onWriteBLEConnectionValue({
+									// 	// 	value: "4"
+									// 	// });
+									// 	// 发送获取mac
+									// 	this.onWriteBLEConnectionValue({
+									// 		value: "M"
+									// 	});
+									// 	if (this.searchMac) {
+									// 		clearTimeout(this.searchMac);
+									// 		this.searchMac = null;
+									// 	}
+									// 	this.searchMac = setTimeout(() => {
+									// 		uni.hideToast();
+									// 		uni.showModal({
+									// 			title: '提示',
+									// 			content: '检测设备失败。\r\n1.再次尝试连接。\r\n2.或者重启手柄(Reset键位也可)后再尝试连接'
+									// 		})
+									// 		this.onOnlyCloseBLEConnection({
+									// 			getSuccess: () => {
+									// 				if (this
+									// 					.currentItem
+									// 				)
+									// 					this
+									// 					.currentItem
+									// 					.bRatio =
+									// 					false;
+
+									// 				this.currentItem =
+									// 					null;
+									// 			}
+									// 		});
+									// 	}, 6000)
+									// }, 3000)
+
+								}
+							});
+						}, 2500);
+					}
+				})
+			},
+
+			_onRadio(item, event) {
+				console.log(this.bConnection, this.BLEGetServices);
+				if (this.bConnection && this.BLEGetServices && this.BLEGetServices.length == 0) {
+					console.log("***直接获取服务*******");
+					this.onGetBLEDeviceServices({
+						item: item,
+						success: (res) => {
+							console.log("*****getBLEDeviceServices************");
+							//连接成功了,设置旧的item
+							this.oldItem = this.currentItem;
+
+							setTimeout(() => {
+								this.saveObj = Object.assign({}, this
+									.saveObj, {
+										deviceMac: '',
+										bOldDevice: false
+									});
+								this.addBLEDevice(this.saveObj);
+								this.ConnectionSuccess();
+
+							}, 2000)
+
+						}
+					});
+					return;
+				}
+				if (!item.bRatio) {
+					//设置默认值
+					this.bTestBondConnect = true;
+					if (this.BLEConnectDevice) {
+						this.onOnlyCloseBLEConnection({
+							getSuccess: () => {
+								if (this.currentItem)
+									this.currentItem.bRatio = false;
+
+								this.currentItem = null;
+								this.currentItem = item;
+								this.bSwitch = true;
+								console.log("this.currentItem1 ==:", this.currentItem, this
+									.bOpenBluetooth,
+									this.BLEConnectDevice);
+								this.startBluetoothDeviceDiscovery();
+							}
+						});
+						return;
+					}
+					this.currentItem = null;
+					this.currentItem = item;
+					// console.log("this.currentItem ==2:", this.currentItem, this.bOpenBluetooth, this.BLEConnectDevice);
+					this.startBluetoothDeviceDiscovery();
+				}
+			},
+			onClise() {
+				this.B_CloseBLEConnection({
+					deviceId: "C5:5C:19:04:01:22"
+				});
+			},
+			//跳转进入升级页面,
+			onNavUpdateDevice() {
+				//需要连接设备后,才能进入升级
+				if (!this.currentItem || !this.currentItem.bRatio || !this.BLEConnectDevice) {
+					uni.showToast({
+						title: '请先连接硬件!',
+						icon: 'none'
+					})
+					return;
+				}
+				this.bLimitClose = true;
+				uni.navigateTo({
+					// url: "../devices-update/devices-update?deviceType=" + this.option.deviceType
+					url: "../devices-update/devices-update"
+				})
+			},
+
+			add: function(data) {
+				// console.log(data)
+
+				if (this.extraLine.length > 500) {
+					this.extraLine = [];
+					this.text = this.extraLine.join('\n');
+				}
+
+				this.extraLine.push(data);
+				this.text = this.extraLine.join('\n');
+
+
+			},
+			remove: function(e) {
+				if (this.extraLine.length > 0) {
+					// this.extraLine.pop();
+					this.extraLine = [];
+					this.text = this.extraLine.join('\n');
+				}
+			},
+			writeBLEValue(str) {
+				this.onWriteBLEConnectionValue({
+					value: str
+				})
+			},
+			onKeyInput: function(event) {
+				this.onSetLocationGameUrl(event.target.value);
+			}
+		}
+
+	}
+</script>
+
+<style>
+	.hardware-border {
+		border: 1rpx solid #9898FF;
+		box-sizing: border-box;
+	}
+
+	.swiper {
+		flex: 1;
+		background-color: rgba(0, 0, 0, 0.32);
+	}
+
+	.swiper-item {
+		flex: 1;
+	}
+
+	.bluetooth-guide-number {
+		border-radius: 18px;
+		border-width: 1rpx;
+		width: 30px;
+		height: 30px;
+		text-align: center;
+		line-height: 30px;
+		color: #000000;
+		/* border-color: #FFFFFF; */
+		background-color: #FFFFFF;
+		margin-right: 13px;
+	}
+
+	.text-box {
+		margin: 20rpx;
+		display: flex;
+		width: 95%;
+		min-height: 300rpx;
+		max-height: 600rpx;
+		background-color: #c6c6c6;
+		justify-content: center;
+		align-items: center;
+		text-align: left;
+		font-size: 30upx;
+		color: #353535;
+		line-height: 1.8;
+		border: 1rpx solid #555555;
+		overflow-y: hidden;
+	}
+
+
+	.content {
+		align-content: center;
+		height: 300rpx;
+		background-color: #F4F5F6;
+	}
+
+	.uni-input {
+		border: 1rpx solid #000000;
+	}
+</style>

BIN
static/devicesIcon/bandage.png


BIN
static/devicesIcon/handle.png


BIN
static/devicesIcon/hotman.png


BIN
static/devicesIcon/rope.png


BIN
static/devicesOther/boxingb.png


BIN
static/devicesOther/boxingw.png


BIN
static/devicesOther/deviceright.png


BIN
static/devicesOther/link.png


BIN
static/devicesOther/radio-b.png


BIN
static/devicesOther/radio-g.png


BIN
static/gameCloseW.png


BIN
static/logo.png


+ 76 - 0
uni.scss

@@ -0,0 +1,76 @@
+/**
+ * 这里是uni-app内置的常用样式变量
+ *
+ * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
+ * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
+ *
+ */
+
+/**
+ * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
+ *
+ * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
+ */
+
+/* 颜色变量 */
+
+/* 行为相关颜色 */
+$uni-color-primary: #007aff;
+$uni-color-success: #4cd964;
+$uni-color-warning: #f0ad4e;
+$uni-color-error: #dd524d;
+
+/* 文字基本颜色 */
+$uni-text-color:#333;//基本色
+$uni-text-color-inverse:#fff;//反色
+$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
+$uni-text-color-placeholder: #808080;
+$uni-text-color-disable:#c0c0c0;
+
+/* 背景颜色 */
+$uni-bg-color:#ffffff;
+$uni-bg-color-grey:#f8f8f8;
+$uni-bg-color-hover:#f1f1f1;//点击状态颜色
+$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
+
+/* 边框颜色 */
+$uni-border-color:#c8c7cc;
+
+/* 尺寸变量 */
+
+/* 文字尺寸 */
+$uni-font-size-sm:12px;
+$uni-font-size-base:14px;
+$uni-font-size-lg:16;
+
+/* 图片尺寸 */
+$uni-img-size-sm:20px;
+$uni-img-size-base:26px;
+$uni-img-size-lg:40px;
+
+/* Border Radius */
+$uni-border-radius-sm: 2px;
+$uni-border-radius-base: 3px;
+$uni-border-radius-lg: 6px;
+$uni-border-radius-circle: 50%;
+
+/* 水平间距 */
+$uni-spacing-row-sm: 5px;
+$uni-spacing-row-base: 10px;
+$uni-spacing-row-lg: 15px;
+
+/* 垂直间距 */
+$uni-spacing-col-sm: 4px;
+$uni-spacing-col-base: 8px;
+$uni-spacing-col-lg: 12px;
+
+/* 透明度 */
+$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
+
+/* 文章场景相关 */
+$uni-color-title: #2C405A; // 文章标题颜色
+$uni-font-size-title:20px;
+$uni-color-subtitle: #555555; // 二级标题颜色
+$uni-font-size-subtitle:26px;
+$uni-color-paragraph: #3F536E; // 文章段落颜色
+$uni-font-size-paragraph:15px;

Файловите разлики са ограничени, защото са твърде много
+ 36 - 0
util/util-css/icon.css


+ 451 - 0
util/util-css/main-nvue.css

@@ -0,0 +1,451 @@
+/* ==================
+          布局
+ ==================== */
+
+/*  -- flex弹性布局 -- */
+
+
+.flex {
+	display: flex;
+}
+
+.flex-sub {
+	flex: 1;
+}
+
+.flex-twice {
+	flex: 2;
+}
+
+.flex-treble {
+	flex: 3;
+}
+
+/* nvue 默认 column */
+.flex-direction-row {
+	flex-direction: row;
+}
+
+.flex-direction-column {
+	flex-direction: column;
+}
+
+
+.flex-wrap {
+	flex-wrap: wrap;
+}
+
+.align-start {
+	align-items: flex-start;
+}
+
+.align-end {
+	align-items: flex-end;
+}
+
+.align-center {
+	align-items: center;
+}
+
+.align-stretch {
+	align-items: stretch;
+}
+
+.justify-start {
+	justify-content: flex-start;
+}
+
+.justify-end {
+	justify-content: flex-end;
+}
+
+.justify-center {
+	justify-content: center;
+}
+
+.justify-between {
+	justify-content: space-between;
+}
+
+.justify-around {
+	justify-content: space-around;
+}
+
+/* ==================
+         position
+ ==================== */
+.pos-relative {
+	position: relative;
+}
+
+.pos-center {
+	position: absolute;
+	top: 0;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	justify-content: center;
+	align-items: center;
+}
+
+.pos-top-center {
+	position: absolute;
+	top: 0;
+	left: 0;
+	right: 0;
+	justify-content: center;
+	align-items: center;
+}
+
+/* ==================
+         线
+ ==================== */
+.border-1rpx-black {
+	border-width: 1rpx;
+	border-style: solid;
+	border-color: #000000;
+}
+.border-1rpx-bottom-black {
+	border-width: 1rpx;
+	border-style: solid;
+	border-color: rgba(0,0,0,0.7);
+}
+.border-1rpx-red {
+	border-width: 1rpx;
+	border-style: solid;
+	border-color: #FF0000;
+}
+
+/* ==================
+         蒙层 透明度
+ ==================== */
+.mask-bg-07 {
+	background-color: rgba(0, 0, 0, 0.7);
+}
+
+/* ==================
+          文本
+ ==================== */
+
+
+.text-18px {
+	font-size: 18px;
+	/* line-height: 36px; */
+}
+
+.text-16px {
+	font-size: 16px;
+	/* line-height: 32px; */
+}
+
+.text-11px {
+	font-size: 11px;
+	/* line-height: 22px; */
+}
+
+.text-12px {
+	font-size: 12px;
+}
+
+.text-13px {
+	font-size: 13px;
+	/* line-height: 23px; */
+}
+
+.text-14px {
+	font-size: 14px;
+	/* line-height: 28px; */
+}
+
+.text-15px {
+	font-size: 15px;
+	/* line-height: 30px; */
+}
+
+.text-22px {
+	font-size: 22px;
+	height: 22px;
+	line-height: 22px;
+}
+
+.text-26px {
+	font-size: 26px;
+	/* line-height: 52px; */
+}
+
+.text-38px {
+	font-size: 38px;
+	/* line-height: 52px; */
+}
+
+.text-18px-before::before {
+	font-size: 18px;
+}
+
+.text-20px-before::before {
+	font-size: 20px;
+}
+
+.text-22px-before::before {
+	font-size: 22px;
+}
+
+
+/* .text-price::before {
+	content: "¥";
+	font-size: 80%;
+	margin-right: 4upx;
+} */
+
+.text-cut {
+	text-overflow: ellipsis;
+	/* white-space: nowrap; */
+	overflow: hidden;
+}
+
+.text-lines1 {
+	/** 显示的行数 **/
+	lines: 1;
+}
+
+.text-lines2 {
+	/** 显示的行数 **/
+	lines: 2;
+}
+
+.text-bold {
+	font-weight: bold;
+}
+
+.text-medium {
+	font-weight: 400;
+}
+
+
+.text-center {
+	text-align: center;
+}
+
+.text-content {
+	line-height: 1.6;
+}
+
+.text-left {
+	text-align: left;
+}
+
+.text-right {
+	text-align: right;
+}
+
+
+.text-red,
+.line-red,
+.lines-red {
+	color: #e54d42;
+}
+
+.text-orange,
+.line-orange,
+.lines-orange {
+	color: #f37b1d;
+}
+
+.text-yellow,
+.line-yellow,
+.lines-yellow {
+	color: #fbbd08;
+}
+
+.text-olive,
+.line-olive,
+.lines-olive {
+	color: #8dc63f;
+}
+
+.text-green,
+.line-green,
+.lines-green {
+	color: #39b54a;
+}
+
+.text-cyan,
+.line-cyan,
+.lines-cyan {
+	color: #1cbbb4;
+}
+
+.text-blue,
+.line-blue,
+.lines-blue {
+	color: #0081ff;
+}
+
+.text-purple,
+.line-purple,
+.lines-purple {
+	color: #6739b6;
+}
+
+.text-mauve,
+.line-mauve,
+.lines-mauve {
+	color: #9c26b0;
+}
+
+.text-pink,
+.line-pink,
+.lines-pink {
+	color: #e03997;
+}
+
+.text-brown,
+.line-brown,
+.lines-brown {
+	color: #a5673f;
+}
+
+.text-grey,
+.line-grey,
+.lines-grey {
+	color: #8799a3;
+}
+
+.line-mGrey {
+	color: #EAEAEA;
+}
+
+.text-gray,
+.line-gray,
+.lines-gray {
+	color: #aaaaaa;
+}
+
+.text-black,
+.line-black,
+.lines-black {
+	color: #333333;
+}
+
+.text-white,
+.line-white,
+.lines-white {
+	color: #ffffff;
+}
+
+/* 蓝紫 */
+.make-line-bPurple::after,
+.make-lines-bPurple::after {
+	border-color: rgba(151, 151, 255, 1);
+}
+
+.make-line-bPurple,
+.make-lines-bPurple,
+.make-text-bPurple {
+	color: rgba(151, 151, 255, 1);
+}
+
+
+.make-bg-bPurple {
+	background-color: rgba(151, 151, 255, 1);
+}
+
+
+.bg-gray {
+	background-color: #f0f0f0;
+	color: #333333;
+}
+
+.bg-grey {
+	background-color: #8799a3;
+	color: #ffffff;
+}
+
+.bg-grey-mid {
+	background-color: #CDCDCD;
+	color: #ffffff;
+}
+
+/*  -- 内外边距 -- */
+
+.margin-0 {
+	margin: 0;
+}
+
+.margin-12px {
+	margin: 12px;
+}
+
+.margin-17px {
+	margin: 17px;
+}
+
+.margin-24px {
+	margin: 24px;
+}
+
+
+
+.position-relative {
+	position: relative;
+}
+
+.position-absolute-center {
+	position: absolute;
+	top: 0;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	justify-content: center;
+	align-items: center;
+}
+
+
+
+.position-absolute-center-bottom {
+	position: absolute;
+	/* top: 0; */
+	bottom: 0;
+	left: 0;
+	right: 0;
+	/* justify-content: center; */
+	align-items: center;
+}
+
+.position-absolute-center-top {
+	position: absolute;
+	top: 0;
+	/* bottom: 0; */
+	left: 0;
+	right: 0;
+	/* justify-content: center; */
+	align-items: center;
+}
+
+.position-absolute-center-around {
+	position: absolute;
+	top: 0;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	justify-content: space-around;
+	align-items: center;
+}
+
+.position-absolute-right-top {
+	position: absolute;
+	right: 0;
+	top: 0;
+}
+
+
+/* 自定义导航栏的图片大小 */
+.png-more {
+	width: 20px;
+	height: 20px;
+}
+
+.png-more-black {
+	width: 16px;
+	height: 16px;
+}

+ 4606 - 0
util/util-css/main.css

@@ -0,0 +1,4606 @@
+/*
+  ColorUi for uniApp  v2.1.6 | by 文晓港 2019-05-31 10:44:24
+  仅供学习交流,如作它用所承受的法律责任一概与作者无关  
+  
+  *使用ColorUi开发扩展与插件时,请注明基于ColorUi开发 
+  
+  (QQ交流群:240787041)
+*/
+
+/* ==================
+        初始化
+ ==================== */
+body {
+	background-color: #f1f1f1;
+	font-size: 28upx;
+	color: #333333;
+	font-family: Helvetica Neue, Helvetica, sans-serif;
+}
+
+view,
+scroll-view,
+swiper,
+button,
+input,
+textarea,
+label,
+navigator,
+image {
+	box-sizing: border-box;
+}
+
+.round {
+	border-radius: 5000upx;
+}
+
+.radius {
+	border-radius: 6upx;
+}
+
+/* ==================
+          图片
+ ==================== */
+
+image {
+	max-width: 100%;
+	display: inline-block;
+	position: relative;
+	z-index: 0;
+}
+
+image.loading::before {
+	content: "";
+	background-color: #f5f5f5;
+	display: block;
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	z-index: -2;
+}
+
+image.loading::after {
+	content: "\e7f1";
+	font-family: "cuIcon";
+	position: absolute;
+	top: 0;
+	left: 0;
+	width: 32upx;
+	height: 32upx;
+	line-height: 32upx;
+	right: 0;
+	bottom: 0;
+	z-index: -1;
+	font-size: 32upx;
+	margin: auto;
+	color: #ccc;
+	-webkit-animation: cuIcon-spin 2s infinite linear;
+	animation: cuIcon-spin 2s infinite linear;
+	display: block;
+}
+
+.response {
+	width: 100%;
+}
+
+/* ==================
+         开关
+ ==================== */
+
+switch,
+checkbox,
+radio {
+	position: relative;
+}
+
+switch::after,
+switch::before {
+	font-family: "cuIcon";
+	content: "\e645";
+	position: absolute;
+	color: #ffffff !important;
+	top: 0%;
+	left: 0upx;
+	font-size: 26upx;
+	line-height: 26px;
+	width: 50%;
+	text-align: center;
+	pointer-events: none;
+	transform: scale(0, 0);
+	transition: all 0.3s ease-in-out 0s;
+	z-index: 9;
+	bottom: 0;
+	height: 26px;
+	margin: auto;
+}
+
+switch::before {
+	content: "\e646";
+	right: 0;
+	transform: scale(1, 1);
+	left: auto;
+}
+
+switch[checked]::after,
+switch.checked::after {
+	transform: scale(1, 1);
+}
+
+switch[checked]::before,
+switch.checked::before {
+	transform: scale(0, 0);
+}
+
+/* #ifndef MP-ALIPAY */
+radio::before,
+checkbox::before {
+	font-family: "cuIcon";
+	content: "\e645";
+	position: absolute;
+	color: #ffffff !important;
+	top: 50%;
+	margin-top: -8px;
+	right: 5px;
+	font-size: 32upx;
+	line-height: 16px;
+	pointer-events: none;
+	transform: scale(1, 1);
+	transition: all 0.3s ease-in-out 0s;
+	z-index: 9;
+}
+
+radio .wx-radio-input,
+checkbox .wx-checkbox-input,
+radio .uni-radio-input,
+checkbox .uni-checkbox-input {
+	margin: 0;
+	width: 24px;
+	height: 24px;
+}
+
+checkbox.round .wx-checkbox-input,
+checkbox.round .uni-checkbox-input {
+	border-radius: 100upx;
+}
+
+/* #endif */
+
+switch[checked]::before {
+	transform: scale(0, 0);
+}
+
+switch .wx-switch-input,
+switch .uni-switch-input {
+	border: none;
+	padding: 0 24px;
+	width: 48px;
+	height: 26px;
+	margin: 0;
+	border-radius: 100upx;
+}
+
+switch .wx-switch-input:not([class*="bg-"]),
+switch .uni-switch-input:not([class*="bg-"]) {
+	background: #8799a3 !important;
+}
+
+switch .wx-switch-input::after,
+switch .uni-switch-input::after {
+	margin: auto;
+	width: 26px;
+	height: 26px;
+	border-radius: 100upx;
+	left: 0upx;
+	top: 0upx;
+	bottom: 0upx;
+	position: absolute;
+	transform: scale(0.9, 0.9);
+	transition: all 0.1s ease-in-out 0s;
+}
+
+switch .wx-switch-input.wx-switch-input-checked::after,
+switch .uni-switch-input.uni-switch-input-checked::after {
+	margin: auto;
+	left: 22px;
+	box-shadow: none;
+	transform: scale(0.9, 0.9);
+}
+
+radio-group {
+	display: inline-block;
+}
+
+
+
+switch.radius .wx-switch-input::after,
+switch.radius .wx-switch-input,
+switch.radius .wx-switch-input::before,
+switch.radius .uni-switch-input::after,
+switch.radius .uni-switch-input,
+switch.radius .uni-switch-input::before {
+	border-radius: 10upx;
+}
+
+switch .wx-switch-input::before,
+radio.radio::before,
+checkbox .wx-checkbox-input::before,
+radio .wx-radio-input::before,
+switch .uni-switch-input::before,
+radio.radio::before,
+checkbox .uni-checkbox-input::before,
+radio .uni-radio-input::before {
+	display: none;
+}
+
+radio.radio[checked]::after,
+radio.radio .uni-radio-input-checked::after {
+	content: "";
+	background-color: transparent;
+	display: block;
+	position: absolute;
+	width: 8px;
+	height: 8px;
+	z-index: 999;
+	top: 0upx;
+	left: 0upx;
+	right: 0;
+	bottom: 0;
+	margin: auto;
+	border-radius: 200upx;
+	/* #ifndef MP */
+	border: 7px solid #ffffff !important;
+	/* #endif */
+
+	/* #ifdef MP */
+	border: 8px solid #ffffff !important;
+	/* #endif */
+}
+
+.switch-sex::after {
+	content: "\e71c";
+}
+
+.switch-sex::before {
+	content: "\e71a";
+}
+
+.switch-sex .wx-switch-input,
+.switch-sex .uni-switch-input {
+	background: #e54d42 !important;
+	border-color: #e54d42 !important;
+}
+
+.switch-sex[checked] .wx-switch-input,
+.switch-sex.checked .uni-switch-input {
+	background: #0081ff !important;
+	border-color: #0081ff !important;
+}
+
+switch.red[checked] .wx-switch-input.wx-switch-input-checked,
+checkbox.red[checked] .wx-checkbox-input,
+radio.red[checked] .wx-radio-input,
+switch.red.checked .uni-switch-input.uni-switch-input-checked,
+checkbox.red.checked .uni-checkbox-input,
+radio.red.checked .uni-radio-input {
+	background-color: #e54d42 !important;
+	border-color: #e54d42 !important;
+	color: #ffffff !important;
+}
+
+switch.orange[checked] .wx-switch-input,
+checkbox.orange[checked] .wx-checkbox-input,
+radio.orange[checked] .wx-radio-input,
+switch.orange.checked .uni-switch-input,
+checkbox.orange.checked .uni-checkbox-input,
+radio.orange.checked .uni-radio-input {
+	background-color: #f37b1d !important;
+	border-color: #f37b1d !important;
+	color: #ffffff !important;
+}
+
+switch.yellow[checked] .wx-switch-input,
+checkbox.yellow[checked] .wx-checkbox-input,
+radio.yellow[checked] .wx-radio-input,
+switch.yellow.checked .uni-switch-input,
+checkbox.yellow.checked .uni-checkbox-input,
+radio.yellow.checked .uni-radio-input {
+	background-color: #fbbd08 !important;
+	border-color: #fbbd08 !important;
+	color: #333333 !important;
+}
+
+switch.olive[checked] .wx-switch-input,
+checkbox.olive[checked] .wx-checkbox-input,
+radio.olive[checked] .wx-radio-input,
+switch.olive.checked .uni-switch-input,
+checkbox.olive.checked .uni-checkbox-input,
+radio.olive.checked .uni-radio-input {
+	background-color: #8dc63f !important;
+	border-color: #8dc63f !important;
+	color: #ffffff !important;
+}
+
+switch.green[checked] .wx-switch-input,
+switch[checked] .wx-switch-input,
+checkbox.green[checked] .wx-checkbox-input,
+checkbox[checked] .wx-checkbox-input,
+radio.green[checked] .wx-radio-input,
+radio[checked] .wx-radio-input,
+switch.green.checked .uni-switch-input,
+switch.checked .uni-switch-input,
+checkbox.green.checked .uni-checkbox-input,
+checkbox.checked .uni-checkbox-input,
+radio.green.checked .uni-radio-input,
+radio.checked .uni-radio-input {
+	background-color: #39b54a !important;
+	border-color: #39b54a !important;
+	color: #ffffff !important;
+	border-color: #39B54A !important;
+}
+
+switch.cyan[checked] .wx-switch-input,
+checkbox.cyan[checked] .wx-checkbox-input,
+radio.cyan[checked] .wx-radio-input,
+switch.cyan.checked .uni-switch-input,
+checkbox.cyan.checked .uni-checkbox-input,
+radio.cyan.checked .uni-radio-input {
+	background-color: #1cbbb4 !important;
+	border-color: #1cbbb4 !important;
+	color: #ffffff !important;
+}
+
+switch.blue[checked] .wx-switch-input,
+checkbox.blue[checked] .wx-checkbox-input,
+radio.blue[checked] .wx-radio-input,
+switch.blue.checked .uni-switch-input,
+checkbox.blue.checked .uni-checkbox-input,
+radio.blue.checked .uni-radio-input {
+	background-color: #0081ff !important;
+	border-color: #0081ff !important;
+	color: #ffffff !important;
+}
+
+switch.purple[checked] .wx-switch-input,
+checkbox.purple[checked] .wx-checkbox-input,
+radio.purple[checked] .wx-radio-input,
+switch.purple.checked .uni-switch-input,
+checkbox.purple.checked .uni-checkbox-input,
+radio.purple.checked .uni-radio-input {
+	background-color: #6739b6 !important;
+	border-color: #6739b6 !important;
+	color: #ffffff !important;
+}
+
+switch.mauve[checked] .wx-switch-input,
+checkbox.mauve[checked] .wx-checkbox-input,
+radio.mauve[checked] .wx-radio-input,
+switch.mauve.checked .uni-switch-input,
+checkbox.mauve.checked .uni-checkbox-input,
+radio.mauve.checked .uni-radio-input {
+	background-color: #9c26b0 !important;
+	border-color: #9c26b0 !important;
+	color: #ffffff !important;
+}
+
+switch.pink[checked] .wx-switch-input,
+checkbox.pink[checked] .wx-checkbox-input,
+radio.pink[checked] .wx-radio-input,
+switch.pink.checked .uni-switch-input,
+checkbox.pink.checked .uni-checkbox-input,
+radio.pink.checked .uni-radio-input {
+	background-color: #e03997 !important;
+	border-color: #e03997 !important;
+	color: #ffffff !important;
+}
+
+switch.brown[checked] .wx-switch-input,
+checkbox.brown[checked] .wx-checkbox-input,
+radio.brown[checked] .wx-radio-input,
+switch.brown.checked .uni-switch-input,
+checkbox.brown.checked .uni-checkbox-input,
+radio.brown.checked .uni-radio-input {
+	background-color: #a5673f !important;
+	border-color: #a5673f !important;
+	color: #ffffff !important;
+}
+
+switch.grey[checked] .wx-switch-input,
+checkbox.grey[checked] .wx-checkbox-input,
+radio.grey[checked] .wx-radio-input,
+switch.grey.checked .uni-switch-input,
+checkbox.grey.checked .uni-checkbox-input,
+radio.grey.checked .uni-radio-input {
+	background-color: #8799a3 !important;
+	border-color: #8799a3 !important;
+	color: #ffffff !important;
+}
+
+switch.gray[checked] .wx-switch-input,
+checkbox.gray[checked] .wx-checkbox-input,
+radio.gray[checked] .wx-radio-input,
+switch.gray.checked .uni-switch-input,
+checkbox.gray.checked .uni-checkbox-input,
+radio.gray.checked .uni-radio-input {
+	background-color: #f0f0f0 !important;
+	border-color: #f0f0f0 !important;
+	color: #333333 !important;
+}
+
+switch.black[checked] .wx-switch-input,
+checkbox.black[checked] .wx-checkbox-input,
+radio.black[checked] .wx-radio-input,
+switch.black.checked .uni-switch-input,
+checkbox.black.checked .uni-checkbox-input,
+radio.black.checked .uni-radio-input {
+	background-color: #333333 !important;
+	border-color: #333333 !important;
+	color: #ffffff !important;
+}
+
+switch.white[checked] .wx-switch-input,
+checkbox.white[checked] .wx-checkbox-input,
+radio.white[checked] .wx-radio-input,
+switch.white.checked .uni-switch-input,
+checkbox.white.checked .uni-checkbox-input,
+radio.white.checked .uni-radio-input {
+	background-color: #ffffff !important;
+	border-color: #ffffff !important;
+	color: #333333 !important;
+}
+
+/* ==================
+          边框
+ ==================== */
+
+/* -- 实线 -- */
+
+.solid,
+.solid-top,
+.solid-right,
+.solid-bottom,
+.solid-left,
+.solids,
+.solids-top,
+.solids-right,
+.solids-bottom,
+.solids-left,
+.dashed,
+.dashed-top,
+.dashed-right,
+.dashed-bottom,
+.dashed-left {
+	position: relative;
+}
+
+.solid::after,
+.solid-top::after,
+.solid-right::after,
+.solid-bottom::after,
+.solid-left::after,
+.solids::after,
+.solids-top::after,
+.solids-right::after,
+.solids-bottom::after,
+.solids-left::after,
+.dashed::after,
+.dashed-top::after,
+.dashed-right::after,
+.dashed-bottom::after,
+.dashed-left::after {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border-radius: inherit;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+}
+
+.solid::after {
+	border: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-top::after {
+	border-top: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-right::after {
+	border-right: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-bottom::after {
+	border-bottom: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-left::after {
+	border-left: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solids::after {
+	border: 8upx solid #eee;
+}
+
+.solids-top::after {
+	border-top: 8upx solid #eee;
+}
+
+.solids-right::after {
+	border-right: 8upx solid #eee;
+}
+
+.solids-bottom::after {
+	border-bottom: 8upx solid #eee;
+}
+
+.solids-left::after {
+	border-left: 8upx solid #eee;
+}
+
+/* -- 虚线 -- */
+
+.dashed::after {
+	border: 1upx dashed #ddd;
+}
+
+.dashed-top::after {
+	border-top: 1upx dashed #ddd;
+}
+
+.dashed-right::after {
+	border-right: 1upx dashed #ddd;
+}
+
+.dashed-bottom::after {
+	border-bottom: 1upx dashed #ddd;
+}
+
+.dashed-left::after {
+	border-left: 1upx dashed #ddd;
+}
+
+/* -- 阴影 -- */
+
+.shadow[class*='white'] {
+	--ShadowSize: 0 1upx 6upx;
+}
+
+.shadow-lg {
+	--ShadowSize: 0upx 40upx 100upx 0upx;
+}
+
+.shadow-warp {
+	position: relative;
+	box-shadow: 0 0 10upx rgba(0, 0, 0, 0.1);
+}
+
+.shadow-warp:before,
+.shadow-warp:after {
+	position: absolute;
+	content: "";
+	top: 20upx;
+	bottom: 30upx;
+	left: 20upx;
+	width: 50%;
+	box-shadow: 0 30upx 20upx rgba(0, 0, 0, 0.2);
+	transform: rotate(-3deg);
+	z-index: -1;
+}
+
+.shadow-warp:after {
+	right: 20upx;
+	left: auto;
+	transform: rotate(3deg);
+}
+
+.shadow-blur {
+	position: relative;
+}
+
+.shadow-blur::before {
+	content: "";
+	display: block;
+	background: inherit;
+	filter: blur(10upx);
+	position: absolute;
+	width: 100%;
+	height: 100%;
+	top: 10upx;
+	left: 10upx;
+	z-index: -1;
+	opacity: 0.4;
+	transform-origin: 0 0;
+	border-radius: inherit;
+	transform: scale(1, 1);
+}
+
+/* ==================
+          按钮
+ ==================== */
+
+.cu-btn {
+	position: relative;
+	border: 0upx;
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	box-sizing: border-box;
+	padding: 0 30upx;
+	font-size: 28upx;
+	height: 64upx;
+	line-height: 1;
+	text-align: center;
+	text-decoration: none;
+	overflow: visible;
+	margin-left: initial;
+	transform: translate(0upx, 0upx);
+	margin-right: initial;
+}
+
+.cu-btn::after {
+	display: none;
+}
+
+.cu-btn:not([class*="bg-"]) {
+	background-color: #f0f0f0;
+}
+
+.cu-btn[class*="line"] {
+	background-color: transparent;
+}
+
+.cu-btn[class*="line"]::after {
+	content: " ";
+	display: block;
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border: 1upx solid currentColor;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	box-sizing: border-box;
+	border-radius: 12upx;
+	z-index: 1;
+	pointer-events: none;
+}
+
+.cu-btn.round[class*="line"]::after {
+	border-radius: 1000upx;
+}
+
+.cu-btn[class*="lines"]::after {
+	border: 6upx solid currentColor;
+}
+
+.cu-btn[class*="bg-"]::after {
+	display: none;
+}
+
+.cu-btn.sm {
+	padding: 0 20upx;
+	font-size: 20upx;
+	height: 48upx;
+}
+
+.cu-btn.lg {
+	padding: 0 40upx;
+	font-size: 32upx;
+	height: 80upx;
+}
+
+.cu-btn.cuIcon.sm {
+	width: 48upx;
+	height: 48upx;
+}
+
+.cu-btn.cuIcon {
+	width: 64upx;
+	height: 64upx;
+	border-radius: 500upx;
+	padding: 0;
+}
+
+button.cuIcon.lg {
+	width: 80upx;
+	height: 80upx;
+}
+
+.cu-btn.shadow-blur::before {
+	top: 4upx;
+	left: 4upx;
+	filter: blur(6upx);
+	opacity: 0.6;
+}
+
+.cu-btn.button-hover {
+	transform: translate(1upx, 1upx);
+}
+
+.block {
+	display: block;
+}
+
+.cu-btn.block {
+	display: flex;
+}
+
+.cu-btn[disabled] {
+	opacity: 0.6;
+	color: #ffffff;
+}
+
+/* ==================
+          徽章
+ ==================== */
+
+.cu-tag {
+	font-size: 24upx;
+	vertical-align: middle;
+	position: relative;
+	display: inline-flex;
+	align-items: center;
+	justify-content: center;
+	box-sizing: border-box;
+	padding: 0upx 16upx;
+	height: 48upx;
+	font-family: Helvetica Neue, Helvetica, sans-serif;
+	white-space: nowrap;
+}
+
+.cu-tag:not([class*="bg"]):not([class*="line"]) {
+	background-color: #f1f1f1;
+}
+
+.cu-tag[class*="line-"]::after {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border: 1upx solid currentColor;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	box-sizing: border-box;
+	border-radius: inherit;
+	z-index: 1;
+	pointer-events: none;
+}
+
+.cu-tag.radius[class*="line"]::after {
+	border-radius: 12upx;
+}
+
+.cu-tag.round[class*="line"]::after {
+	border-radius: 1000upx;
+}
+
+.cu-tag[class*="line-"]::after {
+	border-radius: 0;
+}
+
+.cu-tag+.cu-tag {
+	margin-left: 10upx;
+}
+
+.cu-tag.sm {
+	font-size: 20upx;
+	padding: 0upx 12upx;
+	height: 32upx;
+}
+
+.cu-capsule {
+	display: inline-flex;
+	vertical-align: middle;
+}
+
+.cu-capsule+.cu-capsule {
+	margin-left: 10upx;
+}
+
+.cu-capsule .cu-tag {
+	margin: 0;
+}
+
+.cu-capsule .cu-tag[class*="line-"]:last-child::after {
+	border-left: 0upx solid transparent;
+}
+
+.cu-capsule .cu-tag[class*="line-"]:first-child::after {
+	border-right: 0upx solid transparent;
+}
+
+.cu-capsule.radius .cu-tag:first-child {
+	border-top-left-radius: 6upx;
+	border-bottom-left-radius: 6upx;
+}
+
+.cu-capsule.radius .cu-tag:last-child::after,
+.cu-capsule.radius .cu-tag[class*="line-"] {
+	border-top-right-radius: 12upx;
+	border-bottom-right-radius: 12upx;
+}
+
+.cu-capsule.round .cu-tag:first-child {
+	border-top-left-radius: 200upx;
+	border-bottom-left-radius: 200upx;
+	text-indent: 4upx;
+}
+
+.cu-capsule.round .cu-tag:last-child::after,
+.cu-capsule.round .cu-tag:last-child {
+	border-top-right-radius: 200upx;
+	border-bottom-right-radius: 200upx;
+	text-indent: -4upx;
+}
+
+.cu-tag.badge {
+	border-radius: 200upx;
+	position: absolute;
+	top: -10upx;
+	right: -10upx;
+	font-size: 20upx;
+	padding: 0upx 10upx;
+	height: 28upx;
+	color: #ffffff;
+}
+
+.cu-tag.badge:not([class*="bg-"]) {
+	background-color: #dd514c;
+}
+
+.cu-tag.badge-bottom {
+	border-radius: 200upx;
+	position: absolute;
+	bottom: 0upx;
+	right: -10upx;
+	font-size: 20upx;
+	padding: 0upx 10upx;
+	height: 28upx;
+	color: #ffffff;
+}
+
+.cu-tag.badge-bottom:not([class*="bg-"]) {
+	background-color: rgba(0,0,0,0);
+}
+
+.cu-tag:empty:not([class*="cuIcon-"]) {
+	padding: 0upx;
+	width: 16upx;
+	height: 16upx;
+	top: -4upx;
+	right: -4upx;
+}
+
+.cu-tag[class*="cuIcon-"] {
+	width: 32upx;
+	height: 32upx;
+	top: -4upx;
+	right: -4upx;
+}
+
+/* ==================
+          头像
+ ==================== */
+
+.cu-avatar {
+	font-variant: small-caps;
+	margin: 0;
+	padding: 0;
+	display: inline-flex;
+	text-align: center;
+	justify-content: center;
+	align-items: center;
+	background-color: #ccc;
+	color: #ffffff;
+	white-space: nowrap;
+	position: relative;
+	width: 64upx;
+	height: 64upx;
+	background-size: cover;
+	background-position: center;
+	vertical-align: middle;
+	font-size: 1.5em;
+}
+
+.cu-avatar.sm {
+	width: 48upx;
+	height: 48upx;
+	font-size: 1em;
+}
+
+.cu-avatar.lg {
+	width: 96upx;
+	height: 96upx;
+	font-size: 2em;
+}
+
+.cu-avatar.xl {
+	width: 128upx;
+	height: 128upx;
+	font-size: 2.5em;
+}
+
+.cu-avatar .avatar-text {
+	font-size: 0.4em;
+}
+
+.cu-avatar-group {
+	direction: rtl;
+	unicode-bidi: bidi-override;
+	padding: 0 10upx 0 40upx;
+	display: inline-block;
+}
+
+.cu-avatar-group .cu-avatar {
+	margin-left: -30upx;
+	border: 4upx solid #f1f1f1;
+	vertical-align: middle;
+}
+
+.cu-avatar-group .cu-avatar.sm {
+	margin-left: -20upx;
+	border: 1upx solid #f1f1f1;
+}
+
+/* ==================
+         进度条
+ ==================== */
+
+.cu-progress {
+	overflow: hidden;
+	height: 28upx;
+	background-color: #ebeef5;
+	display: inline-flex;
+	align-items: center;
+	width: 100%;
+}
+
+.cu-progress+view,
+.cu-progress+text {
+	line-height: 1;
+}
+
+.cu-progress.xs {
+	height: 10upx;
+}
+
+.cu-progress.sm {
+	height: 20upx;
+}
+
+.cu-progress view {
+	width: 0;
+	height: 100%;
+	align-items: center;
+	display: flex;
+	justify-items: flex-end;
+	justify-content: space-around;
+	font-size: 20upx;
+	color: #ffffff;
+	transition: width 0.6s ease;
+}
+
+.cu-progress text {
+	align-items: center;
+	display: flex;
+	font-size: 20upx;
+	color: #333333;
+	text-indent: 10upx;
+}
+
+.cu-progress.text-progress {
+	padding-right: 60upx;
+}
+
+.cu-progress.striped view {
+	background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
+	background-size: 72upx 72upx;
+}
+
+.cu-progress.active view {
+	animation: progress-stripes 2s linear infinite;
+}
+
+@keyframes progress-stripes {
+	from {
+		background-position: 72upx 0;
+	}
+
+	to {
+		background-position: 0 0;
+	}
+}
+
+/* ==================
+          加载
+ ==================== */
+
+.cu-load {
+	display: block;
+	line-height: 3em;
+	text-align: center;
+}
+
+.cu-load::before {
+	font-family: "cuIcon";
+	display: inline-block;
+	margin-right: 6upx;
+}
+
+.cu-load.loading::before {
+	content: "\e67a";
+	animation: cuIcon-spin 2s infinite linear;
+}
+
+.cu-load.loading::after {
+	content: "加载中...";
+}
+
+.cu-load.over::before {
+	content: "\e64a";
+}
+
+.cu-load.over::after {
+	content: "没有更多了";
+}
+
+.cu-load.erro::before {
+	content: "\e658";
+}
+
+.cu-load.erro::after {
+	content: "加载失败";
+}
+
+.cu-load.load-cuIcon::before {
+	font-size: 32upx;
+}
+
+.cu-load.load-cuIcon::after {
+	display: none;
+}
+
+.cu-load.load-cuIcon.over {
+	display: none;
+}
+
+.cu-load.load-modal {
+	position: fixed;
+	top: 0;
+	right: 0;
+	bottom: 140upx;
+	left: 0;
+	margin: auto;
+	width: 260upx;
+	height: 260upx;
+	background-color: #ffffff;
+	border-radius: 10upx;
+	box-shadow: 0 0 0upx 2000upx rgba(0, 0, 0, 0.5);
+	display: flex;
+	align-items: center;
+	flex-direction: column;
+	justify-content: center;
+	font-size: 28upx;
+	z-index: 9999;
+	line-height: 2.4em;
+}
+
+.cu-load.load-modal [class*="cuIcon-"] {
+	font-size: 60upx;
+}
+
+.cu-load.load-modal image {
+	width: 70upx;
+	height: 70upx;
+}
+
+.cu-load.load-modal::after {
+	content: "";
+	position: absolute;
+	background-color: #ffffff;
+	border-radius: 50%;
+	width: 200upx;
+	height: 200upx;
+	font-size: 10px;
+	border-top: 6upx solid rgba(0, 0, 0, 0.05);
+	border-right: 6upx solid rgba(0, 0, 0, 0.05);
+	border-bottom: 6upx solid rgba(0, 0, 0, 0.05);
+	border-left: 6upx solid #f37b1d;
+	animation: cuIcon-spin 1s infinite linear;
+	z-index: -1;
+}
+
+.load-progress {
+	pointer-events: none;
+	top: 0;
+	position: fixed;
+	width: 100%;
+	left: 0;
+	z-index: 2000;
+}
+
+.load-progress.hide {
+	display: none;
+}
+
+.load-progress .load-progress-bar {
+	position: relative;
+	width: 100%;
+	height: 4upx;
+	overflow: hidden;
+	transition: all 200ms ease 0s;
+}
+
+.load-progress .load-progress-spinner {
+	position: absolute;
+	top: 10upx;
+	right: 10upx;
+	z-index: 2000;
+	display: block;
+}
+
+.load-progress .load-progress-spinner::after {
+	content: "";
+	display: block;
+	width: 24upx;
+	height: 24upx;
+	-webkit-box-sizing: border-box;
+	box-sizing: border-box;
+	border: solid 4upx transparent;
+	border-top-color: inherit;
+	border-left-color: inherit;
+	border-radius: 50%;
+	-webkit-animation: load-progress-spinner 0.4s linear infinite;
+	animation: load-progress-spinner 0.4s linear infinite;
+}
+
+@-webkit-keyframes load-progress-spinner {
+	0% {
+		-webkit-transform: rotate(0);
+		transform: rotate(0);
+	}
+
+	100% {
+		-webkit-transform: rotate(360deg);
+		transform: rotate(360deg);
+	}
+}
+
+@keyframes load-progress-spinner {
+	0% {
+		-webkit-transform: rotate(0);
+		transform: rotate(0);
+	}
+
+	100% {
+		-webkit-transform: rotate(360deg);
+		transform: rotate(360deg);
+	}
+}
+
+/* ==================
+          列表
+ ==================== */
+.grayscale {
+	filter: grayscale(1);
+}
+
+.cu-list+.cu-list {
+	margin-top: 30upx
+}
+
+.cu-list>.cu-item {
+	transition: all .6s ease-in-out 0s;
+	transform: translateX(0upx)
+}
+
+.cu-list>.cu-item.move-cur {
+	transform: translateX(-260upx)
+}
+
+.cu-list>.cu-item .move {
+	position: absolute;
+	right: 0;
+	display: flex;
+	width: 260upx;
+	height: 100%;
+	transform: translateX(100%)
+}
+
+.cu-list>.cu-item .move view {
+	display: flex;
+	flex: 1;
+	justify-content: center;
+	align-items: center
+}
+
+.cu-list.menu-avatar {
+	overflow: hidden;
+}
+
+.cu-list.menu-avatar>.cu-item {
+	position: relative;
+	display: flex;
+	padding-right: 10upx;
+	height: 140upx;
+	background-color: #ffffff;
+	justify-content: flex-end;
+	align-items: center
+}
+
+.cu-list.menu-avatar>.cu-item>.cu-avatar {
+	position: absolute;
+	left: 30upx
+}
+
+.cu-list.menu-avatar>.cu-item .flex .text-cut {
+	max-width: 510upx
+}
+
+.cu-list.menu-avatar>.cu-item .content {
+	position: absolute;
+	left: 146upx;
+	width: calc(100% - 96upx - 60upx - 120upx - 20upx);
+	line-height: 1.6em;
+}
+
+.cu-list.menu-avatar>.cu-item .content.flex-sub {
+	width: calc(100% - 96upx - 60upx - 20upx);
+}
+
+.cu-list.menu-avatar>.cu-item .content>view:first-child {
+	font-size: 30upx;
+	display: flex;
+	align-items: center
+}
+
+.cu-list.menu-avatar>.cu-item .content .cu-tag.sm {
+	display: inline-block;
+	margin-left: 10upx;
+	height: 28upx;
+	font-size: 16upx;
+	line-height: 32upx
+}
+
+.cu-list.menu-avatar>.cu-item .action {
+	width: 100upx;
+	text-align: center
+}
+
+.cu-list.menu-avatar>.cu-item .action view+view {
+	margin-top: 10upx
+}
+
+.cu-list.menu-avatar.comment>.cu-item .content {
+	position: relative;
+	left: 0;
+	width: auto;
+	flex: 1;
+}
+
+.cu-list.menu-avatar.comment>.cu-item {
+	padding: 30upx 30upx 30upx 120upx;
+	height: auto
+}
+
+.cu-list.menu-avatar.comment .cu-avatar {
+	align-self: flex-start
+}
+
+.cu-list.menu>.cu-item {
+	position: relative;
+	display: flex;
+	padding: 0 30upx;
+	min-height: 100upx;
+	background-color: #ffffff;
+	justify-content: space-between;
+	align-items: center
+}
+
+.cu-list.menu>.cu-item:last-child:after {
+	border: none
+}
+
+.cu-list.menu-avatar>.cu-item:after,
+.cu-list.menu>.cu-item:after {
+	position: absolute;
+	top: 0;
+	left: 0;
+	box-sizing: border-box;
+	width: 200%;
+	height: 200%;
+	border-bottom: 1upx solid #ddd;
+	border-radius: inherit;
+	content: " ";
+	transform: scale(.5);
+	transform-origin: 0 0;
+	pointer-events: none
+}
+
+.cu-list.menu>.cu-item.grayscale {
+	background-color: #f5f5f5
+}
+
+.cu-list.menu>.cu-item.cur {
+	background-color: #fcf7e9
+}
+
+.cu-list.menu>.cu-item.arrow {
+	padding-right: 90upx
+}
+
+.cu-list.menu>.cu-item.arrow:before {
+	position: absolute;
+	top: 0;
+	right: 30upx;
+	bottom: 0;
+	display: block;
+	margin: auto;
+	width: 30upx;
+	height: 30upx;
+	color: #8799a3;
+	content: "\e6a3";
+	text-align: center;
+	font-size: 34upx;
+	font-family: cuIcon;
+	line-height: 30upx
+}
+
+/* slam todo */
+.cu-list.menu>.cu-item.myarrow {
+	padding-right: 90upx
+}
+
+.cu-list.menu>.cu-item.myarrow:before {
+	position: absolute;
+	top: 0;
+	right: 30upx;
+	bottom: 0;
+	display: block;
+	margin: auto;
+	width: 30upx;
+	height: 30upx;
+	color: #cccccc;
+	content: "\e6a3";
+	text-align: center;
+	font-size: 26upx;
+	font-family: cuIcon;
+	line-height: 30upx
+}
+
+.cu-list.menu>.cu-item button.content {
+	padding: 0;
+	background-color: transparent;
+	justify-content: flex-start
+}
+
+.cu-list.menu>.cu-item button.content:after {
+	display: none
+}
+
+.cu-list.menu>.cu-item .cu-avatar-group .cu-avatar {
+	border-color: #ffffff
+}
+
+.cu-list.menu>.cu-item .content>view:first-child {
+	display: flex;
+	align-items: center
+}
+
+.cu-list.menu>.cu-item .content>text[class*=cuIcon] {
+	display: inline-block;
+	margin-right: 10upx;
+	width: 1.6em;
+	text-align: center
+}
+
+.cu-list.menu>.cu-item .content>image {
+	display: inline-block;
+	margin-right: 10upx;
+	width: 1.6em;
+	height: 1.6em;
+	vertical-align: middle
+}
+
+.cu-list.menu>.cu-item .content {
+	font-size: 30upx;
+	line-height: 1.6em;
+	flex: 1
+}
+
+.cu-list.menu>.cu-item .content .cu-tag.sm {
+	display: inline-block;
+	margin-left: 10upx;
+	height: 28upx;
+	font-size: 16upx;
+	line-height: 32upx
+}
+
+.cu-list.menu>.cu-item .action .cu-tag:empty {
+	right: 10upx
+}
+
+.cu-list.menu {
+	display: block;
+	overflow: hidden
+}
+
+.cu-list.menu.sm-border>.cu-item:after {
+	left: 30upx;
+	width: calc(200% - 120upx)
+}
+
+.cu-list.grid>.cu-item {
+	position: relative;
+	display: flex;
+	padding: 20upx 0 30upx;
+	transition-duration: 0s;
+	flex-direction: column
+}
+
+.cu-list.grid>.cu-item:after {
+	position: absolute;
+	top: 0;
+	left: 0;
+	box-sizing: border-box;
+	width: 200%;
+	height: 200%;
+	border-right: 1px solid rgba(0, 0, 0, .1);
+	border-bottom: 1px solid rgba(0, 0, 0, .1);
+	border-radius: inherit;
+	content: " ";
+	transform: scale(.5);
+	transform-origin: 0 0;
+	pointer-events: none
+}
+
+.cu-list.grid>.cu-item text {
+	display: block;
+	margin-top: 10upx;
+	color: #888;
+	font-size: 26upx;
+	line-height: 40upx
+}
+
+.cu-list.grid>.cu-item [class*=cuIcon] {
+	position: relative;
+	display: block;
+	margin-top: 20upx;
+	width: 100%;
+	font-size: 48upx
+}
+
+.cu-list.grid>.cu-item .cu-tag {
+	right: auto;
+	left: 50%;
+	margin-left: 20upx
+}
+
+.cu-list.grid {
+	background-color: #ffffff;
+	text-align: center
+}
+
+.cu-list.grid.no-border>.cu-item {
+	padding-top: 10upx;
+	padding-bottom: 20upx
+}
+
+.cu-list.grid.no-border>.cu-item:after {
+	border: none
+}
+
+.cu-list.grid.no-border {
+	padding: 20upx 10upx
+}
+
+.cu-list.grid.col-3>.cu-item:nth-child(3n):after,
+.cu-list.grid.col-4>.cu-item:nth-child(4n):after,
+.cu-list.grid.col-5>.cu-item:nth-child(5n):after {
+	border-right-width: 0
+}
+
+.cu-list.card-menu {
+	overflow: hidden;
+	margin-right: 30upx;
+	margin-left: 30upx;
+	border-radius: 20upx
+}
+
+
+/* ==================
+          操作条
+ ==================== */
+
+.cu-bar {
+	display: flex;
+	position: relative;
+	align-items: center;
+	min-height: 100upx;
+	justify-content: space-between;
+}
+
+.cu-bar .action {
+	display: flex;
+	align-items: center;
+	height: 100%;
+	justify-content: center;
+	max-width: 100%;
+}
+
+.cu-bar .action.border-title {
+	position: relative;
+	top: -10upx;
+}
+
+.cu-bar .action.border-title text[class*="bg-"]:last-child {
+	position: absolute;
+	bottom: -0.5rem;
+	min-width: 2rem;
+	height: 6upx;
+	left: 0;
+}
+
+.cu-bar .action.sub-title {
+	position: relative;
+	top: -0.2rem;
+}
+
+.cu-bar .action.sub-title text {
+	position: relative;
+	z-index: 1;
+}
+
+.cu-bar .action.sub-title text[class*="bg-"]:last-child {
+	position: absolute;
+	display: inline-block;
+	bottom: -0.2rem;
+	border-radius: 6upx;
+	width: 100%;
+	height: 0.6rem;
+	left: 0.6rem;
+	opacity: 0.3;
+	z-index: 0;
+}
+
+.cu-bar .action.sub-title text[class*="text-"]:last-child {
+	position: absolute;
+	display: inline-block;
+	bottom: -0.7rem;
+	left: 0.5rem;
+	opacity: 0.2;
+	z-index: 0;
+	text-align: right;
+	font-weight: 900;
+	font-size: 36upx;
+}
+
+.cu-bar.justify-center .action.border-title text:last-child,
+.cu-bar.justify-center .action.sub-title text:last-child {
+	left: 0;
+	right: 0;
+	margin: auto;
+	text-align: center;
+}
+
+.cu-bar .action:first-child {
+	margin-left: 30upx;
+	font-size: 30upx;
+}
+
+.cu-bar .action text.text-cut {
+	text-align: left;
+	width: 100%;
+}
+
+.cu-bar .cu-avatar:first-child {
+	margin-left: 20upx;
+}
+
+.cu-bar .action:first-child>text[class*="cuIcon-"] {
+	margin-left: -0.3em;
+	margin-right: 0.3em;
+}
+
+.cu-bar .action:last-child {
+	margin-right: 30upx;
+}
+
+.cu-bar .action>text[class*="cuIcon-"],
+.cu-bar .action>view[class*="cuIcon-"] {
+	font-size: 36upx;
+}
+
+.cu-bar .action>text[class*="cuIcon-"]+text[class*="cuIcon-"] {
+	margin-left: 0.5em;
+}
+
+.cu-bar .content {
+	position: absolute;
+	text-align: center;
+	width: calc(100% - 340upx);
+	left: 0;
+	right: 0;
+	bottom: 0;
+	top: 0;
+	margin: auto;
+	height: 60upx;
+	font-size: 32upx;
+	line-height: 60upx;
+	cursor: none;
+	pointer-events: none;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+}
+
+.cu-bar.ios .content {
+	bottom: 7px;
+	height: 30px;
+	font-size: 32upx;
+	line-height: 30px;
+}
+
+.cu-bar.btn-group {
+	justify-content: space-around;
+}
+
+.cu-bar.btn-group button {
+	padding: 20upx 32upx;
+}
+
+.cu-bar.btn-group button {
+	flex: 1;
+	margin: 0 20upx;
+	max-width: 50%;
+}
+
+.cu-bar .search-form {
+	background-color: #f5f5f5;
+	line-height: 64upx;
+	height: 64upx;
+	font-size: 24upx;
+	color: #333333;
+	flex: 1;
+	display: flex;
+	align-items: center;
+	margin: 0 30upx;
+}
+
+.cu-bar .search-form+.action {
+	margin-right: 30upx;
+}
+
+.cu-bar .search-form input {
+	flex: 1;
+	padding-right: 30upx;
+	height: 64upx;
+	line-height: 64upx;
+	font-size: 26upx;
+	background-color: transparent;
+}
+
+.cu-bar .search-form [class*="cuIcon-"] {
+	margin: 0 0.5em 0 0.8em;
+}
+
+.cu-bar .search-form [class*="cuIcon-"]::before {
+	top: 0upx;
+}
+
+.cu-bar.fixed,
+.nav.fixed {
+	position: fixed;
+	width: 100%;
+	top: 0;
+	z-index: 1024;
+	box-shadow: 0 1upx 6upx rgba(0, 0, 0, 0.1);
+}
+
+.cu-bar.foot {
+	position: fixed;
+	width: 100%;
+	bottom: 0;
+	z-index: 1024;
+	box-shadow: 0 -1upx 6upx rgba(0, 0, 0, 0.1);
+}
+
+.cu-bar.tabbar {
+	padding: 0;
+	height: calc(100upx + env(safe-area-inset-bottom) / 2);
+	padding-bottom: calc(env(safe-area-inset-bottom) / 2);
+}
+
+.cu-tabbar-height {
+	min-height: 100upx;
+	height: calc(100upx + env(safe-area-inset-bottom) / 2);
+}
+
+.cu-bar.tabbar.shadow {
+	box-shadow: 0 -1upx 6upx rgba(0, 0, 0, 0.1);
+}
+
+.cu-bar.tabbar .action {
+	font-size: 22upx;
+	position: relative;
+	flex: 1;
+	text-align: center;
+	padding: 0;
+	display: block;
+	height: auto;
+	line-height: 1;
+	margin: 0;
+	background-color: inherit;
+	overflow: initial;
+}
+
+.cu-bar.tabbar.shop .action {
+	width: 140upx;
+	flex: initial;
+}
+
+.cu-bar.tabbar .action.add-action {
+	position: relative;
+	z-index: 2;
+	padding-top: 50upx;
+}
+
+.cu-bar.tabbar .action.add-action [class*="cuIcon-"] {
+	position: absolute;
+	width: 70upx;
+	z-index: 2;
+	height: 70upx;
+	border-radius: 50%;
+	line-height: 70upx;
+	font-size: 50upx;
+	top: -35upx;
+	left: 0;
+	right: 0;
+	margin: auto;
+	padding: 0;
+}
+
+.cu-bar.tabbar .action.add-action::after {
+	content: "";
+	position: absolute;
+	width: 100upx;
+	height: 100upx;
+	top: -50upx;
+	left: 0;
+	right: 0;
+	margin: auto;
+	box-shadow: 0 -3upx 8upx rgba(0, 0, 0, 0.08);
+	border-radius: 50upx;
+	background-color: inherit;
+	z-index: 0;
+}
+
+.cu-bar.tabbar .action.add-action::before {
+	content: "";
+	position: absolute;
+	width: 100upx;
+	height: 30upx;
+	bottom: 30upx;
+	left: 0;
+	right: 0;
+	margin: auto;
+	background-color: inherit;
+	z-index: 1;
+}
+
+.cu-bar.tabbar .btn-group {
+	flex: 1;
+	display: flex;
+	justify-content: space-around;
+	align-items: center;
+	padding: 0 10upx;
+}
+
+.cu-bar.tabbar button.action::after {
+	border: 0;
+}
+
+.cu-bar.tabbar .action [class*="cuIcon-"] {
+	width: 100upx;
+	position: relative;
+	display: block;
+	height: auto;
+	margin: 0 auto 10upx;
+	text-align: center;
+	font-size: 40upx;
+}
+
+.cu-bar.tabbar .action .cuIcon-cu-image {
+	margin: 0 auto;
+}
+
+.cu-bar.tabbar .action .cuIcon-cu-image image {
+	width: 50upx;
+	height: 50upx;
+	display: inline-block;
+}
+
+.cu-bar.tabbar .submit {
+	align-items: center;
+	display: flex;
+	justify-content: center;
+	text-align: center;
+	position: relative;
+	flex: 2;
+	align-self: stretch;
+}
+
+.cu-bar.tabbar .submit:last-child {
+	flex: 2.6;
+}
+
+.cu-bar.tabbar .submit+.submit {
+	flex: 2;
+}
+
+.cu-bar.tabbar.border .action::before {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	border-right: 1upx solid rgba(0, 0, 0, 0.1);
+	z-index: 3;
+}
+
+.cu-bar.tabbar.border .action:last-child:before {
+	display: none;
+}
+
+.cu-bar.input {
+	padding-right: 20upx;
+	background-color: #ffffff;
+}
+
+.cu-bar.input input {
+	overflow: initial;
+	line-height: 64upx;
+	height: 64upx;
+	min-height: 64upx;
+	flex: 1;
+	font-size: 30upx;
+	margin: 0 20upx;
+}
+
+.cu-bar.input .action {
+	margin-left: 20upx;
+}
+
+.cu-bar.input .action [class*="cuIcon-"] {
+	font-size: 48upx;
+}
+
+.cu-bar.input input+.action {
+	margin-right: 20upx;
+	margin-left: 0upx;
+}
+
+.cu-bar.input .action:first-child [class*="cuIcon-"] {
+	margin-left: 0upx;
+}
+
+.cu-custom {
+	display: block;
+	position: relative;
+}
+
+.cu-custom .cu-bar .content {
+	width: calc(100% - 440upx);
+}
+
+/* #ifdef MP-ALIPAY */
+.cu-custom .cu-bar .action .cuIcon-back {
+	opacity: 0;
+}
+
+/* #endif */
+
+.cu-custom .cu-bar .content image {
+	height: 60upx;
+	width: 240upx;
+}
+
+.cu-custom .cu-bar {
+	min-height: 0px;
+	/* #ifdef MP-WEIXIN */
+	padding-right: 220upx;
+	/* #endif */
+	/* #ifdef MP-ALIPAY */
+	padding-right: 150upx;
+	/* #endif */
+	box-shadow: 0upx 0upx 0upx;
+	z-index: 9999;
+}
+
+.cu-custom .cu-bar .border-custom {
+	position: relative;
+	background: rgba(0, 0, 0, 0.15);
+	border-radius: 1000upx;
+	height: 30px;
+}
+
+.cu-custom .cu-bar .border-custom::after {
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border-radius: inherit;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+	border: 1upx solid #ffffff;
+	opacity: 0.5;
+}
+
+.cu-custom .cu-bar .border-custom::before {
+	content: " ";
+	width: 1upx;
+	height: 110%;
+	position: absolute;
+	top: 22.5%;
+	left: 0;
+	right: 0;
+	margin: auto;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+	opacity: 0.6;
+	background-color: #ffffff;
+}
+
+.cu-custom .cu-bar .border-custom text {
+	display: block;
+	flex: 1;
+	margin: auto !important;
+	text-align: center;
+	font-size: 34upx;
+}
+
+/* ==================
+         导航栏
+ ==================== */
+
+.nav {
+	white-space: nowrap;
+}
+
+::-webkit-scrollbar {
+	display: none;
+}
+
+.nav .cu-item {
+	height: 90upx;
+	display: inline-block;
+	line-height: 90upx;
+	margin: 0 10upx;
+	padding: 0 20upx;
+}
+
+.nav .cu-item.cur {
+	border-bottom: 4upx solid;
+}
+
+/* ==================
+         时间轴
+ ==================== */
+
+.cu-timeline {
+	display: block;
+	background-color: #ffffff;
+}
+
+.cu-timeline .cu-time {
+	width: 120upx;
+	text-align: center;
+	padding: 20upx 0;
+	font-size: 26upx;
+	color: #888;
+	display: block;
+}
+
+.cu-timeline>.cu-item {
+	padding: 30upx 30upx 30upx 120upx;
+	position: relative;
+	display: block;
+	z-index: 0;
+}
+
+.cu-timeline>.cu-item:not([class*="text-"]) {
+	color: #ccc;
+}
+
+.cu-timeline>.cu-item::after {
+	content: "";
+	display: block;
+	position: absolute;
+	width: 1upx;
+	background-color: #ddd;
+	left: 60upx;
+	height: 100%;
+	top: 0;
+	z-index: 8;
+}
+
+.cu-timeline>.cu-item::before {
+	font-family: "cuIcon";
+	display: block;
+	position: absolute;
+	top: 36upx;
+	z-index: 9;
+	background-color: #ffffff;
+	width: 50upx;
+	height: 50upx;
+	text-align: center;
+	border: none;
+	line-height: 50upx;
+	left: 36upx;
+}
+
+.cu-timeline>.cu-item:not([class*="cuIcon-"])::before {
+	content: "\e763";
+}
+
+.cu-timeline>.cu-item[class*="cuIcon-"]::before {
+	background-color: #ffffff;
+	width: 50upx;
+	height: 50upx;
+	text-align: center;
+	border: none;
+	line-height: 50upx;
+	left: 36upx;
+}
+
+.cu-timeline>.cu-item>.content {
+	padding: 30upx;
+	border-radius: 6upx;
+	display: block;
+	line-height: 1.6;
+}
+
+.cu-timeline>.cu-item>.content:not([class*="bg-"]) {
+	background-color: #f1f1f1;
+	color: #333333;
+}
+
+.cu-timeline>.cu-item>.content+.content {
+	margin-top: 20upx;
+}
+
+/* ==================
+        slam custom 时间轴
+ ==================== */
+
+.slam-cu-timeline {
+	display: block;
+	background-color: #ffffff;
+}
+
+.slam-cu-timeline .slam-cu-time {
+	width: 120upx;
+	text-align: center;
+	padding: 20upx 0;
+	font-size: 26upx;
+	color: #888;
+	display: block;
+}
+
+.slam-cu-timeline>.slam-cu-item {
+	padding: 30upx 30upx 30upx 120upx;
+	position: relative;
+	display: block;
+	z-index: 0;
+}
+
+.slam-cu-timeline>.slam-cu-item:not([class*="text-"]) {
+	color: #ccc;
+}
+
+.slam-cu-timeline>.slam-cu-item::after {
+	content: "";
+	display: block;
+	position: absolute;
+	width: 1upx;
+	border: 1upx dashed #9797FF;
+	left: 73upx;
+	height: 100%;
+	top: 0;
+	z-index: 8;
+}
+
+.slam-cu-timeline>.slam-cu-item::before {
+	font-family: "cuIcon";
+	display: block;
+	position: absolute;
+	top: 0upx;
+	z-index: 9;
+	/* background-color: #ffffff; */
+	width: 76upx;
+	height: 76upx;
+	text-align: center;
+	border: none;
+	line-height: 76upx;
+	left: 36upx;
+	background-color: RGBA(235, 235, 255, 1);
+
+	font-size: 20px;
+
+	border-radius: 25px;
+}
+
+.slam-cu-timeline>.slam-cu-item:not([class*="cuIcon-"])::before {
+	content: "\e763";
+}
+
+.slam-cu-timeline>.slam-cu-item[class*="cuIcon-"]::before {
+	/* background-color: #ffffff; */
+	width: 76upx;
+	height: 76upx;
+	text-align: center;
+	border: none;
+	line-height: 76upx;
+	left: 36upx;
+}
+
+.slam-cu-timeline>.slam-cu-item>.content {
+	padding: 30upx;
+	border-radius: 6upx;
+	display: block;
+	line-height: 1.6;
+}
+
+.slam-cu-timeline>.slam-cu-item>.content:not([class*="bg-"]) {
+	background-color: #f1f1f1;
+	color: #333333;
+}
+
+.slam-cu-timeline>.slam-cu-item>.content+.content {
+	margin-top: 20upx;
+}
+
+/* ==================
+         聊天
+ ==================== */
+
+.cu-chat {
+	display: flex;
+	flex-direction: column;
+}
+
+.cu-chat .cu-item {
+	display: flex;
+	padding: 30upx 30upx 70upx;
+	position: relative;
+}
+
+.cu-chat .cu-item>.cu-avatar {
+	width: 80upx;
+	height: 80upx;
+}
+
+.cu-chat .cu-item>.main {
+	max-width: calc(100% - 260upx);
+	margin: 0 40upx;
+	display: flex;
+	align-items: center;
+}
+
+.cu-chat .cu-item>image {
+	height: 320upx;
+}
+
+.cu-chat .cu-item>.main .content {
+	padding: 20upx;
+	border-radius: 6upx;
+	display: inline-flex;
+	max-width: 100%;
+	align-items: center;
+	font-size: 30upx;
+	position: relative;
+	min-height: 80upx;
+	line-height: 40upx;
+	text-align: left;
+}
+
+.cu-chat .cu-item>.main .content:not([class*="bg-"]) {
+	background-color: #ffffff;
+	color: #333333;
+}
+
+.cu-chat .cu-item .date {
+	position: absolute;
+	font-size: 24upx;
+	color: #8799a3;
+	width: calc(100% - 320upx);
+	bottom: 20upx;
+	left: 160upx;
+}
+
+.cu-chat .cu-item .action {
+	padding: 0 30upx;
+	display: flex;
+	align-items: center;
+}
+
+.cu-chat .cu-item>.main .content::after {
+	content: "";
+	top: 27upx;
+	transform: rotate(45deg);
+	position: absolute;
+	z-index: 100;
+	display: inline-block;
+	overflow: hidden;
+	width: 24upx;
+	height: 24upx;
+	left: -12upx;
+	right: initial;
+	background-color: inherit;
+}
+
+.cu-chat .cu-item.self>.main .content::after {
+	left: auto;
+	right: -12upx;
+}
+
+.cu-chat .cu-item>.main .content::before {
+	content: "";
+	top: 30upx;
+	transform: rotate(45deg);
+	position: absolute;
+	z-index: -1;
+	display: inline-block;
+	overflow: hidden;
+	width: 24upx;
+	height: 24upx;
+	left: -12upx;
+	right: initial;
+	background-color: inherit;
+	filter: blur(5upx);
+	opacity: 0.3;
+}
+
+.cu-chat .cu-item>.main .content:not([class*="bg-"])::before {
+	background-color: #333333;
+	opacity: 0.1;
+}
+
+.cu-chat .cu-item.self>.main .content::before {
+	left: auto;
+	right: -12upx;
+}
+
+.cu-chat .cu-item.self {
+	justify-content: flex-end;
+	text-align: right;
+}
+
+.cu-chat .cu-info {
+	display: inline-block;
+	margin: 20upx auto;
+	font-size: 24upx;
+	padding: 8upx 12upx;
+	background-color: rgba(0, 0, 0, 0.2);
+	border-radius: 6upx;
+	color: #ffffff;
+	max-width: 400upx;
+	line-height: 1.4;
+}
+
+/* ==================
+         卡片
+ ==================== */
+
+.cu-card {
+	display: block;
+	overflow: hidden;
+}
+
+.cu-card>.cu-item {
+	display: block;
+	background-color: #ffffff;
+	overflow: hidden;
+	border-radius: 10upx;
+	margin: 30upx;
+}
+
+.cu-card>.cu-item.shadow-blur {
+	overflow: initial;
+}
+
+.cu-card.no-card>.cu-item {
+	margin: 0upx;
+	border-radius: 0upx;
+}
+
+.cu-card .grid.grid-square {
+	margin-bottom: -20upx;
+}
+
+.cu-card.case .image {
+	position: relative;
+}
+
+.cu-card.case .image image {
+	width: 100%;
+}
+
+.cu-card.case .image .cu-tag {
+	position: absolute;
+	right: 0;
+	top: 0;
+}
+
+.cu-card.case .image .cu-bar {
+	position: absolute;
+	bottom: 0;
+	width: 100%;
+	background-color: transparent;
+	padding: 0upx 30upx;
+}
+
+.cu-card.case.no-card .image {
+	margin: 30upx 30upx 0;
+	overflow: hidden;
+	border-radius: 10upx;
+}
+
+.cu-card.dynamic {
+	display: block;
+}
+
+.cu-card.dynamic>.cu-item {
+	display: block;
+	background-color: #ffffff;
+	overflow: hidden;
+}
+
+.cu-card.dynamic>.cu-item>.text-content {
+	padding: 0 30upx 0;
+	max-height: 6.4em;
+	overflow: hidden;
+	font-size: 30upx;
+	margin-bottom: 20upx;
+}
+
+.cu-card.dynamic>.cu-item .square-img {
+	width: 100%;
+	height: 200upx;
+	border-radius: 6upx;
+}
+
+.cu-card.dynamic>.cu-item .only-img {
+	width: 100%;
+	height: 320upx;
+	border-radius: 6upx;
+}
+
+/* card.dynamic>.cu-item .comment {
+  padding: 20upx;
+  background-color: #f1f1f1;
+  margin: 0 30upx 30upx;
+  border-radius: 6upx;
+} */
+
+.cu-card.article {
+	display: block;
+}
+
+.cu-card.article>.cu-item {
+	padding-bottom: 30upx;
+}
+
+.cu-card.article>.cu-item .title {
+	font-size: 30upx;
+	font-weight: 900;
+	color: #333333;
+	line-height: 100upx;
+	padding: 0 30upx;
+}
+
+.cu-card.article>.cu-item .content {
+	display: flex;
+	padding: 0 30upx;
+}
+
+.cu-card.article>.cu-item .content>image {
+	width: 240upx;
+	height: 6.4em;
+	margin-right: 20upx;
+	border-radius: 6upx;
+}
+
+.cu-card.article>.cu-item .content .desc {
+	flex: 1;
+	display: flex;
+	flex-direction: column;
+	justify-content: space-between;
+}
+
+.cu-card.article>.cu-item .content .text-content {
+	font-size: 28upx;
+	color: #888;
+	height: 4.8em;
+	overflow: hidden;
+}
+
+/* ==================
+         表单
+ ==================== */
+
+.cu-form-group {
+	background-color: #ffffff;
+	padding: 1upx 30upx;
+	display: flex;
+	align-items: center;
+	min-height: 100upx;
+	justify-content: space-between;
+}
+
+.cu-form-group+.cu-form-group {
+	border-top: 1upx solid #eee;
+}
+
+.cu-form-group .title {
+	text-align: justify;
+	padding-right: 30upx;
+	font-size: 30upx;
+	position: relative;
+	height: 60upx;
+	line-height: 60upx;
+}
+
+.cu-form-group input {
+	flex: 1;
+	font-size: 30upx;
+	color: #555;
+	padding-right: 20upx;
+}
+
+.cu-form-group>text[class*="cuIcon-"] {
+	font-size: 36upx;
+	padding: 0;
+	box-sizing: border-box;
+}
+
+.cu-form-group textarea {
+	margin: 32upx 0 30upx;
+	height: 4.6em;
+	width: 100%;
+	line-height: 1.2em;
+	flex: 1;
+	font-size: 28upx;
+	padding: 0;
+}
+
+.cu-form-group.align-start .title {
+	height: 1em;
+	margin-top: 32upx;
+	line-height: 1em;
+}
+
+.cu-form-group picker {
+	flex: 1;
+	padding-right: 40upx;
+	overflow: hidden;
+	position: relative;
+}
+
+.cu-form-group picker .picker {
+	line-height: 100upx;
+	font-size: 28upx;
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+	width: 100%;
+	text-align: right;
+}
+
+.cu-form-group picker::after {
+	font-family: cuIcon;
+	display: block;
+	content: "\e6a3";
+	position: absolute;
+	font-size: 34upx;
+	color: #8799a3;
+	line-height: 100upx;
+	width: 60upx;
+	text-align: center;
+	top: 0;
+	bottom: 0;
+	right: -20upx;
+	margin: auto;
+}
+
+.cu-form-group textarea[disabled],
+.cu-form-group textarea[disabled] .placeholder {
+	color: transparent;
+}
+
+/* ==================
+         模态窗口
+ ==================== */
+
+.cu-modal {
+	position: fixed;
+	top: 0;
+	right: 0;
+	bottom: 0;
+	left: 0;
+	z-index: 1110;
+	opacity: 0;
+	outline: 0;
+	text-align: center;
+	-ms-transform: scale(1.185);
+	transform: scale(1.185);
+	backface-visibility: hidden;
+	perspective: 2000upx;
+	background: rgba(0, 0, 0, 0.6);
+	transition: all 0.3s ease-in-out 0s;
+	pointer-events: none;
+	width: 750rpx;
+}
+
+.cu-modal::before {
+	content: "\200B";
+	display: inline-block;
+	height: 100%;
+	vertical-align: middle;
+}
+
+.cu-modal.show {
+	opacity: 1;
+	transition-duration: 0.3s;
+	-ms-transform: scale(1);
+	transform: scale(1);
+	overflow-x: hidden;
+	overflow-y: auto;
+	pointer-events: auto;
+}
+
+.cu-dialog {
+	position: relative;
+	display: inline-block;
+	vertical-align: middle;
+	margin-left: auto;
+	margin-right: auto;
+	width: 680upx;
+	max-width: 100%;
+	background-color: #f6f3f9;
+	/* border-radius: 20px; */
+	overflow: hidden;
+	/* border: 1rpx solid #000000; */
+
+}
+
+.cu-modal.bottom-modal::before {
+	vertical-align: bottom;
+}
+
+.cu-modal.bottom-modal .cu-dialog {
+	width: 100%;
+	border-radius: 0;
+}
+
+.cu-modal.bottom-modal {
+	margin-bottom: -1000upx;
+}
+
+.cu-modal.bottom-modal.show {
+	margin-bottom: 0;
+}
+
+.cu-modal.drawer-modal {
+	transform: scale(1);
+	display: flex;
+}
+
+.cu-modal.drawer-modal .cu-dialog {
+	height: 100%;
+	min-width: 200upx;
+	border-radius: 0;
+	margin: initial;
+	transition-duration: 0.3s;
+}
+
+.cu-modal.drawer-modal.justify-start .cu-dialog {
+	transform: translateX(-100%);
+}
+
+.cu-modal.drawer-modal.justify-end .cu-dialog {
+	transform: translateX(100%);
+}
+
+.cu-modal.drawer-modal.show .cu-dialog {
+	transform: translateX(0%);
+}
+
+.cu-modal .cu-dialog>.cu-bar:first-child .action {
+	min-width: 100rpx;
+	margin-right: 0;
+	min-height: 100rpx;
+}
+
+/* ==================
+         轮播
+ ==================== */
+swiper .a-swiper-dot {
+	display: inline-block;
+	width: 16upx;
+	height: 16upx;
+	background: rgba(0, 0, 0, .3);
+	border-radius: 50%;
+	vertical-align: middle;
+}
+
+swiper[class*="-dot"] .wx-swiper-dots,
+swiper[class*="-dot"] .a-swiper-dots,
+swiper[class*="-dot"] .uni-swiper-dots {
+	display: flex;
+	align-items: center;
+	width: 100%;
+	justify-content: center;
+}
+
+swiper.square-dot .wx-swiper-dot,
+swiper.square-dot .a-swiper-dot,
+swiper.square-dot .uni-swiper-dot {
+	background-color: #ffffff;
+	opacity: 0.4;
+	width: 10upx;
+	height: 10upx;
+	border-radius: 20upx;
+	margin: 0 8upx !important;
+}
+
+swiper.square-dot .wx-swiper-dot.wx-swiper-dot-active,
+swiper.square-dot .a-swiper-dot.a-swiper-dot-active,
+swiper.square-dot .uni-swiper-dot.uni-swiper-dot-active {
+	opacity: 1;
+	width: 30upx;
+}
+
+swiper.round-dot .wx-swiper-dot,
+swiper.round-dot .a-swiper-dot,
+swiper.round-dot .uni-swiper-dot {
+	width: 10upx;
+	height: 10upx;
+	position: relative;
+	margin: 4upx 8upx !important;
+}
+
+swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active::after,
+swiper.round-dot .a-swiper-dot.a-swiper-dot-active::after,
+swiper.round-dot .uni-swiper-dot.uni-swiper-dot-active::after {
+	content: "";
+	position: absolute;
+	width: 10upx;
+	height: 10upx;
+	top: 0upx;
+	left: 0upx;
+	right: 0;
+	bottom: 0;
+	margin: auto;
+	background-color: #ffffff;
+	border-radius: 20upx;
+}
+
+swiper.round-dot .wx-swiper-dot.wx-swiper-dot-active,
+swiper.round-dot .a-swiper-dot.a-swiper-dot-active,
+swiper.round-dot .uni-swiper-dot.uni-swiper-dot-active {
+	width: 18upx;
+	height: 18upx;
+}
+
+.screen-swiper {
+	min-height: 375upx;
+}
+
+.screen-swiper image,
+.screen-swiper video,
+.swiper-item image,
+.swiper-item video {
+	width: 100%;
+	display: block;
+	height: 100%;
+	margin: 0;
+	pointer-events: none;
+}
+
+.card-swiper {
+	height: 420upx !important;
+}
+
+.card-swiper swiper-item {
+	width: 610upx !important;
+	left: 70upx;
+	box-sizing: border-box;
+	padding: 40upx 0upx 70upx;
+	overflow: initial;
+}
+
+.card-swiper swiper-item .swiper-item {
+	width: 100%;
+	display: block;
+	height: 100%;
+	border-radius: 10upx;
+	transform: scale(0.9);
+	transition: all 0.2s ease-in 0s;
+	overflow: hidden;
+}
+
+.card-swiper swiper-item.cur .swiper-item {
+	transform: none;
+	transition: all 0.2s ease-in 0s;
+}
+
+
+.tower-swiper {
+	height: 1334upx;
+	position: relative;
+	max-width: 750upx;
+	overflow: hidden;
+
+	/* background-color: #007AFF; */
+}
+
+.tower-swiper .tower-item {
+	position: absolute;
+	width: 750upx;
+	height: 100%;
+	top: 0;
+	bottom: 10%;
+	left: 0;
+	margin: auto;
+	transition: all 0.2s ease-in 0s;
+	opacity: 1;
+}
+
+.tower-swiper .tower-item.none {
+	opacity: 0;
+}
+
+.tower-swiper .tower-item .swiper-item {
+	width: 100%;
+	height: 100%;
+	border-radius: 45upx;
+	overflow: hidden;
+}
+
+/* ==================
+          步骤条
+ ==================== */
+
+.cu-steps {
+	display: flex;
+}
+
+scroll-view.cu-steps {
+	display: block;
+	white-space: nowrap;
+}
+
+scroll-view.cu-steps .cu-item {
+	display: inline-block;
+}
+
+.cu-steps .cu-item {
+	flex: 1;
+	text-align: center;
+	position: relative;
+	min-width: 100upx;
+}
+
+.cu-steps .cu-item:not([class*="text-"]) {
+	color: #8799a3;
+}
+
+.cu-steps .cu-item [class*="cuIcon-"],
+.cu-steps .cu-item .num {
+	display: block;
+	font-size: 40upx;
+	line-height: 80upx;
+}
+
+.cu-steps .cu-item::before,
+.cu-steps .cu-item::after,
+.cu-steps.steps-arrow .cu-item::before,
+.cu-steps.steps-arrow .cu-item::after {
+	content: "";
+	display: block;
+	position: absolute;
+	height: 0px;
+	width: calc(100% - 80upx);
+	border-bottom: 1px solid #ccc;
+	left: calc(0px - (100% - 80upx) / 2);
+	top: 40upx;
+	z-index: 0;
+}
+
+.cu-steps.steps-arrow .cu-item::before,
+.cu-steps.steps-arrow .cu-item::after {
+	content: "\e6a3";
+	font-family: 'cuIcon';
+	height: 30upx;
+	border-bottom-width: 0px;
+	line-height: 30upx;
+	top: 0;
+	bottom: 0;
+	margin: auto;
+	color: #ccc;
+}
+
+.cu-steps.steps-bottom .cu-item::before,
+.cu-steps.steps-bottom .cu-item::after {
+	bottom: 40upx;
+	top: initial;
+}
+
+.cu-steps .cu-item::after {
+	border-bottom: 1px solid currentColor;
+	width: 0px;
+	transition: all 0.3s ease-in-out 0s;
+}
+
+.cu-steps .cu-item[class*="text-"]::after {
+	width: calc(100% - 80upx);
+	color: currentColor;
+}
+
+.cu-steps .cu-item:first-child::before,
+.cu-steps .cu-item:first-child::after {
+	display: none;
+}
+
+.cu-steps .cu-item .num {
+	width: 40upx;
+	height: 40upx;
+	border-radius: 50%;
+	line-height: 40upx;
+	margin: 20upx auto;
+	font-size: 24upx;
+	border: 1px solid currentColor;
+	position: relative;
+	overflow: hidden;
+}
+
+.cu-steps .cu-item[class*="text-"] .num {
+	background-color: currentColor;
+}
+
+.cu-steps .cu-item .num::before,
+.cu-steps .cu-item .num::after {
+	content: attr(data-index);
+	position: absolute;
+	left: 0;
+	right: 0;
+	top: 0;
+	bottom: 0;
+	margin: auto;
+	transition: all 0.3s ease-in-out 0s;
+	transform: translateY(0upx);
+}
+
+.cu-steps .cu-item[class*="text-"] .num::before {
+	transform: translateY(-40upx);
+	color: #ffffff;
+}
+
+.cu-steps .cu-item .num::after {
+	transform: translateY(40upx);
+	color: #ffffff;
+	transition: all 0.3s ease-in-out 0s;
+}
+
+.cu-steps .cu-item[class*="text-"] .num::after {
+	content: "\e645";
+	font-family: 'cuIcon';
+	color: #ffffff;
+	transform: translateY(0upx);
+}
+
+.cu-steps .cu-item[class*="text-"] .num.err::after {
+	content: "\e646";
+}
+
+/* ==================
+          布局
+ ==================== */
+
+/*  -- flex弹性布局 -- */
+
+.flex {
+	display: flex;
+}
+
+.basis-xs {
+	flex-basis: 20%;
+}
+
+.basis-sm {
+	flex-basis: 40%;
+}
+
+.basis-df {
+	flex-basis: 50%;
+}
+
+.basis-lg {
+	flex-basis: 60%;
+}
+
+.basis-xl {
+	flex-basis: 85%;
+}
+
+.flex-sub {
+	flex: 1;
+}
+
+.flex-twice {
+	flex: 2;
+}
+
+.flex-treble {
+	flex: 3;
+}
+
+.flex-direction {
+	flex-direction: column;
+}
+
+.flex-wrap {
+	flex-wrap: wrap;
+}
+
+.align-start {
+	align-items: flex-start;
+}
+
+.align-end {
+	align-items: flex-end;
+}
+
+.align-center {
+	align-items: center;
+}
+
+.align-stretch {
+	align-items: stretch;
+}
+
+.self-start {
+	align-self: flex-start;
+}
+
+.self-center {
+	align-self: flex-center;
+}
+
+.self-end {
+	align-self: flex-end;
+}
+
+.self-stretch {
+	align-self: stretch;
+}
+
+.align-stretch {
+	align-items: stretch;
+}
+
+.justify-start {
+	justify-content: flex-start;
+}
+
+.justify-end {
+	justify-content: flex-end;
+}
+
+.justify-center {
+	justify-content: center;
+}
+
+.justify-between {
+	justify-content: space-between;
+}
+
+.justify-around {
+	justify-content: space-around;
+}
+
+/* grid布局 */
+
+.grid {
+	display: flex;
+	flex-wrap: wrap;
+}
+
+.grid.grid-square {
+	overflow: hidden;
+}
+
+.grid.grid-square .cu-tag {
+	position: absolute;
+	right: 0;
+	top: 0;
+	border-bottom-left-radius: 6upx;
+	padding: 6upx 12upx;
+	height: auto;
+	background-color: rgba(0, 0, 0, 0.5);
+}
+
+.grid.grid-square>view>text[class*="cuIcon-"] {
+	font-size: 52upx;
+	position: absolute;
+	color: #8799a3;
+	margin: auto;
+	top: 0;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	flex-direction: column;
+}
+
+.grid.grid-square>view {
+	margin-right: 20upx;
+	margin-bottom: 20upx;
+	border-radius: 6upx;
+	position: relative;
+	overflow: hidden;
+}
+
+.grid.grid-square>view.bg-img image {
+	width: 100%;
+	height: 100%;
+	position: absolute;
+}
+
+.grid.col-1.grid-square>view {
+	padding-bottom: 100%;
+	height: 0;
+	margin-right: 0;
+}
+
+.grid.col-2.grid-square>view {
+	padding-bottom: calc((100% - 20upx)/2);
+	height: 0;
+	width: calc((100% - 20upx)/2);
+}
+
+.grid.col-3.grid-square>view {
+	padding-bottom: calc((100% - 40upx)/3);
+	height: 0;
+	width: calc((100% - 40upx)/3);
+}
+
+.grid.col-4.grid-square>view {
+	padding-bottom: calc((100% - 60upx)/4);
+	height: 0;
+	width: calc((100% - 60upx)/4);
+}
+
+.grid.col-5.grid-square>view {
+	padding-bottom: calc((100% - 80upx)/5);
+	height: 0;
+	width: calc((100% - 80upx)/5);
+}
+
+.grid.col-2.grid-square>view:nth-child(2n),
+.grid.col-3.grid-square>view:nth-child(3n),
+.grid.col-4.grid-square>view:nth-child(4n),
+.grid.col-5.grid-square>view:nth-child(5n) {
+	margin-right: 0;
+}
+
+.grid.col-1>view {
+	width: 100%;
+}
+
+.grid.col-2>view {
+	width: 50%;
+}
+
+.grid.col-3>view {
+	width: 33.33%;
+}
+
+.grid.col-4>view {
+	width: 25%;
+}
+
+.grid.col-5>view {
+	width: 20%;
+}
+
+/*  -- 内外边距 -- */
+
+.margin-0 {
+	margin: 0;
+}
+
+.margin-xs {
+	margin: 10upx;
+}
+
+.margin-sm {
+	margin: 20upx;
+}
+
+.margin {
+	margin: 30upx;
+}
+
+.margin-lg {
+	margin: 40upx;
+}
+
+.margin-xl {
+	margin: 50upx;
+}
+
+.margin-top-xs {
+	margin-top: 10upx;
+}
+
+.margin-top-sm {
+	margin-top: 20upx;
+}
+
+.margin-top {
+	margin-top: 30upx;
+}
+
+.margin-top-lg {
+	margin-top: 40upx;
+}
+
+.margin-top-xl {
+	margin-top: 50upx;
+}
+
+.margin-right-xs {
+	margin-right: 10upx;
+}
+
+.margin-right-sm {
+	margin-right: 20upx;
+}
+
+.margin-right {
+	margin-right: 30upx;
+}
+
+.margin-right-lg {
+	margin-right: 40upx;
+}
+
+.margin-right-xl {
+	margin-right: 50upx;
+}
+
+.margin-bottom-xs {
+	margin-bottom: 10upx;
+}
+
+.margin-bottom-sm {
+	margin-bottom: 20upx;
+}
+
+.margin-bottom {
+	margin-bottom: 30upx;
+}
+
+.margin-bottom-lg {
+	margin-bottom: 40upx;
+}
+
+.margin-bottom-xl {
+	margin-bottom: 50upx;
+}
+
+.margin-left-xs {
+	margin-left: 10upx;
+}
+
+.margin-left-sm {
+	margin-left: 20upx;
+}
+
+.margin-left {
+	margin-left: 30upx;
+}
+
+.margin-left-lg {
+	margin-left: 40upx;
+}
+
+.margin-left-xl {
+	margin-left: 50upx;
+}
+
+.margin-lr-xs {
+	margin-left: 10upx;
+	margin-right: 10upx;
+}
+
+.margin-lr-sm {
+	margin-left: 20upx;
+	margin-right: 20upx;
+}
+
+.margin-lr {
+	margin-left: 30upx;
+	margin-right: 30upx;
+}
+
+.margin-lr-lg {
+	margin-left: 40upx;
+	margin-right: 40upx;
+}
+
+.margin-lr-xl {
+	margin-left: 50upx;
+	margin-right: 50upx;
+}
+
+.margin-tb-xs {
+	margin-top: 10upx;
+	margin-bottom: 10upx;
+}
+
+.margin-tb-sm {
+	margin-top: 20upx;
+	margin-bottom: 20upx;
+}
+
+.margin-tb {
+	margin-top: 30upx;
+	margin-bottom: 30upx;
+}
+
+.margin-tb-lg {
+	margin-top: 40upx;
+	margin-bottom: 40upx;
+}
+
+.margin-tb-xl {
+	margin-top: 50upx;
+	margin-bottom: 50upx;
+}
+
+.padding-0 {
+	padding: 0;
+}
+
+.padding-xs {
+	padding: 10upx;
+}
+
+.padding-sm {
+	padding: 20upx;
+}
+
+.padding {
+	padding: 30upx;
+}
+
+.padding-lg {
+	padding: 40upx;
+}
+
+.padding-xl {
+	padding: 50upx;
+}
+
+.padding-top-xs {
+	padding-top: 10upx;
+}
+
+.padding-top-sm {
+	padding-top: 20upx;
+}
+
+.padding-top {
+	padding-top: 30upx;
+}
+
+.padding-top-lg {
+	padding-top: 40upx;
+}
+
+.padding-top-xl {
+	padding-top: 50upx;
+}
+
+.padding-right-xs {
+	padding-right: 10upx;
+}
+
+.padding-right-sm {
+	padding-right: 20upx;
+}
+
+.padding-right {
+	padding-right: 30upx;
+}
+
+.padding-right-lg {
+	padding-right: 40upx;
+}
+
+.padding-right-xl {
+	padding-right: 50upx;
+}
+
+.padding-bottom-xs {
+	padding-bottom: 10upx;
+}
+
+.padding-bottom-sm {
+	padding-bottom: 20upx;
+}
+
+.padding-bottom {
+	padding-bottom: 30upx;
+}
+
+.padding-bottom-lg {
+	padding-bottom: 40upx;
+}
+
+.padding-bottom-xl {
+	padding-bottom: 50upx;
+}
+
+.padding-left-xs {
+	padding-left: 10upx;
+}
+
+.padding-left-sm {
+	padding-left: 20upx;
+}
+
+.padding-left {
+	padding-left: 30upx;
+}
+
+.padding-left-lg {
+	padding-left: 40upx;
+}
+
+.padding-left-xl {
+	padding-left: 50upx;
+}
+
+.padding-lr-xs {
+	padding-left: 10upx;
+	padding-right: 10upx;
+}
+
+.padding-lr-sm {
+	padding-left: 20upx;
+	padding-right: 20upx;
+}
+
+.padding-lr {
+	padding-left: 30upx;
+	padding-right: 30upx;
+}
+
+.padding-lr-lg {
+	padding-left: 40upx;
+	padding-right: 40upx;
+}
+
+.padding-lr-xl {
+	padding-left: 50upx;
+	padding-right: 50upx;
+}
+
+.padding-tb-xs {
+	padding-top: 10upx;
+	padding-bottom: 10upx;
+}
+
+.padding-tb-sm {
+	padding-top: 20upx;
+	padding-bottom: 20upx;
+}
+
+.padding-tb {
+	padding-top: 30upx;
+	padding-bottom: 30upx;
+}
+
+.padding-tb-lg {
+	padding-top: 40upx;
+	padding-bottom: 40upx;
+}
+
+.padding-tb-xl {
+	padding-top: 50upx;
+	padding-bottom: 50upx;
+}
+
+/* -- 浮动 --  */
+
+.cf::after,
+.cf::before {
+	content: " ";
+	display: table;
+}
+
+.cf::after {
+	clear: both;
+}
+
+.fl {
+	float: left;
+}
+
+.fr {
+	float: right;
+}
+
+/* ==================
+          背景
+ ==================== */
+
+.line-red::after,
+.lines-red::after {
+	border-color: #e54d42;
+}
+
+.line-orange::after,
+.lines-orange::after {
+	border-color: #f37b1d;
+}
+
+.line-yellow::after,
+.lines-yellow::after {
+	border-color: #fbbd08;
+}
+
+.line-olive::after,
+.lines-olive::after {
+	border-color: #8dc63f;
+}
+
+.line-green::after,
+.lines-green::after {
+	border-color: #39b54a;
+}
+
+.line-cyan::after,
+.lines-cyan::after {
+	border-color: #1cbbb4;
+}
+
+.line-blue::after,
+.lines-blue::after {
+	border-color: #0081ff;
+}
+
+.line-purple::after,
+.lines-purple::after {
+	border-color: #6739b6;
+}
+
+.line-mauve::after,
+.lines-mauve::after {
+	border-color: #9c26b0;
+}
+
+.line-pink::after,
+.lines-pink::after {
+	border-color: #e03997;
+}
+
+.line-brown::after,
+.lines-brown::after {
+	border-color: #a5673f;
+}
+
+.line-grey::after,
+.lines-grey::after {
+	border-color: #8799a3;
+}
+
+.line-mGrey::after {
+	border-color: #EAEAEA;
+}
+
+
+.line-gray::after,
+.lines-gray::after {
+	border-color: #aaaaaa;
+}
+
+.line-black::after,
+.lines-black::after {
+	border-color: #333333;
+}
+
+.line-white::after,
+.lines-white::after {
+	border-color: #ffffff;
+}
+
+.bg-red {
+	background-color: #e54d42;
+	color: #ffffff;
+}
+
+.bg-orange {
+	background-color: #f37b1d;
+	color: #ffffff;
+}
+
+.bg-yellow {
+	background-color: #fbbd08;
+	color: #333333;
+}
+
+.bg-olive {
+	background-color: #8dc63f;
+	color: #ffffff;
+}
+
+.bg-green {
+	background-color: #39b54a;
+	color: #ffffff;
+}
+
+.bg-cyan {
+	background-color: #1cbbb4;
+	color: #ffffff;
+}
+
+.bg-blue {
+	background-color: #0081ff;
+	color: #ffffff;
+}
+
+.bg-purple {
+	background-color: #6739b6;
+	color: #ffffff;
+}
+
+.bg-mauve {
+	background-color: #9c26b0;
+	color: #ffffff;
+}
+
+.bg-pink {
+	background-color: #e03997;
+	color: #ffffff;
+}
+
+.bg-brown {
+	background-color: #a5673f;
+	color: #ffffff;
+}
+
+.bg-grey {
+	background-color: #8799a3;
+	color: #ffffff;
+}
+
+.bg-gray {
+	background-color: #f0f0f0;
+	color: #333333;
+}
+
+.bg-black {
+	background-color: #333333;
+	color: #ffffff;
+}
+
+.bg-white {
+	background-color: #ffffff;
+	color: #666666;
+}
+
+.bg-shadeTop {
+	background-image: linear-gradient(rgba(0, 0, 0, 1), rgba(0, 0, 0, 0.01));
+	color: #ffffff;
+}
+
+.bg-shadeBottom {
+	background-image: linear-gradient(rgba(0, 0, 0, 0.01), rgba(0, 0, 0, 1));
+	color: #ffffff;
+}
+
+.bg-red.light {
+	color: #e54d42;
+	background-color: #fadbd9;
+}
+
+.bg-orange.light {
+	color: #f37b1d;
+	background-color: #fde6d2;
+}
+
+.bg-yellow.light {
+	color: #fbbd08;
+	background-color: #fef2ced2;
+}
+
+.bg-olive.light {
+	color: #8dc63f;
+	background-color: #e8f4d9;
+}
+
+.bg-green.light {
+	color: #39b54a;
+	background-color: #d7f0dbff;
+}
+
+.bg-cyan.light {
+	color: #1cbbb4;
+	background-color: #d2f1f0;
+}
+
+.bg-blue.light {
+	color: #0081ff;
+	background-color: #cce6ff;
+}
+
+.bg-purple.light {
+	color: #6739b6;
+	background-color: #e1d7f0;
+}
+
+.bg-mauve.light {
+	color: #9c26b0;
+	background-color: #ebd4ef;
+}
+
+.bg-pink.light {
+	color: #e03997;
+	background-color: #f9d7ea;
+}
+
+.bg-brown.light {
+	color: #a5673f;
+	background-color: #ede1d9;
+}
+
+.bg-grey.light {
+	color: #8799a3;
+	background-color: #e7ebed;
+}
+
+.bg-gradual-red {
+	background-image: linear-gradient(45deg, #f43f3b, #ec008c);
+	color: #ffffff;
+}
+
+.bg-gradual-orange {
+	background-image: linear-gradient(45deg, #ff9700, #ed1c24);
+	color: #ffffff;
+}
+
+.bg-gradual-green {
+	background-image: linear-gradient(45deg, #39b54a, #8dc63f);
+	color: #ffffff;
+}
+
+.bg-gradual-purple {
+	background-image: linear-gradient(45deg, #9000ff, #5e00ff);
+	color: #ffffff;
+}
+
+.bg-gradual-pink {
+	background-image: linear-gradient(45deg, #ec008c, #6739b6);
+	color: #ffffff;
+}
+
+.bg-gradual-blue {
+	background-image: linear-gradient(45deg, #0081ff, #1cbbb4);
+	color: #ffffff;
+}
+
+.shadow[class*="-red"] {
+	box-shadow: 6upx 6upx 8upx rgba(204, 69, 59, 0.2);
+}
+
+.shadow[class*="-orange"] {
+	box-shadow: 6upx 6upx 8upx rgba(217, 109, 26, 0.2);
+}
+
+.shadow[class*="-yellow"] {
+	box-shadow: 6upx 6upx 8upx rgba(224, 170, 7, 0.2);
+}
+
+.shadow[class*="-olive"] {
+	box-shadow: 6upx 6upx 8upx rgba(124, 173, 55, 0.2);
+}
+
+.shadow[class*="-green"] {
+	box-shadow: 6upx 6upx 8upx rgba(48, 156, 63, 0.2);
+}
+
+.shadow[class*="-cyan"] {
+	box-shadow: 6upx 6upx 8upx rgba(28, 187, 180, 0.2);
+}
+
+.shadow[class*="-blue"] {
+	box-shadow: 6upx 6upx 8upx rgba(0, 102, 204, 0.2);
+}
+
+.shadow[class*="-purple"] {
+	box-shadow: 6upx 6upx 8upx rgba(88, 48, 156, 0.2);
+}
+
+.shadow[class*="-mauve"] {
+	box-shadow: 6upx 6upx 8upx rgba(133, 33, 150, 0.2);
+}
+
+.shadow[class*="-pink"] {
+	box-shadow: 6upx 6upx 8upx rgba(199, 50, 134, 0.2);
+}
+
+.shadow[class*="-brown"] {
+	box-shadow: 6upx 6upx 8upx rgba(140, 88, 53, 0.2);
+}
+
+.shadow[class*="-grey"] {
+	box-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2);
+}
+
+.shadow[class*="-gray"] {
+	box-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2);
+}
+
+.shadow[class*="-black"] {
+	box-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2);
+}
+
+.shadow[class*="-white"] {
+	box-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2);
+}
+
+.text-shadow[class*="-red"] {
+	text-shadow: 6upx 6upx 8upx rgba(204, 69, 59, 0.2);
+}
+
+.text-shadow[class*="-orange"] {
+	text-shadow: 6upx 6upx 8upx rgba(217, 109, 26, 0.2);
+}
+
+.text-shadow[class*="-yellow"] {
+	text-shadow: 6upx 6upx 8upx rgba(224, 170, 7, 0.2);
+}
+
+.text-shadow[class*="-olive"] {
+	text-shadow: 6upx 6upx 8upx rgba(124, 173, 55, 0.2);
+}
+
+.text-shadow[class*="-green"] {
+	text-shadow: 6upx 6upx 8upx rgba(48, 156, 63, 0.2);
+}
+
+.text-shadow[class*="-cyan"] {
+	text-shadow: 6upx 6upx 8upx rgba(28, 187, 180, 0.2);
+}
+
+.text-shadow[class*="-blue"] {
+	text-shadow: 6upx 6upx 8upx rgba(0, 102, 204, 0.2);
+}
+
+.text-shadow[class*="-purple"] {
+	text-shadow: 6upx 6upx 8upx rgba(88, 48, 156, 0.2);
+}
+
+.text-shadow[class*="-mauve"] {
+	text-shadow: 6upx 6upx 8upx rgba(133, 33, 150, 0.2);
+}
+
+.text-shadow[class*="-pink"] {
+	text-shadow: 6upx 6upx 8upx rgba(199, 50, 134, 0.2);
+}
+
+.text-shadow[class*="-brown"] {
+	text-shadow: 6upx 6upx 8upx rgba(140, 88, 53, 0.2);
+}
+
+.text-shadow[class*="-grey"] {
+	text-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2);
+}
+
+.text-shadow[class*="-gray"] {
+	text-shadow: 6upx 6upx 8upx rgba(114, 130, 138, 0.2);
+}
+
+.text-shadow[class*="-black"] {
+	text-shadow: 6upx 6upx 8upx rgba(26, 26, 26, 0.2);
+}
+
+.bg-img {
+	background-size: cover;
+	background-position: center;
+	background-repeat: no-repeat;
+}
+
+.bg-mask {
+	background-color: #333333;
+	position: relative;
+}
+
+.bg-mask::after {
+	content: "";
+	border-radius: inherit;
+	width: 100%;
+	height: 100%;
+	display: block;
+	background-color: rgba(0, 0, 0, 0.4);
+	position: absolute;
+	left: 0;
+	right: 0;
+	bottom: 0;
+	top: 0;
+}
+
+.bg-mask view,
+.bg-mask cover-view {
+	z-index: 5;
+	position: relative;
+}
+
+.bg-video {
+	position: relative;
+}
+
+.bg-video video {
+	display: block;
+	height: 100%;
+	width: 100%;
+	-o-object-fit: cover;
+	object-fit: cover;
+	position: absolute;
+	top: 0;
+	z-index: 0;
+	pointer-events: none;
+}
+
+/* ==================
+          文本
+ ==================== */
+
+.text-xs {
+	font-size: 20upx;
+}
+
+.text-sm {
+	font-size: 24upx;
+}
+
+.text-df {
+	font-size: 28upx;
+}
+
+.text-lg {
+	font-size: 32upx;
+}
+
+.text-xl {
+	font-size: 36upx;
+}
+
+.text-18px {
+	font-size: 18px;
+}
+
+.text-16px {
+	font-size: 16px;
+}
+
+.text-11px {
+	font-size: 11px;
+}
+
+.text-13px {
+	font-size: 13px;
+}
+
+.text-14px {
+	font-size: 14px;
+}
+
+.text-15px {
+	font-size: 16px;
+}
+
+.text-22px {
+	font-size: 22px;
+}
+
+.text-26px {
+	font-size: 26px;
+}
+
+.text-18px-before::before {
+	font-size: 18px;
+}
+
+.text-20px-before::before {
+	font-size: 20px;
+}
+
+.text-22px-before::before {
+	font-size: 22px;
+}
+
+.text-xxl {
+	font-size: 44upx;
+}
+
+.text-sl {
+	font-size: 80upx;
+}
+
+.text-xsl {
+	font-size: 120upx;
+}
+
+.text-Abc {
+	text-transform: Capitalize;
+}
+
+.text-ABC {
+	text-transform: Uppercase;
+}
+
+.text-abc {
+	text-transform: Lowercase;
+}
+
+.text-price::before {
+	content: "¥";
+	font-size: 80%;
+	margin-right: 4upx;
+}
+
+.text-cut {
+	text-overflow: ellipsis;
+	white-space: nowrap;
+	overflow: hidden;
+}
+
+.text-bold {
+	font-weight: bold;
+}
+
+.text-center {
+	text-align: center;
+}
+
+.text-content {
+	line-height: 1.6;
+}
+
+.text-left {
+	text-align: left;
+}
+
+.text-right {
+	text-align: right;
+}
+
+.text-red,
+.line-red,
+.lines-red {
+	color: #e54d42;
+}
+
+.text-orange,
+.line-orange,
+.lines-orange {
+	color: #f37b1d;
+}
+
+.text-yellow,
+.line-yellow,
+.lines-yellow {
+	color: #fbbd08;
+}
+
+.text-olive,
+.line-olive,
+.lines-olive {
+	color: #8dc63f;
+}
+
+.text-green,
+.line-green,
+.lines-green {
+	color: #39b54a;
+}
+
+.text-cyan,
+.line-cyan,
+.lines-cyan {
+	color: #1cbbb4;
+}
+
+.text-blue,
+.line-blue,
+.lines-blue {
+	color: #0081ff;
+}
+
+.text-purple,
+.line-purple,
+.lines-purple {
+	color: #6739b6;
+}
+
+.text-mauve,
+.line-mauve,
+.lines-mauve {
+	color: #9c26b0;
+}
+
+.text-pink,
+.line-pink,
+.lines-pink {
+	color: #e03997;
+}
+
+.text-brown,
+.line-brown,
+.lines-brown {
+	color: #a5673f;
+}
+
+.text-grey,
+.line-grey,
+.lines-grey {
+	color: #8799a3;
+}
+
+.line-mGrey {
+	color: #EAEAEA;
+}
+
+.text-gray,
+.line-gray,
+.lines-gray {
+	color: #aaaaaa;
+}
+
+.text-black,
+.line-black,
+.lines-black {
+	color: #333333;
+}
+
+.text-white,
+.line-white,
+.lines-white {
+	color: #ffffff;
+}
+
+/* slambb */
+.make-line-purple,
+.make-text-purple {
+	color: rgba(164, 136, 220, 1);
+}
+
+.make-line-purple::after,
+.make-lines-purple::after {
+	border-color: rgba(164, 136, 220, 1);
+}
+
+.make-bg-purple {
+	background-color: rgba(164, 136, 220, 1);
+}
+
+.make-text-blue {
+	color: rgba(116, 172, 240, 1);
+}
+
+/* 蓝紫 */
+.make-line-bPurple::after,
+.make-lines-bPurple::after{
+	border-color: rgba(151, 151, 255, 1);
+}
+
+.make-line-bPurple,
+.make-lines-bPurple,
+.make-text-bPurple {
+	color: rgba(151, 151, 255, 1);
+}
+
+
+.make-bg-bPurple {
+	background-color: rgba(151, 151, 255, 1);
+}
+
+.make-bg-bPurple-01 {
+	background-color: rgba(151, 151, 255, 0.1);
+}
+
+.make-text-r-blue {
+	color: rgba(55, 192, 252, 255);
+}
+
+.make-text-z3-white {
+	color: rgba(255, 255, 255, 0.3);
+}
+
+/* 自定义导航栏的图片大小 */
+.png-more {
+	width: 20px;
+	height: 20px;
+}
+.png-more-black {
+	width: 16px;
+	height: 16px;
+}
+
+.card-view {
+	/* border: 1rpx solid #000000; */
+	border-radius: 18px;
+	margin: 20rpx;
+	overflow: hidden;
+	background-color: #FFFFFF;
+	/* box-shadow: 0px 0px 3px 2px rgba(113, 113, 219, 0.23); */
+	box-shadow: -3px 4px 9px 0px rgba(151, 151, 255, 0.33);
+	position: relative;
+	z-index: 2;
+}
+
+
+.only-arrow {
+	width: 60rpx;
+	/* padding-right: 90upx */
+	/* border: 1rpx solid #000000; */
+}
+
+.only-arrow:before {
+	position: absolute;
+	top: 0;
+	right: 30rpx;
+	bottom: 0;
+	display: block;
+	margin: auto;
+	width: 30rpx;
+	height: 30rpx;
+	color: #8799a3;
+	content: "\e6a3";
+	text-align: center;
+	font-size: 20rpx;
+	font-family: cuIcon;
+	line-height: 30rpx
+}
+
+.full-container {
+	position: absolute;
+	top: 0;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	/* background-color: #FFFFFF; */
+}
+
+
+/* 图片部分大小 */
+.w-left-arrow {
+	width: 11px;
+	height: 19px;
+}
+
+.p-left-arrow {
+	width: 19px;
+	height: 19px;
+}
+
+.b-down-arrow {
+	width: 13px;
+	height: 8px;
+}
+
+.data-png-32 {
+	width: 32px;
+	height: 32px;
+}
+
+.data-png-26 {
+	width: 26px;
+	height: 26px;
+}
+
+.data-png-64 {
+	width: 64px;
+	height: 64px;
+}
+
+/* 设备样式 */
+.container-device {
+	display: flex;
+	flex-direction: row;
+	align-items: center;
+	justify-content: flex-start;
+	flex-wrap: wrap;
+
+	width: 100%;
+}
+
+.width-device {
+	width: calc(50% - 15px);
+	height: 64px;
+	border-radius: 10px;
+	margin: 10px 0 20px 10px;
+	border: 1rpx solid #EEEEEE;
+	box-shadow: 0px 1px 2px 0px rgba(113, 113, 219, 0.23);
+	position: relative;
+}
+
+
+
+/* ==================
+          自定义步骤条
+ ==================== */
+
+.my-cu-steps {
+	display: flex;
+}
+
+
+.my-cu-steps .my-cu-item {
+	flex: 1;
+	text-align: center;
+	position: relative;
+	min-width: 100upx;
+}
+
+.my-cu-steps .my-cu-item:not([class*="text-"]) {
+	color: rgba(255, 255, 255, 0.3);
+}
+
+.my-cu-steps .my-cu-item [class*="cuIcon-"],
+.my-cu-steps .my-cu-item .num {
+	display: block;
+	font-size: 40upx;
+	line-height: 80upx;
+}
+
+.my-cu-steps .my-cu-item::before,
+.my-cu-steps .my-cu-item::after {
+	content: "";
+	display: block;
+	position: absolute;
+	height: 0px;
+	width: calc(100% - 42upx);
+	border-bottom: 4px solid rgba(255, 255, 255, 0.3);
+	left: calc(0px - (100% - 42upx) / 2);
+	top: 35upx;
+	z-index: 0;
+}
+
+.my-cu-steps.steps-bottom .my-cu-item::before,
+.my-cu-steps.steps-bottom .my-cu-item::after {
+	bottom: 40upx;
+	top: initial;
+}
+
+.my-cu-steps .my-cu-item::after {
+	border-bottom: 4px solid #FFFFFF;
+	width: 0px;
+	transition: all 0.3s ease-in-out 0s;
+}
+
+.my-cu-steps .my-cu-item[class*="text-"]::after {
+	width: calc(100% - 40upx);
+	color: currentColor;
+}
+
+.my-cu-steps .my-cu-item:first-child::before,
+.my-cu-steps .my-cu-item:first-child::after {
+	display: none;
+}
+
+.my-cu-steps .my-cu-item .num {
+	width: 40upx;
+	height: 40upx;
+	border-radius: 50%;
+	line-height: 40upx;
+	margin: 20upx auto;
+	font-size: 24upx;
+	border: 1px solid currentColor;
+	position: relative;
+	overflow: hidden;
+}
+
+.my-cu-steps .my-cu-item[class*="text-"] .num {
+	background-color: currentColor;
+}
+
+
+.my-cu-steps .my-cu-item[class*="text-"] .num::before {
+	transform: translateY(-40upx);
+	color: #ffffff;
+}
+
+.my-cu-steps .cu-item .num::after {
+	transform: translateY(40upx);
+	color: #ffffff;
+	transition: all 0.3s ease-in-out 0s;
+}
+
+.my-cu-steps .my-cu-item[class*="text-"] .num::after {
+	content: "\e645";
+	font-family: 'cuIcon';
+	color: #ffffff;
+	transform: translateY(0upx);
+}
+
+.my-cu-steps .my-cu-item[class*="text-"] .num.err::after {
+	content: "\e646";
+}
+
+.cu-bind-modal {
+
+	position: relative;
+	width: 604rpx;
+	height: 576rpx;
+	background-color: rgba(0, 0, 0, 0);
+	border-radius: 25px;
+	display: inline-block;
+	vertical-align: middle;
+	margin-left: auto;
+	margin-right: auto;
+	overflow: hidden;
+}
+
+/* 首页两边格子进度条样式 */
+.grid-progress-vertical-container {
+	position: absolute;
+	top: -50rpx;
+	left: 0;
+	right: 0;
+	display: flex;
+	width: 750rpx;
+	justify-content: space-between;
+	/* border: 1rpx solid #000000; */
+	pointer-events: none;
+}
+
+.grid-progress-vertical-bar {
+	display: flex;
+	flex-direction: column-reverse;
+}
+
+.grid-progress-vertical-child {
+	/* position: relative; */
+	width: 74rpx;
+	height: 14rpx;
+	margin: 14rpx 18rpx 0 18rpx;
+	display: flex;
+	/* align-content: center; */
+	justify-content: space-between;
+
+
+}
+
+.grid-progress-vertical-text {
+	color: #FFFFFF;
+	font-size: 8px;
+	line-height: 8px;
+}
+
+.grid-progress-text-hidden {
+	visibility: hidden;
+}
+
+.grid-progress-vertical-active {
+	background-color: #FFFFFF;
+	width: 30rpx;
+	height: 100%;
+}
+
+.grid-progress-vertical-inactive {
+	width: 30rpx;
+	height: 100%;
+	background: rgba(255, 255, 255, 0.2); //rgba(144, 141, 246, 1);
+}
+
+
+
+/* ==================
+          自定义任务纵向步骤条
+ ==================== */
+
+.my-column-cu-steps {
+	display: flex;
+	flex-direction: column;
+}
+
+.my-column-cu-steps .cu-item {
+	flex: 1;
+	text-align: center;
+	position: relative;
+	min-height: 220upx;
+	/* border: 1px solid #000000; */
+}
+
+.my-column-cu-steps .cu-item:not([class*="text-"]) {
+	color: #8799a3;
+}
+
+.my-column-cu-steps .cu-item [class*="cuIcon-"] {
+	display: block;
+	font-size: 40upx;
+	line-height: 80upx;
+	position: absolute;
+	top: 0;
+	left: 42rpx;
+}
+
+.my-column-cu-steps .cu-item .my-column-cu-image {
+	display: block;
+	position: absolute;
+	top: 30rpx;
+	left: 82rpx;
+	
+	width: 76rpx;
+	height: 76rpx;
+}
+
+.my-column-cu-steps .cu-item .my-column-cu-right-image {
+	display: block;
+	position: absolute;
+	top: 30rpx;
+	right: 88rpx;
+	
+	width: 76rpx;
+	height: 76rpx;
+}
+
+
+.my-column-cu-steps .cu-item::before,
+.my-column-cu-steps .cu-item::after {
+	content: "";
+	display: block;
+	position: absolute;
+	width: 0px;
+	height: calc(100% - 146rpx);
+	border-left: 1px dashed #ccc;
+	top: calc(20px - (100% + 50rpx) / 2);
+	left: 120rpx;
+	/* right: 0; */
+	/* margin: auto; */
+	z-index: 0;
+}
+
+
+.my-column-cu-steps .cu-item::after {
+	border-left: 1px dashed currentColor;
+	width: 0px;
+	transition: all 0.3s ease-in-out 0s;
+}
+
+.my-column-cu-steps .cu-item[class*="text-"]::after {
+	height: calc(100% - 106upx);
+	color: currentColor;
+}
+
+.my-column-cu-steps .cu-item:first-child::before,
+.my-column-cu-steps .cu-item:first-child::after {
+	display: none;
+}
+
+.my-column-cu-steps>.cu-item>.content {
+	margin-left: 160rpx;
+	width: calc(100% - 230rpx);
+	border-radius: 6upx;
+
+	height: 220rpx;
+	line-height: 1.6;
+	display: flex;
+	flex-direction: column;
+	justify-content: start;
+}
+
+/* .my-column-cu-steps>.cu-item>.content:not([class*="bg-"]) {
+	background-color: #f1f1f1;
+	color: #333333;
+} */
+
+/* .my-column-cu-steps>.cu-item>.content+.content {
+	margin-top: 20upx;
+} */
+
+/**
+ * 定位
+ */
+.position-relative {
+	position: relative;
+}
+.position-absolute-center {
+	position: absolute;
+	top: 0;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	margin: auto;
+	justify-content: center;
+	align-items: center;
+}
+
+.position-absolute-center-bottom {
+	position: absolute;
+	bottom: 0;
+	left: 0;
+	right: 0;
+	align-items: center;
+}
+
+.position-absolute-right-top {
+	position: absolute;
+	right: 0;
+	top: 0;
+}
+
+.position-absolute-left-top {
+	position: absolute;
+	left: 0;
+	top: 0;
+}
+
+.position-absolute-right-bottom {
+	position: absolute;
+	right: 0;
+	bottom: 0;
+}
+
+/* 100 - Thin
+200 - Extra Light (Ultra Light)
+300 - Light
+400 - Regular (Normal、Book、Roman)
+500 - Medium
+600 - Semi Bold (Demi Bold)
+700 - Bold
+800 - Extra Bold (Ultra Bold)
+900 - Black (Heavy) */
+
+.text-regular{
+	font-weight: 400;
+}
+
+.text-medium {
+	font-size: 400;
+}
+
+
+
+
+/* ==================
+         蒙层 透明度
+ ==================== */
+.mask-bg-07 {
+	background-color: rgba(0, 0, 0, 0.7);
+}
+
+

+ 79 - 0
util/util-js/AccAndOri.js

@@ -0,0 +1,79 @@
+/**
+ * 绑定加速计
+ */
+function bindAcc(callback,callbackValue) {
+	let id = null;
+	console.log("监听加速计");
+	id = plus.accelerometer.watchAcceleration((a) => {
+		uni.$emit('watchAcceleration', a);
+		if(callbackValue){
+			callbackValue(a);
+		}
+		// console.log(a);
+	}, function(e) {
+		console.log("监听失败:" + e.message);
+		if (id) {
+			plus.accelerometer.clearWatch(id);
+			id = null;
+		}
+	}, {
+		frequency: 20
+	});
+	console.log("监听加速计 id:",id);
+	callback(id);
+}
+
+/**
+ * 绑定陀螺仪
+ */
+function bindOri(callback,callbackValue) {
+	let id = null;
+	console.log("监听陀螺仪");
+	id = plus.orientation.watchOrientation(function(o) {
+		uni.$emit('watchOrientation', o);
+		if(callbackValue){
+			callbackValue(o);
+		}
+	}, function(e) {
+		console.log("监听失败:" + e.message);
+		if (id) {
+			plus.orientation.clearWatch(id);
+			id = null;
+		}
+	}, {
+		frequency: 60
+	});
+	console.log("监听陀螺仪 id:",id);
+	callback(id);
+}
+
+/**
+ * 解除加速计绑定
+ */
+function unBindAcc(accId) {
+	console.log("解除加速计绑定:",accId);
+	if (accId) {
+		plus.accelerometer.clearWatch(accId);
+	} else {
+		console.log("没有监听设备加速变化");
+	}
+}
+/**
+ * 解除陀螺仪绑定
+ */
+function unBindOri(oriId) {
+	console.log("解除陀螺仪绑定:",oriId);
+	if (oriId) {
+		plus.orientation.clearWatch(oriId);
+	} else {
+		console.log("没有监听设备方向变化");
+	}
+}
+
+
+export default {
+	bindAcc,
+	unBindAcc,
+	bindOri,
+	unBindOri
+}

+ 77 - 0
util/util-js/Animation.js

@@ -0,0 +1,77 @@
+var Timing = {
+	easeIn: function easeIn(pos) {
+		return Math.pow(pos, 3);
+	},
+	easeOut: function easeOut(pos) {
+		return Math.pow(pos - 1, 3) + 1;
+	},
+	easeInOut: function easeInOut(pos) {
+		if ((pos /= 0.5) < 1) {
+			return 0.5 * Math.pow(pos, 3);
+		} else {
+			return 0.5 * (Math.pow(pos - 2, 3) + 2);
+		}
+	},
+	linear: function linear(pos) {
+		return pos;
+	}
+};
+
+function Animation(opts) {
+	this.isStop = false;
+	opts.duration = typeof opts.duration === 'undefined' ? 1000 : opts.duration;
+	opts.timing = opts.timing || 'linear';
+	var delay = 17;
+
+	function createAnimationFrame() {
+		if (typeof setTimeout !== 'undefined') {
+			return function(step, delay) {
+				setTimeout(function() {
+					var timeStamp = +new Date();
+					step(timeStamp);
+				}, delay);
+			};
+		} else if (typeof requestAnimationFrame !== 'undefined') {
+			return requestAnimationFrame;
+		} else {
+			return function(step) {
+				step(null);
+			};
+		}
+	};
+	var animationFrame = createAnimationFrame();
+	var startTimeStamp = null;
+	var _step = function step(timestamp) {
+		if (timestamp === null || this.isStop === true) {
+			opts.onProcess && opts.onProcess(1);
+			opts.onAnimationFinish && opts.onAnimationFinish();
+			return;
+		}
+		if (startTimeStamp === null) {
+			startTimeStamp = timestamp;
+		}
+		if (timestamp - startTimeStamp < opts.duration) {
+			var process = (timestamp - startTimeStamp) / opts.duration;
+			var timingFunction = Timing[opts.timing];
+			process = timingFunction(process);
+
+			opts.onProcess && opts.onProcess(process);
+			animationFrame(_step, delay);
+		} else {
+			opts.onProcess && opts.onProcess(1);
+			opts.onAnimationFinish && opts.onAnimationFinish();
+		}
+	};
+	_step = _step.bind(this);
+	animationFrame(_step, delay);
+}
+
+// stop animation immediately
+// and tigger onAnimationFinish
+Animation.prototype.stop = function() {
+	this.isStop = true;
+};
+
+if (typeof module === "object" && typeof module.exports === "object") {
+	module.exports = Animation;
+}

+ 147 - 0
util/util-js/BLE.js

@@ -0,0 +1,147 @@
+// 灵敏度
+// ArrayBuffer转16进制字符串示例
+function ab2hext(buffer) {
+	var hexArr = Array.prototype.map.call(
+		new Uint8Array(buffer),
+		function(bit) {
+			return ('00' + bit.toString(16)).slice(-2)
+		}
+	)
+	return hexArr.join('');
+}
+function buf2hex(buffer) {
+ 
+   return Array.prototype.map.call(new Uint8Array(buffer), x => ('00' + 
+         x.toString(16)).slice(-2)).join('');
+ 
+}
+// 字符串转为ArrayBuffer对象,参数为字符串
+function str2ab(str) {
+	var buf = new ArrayBuffer(str.length * 2); // 每个字符占用2个字节
+	var bufView = new Uint16Array(buf);
+	for (var i = 0, strLen = str.length; i < strLen; i++) {
+		bufView[i] = str.charCodeAt(i);
+	}
+	return buf;
+}
+//16进制的字符串 转换为整数
+function hex2int(hex) {
+	var len = hex.length,
+		a = new Array(len),
+		code;
+	for (var i = 0; i < len; i++) {
+		code = hex.charCodeAt(i);
+		if (48 <= code && code < 58) {
+			code -= 48;
+		} else {
+			code = (code & 0xdf) - 65 + 10;
+		}
+		a[i] = code;
+	}
+
+	return a.reduce(function(acc, c) {
+		acc = 16 * acc + c;
+		return acc;
+	}, 0);
+}
+//16进制转有符号的整数
+function hexToSignedInt(hex) {
+	let two = parseInt(hex, 16).toString(2);
+	let bitNum = hex.length * 4;
+	if (two.length < bitNum) {
+		while (two.length < bitNum) {
+			two = "0" + two;
+		}
+	}
+
+	if (two.substring(0, 1) == "0") {
+		two = parseInt(two, 2);
+
+		return two;
+	} else {
+		let two_unsign = "";
+		two = parseInt(two, 2) - 1;
+		two = two.toString(2);
+		two_unsign = two.substring(1, bitNum);
+		two_unsign = two_unsign.replace(/0/g, "z");
+		two_unsign = two_unsign.replace(/1/g, "0");
+		two_unsign = two_unsign.replace(/z/g, "1");
+		two = parseInt(-two_unsign, 2);
+
+		return two;
+	}
+}
+//十六进制转ASCII码
+function hexCharCodeToStr(hexCharCodeStr) {
+	var trimedStr = hexCharCodeStr.trim();
+	var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;
+	var len = rawStr.length;
+	if (len % 2 !== 0) {
+		alert("存在非法字符!");
+		return "";
+	}
+	var curCharCode;
+	var resultStr = [];
+	for (var i = 0; i < len; i = i + 2) {
+		curCharCode = parseInt(rawStr.substr(i, 2), 16);
+		resultStr.push(String.fromCharCode(curCharCode));
+	}
+	return resultStr.join("");
+}
+
+//ASCII码转16进制
+function strToHexCharCode(str) {
+	if (str === "") {
+		return "";
+	} else {
+		var hexCharCode = [];
+		hexCharCode.push("0x");
+		for (var i = 0; i < str.length; i++) {
+			hexCharCode.push((str.charCodeAt(i)).toString(16));
+		}
+		return hexCharCode.join("");
+	}
+}
+
+//16进制转字符串
+function hexToString(str) {
+	var trimedStr = str.trim();
+	var rawStr =
+		trimedStr.substr(0, 2).toLowerCase() === "0x" ?
+		trimedStr.substr(2) :
+		trimedStr;
+	var len = rawStr.length;
+	if (len % 2 !== 0) {
+		// alert("Illegal Format ASCII Code!");
+		return "";
+	}
+	var curCharCode;
+	var resultStr = [];
+	for (var i = 0; i < len; i = i + 2) {
+		curCharCode = parseInt(rawStr.substr(i, 2), 16); // ASCII Code Value
+		resultStr.push(String.fromCharCode(curCharCode));
+	}
+	return resultStr.join("");
+}
+
+
+
+function getRSSITransDistance(rssi) {
+	return Math.pow(Math.E, (Math.abs(rssi) - 66.78) / 16.56);
+}
+
+
+
+export default {
+	getRSSITransDistance,
+	
+	ab2hext,
+	buf2hex,
+	str2ab,
+	hex2int,
+	hexToSignedInt,
+	hexCharCodeToStr,
+	strToHexCharCode,
+	hexToString
+
+}

+ 689 - 0
util/util-js/EquipmentAction.js

@@ -0,0 +1,689 @@
+let assign = function (target, ...varArgs) {
+	if (target == null) {
+		throw new TypeError('Cannot convert undefined or null to object');
+	}
+	if (!varArgs || varArgs.length <= 0) {
+		return target;
+	}
+	// 深度合并对象
+	function deepAssign(obj1, obj2) {
+		for (let key in obj2) {
+			obj1[key] = obj1[key] && obj1[key].toString() === "[object Object]" ?
+				deepAssign(obj1[key], obj2[key]) : obj1[key] = obj2[key];
+		}
+		return obj1;
+	}
+
+	varArgs.forEach(val => {
+		target = deepAssign(target, val);
+	});
+	return target;
+};
+
+function Event() {
+	this.events = {};
+}
+Event.prototype.addEventListener = function (type, listener) {
+	this.events[type] = this.events[type] || [];
+	this.events[type].push(listener);
+};
+Event.prototype.trigger = function () {
+	for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+		args[_key] = arguments[_key];
+	}
+
+	var type = args[0];
+	var params = args.slice(1);
+	if (!!this.events[type]) {
+		// console.log("type:",type);
+		this.events[type].forEach(function (listener) {
+			try {
+				listener.apply(null, params);
+			} catch (e) {
+				console.error(e);
+			}
+		});
+	}
+};
+
+var EquipmentAction = function EquipmentAction() {
+	let opts = {
+		//合力计算
+		oldResultantDifference: 0,
+		resultantDifference: 0,
+		bCalResultant: false,
+
+		//最大的差值
+		resultantMaxDifference: 0,
+		//最大的加速度
+		resultantMaxX: 0,
+		resultantMaxZ: 0,
+		resultantMaxY: 0,
+
+		resultantMaxAddCount: 0,
+		resultAddDifferenceCount: 0,
+
+		xA: 0,
+		oldxA: 0,
+		zA: 0,
+		oldzA: 0,
+
+		yA: 0,
+		oldyA: 0,
+
+		//初始化
+		initX: false,
+		initZ: false,
+
+		initY: false,
+
+		mass: 5,
+
+		//是否限制回弹,true 是限制回弹,false 是快速打击
+		bLimitRebound: true
+	}
+	this.opts = opts;
+
+	let runOpts = {
+		ValueNum: 4,
+		tempValue: [], //用于存放计算阈值的波峰波谷差值
+		tempCount: 0,
+		//是否上升的标志位
+		isDirectionUp: false,
+		//持续上升次数
+		continueUpCount: 0,
+		//上一点的持续上升的次数,为了记录波峰的上升次数
+		continueUpFormerCount: 0,
+		//上一点的状态,上升还是下降
+		lastStatus: false,
+		//波峰值
+		peakOfWave: 0,
+		//波谷值
+		valleyOfWave: 0,
+		//此次波峰的时间
+		timeOfThisPeak: 0,
+		//上次波峰的时间
+		timeOfLastPeak: 0,
+		//当前的时间
+		timeOfNow: 0,
+		//当前传感器的值
+		gravityNew: 0,
+		//上次传感器的值
+		gravityOld: 0,
+		//上传传感器的陀螺仪
+		gyroOld: 0,
+		//动态阈值需要动态的数据,这个值用于这些动态数据的阈值
+		InitialValue: 1.3,
+		//初始阈值
+		ThreadValue: 2.0,
+		//波峰波谷时间差
+		TimeInterval: 250,
+
+		//跳高
+		jumpStepCount: 0,
+		jumpTimeOfLastStep: 0,
+		jumpTimeOfThisStep: 0,
+		jumpAverageTimeOfEveryStep: 0,
+		//跑步
+		stepCount: 0,
+		timeOfLastStep: 0,
+		timeOfThisStep: 0,
+		averageTimeOfEveryStep: 0,
+
+		currentState: "idle"
+	}
+	this.runOpts = runOpts;
+
+
+	let gyroOpts = {
+		ValueNum: 4,
+		tempValue: [], //用于存放计算阈值的波峰波谷差值
+		tempCount: 0,
+		//是否上升的标志位
+		isDirectionUp: false,
+		//持续上升次数
+		continueUpCount: 0,
+		//上一点的持续上升的次数,为了记录波峰的上升次数
+		continueUpFormerCount: 0,
+		//上一点的状态,上升还是下降
+		lastStatus: false,
+		//波峰值
+		peakOfWave: 0,
+		//波谷值
+		valleyOfWave: 0,
+		//此次波峰的时间
+		timeOfThisPeak: 0,
+		//上次波峰的时间
+		timeOfLastPeak: 0,
+		//当前的时间
+		timeOfNow: 0,
+		//当前传感器的值
+		gravityNew: 0,
+		//上次传感器的值
+		gravityOld: 0,
+		//动态阈值需要动态的数据,这个值用于这些动态数据的阈值
+		InitialValue: 1.3,
+		//初始阈值
+		ThreadValue: 200.0,
+		//波峰波谷时间差
+		TimeInterval: 250,
+
+		bJump: false,
+	}
+	this.gyroOpts = gyroOpts;
+
+	this.event = new Event();
+
+	// console.log("hit instanl:",this.opts);
+}
+EquipmentAction.prototype.addEventListener = function (type, listener) {
+	this.event.addEventListener(type, listener);
+};
+
+/**
+ * 更新两轴数据
+ */
+EquipmentAction.prototype.updateAcc = function () {
+	let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+	// this.opts = assign({}, this.opts, data);
+	let bLimitRebound = data.bLimitRebound && this.opts.bLimitRebound;
+	//使用两个轴的数据,其实就是不计算重力轴的加速度
+	this.opts.xA = data.xA;
+	this.opts.zA = data.zA;
+
+	// console.log(bLimitRebound,data.bLimitRebound,this.opts.bLimitRebound);
+
+	//这里防止第一次触发调用
+	if (!this.opts.initX && this.opts.oldxA === 0) {
+		this.opts.oldxA = data.xA;
+		this.opts.initX = true;
+		console.log("初始化oldxa");
+	}
+	if (!this.opts.initZ && this.opts.oldzA === 0) {
+		this.opts.oldzA = data.zA;
+		this.opts.initZ = true;
+		console.log("初始化oldza");
+	}
+
+	let _differenceX = this.opts.xA - this.opts.oldxA;
+	let _differenceZ = this.opts.zA - this.opts.oldzA;
+	this.opts.resultantDifference = Math.abs(_differenceX) + Math.abs(_differenceZ);
+
+	if (this.opts.oldResultantDifference != this.opts.resultantDifference && 0 !== this.opts.resultantDifference) {
+		//5  默认值是12
+		let _limitresultDifference = 12;
+		//如果是回弹限制时候,判断值等于5
+		if (bLimitRebound)
+			_limitresultDifference = 5;
+
+		if (this.opts.resultantDifference > _limitresultDifference) {
+			if (!this.opts.bCalResultant) {
+				//假如进入了一个计算周期
+				this.opts.bCalResultant = true;
+			}
+		}
+
+		if (this.opts.bCalResultant) {
+			if (this.opts.resultantMaxX <= this.opts.xA)
+				this.opts.resultantMaxX = this.opts.xA;
+			if (this.opts.resultantMaxZ <= this.opts.zA)
+				this.opts.resultantMaxZ = this.opts.zA;
+
+			if (this.opts.resultantMaxDifference <= this.opts.resultantDifference) {
+				this.opts.resultantMaxDifference = this.opts.resultantDifference;
+				this.opts.resultantMaxAddCount = 0;
+			} else {
+				this.opts.resultantMaxAddCount++;
+				//小于最大值的个数判断,超过限制,说明波动下滑
+				// > 4
+				if (this.opts.resultantMaxAddCount >= 4) {
+					//这里区分两个版本,bLimitRebound:true一个是限制回弹版,bLimitRebound:false一个是快速打击版本
+					if (bLimitRebound) {
+						if (this.opts.resultantDifference <= 3) {
+							this.opts.resultAddDifferenceCount++;
+							// 当波动值小于3 次数到达5次,判断达到一个平稳状态
+							if (this.opts.resultAddDifferenceCount >= 5) {
+								let _resultantMaxAcc = Math.abs(this.opts.resultantMaxX) + Math.abs(this.opts.resultantMaxZ);
+
+								this.opts.bCalResultant = false;
+								this.opts.resultantMaxAddCount = 0;
+								this.opts.resultAddDifferenceCount = 0;
+								//成功判断打击直拳 todo return
+								this.event.trigger('resultantHit', {
+									type: "hit",
+									acc: _resultantMaxAcc,
+									power: Math.ceil(_resultantMaxAcc * this.opts.mass),
+									mass: this.opts.mass
+								});
+
+
+								this.opts.oldResultantDifference = 0;
+								this.opts.resultantDifference = 0;
+								this.opts.resultantMaxDifference = 0;
+								this.opts.resultantMaxX = 0;
+								this.opts.resultantMaxZ = 0;
+								// this.opts.oldxA = 0;
+								// this.opts.oldzA = 0;
+
+							}
+						} else {
+							this.opts.resultAddDifferenceCount = 0;
+						}
+					} else {
+						let _resultantMaxAcc = Math.abs(this.opts.resultantMaxX) + Math.abs(this.opts.resultantMaxZ);
+
+						this.opts.bCalResultant = false;
+						this.opts.resultantMaxAddCount = 0;
+						this.opts.resultAddDifferenceCount = 0;
+						//成功判断打击直拳 todo return
+						this.event.trigger('resultantHit', {
+							type: "hit",
+							acc: _resultantMaxAcc,
+							power: Math.ceil(_resultantMaxAcc * this.opts.mass),
+							mass: this.opts.mass
+						});
+
+
+						this.opts.oldResultantDifference = 0;
+						this.opts.resultantDifference = 0;
+						this.opts.resultantMaxDifference = 0;
+						this.opts.resultantMaxX = 0;
+						this.opts.resultantMaxZ = 0;
+						// this.opts.oldxA = 0;
+						// this.opts.oldzA = 0;
+					}
+
+				}
+			}
+		}
+
+		this.opts.oldResultantDifference = this.opts.resultantDifference;
+
+	}
+	this.opts.oldxA = this.opts.xA;
+	this.opts.oldzA = this.opts.zA;
+};
+
+/**
+ * 更新三轴数据
+ */
+EquipmentAction.prototype.updateTriaxialAcc = function () {
+	let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+	// this.opts = assign({}, this.opts, data);
+	let bLimitRebound = data.bLimitRebound && this.opts.bLimitRebound;
+	//使用三个轴的数据,计算重力轴的加速度。最后减去重力的加速度值
+	this.opts.xA = data.xA;
+	this.opts.zA = data.zA;
+	this.opts.yA = data.yA;
+
+	// console.log(bLimitRebound,data.bLimitRebound,this.opts.bLimitRebound);
+
+	//这里防止第一次触发调用
+	if (!this.opts.initX && this.opts.oldxA === 0) {
+		this.opts.oldxA = data.xA;
+		this.opts.initX = true;
+		console.log("初始化oldxa");
+	}
+	if (!this.opts.initZ && this.opts.oldzA === 0) {
+		this.opts.oldzA = data.zA;
+		this.opts.initZ = true;
+		console.log("初始化oldza");
+	}
+
+	if (!this.opts.initY && this.opts.oldyA === 0) {
+		this.opts.oldyA = data.yA;
+		this.opts.initY = true;
+		console.log("初始化oldyA");
+	}
+
+	let _differenceX = this.opts.xA - this.opts.oldxA;
+	let _differenceZ = this.opts.zA - this.opts.oldzA;
+	let _differenceY = this.opts.yA - this.opts.oldyA;
+
+	// let gravityNew = Math.sqrt(xA * xA + yA * yA + zA * zA);
+
+	// this.opts.resultantDifference = Math.abs(_differenceX) + Math.abs(_differenceZ) + Math.abs(_differenceY);
+	this.opts.resultantDifference = Math.sqrt(_differenceX * _differenceX + _differenceZ * _differenceZ + _differenceY *
+		_differenceY);
+
+	if (this.opts.oldResultantDifference != this.opts.resultantDifference && 0 !== this.opts.resultantDifference) {
+		//5  默认值是12
+		let _limitresultDifference = 12;
+		//如果是回弹限制时候,判断值等于5
+		if (bLimitRebound)
+			_limitresultDifference = 5;
+
+		if (this.opts.resultantDifference > _limitresultDifference) {
+			if (!this.opts.bCalResultant) {
+				//假如进入了一个计算周期
+				this.opts.bCalResultant = true;
+			}
+		}
+
+		if (this.opts.bCalResultant) {
+
+			if (this.opts.resultantMaxDifference <= this.opts.resultantDifference) {
+				this.opts.resultantMaxDifference = this.opts.resultantDifference;
+				this.opts.resultantMaxAddCount = 0;
+			} else {
+				this.opts.resultantMaxAddCount++;
+				//小于最大值的个数判断,超过限制,说明波动下滑
+				// > 4
+				if (this.opts.resultantMaxAddCount >= 4) {
+					//这里区分两个版本,bLimitRebound:true一个是限制回弹版,bLimitRebound:false一个是快速打击版本
+					if (bLimitRebound) {
+						if (this.opts.resultantDifference <= 3) {
+							this.opts.resultAddDifferenceCount++;
+							// 当波动值小于3 次数到达5次,判断达到一个平稳状态
+							if (this.opts.resultAddDifferenceCount >= 5) {
+								// let _resultantMaxAcc = Math.abs(this.opts.resultantMaxX) + Math.abs(this.opts.resultantMaxZ) + Math.abs(this.opts.resultantMaxY);
+								// console.log("this.opts.resultantMaxDifference:",this.opts.resultantMaxDifference);
+								this.opts.bCalResultant = false;
+								this.opts.resultantMaxAddCount = 0;
+								this.opts.resultAddDifferenceCount = 0;
+								//成功判断打击直拳 todo return
+								this.event.trigger('resultantHit', {
+									type: "hit",
+									acc: this.opts.resultantMaxDifference,
+									power: Math.ceil(this.opts.resultantMaxDifference * this.opts.mass),
+									mass: this.opts.mass
+								});
+
+
+								this.opts.oldResultantDifference = 0;
+								this.opts.resultantDifference = 0;
+								this.opts.resultantMaxDifference = 0;
+								this.opts.resultantMaxX = 0;
+								this.opts.resultantMaxZ = 0;
+								this.opts.resultantMaxY = 0;
+
+							}
+						} else {
+							this.opts.resultAddDifferenceCount = 0;
+						}
+					} else {
+
+						this.opts.bCalResultant = false;
+						this.opts.resultantMaxAddCount = 0;
+						this.opts.resultAddDifferenceCount = 0;
+						//成功判断打击直拳 todo return
+						this.event.trigger('resultantHit', {
+							type: "hit",
+							acc: this.opts.resultantMaxDifference,
+							power: Math.ceil(this.opts.resultantMaxDifference * this.opts.mass),
+							mass: this.opts.mass
+						});
+
+
+						this.opts.oldResultantDifference = 0;
+						this.opts.resultantDifference = 0;
+						this.opts.resultantMaxDifference = 0;
+						this.opts.resultantMaxX = 0;
+						this.opts.resultantMaxZ = 0;
+						this.opts.resultantMaxY = 0;
+
+					}
+
+				}
+			}
+		}
+
+		this.opts.oldResultantDifference = this.opts.resultantDifference;
+
+	}
+	this.opts.oldxA = this.opts.xA;
+	this.opts.oldzA = this.opts.zA;
+	this.opts.oldyA = this.opts.yA;
+};
+
+EquipmentAction.prototype.updateJumpAndRun = function () {
+	let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+	//使用三个轴的数据,计算重力轴的加速度。最后减去重力的加速度值
+
+	//********加速计********
+	let { ax, ay, az } = data.acc;
+	ax = ax * 9.80665;
+	ay = ay * 9.80665;
+	az = az * 9.80665;
+	let gravityNew = Math.sqrt(ax * ax + ay * ay + az * az);
+
+	let { gx, gy, gz } = data.gyro;
+	let gyroNew = Math.sqrt(gx * gx + gy * gy + gz * gz);
+
+
+	this.detectorNewStep(gravityNew, gyroNew);
+};
+
+
+
+/*
+ * 检测步子,并开始计步
+ * 1.传入数据
+ * 2.如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步
+ * 3.符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中
+ * */
+EquipmentAction.prototype.detectorNewStep = function (values, gyroValue) {
+	if (this.gyroOpts.gravityOld == 0) {
+		this.gyroOpts.gravityOld = gyroValue;
+	} else {
+
+		if (this.gyroDetectorPeak(gyroValue, this.gyroOpts.gravityOld)) {
+			let step1 = this.gyroOpts.peakOfWave - this.gyroOpts.valleyOfWave;
+			// if(step>10)
+			// 	console.log("Gyro:", step);
+
+			if (step1 > this.gyroOpts.ThreadValue) {
+				this.gyroOpts.timeOfThisPeak = this.gyroOpts.timeOfNow;
+				this.gyroOpts.bJump = true;
+			}
+		}
+	}
+	if (this.runOpts.gravityOld == 0) {
+		this.runOpts.gravityOld = values;
+	} else {
+		if (this.detectorPeak(values, this.runOpts.gravityOld)) {
+			this.runOpts.timeOfLastPeak = this.runOpts.timeOfThisPeak;
+			this.runOpts.timeOfNow = new Date().getTime();
+			let step2 = this.runOpts.peakOfWave - this.runOpts.valleyOfWave;
+
+			if (this.runOpts.timeOfNow - this.runOpts.timeOfLastPeak >= this.runOpts.TimeInterval
+				&& step2 > this.runOpts.ThreadValue) {
+				this.runOpts.timeOfThisPeak = this.runOpts.timeOfNow;
+				this.countRunStep();
+			}
+			// if (this.runOpts.timeOfNow - this.runOpts.timeOfLastPeak >= this.runOpts.TimeInterval
+			// 	&& (this.runOpts.peakOfWave - this.runOpts.valleyOfWave >= this.runOpts.InitialValue)) {
+			// 	this.runOpts.timeOfThisPeak = this.runOpts.timeOfNow;
+			// 	this.runOpts.ThreadValue = this.peakValleyThread(this.runOpts.peakOfWave - this.runOpts.valleyOfWave);
+			// }
+		}
+	}
+	this.runOpts.gravityOld = values;
+	this.gyroOpts.gravityOld = gyroValue;
+}
+
+EquipmentAction.prototype.countRunStep = function () {
+
+	this.runOpts.timeOfLastStep = this.runOpts.timeOfThisStep;
+	this.runOpts.timeOfThisStep = new Date().getTime();
+	let diffValue = this.runOpts.timeOfThisStep - this.runOpts.timeOfLastStep;
+	if (diffValue <= 2000) {
+
+		if (this.gyroOpts.bJump) {
+			let step = this.runOpts.peakOfWave - this.runOpts.valleyOfWave;
+			this.event.trigger('resultant', {
+				type: "jump",
+				acc: step
+			});
+			this.resetJumpValue();
+			// this.resSomeValue();
+		} 
+		// else 
+		// {
+			this.runOpts.averageTimeOfEveryStep += diffValue;
+			this.runOpts.stepCount++;
+			// if (this.runOpts.stepCount == 2) 
+			{
+				this.runOpts.averageTimeOfEveryStep = this.runOpts.averageTimeOfEveryStep / 2;
+				// this.runOpts.currentState = "runing";
+				let step = this.runOpts.peakOfWave - this.runOpts.valleyOfWave;
+				this.resSomeValue();
+				this.event.trigger('resultant', {
+					type: "runing",
+					acc: step
+				});
+			}
+		// }
+
+	} else { //超时,说明没有运动了
+		this.resSomeValue();
+		console.log("超时", "averageTimeOfEveryStep: " + this.runOpts.averageTimeOfEveryStep);
+		if (this.gyroOpts.bJump) {
+			//判断是否跳
+			let step = this.runOpts.peakOfWave - this.runOpts.valleyOfWave;
+			this.event.trigger('resultant', {
+				type: "jump",
+				acc: step
+			});
+			this.resetJumpValue();
+		}
+	}
+
+}
+
+
+EquipmentAction.prototype.resSomeValue = function () {
+	this.runOpts.stepCount = 0;
+	this.runOpts.averageTimeOfEveryStep = 0;
+
+
+}
+
+EquipmentAction.prototype.resetJumpValue = function () {
+	// this.runOpts.jumpStepCount = 0;
+	// this.runOpts.jumpAverageTimeOfEveryStep = 0;
+	this.gyroOpts.bJump = false;
+}
+
+
+/*
+ * 检测波峰
+ * 以下四个条件判断为波峰:
+ * 1.目前点为下降的趋势:isDirectionUp为false
+ * 2.之前的点为上升的趋势:lastStatus为true
+ * 3.到波峰为止,持续上升大于等于2次
+ * 4.波峰值大于20
+ * 记录波谷值
+ * 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值
+ * 2.所以要记录每次的波谷值,为了和下次的波峰做对比
+ * */
+EquipmentAction.prototype.detectorPeak = function (newValue, oldValue) {
+	this.runOpts.lastStatus = this.runOpts.isDirectionUp;
+	if (newValue >= oldValue) {
+		this.runOpts.isDirectionUp = true;
+		this.runOpts.continueUpCount++;
+	} else {
+		this.runOpts.continueUpFormerCount = this.runOpts.continueUpCount;
+		this.runOpts.continueUpCount = 0;
+		this.runOpts.isDirectionUp = false;
+	}
+	//this.runOpts.continueUpFormerCount >= 2 || oldValue >= 20
+	if (!this.runOpts.isDirectionUp && this.runOpts.lastStatus &&
+		(this.runOpts.continueUpFormerCount >= 2)) {
+		this.runOpts.peakOfWave = oldValue;
+		return true;
+	} else if (!this.runOpts.lastStatus && this.runOpts.isDirectionUp) {
+		this.runOpts.valleyOfWave = oldValue;
+		return false;
+	} else {
+		return false;
+	}
+}
+
+/*
+ * 检测波峰
+ * 以下四个条件判断为波峰:
+ * 1.目前点为下降的趋势:isDirectionUp为false
+ * 2.之前的点为上升的趋势:lastStatus为true
+ * 3.到波峰为止,持续上升大于等于2次
+ * 4.波峰值大于20
+ * 记录波谷值
+ * 1.观察波形图,可以发现在出现步子的地方,波谷的下一个就是波峰,有比较明显的特征以及差值
+ * 2.所以要记录每次的波谷值,为了和下次的波峰做对比
+ * */
+EquipmentAction.prototype.gyroDetectorPeak = function (newValue, oldValue) {
+	this.gyroOpts.lastStatus = this.gyroOpts.isDirectionUp;
+	if (newValue >= oldValue) {
+		this.gyroOpts.isDirectionUp = true;
+		this.gyroOpts.continueUpCount++;
+	} else {
+		this.gyroOpts.continueUpFormerCount = this.gyroOpts.continueUpCount;
+		this.gyroOpts.continueUpCount = 0;
+		this.gyroOpts.isDirectionUp = false;
+	}
+	//this.runOpts.continueUpFormerCount >= 2 || oldValue >= 20
+	if (!this.gyroOpts.isDirectionUp && this.gyroOpts.lastStatus &&
+		(this.gyroOpts.continueUpFormerCount >= 2)) {
+		this.gyroOpts.peakOfWave = oldValue;
+		return true;
+	} else if (!this.gyroOpts.lastStatus && this.gyroOpts.isDirectionUp) {
+		this.gyroOpts.valleyOfWave = oldValue;
+		return false;
+	} else {
+		return false;
+	}
+}
+
+/*
+ * 阈值的计算
+ * 1.通过波峰波谷的差值计算阈值
+ * 2.记录4个值,存入tempValue[]数组中
+ * 3.在将数组传入函数averageValue中计算阈值
+ * */
+EquipmentAction.prototype.peakValleyThread = function (value) {
+	let tempThread = this.runOpts.ThreadValue;
+	if (this.runOpts.tempCount < this.runOpts.ValueNum) {
+		this.runOpts.tempValue[this.runOpts.tempCount] = value;
+		this.runOpts.tempCount++;
+	} else {
+		tempThread = this.averageValue(this.runOpts.tempValue, this.runOpts.ValueNum);
+		for (let i = 1; i < this.runOpts.ValueNum; i++) {
+			this.runOpts.tempValue[i - 1] = this.runOpts.tempValue[i];
+		}
+		this.runOpts.tempValue[this.runOpts.ValueNum - 1] = value;
+	}
+	return tempThread;
+}
+
+/*
+ * 梯度化阈值
+ * 1.计算数组的均值
+ * 2.通过均值将阈值梯度化在一个范围里
+ * */
+EquipmentAction.prototype.averageValue = function (value, n) {
+	let ave = 0;
+	for (let i = 0; i < n; i++) {
+		ave += value[i];
+	}
+	ave = ave / this.runOpts.ValueNum;
+	// console.log("ave:", ave);
+	if (ave >= 8)
+		ave = 4.3;
+	else if (ave >= 7 && ave < 8)
+		ave = 3.3;
+	else if (ave >= 4 && ave < 7)
+		ave = 2.3;
+	else if (ave >= 3 && ave < 4)
+		ave = 2.0;
+	else {
+		ave = 1.3;
+	}
+	return ave;
+}
+
+
+
+if (typeof module === "object" && typeof module.exports === "object") {
+	module.exports = EquipmentAction;
+	//export default EquipmentAction;//建议使用nodejs的module导出方式,如报错请使用export方式导出
+}

+ 373 - 0
util/util-js/action/jump-0.1.js

@@ -0,0 +1,373 @@
+/**
+ * 跳判断相关脚本代码
+ */
+
+function Event() {
+	this.events = {};
+}
+Event.prototype.addEventListener = function (type, listener) {
+	this.events[type] = this.events[type] || [];
+	this.events[type].push(listener);
+};
+Event.prototype.trigger = function () {
+	for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+		args[_key] = arguments[_key];
+	}
+
+	var type = args[0];
+	var params = args.slice(1);
+	if (!!this.events[type]) {
+		// console.log("type:",type);
+		this.events[type].forEach(function (listener) {
+			try {
+				listener.apply(null, params);
+			} catch (e) {
+				console.error(e);
+			}
+		});
+	}
+};
+var jumpOpts = {
+	//是否上升的标志位
+	isDirectionUp: false,
+	//持续上升次数
+	continueUpCount: 0,
+	//上一点的持续上升的次数,为了记录波峰的上升次数
+	continueUpFormerCount: 0,
+
+	continueDownCount: 0,
+	continueDownFormerCount: 0,
+
+	//上一点的状态,上升还是下降
+	lastStatus: false,
+	//波峰值
+	peakOfWave: 0,
+	//波谷值
+	valleyOfWave: 0,
+	//检测到极快的波动的次数
+	timeOfPeakCount: 0,
+	//开始添加
+	bUpdateTimeOfPeakCount: false,
+	//开始更新的次数
+	startCount: 0,
+	//停止跳
+	bStopJump: false,
+	//上次传感器的值
+	gravityOld: 0,
+
+	bUpState: false,
+}
+var ActionJump = function ActionJump() {
+
+	this.jumpOpts = jumpOpts;
+	//其他波峰波谷参数相关数组记录
+	this.peakOfWaveArray = [];
+	this.peakOfWaveMaxValue = 0;
+	this.valleyOfWaveArray = [];
+	this.valleyOfWaveMinValue = 0;
+
+	this.peakOfWaveArrayValue = [];
+	this.valleyOfWaveArrayValue = [];
+
+	this.peakOfWaveArrayValueLinear = [];
+	this.valleyOfWaveArrayValueLinear = [];
+
+
+	this.highestCount = 0;
+	//陀螺仪
+	this.oriGyroYArray = [];
+
+	this.isJumpTop = false;
+
+	this.event = new Event();
+
+
+	this.frameCapacity = 6;
+	this.frame = [];
+	this.frameLength = 5;
+	this.frameOffset = 0;
+
+	this.frameHitCapacity = 11;
+	this.frameHit = [];//打击后的n帧
+
+	for (var i = 0; i < this.frameCapacity; ++i) {
+		var o = new Object();
+		// o.acc = [0, 0, 0];
+		// o.gyr = [0, 0, 0];
+		o.resultant = 0;
+		this.frame.push(o);
+	}
+
+
+}
+ActionJump.prototype.addEventListener = function (type, listener) {
+	this.event.addEventListener(type, listener);
+};
+
+
+ActionJump.prototype.updateJump = function () {
+	let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+	//使用三个轴的数据,计算重力轴的加速度。最后减去重力的加速度值
+	//********加速计********
+	let {
+		lAccX,
+		lAccY,
+		lAccZ
+	} = data.linearAcc;
+	let {
+		oAccX,
+		oAccY,
+		oAccZ
+	} = data.oriAcc;
+	let {
+		oGyroX,
+		oGyroY,
+		oGyroZ
+	} = data.oriGyro;
+	let {
+		bYAxis
+	} = data;
+	let _tempAxisData = bYAxis ? oGyroY : oGyroX;
+	this.detectorNewStep(data.resultant, lAccX, lAccY, lAccZ, oAccX, oAccY, oAccZ, data.runIndex, _tempAxisData);
+};
+
+
+
+/*
+ * 检测步子,并开始计步
+ * 1.传入数据
+ * 2.如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步
+ * 3.符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中
+ * */
+ActionJump.prototype.detectorNewStep = function (resultant, linearX, linearY, linearZ, oriX, oriY, oriZ, _runIndex,
+	_oGyroY) {
+	let _judgmentValue = oriZ;
+	// if (this.jumpOpts.gravityOld == 0) {
+	// 	this.jumpOpts.gravityOld = _judgmentValue;
+	// } else {
+	if (!this.jumpOpts.bStopJump) {
+		// let {
+		// 	bState,
+		// 	bType,
+		// 	value
+		// } = this.detectorPeakOfWaveAndValleyOfWave(_judgmentValue, this.jumpOpts.gravityOld);
+		// let lastFrame = this.frame[(this.frameOffset + this.frameLength - 1) % this.frameCapacity];
+		// let last2Frame = this.frame[(this.frameOffset + this.frameLength - 2) % this.frameCapacity];
+		// let last3Frame = this.frame[(this.frameOffset + this.frameLength - 3) % this.frameCapacity];
+		// let last4Frame = this.frame[(this.frameOffset + this.frameLength - 4) % this.frameCapacity];
+		// let last5Frame = this.frame[(this.frameOffset + this.frameLength - 5) % this.frameCapacity];
+		let newFrame = this.frame[(this.frameOffset + this.frameLength) % this.frameCapacity];
+		newFrame.resultant = resultant;
+
+		if (resultant > 20 && !this.jumpOpts.bUpState) {
+			this.jumpOpts.bUpState = true;
+			this.isJumpTop = false;
+			this.highestCount = 0;
+			//陀螺仪部分
+			this.oriGyroYArray = [];
+			this.peakOfWaveArrayValue = [];
+			this.valleyOfWaveArrayValue = [];
+			this.peakOfWaveArrayValueLinear = [];
+			this.valleyOfWaveArrayValueLinear = [];
+
+			this.jumpOpts.startCount = 0;
+
+			// console.log("开始:", JSON.stringify(this.frame), '当前:', resultant);
+
+		}
+		if (this.jumpOpts.bUpState) {
+
+			if (_judgmentValue > 2) {
+				if (_judgmentValue > this.peakOfWaveMaxValue)
+					this.peakOfWaveMaxValue += _judgmentValue;
+				// this.peakOfWaveArrayValue.push(_judgmentValue);
+
+			}
+			else if (_judgmentValue < -2) {
+				if (_judgmentValue < this.valleyOfWaveMinValue)
+					this.valleyOfWaveMinValue += _judgmentValue;
+				// this.valleyOfWaveArrayValue.push(_judgmentValue);
+
+			}
+			// if (linearZ > 2)
+			// 	this.peakOfWaveArrayValueLinear.push(linearZ);
+			// else if (linearZ < -2)
+			// 	this.valleyOfWaveArrayValueLinear.push(linearZ);
+
+			if (Math.abs(_oGyroY) > 5)
+				this.oriGyroYArray.push(_oGyroY);
+			//出现极值后
+			// Math.abs(linearZ) < 7 &&
+			if (Math.abs(resultant) < 9.8) {
+				console.log('出现极值后:', linearZ, resultant);
+				// this.isJumpTop = true;
+				this.highestCount++;
+				if (this.highestCount >= 1) {
+					//达到最高点,
+					this.jumpOpts.bStopJump = true;
+					this.jumpOpts.bUpdateTimeOfPeakCount = true;
+					// this.isJumpTop = false;
+
+					let _currentMaxValue = 0;
+					// console.log("highestCount peakOfWaveArray", JSON.stringify(this.peakOfWaveArray));
+					// console.log("highestCount valleyOfWaveArray", JSON.stringify(this.valleyOfWaveArray));
+
+					// let allPeakOfWave = 0;
+					// for (let i = 0; i < this.peakOfWaveArrayValue.length; i++) {
+					// 	allPeakOfWave += this.peakOfWaveArrayValue[i];
+					// }
+
+					// let allValleyOfWave = 0;
+					// for (let i = 0; i < this.valleyOfWaveArrayValue.length; i++) {
+					// 	allValleyOfWave += this.valleyOfWaveArrayValue[i];
+					// }
+
+					// let allPeakOfWaveLinear = 0;
+					// for (let i = 0; i < this.peakOfWaveArrayValueLinear.length; i++) {
+					// 	allPeakOfWaveLinear += this.peakOfWaveArrayValueLinear[i];
+					// }
+
+					// let allValleyOfWaveLinear = 0;
+					// for (let i = 0; i < this.valleyOfWaveArrayValueLinear.length; i++) {
+					// 	allValleyOfWaveLinear += this.valleyOfWaveArrayValueLinear[i];
+					// }
+
+					// console.log("highestCount peakOfWaveArrayValue", JSON.stringify(this.peakOfWaveArrayValue));
+					// console.log("highestCount valleyOfWaveArrayValue", JSON.stringify(this.valleyOfWaveArrayValue));
+					// console.log("ori总值 peak:"+allPeakOfWave+" valley:"+allValleyOfWave);
+					// console.log("linear总值 peak:"+allPeakOfWaveLinear+" valley:"+allValleyOfWaveLinear);
+					// console.log("达到最高点时候数值 Max:", this.peakOfWaveMaxValue, " min:", this.valleyOfWaveMinValue);
+					//(Math.abs(this.peakOfWaveMaxValue) > 5 && Math.abs(this.valleyOfWaveMinValue) - Math
+					//  .abs(this.peakOfWaveMaxValue) < 10) ||
+					if (Math.abs(this.peakOfWaveMaxValue) > Math.abs(this.valleyOfWaveMinValue)) {
+						_currentMaxValue = this.peakOfWaveMaxValue;
+					} else {
+						_currentMaxValue = this.valleyOfWaveMinValue;
+					}
+
+					let allOGyroValue = 0;
+					for (let i = 0; i < this.oriGyroYArray.length; i++) {
+						allOGyroValue += this.oriGyroYArray[i];
+					}
+					allOGyroValue /= this.oriGyroYArray.length;
+
+					// this.event.trigger('resultant', {
+					// 	type: "jump",
+					// 	acc: _currentMaxValue,
+					// 	value: resultant
+					// });
+
+					// this.event.trigger('resultant', {
+					// 	type: "curAngle",
+					// 	value: _currentMaxValue,
+					// 	resultant: resultant
+					// });
+
+					// this.event.trigger('resultant', {
+					// 	type: "rotate",
+					// 	value: allOGyroValue,
+					// 	resultant: resultant
+					// });
+					//后面通用使用这个类型传输数据
+					this.event.trigger('resultant', {
+						type: "stateDataOfJump",
+						currentMaxValue: _currentMaxValue,
+						peakOfWaveMaxValue: this.peakOfWaveMaxValue,
+						valleyOfWaveMinValue: this.valleyOfWaveMinValue,
+						oGyroValue: allOGyroValue,
+						resultant: resultant,
+						name: "highestCountEnd"
+					});
+					this.jumpOpts.bUpState = false;
+				}
+
+			}
+		}
+		if ((this.frameOffset += 1) >= this.frameCapacity) {
+			this.frameOffset -= this.frameCapacity;
+		}
+	} else if (this.jumpOpts.bUpdateTimeOfPeakCount) {
+		this.jumpOpts.timeOfPeakCount++;
+		//todo 如果直跳,可以调节更小的 limitTimeOfPeakCount
+		let limitTimeOfPeakCount = 30;
+		if (this.jumpOpts.timeOfPeakCount >= limitTimeOfPeakCount) {
+			this.jumpOpts.timeOfPeakCount = 0;
+			this.jumpOpts.bStopJump = false;
+			this.event.trigger('resultant', {
+				type: "stop"
+			});
+			console.log("timeOfPeakCount >= " + limitTimeOfPeakCount);
+			this.resetAll();
+			this.jumpOpts.bUpdateTimeOfPeakCount = false;
+		}
+	}
+	// this.event.trigger('resultant', {
+	// 	type: "bUpdateDraw",
+	// 	linearX: linearX,
+	// 	linearZ: linearZ,
+	// 	linearY: linearY,
+	// 	oriX: oriX,
+	// 	oriY: oriY,
+	// 	oriZ: oriZ
+	// });
+}
+
+
+ActionJump.prototype.detectorPeakOfWaveAndValleyOfWave = function (newValue, oldValue) {
+	this.jumpOpts.lastStatus = this.jumpOpts.isDirectionUp;
+	if (newValue >= oldValue) {
+		this.jumpOpts.continueDownFormerCount = this.jumpOpts.continueDownCount;
+		this.jumpOpts.continueDownCount = 0;
+		this.jumpOpts.isDirectionUp = true;
+		this.jumpOpts.continueUpCount++;
+	} else {
+		this.jumpOpts.continueUpFormerCount = this.jumpOpts.continueUpCount;
+		this.jumpOpts.continueUpCount = 0;
+		this.jumpOpts.isDirectionUp = false;
+		this.jumpOpts.continueDownCount++;
+	}
+	if (!this.jumpOpts.isDirectionUp && this.jumpOpts.lastStatus && this.jumpOpts.continueUpFormerCount >= 2 && Math
+		.abs(oldValue) > 4) {
+		this.jumpOpts.peakOfWave = oldValue;
+		return {
+			value: oldValue,
+			bType: 'peakOfWave',
+			bState: true
+		};
+	} else if (!this.jumpOpts.lastStatus && this.jumpOpts.isDirectionUp && this.jumpOpts.continueDownFormerCount >=
+		2 && Math.abs(oldValue) > 4) {
+		this.jumpOpts.valleyOfWave = oldValue;
+		return {
+			value: oldValue,
+			bType: 'valleyOfWave',
+			bState: true
+		};
+	} else {
+		return {
+			value: oldValue,
+			bType: 'None',
+			bState: false
+		};
+	}
+}
+//重置对应的参数
+ActionJump.prototype.resetAll = function () {
+	// console.log('******************* resetAll ******************');
+	this.peakOfWaveArray = [];
+	this.peakOfWaveMaxValue = 0;
+	this.valleyOfWaveArray = [];
+	this.valleyOfWaveMinValue = 0;
+	this.highestCount = 0;
+
+
+	this.jumpOpts.continueDownFormerCount = 0;
+	this.jumpOpts.continueDownCount = 0;
+	this.jumpOpts.continueUpFormerCount = 0;
+	this.jumpOpts.continueUpCount = 0;
+
+	// this.jumpOpts.gravityOld = 0;
+}
+
+if (typeof module === "object" && typeof module.exports === "object") {
+	module.exports = ActionJump;
+}

+ 279 - 0
util/util-js/action/jump-0.2.js

@@ -0,0 +1,279 @@
+/**
+ * 跳判断相关脚本代码
+ */
+
+function Event() {
+	this.events = {};
+}
+Event.prototype.addEventListener = function(type, listener) {
+	this.events[type] = this.events[type] || [];
+	this.events[type].push(listener);
+};
+Event.prototype.trigger = function() {
+	for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+		args[_key] = arguments[_key];
+	}
+
+	var type = args[0];
+	var params = args.slice(1);
+	if (!!this.events[type]) {
+		// console.log("type:",type);
+		this.events[type].forEach(function(listener) {
+			try {
+				listener.apply(null, params);
+			} catch (e) {
+				console.error(e);
+			}
+		});
+	}
+};
+var jumpOpts = {
+	//是否上升的标志位
+	isDirectionUp: false,
+	//持续上升次数
+	continueUpCount: 0,
+	//上一点的持续上升的次数,为了记录波峰的上升次数
+	continueUpFormerCount: 0,
+
+	continueDownCount: 0,
+	continueDownFormerCount: 0,
+
+	//上一点的状态,上升还是下降
+	lastStatus: false,
+	//波峰值
+	peakOfWave: 0,
+	//波谷值
+	valleyOfWave: 0,
+	//检测到极快的波动的次数
+	timeOfPeakCount: 0,
+	//开始添加
+	bUpdateTimeOfPeakCount: false,
+	//开始更新的次数
+	startCount: 0,
+	//停止跳
+	bStopJump: false,
+	//上次传感器的值
+	gravityOld: 0,
+
+	bUpState: false,
+
+	//开始时间
+	startTime: 0,
+	endTime: 0
+}
+var ActionJump = function ActionJump() {
+
+	this.jumpOpts = jumpOpts;
+	this.peakOfWaveMaxValue = 0;
+	this.valleyOfWaveMinValue = 0;
+	this.highestCount = 0;
+	//陀螺仪
+	this.oriGyroYArray = [];
+	this.event = new Event();
+	this.frameCapacity = 6;
+	this.frame = [];
+	this.frameLength = 5;
+	this.frameOffset = 0;
+	for (var i = 0; i < this.frameCapacity; ++i) {
+		var o = new Object();
+		o.maxValue = 0;
+		o.gyroValue = 0;
+		o.resultant = 0;
+		this.frame.push(o);
+	}
+}
+ActionJump.prototype.addEventListener = function(type, listener) {
+	this.event.addEventListener(type, listener);
+};
+
+/**
+ * 更新数据
+ */
+ActionJump.prototype.updateJump = function() {
+	let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+	//使用三个轴的数据,计算重力轴的加速度。最后减去重力的加速度值
+	//********加速计********
+	let {
+		lAccX,
+		lAccY,
+		lAccZ
+	} = data.linearAcc;
+	let {
+		oAccX,
+		oAccY,
+		oAccZ
+	} = data.oriAcc;
+	let {
+		oGyroX,
+		oGyroY,
+		oGyroZ
+	} = data.oriGyro;
+	let {
+		bYAxis
+	} = data;
+	//oGyroX 在用的过程中方向相反,所以添加负号
+	let _tempAxisData = bYAxis ? oGyroY : -oGyroX;
+	this.detectorNewStep(data.resultant, lAccX, lAccY, lAccZ, oAccX, oAccY, oAccZ, data.runIndex, _tempAxisData);
+};
+
+
+
+/*
+ *计算跳逻辑
+ */
+ActionJump.prototype.detectorNewStep = function(resultant, linearX, linearY, linearZ, oriX, oriY, oriZ, _runIndex,
+	_oGyroY) {
+	let _judgmentValue = oriZ;
+	//判断resultant 一个阀值
+	let limitResultant = 20;
+	if (!this.jumpOpts.bStopJump) {
+		if (resultant > limitResultant && !this.jumpOpts.bUpState) {
+			this.jumpOpts.bUpState = true;
+			this.highestCount = 0;
+			//陀螺仪部分
+			// this.oriGyroYArray = [];
+			//开始更新。加入时间判断
+			this.jumpOpts.startTime = new Date().getTime();
+			this.event.trigger('resultant', {
+				type: "log",
+				logType: 'normal',
+				data: "开始时间:" + this.jumpOpts.startTime
+			});
+			for (let i = 0; i < this.frame.length; i++) {
+				this.frame[i].maxValue = 0;
+				this.frame[i].gyroValue = 0;
+				this.frame[i].resultant = 0;
+			}
+		}
+		if (this.jumpOpts.bUpState) {
+			let currTime = new Date().getTime(); //当前时间
+			let diffTime = currTime - this.jumpOpts.startTime; //当前时间减最初时间,得到当前时间差
+			// if (diffTime > 500) {
+			// 	//如果超时重置一下参数
+			// 	this.jumpOpts.startTime = new Date().getTime();
+			// 	for (let i = 0; i < this.frame.length; i++) {
+			// 		this.frame[i].maxValue = 0;
+			// 		this.frame[i].gyroValue = 0;
+			// 		this.frame[i].resultant = 0;
+			// 	}
+			// };
+
+			let newFrame = this.frame[(this.frameOffset + this.frameLength) % this.frameCapacity];
+
+			if (_judgmentValue > 2) {
+				newFrame.maxValue = _judgmentValue;
+				if (_judgmentValue > this.peakOfWaveMaxValue)
+					this.peakOfWaveMaxValue += _judgmentValue;
+			} else if (_judgmentValue < -2) {
+				newFrame.maxValue = _judgmentValue;
+				if (_judgmentValue < this.valleyOfWaveMinValue)
+					this.valleyOfWaveMinValue += _judgmentValue;
+			}
+			if (Math.abs(_oGyroY) > 5) {
+				// this.oriGyroYArray.push(_oGyroY);
+				newFrame.gyroValue = _oGyroY;
+			}
+			newFrame.resultant = resultant;
+
+			//出现极值后
+			// Math.abs(linearZ) < 7 &&
+			if (Math.abs(resultant) < 7) {
+				this.event.trigger('resultant', {
+					type: "log",
+					logType: 'normal',
+					data: '出现极值后:' + resultant + ",时间:" + diffTime
+				});
+				// if (diffTime < 150){
+				// this.jumpOpts.bUpState = false;
+				// return;
+				// };
+				// this.event.trigger('resultant', {
+				// 	type: "log",
+				// 	logType:'normal',
+				// 	data: "************触发成功************"
+				// });
+
+				this.highestCount++;
+				if (this.highestCount >= 2) {
+					//达到最高点,
+					this.jumpOpts.bStopJump = true;
+					this.jumpOpts.bUpdateTimeOfPeakCount = true;
+
+					// let _currentMaxValue = 0;
+
+					// if (Math.abs(this.peakOfWaveMaxValue) > Math.abs(this.valleyOfWaveMinValue)) {
+					// 	_currentMaxValue = this.peakOfWaveMaxValue;
+					// } else {
+					// 	_currentMaxValue = this.valleyOfWaveMinValue;
+					// }
+
+					// let allOGyroValue = 0;
+					// for (let i = 0; i < this.oriGyroYArray.length; i++) {
+					// 	allOGyroValue += this.oriGyroYArray[i];
+					// }
+					// allOGyroValue /= this.oriGyroYArray.length;
+
+					let _frameMaxValue = 0,
+						_frameGyroValue = 0;
+					for (let i = 0; i < this.frame.length; i++) {
+						_frameMaxValue += this.frame[i].maxValue;
+						_frameGyroValue += this.frame[i].gyroValue;
+					}
+					console.log("frame:" + _frameMaxValue + " == " + _frameGyroValue);
+
+					//后面通用使用这个类型传输数据
+					this.event.trigger('resultant', {
+						type: "stateDataOfJump",
+						currentMaxValue: _frameMaxValue,
+						peakOfWaveMaxValue: this.peakOfWaveMaxValue,
+						valleyOfWaveMinValue: this.valleyOfWaveMinValue,
+						oGyroValue: _frameGyroValue / this.frame.length,
+						resultant: resultant,
+						name: "highestCountEnd"
+					});
+					// this.jumpOpts.bUpState = false;
+					// this.jumpOpts.bStopJump = false;
+					this.event.trigger('resultant', {
+						type: "stop"
+					});
+					this.resetAll();
+				}
+			}
+			if ((this.frameOffset += 1) >= this.frameCapacity) {
+				this.frameOffset -= this.frameCapacity;
+			}
+		}
+	} else if (this.jumpOpts.bUpdateTimeOfPeakCount) {
+		// console.log("结束判断时候:" + resultant);
+		this.jumpOpts.timeOfPeakCount++;
+		//todo 如果直跳,可以调节更小的 limitTimeOfPeakCount 30
+		let limitTimeOfPeakCount = 10;
+		if (this.jumpOpts.timeOfPeakCount >= limitTimeOfPeakCount) {
+			this.jumpOpts.timeOfPeakCount = 0;
+			this.jumpOpts.bStopJump = false;
+			this.jumpOpts.bUpState = false;
+			// this.event.trigger('resultant', {
+			// 	type: "stop"
+			// });
+			// this.resetAll();
+			this.jumpOpts.bUpdateTimeOfPeakCount = false;
+			// console.log("timeOfPeakCount >= " + limitTimeOfPeakCount);
+		}
+	}
+}
+
+ActionJump.prototype.setBUpState = function(value) {
+	this.jumpOpts.bUpState = value;
+}
+
+
+//重置对应的参数
+ActionJump.prototype.resetAll = function() {
+	this.peakOfWaveMaxValue = 0;
+	this.valleyOfWaveMinValue = 0;
+	this.highestCount = 0;
+}
+
+if (typeof module === "object" && typeof module.exports === "object") {
+	module.exports = ActionJump;
+}

+ 378 - 0
util/util-js/action/jump.js

@@ -0,0 +1,378 @@
+/**
+ * 跳判断相关脚本代码
+ */
+
+let assign = function(target, ...varArgs) {
+	if (target == null) {
+		throw new TypeError('Cannot convert undefined or null to object');
+	}
+	if (!varArgs || varArgs.length <= 0) {
+		return target;
+	}
+	// 深度合并对象
+	function deepAssign(obj1, obj2) {
+		for (let key in obj2) {
+			obj1[key] = obj1[key] && obj1[key].toString() === "[object Object]" ?
+				deepAssign(obj1[key], obj2[key]) : obj1[key] = obj2[key];
+		}
+		return obj1;
+	}
+
+	varArgs.forEach(val => {
+		target = deepAssign(target, val);
+	});
+	return target;
+};
+
+function Event() {
+	this.events = {};
+}
+Event.prototype.addEventListener = function(type, listener) {
+	this.events[type] = this.events[type] || [];
+	this.events[type].push(listener);
+};
+Event.prototype.trigger = function() {
+	for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+		args[_key] = arguments[_key];
+	}
+
+	var type = args[0];
+	var params = args.slice(1);
+	if (!!this.events[type]) {
+		// console.log("type:",type);
+		this.events[type].forEach(function(listener) {
+			try {
+				listener.apply(null, params);
+			} catch (e) {
+				console.error(e);
+			}
+		});
+	}
+};
+var jumpOpts = {
+	//是否上升的标志位
+	isDirectionUp: false,
+	//持续上升次数
+	continueUpCount: 0,
+	//上一点的持续上升的次数,为了记录波峰的上升次数
+	continueUpFormerCount: 0,
+
+	continueDownCount: 0,
+	continueDownFormerCount: 0,
+
+	//上一点的状态,上升还是下降
+	lastStatus: false,
+	//波峰值
+	peakOfWave: 0,
+	//波谷值
+	valleyOfWave: 0,
+	//检测到极快的波动的次数
+	timeOfPeakCount: 0,
+	//开始添加
+	bUpdateTimeOfPeakCount: false,
+	//开始更新的次数
+	startCount: 0,
+	//停止跳
+	bStopJump: false,
+	//上次传感器的值
+	gravityOld: 0,
+
+	bUpState: false,
+}
+var ActionJump = function ActionJump() {
+
+	this.jumpOpts = jumpOpts;
+	//其他波峰波谷参数相关数组记录
+	this.peakOfWaveArray = [];
+	this.peakOfWaveMaxValue = 0;
+	this.valleyOfWaveArray = [];
+	this.valleyOfWaveMinValue = 0;
+	this.highestCount = 0;
+	//陀螺仪
+	this.oriGyroYArray = [];
+
+	this.isJumpTop = false;
+
+	this.event = new Event();
+
+}
+ActionJump.prototype.addEventListener = function(type, listener) {
+	this.event.addEventListener(type, listener);
+};
+
+
+ActionJump.prototype.updateJump = function() {
+	let data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+	//使用三个轴的数据,计算重力轴的加速度。最后减去重力的加速度值
+	//********加速计********
+	let {
+		lAccX,
+		lAccY,
+		lAccZ
+	} = data.linearAcc;
+	let {
+		oAccX,
+		oAccY,
+		oAccZ
+	} = data.oriAcc;
+	let {
+		oGyroX,
+		oGyroY,
+		oGyroZ
+	} = data.oriGyro;
+	let {
+		bYAxis
+	} = data;
+	let _tempAxisData = bYAxis ? oGyroY : oGyroX;
+	this.detectorNewStep(data.resultant, lAccX, lAccY, lAccZ, oAccX, oAccY, oAccZ, data.runIndex, _tempAxisData);
+};
+
+
+
+/*
+ * 检测步子,并开始计步
+ * 1.传入数据
+ * 2.如果检测到了波峰,并且符合时间差以及阈值的条件,则判定为1步
+ * 3.符合时间差条件,波峰波谷差值大于initialValue,则将该差值纳入阈值的计算中
+ * */
+ActionJump.prototype.detectorNewStep = function(resultant, linearX, linearY, linearZ, oriX, oriY, oriZ, _runIndex,
+	_oGyroY) {
+	let _judgmentValue = oriZ;
+	if (this.jumpOpts.gravityOld == 0) {
+		this.jumpOpts.gravityOld = _judgmentValue;
+	} else {
+
+		if (!this.jumpOpts.bStopJump) {
+			let {
+				bState,
+				bType,
+				value
+			} = this.detectorPeakOfWaveAndValleyOfWave(_judgmentValue, this.jumpOpts.gravityOld);
+			if (bState) {
+				if (!this.jumpOpts.bUpState) {
+					this.jumpOpts.bUpState = true;
+					this.isJumpTop = false;
+					this.highestCount = 0;
+					//陀螺仪部分
+					this.oriGyroYArray = [];
+					this.jumpOpts.startCount = 0;
+				}
+				// let _temp = {
+				// 	type: bType,
+				// 	oldValue: value,
+				// 	// value: resultant,
+				// 	lastIndex: _runIndex - 1
+				// };
+				// this.event.trigger('resultant', _temp);
+				//记录最高点和最低点数组
+				if (bType == 'peakOfWave') {
+					this.peakOfWaveArray.push(value);
+					// if (value > this.peakOfWaveMaxValue)
+					this.peakOfWaveMaxValue += value;
+				} else if (bType == 'valleyOfWave') {
+					this.valleyOfWaveArray.push(value);
+					// if (value < this.valleyOfWaveMinValue)
+					this.valleyOfWaveMinValue += value;
+				}
+
+			}
+
+			if (this.jumpOpts.bUpState) {
+				if(Math.abs(_oGyroY)>10)
+					this.oriGyroYArray.push(_oGyroY);
+				// this.jumpOpts.startCount++;
+				// if (this.jumpOpts.startCount >= 7 ) {
+				// 	console.log("startCount peakOfWaveArray", JSON.stringify(this.peakOfWaveArray));
+				// 	console.log("startCount valleyOfWaveArray", JSON.stringify(this.valleyOfWaveArray));
+				// 	if (this.peakOfWaveArray.length !== 0 || this.valleyOfWaveArray.length !== 0) {
+				// 		let _currentMaxValue = 0;
+				// 		if (this.peakOfWaveMaxValue > 5) {
+				// 			_currentMaxValue = this.peakOfWaveMaxValue;
+				// 		} else if (this.valleyOfWaveMinValue < -5) {
+				// 			_currentMaxValue = this.valleyOfWaveMinValue;
+				// 		}
+				// 		let allOGyroValue = 0;
+				// 		for (let i = 0; i < this.oriGyroYArray.length; i++) {
+				// 			allOGyroValue += this.oriGyroYArray[i];
+				// 		}
+				// 		allOGyroValue /= this.oriGyroYArray.length;
+				// 		//这里相当于处理识别到跳,但是没有判断出什么动作。
+				// 		this.event.trigger('resultant', {
+				// 			type: "stateDataOfJump",
+				// 			currentMaxValue: _currentMaxValue,
+				// 			oGyroValue: allOGyroValue,
+				// 			resultant: resultant,
+				// 			name: "startCountEnd"
+				// 		});
+				// 	}
+
+				// // 如果加过一定数量。判断没有触发,重置状态
+				// this.jumpOpts.bUpState = false;
+				// 	this.jumpOpts.bStopJump = true;
+				// 	this.jumpOpts.bUpdateTimeOfPeakCount = true;
+				// 	this.resetAll();
+				// }
+
+
+				//出现极值后
+				if (Math.abs(linearZ) < 7 && Math.abs(resultant) < 7) {
+					// this.isJumpTop = true;
+					this.highestCount++;
+					if (this.highestCount >= 2) {
+						//达到最高点,
+						this.jumpOpts.bStopJump = true;
+						this.jumpOpts.bUpdateTimeOfPeakCount = true;
+						// this.isJumpTop = false;
+
+						let _currentMaxValue = 0;
+						// console.log("highestCount peakOfWaveArray", JSON.stringify(this.peakOfWaveArray));
+						// console.log("highestCount valleyOfWaveArray", JSON.stringify(this.valleyOfWaveArray));
+						// console.log("达到最高点时候数值 Max:", this.peakOfWaveMaxValue, " min:", this.valleyOfWaveMinValue);
+						//(Math.abs(this.peakOfWaveMaxValue) > 5 && Math.abs(this.valleyOfWaveMinValue) - Math
+						//  .abs(this.peakOfWaveMaxValue) < 10) ||
+						if (Math.abs(this.peakOfWaveMaxValue) > Math.abs(this.valleyOfWaveMinValue)) {
+							_currentMaxValue = this.peakOfWaveMaxValue;
+						} else {
+							_currentMaxValue = this.valleyOfWaveMinValue;
+						}
+
+						let allOGyroValue = 0;
+						for (let i = 0; i < this.oriGyroYArray.length; i++) {
+							allOGyroValue += this.oriGyroYArray[i];
+						}
+						allOGyroValue /= this.oriGyroYArray.length;
+
+						//目前测试预大于100 为旋转跳动
+						// if (allOGyroValue > 0) {
+						// 	console.log('right:', allOGyroValue);
+
+						// } else {
+						// 	console.log('left:', allOGyroValue);
+						// }
+
+						this.event.trigger('resultant', {
+							type: "jump",
+							acc: _currentMaxValue,
+							value: resultant
+						});
+
+						this.event.trigger('resultant', {
+							type: "curAngle",
+							value: _currentMaxValue,
+							resultant: resultant
+						});
+
+						this.event.trigger('resultant', {
+							type: "rotate",
+							value: allOGyroValue,
+							resultant: resultant
+						});
+						//如果_currentMaxValue小于30判断原地跳
+						// console.log("_currentMaxValue:", _currentMaxValue,allOGyroValue);
+
+						//后面通用使用这个类型传输数据
+						this.event.trigger('resultant', {
+							type: "stateDataOfJump",
+							currentMaxValue: _currentMaxValue,
+							peakOfWaveMaxValue: this.peakOfWaveMaxValue,
+							valleyOfWaveMinValue: this.valleyOfWaveMinValue,
+							oGyroValue: allOGyroValue,
+							resultant: resultant,
+							name: "highestCountEnd"
+						});
+						this.jumpOpts.bUpState = false;
+						// this.resetAll();
+					}
+
+				}
+			}
+		} else if (this.jumpOpts.bUpdateTimeOfPeakCount) {
+			this.jumpOpts.timeOfPeakCount++;
+			if (this.jumpOpts.timeOfPeakCount >= 30) {
+				this.jumpOpts.timeOfPeakCount = 0;
+				this.jumpOpts.bStopJump = false;
+				this.event.trigger('resultant', {
+					type: "stop"
+				});
+				console.log("timeOfPeakCount >=30");
+				this.resetAll();
+				this.jumpOpts.bUpdateTimeOfPeakCount = false;
+			}
+		}
+
+		// 		let result = Math.atan2(averX, averZ) * 180 / (Math.PI);
+		// 		result = Math.round(result);
+		// 		let curAngle = result > 0 ? result : (360 + result);
+		// 		console.log("curAngle:", curAngle);
+		this.event.trigger('resultant', {
+			type: "bUpdateDraw",
+			linearX: linearX,
+			linearZ: linearZ,
+			linearY: linearY,
+			oriX: oriX,
+			oriY: oriY,
+			oriZ: oriZ
+		});
+		this.jumpOpts.gravityOld = _judgmentValue;
+	}
+}
+
+
+ActionJump.prototype.detectorPeakOfWaveAndValleyOfWave = function(newValue, oldValue) {
+	this.jumpOpts.lastStatus = this.jumpOpts.isDirectionUp;
+	if (newValue >= oldValue) {
+		this.jumpOpts.continueDownFormerCount = this.jumpOpts.continueDownCount;
+		this.jumpOpts.continueDownCount = 0;
+		this.jumpOpts.isDirectionUp = true;
+		this.jumpOpts.continueUpCount++;
+	} else {
+		this.jumpOpts.continueUpFormerCount = this.jumpOpts.continueUpCount;
+		this.jumpOpts.continueUpCount = 0;
+		this.jumpOpts.isDirectionUp = false;
+		this.jumpOpts.continueDownCount++;
+	}
+	if (!this.jumpOpts.isDirectionUp && this.jumpOpts.lastStatus && this.jumpOpts.continueUpFormerCount >= 2 && Math
+		.abs(oldValue) > 4) {
+		this.jumpOpts.peakOfWave = oldValue;
+		return {
+			value: oldValue,
+			bType: 'peakOfWave',
+			bState: true
+		};
+	} else if (!this.jumpOpts.lastStatus && this.jumpOpts.isDirectionUp && this.jumpOpts.continueDownFormerCount >=
+		2 && Math.abs(oldValue) > 4) {
+		this.jumpOpts.valleyOfWave = oldValue;
+		return {
+			value: oldValue,
+			bType: 'valleyOfWave',
+			bState: true
+		};
+	} else {
+		return {
+			value: oldValue,
+			bType: 'None',
+			bState: false
+		};
+	}
+}
+//重置对应的参数
+ActionJump.prototype.resetAll = function() {
+	// console.log('******************* resetAll ******************');
+	this.peakOfWaveArray = [];
+	this.peakOfWaveMaxValue = 0;
+	this.valleyOfWaveArray = [];
+	this.valleyOfWaveMinValue = 0;
+	this.highestCount = 0;
+
+
+	this.jumpOpts.continueDownFormerCount = 0;
+	this.jumpOpts.continueDownCount = 0;
+	this.jumpOpts.continueUpFormerCount = 0;
+	this.jumpOpts.continueUpCount = 0;
+
+	// this.jumpOpts.gravityOld = 0;
+}
+
+if (typeof module === "object" && typeof module.exports === "object") {
+	module.exports = ActionJump;
+}

+ 57 - 0
util/util-js/avatar.js

@@ -0,0 +1,57 @@
+
+const getAvatarList = function() {
+	const avatarList = [];
+	avatarList.push({
+		name:'蝙蝠人',
+		url:'/static/avatar/1.png'
+	});
+	avatarList.push({
+		name:'变异人',
+		url:'/static/avatar/2.png'
+	});
+	avatarList.push({
+		name:'德古拉伯爵',
+		url:'/static/avatar/3.png'
+	});
+	avatarList.push({
+		name:'德拉克里娜',
+		url:'/static/avatar/4.png'
+	});
+	avatarList.push({
+		name:'地心人',
+		url:'/static/avatar/5.png'
+	});
+	avatarList.push({
+		name:'噩梦',
+		url:'/static/avatar/6.png'
+	});
+	avatarList.push({
+		name:'红拂女',
+		url:'/static/avatar/7.png'
+	});
+	avatarList.push({
+		name:'吸血男',
+		url:'/static/avatar/8.png'
+	});
+	avatarList.push({
+		name:'小丑女',
+		url:'/static/avatar/9.png'
+	});
+	avatarList.push({
+		name:'血腥玛丽',
+		url:'/static/avatar/10.png'
+	});
+	avatarList.push({
+		name:'战狼',
+		url:'/static/avatar/11.png'
+	});
+
+	return {
+		avatarList
+	}
+}
+
+
+export default {
+	getAvatarList
+}

+ 83 - 0
util/util-js/city.js

@@ -0,0 +1,83 @@
+var citys = {
+  '省市': ['区域'],
+  '北京市': ['市辖区'],
+  '天津市': ['市辖区'],
+  '河北省': ['石家庄市', '唐山市', '秦皇岛市', '邯郸市', '邢台市', '保定市', '张家口市', '承德市', '沧州市', '廊坊市', '衡水市', '省直辖县级行政区划'],
+  '山西省': ['太原市', '大同市', '阳泉市', '长治市', '晋城市', '朔州市', '晋中市', '运城市', '忻州市', '临汾市', '吕梁市'],
+  '内蒙古自治区': ['呼和浩特市', '包头市', '乌海市', '赤峰市', '通辽市', '鄂尔多斯市', '呼伦贝尔市', '巴彦淖尔市', '乌兰察布市', '兴安盟', '锡林郭勒盟', '阿拉善盟'],
+  '辽宁省': ['沈阳市', '大连市', '鞍山市', '抚顺市', '本溪市', '丹东市', '锦州市', '营口市', '阜新市', '辽阳市', '盘锦市', '铁岭市', '朝阳市', '葫芦岛市'],
+  '吉林省': ['长春市', '吉林市', '四平市', '辽源市', '通化市', '白山市', '松原市', '白城市', '延边朝鲜族自治州'],
+  '黑龙江省': ['哈尔滨市', '齐齐哈尔市', '鸡西市', '鹤岗市', '双鸭山市', '大庆市', '伊春市', '佳木斯市', '七台河市', '牡丹江市', '黑河市', '绥化市', '大兴安岭地区'],
+  '上海市': ['市辖区'],
+  '江苏省': ['南京市', '无锡市', '徐州市', '常州市', '苏州市', '南通市', '连云港市', '淮安市', '盐城市', '扬州市', '镇江市', '泰州市', '宿迁市'],
+  '浙江省': ['杭州市', '宁波市', '温州市', '嘉兴市', '湖州市', '绍兴市', '金华市', '衢州市', '舟山市', '台州市', '丽水市'],
+  '安徽省': ['合肥市', '芜湖市', '蚌埠市', '淮南市', '马鞍山市', '淮北市', '铜陵市', '安庆市', '黄山市', '滁州市', '阜阳市', '宿州市', '六安市', '亳州市', '池州市', '宣城市'],
+  '福建省': ['福州市', '厦门市', '莆田市', '三明市', '泉州市', '漳州市', '南平市', '龙岩市', '宁德市'],
+  '江西省': ['南昌市', '景德镇市', '萍乡市', '九江市', '新余市', '鹰潭市', '赣州市', '吉安市', '宜春市', '抚州市', '上饶市'],
+  '山东省': ['济南市', '青岛市', '淄博市', '枣庄市', '东营市', '烟台市', '潍坊市', '济宁市', '泰安市', '威海市', '日照市', '莱芜市', '临沂市', '德州市', '聊城市', '滨州市', '菏泽市'],
+  '河南省': ['郑州市', '开封市', '洛阳市', '平顶山市', '安阳市', '鹤壁市', '新乡市', '焦作市', '濮阳市', '许昌市', '漯河市', '三门峡市', '南阳市', '商丘市', '信阳市', '周口市', '驻马店市', '省直辖县级行政区划'],
+  '湖北省': ['武汉市', '黄石市', '十堰市', '宜昌市', '襄阳市', '鄂州市', '荆门市', '孝感市', '荆州市', '黄冈市', '咸宁市', '随州市', '恩施土家族苗族自治州', '省直辖县级行政区划'],
+  '湖南省': ['长沙市', '株洲市', '湘潭市', '衡阳市', '邵阳市', '岳阳市', '常德市', '张家界市', '益阳市', '郴州市', '永州市', '怀化市', '娄底市', '湘西土家族苗族自治州'],
+  '广东省': ['广州市', '韶关市', '深圳市', '珠海市', '汕头市', '佛山市', '江门市', '湛江市', '茂名市', '肇庆市', '惠州市', '梅州市', '汕尾市', '河源市', '阳江市', '清远市', '东莞市', '中山市', '潮州市', '揭阳市', '云浮市'],
+  '广西壮族自治区': ['南宁市', '柳州市', '桂林市', '梧州市', '北海市', '防城港市', '钦州市', '贵港市', '玉林市', '百色市', '贺州市', '河池市', '来宾市', '崇左市'],
+  '海南省': ['海口市', '三亚市', '三沙市', '儋州市', '省直辖县级行政区划'],
+  '重庆市': ['市辖区', '县'],
+  '四川省': ['成都市', '自贡市', '攀枝花市', '泸州市', '德阳市', '绵阳市', '广元市', '遂宁市', '内江市', '乐山市', '南充市', '眉山市', '宜宾市', '广安市', '达州市', '雅安市', '巴中市', '资阳市', '阿坝藏族羌族自治州', '甘孜藏族自治州', '凉山彝族自治州'],
+  '贵州省': ['贵阳市', '六盘水市', '遵义市', '安顺市', '毕节市', '铜仁市', '黔西南布依族苗族自治州', '黔东南苗族侗族自治州', '黔南布依族苗族自治州'],
+  '云南省': ['昆明市', '曲靖市', '玉溪市', '保山市', '昭通市', '丽江市', '普洱市', '临沧市', '楚雄彝族自治州', '红河哈尼族彝族自治州', '文山壮族苗族自治州', '西双版纳傣族自治州', '大理白族自治州', '德宏傣族景颇族自治州', '怒江傈僳族自治州', '迪庆藏族自治州'],
+  '西藏自治区': ['拉萨市', '日喀则市', '昌都市', '林芝市', '山南市', '那曲地区', '阿里地区'],
+  '陕西省': ['西安市', '铜川市', '宝鸡市', '咸阳市', '渭南市', '延安市', '汉中市', '榆林市', '安康市', '商洛市'],
+  '甘肃省': ['兰州市', '嘉峪关市', '金昌市', '白银市', '天水市', '武威市', '张掖市', '平凉市', '酒泉市', '庆阳市', '定西市', '陇南市', '临夏回族自治州', '甘南藏族自治州'],
+  '青海省': ['西宁市', '海东市', '海北藏族自治州', '黄南藏族自治州', '海南藏族自治州', '果洛藏族自治州', '玉树藏族自治州', '海西蒙古族藏族自治州'],
+  '宁夏回族自治区': ['银川市', '石嘴山市', '吴忠市', '固原市', '中卫市'],
+  '新疆维吾尔自治区': ['乌鲁木齐市', '克拉玛依市', '吐鲁番市', '哈密市', '昌吉回族自治州', '博尔塔拉蒙古自治州', '巴音郭楞蒙古自治州', '阿克苏地区', '克孜勒苏柯尔克孜自治州', '喀什地区', '和田地区', '伊犁哈萨克自治州', '塔城地区', '阿勒泰地区', '自治区直辖县级行政区划'],
+  '台湾省': ['台湾'],
+  '香港特别行政区': ['香港'],
+  '澳门特别行政区': ['澳门']
+}
+//省份
+var Province = ["北京", "天津", "上海", "重庆", "河北", "山西", "辽宁", "吉林", "黑龙江", "江苏", "浙江", "安徽", "福建", "江西", "山东", "河南", "湖北", "湖南", "广东", "海南", "四川", "贵州", "云南", "陕西", "甘肃", "青海", "内蒙古", "广西", "西藏", "宁夏", "新疆维吾尔自治区", "香港", "澳门", "台湾"]
+
+//城市
+var city = {
+  // 省份: ['选择省份'],
+  北京: ["东城区", "西城区", "崇文区", "宣武区", "朝阳区", "海淀区", "丰台区", "石景山区", "房山区", "通州区", "顺义区", "昌平区", "大兴区", "怀柔区", "平谷区", "门头沟区", "密云县", "延庆县"],
+  天津: ["和平区", "河东区", "河西区", "南开区", "河北区", "红桥区", "东丽区", "西青区", "北辰区", "津南区", "武清区", "宝坻区", "滨海新区", "静海县", "宁河县", "蓟县"],
+  上海: ["黄浦区", "卢湾区", "徐汇区", "长宁区", "静安区", "普陀区", "闸北区", "虹口区", "杨浦区", "闵行区", "宝山区", "嘉定区", "浦东新区", "金山区", "松江区", "青浦区", "奉贤区", "崇明县"],
+  重庆: ["渝中区", "大渡口区", "江北区", "南岸区", "北碚区", "渝北区", "巴南区", "长寿区", "双桥区", "沙坪坝区", "万盛区", "万州区", "涪陵区", "黔江区", "永川区", "合川区", "江津区", "九龙坡区", "南川区", "綦江县", "潼南县", "荣昌县", "璧山县", "大足县", "铜梁县", "梁平县", "开县", "忠县", "城口县", "垫江县", "武隆县", "丰都县", "奉节县", "云阳县", "巫溪县", "巫山县", "石柱土家族自治县", "秀山土家族苗族自治县", "酉阳土家族苗族自治县", "彭水苗族土家族自治县"],
+  河北: ["石家庄", "唐山", "秦皇岛", "邯郸", "邢台", "保定", "张家口", "承德", "沧州", "廊坊", "衡水"],
+  山西: ["太原", "大同", "阳泉", "长治", "晋城", "朔州", "晋中", "运城", "忻州", "临汾", "吕梁"],
+  辽宁: ["沈阳", "大连", "鞍山", "抚顺", "本溪", "丹东", "锦州", "营口", "阜新", "辽阳", "盘锦", "铁岭", "朝阳", "葫芦岛"],
+  吉林: ["长春", "吉林", "四平", "辽源", "通化", "白山", "松原", "白城", "延边朝鲜族自治州"],
+  黑龙江: ["哈尔滨", "齐齐哈尔", "鹤岗", "双鸭山", "鸡西", "大庆", "伊春", "牡丹江", "佳木斯", "七台河", "黑河", "绥化", "大兴安岭"],
+  江苏: ["南京", "苏州", "无锡", "常州", "镇江", "南通", "泰州", "扬州", "盐城", "连云港", "徐州", "淮安", "宿迁"],
+  浙江: ["杭州", "宁波", "温州", "嘉兴", "湖州", "绍兴", "金华", "衢州", "舟山", "台州", "丽水"],
+  安徽: ["合肥", "芜湖", "蚌埠", "淮南", "马鞍山", "淮北", "铜陵", "安庆", "黄山", "滁州", "阜阳", "宿州", "巢湖", "六安", "亳州", "池州", "宣城"],
+  福建: ["福州", "厦门", "莆田", "三明", "泉州", "漳州", "南平", "龙岩", "宁德"],
+  江西: ["南昌", "景德镇", "萍乡", "九江", "新余", "鹰潭", "赣州", "吉安", "宜春", "抚州", "上饶"],
+  山东: ["济南", "青岛", "淄博", "枣庄", "东营", "烟台", "潍坊", "济宁", "泰安", "威海", "日照", "莱芜", "临沂", "德州", "聊城", "滨州", "菏泽"],
+  河南: ["郑州", "开封", "洛阳", "平顶山", "安阳", "鹤壁", "新乡", "焦作", "濮阳", "许昌", "漯河", "三门峡", "南阳", "商丘", "信阳", "周口", "驻马店"],
+  湖北: ["武汉", "黄石", "十堰", "荆州", "宜昌", "襄樊", "鄂州", "荆门", "孝感", "黄冈", "咸宁", "随州", "恩施"],
+  湖南: ["长沙", "株洲", "湘潭", "衡阳", "邵阳", "岳阳", "常德", "张家界", "益阳", "郴州", "永州", "怀化", "娄底", "湘西"],
+  广东: ["广州", "深圳", "珠海", "汕头", "韶关", "佛山", "江门", "湛江", "茂名", "肇庆", "惠州", "梅州", "汕尾", "河源", "阳江", "清远", "东莞", "中山", "潮州", "揭阳", "云浮"],
+  海南: ["海口", "三亚"],
+  四川: ["成都", "自贡", "攀枝花", "泸州", "德阳", "绵阳", "广元", "遂宁", "内江", "乐山", "南充", "眉山", "宜宾", "广安", "达州", "雅安", "巴中", "资阳", "阿坝", "甘孜", "凉山"],
+  贵州: ["贵阳", "六盘水", "遵义", "安顺", "铜仁", "毕节", "黔西南", "黔东南", "黔南"],
+  云南: ["昆明", "曲靖", "玉溪", "保山", "昭通", "丽江", "普洱", "临沧", "德宏", "怒江", "迪庆", "大理", "楚雄", "红河", "文山", "西双版纳"],
+  陕西: ["西安", "铜川", "宝鸡", "咸阳", "渭南", "延安", "汉中", "榆林", "安康", "商洛"],
+  甘肃: ["兰州", "嘉峪关", "金昌", "白银", "天水", "武威", "酒泉", "张掖", "庆阳", "平凉", "定西", "陇南", "临夏", "甘南"],
+  青海: ["西宁", "海东", "海北", "海南", "黄南", "果洛", "玉树", "海西"],
+  内蒙古: ["呼和浩特", "包头", "乌海", "赤峰", "通辽", "鄂尔多斯", "呼伦贝尔", "巴彦淖尔", "乌兰察布", "锡林郭勒盟", "兴安盟", "阿拉善盟"],
+  广西: ["南宁", "柳州", "桂林", "梧州", "北海", "防城港", "钦州", "贵港", "玉林", "百色", "贺州", "河池", "来宾", "崇左"],
+  西藏: ["拉萨", "那曲", "昌都", "林芝", "山南", "日喀则", "阿里"],
+  宁夏: ["银川", "石嘴山", "吴忠", "固原", "中卫"],
+  新疆维吾尔自治区: ["乌鲁木齐", "克拉玛依", "吐鲁番", "哈密", "和田", "阿克苏", "喀什", "克孜勒苏", "巴音郭楞", "昌吉", "博尔塔拉", "伊犁", "塔城", "阿勒泰"],
+  香港: ["香港岛", "九龙东", "九龙西", "新界东", "新界西"],
+  澳门: ["澳门半岛", "离岛"],
+  台湾: ["台北", "高雄", "基隆", "新竹", "台中", "嘉义", "台南市"]
+}
+
+module.exports = {
+  citys: citys,
+  city: city,
+}

+ 89 - 0
util/util-js/date.js

@@ -0,0 +1,89 @@
+const formatTime = date => {
+	const year = date.getFullYear()
+	const month = date.getMonth() + 1
+	const day = date.getDate()
+	const hour = date.getHours()
+	const minute = date.getMinutes()
+	const second = date.getSeconds()
+
+	return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
+}
+const formatNumber = n => {
+	n = n.toString()
+	return n[1] ? n : '0' + n
+}
+
+const formatDate = date => {
+	const year = date.getFullYear()
+	const month = date.getMonth() + 1
+	const day = date.getDate()
+	const hour = date.getHours()
+	const minute = date.getMinutes()
+	const second = date.getSeconds()
+
+	return [year, month, day].map(formatNumber).join('/')
+}
+
+//计算相差天数
+const datedifference = (sDate1, sDate2) => { //sDate1和sDate2是2006-12-18格式 
+	var dateSpan,
+		tempDate,
+		iDays;
+	sDate1 = Date.parse(sDate1.replace(/-/g, '/'));
+	sDate2 = Date.parse(sDate2.replace(/-/g, '/'));
+	dateSpan = sDate2 - sDate1;
+	dateSpan = Math.abs(dateSpan);
+	iDays = Math.floor(dateSpan / (24 * 3600 * 1000));
+	return iDays
+};
+
+const getDays =(date1, date2)=> {
+    const dateTime = 1000 * 60 * 60 * 24; //每一天的毫秒数
+    const minusDays = Math.floor(((date2.getTime() - date1.getTime()) / dateTime));//计算出两个日期的天数差
+    return Math.abs(minusDays);
+}
+
+/**
+ * [dateAddDays 从某个日期增加n天后的日期]
+ * @param  {[string]} dateStr  [日期字符串]
+ * @param  {[int]} dayCount [增加的天数]
+ * @return {[string]}[增加n天后的日期字符串]
+ */
+const dateAddDays=(dateStr,dayCount) => {
+    var tempDate=new Date(dateStr.replace(/-/g,"/"));//把日期字符串转换成日期格式
+    var resultDate=new Date((tempDate/1000+(86400*dayCount))*1000);//增加n天后的日期
+    var resultDateStr=resultDate.getFullYear()+"-"+(resultDate.getMonth()+1)+"-"+(resultDate.getDate());//将日期转化为字符串格式
+    return resultDateStr;
+}
+
+/**
+ * 根据newDate 来获取加的日期
+ */
+const addDaysFromNewDate=(tempDate,dayCount) => {
+    var resultDate=new Date((tempDate/1000+(86400*dayCount))*1000);//增加n天后的日期
+ //    var resultDateStr=resultDate.getFullYear()+"/"+(resultDate.getMonth()+1)+"/"+(resultDate.getDate());//将日期转化为字符串格式
+	// return resultDateStr;
+	
+	const year = resultDate.getFullYear();
+	const month = resultDate.getMonth() + 1;
+	const day = resultDate.getDate();
+	
+	return [year, month, day].map(formatNumber).join('/')
+	
+}
+
+const getWeightDate = date => {
+	var timearr = date.replace(" ", ":").replace(/\:/g, "-").split("-");
+	var timestr = "" + timearr[1] + "/" + timearr[2]
+	return timestr 
+}
+
+export default {
+	formatTime,
+	formatDate,
+	datedifference,
+	getDays,
+	dateAddDays,
+	addDaysFromNewDate,
+	getWeightDate
+}

+ 109 - 0
util/util-js/devices.js

@@ -0,0 +1,109 @@
+
+const getDeviceList = function() {
+	
+	let deviceList = [
+			{
+				id: 0,
+				cname: "手机绑带",
+				ename: "mobilePhoneBandage",
+				icon: "/static/devicesIcon/bandage.png",
+				mIcon: "/static/devicesIcon/bandage.png",
+				bRatio: false,
+				usageMode: 'phone',
+				describe: '手机情景下使用',
+				limitType: 'rebound', //限制回弹版本
+				deviceType: 'mySelf', //指的是使用手机本身加速计计算
+				deviceName: 'ITAG', //连接硬件名称
+				limitDis: 0.5,
+				/**
+				 * 主服务的 uuid Cofing
+				 */
+				primaryUUID: '', //蓝牙主服务id
+				PRIMARY_SERVICE: '',
+				PRIMARY_WRITE: '',
+				PRIMARY_NOTIFY: '',
+				/***********/
+				currentVersion: '', //当前固件版本
+				latestVersion: '' //服务器最新固件版本
+			},
+			{
+				id: 1,
+				cname: "拳击模式",
+				ename: "hotman",
+				icon: "/static/devicesIcon/hotman.png",
+				mIcon: "/static/devicesIconSimple/hotman.png",
+				bRatio: false,
+				usageMode: "hotman", //使用模式,在hotman情景下使用
+				describe: '拳击模式情景下使用,快速打击模式',
+				limitType: 'noRebound', //不限制回弹版本
+				deviceType: 'BLEHandle', //使用设备,蓝牙手柄
+				deviceName: 'BGBox', // 使用设备名称:PBox-000000b BGBox_202012
+				limitDis: 100, //限制距离 米
+				/**
+				 * 主服务的 uuid Cofing
+				 */
+				primaryUUID: 'FFF0', //蓝牙主服务id
+				PRIMARY_SERVICE: '0000FFF0-0000-1000-8000-00805F9B34FB',
+				PRIMARY_WRITE: '0000FFF2-0000-1000-8000-00805F9B34FB',
+				PRIMARY_NOTIFY: '0000FFF1-0000-1000-8000-00805F9B34FB',
+				/***********/
+				currentVersion: '', //当前固件版本
+				latestVersion: '' //服务器最新固件版本
+			},
+			{
+				id: 2,
+				cname: "普通模式",
+				ename: "BLEHandle",
+				icon: "/static/devicesIcon/handle.png",
+				mIcon: "/static/devicesIconSimple/handle.png",
+				bRatio: false,
+				usageMode: "general", //通用情况,根据需求处理
+				describe: '自由情景下使用',
+				limitType: 'rebound', //app处理蓝牙发送的数据
+				deviceType: 'BLEHandle', //指的是外部蓝牙,目前定义为BLEHandle
+				deviceName: 'BGBox', //连接的设备名称
+				limitDis: 100, //
+				/**
+				 * 主服务的 uuid Cofing
+				 */
+				primaryUUID: 'FFF0', //蓝牙主服务id
+				PRIMARY_SERVICE: '0000FFF0-0000-1000-8000-00805F9B34FB',
+				PRIMARY_WRITE: '0000FFF2-0000-1000-8000-00805F9B34FB',
+				PRIMARY_NOTIFY: '0000FFF1-0000-1000-8000-00805F9B34FB',
+				/***********/
+				currentVersion: '1.2.0', //当前固件版本
+				latestVersion: '1.2.0' //服务器最新固件版本
+			},
+			{
+				id: 3,
+				cname: "跳绳模式",
+				ename: "rope",
+				icon: "/static/devicesIcon/rope.png",
+				mIcon: "/static/devicesIconSimple/rope_icon@2x.png",
+				bRatio: false,
+				usageMode: "ropeSkipping", //通用情况,根据需求处理
+				describe: '*长按开机键至蓝灯正常闪烁\n*蓝灯正常闪烁后,点击灰色选中按钮匹配手柄',
+				limitType: 'rebound', //app处理蓝牙发送的数据
+				deviceType: 'BLERope', //指的是外部蓝牙,目前定义为BLERope
+				deviceName: 'Rope', //连接的设备名称
+				limitDis: 100, //
+				/**
+				 * 主服务的 uuid Cofing
+				 */
+				primaryUUID: 'FFF0', //蓝牙主服务id
+				PRIMARY_SERVICE: '0000FFF0-0000-1000-8000-00805F9B34FB',
+				PRIMARY_WRITE: '0000FFF2-0000-1000-8000-00805F9B34FB',
+				PRIMARY_NOTIFY: '0000FFF1-0000-1000-8000-00805F9B34FB',
+				/***********/
+				currentVersion: '1.2.0', //当前固件版本
+				latestVersion: '1.2.0' //服务器最新固件版本
+			}
+		];
+
+	return deviceList;
+}
+
+
+export default {
+	getDeviceList
+}

+ 157 - 0
util/util-js/effect/firework.js

@@ -0,0 +1,157 @@
+/**
+ * 烟花特效
+ */
+function Event() {
+	this.events = {};
+}
+Event.prototype.addEventListener = function(type, listener) {
+	this.events[type] = this.events[type] || [];
+	this.events[type].push(listener);
+};
+Event.prototype.trigger = function() {
+	for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+		args[_key] = arguments[_key];
+	}
+
+	var type = args[0];
+	var params = args.slice(1);
+	if (!!this.events[type]) {
+		// console.log("type:",type);
+		this.events[type].forEach(function(listener) {
+			try {
+				listener.apply(null, params);
+			} catch (e) {
+				console.error(e);
+			}
+		});
+	}
+};
+// get a random number within a range
+function random(min, max) {
+	return Math.random() * (max - min) + min;
+}
+
+// calculate the distance between two points
+function calculateDistance(p1x, p1y, p2x, p2y) {
+	var xDistance = p1x - p2x,
+		yDistance = p1y - p2y;
+	return Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
+}
+
+
+// create firework
+var Firework = function Firework(image, typeImage, direction, tx, ty, cw, ch, offest, hiddenMidImage) {
+	this.event = new Event();
+	//图片信息
+	this.image = image;
+	this.typeImage = typeImage;
+	this.direction = direction;
+	this.position = {
+		"EF_baozha_0": [0, 0, 312, 312],
+		"EF_baozha_1": [312, 0, 312, 312],
+		"EF_baozha_2": [624, 0, 312, 312],
+		"EF_baozha_3": [936, 0, 312, 312],
+		"EF_baozha_4": [0, 312, 312, 312],
+		"EF_baozha_5": [312, 312, 312, 312],
+		"EF_baozha_6": [624, 312, 312, 312],
+		"EF_baozha_7": [936, 312, 312, 312],
+		"EF_baozha_8": [0, 624, 312, 312],
+		"EF_baozha_9": [312, 624, 312, 312],
+		"EF_baozha_10": [624, 624, 312, 312],
+		"EF_baozha_11": [936, 624, 312, 312],
+		"EF_baozha_12": [0, 936, 312, 312],
+		"EF_baozha_13": [312, 936, 312, 312],
+		"EF_baozha_14": [624, 936, 312, 312],
+		"EF_baozha_15": [936, 936, 312, 312],
+		"EF_baozha_16": [0, 1248, 312, 312],
+		"EF_baozha_17": [312, 1248, 312, 312],
+		"EF_baozha_18": [624, 1248, 312, 312],
+		"EF_baozha_19": [936, 1248, 312, 312]
+	};
+	// target coordinates
+	this.tx = tx;
+	this.ty = ty;
+
+	this.cw = cw;
+	this.ch = ch;
+
+	this.offest = offest;
+
+	this.index = 0;
+	// let _this = this;
+	// this.animationInstance = new Animation({
+	// 	timing: 'easeIn',
+	// 	duration: 1000,
+	// 	onProcess: function onProcess(process) {
+	// 		_this.event.trigger('renderProcess', process);
+
+	// 	},
+	// 	onAnimationFinish: function onAnimationFinish() {
+	// 		_this.event.trigger('renderComplete');
+	// 	}
+	// });
+	this.hiddenMidImage = hiddenMidImage || false;
+
+
+	const innerAudioContext = uni.createInnerAudioContext();
+	innerAudioContext.autoplay = true;
+	innerAudioContext.src = '/static/elect/hit.mp3';
+	innerAudioContext.onPlay(() => {
+		// console.log('开始播放');
+	});
+	innerAudioContext.onError((res) => {
+		console.log(res.errMsg);
+		console.log(res.errCode);
+	});
+	setTimeout(() => {
+		innerAudioContext.destroy();
+	}, 800)
+}
+
+Firework.prototype.addEventListener = function(type, listener) {
+	this.event.addEventListener(type, listener);
+};
+
+// draw firework
+Firework.prototype.draw = function(ctx, callback) {
+	if (this.index > 19) return;
+	let i = this.index;
+	let temp = this.position["EF_baozha_" + i];
+	// console.log("draw:"+this.direction);
+	let tempX = this.tx * this.direction;
+	let tempValue = this.direction < 0 ? 65 : -25
+	ctx.drawImage(this.image.path,
+		temp[0] //截取原始图片的 x坐标
+		, temp[1] //截取原始图片的 y坐标
+		, 312 //截取原始图片的 宽度
+		, 312 // 截取的高度
+		, tempX - 264 * 0.5 - tempValue + this.offest //图片在canvas画布上的x坐标
+		, -50 //图片在canvas画布上的y坐标
+		, 264 //绘制图片的宽度
+		, 264 //绘制图片的高度
+	);
+	if (!this.hiddenMidImage) {
+		//19
+		let _r = this.index / 32 + 1;
+		ctx.save();
+		//如果是相反绘制,需要加多一个自身位置偏移
+		let _pos = this.direction < 0 ? this.typeImage.width : 0;
+		//左边位置
+		let left = (this.typeImage.width + tempX - 164 * 0.5) - (this.typeImage.width / 2 - _pos) * _r + 20 -
+			tempValue + this.offest;
+		// 中心点 this.cw / 2 - this.typeImage.width / 2 * _r
+		ctx.translate(left, this.ch / 2 - this.typeImage.height / 2 * _r);
+		ctx.scale(_r * this.direction, _r);
+		ctx.drawImage(this.typeImage.path, 0, 0);
+		ctx.restore();
+	}
+	if (i === 19 && callback) {
+		callback();
+	}
+	this.index++;
+
+}
+
+if (typeof module === "object" && typeof module.exports === "object") {
+	module.exports = Firework;
+}

+ 10 - 0
util/util-js/enum.js

@@ -0,0 +1,10 @@
+var CONDITIONPASSED = {
+	SCORE:0,//分数解锁
+	ENERGYBARFULL: 10000,//充满左右两边蓄能槽
+	SKIPALLFLAGWITHINTIME: 10001,//规定时间内跳完所有标志块
+	JUMPTHEMOSTWITHINTIME: 10002,//规定时间内跳最多
+}
+
+module.exports = {
+	CONDITIONPASSED:CONDITIONPASSED
+} 

+ 17 - 0
util/util-js/makeNumber.js

@@ -0,0 +1,17 @@
+//给Number类型增加   减法函数  
+Number.prototype.sub = function(arg) {
+	var l1 = this.toString().indexOf('.') > 0 ? this.toString().split(".")[1].length : 0,
+		l2 = arg.toString().indexOf('.') > 0 ? arg.toString().split(".")[1].length : 0,
+		pw = Math.pow(10, Math.max(l1, l2)),
+		//动态控制精度长度  
+		l = (l1 >= l2) ? l1 : l2;
+	return Number(((this * pw - arg * pw) / pw).toFixed(l));
+}
+
+//给Number类型增加   加法函数  
+Number.prototype.add = function(arg) {
+	var l1 = this.toString().indexOf('.') > 0 ? this.toString().split(".")[1].length : 0,
+		l2 = arg.toString().indexOf('.') > 0 ? arg.toString().split(".")[1].length : 0,
+		pw = Math.pow(10, Math.max(l1, l2));
+	return Number((arg * pw + pw * this) / pw);
+};

+ 455 - 0
util/util-js/o0.js

@@ -0,0 +1,455 @@
+module.exports = {
+    Timer: class{
+        constructor(second) {
+            this.interval = second * 1000;
+            this.nextTiming();
+        }
+        get isDue(){
+            return new Date().getTime() - this.date.getTime() >= this.interval;
+        }
+        nextTiming(){
+            this.date = new Date();
+        }
+        tryNextTiming(){
+            if(!this.isDue){
+                return false;
+            }
+            this.nextTiming();
+            return true;
+        }
+    },
+    FixedTimer:class{
+        constructor(fps) {
+            this.fps = fps;
+            this.updateInterval = 1000.0/fps;
+            this.remainder = 0;
+            this.nextTiming();
+        }
+        nextTiming(){
+            this.date = new Date();
+        }
+        fixedUpdateTimes(){
+            var newTime = new Date();
+            var interval = newTime.getTime() - this.date.getTime() + this.remainder;
+            this.date = newTime;
+            this.remainder = interval % this.updateInterval;
+
+            return parseInt(interval / this.updateInterval);
+        }
+    },
+    FixedTimerDT:class{
+        constructor(fps) {
+            this.fps = fps;
+            this.updateInterval = 1000.0/fps;
+            this.remainder = 0;
+        }
+        fixedUpdateTimes(dt){//time in second
+            var interval = dt*1000 + this.remainder;
+            this.remainder = interval % this.updateInterval;
+
+            //cc.log(parseInt(interval / this.updateInterval));
+            return parseInt(interval / this.updateInterval);
+        }
+    },
+    QuadraticEquation: class{
+        constructor(x1,y1,x2,y2,x3,y3){
+            this.a = y1 / (x1 - x2) / (x1 - x3) + y2 / (x2 - x1) / (x2 - x3) + y3 / (x3 - x1) / (x3 - x2);
+            this.b = -y1 * (x2 + x3) / (x1 - x2) / (x1 - x3) - y2 * (x1 + x3) / (x2 - x1) / (x2 - x3) - y3 * (x1 + x2) / (x3 - x1) / (x3 - x2);
+            this.c = y1 * x2 * x3 / (x1 - x2) / (x1 - x3) + y2 * x1 * x3 / (x2 - x1) / (x2 - x3) + y3 * x1 * x2 / (x3 - x1) / (x3 - x2);
+        }
+        y(x){
+            //console.log(this.a+" "+this.b+" "+this.c);
+            return this.a*x*x +this.b*x +this.c;
+        }
+    },
+    Vector2: class{
+        constructor() {
+            switch(arguments.length) {
+                default:
+              case 1:
+              this.x = arguments[0].x;
+              this.y = arguments[0].y;
+                break;
+              case 2:
+              this.x = arguments[0];
+              this.y = arguments[1];
+                break;
+            }
+        }
+        get length(){
+            if(this.x == 0 && this.y == 0)
+                return 0;
+            return Math.sqrt(this.x*this.x+this.y*this.y);
+        }/** */
+        get mod(){
+            var length = this.length;
+            return new this.constructor(this.x/length,this.y/length);
+        }/**/
+        radian(anotherVector){//都必须是长度为1的vector
+            return Math.asin(Math.sqrt(Math.pow(this.x - anotherVector.x,2)+Math.pow(this.y - anotherVector.y,2))/2)*2; 
+        }
+        angle(anotherModVector){
+            return this.radian(anotherModVector)/Math.PI*180; 
+        }
+        rotate(radian){
+            var cosRadian = Math.cos(radian);
+            var sinRadian = Math.sin(radian);
+            return new this.constructor(this.x * cosRadian + this.y * sinRadian, this.y * cosRadian - this.x * sinRadian);
+        }
+        rotateAngle(angle){
+            return this.rotate(angle / 180 * Math.PI);
+        }
+        plus(anotherVector){
+            return new this.constructor(this.x + anotherVector.x, this.y + anotherVector.y);
+        }
+        minus(anotherVector){
+            return new this.constructor(this.x - anotherVector.x, this.y - anotherVector.y);
+        }
+        multiply(num){
+            return new this.constructor(this.x * num, this.y * num);
+        }
+        toLength(length){
+            var mod = this.mod;
+            return new this.constructor(mod.x * length, mod.y * length);
+        }
+    },
+    Line2:class{
+        constructor() {
+            switch(arguments.length) {
+                default:
+              case 1:
+              this.a = arguments[0].a;
+              this.b = arguments[0].b;
+                break;
+              case 2:
+              this.a = arguments[0];
+              this.b = arguments[1];
+                break;
+              case 4:
+              this.a = new module.exports.Vector2(arguments[0],arguments[1]);
+              this.b = new module.exports.Vector2(arguments[2],arguments[3]);
+                break;
+            }
+        }
+        vertex(index){
+            switch(index){
+                default:
+                case 0:
+                    return this.a;
+                case 1:
+                    return this.b;
+            }
+        }
+        get vector(){
+            return this.b.minus(this.a);
+        }
+        get length(){
+            return this.vector.length;
+        }
+    },
+    Rect:class{
+        constructor() {
+            switch(arguments.length) {
+                default:
+              case 1:
+              this.position = arguments[0].position;
+              this.size = arguments[0].size;
+                break;
+              case 2:
+              this.position = arguments[0];
+              this.size = arguments[1];
+                break;
+              case 4:
+              this.position = new module.exports.Vector2(arguments[0],arguments[1]);
+              this.size = new module.exports.Vector2(arguments[2],arguments[3]);
+                break;
+            }
+        }
+        vertex(index){
+            switch(index){
+                default:
+                case 0:
+                    return this.position;
+                case 1:
+                    return new module.exports.Vector2(this.position.x,this.position.y+this.size.y);
+                case 2:
+                    return this.position.plus(this.size);
+                case 3:
+                    return new module.exports.Vector2(this.position.x+this.size.x,this.position.y);
+            }
+        }//Clockwise
+        edge(index){
+            switch(index){
+                default:
+                case 0:
+                    return new module.exports.Line2(this.vertex(0),this.vertex(1));
+                case 1:
+                    return new module.exports.Line2(this.vertex(1),this.vertex(2));
+                case 2:
+                    return new module.exports.Line2(this.vertex(2),this.vertex(3));
+                case 3:
+                    return new module.exports.Line2(this.vertex(3),this.vertex(0));
+            }
+        }//Clockwise
+        get vertexs(){
+            var edges = [];
+            for(var i = 0;i<4;++i){
+                edges.push(this.vertex(i));
+            }
+            return edges;
+        }
+        get edges(){
+            var edges = [];
+            for(var i = 0;i<4;++i){
+                edges.push(this.edge(i));
+            }
+            return edges;
+        }
+        get pos(){
+            return this.position;
+        }
+        set pos(value){
+            this.position = value;
+        }
+        get x(){
+            return this.position.x;
+        }
+        set x(value){
+            this.position.x = value;
+        }
+        get y(){
+            return this.position.y;
+        }
+        set y(value){
+            this.position.y = value;
+        }
+        get width(){
+            return this.size.x;
+        }
+        set width(value){
+            this.size.x = value;
+        }
+        get height(){
+            return this.size.y;
+        }
+        set height(value){
+            this.size.y = value;
+        }
+    },
+    Vector3: class{
+        constructor() {
+            switch(arguments.length) {
+                default:
+                case 1:
+                    this.x = arguments[0].x;
+                    this.y = arguments[0].y;
+                    this.z = arguments[0].z;
+                    break;
+                case 3:
+                    this.x = arguments[0];
+                    this.y = arguments[1];
+                    this.z = arguments[2];
+                    break;
+            }
+        }
+        get length(){
+            if(this.x == 0 && this.y == 0 && this.z == 0)
+                return 0;
+            return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z);
+        }/** */
+        get mod(){
+            var length = this.length;
+            return new this.constructor(this.x/length,this.y/length,this.z/length);
+        }
+        plus(anotherVector){
+            return new this.constructor(this.x + anotherVector.x, this.y + anotherVector.y, this.z + anotherVector.z);
+        }
+        minus(anotherVector){
+            return new this.constructor(this.x - anotherVector.x, this.y - anotherVector.y, this.z - anotherVector.z);
+        }
+        multiply(num){
+            return new this.constructor(this.x * num, this.y * num, this.z * num);
+        }
+        toLength(length){
+            var mod = this.mod;
+            return new this.constructor(mod.x * length, mod.y * length, mod.z * length);
+        }
+    },
+    isSameSign:function(a,b){
+        if((a>=0&&b>=0)||(a<=0&&b<=0)){
+            return true;
+        }
+        return false;
+    },
+    distance2:function(a,b){
+        var distance = Math.sqrt(Math.pow(a.x-b.x,2)+Math.pow(a.y-b.y,2));
+        switch(arguments.length) {
+            default:
+            case 2:
+                return distance;
+            case 3:
+                var vector = arguments[2];//vector must be in same line with a b
+                if(module.exports.isSameSign(b.x - a.x,vector.x)&&module.exports.isSameSign(b.y - a.y,vector.y)){
+                    return distance;
+                }else{
+                    return -distance;
+                }
+        }
+    },
+    maxLengthLine2:function(vertexs){
+        if(vertexs.length==0){
+            return null;
+        }
+        if(vertexs.length==1){
+            return new module.exports.Line2(vertexs[0],vertexs[0]);
+        }
+        var maxLengthLine = null;
+        var maxLength = -1;
+        for(var i = 0;i<vertexs.length-1;++i){            
+            for(var j = i+1;j<vertexs.length;++j){
+                var newLine = new module.exports.Line2(vertexs[i],vertexs[j]);
+                var newLength = newLine.length;
+                if(maxLength < newLength){
+                    maxLength = newLength;
+                    maxLengthLine = newLine;
+                }
+            }
+        }
+        return maxLengthLine;
+    },
+    randomInCircle2:function(){
+        var center;//diameter
+        var size;//diameter
+        switch(arguments.length) {
+            default:
+            case 1:
+                center = new module.exports.Vector2(0,0);
+                size = arguments[0];
+                break;
+            case 2:
+                center = arguments[0];
+                size = arguments[1];
+                break;
+        }
+        return new module.exports.Vector2(1,0).rotate(Math.random() * Math.PI*2).toLength(Math.sqrt(Math.random()*Math.pow(size/2,2))).plus(center);
+    },
+    intersectionLineLine2:function(){//for 2D //https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
+        var p11,p12,p21,p22;
+        switch(arguments.length) {
+            default:
+            case 4:
+                p11 = arguments[0];
+                p12 = arguments[1];
+                p21 = arguments[2];
+                p22 = arguments[3];
+                break;
+            case 2:
+                p11 = arguments[0].a;
+                p12 = arguments[0].b;
+                p21 = arguments[1].a;
+                p22 = arguments[1].b;
+                break;
+        }
+        var denominator = (p11.x-p12.x)*(p21.y-p22.y) - (p11.y-p12.y)*(p21.x-p22.x);
+        if(denominator == 0){
+            return null;
+        }
+        var t = ((p11.x-p21.x)*(p21.y-p22.y) - (p11.y-p21.y)*(p21.x-p22.x))/denominator;
+        var u = ((p11.x-p12.x)*(p11.y-p21.y) - (p11.y-p12.y)*(p11.x-p21.x))/denominator;
+        return new module.exports.Vector2(p11.x+t*(p12.x-p11.x),p11.y+t*(p12.y-p11.y));
+    },
+    arrangeInLine1:function(p1, p2, vector){//1维//vector为正,p1小于p2
+        var values = [];
+        for(var i =  Math.ceil(p1/vector)*vector;i<=p2;i+=vector){
+            values.push(i);
+        }
+        return values;
+    },
+    arrangeInLine2:function(){//3点必须在1线
+        //return [];
+        var p1, p2, origin, vector;
+        switch(arguments.length) {
+            default:
+            case 4:
+                p1 = arguments[0];
+                p2 = arguments[1];
+                origin = arguments[2];
+                vector = arguments[3];
+                break;
+            case 3:
+                if(arguments[0] == null){
+                    return [];
+                } 
+                p1 = arguments[0].a;
+                p2 = arguments[0].b;
+                origin = arguments[1];
+                vector = arguments[2];
+                break;
+        }
+        var begin,end;
+        if(module.exports.isSameSign(p2.x - p1.x,vector.x)&&module.exports.isSameSign(p2.y - p1.y,vector.y)){
+            begin = p1;
+            end = p2;
+        }else{
+            begin = p2;
+            end = p1;
+        }
+        if(module.exports.isSameSign(begin.x - origin.x,vector.x)&&module.exports.isSameSign(begin.y - origin.y,vector.y)){
+            begin = module.exports.distance2(origin,begin);
+        }else{
+            begin = -module.exports.distance2(origin,begin);
+        }
+        if(module.exports.isSameSign(end.x - origin.x,vector.x)&&module.exports.isSameSign(end.y - origin.y,vector.y)){
+            end = module.exports.distance2(origin,end);
+        }else{
+            end = -module.exports.distance2(origin,end);
+        }
+        var points = [];
+        var modVector = vector.mod;
+        var values = module.exports.arrangeInLine1(begin, end, vector.length);
+        for(var i = 0;i<values.length;++i){
+            points.push(origin.plus(modVector.multiply(values[i])));
+        }
+        return points;/** */        
+    },
+    pointOnLineSegment(line,point){
+        var acceptableError = line.length / 1000000;//存在计算误差
+        var v1 = line.a.minus(point);
+        var v2 = line.b.minus(point);
+        if(module.exports.isSameSign(v1.x,v2.x)&&module.exports.isSameSign(v1.y,v2.y)&&v1.length>=acceptableError&&v2.length>=acceptableError){//存在计算误差
+            return false;
+        }
+        return true;
+    },
+    lineSegmentInRect(rect,line){
+        var edge = rect.edges;
+        var ip = [];
+        for(var i = 0;i<edge.length;++i){
+            var newIp = module.exports.intersectionLineLine2(edge[i], line);
+            if(newIp != null &&module.exports.pointOnLineSegment(edge[i],newIp)){
+                ip.push(newIp);
+            }
+        }
+        return module.exports.maxLengthLine2(ip);/** */
+    },
+    arrangeInRect2:function(rect, origin, horizontalVector, verticalVector){
+        var ip = [];
+        for(var i = 0; i < 4;++i){
+            ip.push(module.exports.intersectionLineLine2(origin,origin.plus(verticalVector),rect.vertex(i),rect.vertex(i).plus(horizontalVector)));
+        }
+        if(module.exports.distance2(ip[0],ip[2]) > module.exports.distance2(ip[1],ip[3])){
+            ip = [ip[0],ip[2],ip[1],ip[3]];//verticalBegin;verticalEnd;horizontalBegin;horizontalEnd;
+        }else{
+            ip = [ip[1],ip[3],ip[0],ip[2]];//verticalBegin;verticalEnd;horizontalBegin;horizontalEnd;
+        }
+        var pos = [];
+        var verticalPoints = module.exports.arrangeInLine2(ip[0],ip[1],origin,verticalVector);
+        for(var i = 0; i<verticalPoints.length;++i){
+            var lineSegmentInRect = module.exports.lineSegmentInRect(rect,new module.exports.Line2(verticalPoints[i],verticalPoints[i].plus(horizontalVector)));//}/*
+            var horizontalPoints = module.exports.arrangeInLine2(lineSegmentInRect,verticalPoints[i],horizontalVector);
+            pos = pos.concat(horizontalPoints);
+        }
+        return pos;/** */
+        //return verticalPoints;
+    }
+};

+ 437 - 0
util/util-js/o0Project.js

@@ -0,0 +1,437 @@
+import o0 from "./o0.js"
+
+module.exports = {
+	Filter: class {
+		constructor() {
+
+			this.stableAcceleration = null;
+			this.maxrecordCount = 999999;
+
+			this.frame = [];
+			this.frameHit = []; //打击后的n帧
+			for (var i = 0; i < 200; ++i) {
+				var o = new Object();
+				o.time = new Date().getTime();
+				o.timeGap = 20;
+				o.acc = new o0.Vector2(0, 0);
+				o.gyr = new o0.Vector2(0, 0);
+				o.accFixed = 0;
+				o.accSlope = 0;
+				o.pos = new o0.Vector2(0, 0);
+				o.predict = new o0.Vector2(0, 0);
+				o.shake = 0;
+				o.shakeFixed = 1;
+				o.shakeSlope = 0;
+				o.reliable = 1;
+				o.speed = new o0.Vector2(0, 0);
+				o.hit = 0;
+				this.frame.push(o);
+				//this.frameHit.push(o);
+			}
+			this.frameSwing = this.frame[0];
+			//this.frame = 0;
+
+			this.force = new o0.Vector2(0, 0);
+			this.forceChanged = 0;
+			this.momentum = 999999;
+			this.momentunTime = 0;
+			this.momentunSeek = 0.1;
+			this.momentunPunch = false;
+			this.punchCount = 0;
+			this.leftRight = false;
+
+			this.forceRecord = [];
+			for (var i = 0; i < 1; ++i) {
+				this.forceRecord.push(new o0.Vector2(0, 0));
+			} /** */
+			this.angle = 0;
+			this.quitHitCount = 0;
+		}
+		Update(vector3, timeGap, gyr, callback) {
+			if (this.stableAcceleration == null) {
+				this.stableAcceleration = vector3;
+				this.recordCount = 1;
+			} else {
+				this.recordCount += 1;
+				if (this.recordCount > this.maxrecordCount) {
+					this.recordCount = this.maxrecordCount;
+				}
+				let recordCount = this.recordCount;
+				this.stableAcceleration = this.stableAcceleration.multiply((recordCount - 1) / recordCount).plus(vector3.multiply(
+					1 / recordCount));
+			}
+
+			//++this.frame;
+
+			var newForce = vector3.minus(this.stableAcceleration);
+
+			var newFrame = new Object();
+			newFrame.time = new Date().getTime();
+			newFrame.timeGap = timeGap;
+			newFrame.acc = new o0.Vector2(newForce.x, newForce.z);
+			newFrame.gyr = new o0.Vector2(gyr.z, -gyr.x);
+			let lastFrame = this.frame[this.frame.length - 1];
+			let last2Frame = this.frame[this.frame.length - 2];
+			let last3Frame = this.frame[this.frame.length - 3];
+			let last4Frame = this.frame[this.frame.length - 4];
+			let last5Frame = this.frame[this.frame.length - 5];
+			//////////////////////////////////////////////////////////////////////
+			newFrame.accFixed = newFrame.acc.length * 100;
+
+			if (newFrame.accFixed < lastFrame.accFixed * 0.85) {
+				newFrame.accFixed = lastFrame.accFixed * 0.85;
+			}
+			lastFrame.accFixed = Math.max(lastFrame.accFixed, Math.min(newFrame.accFixed, last2Frame.accFixed), Math.min(
+				newFrame.accFixed, last3Frame.accFixed));
+			///////////////////////////////////////////////////////////////////////
+			//newFrame.pos = lastFrame.pos.plus(lastFrame.acc.plus(newFrame.acc).multiply(timeGap/60)).multiply(Math.max(1-timeGap/200,0));
+			newFrame.pos = lastFrame.pos.plus(newFrame.acc.multiply(timeGap / 30)).multiply(Math.max(1 - timeGap / 1000, 0));
+			////////////////////////////////////////////
+			var accSlpoe1 = (newFrame.accFixed - lastFrame.accFixed);
+			var accSlpoe2 = (newFrame.accFixed - last2Frame.accFixed);
+			var accSlpoe3 = (newFrame.accFixed - last3Frame.accFixed);
+			//newFrame.accSlope = accSlpoe1;
+			//newFrame.accSlope = Math.min(accSlpoe1,accSlpoe2);
+			//newFrame.accSlope = Math.min(accSlpoe1,accSlpoe2,accSlpoe3);
+			newFrame.accSlope = Math.max(newFrame.accFixed - lastFrame.accFixed, 0);
+
+			/*
+			if(newFrame.accSlope > 8){
+				newFrame.accSlope = 1; 
+			}else if(newFrame.accSlope <= 8){
+				newFrame.accSlope = 0;
+			}/** */
+			/////////////////////////////////////////////////
+
+			var lastI = this.frame.length - 1;
+			var t2 = this.frame[lastI - 1].timeGap;
+			var t3 = this.frame[lastI].timeGap + t2;
+			var t4 = newFrame.timeGap + t3;
+
+			/*newFrame.predict = new o0.Vector2(
+				new o0.QuadraticEquation(0,this.frame[lastI-2].acc.x,t2,this.frame[lastI-1].acc.x,t3,this.frame[lastI].acc.x).y(t4),
+				new o0.QuadraticEquation(0,this.frame[lastI-2].acc.y,t2,this.frame[lastI-1].acc.y,t3,this.frame[lastI].acc.y).y(t4));/** */
+			/*
+			newFrame.predict = new o0.Vector2(
+				new o0.QuadraticEquation(0,this.frame[lastI-2].pos.x,t2,this.frame[lastI-1].pos.x,t3,this.frame[lastI].pos.x).y(t4),
+				new o0.QuadraticEquation(0,this.frame[lastI-2].pos.y,t2,this.frame[lastI-1].pos.y,t3,this.frame[lastI].pos.y).y(t4));/** */
+
+			newFrame.predict = new o0.Vector2(
+				new o0.QuadraticEquation(0, this.frame[lastI - 2].pos.x, t2, this.frame[lastI - 1].pos.x, t3, this.frame[lastI]
+					.pos.x).y(t4),
+				new o0.QuadraticEquation(0, this.frame[lastI - 2].pos.y, t2, this.frame[lastI - 1].pos.y, t3, this.frame[lastI]
+					.pos.y).y(t4)); /** */
+			//console.log(newFrame.pos);
+			//////////////////////////////////////////
+			//newFrame.shake = o0.distance2(newFrame.predict,newFrame.pos) * 500;
+			//console.log(newFrame.pos.minus(lastFrame.pos).mod.angle(newFrame.predict.minus(lastFrame.pos).mod));
+
+			//newFrame.shake = o0.distance2(newFrame.predict,newFrame.acc) * 100;
+			newFrame.shake = o0.distance2(newFrame.predict, newFrame.pos) * 100;
+
+
+			//newFrame.shake = o0.distance2(newFrame.predict,lastFrame.pos) * newFrame.acc.length / timeGap * 2000;
+
+			if (isNaN(newFrame.shake)) {
+				newFrame.shake = 0.0;
+			} /** */
+			//newFrame.shake = Math.pow(o0.distance2(newFrame.predict,newFrame.pos) * newFrame.acc.length / timeGap,0.5) * 500;
+			/////////////////////////////下面的代码有优化空间
+			//newFrame.shakeFixed = lastFrame.shakeFixed * 0.9;
+			//newFrame.shakeFixed = lastFrame.shakeFixed*(1.0+newFrame.shake)*0.9;
+			//newFrame.shakeFixed = Math.pow(lastFrame.shakeFixed*(1.0+newFrame.shake),0.5)+1;
+			//console.log(newFrame.shakeFixed+1);
+			//newFrame.shakeFixed = newFrame.shake;
+
+			newFrame.shakeFixed = lastFrame.shakeFixed * 0.85;
+			if (newFrame.shake > newFrame.shakeFixed) {
+				newFrame.shakeFixed = newFrame.shake;
+			} /* */
+			lastFrame.shakeFixed = Math.max(lastFrame.shakeFixed, Math.min(newFrame.shakeFixed, last2Frame.shakeFixed), Math.min(
+				newFrame.shakeFixed, last3Frame.shakeFixed));
+			////////////////////////////////////////////////////////////////
+			/*
+			var shakeSlpoe1 = (newFrame.shakeFixed-lastFrame.shakeFixed);
+			var shakeSlpoe2 = (newFrame.shakeFixed-last2Frame.shakeFixed);
+			var shakeSlpoe3 = (newFrame.shakeFixed-last3Frame.shakeFixed);
+			//newFrame.accSlope = accSlpoe1;
+			//newFrame.accSlope = Math.min(accSlpoe1,accSlpoe2);
+			newFrame.shakeSlope = Math.min(shakeSlpoe1,shakeSlpoe2,shakeSlpoe3);
+			newFrame.shakeSlope = Math.max(newFrame.shakeSlope,0);/** */
+			newFrame.shakeSlope = Math.max(newFrame.shakeFixed - lastFrame.shakeFixed, 0);
+
+			/*
+			if(newFrame.shakeSlope > 40){
+				newFrame.shakeSlope = 1;
+			}else{
+				newFrame.shakeSlope = 0;
+			}/** */
+			//////////////////////////////////////////////
+			/*
+			var slopeChange = newFrame.shakeFixed - lastFrame.shakeFixed;
+			if(slopeChange < 0){
+				newFrame.slope = (lastFrame.slope + (newFrame.shakeFixed - lastFrame.shakeFixed) / timeGap * 100) * 0.8;
+			}else{
+				newFrame.slope = (lastFrame.slope + (newFrame.shakeFixed - lastFrame.shakeFixed) / timeGap * 20) * 0.8;
+			}
+			if(newFrame.slope<0){
+				newFrame.slope = 0;
+			}/** */
+			/////////////////////////////下面的代码有很大优化空间
+			if (lastFrame.hit == 0 &&
+				last2Frame.hit == 0 &&
+				last3Frame.hit == 0 &&
+				last4Frame.hit == 0 &&
+				last5Frame.hit == 0 &&
+				(newFrame.accSlope >= 15 || lastFrame.accSlope >= 20) &&
+				(newFrame.shakeSlope >= 20 || lastFrame.shakeSlope >= 40)) {
+				newFrame.hit = newFrame.shake;
+				this.frameHit = [];
+
+				//this.frameSwing = last2Frame;
+				for (var i = this.frame.length - 3; i >= 1; --i) {
+					let io = this.frame[i];
+					let pio = this.frame[i - 1];
+					if (io.accFixed * 0.85 <= pio.accFixed && io.accFixed >= pio.accFixed * 0.85) {
+						this.frameSwing = io;
+					}
+				}
+
+
+			} else {
+				newFrame.hit = 0;
+			}
+
+
+			/*
+			if(lastFrame.hit == 0 
+				&& this.frame[this.frame.length-2].hit == 0
+				&& this.frame[this.frame.length-3].hit == 0
+				&& newFrame.shakeFixed > 150
+				&& newFrame.shakeFixed > lastFrame.shakeFixed * 2){
+				newFrame.hit = newFrame.shakeFixed;
+			}else{
+				newFrame.hit = 0;
+			}/** */
+			/////////////力量大小
+			if (lastFrame.hit != 0) {
+				lastFrame.hit = lastFrame.hit + newFrame.shake;
+			} else if (last2Frame.hit != 0) {
+				last2Frame.hit = last2Frame.hit + newFrame.shake;
+			} else if (last3Frame.hit != 0) {
+				last3Frame.hit = last3Frame.hit + newFrame.shake;
+			} else if (last4Frame.hit != 0) {
+				last4Frame.hit = last4Frame.hit + newFrame.shake;
+			} else if (last5Frame.hit != 0) {
+				last5Frame.hit = last5Frame.hit + newFrame.shake;
+				this.getDirection(last5Frame.hit, callback);
+			} /** */
+			//newFrame.shake = o0.distance2(newFrame.predict,newFrame.pos) * o0.distance2(lastFrame.pos,newFrame.pos);
+			//////////////////////////////////////////////////////////////////////////////////
+			newFrame.reliable = Math.pow((Math.PI / 2 - Math.atan(newFrame.shakeFixed / 10000)) / (Math.PI / 2), 2000);
+
+			let lastFrameAddSpeed = lastFrame.acc.multiply(lastFrame.timeGap / 20).multiply(lastFrame.reliable);
+			let newFrameAddSpeed = newFrame.acc.multiply(newFrame.timeGap / 20).multiply(newFrame.reliable);
+
+			newFrame.speed = lastFrame.speed.multiply(0.8);
+			var lastFrameAngle = newFrame.speed.angle(lastFrameAddSpeed);
+			if (isNaN(lastFrameAngle)) {
+				lastFrameAngle = 180.0;
+			}
+			//newFrame.speed = newFrame.speed.plus(lastFrameAddSpeed.multiply(Math.max(1,lastFrameAngle/60.0 - 1)));
+			//newFrame.speed = newFrame.speed.multiply(1).plus(lastFrameAddSpeed.multiply(Math.max(1,lastFrameAngle/60.0 - 1)));
+			newFrame.speed = newFrame.speed.multiply(1 - lastFrameAngle / 360.0).plus(lastFrameAddSpeed.multiply(Math.max(1,
+				lastFrameAngle / 60.0 - 1)));
+			var newFrameAngle = newFrame.speed.angle(newFrameAddSpeed);
+			if (isNaN(newFrameAngle)) {
+				newFrameAngle = 180.0;
+			}
+			//newFrame.speed = newFrame.speed.plus(newFrameAddSpeed.multiply(Math.min(1,newFrameAngle/60.0-1)));
+			newFrame.speed = newFrame.speed.multiply(1 - newFrameAngle / 360.0).plus(newFrameAddSpeed.multiply(Math.max(1,
+				newFrameAngle / 60.0 - 1)));
+
+
+			//////////////////////
+			this.frame.shift();
+			this.frame.push(newFrame);
+			if (this.frameHit.length <= 10) {
+				var o = new Object();
+				o.time = newFrame.time;
+				o.timeGap = newFrame.timeGap;
+				o.acc = newFrame.acc;
+				o.gyr = newFrame.gyr;
+
+				let frameHitLength = this.frameHit.length + 1;
+				let lastFrameHit = this.frameHit[this.frameHit.length - 1];
+				if (frameHitLength == 1) {
+					o.allShakeLength = newFrame.shakeFixed;
+				} else {
+					o.allShakeLength = lastFrameHit.allShakeLength + newFrame.shakeFixed;
+				}
+
+				o.accFixed = o.acc.multiply(Math.pow(Math.max(0, 1 - newFrame.shakeFixed * frameHitLength / o.allShakeLength), 5) *
+					20); //数字越大越忽略历史数据
+
+				if (frameHitLength == 1) {
+					o.pos = o.accFixed.multiply(o.timeGap / 60);
+				} else {
+					o.pos = lastFrameHit.pos.plus(lastFrameHit.accFixed.plus(o.accFixed).multiply(o.timeGap / 60));
+				}
+				this.frameHit.push(o);
+			}
+
+			var vectorChanged = newForce.minus(this.force);
+			var forceLength = this.force.length;
+			var ForceChanged = newForce.length - forceLength;
+			this.force = newForce;
+
+			var currentLeftRight;
+			if (Math.abs(newForce.x + newForce.z) > Math.abs(newForce.x - newForce.z)) {
+				currentLeftRight = Math.abs(newForce.x + newForce.z);
+			} else {
+				currentLeftRight = -Math.abs(newForce.x - newForce.z);
+			}
+			this.forceRecord.shift();
+			this.forceRecord.push(newForce);
+
+			if (this.forceChanged > 0 && ForceChanged < 0) { // && forceLength > 0.1
+				//&& this.momentum * Math.pow(0.9,(new Date().getTime()-this.momentunTime)/1) < forceLength){
+				/*console.log(forceLength.toFixed(2));
+				if( forceLength > 0.1 && forceLength >= this.momentum * 1.5){
+					console.log(this.frame+" "+forceLength);
+				}/** */
+				if (forceLength > 0.1 && this.momentum != 999999) {
+					if (!this.momentunPunch) { //等待击打
+						if (this.momentunSeek > this.momentum) {
+							this.momentunSeek = this.momentum;
+						} else {
+							if (this.momentunSeek < this.momentum * 0.8 - 0.1) {
+								this.momentunPunch = !this.momentunPunch;
+								this.punchCount++;
+								//this.leftRight = (newForce.x+this.force.x) < 0;
+
+								/*
+								var largestForce = new o0.Vector3(0,0,0)
+								for(var i = 0;i<this.forceRecord.length;++i){
+									var element = this.forceRecord[i];
+									if(largestForce.length < element.length){
+										largestForce = element;
+									}
+								}
+								if(Math.abs(largestForce.x + largestForce.z) > Math.abs(largestForce.x - largestForce.z)){
+									currentLeftRight = Math.abs(largestForce.x + largestForce.z);
+								}else{
+									currentLeftRight = -Math.abs(largestForce.x - largestForce.z);
+								}/** */
+								this.leftRight = currentLeftRight < 0 ? "Right" : "Left";
+								this.angle = new o0.Vector2(newForce.x, newForce.z).mod.angle(new o0.Vector2(0, 1));
+								if (this.angle > 90) {
+									this.angle = 180 - this.angle;
+								}
+								if (currentLeftRight > 0) {
+									this.angle = -this.angle;
+								} /** */
+								//this.leftRight = (largestChange.x > 0 && largestChange.z > 0) || (largestChange.x < 0 && largestChange.z < 0);
+								/* */
+								//console.log(this.momentum);
+							}
+						}
+					} else { //打完了
+						if (this.momentunSeek < this.momentum) {
+							this.momentunSeek = this.momentum;
+						} else if (this.momentunSeek > this.momentum * 1.2 + 0.1) {
+							this.momentunPunch = !this.momentunPunch;
+						}
+					}
+				}
+
+				this.momentum = forceLength;
+				this.momentunTime = new Date().getTime();
+			}
+
+			this.forceChanged = ForceChanged;
+
+
+
+			//console.log(vector3.x);
+			return [new o0.Vector3(newForce), currentLeftRight, this.momentum];
+		}
+		test() {
+			return "123123131";
+		}
+		getDirection(hitValue, callback) {
+			var direction = new o0.Vector2(0, 0);
+			var directionDistance = 0;
+			for (var fi = 1; fi < this.frameHit.length - 1; ++fi) {
+				for (var li = fi + 1; li < this.frameHit.length; ++li) {
+					let firstGyr = this.frameHit[fi].gyr;
+					let lastGyr = this.frameHit[li].gyr;
+					let newDirectionDistance = o0.distance2(firstGyr, lastGyr);
+					if (directionDistance < newDirectionDistance) {
+						directionDistance = newDirectionDistance;
+						direction = lastGyr.minus(firstGyr);
+					}
+				}
+			}
+
+			let curAngle = new o0.Vector2(direction.x, direction.y).mod.angle(new o0.Vector2(0, 1));
+			let directionPunch = "all",
+				name = "击中",
+				ename = "hit";
+			let curAngleCeil = Math.ceil(curAngle);
+			//已坐标 (0,1) 向量为参考
+			if (direction.y < 0) {
+				//相反方向击打
+				//正方向
+				if (curAngleCeil > 150) {
+					directionPunch = "straightPunch";
+					name = "负向的直拳";
+					ename = "back-straight";
+				} else if (direction.x > 0) {
+					directionPunch = "rightPunch";
+					name = "负向的右拳";
+					ename = "back-right";
+				} else if (direction.x < 0) {
+					directionPunch = "leftPunch";
+					name = "负向的左拳";
+					ename = "back-left";
+				}
+			} else {
+				// y 大于零 手柄正方向击打
+				if (curAngleCeil < 30) {
+					directionPunch = "straightPunch";
+					name = "正向的直拳";
+					ename = "front-straight";
+				} else if (direction.x < 0) {
+					directionPunch = "rightPunch";
+					name = "正向的右拳";
+					ename = "front-right";
+				} else if (direction.x > 0) {
+					directionPunch = "leftPunch";
+					name = "正向的左拳";
+					ename = "front-left";
+				}
+			}
+
+
+			this.quitHitCount++;
+			if (callback) {
+				let temp = {
+					type: 'hit',
+					hit: hitValue / 5,
+					hitCount: this.quitHitCount,
+					direction: directionPunch,
+					directionVect: {
+						'x': direction.x,
+						'y': direction.y
+					},
+					angle: curAngleCeil,
+					name: name,
+					ename: ename
+				}
+				callback(temp);
+			}
+
+		}
+	}
+};

+ 164 - 0
util/util-js/o0ProjectRelease.js

@@ -0,0 +1,164 @@
+import o0 from "./o0.js"
+
+module.exports = {
+    SandbagAlgorithm: class{
+        constructor() {
+
+			this.stableAcc = new o0.Vector2(0,0);
+			this.stableGyr = new o0.Vector2(0,0);
+			this.stableCount = 0;
+			this.stableCountMax = 3000;
+
+			this.frameCapacity = 6;
+			this.frame = [];
+			this.frameLength = 5;
+			this.frameOffset = 0;
+
+			this.frameHitCapacity = 11;
+			this.frameHit = [];//打击后的n帧
+
+			for(var i = 0;i<this.frameCapacity;++i){
+				var o = new Object();
+				o.acc = new o0.Vector2(0,0);
+				o.gyr = new o0.Vector2(0,0);
+				
+				o.timeGap = 20;
+				o.accFixed = 0;
+				o.accSlope = 0;
+
+				o.pos = new o0.Vector2(0,0);
+				o.predict = new o0.Vector2(0,0);
+
+				o.shake = 0;
+				o.shakeFixed = 0;
+				o.shakeSlope = 0;
+
+				o.hit = 0;
+				this.frame.push(o);
+			}
+		}
+		//这个函数不建议外部调用
+		GetDirection(){
+            var direction = new o0.Vector2(0,0);
+			var directionDistance = 0.0;
+			for (var fi = 0;fi < this.frameHit.length - 1;++fi) {
+				for (var li = fi + 1;li < this.frameHit.length;++li) {
+					var newDirection = this.frameHit[li].gyr - this.frameHit[fi].gyr;
+					var newDirectionDistance = newDirection.length;
+					if (directionDistance < newDirectionDistance) {
+						directionDistance = newDirectionDistance;
+						direction = newDirection.multiply(this.frameHit[this.frameHit.length -1].time - this.frameHit[0].time);
+					}
+					else {
+						//cout << "false" << endl;
+					}
+				}
+			}
+			return direction;
+		}
+		// 输入俯视的平面坐标系下的xy轴坐标 的 加速计向量/陀螺仪向量。
+		// timeGap 代表当前帧读取传感器与上一帧读取传感器 之间的时间差
+		Update(accX, accY, gyrX,gyrY,timeGap,callback){
+			var rawAcc = new o0.Vector2(accX,accY);
+			var rawGyr = new o0.Vector2(gyrX,gyrY);
+
+			let lastFrame = this.frame[(this.frameOffset + this.frameLength - 1) % this.frameCapacity];
+			let last2Frame = this.frame[(this.frameOffset + this.frameLength - 2) % this.frameCapacity];
+			let last3Frame = this.frame[(this.frameOffset + this.frameLength - 3) % this.frameCapacity];
+			let last4Frame = this.frame[(this.frameOffset + this.frameLength - 4) % this.frameCapacity];
+			let last5Frame = this.frame[(this.frameOffset + this.frameLength - 5) % this.frameCapacity];
+			var newFrame = this.frame[(this.frameOffset + this.frameLength) % this.frameCapacity];
+
+			newFrame.timeGap = timeGap;
+
+			newFrame.acc = rawAcc.minus(this.stableAcc);
+			newFrame.gyr = rawGyr.minus(this.stableGyr);
+
+			if (this.stableCount < this.stableCountMax){
+				this.stableCount += 1;
+			}
+			this.stableAcc = this.stableAcc.multiply((this.stableCount - 1.0) / this.stableCount).plus(rawAcc.multiply(1/this.stableCount));
+			this.stableGyr = this.stableGyr.multiply((this.stableCount - 1.0) / this.stableCount).plus(rawGyr.multiply(1/this.stableCount));
+			//////////////////////////////////////////////////////////////////////////////////
+			newFrame.accFixed = newFrame.acc.length * 100;
+
+			if(newFrame.accFixed < lastFrame.accFixed * 0.85){
+				newFrame.accFixed = lastFrame.accFixed * 0.85;
+			}
+			lastFrame.accFixed = Math.max(lastFrame.accFixed, Math.min(newFrame.accFixed,last2Frame.accFixed), Math.min(newFrame.accFixed,last3Frame.accFixed));
+			///////////////////////////////////////////////////////////////////////
+			//newFrame.pos = lastFrame.pos.plus(lastFrame.acc.plus(newFrame.acc).multiply(timeGap/60)).multiply(Math.max(1-timeGap/200,0));
+			newFrame.pos = lastFrame.pos.plus(newFrame.acc.multiply(timeGap/30)).multiply(Math.max(1-timeGap/1000,0));
+			////////////////////////////////////////////
+			newFrame.accSlope = Math.max(newFrame.accFixed-lastFrame.accFixed,0);
+
+
+			var lastI = this.frame.length-1;
+			var t2 = this.frame[lastI-1].timeGap;
+			var t3 = this.frame[lastI].timeGap + t2;
+			var t4 = newFrame.timeGap + t3;
+			
+			newFrame.predict = new o0.Vector2(
+				new o0.QuadraticEquation(0,this.frame[lastI-2].pos.x,t2,this.frame[lastI-1].pos.x,t3,this.frame[lastI].pos.x).y(t4),
+				new o0.QuadraticEquation(0,this.frame[lastI-2].pos.y,t2,this.frame[lastI-1].pos.y,t3,this.frame[lastI].pos.y).y(t4));/** */
+
+			newFrame.shake = o0.distance2(newFrame.predict,newFrame.pos) * 100;
+
+
+			if(isNaN(newFrame.shake)){
+				newFrame.shake = 0.0;
+			}
+			
+			newFrame.shakeFixed = lastFrame.shakeFixed * 0.85;
+			if(newFrame.shake > newFrame.shakeFixed){
+				newFrame.shakeFixed = newFrame.shake;
+			}/* */
+			lastFrame.shakeFixed = Math.max(lastFrame.shakeFixed, Math.min(newFrame.shakeFixed,last2Frame.shakeFixed), Math.min(newFrame.shakeFixed,last3Frame.shakeFixed));
+			////////////////////////////////////////////////////////////////
+			newFrame.shakeSlope = Math.max(newFrame.shakeFixed-lastFrame.shakeFixed,0);
+			///////////////////////////////////////////////////////////////
+
+			var direction = new o0.Vector2(0,0);
+
+			if(lastFrame.hit==0
+				&& last2Frame.hit==0
+				&& last3Frame.hit==0
+				&& last4Frame.hit==0
+				&& last5Frame.hit==0
+				&& (newFrame.accSlope >= 15 || lastFrame.accSlope >= 20)
+				&& (newFrame.shakeSlope >= 20 || lastFrame.shakeSlope >= 40)){
+				newFrame.hit = 1;
+				if (this.frameHit.length < this.frameHitCapacity) {
+					direction = this.GetDirection();
+				}/**/
+				this.frameHit = [];
+				var o = new Object();
+				o.time = 0;
+				o.gyr = lastFrame.gyr;
+				this.frameHit.push(o);
+			}else{
+				newFrame.hit = 0;
+			}
+
+			if (this.frameHit.length < this.frameHitCapacity) {
+				var o = new Object();
+				o.time = this.frameHit[this.frameHit.length - 1].time + newFrame.timeGap;
+				o.gyr = newFrame.gyr; 
+				if (this.frameHit.length == this.frameHitCapacity) {
+					direction =  this.GetDirection();
+				}
+			}
+			if ((this.frameOffset+=1) >= this.frameCapacity){
+				this.frameOffset -= this.frameCapacity;
+			}
+			
+			if(newFrame.hit != 0){
+				console.log(newFrame.hit, direction);
+			}
+			return (newFrame.hit, direction);
+		}
+        test(){
+            return "123123131";
+        }
+    }
+};

+ 255 - 0
util/util-js/o0ProjectRelease0.1.js

@@ -0,0 +1,255 @@
+import o0 from "./o0.js"
+
+module.exports = {
+	SandbagAlgorithm: class {
+		constructor() {
+
+			this.stableAcc = new o0.Vector2(0, 0);
+			this.stableGyr = new o0.Vector2(0, 0);
+			this.stableCount = 0;
+			this.stableCountMax = 3000;
+
+			this.frameCapacity = 6;
+			this.frame = [];
+			this.frameLength = 5;
+			this.frameOffset = 0;
+
+			this.frameHitCapacity = 11;
+			this.frameHit = []; //打击后的n帧
+
+			for (var i = 0; i < this.frameCapacity; ++i) {
+				var o = new Object();
+				o.acc = new o0.Vector2(0, 0);
+				o.gyr = new o0.Vector2(0, 0);
+
+				o.timeGap = 20;
+				o.accFixed = 0;
+				o.accSlope = 0;
+
+				o.pos = new o0.Vector2(0, 0);
+				o.predict = new o0.Vector2(0, 0);
+
+				o.shake = 0;
+				o.shakeFixed = 0;
+				o.shakeSlope = 0;
+
+				o.hit = 0;
+				this.frame.push(o);
+			}
+
+			this.quitHitCount = 0;
+		}
+		//这个函数不建议外部调用
+		GetDirection() {
+			var direction = new o0.Vector2(0, 0);
+			var directionDistance = 0.0;
+			for (var fi = 0; fi < this.frameHit.length - 1; ++fi) {
+				for (var li = fi + 1; li < this.frameHit.length; ++li) {
+					var newDirection = this.frameHit[li].gyr.minus(this.frameHit[fi].gyr);
+					var newDirectionDistance = newDirection.length;
+					if (directionDistance < newDirectionDistance) {
+						directionDistance = newDirectionDistance;
+						direction = newDirection.multiply(this.frameHit[this.frameHit.length - 1].time -
+							this.frameHit[0].time);
+					} else {
+						//cout << "false" << endl;
+					}
+				}
+			}
+			return direction;
+		}
+		// 输入俯视的平面坐标系下的xy轴坐标 的 加速计向量/陀螺仪向量。
+		// timeGap 代表当前帧读取传感器与上一帧读取传感器 之间的时间差
+		Update(accX, accY, gyrX, gyrY, timeGap) {
+			var rawAcc = new o0.Vector2(accX, accY);
+			var rawGyr = new o0.Vector2(gyrX, gyrY);
+
+			let lastFrame = this.frame[(this.frameOffset + this.frameLength - 1) % this.frameCapacity];
+			let last2Frame = this.frame[(this.frameOffset + this.frameLength - 2) % this.frameCapacity];
+			let last3Frame = this.frame[(this.frameOffset + this.frameLength - 3) % this.frameCapacity];
+			let last4Frame = this.frame[(this.frameOffset + this.frameLength - 4) % this.frameCapacity];
+			let last5Frame = this.frame[(this.frameOffset + this.frameLength - 5) % this.frameCapacity];
+			var newFrame = this.frame[(this.frameOffset + this.frameLength) % this.frameCapacity];
+
+			newFrame.timeGap = timeGap;
+
+			newFrame.acc = rawAcc.minus(this.stableAcc);
+			newFrame.gyr = rawGyr.minus(this.stableGyr);
+
+			if (this.stableCount < this.stableCountMax) {
+				this.stableCount += 1;
+			}
+			this.stableAcc = this.stableAcc.multiply((this.stableCount - 1.0) / this.stableCount).plus(
+				rawAcc.multiply(1 / this.stableCount));
+			this.stableGyr = this.stableGyr.multiply((this.stableCount - 1.0) / this.stableCount).plus(
+				rawGyr.multiply(1 / this.stableCount));
+			//////////////////////////////////////////////////////////////////////////////////
+			newFrame.accFixed = newFrame.acc.length * 100;
+
+			if (newFrame.accFixed < lastFrame.accFixed * 0.85) {
+				newFrame.accFixed = lastFrame.accFixed * 0.85;
+			}
+			lastFrame.accFixed = Math.max(lastFrame.accFixed, Math.min(newFrame.accFixed, last2Frame
+				.accFixed), Math.min(newFrame.accFixed, last3Frame.accFixed));
+			///////////////////////////////////////////////////////////////////////
+			//newFrame.pos = lastFrame.pos.plus(lastFrame.acc.plus(newFrame.acc).multiply(timeGap/60)).multiply(Math.max(1-timeGap/200,0));
+			newFrame.pos = lastFrame.pos.plus(newFrame.acc.multiply(timeGap / 30)).multiply(Math.max(1 -
+				timeGap / 1000, 0));
+			////////////////////////////////////////////
+			newFrame.accSlope = Math.max(newFrame.accFixed - lastFrame.accFixed, 0);
+
+
+			var lastI = this.frame.length - 1;
+			var t2 = this.frame[lastI - 1].timeGap;
+			var t3 = this.frame[lastI].timeGap + t2;
+			var t4 = newFrame.timeGap + t3;
+
+			newFrame.predict = new o0.Vector2(
+				new o0.QuadraticEquation(0, this.frame[lastI - 2].pos.x, t2, this.frame[lastI - 1].pos
+					.x, t3, this.frame[lastI].pos.x).y(t4),
+				new o0.QuadraticEquation(0, this.frame[lastI - 2].pos.y, t2, this.frame[lastI - 1].pos
+					.y, t3, this.frame[lastI].pos.y).y(t4)); /** */
+
+			newFrame.shake = o0.distance2(newFrame.predict, newFrame.pos) * 100;
+
+
+			if (isNaN(newFrame.shake)) {
+				newFrame.shake = 0.0;
+			}
+
+			newFrame.shakeFixed = lastFrame.shakeFixed * 0.85;
+			if (newFrame.shake > newFrame.shakeFixed) {
+				newFrame.shakeFixed = newFrame.shake;
+			} /* */
+			lastFrame.shakeFixed = Math.max(lastFrame.shakeFixed, Math.min(newFrame.shakeFixed, last2Frame
+				.shakeFixed), Math.min(newFrame.shakeFixed, last3Frame.shakeFixed));
+			////////////////////////////////////////////////////////////////
+			newFrame.shakeSlope = Math.max(newFrame.shakeFixed - lastFrame.shakeFixed, 0);
+			///////////////////////////////////////////////////////////////
+
+			// (newFrame.accSlope >= 15 || lastFrame.accSlope >= 20) &&
+			// (newFrame.shakeSlope >= 20 || lastFrame.shakeSlope >= 40)
+			
+			var direction = undefined;
+			let _threshold = [15,20,20,40];//判定的阈值
+			if (lastFrame.hit == 0 &&
+				last2Frame.hit == 0 &&
+				last3Frame.hit == 0 &&
+				last4Frame.hit == 0 &&
+				last5Frame.hit == 0 &&
+				(newFrame.accSlope >= _threshold[0] || lastFrame.accSlope >= _threshold[1]) &&
+				(newFrame.shakeSlope >= _threshold[2] || lastFrame.shakeSlope >= _threshold[3])) {
+				newFrame.hit = 1;
+				if (this.frameHit.length < this.frameHitCapacity && this.frameHit.length !=
+					0) { //判断到第二次hit,但还未输出第一次hit的方向,强制输出方向
+					direction = this.GetDirection();
+				} /**/
+				this.frameHit = [];
+
+				/*
+				var o3 = new Object();
+				o3.time = 0;
+				o3.gyr = lastFrame3.gyr;
+				this.frameHit.push(o3);/* */
+
+				var o2 = new Object();
+				o2.time = last2Frame.timeGap;
+				o2.gyr = last2Frame.gyr;
+				this.frameHit.push(o2);
+
+				var o = new Object();
+				o.time = last2Frame.timeGap + lastFrame.timeGap;
+				o.gyr = lastFrame.gyr;
+				this.frameHit.push(o);
+			} else {
+				newFrame.hit = 0;
+			}
+
+			if (this.frameHit.length < this.frameHitCapacity && this.frameHit.length != 0) {
+				var o = new Object();
+				o.time = this.frameHit[this.frameHit.length - 1].time + newFrame.timeGap;
+				//o.gyr = this.frameHit[this.frameHit.length-1].gyr.plus(newFrame.gyr);
+				o.gyr = newFrame.gyr;
+				this.frameHit.push(o);
+				if (this.frameHit.length == this.frameHitCapacity) { //累计达到设定的延迟帧数,输出方向
+					direction = this.GetDirection();
+				}
+			}
+			if ((this.frameOffset += 1) >= this.frameCapacity) {
+				this.frameOffset -= this.frameCapacity;
+			}
+			return [newFrame.hit, direction];
+		}
+
+		getTempValue(curDirection) {
+			let result = Math.atan2(curDirection.y, curDirection.x) * 180 / (Math.PI);
+			result = Math.round(result);
+			let curAngle = result > 0 ? result : (360 + result);
+
+			let directionPunch = "all",
+				name = "击中",
+				ename = "hit";
+
+			//min , max
+			let pLeftBetween = [105, 180];
+			let pStraightBetween = [75, 105];
+			let pRightBetween = [0, 75];
+
+			if (curAngle >= pStraightBetween[0] && curAngle < pStraightBetween[1]) {
+				directionPunch = "straightPunch";
+				name = "正向的直拳";
+				ename = "front-straight";
+			} else if (curAngle >= pRightBetween[0] && curAngle < pRightBetween[1]) {
+				directionPunch = "rightPunch";
+				name = "正向的右拳";
+				ename = "front-right";
+			} else if (curAngle >= pLeftBetween[0] && curAngle <= pLeftBetween[1]) {
+				directionPunch = "leftPunch";
+				name = "正向的左拳";
+				ename = "front-left";
+			}
+			//相反方向击打
+			//正方向
+			else {
+				let mAngle = curAngle - 180;
+
+				if (mAngle > pRightBetween[0] && mAngle <= pRightBetween[1]) {
+					directionPunch = "rightPunch";
+					name = "负向的右拳";
+					ename = "back-right";
+				} else if (mAngle > pStraightBetween[0] && mAngle <= pStraightBetween[1]) {
+					directionPunch = "straightPunch";
+					name = "负向的直拳";
+					ename = "back-straight";
+				} else if (mAngle > pLeftBetween[0] && mAngle <= pLeftBetween[1]) {
+					directionPunch = "leftPunch";
+					name = "负向的左拳";
+					ename = "back-left";
+				}
+			}
+
+
+
+			this.quitHitCount++;
+
+			let temp = {
+				type: 'hit',
+				hit: curDirection.length,
+				hitCount: this.quitHitCount,
+				direction: directionPunch,
+				directionVect: {
+					'x': curDirection.x,
+					'y': curDirection.y
+				},
+				angle: curAngle,
+				name: name,
+				ename: ename
+			}
+
+			console.log("hit:" + JSON.stringify(temp));
+
+			return temp;
+
+		}
+	}
+};

+ 52 - 0
util/util-js/puchConfig.js

@@ -0,0 +1,52 @@
+// 拳击柱质量
+const BOXING_MASS = 5;
+// 角度比
+const ANGLE_RATIO = 2;
+// 灵敏度
+const SENDITIVITY = 15;
+
+
+//获取boxing 消耗的卡路里
+const getBoxingCalorie = function(count) {
+	
+	//打一拳,大约消耗的热量,是450*4/60=1.875 焦耳。
+	//因为打拳一小时,需要消耗的热量是450大卡,而一分钟约打一下,一大卡是4焦耳。
+	//现在大概是2s 打一下,1.875/30
+	return (count * 1.875) / (4*30);
+}
+
+//获取额外的加速度 转换的卡路里
+const getAccCalorie = function(acc) {
+	
+	//假如回弹版本的加速度最小值 是5 ,以5为基准,最大值限制是 30
+	if(acc<5){
+		acc =5;
+	}
+	if(acc>50){
+		acc = 50;
+	}
+	
+	return acc/5*0.015625;
+}
+//一步72厘米,已 6 公里消耗 470 大卡计算,一步出来 约是 55 卡路里
+const getRunCalorie = function(runCount){
+	return runCount * 0.055; //单位大卡
+}
+
+
+// 一分钟 60下,30分钟 消耗卡路里大概 270大卡
+const getJumpCalorie  = function(jumpCount){
+	return jumpCount * 0.1125; //单位大卡
+}
+
+
+export default {
+	BOXING_MASS,
+	ANGLE_RATIO,
+	SENDITIVITY,
+	getBoxingCalorie,
+	getAccCalorie,
+	getRunCalorie,
+	// calculation
+	getJumpCalorie
+}

+ 100 - 0
util/util-js/requstUtil.js

@@ -0,0 +1,100 @@
+//请求Url数据
+function requestData(url, params, method) {
+	return new Promise((resolve, reject) => {
+		uni.request({
+			url: url,
+			data: params,
+			method: method ? "POST" : "GET",
+			header: {
+				//application/x-www-form-urlencoded text/html;charset=UTF-8;application/json; accessToken backend_api_context Bearer 
+				"Content-Type": "application/x-www-form-urlencoded",
+				"token": uni.getStorageSync('token') ? `${uni.getStorageSync('token')}` : '',
+				"platform": uni.getStorageSync('platform') || uni.getStorageSync('platform') === 0 ? `${uni.getStorageSync('platform')}` : 2
+			},
+			success: function(res) {
+				console.log("GET URL:", url, ". Params:", params);
+				if (res.statusCode == 200) {
+					resolve(res.data);
+				} else {
+					console.error("Error:", res)
+					reject("error")
+				}
+			},
+			fail: function(e) {
+				console.error("Failed:", e)
+				reject(e);
+			}
+		})
+	});
+}
+
+function reqUpload(url, params,filePath) {
+	console.log("reqUpload",filePath,params);
+	return new Promise((resolve, reject) => {
+		uni.uploadFile({
+			url: url, 
+			header:{
+				//application/x-www-form-urlencoded text/html;charset=UTF-8;application/json; accessToken backend_api_context Bearer 
+				// "Content-Type": "multipart/form-data",
+				"token": uni.getStorageSync('token') ? `${uni.getStorageSync('token')}` : '',
+				"platform": uni.getStorageSync('platform') || uni.getStorageSync('platform') === 0 ? `${uni.getStorageSync('platform')}` : 2
+			},
+			filePath: filePath,
+			name: 'file',
+			formData: params,
+			method:"POST",
+			success: (uploadFileRes) => {
+				console.log(filePath,"上传数据后",uploadFileRes);
+				if (uploadFileRes.statusCode == 200) {
+					resolve(JSON.parse(uploadFileRes.data));
+				} else {
+					console.error("Error:", uploadFileRes)
+					reject("error")
+				}
+			},
+			fail: function(e) {
+				console.error("Failed:", e)
+				reject(e);
+			}
+		})
+		
+	});
+}
+
+
+function reqUploadFiles(url, params,files) {
+	console.log("reqUploadFiles",files,params);
+	return new Promise((resolve, reject) => {
+		uni.uploadFile({
+			url: url, 
+			header:{
+				"token": uni.getStorageSync('token') ? `${uni.getStorageSync('token')}` : '',
+				"platform": uni.getStorageSync('platform') || uni.getStorageSync('platform') === 0 ? `${uni.getStorageSync('platform')}` : 2
+			},
+			files: files,
+			name: 'files',
+			formData: params,
+			method:"POST",
+			success: (uploadFileRes) => {
+				console.log(files,"上传数据后",uploadFileRes);
+				if (uploadFileRes.statusCode == 200) {
+					resolve(JSON.parse(uploadFileRes.data));
+				} else {
+					console.error("Error:", uploadFileRes)
+					reject("error")
+				}
+			},
+			fail: function(e) {
+				console.error("Failed:", e)
+				reject(e);
+			}
+		})
+		
+	});
+}
+
+export default {
+	requestData,
+	reqUpload,
+	reqUploadFiles
+}

+ 26 - 0
util/util-js/service.js

@@ -0,0 +1,26 @@
+// 管理账号信息
+const USERS_KEY = 'USERS_KEY';
+const STATE_KEY = 'STATE_KEY';
+
+const getUsers = function () {
+    let ret = '';
+    ret = uni.getStorageSync(USERS_KEY);
+    if (!ret) {
+        ret = '[]';
+    }
+    return JSON.parse(ret);
+}
+
+const addUser = function (userInfo) {
+    let users = getUsers();
+    users.push({
+        account: userInfo.account,
+        password: userInfo.password
+    });
+    uni.setStorageSync(USERS_KEY, JSON.stringify(users));
+}
+
+export default {
+    getUsers,
+    addUser
+}

+ 2099 - 0
util/util-js/store.js

@@ -0,0 +1,2099 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import config from 'common/config.js'
+import reqUtil from 'util/util-js/requstUtil.js'
+import date from 'util/util-js/date.js'
+import cNumber from 'util/util-js/makeNumber.js'
+import BLE from 'util/util-js/BLE.js';
+//快速打击部分
+import o0 from "@/util/util-js/o0.js"
+import o0Project from "@/util/util-js/o0Project.js"
+import o0ProjectRelease from "@/util/util-js/o0ProjectRelease0.1.js"
+
+import deviceData from "@/util/util-js/devices.js"
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+	state: {
+		// vLog:'',
+		//引导层
+		bGuidePages: false,
+
+		//是否显示Canvas
+		bCanvasShow: true,
+		/**
+		 * 是否需要强制登录
+		 */
+		forcedLogin: false,
+
+		/**
+		 * 蓝牙实时发送数据的页面的名称
+		 */
+		currentPageName: '',
+
+		hasLogin: false,
+		userInfo: null,
+		userName: "匿名",
+		days: 0,
+		remainingDays: 0,
+		signature: '',
+		avatarUrl: "/static/defaultAvatar.png",
+
+		/**
+		 * 新手教程相关
+		 */
+		// 是否是新用户,
+		//TODO:登录接口返回的数据来判断
+		bNewUser: false,
+		//是否是第一次走新手
+		bNewGuide: false,
+		//解锁状态,和首次安装app相关
+		//注意添加新字段时候。需要到 platform-page/guide.vue 确认需不需要添加新的reset
+		guideUnlockState: {
+			firstInstallation: true, //是否首次安装
+			firstDisconnectBluetooth: true, //是否首次连接蓝牙
+			firstUnlockJumpUp: true, //是否首次向上跳
+			firstUnlockLeftAndRightJump: true, //是否首次左右跳
+			firstUnlockLeftAndRightRotationJump: true,
+			firstPromptSelectLevel: true //是否首次提示选择关卡
+		},
+
+
+		token: '',
+		gender: 0,
+
+		//省市区数据
+		city: {
+			label: '北京市-北京市-东城区',
+			cityCode: "110101",
+			//picker 选择器的index数组
+			value: [0, 0, 0]
+		},
+
+		birthday: date.formatTime(new Date()),
+		//默认值
+		height: 0,
+		weight: 0,
+		//最近在玩的列表
+		playGames: [],
+		//最近在玩的排行游戏列表
+		playRankingGames: [],
+		//全部的游戏列表
+		allGames: [],
+		//关注的游戏列表
+		favoriteGames: [],
+		// 排行榜里面显示的游戏
+		rankSelectedGame: null,
+		rankInfo: null,
+		cityName: "某市",
+		/**
+		 * 默认的运动数据
+		 * date.addDaysFromNewDate(new Date(),1)
+		 */
+		defaultPlanData: {
+			startTime: date.formatDate(new Date()),
+			endTime: date.addDaysFromNewDate(new Date(), 6),
+			targetWeight: 0, //目标公斤
+			calorie: 360, //运动消耗的卡路里,默认300 大卡
+			cumulativeCalorie: 0, //累计增重
+			sportTime: 40, //运动时间
+			/**
+			 * 本地记录的消耗卡路里数量
+			 */
+			localCalorie: 0,
+			/**
+			 * 显示卡路里,过了12点清空
+			 */
+			showCalorie: 0,
+			/**
+			 * 总和
+			 */
+			allCalorie: 0
+		},
+		/**
+		 * 计划的运动数据
+		 */
+		planData: {
+			startTime: date.formatDate(new Date()),
+			endTime: date.formatDate(new Date()), //date.addDaysFromNewDate(new Date(),1),
+			targetWeight: 0, //目标公斤
+			cumulativeCalorie: 0, //累计增重
+			calorie: 300, //运动消耗的卡路里
+			sportTime: 40, //运动时间
+			/**
+			 * 本地记录的消耗卡路里数量
+			 */
+			localCalorie: 0,
+			/**
+			 * 显示卡路里,过了12点清空
+			 */
+			showCalorie: 0,
+			/**
+			 * 总和
+			 */
+			allCalorie: 0
+		},
+
+		//记录表盘计划刷新的卡路里
+		oldArcbarProCalorie: 0,
+		//记录表盘当前的总卡路里
+		oldArcbarAllCalorie: 0,
+
+
+		//当前运动的世时间
+		localSportTime: 0,
+
+
+		//当前运动时间,运动时候记录的时间
+		runingTime: 0,
+		//蓝牙设备信息列表
+		//id 不可变,用于保存到本地区分
+		BLEInfoList: deviceData.getDeviceList(),
+		//记录的蓝牙设备,保存id, 和对应的蓝牙连接数据
+		BLEDeviceList: [],
+		//显示的蓝牙设备,取本地数据时候更新
+		BLEDeviceShowList: [],
+		//选择连接的蓝牙设备
+		BLEConnectDevice: null,
+		//获取到的服务
+		BLEGetServices: null,
+		//当前发送给蓝牙的指令,目前是只有蓝牙手柄
+		currentInstruction: '',
+
+		instructionState: {
+			// bAcc: false, //是否开启加速计状态
+			// bGyroscope: false, //是否开启陀螺仪状态
+			bOpen: false, //是否开启指令
+			bSteps: false, //是否开启步数
+		},
+
+
+		//绑定的设备
+		DeviceBindingList: [{
+			id: 0,
+			cname: "开启手机数据",
+			ename: "bindMobilePhoneBandage",
+			icon: "/static/devicesIcon/bandage.png",
+			mIcon: "/static/devicesIcon/bandage.png",
+			bRatio: false,
+			usageMode: 'bindPhone',
+			describe: '手机情景下使用',
+			limitType: 'rebound', //限制回弹版本
+			deviceType: 'mySelf', //指的是使用手机本身加速计计算
+			deviceName: 'PHONE', //连接硬件名称
+
+		}],
+		ConnectBindingDevice: null,
+
+		cIndex: -1,
+		//当前是否连接
+		bConnection: false,
+		/**
+		 * 通过验证的连接,比如通过mac验证,或者说是首页直连,都设置这个参数,确保已经连上
+		 */
+		bVerifiedConnection: false,
+		/**
+		 * 默认不是旧设备,旧设备使用的轴向不一样,名字为 BGBox_202012 ,新设备为 BGBox_202112
+		 */
+		bOldDeviceType: false,
+
+		/**
+		 * Android 出现不匹配的情况下,判断
+		 * ios 暂时没有此类问题
+		 */
+		bPhoneMatched: false,
+
+		//最近连接过的设备
+		finallyUseDevice: null,
+
+		/**
+		 * 用户选择好友的信息
+		 */
+		finallySelectFriendInfo: null,
+
+		//phoneNumber
+		phoneNumber: '',
+		mailboxNumber: '',
+		//是否是第一次设置密码,根据这个值判断.默认未设置,即设置true
+		setPasswordFirstTime: true,
+		openid: '',
+		appleid: '',
+
+		//获取验证码
+		bCodeDisabled: false,
+		count: 59,
+		interval: null,
+
+		//conversion列表
+		oldSwiperList: [],
+
+		// 计划任务过期
+		bPlanExpired: false,
+		// 制定玩计划任务后
+		bPlanFinish: false,
+
+		//标准体重,男女根据当前年龄计算
+		standardWeight: 0,
+
+		//是否安装了微信
+		bInstallWechat: false,
+		bHideWeixin: false,
+
+		//导航栏高度。这里统一参数,单位px
+		navHeight: 46,
+		tabbarHeight: 65,
+
+		systemInfo: null, //系统全部信息
+		clientName: '', //但是客户端名字
+		system: '', // 系统版本
+		platform: '', // 平台
+		appName: '',
+		version: '1.6.3', //软件版本
+		versionCode: '21120701', //app.vue 自动获取.目前是h5 设置给了一个默认值
+		showEndTime: config.endTime, //游戏显示时间字段,后台返回对应此时间之前的数据
+
+		//现在游戏显示在对应的平台
+		gamePlatform: {
+			0: 'android',
+			1: 'ios',
+			2: 'all'
+		},
+
+		globalAcc: null,
+		globalOri: null,
+		globalAccData: {
+			ax: 0,
+			ay: 0,
+			az: 0
+		},
+		globalGyroData: {
+			gx: 0,
+			gy: 0,
+			gz: 0
+		},
+		globalLastGyroData: {
+			gx: 0,
+			gy: 0,
+			gz: 0
+		},
+		globalMyAttitude: null,
+
+		/**
+		 * 当前显示的模式下标,区分总体的显示模块
+		 * 比如拳击模块体验下,设置 0
+		 * 跳绳为主的模式体验下,设置 1
+		 */
+		currentModeIndex: 0,
+
+		//蓝牙变量操作
+		/**
+		 * 操作蓝牙设备
+		 */
+		bOpenBluetooth: false,
+		/**
+		 * 是否初始化蓝牙适配器
+		 */
+		bOpenSuccess: false,
+		/**
+		 * 是否监听蓝牙状态变化
+		 */
+		bListenAdapterStateChange: false,
+		/**
+		 * 是否监听寻找新设备事件
+		 */
+		bListenDeviceFound: false,
+
+		// 设备Id
+		BLEDeviceId: "",
+		// 服务Id
+		BLEServiceId: "",
+		// 特征值id
+		BLENotifyCharacteristicId: "",
+
+		//监听rssi对象
+		BLERSSIInterval: null,
+
+		//蓝牙服务timeout
+		getBLEDeviceServicesTimeout: null,
+
+		//本地游戏地址
+		// http://192.168.0.112:7456/build/index.html
+		// http://127.0.0.1:7456/build/index.html
+		LocationGameUrl: "", //192.168.1.12:7456
+
+		//快速打击对象
+		filter: null,
+		deviceMs: 1,
+
+		//改进版的沙袋打击对象
+		sandbagAlgorithm: null,
+		sandbagAlgorithmLastTime: new Date().getTime(),
+
+
+		/**
+		 * 蓝牙参数对象
+		 */
+
+		// 设备Id
+		deviceId: "",
+		// 服务Id
+		serviceId: "",
+		notifyCharacteristicId: "",
+		writeCharacteristicId: "",
+
+		showToast: false,
+		bListenerUpdate: false,
+		bListenerJson: false,
+		bListenerMac: false,
+		bListenerAccArray: false,
+
+
+
+		/**
+		 * OTA config
+		 */
+		UUID_OTA_SERVICE: "f000ffc0-0451-4000-b000-000000000000", //OTA 服务对应的服务的 UUID
+		UUID_IDENTFY: "f000ffc1-0451-4000-b000-000000000000", //OTA 版本特征值的UUID,读取版本就是写向这个特征值写入:0x00
+		UUID_BLOCK: "f000ffc2-0451-4000-b000-000000000000", //OTA 写bin文件特征值UUID,发送bin文件就是写这个特征值
+		/*****/
+
+
+		/**
+		 * 发送16进制时候,返回的刷新数据
+		 */
+		bListenerHexUpdate: false,
+
+
+		BluetoothAdapter: null,
+
+		//版本状态,用于区分部分特定的环境
+		versionCodeState: {
+			showGame: false,
+			showVideo: false,
+			versionCode: 0,
+			title: 'none'
+		},
+
+		//显示蓝牙是否断开连接Modal
+		bShowBLEConnectModal: false,
+		bGamePlaying: false,
+
+		//跳绳条件下计数
+		bRopeKeyOne: 0,
+		bRopeKeyTwo: 0,
+
+		//钻石,金币
+		cDiamond: 0,
+		cGold: 0,
+
+		/**
+		 * 任务相关
+		 */
+		currentJumpTask: null,
+		multiPersonList: [],
+		singlePersonList: [],
+		levels: [],
+
+		/**
+		 * 校准识别部分
+		 */
+		convertAcc: [{
+			type: 'x',
+			match: 'ax', //默认匹配一一对应
+			direction: 1,
+		}, {
+			type: 'y',
+			match: 'ay',
+			direction: -1,
+		}, {
+			type: 'z',
+			match: 'az',
+			direction: -1,
+		}],
+		convertGyro: [{
+			type: 'x',
+			match: 'gx', //默认匹配一一对应
+			direction: 1,
+		}, {
+			type: 'y',
+			match: 'gy',
+			direction: 1,
+		}, {
+			type: 'z',
+			match: 'gz',
+			direction: 1,
+		}],
+
+		/**
+		 * 签到列表
+		 */
+		signInList: [],
+		isSignIn: false,
+
+	},
+	mutations: {
+
+		onSetLocationGameUrl(state, value) {
+			uni.setStorageSync('LocationGameUrl', value);
+			state.LocationGameUrl = value;
+		},
+		//获取本地任务对象
+		onGetLocationGameUrl(state) {
+			//如果存在本地任务
+			const value = uni.getStorageSync('LocationGameUrl');
+			if (value) {
+				state.LocationGameUrl = value;
+			}
+			return value;
+			console.log('onGetLocationGameUrl ' + value);
+		},
+		/**
+		 * 蓝牙解析后的数据,转化成对应的坐标系方向
+		 * @param {Object} context
+		 */
+		onConvertDeviceData(state, context) {
+			let {
+				data,
+				callback = null
+			} = context;
+			let {
+				acc,
+				gyro,
+			} = data;
+			//根据已校准的数据转化对应的轴
+			let outAcc = {
+				ax: acc[state.convertAcc[0].match] * state.convertAcc[0].direction,
+				ay: acc[state.convertAcc[1].match] * state.convertAcc[1].direction,
+				az: acc[state.convertAcc[2].match] * state.convertAcc[2].direction
+			};
+			let outGyro = {
+				gx: gyro[state.convertGyro[0].match] * state.convertGyro[0].direction,
+				gy: gyro[state.convertGyro[1].match] * state.convertGyro[1].direction,
+				gz: gyro[state.convertGyro[2].match] * state.convertGyro[2].direction
+			}
+			if (callback)
+				callback({
+					convertAcc: outAcc,
+					convertGyro: outGyro
+				});
+
+		},
+		onAccAndGyroConvertDataGet(state) {
+			const convertAcc = uni.getStorageSync('convertAcc');
+			if (convertAcc) {
+				state.convertAcc = convertAcc;
+			}
+			const convertGyro = uni.getStorageSync('convertGyro');
+			if (convertGyro) {
+				state.convertGyro = convertGyro;
+			}
+		},
+		onAccAndGyroConvertDataSave(state) {
+			uni.setStorageSync('convertAcc', state.convertAcc);
+			uni.setStorageSync('convertGyro', state.convertGyro);
+		},
+		onAccAndGyroConvertDataReset(state) {
+			state.convertAcc = [{
+				type: 'x',
+				match: 'ax', //默认匹配一一对应
+				direction: 1,
+			}, {
+				type: 'y',
+				match: 'ay',
+				direction: -1,
+			}, {
+				type: 'z',
+				match: 'az',
+				direction: -1,
+			}];
+			state.convertGyro = [{
+				type: 'x',
+				match: 'gx', //默认匹配一一对应
+				direction: 1,
+			}, {
+				type: 'y',
+				match: 'gy',
+				direction: 1,
+			}, {
+				type: 'z',
+				match: 'gz',
+				direction: 1,
+			}];
+			//重置一下数据保存
+			this.commit('onAccAndGyroConvertDataSave');
+		},
+
+		setGuideUnlockState(state, _guideUnlockState) {
+			uni.setStorageSync('guideUnlockState', _guideUnlockState);
+			state.guideUnlockState = _guideUnlockState;
+		},
+
+		getGuideUnlockState(state, _guideUnlockState) {
+			//如果存在本地任务
+			const value = uni.getStorageSync('guideUnlockState');
+			if (value) {
+				state.guideUnlockState = value;
+			}
+			console.log('获取guideUnlockState', state.guideUnlockState)
+		},
+
+		/**
+		 * 设置当前操作的任务记录到本地
+		 * @param {Object} state
+		 * @param {Object} _taskObj
+		 */
+		setActionJumpTask(state, _taskObj) {
+			uni.setStorageSync('currentJumpTask', _taskObj);
+			state.currentJumpTask = _taskObj;
+		},
+		//获取本地任务对象
+		getActionJumpTask(state) {
+			//如果存在本地任务
+			const value = uni.getStorageSync('currentJumpTask');
+			if (value) {
+				state.currentJumpTask = value;
+			}
+		},
+		resetActionJumpTask(state) {
+			state.currentJumpTask = null;
+			uni.setStorageSync('currentJumpTask', state.currentJumpTask);
+		},
+
+		setFinallSelectFriendInfo(state, friendInfo) {
+			state.finallySelectFriendInfo = friendInfo;
+			console.log('finallySelectFriendInfo', JSON.stringify(friendInfo));
+		},
+		clearFinallFriendInfo(state) {
+			state.finallySelectFriendInfo = null;
+		},
+		/**
+		 * 获取记录的最后一次连接设备
+		 * @param {Object} state
+		 */
+		getFinalUseDevice(state) {
+			// 获取本地存储的最后一次使用的设备
+			//1.获取最近连接的蓝牙设备, 指蓝牙搜索到的obj
+			const value = uni.getStorageSync('finallyUseDevice');
+			if (value) {
+				state.finallyUseDevice = value;
+			}
+			console.log('获取的finallyUseDevice', value);
+		},
+
+		/**
+		 * 存储最后一次使用的设备信息,后面登陆时候,如果存在设备最后一次使用信息,则自动连接
+		 * @param {Object} state
+		 * @param {Object} device
+		 */
+		setFinallUseDevice(state, device) {
+			uni.setStorageSync('finallyUseDevice', device);
+			state.finallyUseDevice = device;
+			// console.log("保存finallyUseDevice:", state.finallyUseDevice);
+			// uni.setStorage({
+			// 	key: 'finallyUseDevice',
+			// 	data: device,
+			// 	success: (res) => {
+			// 		state.finallyUseDevice = device;
+			// 		console.log("保存finallyUseDevice:", res);
+			// 	}
+			// })
+		},
+
+
+		//获取记录的蓝牙列表数据
+		getBLEDeviceList(state) {
+			// console.log("getBLEDeviceList=");
+			uni.getStorage({
+				key: 'BLEDeviceList',
+				success: (res) => {
+					// console.log("*****getBLEDeviceList=", res);
+					let _list = res.data;
+					state.BLEDeviceList = res.data;
+					//更新BLEDeviceShowList 数组
+					state.BLEDeviceShowList = [];
+					_list.forEach(item => {
+						//如果记录到本地的id,和信息列表中的id一致,则结合
+						for (let i = 0; i < state.BLEInfoList.length; i++) {
+							let eq = state.BLEInfoList[i];
+							if (item.id == eq.id) {
+								state.BLEDeviceShowList.push(Object.assign({}, item, eq));
+								break;
+							}
+						}
+					})
+
+				}
+			})
+		},
+
+		//添加蓝牙设备数据
+		addBLEDevice(state, data) {
+			let devicelist = [];
+			if (state.BLEDeviceList && state.BLEDeviceList.length != 0) {
+				devicelist = state.BLEDeviceList;
+			}
+			// console.log(data, devicelist)
+
+			let bHas = false;
+			devicelist.forEach((item, index, selfArr) => {
+				if (item.id == data.id) {
+					//如果存在,更新保存的数据,比如 mac或者uuid等 
+					selfArr[index] = item = Object.assign({}, item, data);
+					bHas = true;
+				}
+			})
+			//把当前添加的的蓝牙设信息备作为最后一次连接覆盖到本地
+			this.commit('setFinallUseDevice', data);
+
+			if (!bHas) {
+				//如果不是更新数据,就添加但却数据到列表
+				devicelist.push(data);
+			}
+			uni.setStorage({
+				key: 'BLEDeviceList',
+				data: devicelist,
+				success: (res) => {
+					// uni.showToast({
+					// 	title: "保存成功"
+					// })
+					state.BLEDeviceList = devicelist;
+					// console.log("devicelist:",devicelist);
+					//更新BLEDeviceShowList 数组
+					state.BLEDeviceShowList = [];
+					devicelist.forEach(item => {
+						//如果记录到本地的id,和信息列表中的id一致,则结合
+						for (let i = 0; i < state.BLEInfoList.length; i++) {
+							let eq = state.BLEInfoList[i];
+							if (item.id == eq.id) {
+								// console.log("存储的======================:", item, eq);
+								state.BLEDeviceShowList.push(Object.assign({}, item, eq));
+								break;
+							}
+						}
+					})
+					// console.log("state.BLEDeviceShowList:",state.BLEDeviceShowList);
+				}
+			})
+		},
+		//删除蓝牙设备数据
+		deleteBLEDevice(state, index) {
+			let devicelist = [];
+			devicelist = state.BLEDeviceList;
+
+			devicelist.splice(index, 1);
+			uni.setStorage({
+				key: 'BLEDeviceList',
+				data: devicelist,
+				success: (res) => {
+					uni.showToast({
+						title: "删除成功"
+					})
+					state.BLEDeviceList = devicelist;
+					//更新BLEDeviceShowList 数组
+					state.BLEDeviceShowList = [];
+					devicelist.forEach(item => {
+						//如果记录到本地的id,和信息列表中的id一致,则结合
+						for (let i = 0; i < state.BLEInfoList.length; i++) {
+							let eq = state.BLEInfoList[i];
+							if (item.id == eq.id) {
+								state.BLEDeviceShowList.push(Object.assign({}, item, eq));
+								break;
+							}
+						}
+					})
+				}
+			})
+		},
+
+
+		initAdapter(state, callback) {
+			//初始化蓝牙模块
+			let params = {
+				success: (res) => {
+					state.bOpenSuccess = true;
+					state.bOpenBluetooth = true;
+					if (callback)
+						callback(res);
+					//监听断开事件
+					this.commit("B_OnBLEConnectionStateChange");
+				},
+				fail: (fail) => {
+					state.bOpenSuccess = false;
+					state.bOpenBluetooth = false;
+					uni.showToast({
+						title: '蓝牙尚未开启!',
+						icon: 'none'
+					})
+				},
+				complete: (complete) => {
+					// console.log("complete bListenAdapterStateChange:", state.bListenAdapterStateChange);
+					if (state.bListenAdapterStateChange) return;
+
+					state.bListenAdapterStateChange = true;
+					uni.onBluetoothAdapterStateChange((res) => {
+						// console.log('adapterState changed, now is', res)
+						// 手机蓝牙状态
+						state.bOpenBluetooth = res.available;
+						if (state.bOpenBluetooth && !state.bOpenSuccess) {
+							this.commit('initAdapter');
+						}
+					})
+
+				}
+			};
+			this.commit("B_OpenBluetoothAdapter", params);
+		},
+		// todo 未使用到
+		onGetDevices(state, context) {
+			let {
+				success
+			} = context;
+			if (!state.BLEConnectDevice) return;
+			// #ifdef APP-PLUS
+			let deviceId = state.BLEConnectDevice.deviceId;
+			uni.getBLEDeviceRSSI({
+				deviceId,
+				success: res => {
+					let _dis = Math.pow(Math.E, (Math.abs(res.RSSI) - 66.78) / 16.56);
+
+					if (_dis > state.BLEConnectDevice.limitDis) {
+						if (state.cIndex != -1) {
+							uni.showToast({
+								title: '设备断开连接!',
+								icon: 'none',
+								duration: 2000,
+								mask: true
+							})
+						}
+
+						setTimeout(() => {
+							this.commit("B_CloseBLEConnection", {
+								deviceId: deviceId
+							})
+							state.cIndex = -1;
+							state.bConnection = false;
+							state.bVerifiedConnection = false;
+						}, 1000)
+
+					} else {
+						// console.log("DIS~~~~~~~~~", _dis);
+						if (success) {
+							success({
+								RSSI: res.RSSI,
+								DIS: _dis
+							});
+						}
+					}
+				}
+			})
+			// #endif
+
+
+		},
+		//清除连接的开启的timeout
+		onUnloadCreateBLEConnectionTimeout(state) {
+			if (state.getBLEDeviceServicesTimeout) {
+				clearTimeout(state.getBLEDeviceServicesTimeout);
+				state.getBLEDeviceServicesTimeout = null;
+			}
+		},
+
+		initBLEData(state) {
+			// 设备Id
+			state.deviceId = "";
+			// 服务Id
+			state.serviceId = "";
+
+			state.notifyCharacteristicId = "";
+
+			state.writeCharacteristicId = "";
+
+			state.currentInstruction = "";
+
+			state.showToast = false;
+
+			state.bListenerUpdate = false;
+
+			state.bListenerJson = false;
+
+			state.bListenerMac = false;
+
+			state.bListenerAccArray = false;
+			//更新二进制的
+			state.bListenerHexUpdate = false;
+
+		},
+		//连接蓝牙
+		onCreateBLEConnection(state, context) {
+			let {
+				index,
+				item,
+				initItem = false,
+				getSuccess = null,
+				getinitAdapter = null
+			} = context;
+
+			uni.showToast({
+				title: '连接设备中...',
+				icon: 'loading',
+				duration: 10000,
+				mask: true
+			})
+
+			let params = {
+				item: item,
+				success: (success) => {
+					state.bConnection = true;
+					if (state.getBLEDeviceServicesTimeout) {
+						clearTimeout(state.getBLEDeviceServicesTimeout);
+						state.getBLEDeviceServicesTimeout = null;
+					}
+
+					state.getBLEDeviceServicesTimeout = setTimeout(() => {
+						let retryCount = 5;
+						this.commit("B_GetBLEDeviceServices", {
+							retryCount: retryCount,
+							item: item,
+							callback: () => {
+								uni.showToast({
+									title: '连接成功',
+									icon: 'loading',
+									duration: 2000,
+									mask: true
+								})
+								//是否需要设置item,默认不设置
+								if (initItem) {
+									state.cIndex = index;
+									state.BLEConnectDevice = item;
+								}
+
+								if (getSuccess)
+									getSuccess();
+
+								/**
+								 * 直接连接过成功
+								 */
+								state.bVerifiedConnection = true;
+
+							},
+							getServiceList: (serviceList) => {
+								//搜索服务失败后
+								state.BLEGetServices = serviceList;
+							},
+							getFail: () => {
+								this.commit("B_CloseBLEConnection", {
+									deviceId: item.deviceId
+								})
+								// state.cIndex = -1;
+								// state.bConnection = false;
+								// state.bVerifiedConnection = false;
+								this.commit("onResetBLEConnection");
+							}
+						});
+
+					}, 2000);
+
+				},
+				fail: (fail) => {
+					console.log("***fail:", fail);
+					if (fail.errCode === 10012) {
+						console.log("连接超时,请重试!");
+						uni.showToast({
+							title: '连接失败,开启设备后尝试重新连接!',
+							icon: 'none',
+							duration: 3000,
+							mask: true
+						})
+					} else if (fail.errCode === 10013) {
+						console.log("连接失败,蓝牙地址无效!");
+						uni.showToast({
+							title: '连接失败,蓝牙地址无效',
+							icon: 'none',
+							duration: 2000,
+							mask: true
+						})
+					} else if (fail.errCode === 10000) {
+						this.commit('initAdapter', () => {
+							if (getinitAdapter) {
+								getinitAdapter();
+							}
+						})
+					} else {
+						// err.errCode10003原因多种:蓝牙设备未开启或异常导致无法连接;蓝牙设备被占用或者上次蓝牙连接未断开导致无法连接
+						console.log("连接失败,请重试!", state.BLEConnectDevice);
+						uni.showToast({
+							title: '请尝试开启设备和重启app。',
+							icon: 'none',
+							duration: 2000,
+							mask: true
+						})
+					}
+				}
+			};
+			this.commit("B_CreateBLEConnection", params);
+		},
+		//devices hardware 连接后验证,这里不需要处理 bVerifiedConnection,通过mac 验证后处理
+		onCreateBLESuccess(state, context) {
+			let {
+				item,
+				getSuccess = null
+			} = context;
+			this.commit("B_CreateBLEConnection", {
+				item: item,
+				success: success => {
+					state.BLEConnectDevice = item;
+					state.bConnection = true;
+					if (getSuccess) {
+						getSuccess();
+					}
+				},
+				fail: fail => {
+					if (fail.errCode === 10012) {
+						console.log("连接超时,请重试!");
+						uni.showToast({
+							title: '连接超时,检查对应设备是否开启?',
+							icon: 'none',
+							duration: 2000,
+							mask: true
+						})
+					} else if (fail.errCode === 10013) {
+						console.log("连接失败,蓝牙地址无效!");
+						uni.showToast({
+							title: '蓝牙地址无效,检查设备是否正常?',
+							icon: 'none',
+							duration: 2000,
+							mask: true
+						})
+					} else if (fail.errCode === 10000) {
+						console.log("连接失败,初始化 wx.openBluetoothAdapter 调用之后使用");
+						uni.showToast({
+							title: '连接失败,检查手机蓝牙是否开启?',
+							icon: 'none',
+							duration: 2000,
+							mask: true
+						})
+					} else {
+						console.log("连接失败,请重试!");
+						uni.showModal({
+							title: '连接失败',
+							content: '设备未开启或被占用。请重启app和设备后重新连接。'
+						})
+						// uni.showToast({
+						// 	title: '设备未开启或被占用异常导致无法连接。',
+						// 	icon: 'none',
+						// 	duration: 2000,
+						// 	mask: true
+						// })
+					}
+				}
+			});
+		},
+		//获取蓝牙服务
+		onGetBLEDeviceServices(state, context) {
+			let {
+				item,
+				success = null,
+			} = context;
+			let retryCount = 5;
+			this.commit("B_GetBLEDeviceServices", {
+				retryCount: retryCount,
+				item: item,
+				callback: success,
+				getServiceList: (serviceList) => {
+					state.BLEGetServices = serviceList;
+				},
+				getFail: () => {
+					this.commit("B_CloseBLEConnection", {
+						deviceId: item.deviceId
+					})
+					this.commit("onResetBLEConnection");
+				}
+			})
+		},
+		//重置蓝牙连接参数
+		onResetBLEConnection(state) {
+			state.cIndex = -1;
+			state.BLEConnectDevice = null;
+			//蓝牙服务
+			state.BLEGetServices = null;
+			state.bConnection = false;
+			state.bVerifiedConnection = false;
+		},
+		onCloseBLEConnection(state, context) {
+
+			console.log("onCloseBLEConnection", state.BLEConnectDevice);
+			let {
+				getSuccess = null,
+			} = context;
+
+			if (state.BLERSSIInterval) {
+				clearInterval(state.BLERSSIInterval);
+				state.BLERSSIInterval = null;
+			}
+			this.commit("B_CloseBLEConnection", {
+				deviceId: state.BLEConnectDevice.deviceId,
+				success: () => {
+					state.cIndex = -1;
+					state.BLEConnectDevice = null;
+					//蓝牙服务
+					state.BLEGetServices = null;
+
+					if (getSuccess) {
+						getSuccess();
+					}
+					state.bConnection = false;
+
+					state.bVerifiedConnection = false;
+
+					uni.closeBluetoothAdapter({
+						success(res) {
+							console.log(res)
+							state.bOpenBluetooth = false;
+						}
+					})
+				}
+			});
+
+		},
+		//不关闭 adapter
+		onOnlyCloseBLEConnection(state, context) {
+			let {
+				getSuccess = null
+			} = context;
+
+			if (state.BLERSSIInterval) {
+				clearInterval(state.BLERSSIInterval);
+				state.BLERSSIInterval = null;
+			}
+
+			this.commit("B_CloseBLEConnection", {
+				deviceId: state.BLEConnectDevice.deviceId,
+				success: () => {
+					state.cIndex = -1;
+					state.BLEConnectDevice = null;
+					//蓝牙服务
+					state.BLEGetServices = null;
+					if (getSuccess) {
+						getSuccess();
+					}
+					state.bConnection = false;
+
+					state.bVerifiedConnection = false;
+				}
+			});
+
+		},
+		onWriteBLEConnectionValue(state, context) {
+			//#ifdef H5
+			console.warn("h5不支持蓝牙:", 'onWriteBLEConnectionValue');
+			return;
+			//#endif
+			let {
+				getSuccess = null,
+					getFail = null,
+					value,
+					bSendHex = false,
+					bOpen = false,
+			} = context;
+
+			if (!state.BLEConnectDevice && state.cIndex == -1) {
+				uni.showToast({
+					title: '蓝牙设备未连接',
+					icon: 'none'
+				})
+			}
+			// console.log(22);
+			//记录蓝牙盒子当前的指令
+			// state.currentInstruction = value;
+			// 发送 3 :开启原始数据
+			// 发送4 :关闭原始数据
+			// 发送 5 :开启步数
+			// 发送6 :关闭步数
+			if (value == "3") {
+				state.instructionState.bOpen = true;
+			} else if (value == "4") {
+				state.instructionState.bOpen = false;
+			} else if (value == "5") {
+				state.instructionState.bSteps = true;
+			} else if (value == "6") {
+				state.instructionState.bSteps = false;
+			} else if (bSendHex && bOpen) {
+				state.instructionState.bOpen = true;
+			} else if (bSendHex && !bOpen) {
+				state.instructionState.bOpen = false;
+			}
+			let retryCount = 5;
+			this.commit("B_WriteBLECharacteristicValue", {
+				value,
+				retryCount,
+				getSuccess,
+				getFail,
+				bSendHex
+			});
+		},
+		//获取距离
+		onGetRSSITransDistance(state, context) {
+			let {
+				RSSI
+			} = context;
+			BLE.getRSSITransDistance(RSSI);
+		},
+
+
+		//添加使用的前端信息
+		gOnAddClientInfo(state, context) {
+
+			uni.getSystemInfo({
+				success: (res) => {
+					// console.log("系统信息:", res);
+					let clientInfo = res;
+
+					clientInfo.clientSystem = res.system;
+
+					reqUtil.requestData(config.URL.ADDCLIENTINFO, clientInfo, 'POST').then(
+						res => {
+							console.warn(res);
+						},
+						e => {}
+					);
+				},
+				fail: (err) => {},
+				complete: () => {}
+			})
+
+
+		},
+
+		//创建快速打击对象
+		gCreateFilterObj(state) {
+			state.filter = null;
+			state.deviceMs = 1;
+			state.filter = new o0Project.Filter();
+			console.log("gCreateFilterObj");
+		},
+		//更新快速打击对象数据
+		gUpdateFilter(state, context) {
+
+			let {
+				data,
+				callback
+			} = context;
+
+			let {
+				min,
+				s,
+				ms
+			} = data;
+			var msGap = ms - state.deviceMs;
+			state.deviceMs = ms;
+			while (msGap < 0) {
+				msGap += 1000;
+			}
+			// console.log(data);
+			let {
+				ax,
+				ay,
+				az
+			} = data.acc;
+
+			let {
+				gx,
+				gy,
+				gz
+			} = data.gyro;
+
+			state.filter.Update(new o0.Vector3(ax, ay, az), msGap, new o0.Vector3(gx, gy, gz),
+				callback); //我自己的更新acc的函数
+		},
+
+		/**
+		 * 创建一个沙袋打击对象
+		 * @param {Object} state
+		 */
+		gCreateSandbagAlgorithm(state) {
+			state.sandbagAlgorithm = null;
+			state.deviceMs = 1;
+			state.sandbagAlgorithmLastTime = new Date().getTime();
+			state.sandbagAlgorithm = new o0ProjectRelease.SandbagAlgorithm();
+			console.log("gCreateSandbagAlgorithm");
+		},
+		/**
+		 * 更新 沙袋打击对象 数据
+		 * @param {Object} state
+		 * @param {Object} context
+		 */
+		gUpdateSandbagAlgorithm(state, context) {
+
+			let {
+				data,
+				callback = null
+			} = context;
+
+			let {
+				min,
+				s,
+				ms
+			} = data;
+			let msGap = ms - state.deviceMs;
+			state.deviceMs = ms;
+			while (msGap < 0) {
+				msGap += 1000;
+			}
+
+			let {
+				ax,
+				ay,
+				az
+			} = data.acc;
+
+			let {
+				gx,
+				gy,
+				gz
+			} = data.gyro;
+
+			// ax / 10, az / 10, gz, -gx, data.ms ----- old
+			// ay / 10, -az / 10, gy, gz, data.ms
+			let [hit, dir] = state.sandbagAlgorithm.Update(ay, -az, gz, gy, msGap);
+			if (dir != undefined) {
+				let temp = state.sandbagAlgorithm.getTempValue(dir);
+				if (callback) {
+					callback(temp);
+				}
+			}
+		},
+
+		/**
+		 * 开启加速计,陀螺仪,并且模拟ble发送
+		 * @param {Object} state
+		 */
+		gStartSimulateBLEUpdate(state) {
+
+			//todo 区分平台,目前是android 模块
+
+			if (state.globalMyAttitude == null) {
+				state.globalMyAttitude = uni.requireNativePlugin("MyAttitude");
+
+				let globalEvent = uni.requireNativePlugin('globalEvent');
+				globalEvent.addEventListener('updateAccAndGyro', function(e) {
+					//updateAccAndGyro{"accelerometer":[-0.178375244140625,9.327804565429688,2.6168670654296875],"gyroscope":[0.0018310546875,-0.0019989013671875,0.0027923583984375]}
+					//console.log('updateAccAndGyro' + JSON.stringify(e));
+					let _accArray = e.accelerometer;
+					let _gyroArray = e.gyroscope;
+
+					state.globalAccData.ax = _accArray[0];
+					state.globalAccData.ay = _accArray[1];
+					state.globalAccData.az = _accArray[2];
+
+					state.globalGyroData.gx = _gyroArray[0];
+					state.globalGyroData.gy = _gyroArray[1];
+					state.globalGyroData.gz = _gyroArray[2];
+
+					let box = {};
+					box["acc"] = state.globalAccData;
+					box["gyro"] = state.globalGyroData;
+					box["ms"] = e.ms;
+					//更新数据给webview,在game-play-web||game-play-sub绑定
+					//后面更新数据都用此接口
+					uni.$emit('updateBLEDeviceData', box);
+				});
+			}
+
+			var ret = state.globalMyAttitude.onStartAccAndGyro();
+			if (!ret.accelerometer || !ret.gyroscope) {
+				uni.showModal({
+					title: '提示',
+					content: '是否初始化,加速计:' + ret.accelerometer + ',陀螺仪:' + ret.gyroscope
+				})
+			}
+			console.log('gStartSimulateBLEUpdate:', ret);
+
+		},
+		/**
+		 * 停止加速计,陀螺仪
+		 * @param {Object} state
+		 */
+		gStopSimulateBLEUpdate(state) {
+			//todo 区分平台,目前是android 模块
+			let globalEvent = uni.requireNativePlugin('globalEvent');
+			globalEvent.removeEventListener('updateAccAndGyro');
+			var ret = state.globalMyAttitude.onStopAccAndGyro();
+			console.log('gStopSimulateBLEUpdate:', ret);
+			state.globalMyAttitude = null;
+		},
+		/**
+		 * 限制开始游戏
+		 */
+		glimitPlayGame(state, context) {
+			let {
+				gameTags,
+				callback
+			} = context;
+
+			//没有标签直接进去
+			if (gameTags.length == 0) {
+				callback();
+				return;
+			}
+
+			let canPlay = false;
+			gameTags.forEach((item) => {
+				//如果存在普通模式
+				if (item.tagMode === 'normal') {
+					canPlay = true;
+				}
+				if (canPlay)
+					return;
+			})
+
+			if (!canPlay) {
+				//2.如果普通模式不存在,就判断是否连接硬件了
+				if (!state.BLEConnectDevice || state.cIndex == -1) {
+					uni.showToast({
+						title: "请连接标签对应的设备模式!",
+						icon: "none",
+						duration: 2000,
+						mask: true
+					})
+					return;
+				}
+				//3.如果连接了设备,判断但是处于什么模式
+				gameTags.forEach((item, index, selfArr) => {
+					//如果存在普通模式
+					if (item.tagMode === state.BLEConnectDevice.usageMode) {
+						canPlay = true;
+					}
+					if (canPlay)
+						return;
+					if (index == selfArr.length - 1) {
+						uni.showToast({
+							title: "游戏没有当前设备模式!",
+							icon: "none",
+							duration: 2000,
+							mask: true
+						})
+					}
+				})
+			}
+
+			if (canPlay) {
+				callback();
+			}
+		},
+
+		checkAppUpdata(state) {
+			//#ifdef APP-PLUS
+			let _temp = {
+				appid: plus.runtime.appid,
+				version: state.version,
+				versionCode: state.versionCode,
+				platform: state.platform.toLocaleLowerCase(),
+			}
+			//#endif
+			//#ifdef H5
+			//此 _temp 测试用
+			let _temp = {
+				appid: '1',
+				version: "2.0.0",
+				versionCode: "20122202",
+				platform: "android",
+			}
+			//#endif
+			reqUtil.requestData(config.URL.APPVERSIONUPDATE, _temp).then(res => {
+					console.log('requestData APPVERSIONUPDATE =====', res);
+					let _data = res.data;
+					if (res.code == 0 && res.data.status === 1) {
+						uni.showModal({ //提醒用户更新  
+							title: "更新提示",
+							content: res.data.note,
+							success: (res) => {
+								if (res.confirm) {
+									if (state.platform.toLocaleLowerCase() == "android") {
+										plus.runtime.openURL(_data.url, function(res) {
+											plus.nativeUI.alert("本机没安装应用宝,请安装后获取新版本。");
+										}, 'com.tencent.android.qqdownloader');
+
+									} else {
+										//ios
+										plus.runtime.openURL(_data.url);
+									}
+								}
+							}
+						})
+
+					} else {
+						uni.showToast({
+							title: '当前为最新版本',
+							icon: 'none',
+							duration: 2000,
+							mask: true
+						})
+					}
+				},
+				e => {
+					console.log(e)
+				});
+
+		},
+
+
+		/**
+		 * 蓝牙BLE迁移到store.js
+		 */
+		// 初始化蓝牙模块适配器
+		B_OpenBluetoothAdapter(state, context) {
+			let {
+				success,
+				fail,
+				complete
+			} = context;
+			//#ifdef H5
+			console.warn('h5不加载蓝牙模块');
+			return;
+			//#endif
+			uni.openBluetoothAdapter({
+				success: res => {
+					if (success)
+						success(res);
+				},
+				fail: res => {
+					if (fail)
+						fail(res);
+				},
+				complete: res => {
+					if (complete)
+						complete(res);
+				}
+			})
+		},
+
+		/**
+		 * 关闭蓝牙模块适配器
+		 */
+		B_CloseBluetoothAdapter() {
+			//#ifdef H5
+			console.warn('h5不加载蓝牙模块');
+			return;
+			//#endif
+			uni.closeBluetoothAdapter({
+				success: res => {
+					console.log('断开蓝牙模块成功');
+					uni.showToast({
+						icon: "none",
+						title: "蓝牙已经断开!",
+						mask: false,
+						duration: 3000
+					});
+				}
+			});
+		},
+
+		B_OnBLEConnectionStateChange(state) {
+			let _self = this;
+			//#ifdef H5
+			console.warn('h5不加载蓝牙模块');
+			return;
+			//#endif
+			uni.onBLEConnectionStateChange(res => {
+				// 该方法回调中可以用于处理连接意外断开等异常情况
+				console.log(`蓝牙连接状态 -------------------------->`, JSON.stringify(res));
+				if (!res.connected) {
+
+					//要在连接的状态下 ,并且获取过匹配列表有参数的情况下,才提示重连
+					if (!state.bShowBLEConnectModal && state.bVerifiedConnection) {
+						state.bShowBLEConnectModal = true;
+						let _connectItem = Object.assign({}, state.BLEConnectDevice);
+						let _cIndex = state.cIndex;
+						//断开连接后reset一下参数
+						_self.commit("onResetBLEConnection");
+
+						let _tip = state.bGamePlaying ? "蓝牙已断开是否重新连接蓝牙?重连需要重启游戏!" : "蓝牙已断开是否重新连接蓝牙";
+						uni.showModal({
+							title: _tip,
+							success: (sRes) => {
+								state.bShowBLEConnectModal = false;
+								if (sRes.confirm) {
+									console.log("重连的_cIndex:", _cIndex);
+									_self.commit("onCreateBLEConnection", {
+										item: _connectItem,
+										index: _cIndex,
+										initItem: true,
+										getSuccess: () => {
+											//此处不检查外部设备
+											uni.$emit('retryConnectBLESuccess');
+										},
+										getinitAdapter: () => {}
+									})
+								}
+							}
+						})
+					} else {
+						//断开连接后reset一下参数
+						_self.commit("onResetBLEConnection");
+					}
+
+
+					uni.$emit('callbackCloseBLE');
+				}
+			});
+		},
+		/**
+		 * 连接低功耗蓝牙设备。
+		 * 若APP在之前已有搜索过某个蓝牙设备,并成功建立连接,可直接传入之前搜索获取的 deviceId 直接尝试连接该设备,无需进行搜索操作。
+		 */
+		B_CreateBLEConnection(state, context) {
+			let {
+				item,
+				success,
+				fail
+			} = context;
+			this.commit('initBLEData');
+			state.deviceId = item.deviceId;
+			let timeout = 10000;
+			// console.log("B_CreateBLEConnection deviceId ==", state.deviceId)
+			uni.createBLEConnection({
+				// 这里的 deviceId 需要已经通过 createBLEConnection 与对应设备建立链接
+				deviceId: state.deviceId,
+				timeout: timeout,
+				success: res => {
+					if (success) {
+						success(res);
+					}
+					//设置mtu
+					// setTimeout(() => {
+					// 	uni.setBLEMTU({
+					// 		deviceId: state.deviceId,
+					// 		mtu: 80,
+					// 		success: (res) => {
+					// 			console.log("设置mtu");
+					// 			console.log(res)
+					// 			uni.$emit('log', "设置mtu=80," + JSON.stringify(
+					// 				res));
+
+					// 		},
+					// 		fail: (error) => {
+					// 			console.log(error)
+					// 		}
+					// 	})
+					// }, 1000)
+
+				},
+				fail: res => {
+					if (fail)
+						fail(res);
+				}
+			});
+		},
+
+
+		/**
+		 * 获取设备的服务ID
+		 */
+		B_GetBLEDeviceServices(state, context) {
+
+			let {
+				retryCount,
+				item,
+				callback,
+				getServiceList,
+				getFail,
+			} = context;
+			let serviceList = [];
+			let _self = this;
+			uni.getBLEDeviceServices({
+				deviceId: item.deviceId,
+				success: res => {
+					// console.log("getBLEDeviceServices==", JSON.stringify(res), item);
+					serviceList = res.services;
+					if (getServiceList) {
+						getServiceList(serviceList);
+					}
+					if (serviceList.length == 0) {
+						console.log(item.deviceId + " retryCount:" + retryCount);
+						if (retryCount > 0) {
+							retryCount--;
+							context.retryCount = retryCount;
+							setTimeout(() => {
+								this.commit('B_GetBLEDeviceServices', context);
+							}, 1000)
+							return;
+						}
+						if (getFail) {
+							getFail();
+						}
+						uni.hideToast();
+						uni.showModal({
+							title: '提示',
+							content: '1.获取服务失败,请尝试重新连接设备。\r\n2.尝试重启设备再重新连接。'
+						})
+
+					}
+					for (let i = 0; i < serviceList.length; i++) {
+						let service = serviceList[i];
+						if (service.uuid.toLocaleLowerCase() === item.PRIMARY_SERVICE
+							.toLocaleLowerCase()) {
+							state.serviceId = service.uuid;
+							//开始获取指定服务的特征值
+							_self.commit('B_GetBLEDeviceCharacteristics', {
+								item: item,
+								callback: callback
+							});
+							break;
+						}
+					}
+				},
+				fail: failRes => {
+					console.log('device services:', failRes.services);
+					uni.hideToast();
+					uni.showModal({
+						title: '连接错误',
+						content: '请尝试重新连接设备。'
+					})
+					if (getFail) {
+						getFail();
+					}
+				}
+			});
+		},
+		/**
+		 * 获取指定服务的特征值
+		 */
+		B_GetBLEDeviceCharacteristics(state, context) {
+			let {
+				item,
+				callback
+			} = context;
+			let deviceId = state.deviceId;
+			let serviceId = state.serviceId;
+			let characteristicsList = [];
+			uni.getBLEDeviceCharacteristics({
+				deviceId,
+				serviceId,
+				success: res => {
+					if (item.PRIMARY_NOTIFY != '') {
+						state.notifyCharacteristicId = item.PRIMARY_NOTIFY;
+						this.commit('B_NotifyBLECharacteristicValueChange', {
+							callback: callback
+						});
+					}
+					if (item.PRIMARY_WRITE != '') {
+						state.writeCharacteristicId = item.PRIMARY_WRITE;
+					}
+				},
+				fail: res => {
+					console.log('device getBLEDeviceCharacteristics failed:', JSON.stringify(res))
+				}
+			})
+		},
+
+		//启用低功耗蓝牙设备特征值变化时的 notify 功能,订阅特征值。
+		//注意:必须设备的特征值支持notify或者indicate才可以成功调用,具体参照 characteristic 的 properties 属性
+		B_NotifyBLECharacteristicValueChange(state, context) {
+			let {
+				callback
+			} = context;
+			// 启用notify功能
+			// console.log("启用notify功能");
+			uni.notifyBLECharacteristicValueChange({
+				state: true,
+				deviceId: state.deviceId,
+				serviceId: state.serviceId,
+				characteristicId: state.notifyCharacteristicId,
+				success: (res) => {
+					this.commit('B_OnBLECharacteristicValueChange', {
+						callback: callback
+					});
+				},
+				fail: (res) => {
+					uni.showToast({
+						title: 'notify启动失败',
+						icon: "none",
+						mask: true
+					});
+
+				}
+			})
+		},
+		//监听低功耗蓝牙设备的特征值变化。必须先启用notify接口才能接收到设备推送的notification。
+		B_OnBLECharacteristicValueChange(state, context) {
+			let {
+				callback
+			} = context;
+			// console.log("onBLECharacteristicValueChange success");
+			if (callback) {
+				callback({
+					notifyCharacteristicId: state.notifyCharacteristicId,
+					writeCharacteristicId: state.writeCharacteristicId
+				})
+			}
+			uni.onBLECharacteristicValueChange(function(res) {
+				//如果是ota 更新服务,这里处理通知ota更新数据
+				if (res.serviceId.toLocaleLowerCase() === state.UUID_OTA_SERVICE) {
+					uni.$emit("OTAValueChange", res);
+					return;
+				}
+				//serviceId 0000FFF0-0000-1000-8000-00805F9B34FB characteristic 0000FFF1-0000-1000-8000-00805F9B34FB
+				// console.log(`store ${res.serviceId} characteristic ${res.characteristicId} has changed, now is ${res.value}`);
+				let box = {};
+				var resValue = BLE.ab2hext(res.value); //16进制字符串
+				if (state.currentInstruction == "V" && state.showToast) {
+					var resValueStr = BLE.hexToString(resValue);
+					let _info = {
+						type: 'version',
+						instruction: 'V',
+						value: resValueStr.replace(/\{|}/g, '').trim()
+					}
+					uni.$emit('listenerBLE', _info);
+					state.currentInstruction = "";
+					state.showToast = false;
+					return;
+				} else if (state.currentInstruction == 'M' && state.bListenerMac) {
+					var resValueStr = BLE.hexToString(resValue);
+					let _info = {
+						type: 'mac',
+						instruction: 'M',
+						value: resValueStr.replace(/\{|}/g, '').trim()
+					}
+					uni.$emit('listenerBLE', _info);
+					state.currentInstruction = "";
+					state.bListenerMac = false;
+					return;
+				}
+				//步数数据解析
+				if (state.bListenerJson) {
+					var resValueStr = BLE.hexToString(resValue);
+					console.log(resValueStr);
+					box["Json"] = resValueStr;
+					uni.$emit('updateBLEDeviceJson', box);
+				}
+
+				//解析4组加速计数据
+				if (state.bListenerAccArray) {
+					let accArray = [];
+					// 5B00E000260019F7F4FFF6FFF1000000E200260019F7F4FFF6FFF1000000E60031001BF81AFFF5FFF0000000E90031001BF81AFFF5FFF0000000EB0031001BF81AFFF5FFF000005D: length =144
+					// console.log("1======= " + BLE.buf2hex(res.value));
+					// var hex =
+					// 	'5B00E000260019F7F4FFF6FFF1000000E200260019F7F4FFF6FFF1000000E60031001BF81AFFF5FFF0000000E90031001BF81AFFF5FFF0000000EB0031001BF81AFFF5FFF000005D'
+					// var typedArray = new Uint8Array(hex.match(/[\da-f]{2}/gi).map(function(h) {
+					// 	return parseInt(h, 16)
+					// }))
+					// var buffer = typedArray.buffer;
+
+					// console.log("hex= " + resValue + ",length:"+ resValue.length);
+					// console.log(resValue.length);
+					// console.log(res.value);
+					// console.log(buffer);
+					for (let i = 0; i < 5; i++) {
+						let index = i * 28;
+						let ms = BLE.hex2int(resValue.substr(2 + index, 4));
+						// console.log(index + "==" + resValue.substr(2 + index, 4));
+						let axStr = resValue.substr(6 + index, 4);
+						let ayStr = resValue.substr(10 + index, 4);
+						let azStr = resValue.substr(14 + index, 4);
+						let gxStr = resValue.substr(18 + index, 4);
+						let gyStr = resValue.substr(22 + index, 4);
+						let gzStr = resValue.substr(26 + index, 4);
+						//一个字节最大只能表示265  2个字节可以表示65536  然后你这边做一下转换 例如00 3E   3*16+14=62 ----->0.03  g 
+						//(真实值= AD值 /32768  * 16)
+						//0.003 = 62 / 2768  * 16
+						let ax = BLE.hexToSignedInt(axStr) / 32768 * 16;
+						let ay = BLE.hexToSignedInt(ayStr) / 32768 * 16;
+						let az = BLE.hexToSignedInt(azStr) / 32768 * 16;
+						//角速度(AD值/32768 * 2000) 角速度单位是 °/s  范围是 正负2000
+						let gx = BLE.hexToSignedInt(gxStr) / 32768 * 2000;
+						let gy = BLE.hexToSignedInt(gyStr) / 32768 * 2000;
+						let gz = BLE.hexToSignedInt(gzStr) / 32768 * 2000;
+
+						accArray.push({
+							acc: {
+								ax: ax,
+								ay: ay,
+								az: az
+							},
+							gyro: {
+								gx: gx,
+								gy: gy,
+								gz: gz
+							},
+							ms: ms
+						})
+					}
+					uni.$emit('updateBLEDeviceData', accArray);
+					// for (let i = 0; i < accArray.length; i++) {
+					// 	let _temp = accArray[i];
+					// 	box["acc"] = {
+					// 		ax: _temp.ax,
+					// 		ay: _temp.ay,
+					// 		az: _temp.az,
+					// 	};
+					// 	box["gyro"] = {
+					// 		gx: _temp.gx,
+					// 		gy: _temp.gy,
+					// 		gz: _temp.gz,
+					// 	};
+					// 	box["ms"] = _temp.ms;
+					// 	uni.$emit('updateBLEDeviceData', box);
+					// }
+
+				}
+
+
+				//原始数据解析
+				if (state.bListenerUpdate) {
+					//R/L 左手还是右手
+					let handle = resValue.substr(6, 2);
+					let axStr = resValue.substr(8, 4);
+					let ayStr = resValue.substr(12, 4);
+					let azStr = resValue.substr(16, 4);
+					//一个字节最大只能表示265  2个字节可以表示65536  然后你这边做一下转换 例如00 3E   3*16+14=62 ----->0.03  g 
+					//(真实值= AD值 /32768  * 16)
+					//0.003 = 62 / 2768  * 16
+					let ax = BLE.hexToSignedInt(axStr) / 32768 * 16;
+					let ay = BLE.hexToSignedInt(ayStr) / 32768 * 16;
+					let az = BLE.hexToSignedInt(azStr) / 32768 * 16;
+
+					let gxStr = resValue.substr(20, 4);
+					let gyStr = resValue.substr(24, 4);
+					let gzStr = resValue.substr(28, 4);
+					//角速度(AD值/32768 * 2000) 角速度单位是 °/s  范围是 正负2000
+					let gx = BLE.hexToSignedInt(gxStr) / 32768 * 2000;
+					let gy = BLE.hexToSignedInt(gyStr) / 32768 * 2000;
+					let gz = BLE.hexToSignedInt(gzStr) / 32768 * 2000;
+					//毫秒
+					let ms = BLE.hex2int(resValue.substr(2, 4));
+					//分
+					let min = BLE.hex2int(resValue.substr(32, 2));
+					//秒
+					let s = BLE.hex2int(resValue.substr(34, 2));
+					box["handle"] = BLE.hexToString(handle);
+					box["acc"] = {
+						ax,
+						ay,
+						az
+					};
+					box["gyro"] = {
+						gx,
+						gy,
+						gz
+					};
+
+					box["min"] = min;
+					box["s"] = s;
+					box["ms"] = ms;
+
+					//更新数据给webview,在game-play-web||game-play-sub绑定
+					//后面更新数据都用此接口
+					uni.$emit('updateBLEDeviceData', box);
+				}
+			});
+		},
+
+		onTestEmit(state) {
+			let box = {};
+			let accArray = [];
+			var resValue =
+				'5B00E000260019F7F4FFF6FFF1000000E200260019F7F4FFF6FFF1000000E60031001BF81AFFF5FFF0000000E90031001BF81AFFF5FFF0000000EB0031001BF81AFFF5FFF000005D';
+			for (let i = 0; i < 5; i++) {
+				let index = i * 28;
+				let ms = BLE.hex2int(resValue.substr(2 + index, 4));
+				// console.log(index + "==" + resValue.substr(2 + index, 4));
+				let axStr = resValue.substr(6 + index, 4);
+				let ayStr = resValue.substr(10 + index, 4);
+				let azStr = resValue.substr(14 + index, 4);
+				let gxStr = resValue.substr(18 + index, 4);
+				let gyStr = resValue.substr(22 + index, 4);
+				let gzStr = resValue.substr(26 + index, 4);
+				//一个字节最大只能表示265  2个字节可以表示65536  然后你这边做一下转换 例如00 3E   3*16+14=62 ----->0.03  g 
+				//(真实值= AD值 /32768  * 16)
+				//0.003 = 62 / 2768  * 16
+				let ax = BLE.hexToSignedInt(axStr) / 32768 * 16;
+				let ay = BLE.hexToSignedInt(ayStr) / 32768 * 16;
+				let az = BLE.hexToSignedInt(azStr) / 32768 * 16;
+				//角速度(AD值/32768 * 2000) 角速度单位是 °/s  范围是 正负2000
+				let gx = BLE.hexToSignedInt(gxStr) / 32768 * 2000;
+				let gy = BLE.hexToSignedInt(gyStr) / 32768 * 2000;
+				let gz = BLE.hexToSignedInt(gzStr) / 32768 * 2000;
+
+				accArray.push({
+					ax: ax,
+					ay: ay,
+					az: az,
+					gx: gx,
+					gy: gy,
+					gz: gz,
+					ms: ms
+				})
+			}
+			for (let i = 0; i < accArray.length; i++) {
+				let _temp = accArray[i];
+				box["acc"] = {
+					ax: _temp.ax,
+					ay: _temp.ay,
+					az: _temp.az,
+				};
+				box["gyro"] = {
+					gx: _temp.gx,
+					gy: _temp.gy,
+					gz: _temp.gz,
+				};
+				box["ms"] = _temp.ms;
+				uni.$emit('updateBLEDeviceData', box);
+			}
+		},
+
+		//向低功耗蓝牙设备特征值中写入二进制数据。注意:必须设备的特征值支持 write 才可以成功调用。
+		B_WriteBLECharacteristicValue(state, context) {
+			let {
+				value,
+				retryCount,
+				success,
+				getFail,
+				bSendHex,
+			} = context;
+			if (!value && value === '') {
+				uni.showToast({
+					title: "指令为空"
+				})
+				return;
+			}
+			let _sendData;
+			if (bSendHex) {
+
+				state.bRopeKeyTwo = 0;
+				state.bRopeKeyOne = 0;
+
+				//如果是发送16进制
+				state.bListenerHexUpdate = true;
+
+				//重置原 update
+				state.bListenerUpdate = false;
+
+				let typedArray = new Uint8Array(value.match(/[\da-f]{2}/gi).map(function(h) {
+					return parseInt(h, 16)
+				}))
+				_sendData = typedArray.buffer;
+			} else {
+				state.bListenerHexUpdate = false;
+				//记录一下指令
+				state.currentInstruction = value;
+
+				state.showToast = false;
+				state.bListenerUpdate = false;
+				state.bListenerAccArray = false;
+
+				//V 获取版本,M 获取mac 地址
+				if (value == "V")
+					state.showToast = true;
+
+				if (value == "M") {
+					state.showToast = true;
+					state.bListenerMac = true;
+				}
+				if (value == "4") {
+					state.bListenerUpdate = false;
+				}
+				if (value == "3") {
+					if (state.bListenerUpdate) {
+						console.warn("原始数据已开启");
+					}
+					state.bListenerUpdate = true;
+				}
+
+				if (value == "h") {
+					state.bListenerAccArray = false;
+				}
+				if (value == "H") {
+					if (state.bListenerAccArray) {
+						uni.showToast({
+							title: "加速计组数据已开启"
+						})
+						return;
+					}
+					state.bListenerAccArray = true;
+				}
+
+				_sendData = BLE.str2ab(value);
+			}
+			console.log("currentInstruction:" + state.currentInstruction);
+			uni.writeBLECharacteristicValue({
+				deviceId: state.deviceId,
+				serviceId: state.serviceId,
+				// 这里的 characteristicId 需要在 getBLEDeviceCharacteristics 接口中获取
+				characteristicId: state.writeCharacteristicId,
+				// 这里的value是ArrayBuffer类型
+				value: _sendData,
+				success: (res) => {
+					console.log('writeBLECharacteristicValue success', res.errMsg, value,
+						retryCount);
+
+
+					if (success) {
+						success(res);
+					}
+				},
+				fail: (fail) => {
+					console.log(fail)
+					//重新写入
+					if (retryCount > 0) {
+						console.log("writeBLECharacteristicValue Rewrite ===================>" +
+							value + " == " + retryCount);
+						retryCount--;
+						setTimeout(() => {
+							this.commit("B_WriteBLECharacteristicValue", {
+								value,
+								retryCount,
+								success,
+								getFail
+							});
+						}, 300);
+					}
+					if (getFail) {
+						getFail(fail);
+					}
+				}
+			})
+
+		},
+
+		B_OnSetMTU(state) {
+			uni.setBLEMTU({
+				deviceId: state.deviceId,
+				mtu: 80,
+				success: (res) => {
+					console.log("设置mtu");
+					console.log(res)
+					uni.$emit('log', "设置mtu=80," + JSON.stringify(
+						res));
+
+				},
+				fail: (error) => {
+					console.log(error)
+				}
+			})
+		},
+
+		/**
+		 * 断开蓝牙连接
+		 */
+		B_CloseBLEConnection(state, context) {
+			let {
+				deviceId,
+				success = null
+			} = context;
+			uni.closeBLEConnection({
+				deviceId,
+				success: res => {
+					console.log("关闭蓝牙连接!deviceId=" + deviceId);
+					if (success)
+						success();
+				},
+				fail: (fail) => {
+					console.log("关闭蓝牙失败", fail);
+				}
+			});
+		}
+	}
+})
+
+export default store

+ 26 - 0
util/util-js/util-data.js

@@ -0,0 +1,26 @@
+/**
+ * 计算数据
+ */
+
+
+/**
+ * 公斤与卡路里转化公式
+ * 公斤= 大卡x1.296(一公斤=7716千卡)
+ * 
+ * 卡路里数x2÷7000=斤数
+ */
+
+const calorieConversionKg = function(calorie){
+	return calorie / 7000;
+}
+
+
+// 计算标准体重
+const calculateStandardWeight = function(){
+	return 0;
+}
+
+export default {
+	calorieConversionKg,
+	calculateStandardWeight
+}

Файловите разлики са ограничени, защото са твърде много
+ 9 - 0
util/util-js/vconsole.min.js


+ 150 - 0
util/util-js/verify.js

@@ -0,0 +1,150 @@
+
+function checkPassword(string){
+	//密码组合规则-6-16位数字和字符组合,不能纯数字、纯英文
+	// var filter = /^(?=.*[0-9\!@#\$%\^&\*])(?=.*[a-zA-Z]).{6,16}$/;
+	//不限制特殊字符种类 /^(?![\d]+$)(?![a-zA-Z]+$)(?![^\da-zA-Z]+$).{6,18}$/
+	// 6-18位字符,数字、字母、特殊字符-=_+,. ,必须两种及以上组合
+	var filter = /^(?![\d]+$)(?![a-zA-Z]+$)(?![-=+_.,]+$)[\da-zA-Z-=+_.,]{6,16}$/;
+	if (string == undefined) {
+		return false;
+	} else if (!filter.test(string)) {
+		return false;
+	} else {
+		return true;
+	}
+}
+
+
+function checkEMail(string) {
+
+	var myreg = /^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$/;
+	if (string == undefined) {
+		return false;
+	} else if (!myreg.test(string)) {
+		return false;
+	} else {
+		return true;
+	}
+}
+
+
+function checkPhone(string) {
+
+	// var myreg = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1}))+\d{8})$/;
+	var myreg = /^(13[0-9]|14[5-9]|15[012356789]|166|17[0-8]|18[0-9]|19[8-9])[0-9]{8}$/;
+	if (string == undefined) {
+		return false;
+	} else if (string.length < 11) {
+		return false;
+	} else if (!myreg.test(string)) {
+		return false;
+	} else {
+		return true;
+	}
+}
+
+function checkRequired(string) {
+	if (string == undefined || string == '') {
+		return false;
+	} else {
+		return true;
+	}
+}
+
+function checkLength(num, length) {
+	if (num < length) {
+		return false;
+	} else {
+		return true;
+	}
+}
+
+function checkCardId(string) {
+	var code = string;
+
+	var city = {
+		11: "北京",
+		12: "天津",
+		13: "河北",
+		14: "山西",
+		15: "内蒙古",
+		21: "辽宁",
+		22: "吉林",
+		23: "黑龙江 ",
+		31: "上海",
+		32: "江苏",
+		33: "浙江",
+		34: "安徽",
+		35: "福建",
+		36: "江西",
+		37: "山东",
+		41: "河南",
+		42: "湖北 ",
+		43: "湖南",
+		44: "广东",
+		45: "广西",
+		46: "海南",
+		50: "重庆",
+		51: "四川",
+		52: "贵州",
+		53: "云南",
+		54: "西藏 ",
+		61: "陕西",
+		62: "甘肃",
+		63: "青海",
+		64: "宁夏",
+		65: "新疆",
+		71: "台湾",
+		81: "香港",
+		82: "澳门",
+		91: "国外 "
+	};
+	var tip = "";
+	var pass = true;
+	var reg = /^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/;
+	if (!code || !code.match(reg)) {
+		tip = "身份证号格式错误";
+		pass = false;
+	} else if (!city[code.substr(0, 2)]) {
+		tip = "地址编码错误";
+		pass = false;
+	} else {
+		//18位身份证需要验证最后一位校验位
+		if (code.length == 18) {
+			code = code.split('');
+			//∑(ai×Wi)(mod 11)
+			//加权因子
+			var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
+			//校验位
+			var parity = [1, 0, 'X', 9, 8, 7, 6, 5, 4, 3, 2];
+			var sum = 0;
+			var ai = 0;
+			var wi = 0;
+			for (var i = 0; i < 17; i++) {
+				ai = code[i];
+				wi = factor[i];
+				sum += ai * wi;
+			}
+			var last = parity[sum % 11];
+			if (parity[sum % 11] != code[17]) {
+				tip = "校验位错误";
+				pass = false;
+			}
+		}
+	}
+	console.log(pass)
+	if (pass) {
+		return true
+	}
+	if (!pass) return false;
+
+}
+
+export default {
+	checkPassword,
+	checkEMail,
+	checkPhone,
+	checkRequired,
+	checkCardId,
+	checkLength
+}

+ 37 - 0
util/util-js/webSocket.js

@@ -0,0 +1,37 @@
+var socketOpen = false;
+var socketMsgQueue = [];
+
+const connectSocket = function(callback) {
+	console.warn('connectSocket打开!');
+	uni.connectSocket({
+		url: 'wss://www.yuyekeji.cn/node/'
+	});
+	uni.onSocketOpen(function(res) {
+		socketOpen = true;
+		console.log('WebSocket连接已打开!');
+		for (var i = 0; i < socketMsgQueue.length; i++) {
+			sendSocketMessage(socketMsgQueue[i]);
+		}
+		socketMsgQueue = [];
+
+		if (callback)
+			callback();
+	});
+	uni.onSocketError(function(res) {
+		console.log('WebSocket连接打开失败,请检查!');
+	});
+}
+const sendSocketMessage = function sendSocketMessage(msg) {
+	if (socketOpen) {
+		uni.sendSocketMessage({
+			data: msg
+		});
+	} else {
+		socketMsgQueue.push(msg);
+	}
+}
+
+export default {
+	connectSocket,
+	sendSocketMessage
+}

+ 0 - 0
util/util-js/wxLogin.js


Някои файлове не бяха показани, защото твърде много файлове са промени