瀏覽代碼

refactor(开关和设备异常)
- 锁和钥匙过滤完成

周文健 5 月之前
父節點
當前提交
e796361edf

+ 111 - 58
app/src/main/java/com/grkj/iscs/BusinessManager.kt

@@ -56,7 +56,11 @@ import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_SWITCH_MODE
 import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_UPDATE_TICKET_PROGRESS
 import com.grkj.iscs.model.eventmsg.SwitchModeMsg
 import com.grkj.iscs.model.eventmsg.UpdateTicketProgressMsg
+import com.grkj.iscs.model.vo.dict.CommonDictRespVO
+import com.grkj.iscs.model.vo.hardware.CabinetSlotsRespVo
 import com.grkj.iscs.model.vo.hardware.SwitchListReqVO
+import com.grkj.iscs.model.vo.key.KeyPageRespVO
+import com.grkj.iscs.model.vo.lock.LockPageRespVO
 import com.grkj.iscs.model.vo.lock.LockTakeUpdateReqVO
 import com.grkj.iscs.model.vo.ticket.LockPointUpdateReqVO
 import com.grkj.iscs.model.vo.ticket.TicketDetailRespVO
@@ -74,9 +78,12 @@ import com.sik.sikcore.activity.ActivityTracker
 import com.sik.sikcore.date.TimeUtils
 import com.sik.sikcore.thread.ThreadUtils
 import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.async
 import kotlinx.coroutines.delay
+import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withContext
 import pub.devrel.easypermissions.AfterPermissionGranted
