Kaynağa Gözat

蓝牙重连提交

liyuliangjiazai 3 ay önce
ebeveyn
işleme
f8e94cd1a5

+ 169 - 3
code/ajyApp/pages/device/deviceInfo/deviceInfo.nvue

@@ -47,6 +47,20 @@
 					</view>
 				</view>
 
+				<!-- 方案选择 -->
+				<view class="planSection" v-if="modeType != 0 && picMode == 1">
+					<text class="planSectionTitle">选择方案</text>
+					<view class="planCard" @click="showPlanDrawer">
+						<view class="planCardLeft">
+							<text class="planCardName">{{selectedPlan ? selectedPlan.name : '点击选择方案'}}</text>
+							<text class="planCardDesc" v-if="selectedPlan && selectedPlan.description">{{selectedPlan.description}}</text>
+						</view>
+						<view class="planCardRight">
+							<text class="planCardArrow">›</text>
+						</view>
+					</view>
+				</view>
+
 				<!-- 其他功能 -->
 				<view class="otherSetting" v-if="modeType != 0 && picMode == 1">
 					<text class="otherTxt">其他功能</text>
@@ -241,6 +255,36 @@
 			</view>
 		</customPopup>
 
+		<!-- 方案选择弹框 -->
+		<customPopup :isShow="isShowPlanDrawer" @closePop="isShowPlanDrawer=false">
+			<text class="planDrawerTitle">选择方案</text>
+			<text class="planDrawerSub">{{modelist[modeType]}} - 可用方案</text>
+			<scroll-view class="planDrawerList" scroll-y="true">
+				<view class="planDrawerEmpty" v-if="planList.length === 0 && !planLoading">
+					<text class="planEmptyTxt">暂无可用方案</text>
+				</view>
+				<view class="planDrawerEmpty" v-if="planLoading">
+					<text class="planEmptyTxt">加载中...</text>
+				</view>
+				<view class="planItem" :class="selectedPlan && selectedPlan.id === item.id ? 'planItemActive' : ''"
+					v-for="(item, index) in planList" :key="index" @click="selectPlan(item)">
+					<view class="planItemInfo">
+						<text class="planItemName">{{item.name}}</text>
+						<text class="planItemDesc" v-if="item.description">{{item.description}}</text>
+						<view class="planItemMeta" v-if="item.steps || item.duration">
+							<text class="planMetaTxt" v-if="item.steps">{{item.steps}}步</text>
+							<text class="planMetaTxt" v-if="item.duration">约{{item.duration}}分钟</text>
+						</view>
+					</view>
+					<view class="planItemCheck">
+						<view class="checkboxCustom">
+							<view v-if="selectedPlan && selectedPlan.id === item.id" class="checkboxCircle"></view>
+						</view>
+					</view>
+				</view>
+			</scroll-view>
+		</customPopup>
+
 		<!-- 时间配置器 -->
 		<customPopup :isShow="isShowTimeDrawer" @closePop="isShowTimeDrawer=false">
 			<text class="aijiuTime">选择灸疗时间</text>
@@ -260,11 +304,11 @@
 		</customPopup>
 
 		<!-- 重连弹框 -->
-		<view class="maskbg" v-if="reconnectDrawer">
+		<view class="maskbg" v-if="reconnectDrawer" @click.stop="">
 			<view class="maskbox">
 				<text class="maskTxt">蓝牙连接断开,第{{reconnectCount}}次重连中...</text>
 			</view>
-		</view>
+		</view>	
 
 		<ay-toast ref="ayToast" />
 	</view>
@@ -277,6 +321,7 @@ import lSliderRange from '@/components/l-sliderRange/l-sliderRange.nvue'
 import bleMixin from './mixins/ble-mixin.js'
 import audioMixin from './mixins/audio-mixin.js'
 import acupointMixin from './mixins/acupoint-mixin.js'
