Browse Source

refactor(更新)
- 蓝牙连接逻辑优化
- 修复钥匙在归还队列时,下发作业票会断开连接的问题
- 修复钥匙在发送队列时,归还钥匙会断开连接的问题
- 修复获取钥匙失败,提示作业票获取失败的问题
- 修复同时连接多把钥匙时,无法获取钥匙状态的问题
- 修复退出登录未取消监听钥匙状态的问题

周文健 3 months ago
parent
commit
8e4119aba4

+ 4 - 3
app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt

@@ -141,7 +141,7 @@ class MainActivity() : BaseActivity<ActivityMainBinding>() {
                 val firstId = binding.navBar.menu[0].itemId
                 binding.navBar.selectedItemId = firstId
                 MainDomainData.fromQuickEntry = false
-                viewModel.checkMyTodoForHandleKey().observe(this){}
+                viewModel.checkMyTodoForHandleKey().observe(this) {}
             }
             binding.navBar.isVisible = bottomNavDestinations.contains(destination.id)
         }
@@ -179,9 +179,9 @@ class MainActivity() : BaseActivity<ActivityMainBinding>() {
 
     override fun initData() {
         super.initData()
-        if (isFirstEnter){
+        if (isFirstEnter) {
             isFirstEnter = false
-            viewModel.checkMyTodoForHandleKey().observe(this){}
+            viewModel.checkMyTodoForHandleKey().observe(this) {}
         }
         viewModel.bleIndicate()
         viewModel.registerStatusListener()
@@ -213,6 +213,7 @@ class MainActivity() : BaseActivity<ActivityMainBinding>() {
      * 退出登录
      */
     private fun logout() {
+        viewModel.unregisterStatusListener()
         BleSendDispatcher.disconnectAll(60_0000L)
         viewModel.removeBleIndicate()
         startActivity(Intent(this, LoginActivity::class.java).apply {

+ 33 - 32
app/src/main/java/com/grkj/iscs/features/main/viewmodel/MainViewModel.kt

@@ -1,10 +1,12 @@
 package com.grkj.iscs.features.main.viewmodel
 
+import android.annotation.SuppressLint
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.logic.IJobTicketLogic
 import com.grkj.shared.utils.extension.startsWith
+import com.grkj.ui_base.R
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.business.BleBusinessManager
 import com.grkj.ui_base.business.DataBusiness
@@ -21,6 +23,7 @@ import com.grkj.ui_base.utils.ble.BleReturnDispatcher
 import com.grkj.ui_base.utils.ble.BleSendDispatcher
 import com.grkj.ui_base.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.modbus.DeviceConst
+import com.grkj.ui_base.utils.modbus.ModBusController
 import com.sik.sikcore.thread.ThreadUtils
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.Dispatchers
@@ -75,6 +78,16 @@ class MainViewModel @Inject constructor(
         BleConnectionManager.removeBleIndicateListener(MainViewModel::class.java.simpleName)
     }
 
+    /**
+     * 取消注册状态监听
+     */
+    fun unregisterStatusListener(){
+        ModbusBusinessManager.unregisterListener(this)
+    }
+
+    /**
+     * 注册状态监听
+     */
     fun registerStatusListener() {
         ModbusBusinessManager.registerStatusListener(this) { dockBean ->
             if (MainDomainData.userInfo == null || ISCSConfig.isDeviceRegistration) {
@@ -85,41 +98,29 @@ class MainViewModel @Inject constructor(
                     dockBean.getKeyList().forEach { keyBean ->
                         if (keyBean.isExist) {
                             keyBean.mac?.let { mac ->
-                                ThreadUtils.runOnMain {
-                                    LoadingEvent.sendLoadingEvent(
-                                        CommonUtils.getStr(com.grkj.ui_base.R.string.loading_msg_return_key_start),
-                                        true
-                                    )
-                                }
                                 ThreadUtils.runOnIO {
-                                    fun readJobTicket(mac: String, retryCount: Int = 3) {
+                                    @SuppressLint("MissingPermission")
+                                    fun readJobTicket(mac: String) {
                                         ThreadUtils.runOnIO {
-                                            if (BleSendDispatcher.isConnecting(mac) || BleSendDispatcher.isConnected(
-                                                    mac
-                                                )
-                                            ) {
-                                                BleSendDispatcher.scheduleDisconnect(mac)
-                                                delay(300)
-                                                BleReturnDispatcher.submit(mac) { isConnect ->
-                                                    if (isConnect) {
-                                                        val bleBean =
-                                                            BleConnectionManager.getBleDeviceByMac(mac)
-                                                        Executor.delayOnMain(300) {
-                                                            bleBean?.let {
-                                                                LoadingEvent.sendLoadingEvent(
-                                                                    CommonUtils.getStr(com.grkj.ui_base.R.string.loading_msg_get_ticket_status_start),
-                                                                    true
-                                                                )
-                                                                BleConnectionManager.getCurrentStatus(
-                                                                    4,
-                                                                    it.bleDevice
-                                                                )
-                                                            }
+                                            BleReturnDispatcher.submit(mac) { isConnect ->
+                                                if (isConnect) {
+                                                    val bleBean =
+                                                        BleConnectionManager.getBleDeviceByMac(mac)
+                                                    Executor.delayOnMain(300) {
+                                                        bleBean?.let {
+                                                            LoadingEvent.sendLoadingEvent(
+                                                                CommonUtils.getStr(com.grkj.ui_base.R.string.loading_msg_get_ticket_status_start),
+                                                                true
+                                                            )
+                                                            BleConnectionManager.getCurrentStatus(
+                                                                4,
+                                                                it.bleDevice
+                                                            )
                                                         }
-                                                    } else if (retryCount > 0) {
-                                                        readJobTicket(mac, retryCount - 1)
-                                                    } else {
-                                                        LoadingEvent.sendLoadingEvent()
+                                                    }
+                                                }else{
+                                                    ModBusController.controlKeyBuckle(true,mac){
+                                                        showTip(CommonUtils.getStr(R.string.ticket_get_failed).toString())
                                                     }
                                                 }
                                             }

+ 107 - 73
ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt

@@ -1,5 +1,6 @@
 package com.grkj.ui_base.business
 
+import android.annotation.SuppressLint
 import android.bluetooth.BluetoothGattCharacteristic
 import com.google.gson.Gson
 import com.grkj.data.data.DictConstants
@@ -362,6 +363,7 @@ object BleBusinessManager {
     /**
      * 根据当前模式进行处理
      */
+    @SuppressLint("MissingPermission")
     private fun handleCurrentMode(currentModeEvent: CurrentModeEvent) {
         when (currentModeEvent.mode) {
             // 工作模式
@@ -386,62 +388,17 @@ object BleBusinessManager {
                         return
                     }
                     updateBo?.let { itBO ->
-                        ThreadUtils.runOnIO {
-                            val jobTicketData =
-                                LogicManager.jobTicketLogic.getJobTicketDataByTicketId(itBO.ticketId)
-                            if (jobTicketData == null) {
-                                ModBusController.updateKeyReadyStatus(
-                                    currentModeEvent.bleBean.bleDevice.mac, true, 4
-                                )
-                                ModBusController.controlKeyBuckle(
-                                    false, currentModeEvent.bleBean.bleDevice.mac
-                                )
-                                LoadingEvent.sendLoadingEvent()
-                                logger.info("作业票数据为空")
-                                return@runOnIO
-                            }
-                            LogicManager.jobTicketLogic.getStepDetail(itBO.ticketId) {
-                                logger.info("步骤数据:${it.toJson()}")
-                                val step = it?.firstOrNull { it.stepStatus == "0" }
-                                logger.info("当前步骤:${step.toJson()}")
-                                LogicManager.jobTicketLogic.getTicketDetail(itBO.ticketId) { ticketDetail ->
-                                    logger.info("步骤详情:${ticketDetail.toJson()}")
-                                    val role =
-                                        ticketDetail?.ticketUserVOList?.filter { it.userRole == RoleEnum.JTLOCKER.roleKey }
-                                            ?.find {
-                                                it.userId == MainDomainData.userInfo?.userId
-                                            }
-                                    if (role == null) {
-                                        ThreadUtils.runOnMain {
-                                            PopTip.build()
-                                                .tip(CommonUtils.getStr(R.string.you_are_not_locker_tip))
-                                        }
-                                        return@getTicketDetail
-                                    }
-                                    if (step?.enableLock == true) {    // 上锁工作票
-                                        sendTicketBusiness(
-                                            true,
-                                            currentModeEvent.bleBean.bleDevice.mac,
-                                            ticketDetail,
-                                            ticketDetail.ticketLockVOList?.filter {
-                                                it.groupId == MainDomainData.deviceTakeTicketGroupBound[itBO.ticketId] &&
-                                                        ticketDetail.ticketPointsVOList?.filter { it.groupId == MainDomainData.deviceTakeTicketGroupBound[itBO.ticketId] }
-                                                            ?.mapNotNull { it.lockId }
-                                                            ?.contains(it.lockId) != true
-                                            }
-                                                ?.map { it.lockNfc }?.toMutableList(),
-                                            true
-                                        )
-                                    } else if (step?.enableUnlock == true) { // 解锁工作票
-                                        sendTicketBusiness(
-                                            false,
-                                            currentModeEvent.bleBean.bleDevice.mac,
-                                            ticketDetail,
-                                            null,
-                                            true
-                                        )
-                                    }
-                                }
+                        if (BleReturnDispatcher.isConnected(currentModeEvent.bleBean.bleDevice.mac)) {
+                            logger.info("当前钥匙在归还队列,断开连接")
+                            BleReturnDispatcher.scheduleDisconnect(currentModeEvent.bleBean.bleDevice.mac)
+                        }
+                        if (BleSendDispatcher.isConnected(currentModeEvent.bleBean.bleDevice.mac)) {
+                            logger.info("当前钥匙已在发送队列连接")
+                            checkAndSendTicket(currentModeEvent, itBO)
+                        } else {
+                            logger.info("当前钥匙未加入发送队列,连接后发送")
+                            BleSendDispatcher.submit(currentModeEvent.bleBean.bleDevice.mac) {
+                                checkAndSendTicket(currentModeEvent, itBO)
                             }
                         }
                     } ?: let {
@@ -453,12 +410,22 @@ object BleBusinessManager {
                         )
                         LoadingEvent.sendLoadingEvent()
                         ThreadUtils.runOnIO {
-                            if (BleReturnDispatcher.isConnected(currentModeEvent.bleBean.bleDevice.mac)) {
-                                BleReturnDispatcher.scheduleDisconnect(currentModeEvent.bleBean.bleDevice.mac)
-                            }
+                            BleReturnDispatcher.scheduleDisconnect(currentModeEvent.bleBean.bleDevice.mac)
                             DataBusiness.checkMyTodoForHandleKey(currentModeEvent.bleBean.bleDevice.mac)
                         }
                     }
+                } ?: let {
+                    ModBusController.updateKeyReadyStatus(
+                        currentModeEvent.bleBean.bleDevice.mac, true, 4
+                    )
+                    ModBusController.controlKeyBuckle(
+                        false, currentModeEvent.bleBean.bleDevice.mac
+                    )
+                    LoadingEvent.sendLoadingEvent()
+                    ThreadUtils.runOnIO {
+                        BleReturnDispatcher.scheduleDisconnect(currentModeEvent.bleBean.bleDevice.mac)
+                        DataBusiness.checkMyTodoForHandleKey(currentModeEvent.bleBean.bleDevice.mac)
+                    }
                 }
             }
             // 故障模式
@@ -471,20 +438,85 @@ object BleBusinessManager {
         }
     }
 
+    /**
+     * 检查并下发作业票
+     */
+    private fun checkAndSendTicket(currentModeEvent: CurrentModeEvent, itBO: DeviceTakeUpdate) {
+        ThreadUtils.runOnIO {
+            val jobTicketData =
+                LogicManager.jobTicketLogic.getJobTicketDataByTicketId(itBO.ticketId)
+            if (jobTicketData == null) {
+                ModBusController.updateKeyReadyStatus(
+                    currentModeEvent.bleBean.bleDevice.mac, true, 4
+                )
+                ModBusController.controlKeyBuckle(
+                    false, currentModeEvent.bleBean.bleDevice.mac
+                )
+                LoadingEvent.sendLoadingEvent()
+                logger.info("作业票数据为空")
+                return@runOnIO
+            }
+            LogicManager.jobTicketLogic.getStepDetail(itBO.ticketId) {
+                logger.info("步骤数据:${it.toJson()}")
+                val step = it?.firstOrNull { it.stepStatus == "0" }
+                logger.info("当前步骤:${step.toJson()}")
+                LogicManager.jobTicketLogic.getTicketDetail(itBO.ticketId) { ticketDetail ->
+                    logger.info("步骤详情:${ticketDetail.toJson()}")
+                    val role =
+                        ticketDetail?.ticketUserVOList?.filter { it.userRole == RoleEnum.JTLOCKER.roleKey }
+                            ?.find {
+                                it.userId == MainDomainData.userInfo?.userId
+                            }
+                    if (role == null) {
+                        ThreadUtils.runOnMain {
+                            PopTip.build()
+                                .tip(CommonUtils.getStr(R.string.you_are_not_locker_tip))
+                        }
+                        return@getTicketDetail
+                    }
+                    if (step?.enableLock == true) {    // 上锁工作票
+                        sendTicketBusiness(
+                            true,
+                            currentModeEvent.bleBean.bleDevice.mac,
+                            ticketDetail,
+                            ticketDetail.ticketLockVOList?.filter {
+                                it.groupId == MainDomainData.deviceTakeTicketGroupBound[itBO.ticketId] &&
+                                        ticketDetail.ticketPointsVOList?.filter { it.groupId == MainDomainData.deviceTakeTicketGroupBound[itBO.ticketId] }
+                                            ?.mapNotNull { it.lockId }
+                                            ?.contains(it.lockId) != true
+                            }
+                                ?.map { it.lockNfc }?.toMutableList(),
+                            true
+                        )
+                    } else if (step?.enableUnlock == true) { // 解锁工作票
+                        sendTicketBusiness(
+                            false,
+                            currentModeEvent.bleBean.bleDevice.mac,
+                            ticketDetail,
+                            null,
+                            true
+                        )
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * 读取工作票完成情况
      */
+    @SuppressLint("MissingPermission")
     private fun getTicketStatusBusiness(
         mac: String, isNeedLoading: Boolean = false
     ) {
-        BleConnectionManager.registerConnectListener(mac, isSend = false) { isDone, bleBean ->
-            if (isDone) {
-                Executor.delayOnMain(500) {
-                    getTicketStatusWithRetry(bleBean!!.bleDevice, isNeedLoading)
-                }
-            } else {
-                if (isNeedLoading) LoadingEvent.sendLoadingEvent()
+        logger.info("检查钥匙连接情况")
+        if (BleReturnDispatcher.isConnected(mac)) {
+            BleConnectionManager.getBleDeviceByMac(mac)?.bleDevice?.let {
+                logger.info("开始读取作业票")
+                getTicketStatusWithRetry(it, isNeedLoading)
             }
+        } else {
+            if (isNeedLoading) LoadingEvent.sendLoadingEvent()
         }
     }
 
@@ -520,6 +552,7 @@ object BleBusinessManager {
         isNeedLoading: Boolean = false,
         processCallback: ((Boolean) -> Unit)? = null
     ) {
+        logger.info("发送获取作业票指令")
         if (isNeedLoading) LoadingEvent.sendLoadingEvent("开始获取工作票", true)
         BleCmdManager.getTicketStatus(bleDevice, object : CustomBleWriteCallback() {
             override fun onWriteSuccess(
@@ -1005,6 +1038,7 @@ object BleBusinessManager {
     /**
      * 下发工作票
      */
+    @SuppressLint("MissingPermission")
     private fun sendTicketBusiness(
         isLock: Boolean,
         mac: String,
@@ -1012,15 +1046,11 @@ object BleBusinessManager {
         lockList: MutableList<String?>?,
         isNeedLoading: Boolean = false,
     ) {
-        BleConnectionManager.registerConnectListener(mac) { isDone, bleBean ->
-            if (!isDone) {
-                sendTicketBusiness(isLock, mac, ticketDetail, lockList, isNeedLoading)
-                return@registerConnectListener
-            }
+        if (BleSendDispatcher.isConnected(mac)) {
+            val bleBean = BleConnectionManager.getBleDeviceByMac(mac)
             if (bleBean == null) {
-//                ToastUtils.tip(R.string.simple_key_is_not_connected)
                 logger.error("sendTicketBusiness fail : $mac, bleBean is null")
-                return@registerConnectListener
+                return
             }
             // 单bleBean json赋值
             bleBean.retryCount = 0
@@ -1028,6 +1058,10 @@ object BleBusinessManager {
             bleBean.ticketSend?.let { itJson ->
                 sendTicketWithRetry(itJson, bleBean.bleDevice, isNeedLoading)
             }
+        } else {
+            ThreadUtils.runOnIODelayed(1000) {
+                sendTicketBusiness(isLock, mac, ticketDetail, lockList, isNeedLoading)
+            }
         }
     }
 

+ 11 - 11
ui-base/src/main/java/com/grkj/ui_base/business/DataBusiness.kt

@@ -11,12 +11,15 @@ import com.grkj.data.model.res.LockPageRes
 import com.grkj.ui_base.business.BleBusinessManager.connectExistsKey
 import com.grkj.ui_base.utils.ble.BleSendDispatcher
 import kotlinx.coroutines.suspendCancellableCoroutine
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
 import kotlin.coroutines.resume
 
 /**
  * 数据业务
  */
 object DataBusiness {
+    private val logger: Logger = LoggerFactory.getLogger(DataBusiness::class.java)
 
     // 1. 把 NetApi.get…Page 包成 suspend 函数
     suspend fun getSlotsPage(): CabinetSlotsRes? = suspendCancellableCoroutine { cont ->
@@ -71,19 +74,16 @@ object DataBusiness {
                 .toMutableList()
         val todoData = splitTodoSteps(todoItemVos, 1)
         if (todoData.first.any { it.enableLock || it.enableUnlock } || todoData.second.any { it.enableLock || it.enableUnlock }) {
-            val maxPowerMac = ModbusBusinessManager.getMaxPowerKey(mac?:"").mac
-            if (maxPowerMac != mac) {
-                connectExistsKey(listOf(mac ?: ""))
-                BleSendDispatcher.scheduleDisconnect(mac ?: "", delay)
-            } else {
-                connectExistsKey()
+            logger.info("蓝牙连接-存在上锁解锁待办")
+            if (BleSendDispatcher.canConnect()) {
+                logger.info("蓝牙连接-发送队列可以连接")
+                mac?.let {
+                    connectExistsKey(listOf(it))
+                }
             }
         } else {
-            mac?.let {
-                BleSendDispatcher.scheduleDisconnect(mac, delay)
-            } ?: let {
-                BleSendDispatcher.disconnectAll(delay)
-            }
+            logger.info("蓝牙连接-没有待办数据,延迟断开所有发送连接")
+            BleSendDispatcher.disconnectAll(delay)
         }
         return true
     }

+ 6 - 7
ui-base/src/main/java/com/grkj/ui_base/business/ModbusBusinessManager.kt

@@ -18,6 +18,7 @@ import com.grkj.ui_base.utils.event.UpdateTicketProgressEvent
 import com.grkj.shared.utils.extension.removeLeadingZeros
 import com.grkj.ui_base.utils.extension.serialNo
 import com.grkj.shared.utils.extension.toHexStrings
+import com.grkj.ui_base.utils.ble.BleSendDispatcher
 import com.grkj.ui_base.utils.extension.tip
 import com.grkj.ui_base.utils.modbus.DeviceConst
 import com.grkj.ui_base.utils.modbus.DockBean
@@ -126,6 +127,11 @@ object ModbusBusinessManager {
             DeviceConst.DEVICE_TYPE_KEY -> {
                 mDeviceTakeList.find { it.deviceType == DeviceConst.DEVICE_TYPE_KEY && it.nfc == deviceTakeUpdateBO.nfc }
                     ?.let { info ->
+                        if (mDeviceTakeList.any { it.deviceType == DeviceConst.DEVICE_TYPE_LOCK && it.ticketId == info.ticketId }) {
+                            BleSendDispatcher.scheduleDisconnect(getKeyMacByRfid(info.nfc), 60_000)
+                            logger.info("存在未取出的挂锁,不继续操作")
+                            return
+                        }
                         LoadingEvent.sendLoadingEvent()
                         SPUtils.takeKey(info.ticketId)
                         LogicManager.jobTicketLogic.updateKeyTake(
@@ -622,11 +628,4 @@ object ModbusBusinessManager {
         return dockData.filter { it.type == DeviceConst.DOCK_TYPE_KEY }.flatMap { it.deviceList }
             .filterIsInstance<DockBean.KeyBean>()
     }
-
-    /**
-     * 获取电量最多的钥匙
-     */
-    fun getMaxPowerKey(mac: String): DockBean.KeyBean {
-        return ModBusController.getMaxPowerKey(mac)
-    }
 }

+ 11 - 12
ui-base/src/main/java/com/grkj/ui_base/service/CheckKeyInfoTask.kt

@@ -21,17 +21,16 @@ class CheckKeyInfoTask {
     @CronJob(intervalMillis = 30 * 60_000L, initialDelay = 0, runOnMainThread = false)
     fun checkKeyInfo() {
         logger.info("开始检查钥匙信息")
-        val existsKey = ModbusBusinessManager.getExistsKey()
-        ThreadUtils.runOnIO {
-            for (bean in existsKey) {
-                bean.mac?.let { mac ->
-                    BleSendDispatcher.submit(mac) {
-                        logger.info("信息获取完成,检查是否立即断开")
-                        DataBusiness.checkMyTodoForHandleKey(mac, 0)
-                    }
-                }
-            }
-        }
-
+//        val existsKey = ModbusBusinessManager.getExistsKey()
+//        ThreadUtils.runOnIO {
+//            for (bean in existsKey) {
+//                bean.mac?.let { mac ->
+//                    BleSendDispatcher.submit(mac) {
+//                        logger.info("信息获取完成,检查是否立即断开")
+//                        DataBusiness.checkMyTodoForHandleKey(mac, 0)
+//                    }
+//                }
+//            }
+//        }
     }
 }

+ 2 - 0
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleCmdManager.kt

@@ -1,5 +1,6 @@
 package com.grkj.ui_base.utils.ble
 
+import android.annotation.SuppressLint
 import android.bluetooth.BluetoothGattCharacteristic
 import com.grkj.ui_base.utils.event.GetTicketStatusEvent
 import com.grkj.shared.utils.extension.crc16
@@ -226,6 +227,7 @@ object BleCmdManager {
     /**
      * 获取设备当前状态
      */
+    @SuppressLint("MissingPermission")
     fun getCurrentStatus(bleDevice: BleDevice, callback: CustomBleWriteCallback?) {
         BleConnectionManager.getBleDeviceByMac(bleDevice.mac)?.let {
             BleUtil.instance?.write(

+ 16 - 13
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConnectionManager.kt

@@ -142,7 +142,6 @@ object BleConnectionManager {
         }
         if (connectNow) {
             logger.warn("蓝牙连接-立即连接 mac: $mac")
-            if (isSend) BleSendDispatcher.disconnectAll() else BleReturnDispatcher.disconnectAll()
             unregisterConnectListener(mac)
             currentConnectingMac.removeIf { it == mac }
         }
@@ -320,7 +319,7 @@ object BleConnectionManager {
                 scannedBefore: Boolean
             ) {
                 val scanMac = newDevice.mac
-                logger.info("蓝牙连接-onScanning:${mac}")
+                logger.info("蓝牙连接-onScanning:${mac},${scanMac}")
                 if (scanMac.equals(mac, ignoreCase = true)) {
                     // 找到目标设备,马上停止扫描
                     logger.info("找到目标设备 $mac,停止扫描并尝试连接")
@@ -423,6 +422,12 @@ object BleConnectionManager {
                             null, false
                         )
                         logger.info("蓝牙连接-onDisConnected : ${device?.mac} - $isActiveDisConnected")
+                        if (BleSendDispatcher.isConnected(bleDevice.mac)) {
+                            BleSendDispatcher.clear(bleDevice.mac)
+                        }
+                        if (BleReturnDispatcher.isConnected(bleDevice.mac)) {
+                            BleSendDispatcher.clear(bleDevice.mac)
+                        }
                         bleDevice.mac?.let { itMac ->
                             unregisterConnectListener(itMac)
                         }
@@ -431,16 +436,6 @@ object BleConnectionManager {
                             if (ISCSConfig.isTestMode) {
                                 return
                             }
-                            // 断开和重连之间最好间隔一段时间,否则可能会出现长时间连接不上的情况
-//                            ThreadUtils.runOnMainDelayed(300) {
-//                                registerConnectListener(bleDevice.mac) { isDone, bleBean ->
-//                                    if (isDone && bleBean != null) {
-//                                        ThreadUtils.runOnMainDelayed(300) {
-//                                            getCurrentStatus(6, bleBean.bleDevice)
-//                                        }
-//                                    }
-//                                }
-//                            }
                             ModBusController.updateKeyReadyStatus(bleDevice.mac, false, 3)
                         } else {
                             ModBusController.updateKeyReadyStatus(bleDevice.mac, false, 3)
@@ -457,6 +452,7 @@ object BleConnectionManager {
     /**
      * 获取当前钥匙的状态
      */
+    @SuppressLint("MissingPermission")
     fun getCurrentStatus(
         from: Int,
         bleDevice: BleDevice,
@@ -474,6 +470,8 @@ object BleConnectionManager {
                         getCurrentStatus(from, bleDevice, retryCount - 1, timeoutCallBack)
                     }
                 } else {
+                    BleSendDispatcher.scheduleDisconnect(bleDevice.mac)
+                    BleReturnDispatcher.scheduleDisconnect(bleDevice.mac)
                     ModBusController.getKeyByMac(bleDevice.mac)?.rfid?.let {
                         addExceptionKey(it)
                         timeoutCallBack?.invoke(true)
@@ -508,7 +506,12 @@ object BleConnectionManager {
                 logger.info("getCurrentStatus fail : ${bleDevice.mac}")
                 isTimeout = false
                 ThreadUtils.runOnMainDelayed(1000) {
-                    getCurrentStatus(from, bleDevice, timeoutCallBack = timeoutCallBack)
+                    getCurrentStatus(
+                        from,
+                        bleDevice,
+                        retryCount - 1,
+                        timeoutCallBack = timeoutCallBack
+                    )
                 }
             }
         })

+ 37 - 17
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleQueueDispatcher.kt

@@ -5,6 +5,7 @@ import android.annotation.SuppressLint
 import androidx.annotation.RequiresPermission
 import com.grkj.ui_base.utils.ble.BleConnectionManager.deviceList
 import com.huyuhui.fastble.BleManager
+import com.sik.sikcore.thread.ThreadUtils
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.Job
@@ -13,46 +14,64 @@ import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
+import kotlin.math.log
 
 abstract class BleQueueDispatcher {
     private val logger: Logger = LoggerFactory.getLogger(BleQueueDispatcher::class.java)
-    private val taskQueue = ArrayDeque<Pair<String, (Boolean) -> Unit>>() // mac + callback
-    private val activeMacs = mutableMapOf<String, (Boolean) -> Unit>()
+    private val taskQueue =
+        ArrayDeque<Pair<String, MutableList<(Boolean) -> Unit>>>() // mac + callback
+    private val activeMacs = mutableMapOf<String, MutableList<(Boolean) -> Unit>>()
     private val connectedMacs = mutableSetOf<String>()
     private val pendingDisconnectJobs = mutableMapOf<String, Job>()
 
     open val maxConnections: Int = 1
     private val dispatcherScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
 
+    /**
+     * 检查钥匙状态
+     */
+    @RequiresPermission(Manifest.permission.BLUETOOTH_CONNECT)
     @Synchronized
     fun submit(mac: String, onResult: (Boolean) -> Unit) {
-
+        logger.info("开始检查钥匙状态:${mac}")
         if (activeMacs.containsKey(mac) || taskQueue.any { it.first == mac } || connectedMacs.contains(
                 mac
             )) {
             if (connectedMacs.contains(mac)) {
+                logger.info("${this::class.java} 检查到钥匙已连接")
                 onResult(true)
+            } else if (activeMacs.containsKey(mac)) {
+                logger.info("${this::class.java} 检查到钥匙连接中添加回调")
+                activeMacs[mac]?.add(onResult)
+            } else if (taskQueue.find { it.first == mac } != null) {
+                logger.info("${this::class.java} 检查到钥匙队列中添加回调")
+                taskQueue.find { it.first == mac }?.second?.add(onResult)
             }
             // 如果已存在断连计划,取消它
             pendingDisconnectJobs.remove(mac)?.cancel()
             return
         }
-        taskQueue.add(mac to onResult)
+        taskQueue.add(mac to mutableListOf(onResult))
         tryStartNext()
     }
 
+    /**
+     * 开始连接
+     */
     @Synchronized
     private fun tryStartNext() {
         if ((activeMacs.size + connectedMacs.size) >= maxConnections || taskQueue.isEmpty()) return
-        val (mac, callback) = taskQueue.removeFirst()
-        activeMacs[mac] = callback
+        val (mac, callbacks) = taskQueue.removeFirst()
+        activeMacs[mac] = callbacks
         doConnect(mac) { success ->
             synchronized(this) {
                 activeMacs.remove(mac)
                 if (success) {
                     connectedMacs.add(mac)
                 }
-                callback(success)
+                callbacks.forEach {
+                    it.invoke(success)
+                }
                 tryStartNext()
             }
         }
@@ -66,9 +85,6 @@ abstract class BleQueueDispatcher {
         activeMacs.remove(mac)
         connectedMacs.remove(mac)
         pendingDisconnectJobs.remove(mac)?.cancel()
-        if ((activeMacs.size + connectedMacs.size) < maxConnections && taskQueue.isNotEmpty()) {
-            tryStartNext()
-        }
     }
 
     @SuppressLint("MissingPermission")
@@ -80,14 +96,18 @@ abstract class BleQueueDispatcher {
             delay(delayMillis)
             synchronized(this@BleQueueDispatcher) {
                 if (connectedMacs.remove(mac)) {
-                    val deviceBean = deviceList.find { it.bleDevice.mac == mac }
-                    deviceBean?.let {
-                        disconnectDeviceByMac(mac)
-                        deviceList.removeIf { it.bleDevice.mac == deviceBean.bleDevice.mac }
+                    ThreadUtils.runOnIO {
+                        val deviceBean = deviceList.find { it.bleDevice.mac == mac }
+                        deviceBean?.let {
+                            disconnectDeviceByMac(mac)
+                            deviceList.removeIf { it.bleDevice.mac == deviceBean.bleDevice.mac }
+                        }
+                        logger.info("当前线程:${Thread.currentThread().name}")
+                        clear(mac)
+                        if ((activeMacs.size + connectedMacs.size) < maxConnections && taskQueue.isNotEmpty()) {
+                            tryStartNext()
+                        }
                     }
-                    logger.info("当前线程:${Thread.currentThread().name}")
-                    clear(mac)
-                    tryStartNext()
                 }
                 pendingDisconnectJobs.remove(mac)
             }

+ 5 - 0
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleReturnDispatcher.kt

@@ -1,11 +1,16 @@
 package com.grkj.ui_base.utils.ble
 
+import com.grkj.ui_base.utils.CommonUtils
+import com.grkj.ui_base.utils.event.LoadingEvent
 import com.sik.sikcore.thread.ThreadUtils
 
 object BleReturnDispatcher : BleQueueDispatcher() {
     override val maxConnections = 1
 
     override fun doConnect(mac: String, callback: (Boolean) -> Unit) {
+        ThreadUtils.runOnMain {
+            LoadingEvent.sendLoadingEvent(CommonUtils.getStr(com.grkj.ui_base.R.string.loading_msg_return_key_start))
+        }
         ThreadUtils.runOnIO {
             val isConnected = BleConnectionManager.tryConnectWithOptionalCharge(mac, isSend = false)
             callback(isConnected)

+ 1 - 8
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleUtil.kt

@@ -50,7 +50,7 @@ class BleUtil private constructor() {
             if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
                 //Android 12及以上不允许添加过滤器
                 val bleScanRuleConfig = BleScanRuleConfig.Builder()
-                    .setScanTimeOut(3_000L)
+                    .setScanTimeOut(6_000L)
                     .setDeviceName(BleConst.BLE_LOCAL_NAME)
                     .apply {
                         setScanSettings(ScanSettings.Builder().apply {
@@ -239,13 +239,6 @@ class BleUtil private constructor() {
                             cmd,
                             callback = writeCallback
                         )
-                    } else {
-                        delay(800)
-                        bleDevice.mac?.let {
-                            BleSendDispatcher.submit(bleDevice.mac) {
-                                connectAndWrite()
-                            }
-                        }
                     }
                 }
             }

+ 54 - 22
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusController.kt

@@ -1,5 +1,6 @@
 package com.grkj.ui_base.utils.modbus
 
+import android.annotation.SuppressLint
 import com.grkj.data.di.LogicManager
 import com.grkj.data.model.res.CabinetSlotsRecord
 import com.grkj.shared.utils.extension.isPureZero
@@ -8,11 +9,11 @@ import com.grkj.shared.utils.extension.toHexStrings
 import com.grkj.ui_base.R
 import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.ui_base.utils.ble.BleConnectionManager
 import com.grkj.ui_base.utils.ble.BleReturnDispatcher
 import com.grkj.ui_base.utils.ble.BleSendDispatcher
 import com.grkj.ui_base.utils.event.ModbusInitCompleteEvent
 import com.grkj.ui_base.utils.extension.tip
+import com.huyuhui.fastble.BleManager
 import com.kongzue.dialogx.dialogs.PopTip
 import kotlinx.coroutines.isActive
 import org.slf4j.Logger
@@ -977,6 +978,7 @@ object ModBusController {
      *
      * @return 底座地址,钥匙
      */
+    @SuppressLint("MissingPermission")
     suspend fun getOneKey(
         exceptionSlots: List<CabinetSlotsRecord>,
         exceptionKeysRfid: List<String>,
@@ -987,7 +989,16 @@ object ModBusController {
         val keyDockList =
             dockList.filter { it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
                 .sortedBy { it.addr }.onEach { it.deviceList.sortBy { dev -> dev.idx } }
-
+        val noBelongDevice = BleManager.getAllConnectedDevice().filter {
+            !BleSendDispatcher.isConnected(it.mac) &&
+                    !BleSendDispatcher.isConnecting(it.mac) &&
+                    !BleReturnDispatcher.isConnected(it.mac) &&
+                    !BleReturnDispatcher.isConnecting(it.mac)
+        }
+        logger.info("检查到不属于任何队列的设备:${noBelongDevice.map { it.mac }},立即断开连接让路")
+        noBelongDevice.forEach {
+            BleManager.disconnect(it)
+        }
         var keyList = keyDockList.flatMap { it.deviceList }.apply {
             logger.info("keyStatus:${this}")
         }.filterIsInstance<DockBean.KeyBean>()
@@ -1008,13 +1019,44 @@ object ModBusController {
                     it.mac ?: ""
                 )
             }    // 主键:在线优先
-                .thenByDescending { BleConnectionManager.getBleDeviceByMac(it.mac)?.token != null } // 次键:有 token 优先
                 .thenByDescending { it.power }                                                // 三级:电量越高
         )
-
+        val connectedKey = keyList.find { BleSendDispatcher.isConnected(it.mac ?: "") }
+        if (connectedKey != null) {
+            val addr =
+                keyDockList.firstOrNull {
+                    it.getKeyList().any { it.rfid == connectedKey.rfid }
+                }?.addr
+            if (addr != null) {
+                return addr to connectedKey
+            }
+        }
+        val connectingKey = keyList.find { BleSendDispatcher.isConnecting(it.mac ?: "") }
+        if (connectingKey != null) {
+            val result = suspendCoroutine { cont ->
+                BleSendDispatcher.submit(connectingKey.mac ?: "") { connected ->
+                    if (connected) {
+                        val addr =
+                            keyDockList.firstOrNull {
+                                it.getKeyList().any { it.rfid == connectingKey.rfid }
+                            }?.addr
+                        if (addr != null) {
+                            cont.resume(addr to connectingKey)
+                        } else {
+                            cont.resume(null)
+                        }
+                    } else {
+                        cont.resume(null)
+                    }
+                }
+            }
+            if (result != null) {
+                return result
+            }
+        }
         for (kb in keyList) {
             val mac = kb.mac ?: continue
-            val result = suspendCoroutine<Pair<Byte, DockBean.KeyBean>?> { cont ->
+            val result = suspendCoroutine { cont ->
                 BleSendDispatcher.submit(mac) { connected ->
                     if (connected) {
                         logger.info("蓝牙连接完成 :${mac}")
@@ -1023,22 +1065,26 @@ object ModBusController {
                             keyDockList.firstOrNull {
                                 it.getKeyList().any { it.rfid == kb.rfid }
                             }?.addr
+                        logger.info("蓝牙连接-找到的底座地址 :${addr}")
                         if (addr != null) {
                             if (cont.context.isActive) {
                                 cont.resume(addr to kb)
                             }
                         } else {
-                            null
+                            if (cont.context.isActive) {
+                                cont.resume(null)
+                            }
                         }
                     } else {
-                        null
+                        if (cont.context.isActive) {
+                            cont.resume(null)
+                        }
                     }
                 }
             }
             if (result != null) {
                 return result
             }
-
         }
 
         // 一个都没成功
@@ -1137,18 +1183,4 @@ object ModBusController {
         return dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
             .flatMap { it.getLockList() }.find { it.rfid == rfid }
     }
-
-    /**
-     * 获取电量最多的钥匙
-     */
-    fun getMaxPowerKey(mac: String): DockBean.KeyBean {
-        return dockList.filter {
-            it.type in listOf(
-                DeviceConst.DOCK_TYPE_KEY,
-                DeviceConst.DOCK_TYPE_PORTABLE
-            )
-        }
-            .flatMap { it.deviceList }.filterIsInstance<DockBean.KeyBean>().filter { it.mac != mac }
-            .maxBy { it.power }
-    }
 }