+import kotlin.coroutines.resume
 
 /**
  * 业务层管理
@@ -200,6 +207,8 @@ object BusinessManager {
                         // 待机模式
                         2 -> {
                             if (it.data.res == 1) {
+                                // 只能在这里断开,不能全部断开
+                                BleManager.getInstance().disconnect(it.data.bleBean.bleDevice)
                                 ModBusController.updateKeyReadyStatus(
                                     it.data.bleBean.bleDevice.mac,
                                     true,
@@ -608,79 +617,121 @@ object BusinessManager {
         }
     }
 
-    /**
-     * 检查钥匙和锁具数量
-     *
-     * @param needLockCount 需要的锁具的数量(可能在别的机柜取过)
-     * @param isNeedKey 是否需要钥匙(可能存在前一次拿了部分锁和钥匙,有锁取出失败)
-     */
+    // 1. 把 NetApi.get…Page 包成 suspend 函数
+    private suspend fun getSlotsPage(): CabinetSlotsRespVo? = suspendCancellableCoroutine { cont ->
+        NetApi.getIsLockCabinetSlotsPage { slots ->
+            cont.resume(slots)
+        }
+    }
+
+    private suspend fun getLocksPage(): LockPageRespVO? = suspendCancellableCoroutine { cont ->
+        NetApi.getIsLockPage { locks ->
+            cont.resume(locks)
+        }
+    }
+
+    private suspend fun getKeyPage(): KeyPageRespVO? = suspendCancellableCoroutine { cont ->
+        NetApi.getIsKeyPage { keys ->
+            cont.resume(keys)
+        }
+    }
+
+    // 2. 把原本同步的字典查询留在 IO 线程
+    private suspend fun <T> fetchDict(key: String): List<T> =
+        withContext(Dispatchers.IO) {
+            @Suppress("UNCHECKED_CAST")
+            NetApi.getDictData(key) as List<T>
+        }
+
+    // 3. 重写 checkEquipCount
     fun checkEquipCount(
         needLockCount: Int,
         isNeedKey: Boolean,
         callBack: (Pair<Byte, DockBean.KeyBean?>?, MutableMap<Byte, MutableList<DockBean.LockBean>>) -> Unit
     ) {
-        var lockCount = 0
-        NetApi.getIsLockCabinetSlotsPage { slots ->
-            NetApi.getIsLockPage { locks ->
-                ThreadUtils.runOnIO {
-                    val lockStatus = NetApi.getDictData(DictConstants.KEY_PAD_LOCK_STATUS)
-                    val slotsStatus = NetApi.getDictData(DictConstants.KEY_SLOT_STATUS)
-                    val keyStatus = NetApi.getDictData(DictConstants.KEY_KEY_STATUS)
-                    val slotsType = NetApi.getDictData(DictConstants.KEY_SLOT_TYPE)
-                    val lockMap = ModBusController.getLocks(
+        // 你可以改成接收 CoroutineScope 或者直接在全局 Scope 启动
+        ThreadUtils.runOnMain {
+            try {
+                // —— 串行请求1 & 2 ——
+                val slotsPage = getSlotsPage()
+                val locksPage = getLocksPage()
+
+                // —— 并行加载字典(或按需串行也行) ——
+                val lockStatus =
+                    async { fetchDict<CommonDictRespVO>(DictConstants.KEY_PAD_LOCK_STATUS) }
+                val slotStatus =
+                    async { fetchDict<CommonDictRespVO>(DictConstants.KEY_SLOT_STATUS) }
+                val keyStatus = async { fetchDict<CommonDictRespVO>(DictConstants.KEY_KEY_STATUS) }
+                val slotType = async { fetchDict<CommonDictRespVO>(DictConstants.KEY_SLOT_TYPE) }
+
+                // 等待字典加载完成
+                val lockStatusList = lockStatus.await()
+                val slotStatusList = slotStatus.await()
+                val keyStatusList = keyStatus.await()
+                val slotTypeList = slotType.await()
+
+                // —— 在 Default 线程做计算密集操作 ——
+                val lockMap = withContext(Dispatchers.Default) {
+                    ModBusController.getLocks(
                         needLockCount,
-                        slots?.records?.filter { it.slotType == slotsType?.find { it.dictLabel == "锁" }?.dictValue && it.status == slotsStatus?.find { it.dictLabel == "异常" }?.dictValue }
-                            ?.toMutableList() ?: mutableListOf(),
-                        locks?.records?.filter { it.exStatus == lockStatus?.find { it.dictLabel == "异常" }?.dictValue }
-                            ?.map { it.lockNfc }?.toMutableList() ?: mutableListOf()
+                        slotsPage?.records
+                            ?.filter {
+                                it.slotType == slotTypeList.find { d -> d.dictLabel == "锁" }?.dictValue &&
+                                        it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
+                            }?.toMutableList() ?: mutableListOf(),
+                        locksPage?.records
+                            ?.filter { it.exStatus == lockStatusList.find { d -> d.dictLabel == "异常" }?.dictValue }
+                            ?.map { it.lockNfc }
+                            ?.toMutableList() ?: mutableListOf()
                     )
-                    lockMap.forEach { (_, rfidList) ->
-                        lockCount += rfidList.size
-                    }
+                }
 
-                    var tipStr = ""
-                    if (lockCount < needLockCount) {
-                        val msg =
-                            MyApplication.instance!!.applicationContext.resources.getString(R.string.lock_is_not_enough)
-                        LogUtil.w(msg)
-                        lockMap.clear()
-                    }
+                val actualLockCount = lockMap.values.sumBy { it.size }
+                // 如果锁不够,提前清空并立刻返回
+                if (actualLockCount < needLockCount) {
+                    ToastUtils.tip(
+                        MyApplication.instance!!.getString(R.string.lock_is_not_enough)
+                    )
+                    callBack(null, mutableMapOf())
+                    return@runOnMain
+                }
 
-                    var key: Pair<Byte, DockBean.KeyBean?>? = null
-                    if (isNeedKey && lockCount >= needLockCount) {
-                        NetApi.getIsKeyPage { keyList ->
-                            key =
-                                ModBusController.getOneKey(slots?.records?.filter { it.slotType == slotsType?.find { it.dictLabel == "钥匙" }?.dictValue && it.status == slotsStatus?.find { it.dictLabel == "异常" }?.dictValue }
-                                    ?.toMutableList() ?: mutableListOf(),
-                                    keyList?.records?.filter { it.exStatus == keyStatus?.find { it.dictLabel == "异常" }?.dictValue }
-                                        ?.map { it.keyNfc }?.toMutableList() ?: mutableListOf())
-                            if (key == null) {
-                                val msg =
-                                    MyApplication.instance!!.applicationContext.resources.getString(
-                                        R.string.no_available_key
-                                    )
-                                LogUtil.w(msg)
-                                tipStr = if (tipStr.isEmpty()) {
-                                    msg
-                                } else {
-                                    tipStr + "\n" + msg
-                                }
-                            }
-                        }
+                // —— 如果需钥匙,再请求并计算 ——
+                var keyPair: Pair<Byte, DockBean.KeyBean?>? = null
+                if (isNeedKey) {
+                    val keyPage = withContext(Dispatchers.IO) { getKeyPage() }
+                    keyPair = withContext(Dispatchers.Default) {
+                        ModBusController.getOneKey(
+                            slotsPage?.records
+                                ?.filter {
+                                    it.slotType == slotTypeList.find { d -> d.dictLabel == "钥匙" }?.dictValue &&
+                                            it.status == slotStatusList.find { d -> d.dictLabel == "异常" }?.dictValue
+                                }?.toMutableList() ?: mutableListOf(),
+                            keyPage?.records
+                                ?.filter { it.exStatus == keyStatusList.find { d -> d.dictLabel == "异常" }?.dictValue }
+                                ?.map { it.keyNfc }
+                                ?.toMutableList() ?: mutableListOf()
+                        )
                     }
-
-                    withContext(Dispatchers.Main) {
-                        if (tipStr.isNotEmpty()) {
-                            ToastUtils.tip(tipStr)
-                        }
-                        LogUtil.i("checkEquipCount : key = $key, lockMap = $lockMap")
-                        callBack.invoke(key, lockMap)
+                    if (keyPair == null) {
+                        ToastUtils.tip(
+                            MyApplication.instance!!.getString(R.string.no_available_key)
+                        )
                     }
                 }
+
+                // —— 全部计算完毕,在主线程一次性回调 ——
+                callBack(keyPair, lockMap)
+
+            } catch (e: Exception) {
+                // 根据需求处理异常,或把异常信息也通过 callback 返回
+                e.printStackTrace()
+                ToastUtils.tip("检查设备异常:${e.message}")
             }
         }
     }
 
+
     /**
      * 获取开关量数据
      */
@@ -754,7 +805,7 @@ object BusinessManager {
         if (connectListeners.isEmpty()) {
             return
         }
-        if (isPreparing) {
+        if (isPreparing || BleManager.getInstance().allConnectedDevice.size >= BleConst.MAX_CONNECTED_DEVICE_SIZE) {
             Executor.delayOnMain(1000) {
                 connectKey()
             }
@@ -1915,6 +1966,8 @@ object BusinessManager {
                             false, currentModeMsg.bleBean.bleDevice.mac
                         )
                         sendLoadingEventMsg(null, false)
+                        //连上之后没有工作票要下发就断开,不要占位
+                        BleManager.getInstance().disconnect(currentModeMsg.bleBean.bleDevice)
                     }
                 }
             }

+ 11 - 0
app/src/main/java/com/grkj/iscs/ble/BleConst.kt

@@ -5,6 +5,8 @@ package com.grkj.iscs.ble
  */
 object BleConst {
 
+    const val MAX_CONNECTED_DEVICE_SIZE: Int = 2
+
     const val MTU = 500
 
     const val SERVICE_UUID = "0000FEE7-0000-1000-8000-00805F9B34FB"
@@ -20,43 +22,52 @@ object BleConst {
      */
     // 获取令牌,需增加4字节的时间戳,总长8个字节长度
     val REQ_GET_TOKEN = byteArrayOf(0x01, 0x01, 0x05, 0x00)
+
     // 获取令牌响应,最后4个是token,总长15个字节长度
     val RSP_GET_TOKEN = byteArrayOf(0x01, 0x02, 0x04)
 
     // 设备工作模式切换
     val REQ_SWITCH_MODE = byteArrayOf(0x02, 0x01, 0x02, 0x01)
+
     // 工作模式切换响应
     val RSP_SWITCH_MODE = byteArrayOf(0x02, 0x02, 0x03, 0x01)
 
     // 工作票下发
     val REQ_SEND_WORK_TICKET = byteArrayOf(0x02, 0x01)
+
     // 工作票下发响应
     val RSP_SEND_WORK_TICKET = byteArrayOf(0x02, 0x02, 0x06, 0x02)
 
     // 获取设备当前状态
     val REQ_CURRENT_STATUS = byteArrayOf(0x03, 0x01, 0x01, 0x01)
+
     // 获取当前设备响应
     val RSP_CURRENT_STATUS = byteArrayOf(0x03, 0x02, 0x02, 0x01)
 
     // 获取设备工作票完成情况
     val REQ_WORK_TICKET_RESULT = byteArrayOf(0x03, 0x01, 0x01, 0x02)
+
     // 获取设备工作票完成情况响应
     val RSP_WORK_TICKET_RESULT = byteArrayOf(0x03, 0x02)
+
     // 获取设备工作票完成情况分包
     val REQ_WORK_TICKET_RESULT_PART = byteArrayOf(0x03, 0x01, 0x06, 0x02)
 
     // 获取钥匙电量
     val REQ_POWER_STATUS = byteArrayOf(0x03, 0x01, 0x01, 0x03)
+
     // 获取钥匙电量响应
     val RSP_POWER_STATUS = byteArrayOf(0x03, 0x02, 0x03, 0x03)
 
     // 传输文件
     val REQ_TRANSFER_FILE = byteArrayOf(0x06, 0x01)
+
     // 传输文件完成响应
     val RSP_TRANSFER_FILE = byteArrayOf(0x06, 0x02)
 
     // 获取固件版本号
     val REQ_GET_VERSION = byteArrayOf(0xEE.toByte(), 0x01, 0x02, 0x01, 0x01)
+
     // 获取固件版本号响应
     val RSP_GET_VERSION = byteArrayOf(0xEE.toByte(), 0x02, 0x03, 0x01)
 }

+ 28 - 14
app/src/main/java/com/grkj/iscs/modbus/ModBusController.kt

@@ -24,6 +24,8 @@ import com.grkj.iscs.util.ToastUtils
 import com.grkj.iscs.util.log.LogUtil
 import java.util.concurrent.atomic.AtomicInteger
 import java.util.stream.Collectors
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
 
 
 /**
@@ -899,17 +901,17 @@ object ModBusController {
      *
      * @return 底座地址,钥匙
      */
-    fun getOneKey(
-        exceptionSlots: MutableList<CabinetSlotsRecord>,
-        exceptionKeys: MutableList<String>
+    suspend fun getOneKey(
+        exceptionSlots: MutableList<CabinetSlotsRecord>, exceptionKeys: MutableList<String>
     ): Pair<Byte, DockBean.KeyBean?>? {
+        LogUtil.i("异常钥匙rfid:${exceptionKeys}")
+        LogUtil.i("异常钥匙仓位:${exceptionSlots.joinToString(",") { "${it.row},${it.col}" }}")
         val keyDockList =
             dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }
         keyDockList.sortedBy { it.addr }
         keyDockList.forEach { it.deviceList.sortedBy { it.idx } }
         val keyList =
-            keyDockList.map { it.deviceList }.flatten()
-                .filterIsInstance<DockBean.KeyBean>()
+            keyDockList.map { it.deviceList }.flatten().filterIsInstance<DockBean.KeyBean>()
                 .filterIndexed { index, _ -> (index + 1) !in exceptionSlots.map { it.col?.toInt() } }
                 .filter { it.rfid !in exceptionKeys && !it.rfid.isNullOrEmpty() && !it.mac.isNullOrEmpty() && it.isExist }
                 .toMutableList()
@@ -931,18 +933,27 @@ object ModBusController {
                 } - " + "${!BusinessManager.mExceptionKeyList.contains(it.rfid)}"
             )
         }
-        val key = keyList.filter {
-            it.isExist && it.rfid != null && it.mac != null && it.isReady && BleManager.getInstance()
-                .isConnected(BusinessManager.getBleDeviceByMac(it.mac)?.bleDevice) && !BusinessManager.mExceptionKeyList.contains(
-                it.rfid
-            )
-        }.shuffled().firstOrNull()
+        //等待检查的钥匙,打乱
+        val waitToCheckKeys = keyList.shuffled()
+        var key: DockBean.KeyBean? = null
+        for (waitToCheckKey in waitToCheckKeys) {
+            waitToCheckKey.mac?.let {
+                key = suspendCoroutine { cont ->
+                    BusinessManager.registerConnectListener(it) { isDone, bleBean ->
+                        if (isDone) {
+                            cont.resume(waitToCheckKey)
+                        }
+                    }
+                }
+            }
+        }
+
         if (key == null) {
             LogUtil.e("getOneKey : no key match")
             return null
         }
-
-        val address = keyDockList.find { it.getKeyList().any { it.rfid == key.rfid } }?.addr
+        LogUtil.i("待取钥匙:${key}")
+        val address = keyDockList.find { it.getKeyList().any { it.rfid == key?.rfid } }?.addr
         if (address == null) {
             LogUtil.e("getOneKey : no dock match")
             return null
@@ -970,13 +981,15 @@ object ModBusController {
             dockList.filter { it.type == DOCK_TYPE_LOCK || it.type == DOCK_TYPE_PORTABLE }
         lockDockList.sortedBy { it.addr }
         var provideCount = 0
+        LogUtil.i("异常锁rfid:${exceptionLocks}")
+        LogUtil.i("异常锁仓位:${exceptionSlots.joinToString(",") { "${it.row},${it.col}" }}")
         for (lockDockIndex in lockDockList.indices) {
             if (provideCount >= needLockCount) break
 
             val validLocks =
                 lockDockList[lockDockIndex].getLockList().filter { it.rfid !in exceptionLocks }
                     .filter {
-                        it.isExist && it.idx !in exceptionSlots.filter { it.row?.toInt() == (lockDockIndex + 1) }
+                        it.isExist && it.idx !in exceptionSlots.filter { it.row?.toInt() == (lockDockIndex + 2) }
                             .map { (it.col?.toInt() ?: 1) - 1 }
                     }
             val toTake = (needLockCount - provideCount).coerceAtMost(validLocks.size)
@@ -985,6 +998,7 @@ object ModBusController {
                 provideCount += toTake
             }
         }
+        LogUtil.i("待取锁:${map}")
         return map
     }
 

+ 1 - 0
app/src/main/java/com/grkj/iscs/util/NetApi.kt

@@ -1007,6 +1007,7 @@ object NetApi {
             "exceptionType" to exceptionType,
             "raiser" to raiser,
             "sourceName" to sourceName,
+            "parameters" to sourceName,//设备id
             "raiseTime" to SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(
                 Calendar.getInstance().time
             )

+ 1 - 1
app/src/main/java/com/grkj/iscs/view/dialog/SlotExceptionDialog.kt

@@ -22,7 +22,7 @@ class SlotExceptionDialog(
     override fun initView() {
         mBinding?.hardwareInfo?.text = context.getString(
             R.string.hardware_info,
-            "${getDeviceTypeStr(slotType)},${context.getString(R.string.number)} ${col}"
+            "${getDeviceTypeStr(slotType)},${context.getString(R.string.number)} 行${row},列${col}"
         )
         mBinding?.btnConfirm?.setOnClickListener {
             val exceptionReason = mBinding?.et?.text?.toString()

+ 93 - 0
app/src/main/java/com/grkj/iscs/view/fragment/DeviceStatusFragment.kt

@@ -13,6 +13,7 @@ import com.grkj.iscs.extentions.setVisibleWithHolder
 import com.grkj.iscs.modbus.ModBusController
 import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_KEY
 import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_LOCK
+import com.grkj.iscs.util.ToastUtils
 import com.grkj.iscs.view.base.BaseMvpFragment
 import com.grkj.iscs.view.dialog.SlotExceptionDialog
 import com.grkj.iscs.view.dialog.TipDialog
@@ -50,6 +51,34 @@ class DeviceStatusFragment :
             tipDialog.setTip(it)
             tipDialog.showCancelCountdown(10)
         }
+        presenter?.mExceptionRecovery = { row, col, slotType ->
+            tipDialog.setType(TipDialog.TYPE_CONFIRM)
+            tipDialog.setTip(
+                requireContext().getString(
+                    R.string.is_device_recovery_check,
+                    getDeviceTypeStr(slotType),
+                    "${requireContext().getString(R.string.number)} 行${row},列${col}"
+                )
+            )
+            tipDialog.setConfirmListener {
+                presenter?.slotStatus?.find { it.dictLabel == "可用" }?.dictValue?.let { exceptionStatus ->
+                    presenter?.reportException(
+                        row,
+                        col,
+                        exceptionStatus.toInt(),
+                        ""
+                    ) {
+                        if (it) {
+                            ToastUtils.tip(R.string.recovery_success)
+                        } else {
+                            ToastUtils.tip(R.string.recovery_failed)
+                        }
+                        getSlotsStatus()
+                    }
+                }
+            }
+            tipDialog.showCancelCountdown(10)
+        }
         presenter?.mExceptionReporter = { row, col, slotType ->
             SlotExceptionDialog(requireContext(), row, col, slotType) { exceptionReason ->
                 presenter?.slotStatus?.find { it.dictLabel == "异常" }?.dictValue?.let { exceptionStatus ->
@@ -59,6 +88,11 @@ class DeviceStatusFragment :
                         exceptionStatus.toInt(),
                         exceptionReason
                     ) {
+                        if (it) {
+                            ToastUtils.tip(R.string.report_success)
+                        } else {
+                            ToastUtils.tip(R.string.report_failed)
+                        }
                         getSlotsStatus()
                     }
                 }
@@ -91,6 +125,15 @@ class DeviceStatusFragment :
         }
     }
 
+    private fun getDeviceTypeStr(slotType: Int): String {
+        return when (slotType) {
+            0 -> requireContext().getString(R.string.hardware_key)
+            1 -> requireContext().getString(R.string.hardware_lock)
+            else -> requireContext().getString(R.string.hardware_unknown)
+        }
+    }
+
+
     override fun initPresenter(): DeviceStatusPresenter {
         return DeviceStatusPresenter()
     }
@@ -207,6 +250,16 @@ class DeviceStatusFragment :
                                 holder?.setOnClickListener(R.id.iv_key_exception_1) {
                                     presenter?.exceptionHint(cabinetSlotsRecord.remark ?: "")
                                 }
+                                holder?.setOnLongClickListener(R.id.iv_key_exception_1) {
+                                    presenter?.slotType?.find { it.dictLabel == "钥匙" }?.dictValue?.let {
+                                        presenter?.mExceptionRecovery?.invoke(
+                                            (row.row + 1),
+                                            1,
+                                            it.toInt()
+                                        )
+                                    }
+                                    true
+                                }
                             }
                         }
 
@@ -220,6 +273,16 @@ class DeviceStatusFragment :
                                 holder?.setOnClickListener(R.id.iv_key_exception_2) {
                                     presenter?.exceptionHint(cabinetSlotsRecord.remark ?: "")
                                 }
+                                holder?.setOnLongClickListener(R.id.iv_key_exception_2) {
+                                    presenter?.slotType?.find { it.dictLabel == "钥匙" }?.dictValue?.let {
+                                        presenter?.mExceptionRecovery?.invoke(
+                                            (row.row + 1),
+                                            2,
+                                            it.toInt()
+                                        )
+                                    }
+                                    true
+                                }
                             }
                         }
 
@@ -233,6 +296,16 @@ class DeviceStatusFragment :
                                 holder?.setOnClickListener(R.id.iv_key_exception_3) {
                                     presenter?.exceptionHint(cabinetSlotsRecord.remark ?: "")
                                 }
+                                holder?.setOnLongClickListener(R.id.iv_key_exception_3) {
+                                    presenter?.slotType?.find { it.dictLabel == "钥匙" }?.dictValue?.let {
+                                        presenter?.mExceptionRecovery?.invoke(
+                                            (row.row + 1),
+                                            3,
+                                            it.toInt()
+                                        )
+                                    }
+                                    true
+                                }
                             }
                         }
 
@@ -246,6 +319,16 @@ class DeviceStatusFragment :
                                 holder?.setOnClickListener(R.id.iv_key_exception_4) {
                                     presenter?.exceptionHint(cabinetSlotsRecord.remark ?: "")
                                 }
+                                holder?.setOnLongClickListener(R.id.iv_key_exception_4) {
+                                    presenter?.slotType?.find { it.dictLabel == "钥匙" }?.dictValue?.let {
+                                        presenter?.mExceptionRecovery?.invoke(
+                                            (row.row + 1),
+                                            4,
+                                            it.toInt()
+                                        )
+                                    }
+                                    true
+                                }
                             }
                         }
                     }