+import planMixin from './mixins/plan-mixin.js'
 import bleManager, { CHAIR_ANGLE } from '@/utils/ble'
 
 export default {
@@ -285,7 +330,7 @@ export default {
 		ayToast,
 		lSliderRange
 	},
-	mixins: [bleMixin, audioMixin, acupointMixin],
+	mixins: [bleMixin, audioMixin, acupointMixin, planMixin],
 	data() {
 		return {
 			statusBarHeight: 44,
@@ -798,6 +843,127 @@ export default {
 .empty {
 	height: 180rpx;
 }
+/* 方案选择区 */
+.planSection {
+	margin-left: 38rpx;
+	margin-right: 38rpx;
+	margin-top: 20rpx;
+	background-color: rgba(255,255,255,0.9);
+	border-radius: 16rpx;
+	padding: 30rpx;
+}
+.planSectionTitle {
+	font-size: 28rpx;
+	color: #9BA5B7;
+	margin-bottom: 16rpx;
+}
+.planCard {
+	flex-direction: row;
+	justify-content: space-between;
+	align-items: center;
+	background-color: #389588;
+	border-radius: 40rpx;
+	padding-left: 30rpx;
+	padding-right: 24rpx;
+	padding-top: 20rpx;
+	padding-bottom: 20rpx;
+}
+.planCardLeft {
+	flex: 1;
+}
+.planCardName {
+	font-size: 30rpx;
+	font-weight: bold;
+	color: #FFFFFF;
+}
+.planCardDesc {
+	font-size: 22rpx;
+	color: rgba(255,255,255,0.7);
+	margin-top: 6rpx;
+}
+.planCardRight {
+	width: 40rpx;
+	align-items: center;
+}
+.planCardArrow {
+	font-size: 40rpx;
+	color: #FFFFFF;
+}
+/* 方案选择弹框 */
+.planDrawerTitle {
+	font-size: 32rpx;
+	color: #545F71;
+	font-weight: bold;
+	text-align: center;
+}
+.planDrawerSub {
+	font-size: 24rpx;
+	color: #9BA5B7;
+	text-align: center;
+	margin-top: 8rpx;
+	margin-bottom: 24rpx;
+}
+.planDrawerList {
+	max-height: 600rpx;
+}
+.planDrawerEmpty {
+	align-items: center;
+	padding-top: 60rpx;
+	padding-bottom: 60rpx;
+}
+.planEmptyTxt {
+	font-size: 28rpx;
+	color: #9BA5B7;
+}
+.planItem {
+	flex-direction: row;
+	justify-content: space-between;
+	align-items: center;
+	padding-left: 20rpx;
+	padding-right: 20rpx;
+	padding-top: 24rpx;
+	padding-bottom: 24rpx;
+	border-bottom-width: 1px;
+	border-bottom-style: solid;
+	border-bottom-color: #EEF1F4;
+	border-radius: 12rpx;
+}
+.planItemActive {
+	background-color: #F0F8F7;
+}
+.planItemInfo {
+	flex: 1;
+	margin-right: 20rpx;
+}
+.planItemName {
+	font-size: 30rpx;
+	color: #545F71;
+	font-weight: bold;
+}
+.planItemDesc {
+	font-size: 24rpx;
+	color: #9BA5B7;
+	margin-top: 8rpx;
+}
+.planItemMeta {
+	flex-direction: row;
+	margin-top: 10rpx;
+}
+.planMetaTxt {
+	font-size: 22rpx;
+	color: #389588;
+	margin-right: 20rpx;
+	background-color: rgba(56,149,136,0.1);
+	padding-left: 12rpx;
+	padding-right: 12rpx;
+	padding-top: 4rpx;
+	padding-bottom: 4rpx;
+	border-radius: 8rpx;
+}
+.planItemCheck {
+	width: 50rpx;
+	align-items: center;
+}
 /* 弹框样式 */
 .tip1 {
 	font-size: 28rpx;

+ 12 - 18
code/ajyApp/pages/device/deviceInfo/mixins/ble-mixin.js

@@ -47,23 +47,30 @@ export default {
 			this._unbinders = [
 				bleManager.on('state', (s) => {
 					this.linked = (s === BLE_STATE.READY_COMM)
-					if (s === BLE_STATE.DISCONNECTED) {
-						this.linked = false
-						this._handleBleDisconnect()
-					}
 				}),
 				bleManager.on('disconnected', (info) => {
 					this.linked = false
 					if (!info.manual) {
-						this._handleBleDisconnect()
+						this.reconnectDrawer = true
 					}
 				}),
+				bleManager.on('reconnecting', ({ count }) => {
+					this.reconnectCount = count
+					this.reconnectDrawer = true
+				}),
 				bleManager.on('reconnected', () => {
 					this.reconnectDrawer = false
 					this.reconnectCount = 0
 					this.linked = true
 					this.$refs.ayToast.success('重连成功')
 				}),
+				bleManager.on('reconnectFailed', () => {
+					this.reconnectDrawer = false
+					this.$refs.ayToast.error('连接失败,请返回重试')
+					setTimeout(() => {
+						uni.navigateBack()
+					}, 1500)
+				}),
 				bleManager.on('report:GROUP_1', (data) => {
 					this._handleGroup1(data)
 				}),
@@ -94,19 +101,6 @@ export default {
 			}
 		},
 
-		_handleBleDisconnect() {
-			this.reconnectCount++
-			if (this.reconnectCount >= 4) {
-				this.reconnectDrawer = false
-				this.$refs.ayToast.error('连接失败,请返回重试')
-				setTimeout(() => {
-					uni.navigateBack()
-				}, 1500)
-			} else {
-				this.reconnectDrawer = true
-			}
-		},
-
 		// ========== 设备上报数据解析 ==========
 		_handleGroup1(data) {
 			// 参数组1: 设备状态

+ 23 - 14
code/ajyApp/utils/ble/BleManager.js

@@ -325,21 +325,30 @@ class BleManager extends EventEmitter {
     this.emit('disconnected', { manual: false, reason })
     this._parser.reset()
     // 尝试自动重连
-    if (this.config.autoReconnect && device && this._reconnectCount < this.config.maxReconnect) {
-      this._reconnectCount++
-      const delay = Math.min(1000 * this._reconnectCount, 5000)
-      logger.warn(`reconnect in ${delay}ms (${this._reconnectCount}/${this.config.maxReconnect})`)
-      this._reconnectTimer = setTimeout(async () => {
-        try {
-          await this.init()
-          await this.connect(device.deviceId)
-          this.emit('reconnected', this._device)
-        } catch (e) {
-          logger.error('reconnect fail', e)
-          this._handleDisconnected(reason)
-        }
-      }, delay)
+    this._attemptReconnect(device, reason)
+  }
+
+  _attemptReconnect(device, reason) {
+    if (!this.config.autoReconnect || !device || this._reconnectCount >= this.config.maxReconnect) {
+      if (this._reconnectCount >= this.config.maxReconnect) {
+        this.emit('reconnectFailed')
+      }
+      return
     }
+    this._reconnectCount++
+    const delay = Math.min(1000 * this._reconnectCount, 5000)
+    logger.warn(`reconnect in ${delay}ms (${this._reconnectCount}/${this.config.maxReconnect})`)
+    this.emit('reconnecting', { count: this._reconnectCount, max: this.config.maxReconnect })
+    this._reconnectTimer = setTimeout(async () => {
+      try {
+        await this.init()
+        await this.connect(device.deviceId)
+        this.emit('reconnected', this._device)
+      } catch (e) {
+        logger.error('reconnect fail', e)
+        this._attemptReconnect(device, reason)
+      }
+    }, delay)
   }
 
   _clearReconnect() {