@@ -352,6 +435,16 @@ class DeviceStatusFragment :
                                 holder?.setOnClickListener(R.id.iv_lock_exception) {
                                     presenter?.exceptionHint(cabinetSlotsRecord.remark ?: "")
                                 }
+                                holder?.setOnLongClickListener(R.id.iv_lock_exception) {
+                                    presenter?.slotType?.find { it.dictLabel == "钥匙" }?.dictValue?.let {
+                                        presenter?.mExceptionRecovery?.invoke(
+                                            row.row,
+                                            (lockIdx + 1),
+                                            it.toInt()
+                                        )
+                                    }
+                                    true
+                                }
                             }
                         }
                 }

+ 3 - 7
app/src/main/java/com/grkj/iscs/view/presenter/DeviceStatusPresenter.kt

@@ -30,6 +30,7 @@ class DeviceStatusPresenter : BasePresenter<IDeviceStatusView>() {
     var mCabinetSlotsData: List<CabinetSlotsRecord> = listOf()
     var mExceptionIcon: Bitmap? = null
     var mExceptionHintTip: ((String) -> Unit)? = null
+    var mExceptionRecovery: ((row: Int, col: Int, slotType: Int) -> Unit)? = null
     var mExceptionReporter: ((row: Int, col: Int, slotType: Int) -> Unit)? =
         null
     var slotType: MutableList<CommonDictRespVO>? = null
@@ -196,7 +197,7 @@ class DeviceStatusPresenter : BasePresenter<IDeviceStatusView>() {
         col: Int,
         slotStatus: Int,
         exceptionReason: String,
-        done: () -> Unit
+        done: (Boolean) -> Unit
     ) {
         NetApi.updateHardwareEsStatus(
             slotsExDTOList = mutableListOf(
@@ -208,12 +209,7 @@ class DeviceStatusPresenter : BasePresenter<IDeviceStatusView>() {
                 )
             )
         ) {
-            if (it) {
-                ToastUtils.tip(R.string.report_success)
-                done()
-            } else {
-                ToastUtils.tip(R.string.report_failed)
-            }
+            done(it)
         }
     }
 

+ 3 - 0
app/src/main/res/values-en/strings.xml

@@ -347,4 +347,7 @@
     <string name="number">Number: </string>
     <string name="report_success">exception report success</string>
     <string name="report_failed">exception report failed</string>
+    <string name="is_device_recovery_check">Is device recovery check(%1$s,%2$s)?</string>
+    <string name="recovery_success">recovery success</string>
+    <string name="recovery_failed">recovery failed</string>
 </resources>

+ 3 - 0
app/src/main/res/values-zh/strings.xml

@@ -347,4 +347,7 @@
     <string name="number">编号: </string>
     <string name="report_success">异常上报成功</string>
     <string name="report_failed">异常上报失败</string>
+    <string name="is_device_recovery_check">是否确认恢复设备(%1$s,%2$s)</string>
+    <string name="recovery_success">恢复成功</string>
+    <string name="recovery_failed">恢复失败</string>
 </resources>

+ 3 - 0
app/src/main/res/values/strings.xml

@@ -347,4 +347,7 @@
     <string name="number">编号: </string>
     <string name="report_success">异常上报成功</string>
     <string name="report_failed">异常上报失败</string>
+    <string name="is_device_recovery_check">是否确认恢复设备(%1$s,%2$s)</string>
+    <string name="recovery_success">恢复成功</string>
+    <string name="recovery_failed">恢复失败</string>
 </resources>