Bläddra i källkod

refactor(优化):
- 锁仓状态不持久化获取

周文健 6 månader sedan
förälder
incheckning
318f302f06

+ 11 - 152
app/src/main/java/com/grkj/iscs/BusinessManager.kt

@@ -68,6 +68,7 @@ import com.grkj.iscs.util.log.LogUtil
 import com.grkj.iscs.view.activity.LoginActivity
 import com.grkj.iscs.view.base.BaseActivity
 import com.grkj.iscs.view.dialog.TipDialog
+import com.sik.sikcore.activity.ActivityTracker
 import pub.devrel.easypermissions.AfterPermissionGranted
 
 /**
@@ -247,157 +248,8 @@ object BusinessManager {
      * 总的监听,做预处理,其余的所有监听均使用本监听处理后的数据,只允许调用一次
      */
     fun registerMainListener() {
-        ModBusController.registerStatusListener(this) { mbFrame, res ->
-            when (mbFrame) {
-                MBFrame.READ_STATUS -> {
-                    deviceStatusHandle(res)
-                }
-
-                MBFrame.READ_BUCKLE_STATUS -> {
-                    lockBuckleStatus(res)
-                }
-
-                MBFrame.READ_LOCK_BUCKLE_EXTRA_STATUS -> {
-                    lockBuckleExtraStatus(res)
-                }
-            }
-        }
-    }
-
-    /**
-     * 第9,10锁位卡扣状态
-     */
-    private fun lockBuckleExtraStatus(res: Any) {
-        LogUtil.i("硬件状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
-        if (res.isEmpty() || res.any { it.isEmpty() }) {
-            var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : "
-            val addressList = mutableListOf<String>()
-
-            ModBusController.modBusManager?.mSlaveAddressList?.forEach { itDock ->
-                if (res.none { it.isNotEmpty() && it[0] == itDock }) {
-                    addressList.add("0x${String.format("%02X", itDock)}")
-                }
-            }
-            tipStr += addressList
-            ToastUtils.tip(tipStr)
-        }
-        res.forEach { bytes ->
-            val dockBean = ModBusController.updateExtraLockStatus(bytes) ?: return@forEach
-            ModBusController.isInitReady = true
-            if (!CAN_RETURN) {
-                return@forEach
-            }
-            when (dockBean.type) {
-                DOCK_TYPE_LOCK -> {
-                    dockBean.getLockList().filter { it.idx > 7 }.forEach { lockBean ->
-                        ModBusController.updateLockStatus(
-                            dockBean.addr,
-                            lockBean.idx,
-                            lockBean.lockEnabled
-                        )
-                    }
-                }
-            }
-            Executor.delayOnMain(200) {
-                listeners.forEach { it.callBack(dockBean) }
-            }
-        }
-    }
-
-    /**
-     * 第1-8锁位卡扣状态和钥匙
-     */
-    private fun lockBuckleStatus(res: Any) {
-        LogUtil.i("硬件状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
-        if (res.isEmpty() || res.any { it.isEmpty() }) {
-            var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : "
-            val addressList = mutableListOf<String>()
-
-            ModBusController.modBusManager?.mSlaveAddressList?.forEach { itDock ->
-                if (res.none { it.isNotEmpty() && it[0] == itDock }) {
-                    addressList.add("0x${String.format("%02X", itDock)}")
-                }
-            }
-            tipStr += addressList
-            ToastUtils.tip(tipStr)
-        }
-
-        res.forEach { bytes ->
-            val dockBean = ModBusController.updateLockStatus(bytes) ?: return@forEach
-            ModBusController.isInitReady = true
-            if (!CAN_RETURN) {
-                return@forEach
-            }
-            when (dockBean.type) {
-                DOCK_TYPE_KEY -> {
-                    dockBean.getKeyList().forEach { keyBean ->
-                        ModBusController.updateKeyLockStatus(
-                            dockBean.addr,
-                            keyBean.isLeft,
-                            keyBean.lockEnabled
-                        )
-                        //todo 更新锁仓状态
-                    }
-                }
-
-                DOCK_TYPE_LOCK -> {
-                    dockBean.getLockList().forEach { lockBean ->
-                        ModBusController.updateLockStatus(
-                            dockBean.addr,
-                            lockBean.idx,
-                            lockBean.lockEnabled
-                        )
-                    }
-                }
-
-                DOCK_TYPE_ELEC_LOCK_BOARD -> {
-                    // TODO 占位
-                }
-
-                DOCK_TYPE_PORTABLE -> {
-                    // TODO 便携式待完善
-                    dockBean.deviceList.forEach { deviceBean ->
-                        if (deviceBean.isExist) {
-                            when (deviceBean.type) {
-                                DEVICE_TYPE_KEY -> {
-                                    ModBusController.updateKeyLockStatus(
-                                        dockBean.addr,
-                                        true,
-                                        deviceBean.lockEnabled
-                                    )
-                                }
-
-                                DEVICE_TYPE_LOCK -> {
-                                    ModBusController.updateLockStatus(
-                                        dockBean.addr,
-                                        deviceBean.idx,
-                                        deviceBean.lockEnabled
-                                    )
-                                }
-
-                                DEVICE_TYPE_CARD -> {
-                                    ModBusController.readPortalCaseCardRfid(dockBean.addr) { res ->
-                                        if (res.size < 11) {
-                                            LogUtil.e("Portal Case card rfid error")
-                                            return@readPortalCaseCardRfid
-                                        }
-                                        val rfid = res.copyOfRange(3, 11).toHexStrings(false)
-                                            .removeLeadingZeros()
-                                        LogUtil.i("卡片RFID : $rfid")
-                                    }
-                                }
-
-                                DEVICE_TYPE_FINGERPRINT -> {
-
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            Executor.delayOnMain(200) {
-                listeners.forEach { it.callBack(dockBean) }
-            }
+        ModBusController.registerStatusListener(this) { res ->
+            deviceStatusHandle(res)
         }
     }
 
@@ -631,6 +483,13 @@ object BusinessManager {
         }
     }
 
+    /**
+     * 更新所有锁仓状态
+     */
+    fun updateAllBuckleStatus(done: () -> Unit){
+        ModBusController.updateAllBuckleStatus(done)
+    }
+
     /**
      * 钥匙归还提示确认弹框,当前策略:作业票未完成禁止归还钥匙
      */
@@ -830,7 +689,7 @@ object BusinessManager {
         }
         isPreparing = true
         val listener = connectListeners[0]
-        if (ActivityUtils.currentActivity() == null) {
+        if (ActivityTracker.getCurrentActivity() == null) {
             LogUtil.w("Ignore connectKey : ${listener.mac} no current activity")
             isPreparing = false
             return

+ 76 - 42
app/src/main/java/com/grkj/iscs/modbus/DockBean.kt

@@ -4,6 +4,8 @@ import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_CARD
 import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_FINGERPRINT
 import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_KEY
 import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_LOCK
+import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_SWITCH
+import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_COLLECT
 import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD
 import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_KEY
 import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_LOCK
@@ -20,6 +22,7 @@ import com.grkj.iscs.util.log.LogUtil
 class DockBean(
     var addr: Byte,
     var type: Byte?,
+    var isWorking: Boolean = true,
     var deviceList: MutableList<DeviceBean>
 ) {
     /**
@@ -41,24 +44,12 @@ class DockBean(
                     if (getKeyList().isEmpty()) {
                         deviceList.add(
                             KeyBean(
-                                0,
-                                leftHasKey,
-                                true,
-                                isLeftCharging,
-                                false,
-                                null,
-                                null
+                                0, leftHasKey, true, isLeftCharging, false, null, null
                             )
                         )
                         deviceList.add(
                             KeyBean(
-                                1,
-                                rightHasKey,
-                                false,
-                                isRightCharging,
-                                false,
-                                null,
-                                null
+                                1, rightHasKey, false, isRightCharging, false, null, null
                             )
                         )
                         return null
@@ -98,7 +89,7 @@ class DockBean(
                         }
                     }
 
-                    return DockBean(addr, it, changeList)
+                    return DockBean(addr, it, true, changeList)
                 }
 
                 DOCK_TYPE_LOCK -> {
@@ -130,7 +121,7 @@ class DockBean(
                     }
 
                     LogUtil.i("锁具刷新状态 : $changeList")
-                    return DockBean(addr, it, changeList)
+                    return DockBean(addr, it, true, changeList)
                 }
 
                 DOCK_TYPE_ELEC_LOCK_BOARD -> {
@@ -156,13 +147,7 @@ class DockBean(
                     if (getKeyList().isEmpty()) {
                         deviceList.add(
                             KeyBean(
-                                4,
-                                isKeyExist,
-                                true,
-                                isKeyCharging,
-                                false,
-                                null,
-                                null
+                                4, isKeyExist, true, isKeyCharging, false, null, null
                             )
                         )
                     }
@@ -215,7 +200,13 @@ class DockBean(
                         changeList.add(getFingerPrintList()[0])
                     }
                     LogUtil.i("便携式刷新状态 : $changeList")
-                    return DockBean(addr, it, changeList)
+                    return DockBean(addr, it, true, changeList)
+                }
+
+                DOCK_TYPE_COLLECT -> {
+                    val working = (byteArray[4].toInt() shr 0) and 0x1 == 1
+                    LogUtil.i("开关量采集板是否工作 : $working")
+                    return DockBean(addr, it, working, mutableListOf())
                 }
 
                 else -> return null
@@ -249,7 +240,7 @@ class DockBean(
                         }
                     }
 
-                    return DockBean(addr, it, changeList)
+                    return DockBean(addr, it, true, changeList)
                 }
 
                 DOCK_TYPE_LOCK -> {
@@ -268,12 +259,28 @@ class DockBean(
                     }
 
                     LogUtil.i("锁具刷新状态 : $changeList")
-                    return DockBean(addr, it, changeList)
+                    return DockBean(addr, it, true, changeList)
                 }
 
                 DOCK_TYPE_ELEC_LOCK_BOARD -> {
-                    // TODO 临时占位
-                    return null
+                    val tempList = mutableListOf<Boolean>()
+                    for (i in 0..2) {
+                        tempList.add((byteArray[4].toInt() shr i) and 0x1 == 1)
+                    }
+                    if (getLockList().isEmpty()) {
+                        for (i in 0 until tempList.size) {
+                            deviceList.add(LockBean(i, tempList[i], tempList[i], null))
+                        }
+                        return null
+                    }
+
+                    val changeList = mutableListOf<DeviceBean>()
+                    for (i in 0 until getLockList().size) {
+                        getLockList()[i].lockEnabled = tempList[i]
+                    }
+
+                    LogUtil.i("电磁锁具刷新状态 : $changeList")
+                    return DockBean(addr, it, true, changeList)
                 }
 
                 DOCK_TYPE_PORTABLE -> {
@@ -294,7 +301,19 @@ class DockBean(
                         getKeyList()[0].lockEnabled = keyLockEnabled
                     }
                     LogUtil.i("便携式刷新状态 : $changeList")
-                    return DockBean(addr, it, changeList)
+                    return DockBean(addr, it, true, changeList)
+                }
+
+                DOCK_TYPE_COLLECT -> {
+                    for (i in 0..7) {
+                        if ((byteArray[4].toInt() shr i) and 0x1 == 1) {
+                            val switchBoardAddr = (0x20 + i).toByte()
+                            ModBusController.readSwitchStatus(addr, switchBoardAddr) { res ->
+                                //todo 开关量新增
+                            }
+                        }
+                    }
+                    return DockBean(addr, type, isWorking, deviceList)
                 }
 
                 else -> return null
@@ -327,7 +346,7 @@ class DockBean(
                     }
 
                     LogUtil.i("锁具刷新状态 : $changeList")
-                    return DockBean(addr, it, changeList)
+                    return DockBean(addr, it, true, changeList)
                 }
 
                 else -> return null
@@ -335,41 +354,48 @@ class DockBean(
         } ?: return null
     }
 
+    /**
+     * 获取钥匙列表
+     */
     fun getKeyList(): MutableList<KeyBean> {
         return deviceList.filterIsInstance<KeyBean>().filter { it.type == DEVICE_TYPE_KEY }
             .toMutableList()
     }
 
+    /**
+     * 获取锁列表
+     */
     fun getLockList(): MutableList<LockBean> {
         return deviceList.filterIsInstance<LockBean>().filter { it.type == DEVICE_TYPE_LOCK }
             .toMutableList()
     }
 
+    /**
+     * 获取工卡列表
+     */
     fun getCardList(): MutableList<CardBean> {
         return deviceList.filterIsInstance<CardBean>().filter { it.type == DEVICE_TYPE_CARD }
             .toMutableList()
     }
 
+    /**
+     * 获取指纹列表
+     */
     fun getFingerPrintList(): MutableList<FingerPrintBean> {
         return deviceList.filterIsInstance<FingerPrintBean>()
             .filter { it.type == DEVICE_TYPE_FINGERPRINT }.toMutableList()
     }
 
-    fun getBit(by: Byte): String {
-        val sb = StringBuffer()
-        sb.append((by.toInt() shr 7) and 0x1)
-            .append((by.toInt() shr 6) and 0x1)
-            .append((by.toInt() shr 5) and 0x1)
-            .append((by.toInt() shr 4) and 0x1)
-            .append((by.toInt() shr 3) and 0x1)
-            .append((by.toInt() shr 2) and 0x1)
-            .append((by.toInt() shr 1) and 0x1)
-            .append((by.toInt() shr 0) and 0x1)
-        return sb.toString()
+    /**
+     * 获取开关列表
+     */
+    fun getSwitchList(): MutableList<SwitchBean> {
+        return deviceList.filterIsInstance<SwitchBean>().filter { it.type == DEVICE_TYPE_SWITCH }
+            .toMutableList()
     }
 
     override fun toString(): String {
-        return "DockBean(addr=$addr, type=$type, deviceList=$deviceList)"
+        return "DockBean(addr=$addr, type=$type, isWorking=$isWorking, deviceList=$deviceList)"
     }
 
 
@@ -451,4 +477,12 @@ class DockBean(
         isExist: Boolean,
         lockEnabled: Boolean = false,
     ) : DeviceBean(DEVICE_TYPE_FINGERPRINT, idx, isExist, lockEnabled)
+
+    /**
+     * 开关
+     */
+    class SwitchBean(
+        idx: Int,
+        isExist: Boolean,
+    ) : DeviceBean(DEVICE_TYPE_SWITCH, idx, isExist)
 }

+ 9 - 1
app/src/main/java/com/grkj/iscs/modbus/MBFrame.kt

@@ -61,7 +61,7 @@ class MBFrame(
         )
 
         /**
-         * 读钥匙/锁具/便携式底座状态
+         * 读钥匙/锁具/便携式底座/开关量采集板状态
          */
         val READ_STATUS = MBFrame(
             FRAME_TYPE_READ,
@@ -83,5 +83,13 @@ class MBFrame(
             FRAME_TYPE_READ,
             byteArrayOf(0x00, 0x12, 0x00, 0x01)
         )
+
+        /**
+         * 读取电子锁控灯光状态
+         */
+        val READ_ELE_LOCK_LIGHT_STATUS = MBFrame(
+            FRAME_TYPE_READ,
+            byteArrayOf(0x00, 0x15, 0x00, 0x01)
+        )
     }
 }

+ 44 - 6
app/src/main/java/com/grkj/iscs/modbus/ModBusCMDHelper.kt

@@ -21,7 +21,8 @@ object ModBusCMDHelper {
         // 第三位是 是否响应,第四位是操作哪个,操作默认全是0或者1,使用第三位响应来进行操作
         return MBFrame(
             FRAME_TYPE_WRITE,
-            byteArrayOf(0x00,
+            byteArrayOf(
+                0x00,
                 if (lockIndex in 0..7) 0x11 else 0x12,
                 str.toInt(2).toByte(),
                 if (isOpen) 0x00 else 0xFF.toByte()
@@ -32,7 +33,10 @@ object ModBusCMDHelper {
     /**
      * 生成多个锁具卡扣开关指令(只能针对同一个底座,不能跨底座)
      */
-    fun generateLockBuckleCmd(isOpen: Boolean, lockIndexList: MutableList<Int>): MutableList<MBFrame> {
+    fun generateLockBuckleCmd(
+        isOpen: Boolean,
+        lockIndexList: MutableList<Int>
+    ): MutableList<MBFrame> {
         var str = ""
         val rstList = mutableListOf<MBFrame>()
         val smallIdxList = lockIndexList.filter { it in 0..7 }
@@ -45,7 +49,17 @@ object ModBusCMDHelper {
                     "0"
                 }
             }
-            rstList.add(MBFrame(FRAME_TYPE_WRITE, byteArrayOf(0x00, 0x11, str.toInt(2).toByte(), if (isOpen) 0x00 else 0xFF.toByte())))
+            rstList.add(
+                MBFrame(
+                    FRAME_TYPE_WRITE,
+                    byteArrayOf(
+                        0x00,
+                        0x11,
+                        str.toInt(2).toByte(),
+                        if (isOpen) 0x00 else 0xFF.toByte()
+                    )
+                )
+            )
         }
         if (bigIdxList.isNotEmpty()) {
             str = ""
@@ -56,13 +70,22 @@ object ModBusCMDHelper {
                     "0"
                 }
             }
-            rstList.add(MBFrame(FRAME_TYPE_WRITE, byteArrayOf(0x00, 0x12, str.toInt(2).toByte(), if (isOpen) 0x00 else 0xFF.toByte())))
+            rstList.add(
+                MBFrame(
+                    FRAME_TYPE_WRITE,
+                    byteArrayOf(
+                        0x00,
+                        0x12,
+                        str.toInt(2).toByte(),
+                        if (isOpen) 0x00 else 0xFF.toByte()
+                    )
+                )
+            )
         }
         return rstList
     }
 
 
-
     /**
      * 生成钥匙底座灯光指令
      *
@@ -86,7 +109,12 @@ object ModBusCMDHelper {
     fun generateKeyBuckleCmd(isOpen: Boolean, index: Int): MBFrame {
         return MBFrame(
             FRAME_TYPE_WRITE,
-            byteArrayOf(0x00, 0x11, if (index == 1) 0b00010000.toByte() else 0b0000001, if (isOpen) 0x00 else 0xFF.toByte())
+            byteArrayOf(
+                0x00,
+                0x11,
+                if (index == 1) 0b00010000.toByte() else 0b0000001,
+                if (isOpen) 0x00 else 0xFF.toByte()
+            )
         )
     }
 
@@ -101,4 +129,14 @@ object ModBusCMDHelper {
             byteArrayOf(0x00, (0x20 + idx * 4).toByte(), 0x00, 0x04)
         )
     }
+
+    /**
+     * 生成读取开关采集板的指令
+     */
+    fun generateSwitchBoardStatusCmd(addr: Byte): MBFrame {
+        return MBFrame(
+            FRAME_TYPE_READ,
+            byteArrayOf(0x00, addr, 0x00, 0x01)
+        )
+    }
 }

+ 181 - 27
app/src/main/java/com/grkj/iscs/modbus/ModBusController.kt

@@ -3,19 +3,25 @@ package com.grkj.iscs.modbus
 import android.content.Context
 import com.clj.fastble.BleManager
 import com.grkj.iscs.BusinessManager
+import com.grkj.iscs.BusinessManager.CAN_RETURN
 import com.grkj.iscs.R
 import com.grkj.iscs.extentions.removeLeadingZeros
 import com.grkj.iscs.extentions.toHexStrings
+import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_CARD
+import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_FINGERPRINT
 import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_KEY
 import com.grkj.iscs.model.DeviceConst.DEVICE_TYPE_LOCK
+import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_COLLECT
 import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD
 import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_KEY
 import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_LOCK
 import com.grkj.iscs.model.DeviceConst.DOCK_TYPE_PORTABLE
+import com.grkj.iscs.util.CommonUtils
 import com.grkj.iscs.util.Executor
 import com.grkj.iscs.util.NetApi
 import com.grkj.iscs.util.ToastUtils
 import com.grkj.iscs.util.log.LogUtil
+import java.util.concurrent.atomic.AtomicInteger
 import java.util.stream.Collectors
 
 
@@ -82,31 +88,7 @@ object ModBusController {
                 // 不再使用slaveCount,改用地址池
                 for (l in listeners) {
                     if (l.type == LISTENER_TYPE_STATUS) {
-                        l.listener(MBFrame.READ_STATUS, res)
-                    }
-                }
-            }, REPEAT_FREQUENCY)
-            ?.repeatSendToAll(MBFrame.READ_BUCKLE_STATUS, {
-                interruptReadStatus
-            }, { res ->
-                LogUtil.i("****************************************************************************")
-                // 过滤非空的数据,重置slaveCount
-                // 不再使用slaveCount,改用地址池
-                for (l in listeners) {
-                    if (l.type == LISTENER_TYPE_STATUS) {
-                        l.listener(MBFrame.READ_BUCKLE_STATUS, res)
-                    }
-                }
-            }, REPEAT_FREQUENCY)
-            ?.repeatSendToAll(MBFrame.READ_LOCK_BUCKLE_EXTRA_STATUS, {
-                interruptReadStatus
-            }, { res ->
-                LogUtil.i("****************************************************************************")
-                // 过滤非空的数据,重置slaveCount
-                // 不再使用slaveCount,改用地址池
-                for (l in listeners) {
-                    if (l.type == LISTENER_TYPE_STATUS) {
-                        l.listener(MBFrame.READ_LOCK_BUCKLE_EXTRA_STATUS, res)
+                        l.listener(res)
                     }
                 }
             }, REPEAT_FREQUENCY)
@@ -119,7 +101,7 @@ object ModBusController {
     /**
      * 注册监听器
      */
-    fun registerStatusListener(key: Any, listener: (MBFrame, Any) -> Unit) {
+    fun registerStatusListener(key: Any, listener: (Any) -> Unit) {
         listeners.add(StatusListener(key, listener, LISTENER_TYPE_STATUS))
     }
 
@@ -165,6 +147,7 @@ object ModBusController {
                     DOCK_TYPE_LOCK -> "锁具底座"
                     DOCK_TYPE_ELEC_LOCK_BOARD -> "电磁锁控制板"
                     DOCK_TYPE_PORTABLE -> "便携式底座"
+                    DOCK_TYPE_COLLECT -> "开关量采集板"
                     else -> "未知"
                 }
                 LogUtil.i("initDevicesStatus 设备(${bytes[0].toInt()})类型:$type")
@@ -270,6 +253,162 @@ object ModBusController {
         return dockB?.parseStatus(byteArray)
     }
 
+    /**
+     * 更新所有锁仓状态
+     */
+    fun updateAllBuckleStatus(done: () -> Unit) {
+        val remaining = AtomicInteger(2)
+        modBusManager?.sendToAll(MBFrame.READ_BUCKLE_STATUS) { res ->
+            LogUtil.i("****************************************************************************")
+            // 过滤非空的数据,重置slaveCount
+            // 不再使用slaveCount,改用地址池
+            lockBuckleStatus(res)
+            // 每完成一个就把计数减一,减到 0 就触发 done()
+            if (remaining.decrementAndGet() == 0) {
+                done()
+            }
+        }
+        modBusManager?.sendToAll(MBFrame.READ_LOCK_BUCKLE_EXTRA_STATUS) { res ->
+            LogUtil.i("****************************************************************************")
+            // 过滤非空的数据,重置slaveCount
+            // 不再使用slaveCount,改用地址池
+            lockBuckleExtraStatus(res)
+            // 每完成一个就把计数减一,减到 0 就触发 done()
+            if (remaining.decrementAndGet() == 0) {
+                done()
+            }
+        }
+    }
+
+    /**
+     * 第9,10锁位卡扣状态
+     */
+    private fun lockBuckleExtraStatus(res: Any) {
+        LogUtil.i("硬件状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
+        if (res.isEmpty() || res.any { it.isEmpty() }) {
+            var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : "
+            val addressList = mutableListOf<String>()
+
+            modBusManager?.mSlaveAddressList?.forEach { itDock ->
+                if (res.none { it.isNotEmpty() && it[0] == itDock }) {
+                    addressList.add("0x${String.format("%02X", itDock)}")
+                }
+            }
+            tipStr += addressList
+            ToastUtils.tip(tipStr)
+        }
+        res.forEach { bytes ->
+            val dockBean = updateExtraLockStatus(bytes) ?: return@forEach
+            if (!CAN_RETURN) {
+                return@forEach
+            }
+            when (dockBean.type) {
+                DOCK_TYPE_LOCK -> {
+                    dockBean.getLockList().filter { it.idx > 7 }.forEach { lockBean ->
+                        updateLockStatus(
+                            dockBean.addr,
+                            lockBean.idx,
+                            lockBean.lockEnabled
+                        )
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 第1-8锁位卡扣状态和钥匙
+     */
+    private fun lockBuckleStatus(res: Any) {
+        LogUtil.i("硬件状态:${(res as List<ByteArray>).map { it.toHexStrings() }}")
+        if (res.isEmpty() || res.any { it.isEmpty() }) {
+            var tipStr = CommonUtils.getStr(R.string.no_response_board_exists) + " : "
+            val addressList = mutableListOf<String>()
+
+            modBusManager?.mSlaveAddressList?.forEach { itDock ->
+                if (res.none { it.isNotEmpty() && it[0] == itDock }) {
+                    addressList.add("0x${String.format("%02X", itDock)}")
+                }
+            }
+            tipStr += addressList
+            ToastUtils.tip(tipStr)
+        }
+
+        res.forEach { bytes ->
+            val dockBean = updateLockStatus(bytes) ?: return@forEach
+            if (!CAN_RETURN) {
+                return@forEach
+            }
+            when (dockBean.type) {
+                DOCK_TYPE_KEY -> {
+                    dockBean.getKeyList().forEach { keyBean ->
+                        updateKeyLockStatus(
+                            dockBean.addr,
+                            keyBean.isLeft,
+                            keyBean.lockEnabled
+                        )
+                        //todo 更新锁仓状态
+                    }
+                }
+
+                DOCK_TYPE_LOCK -> {
+                    dockBean.getLockList().forEach { lockBean ->
+                        updateLockStatus(
+                            dockBean.addr,
+                            lockBean.idx,
+                            lockBean.lockEnabled
+                        )
+                    }
+                }
+
+                DOCK_TYPE_ELEC_LOCK_BOARD -> {
+                    // TODO 占位
+                }
+
+                DOCK_TYPE_PORTABLE -> {
+                    // TODO 便携式待完善
+                    dockBean.deviceList.forEach { deviceBean ->
+                        if (deviceBean.isExist) {
+                            when (deviceBean.type) {
+                                DEVICE_TYPE_KEY -> {
+                                    updateKeyLockStatus(
+                                        dockBean.addr,
+                                        true,
+                                        deviceBean.lockEnabled
+                                    )
+                                }
+
+                                DEVICE_TYPE_LOCK -> {
+                                    updateLockStatus(
+                                        dockBean.addr,
+                                        deviceBean.idx,
+                                        deviceBean.lockEnabled
+                                    )
+                                }
+
+                                DEVICE_TYPE_CARD -> {
+                                    readPortalCaseCardRfid(dockBean.addr) { res ->
+                                        if (res.size < 11) {
+                                            LogUtil.e("Portal Case card rfid error")
+                                            return@readPortalCaseCardRfid
+                                        }
+                                        val rfid = res.copyOfRange(3, 11).toHexStrings(false)
+                                            .removeLeadingZeros()
+                                        LogUtil.i("卡片RFID : $rfid")
+                                    }
+                                }
+
+                                DEVICE_TYPE_FINGERPRINT -> {
+
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * 获取第1-8的锁仓数据和左右钥匙数据
      */
@@ -309,7 +448,7 @@ object ModBusController {
         dock?.let {
             it.type = type
         } ?: let {
-            dockList.add(DockBean(idx, type, mutableListOf()))
+            dockList.add(DockBean(idx, type, true, mutableListOf()))
         }
     }
 
@@ -780,4 +919,19 @@ object ModBusController {
         }
         return map
     }
+
+    /**
+     * 读取开关采集板数据
+     */
+    fun readSwitchStatus(
+        slaveAddress: Byte?, idx: Byte, done: ((res: ByteArray) -> Unit)? = null
+    ) {
+        slaveAddress?.let {
+            ModBusCMDHelper.generateSwitchBoardStatusCmd(idx)?.let { cmd ->
+                modBusManager?.sendTo(it, cmd) { res ->
+                    done?.invoke(res)
+                }
+            }
+        }
+    }
 }

+ 1 - 1
app/src/main/java/com/grkj/iscs/modbus/StatusListener.kt

@@ -5,6 +5,6 @@ package com.grkj.iscs.modbus
  */
 class StatusListener(
     val key: Any,
-    val listener: (MBFrame, Any) -> Unit,
+    val listener: (Any) -> Unit,
     val type: Int
 )

+ 1 - 0
app/src/main/java/com/grkj/iscs/model/DeviceConst.kt

@@ -17,4 +17,5 @@ object DeviceConst {
     const val DEVICE_TYPE_CARD = 2          // 卡
     const val DEVICE_TYPE_FINGERPRINT = 3   // 指纹
     const val DEVICE_TYPE_PORTAL_CASE = 4   // 便携柜
+    const val DEVICE_TYPE_SWITCH = 5        // 开关
 }

+ 5 - 0
app/src/main/java/com/grkj/iscs/model/UrlConsts.kt

@@ -281,4 +281,9 @@ object UrlConsts {
      * 批量更新硬件状态
      */
     const val UPDATE_HARDWARE_ES_STATUS = "/iscs/hardware-api/updateHardwareEsStatus"
+
+    /**
+     * 重合点位数据解锁
+     */
+    const val UPDATE_COINCIDE_TO_UNLOCK = "/iscs/hardware-api/updateCoincideToUnLock"
 }

+ 153 - 33
app/src/main/java/com/grkj/iscs/util/NetApi.kt

@@ -63,7 +63,8 @@ object NetApi {
                 } ?: run {
                     callBack.invoke(false)
                 }
-            }, isGet = false, isAuth = false)
+            }, isGet = false, isAuth = false
+        )
     }
 
     /**
@@ -99,13 +100,20 @@ object NetApi {
                 } ?: run {
                     callBack.invoke(false)
                 }
-            }, isGet = false, isAuth = false)
+            }, isGet = false, isAuth = false
+        )
     }
 
     /**
      * 获取SOP分页
      */
-    fun getSopPage(pages: Int, size: Int, machineryId: Long, sopType: Int, callBack: (SopPageRespVO?) -> Unit) {
+    fun getSopPage(
+        pages: Int,
+        size: Int,
+        machineryId: Long,
+        sopType: Int,
+        callBack: (SopPageRespVO?) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.SOP_PAGE,
             false,
@@ -119,7 +127,8 @@ object NetApi {
                 res?.let {
                     callBack.invoke(getRefBean(it))
                 }
-            }, isGet = true, isAuth = true)
+            }, isGet = true, isAuth = true
+        )
     }
 
     /**
@@ -130,12 +139,13 @@ object NetApi {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.TICKET_TYPE,
             false,
-            mapOf<String,String>(),
+            mapOf<String, String>(),
             { res, _, _ ->
                 res?.let {
                     callBack.invoke(getRefBean(it))
                 }
-            }, isGet = true, isAuth = true)
+            }, isGet = true, isAuth = true
+        )
     }
 
     /**
@@ -144,14 +154,15 @@ object NetApi {
     @Deprecated("不使用")
     fun getAutoCode(type: String, callBack: (String?) -> Unit) {
         NetHttpManager.getInstance().doRequestNet(
-            UrlConsts.AUTO_CODE + "/" +type,
+            UrlConsts.AUTO_CODE + "/" + type,
             false,
             mapOf<String, String>(),
             { res, _, _ ->
                 res?.let {
                     callBack.invoke(it.toString())
                 }
-            }, isGet = true, isAuth = true)
+            }, isGet = true, isAuth = true
+        )
     }
 
     /**
@@ -169,7 +180,8 @@ object NetApi {
                 res?.let {
                     callBack.invoke(getRefBean(it))
                 }
-            }, isGet = true, isAuth = true)
+            }, isGet = true, isAuth = true
+        )
     }
 
     /**
@@ -186,7 +198,8 @@ object NetApi {
         unitId: Long? = null,
         callBack: (UserListRespVO?) -> Unit
     ) {
-        val map: MutableMap<String, Any> = mutableMapOf("pageNum" to pageNum, "pageSize" to pageSize)
+        val map: MutableMap<String, Any> =
+            mutableMapOf("pageNum" to pageNum, "pageSize" to pageSize)
         workstationId?.let {
             map["workstationId"] = it
         }
@@ -204,7 +217,8 @@ object NetApi {
                 res?.let {
                     callBack.invoke(it.toBean(UserListRespVO::class.java))
                 }
-            }, isGet = true, isAuth = true)
+            }, isGet = true, isAuth = true
+        )
     }
 
     /**
@@ -251,7 +265,13 @@ object NetApi {
      * 获取工作票分页
      */
     @Deprecated("不使用")
-    fun getTicketPage(pageNum: Int, pageSize: Int, userId: Long, ticketStatus: Int?, callBack: (TicketPageRespVO?) -> Unit) {
+    fun getTicketPage(
+        pageNum: Int,
+        pageSize: Int,
+        userId: Long,
+        ticketStatus: Int?,
+        callBack: (TicketPageRespVO?) -> Unit
+    ) {
         val map = mutableMapOf(
             "pageNum" to pageNum,
             "pageSize" to pageSize,
@@ -304,7 +324,7 @@ object NetApi {
                 }
             }, isGet = true, isAuth = true
         )
-   }
+    }
 
     /**
      * 通过nfc编号获取key信息
@@ -390,7 +410,12 @@ object NetApi {
     /**
      * 挂锁上锁时更新数据,更新挂锁和哪个隔离点进行了绑定
      */
-    fun updateLockPoint(ticketId: Long, lockNfc: String, pointNfc: String, callBack: (Boolean?) -> Unit) {
+    fun updateLockPoint(
+        ticketId: Long,
+        lockNfc: String,
+        pointNfc: String,
+        callBack: (Boolean?) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.LOCK_POINT_UPDATE,
             false,
@@ -426,7 +451,12 @@ object NetApi {
     /**
      * 取出钥匙
      */
-    fun updateKeyTake(ticketId: Long, keyNfc: String, serialNumber: String, callBack: (Boolean) -> Unit) {
+    fun updateKeyTake(
+        ticketId: Long,
+        keyNfc: String,
+        serialNumber: String,
+        callBack: (Boolean) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.KEY_TAKE_UPDATE,
             false,
@@ -444,7 +474,13 @@ object NetApi {
     /**
      * 归还钥匙
      */
-    fun updateKeyReturn(ticketId: Long, keyNfc: String, serialNumber: String, retryCount: Int = 3, callBack: (Boolean) -> Unit) {
+    fun updateKeyReturn(
+        ticketId: Long,
+        keyNfc: String,
+        serialNumber: String,
+        retryCount: Int = 3,
+        callBack: (Boolean) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.KEY_RETURN_UPDATE,
             false,
@@ -459,7 +495,13 @@ object NetApi {
                 } ?: let {
                     if (retryCount > 0) {
                         Executor.delayOnIO(500) {
-                            updateKeyReturn(ticketId, keyNfc, serialNumber, retryCount - 1, callBack)
+                            updateKeyReturn(
+                                ticketId,
+                                keyNfc,
+                                serialNumber,
+                                retryCount - 1,
+                                callBack
+                            )
                         }
                     } else {
                         callBack.invoke(false)
@@ -490,7 +532,11 @@ object NetApi {
     /**
      * 批量更新作业票下隔离点的上锁解锁状况
      */
-    fun updateLockPointBatch(list: MutableList<LockPointUpdateReqVO>, retryCount: Int = 3, callBack: (Boolean) -> Unit) {
+    fun updateLockPointBatch(
+        list: MutableList<LockPointUpdateReqVO>,
+        retryCount: Int = 3,
+        callBack: (Boolean) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.LOCK_POINT_UPDATE_BATCH,
             false,
@@ -517,7 +563,12 @@ object NetApi {
      * 根据角色获取人员列表
      */
     @Deprecated("不使用")
-    fun getRoleList(pageNum: Int, pageSize: Int, roleKey: String, callBack: (RoleListRespVO?) -> Unit) {
+    fun getRoleList(
+        pageNum: Int,
+        pageSize: Int,
+        roleKey: String,
+        callBack: (RoleListRespVO?) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.ROLE_LIST,
             false,
@@ -537,7 +588,11 @@ object NetApi {
     /**
      * 正在进行中的作业票列表
      */
-    fun getWorkstationTicketList(pages: Int, size: Int, callBack: (MutableList<WorkstationTicketListRespVO>?) -> Unit) {
+    fun getWorkstationTicketList(
+        pages: Int,
+        size: Int,
+        callBack: (MutableList<WorkstationTicketListRespVO>?) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.WORKSTATION_TICKET_LIST,
             false,
@@ -556,7 +611,12 @@ object NetApi {
     /**
      * 获取工艺分页
      */
-    fun getMachineryPage(pages: Int, size: Int, workstationId: Long, callBack: (MachineryPageRespVO?) -> Unit) {
+    fun getMachineryPage(
+        pages: Int,
+        size: Int,
+        workstationId: Long,
+        callBack: (MachineryPageRespVO?) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.MACHINERY_PAGE,
             false,
@@ -626,7 +686,7 @@ object NetApi {
                 }
             }, isGet = true, isAuth = true
         )
-   }
+    }
 
     /**
      * 取消作业票
@@ -671,7 +731,11 @@ object NetApi {
     /**
      * 新增/更新作业票人员
      */
-    fun updateTicketUser(ticketId: Long, userList: MutableList<TicketUserReqVO>, callBack: (Boolean) -> Unit) {
+    fun updateTicketUser(
+        ticketId: Long,
+        userList: MutableList<TicketUserReqVO>,
+        callBack: (Boolean) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.UPDATE_TICKET_USER,
             false,
@@ -731,7 +795,12 @@ object NetApi {
     /**
      * 共锁人上锁/解锁
      */
-    fun updateColockerStatus(ticketId: Long, cardNfc: String, jobStatus: String, callBack: (Boolean) -> Unit) {
+    fun updateColockerStatus(
+        ticketId: Long,
+        cardNfc: String,
+        jobStatus: String,
+        callBack: (Boolean) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.UPDATE_COLOCKER_STATUS,
             false,
@@ -791,7 +860,12 @@ object NetApi {
      *
      * @param mapId 机柜固定传1,物资柜固定传4
      */
-    fun getMapPointPage(pages: Int, size: Int, mapId: Long, callBack: (MapPointPageRespVO?) -> Unit) {
+    fun getMapPointPage(
+        pages: Int,
+        size: Int,
+        mapId: Long,
+        callBack: (MapPointPageRespVO?) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.MAP_POINT_PAGE,
             false,
@@ -811,7 +885,11 @@ object NetApi {
     /**
      * 新增指纹录入-指纹图片转成dat存储
      */
-    fun insertFinger(userName: String, fileList: MutableList<FileStreamReqParam>?, callBack: (Boolean) -> Unit) {
+    fun insertFinger(
+        userName: String,
+        fileList: MutableList<FileStreamReqParam>?,
+        callBack: (Boolean) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.INSERT_FINGER,
             false,
@@ -838,14 +916,15 @@ object NetApi {
             mapOf<String, String>(),
             { res, _, _ ->
                 res?.let {
-                    val resp: LoginCharacteristicRespVO? = it.toBean(LoginCharacteristicRespVO::class.java)
+                    val resp: LoginCharacteristicRespVO? =
+                        it.toBean(LoginCharacteristicRespVO::class.java)
                     Token(resp?.token!!, 0).saveToSp(MyApplication.instance!!.applicationContext)
                     callBack.invoke(true)
                 } ?: run {
                     callBack.invoke(false)
                 }
             }, isGet = false, isAuth = false, fileList = fileList
-       )
+        )
     }
 
     /**
@@ -853,7 +932,13 @@ object NetApi {
      *
      * @param type 1-指纹,2-面部
      */
-    fun getUserCharacteristicPage(pages: Int, size: Int, type: String, userId: Long, callBack: (CharacteristicPageRespVO?) -> Unit) {
+    fun getUserCharacteristicPage(
+        pages: Int,
+        size: Int,
+        type: String,
+        userId: Long,
+        callBack: (CharacteristicPageRespVO?) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.USER_CHARACTERISTIC_PAGE,
             false,
@@ -911,7 +996,9 @@ object NetApi {
             "exceptionType" to exceptionType,
             "raiser" to raiser,
             "sourceName" to sourceName,
-            "raiseTime" to SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(Calendar.getInstance().time)
+            "raiseTime" to SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(
+                Calendar.getInstance().time
+            )
         )
         exceptionDescription?.let {
             map["exceptionDescription"] = it
@@ -976,7 +1063,8 @@ object NetApi {
             mapOf<String, String>(),
             { res, _, _ ->
                 res?.let {
-                    val resp: LoginCharacteristicRespVO? = it.toBean(LoginCharacteristicRespVO::class.java)
+                    val resp: LoginCharacteristicRespVO? =
+                        it.toBean(LoginCharacteristicRespVO::class.java)
                     Token(resp?.token!!, 0).saveToSp(MyApplication.instance!!.applicationContext)
                     callBack.invoke(true)
                 } ?: run {
@@ -989,7 +1077,11 @@ object NetApi {
     /**
      * 查询基础数据-分页
      */
-    fun getSystemAttributePage(pages: Int, size: Int, callBack: (SystemAttributePageRespVO?) -> Unit) {
+    fun getSystemAttributePage(
+        pages: Int,
+        size: Int,
+        callBack: (SystemAttributePageRespVO?) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.SYSTEM_ATTRIBUTE_PAGE,
             false,
@@ -1028,7 +1120,12 @@ object NetApi {
     /**
      * 批量更新硬件状态
      */
-    fun updateHardwareEsStatus(jobCardExDTOList:List<JobCardExDTO>,keyExDTOList:List<KeyExDTO>,lockExDTOList:List<LockExDTO>, callBack: (Boolean) -> Unit){
+    fun updateHardwareEsStatus(
+        jobCardExDTOList: List<JobCardExDTO>,
+        keyExDTOList: List<KeyExDTO>,
+        lockExDTOList: List<LockExDTO>,
+        callBack: (Boolean) -> Unit
+    ) {
         NetHttpManager.getInstance().doRequestNet(
             UrlConsts.UPDATE_HARDWARE_ES_STATUS,
             false,
@@ -1046,4 +1143,27 @@ object NetApi {
             }, isGet = false, isAuth = true
         )
     }
+
+    /**
+     * 重合点位数据解锁
+     */
+    fun updateCoincideToUnLock(
+        noUnlockTicketPointsVOSet: List<TicketDetailRespVO.JobTicketPointsVO>,
+        callBack: (Boolean) -> Unit
+    ) {
+        NetHttpManager.getInstance().doRequestNet(
+            UrlConsts.UPDATE_COINCIDE_TO_UNLOCK,
+            false,
+            mapOf(
+                "noUnlockTicketPointsVOSet" to noUnlockTicketPointsVOSet
+            ),
+            { res, _, _ ->
+                res?.let {
+                    callBack.invoke(true)
+                } ?: run {
+                    callBack.invoke(false)
+                }
+            }, isGet = false, isAuth = true
+        )
+    }
 }

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

@@ -5,6 +5,7 @@ import android.content.res.ColorStateList
 import android.view.View
 import androidx.core.content.ContextCompat
 import androidx.recyclerview.widget.RecyclerView
+import com.grkj.iscs.BusinessManager
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentDeviceStatusBinding
 import com.grkj.iscs.extentions.setSelected
@@ -12,14 +13,19 @@ 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.Executor
+import com.grkj.iscs.util.ToastUtils
 import com.grkj.iscs.view.base.BaseMvpFragment
 import com.grkj.iscs.view.fragment.DockTestFragment.DockTestBean
 import com.grkj.iscs.view.iview.IDeviceStatusView
 import com.grkj.iscs.view.presenter.DeviceStatusPresenter
+import com.sik.sikcore.thread.ThreadUtils
 import com.zhy.adapter.recyclerview.CommonAdapter
 import com.zhy.adapter.recyclerview.MultiItemTypeAdapter
 import com.zhy.adapter.recyclerview.base.ItemViewDelegate
 import com.zhy.adapter.recyclerview.base.ViewHolder
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.withContext
 
 /**
  * 硬件状态页
@@ -50,6 +56,17 @@ class DeviceStatusFragment :
     override fun onResume() {
         super.onResume()
         mBinding?.rvDock?.adapter?.notifyDataSetChanged()
+        fun refreshBuckleStatus() {
+            ThreadUtils.runOnIODelayed(1000) {
+                BusinessManager.updateAllBuckleStatus {
+                    ThreadUtils.runOnMain {
+                        mBinding?.rvDock?.adapter?.notifyDataSetChanged()
+                        refreshBuckleStatus()
+                    }
+                }
+            }
+        }
+        refreshBuckleStatus()
     }
 
     override fun initPresenter(): DeviceStatusPresenter {
@@ -155,6 +172,22 @@ class DeviceStatusFragment :
             holder?.setOnClickListener(R.id.tv_repair_4) {
                 presenter?.repairKey(row.dockList.find { it.column == "2" }?.address, false)
             }
+            holder?.setOnLongClickListener(R.id.iv_key_1) {
+                ToastUtils.tip("钥匙1上报异常")
+                true
+            }
+            holder?.setOnLongClickListener(R.id.iv_key_2) {
+                ToastUtils.tip("钥匙2上报异常")
+                true
+            }
+            holder?.setOnLongClickListener(R.id.iv_key_3) {
+                ToastUtils.tip("钥匙3上报异常")
+                true
+            }
+            holder?.setOnLongClickListener(R.id.iv_key_4) {
+                ToastUtils.tip("钥匙4上报异常")
+                true
+            }
         }
 
         override fun isForViewType(item: DockStatusBO?, position: Int): Boolean {
@@ -191,6 +224,10 @@ class DeviceStatusFragment :
                         R.id.root,
                         ModBusController.isLockExist(row.dockList[0].address, lockIdx)
                     )
+                    holder?.convertView?.setOnLongClickListener {
+                        ToastUtils.tip("锁${row.dockList[0].row},${row.dockList[0].column},${lockIdx}上报异常")
+                        true
+                    }
                     ColorStateList.valueOf(statusNotLightTintColor).let {
                         holder?.getView<View>(R.id.v_buckle_status_close)?.backgroundTintList = it
                         holder?.getView<View>(R.id.v_buckle_status_open)?.backgroundTintList = it

+ 23 - 10
app/src/main/java/com/grkj/iscs/view/fragment/JobProgressFragment.kt

@@ -12,11 +12,8 @@ import com.grkj.iscs.model.bo.PageChangeBO
 import com.grkj.iscs.model.eventmsg.MsgEvent
 import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_UPDATE_TICKET_PROGRESS
 import com.grkj.iscs.model.eventmsg.UpdateTicketProgressMsg
-import com.grkj.iscs.model.vo.ticket.StepDetailRespVO
 import com.grkj.iscs.model.vo.ticket.TicketDetailMonitorRespVO
 import com.grkj.iscs.model.vo.ticket.TicketDetailRespVO
-import com.grkj.iscs.util.Executor
-import com.grkj.iscs.util.NetApi
 import com.grkj.iscs.util.SPUtils
 import com.grkj.iscs.util.ToastUtils
 import com.grkj.iscs.util.log.LogUtil
@@ -37,7 +34,7 @@ class JobProgressFragment(val goBack: () -> Unit) :
     private val mUserList = mutableListOf<TicketDetailMonitorRespVO.IsJobTicketUser>()
     private var mTicketDetail: TicketDetailRespVO? = null
     private var mStep = 0
-    private var mCurrentStep: StepDetailRespVO? = null
+    private var mCurrentStepId: Long? = null
     private var mPageChangeBO: PageChangeBO? = null
     private var mTipDialog: TipDialog? = null
     private lateinit var observer: Observer<MsgEvent>
@@ -136,11 +133,16 @@ class JobProgressFragment(val goBack: () -> Unit) :
                         mTipDialog?.setTip(getString(R.string.all_point_have_other_job_not_finish))
                         mTipDialog?.setType(TipDialog.TYPE_HINT)
                         mTipDialog?.setConfirmListener {
-                            mCurrentStep?.stepId?.let {
-                                presenter?.updateStep(it, "1") {
-                                    goBack()
+                            mTicketDetail?.noUnlockTicketPointsVOSet?.let { noUnlockTicketPointsVOSet ->
+                                presenter?.updateCoincideToUnLock(noUnlockTicketPointsVOSet) {
+                                    mCurrentStepId?.let {
+                                        presenter?.updateStep(it, "1") {
+                                            goBack()
+                                        }
+                                    }
+                                        ?: ToastUtils.tip(getString(R.string.current_step_can_not_be_process))
                                 }
-                            } ?: ToastUtils.tip(getString(R.string.current_step_can_not_be_process))
+                            }
                         }
                         mTipDialog?.showCancelCountdown(10)
                     } else {
@@ -152,11 +154,21 @@ class JobProgressFragment(val goBack: () -> Unit) :
                             mTipDialog?.setType(TipDialog.TYPE_HINT)
                             mTipDialog?.setConfirmListener {
                                 BusinessManager.sendLoadingEventMsg(getString(R.string.system_is_processing))
+                                if (mTicketDetail?.noUnlockTicketPointsVOSet?.isNotEmpty() == true) {
+                                    mTicketDetail?.noUnlockTicketPointsVOSet?.let { noUnlockTicketPointsVOSet ->
+                                        presenter?.updateCoincideToUnLock(noUnlockTicketPointsVOSet)
+                                    }
+                                }
                                 presenter?.handleUnlockProcess(mPageChangeBO?.ticketId!!)
                             }
                             mTipDialog?.showCancelCountdown(10)
                         } else {
                             BusinessManager.sendLoadingEventMsg(getString(R.string.system_is_processing))
+                            if (mTicketDetail?.noUnlockTicketPointsVOSet?.isNotEmpty() == true) {
+                                mTicketDetail?.noUnlockTicketPointsVOSet?.let { noUnlockTicketPointsVOSet ->
+                                    presenter?.updateCoincideToUnLock(noUnlockTicketPointsVOSet)
+                                }
+                            }
                             presenter?.handleUnlockProcess(mPageChangeBO?.ticketId!!)
                         }
                     }
@@ -253,7 +265,7 @@ class JobProgressFragment(val goBack: () -> Unit) :
                 //刷卡处理共锁的位置调整步骤主要在这块
                 if (presenter?.canHandleColockerLock(
                         requireContext(),
-                        mStep
+                        mStep, mTicketDetail
                     ) == true
                 ) {
                     if (presenter?.canHandleColockerUnlock(
@@ -322,7 +334,8 @@ class JobProgressFragment(val goBack: () -> Unit) :
             it?.filter { it.stepStatus == "1" }?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
                 mStep = it
             }
-            mCurrentStep = it?.get(mStep)
+            mCurrentStepId =
+                it?.filter { it.stepStatus == "0" }?.minByOrNull { it.stepIndex!! }?.stepId
             handleActionBtnVisibility()
             callback?.invoke()
         }

+ 61 - 33
app/src/main/java/com/grkj/iscs/view/fragment/StepFragment.kt

@@ -337,8 +337,7 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
     private fun updateStep(step: Int) {
         val canContinue =
             presenter?.checkCanContinue(requireContext(), step, mTicketDetailData) ?: ""
-        if (canContinue.isEmpty()
-        ) {
+        if (canContinue.isEmpty()) {
             val str = when (step) {
                 4 -> getString(R.string.action_confirm_shut_down)
                 5 -> getString(R.string.action_confirm_lock)
@@ -347,15 +346,66 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
                 8 -> getString(R.string.action_confirm_restore)
                 else -> ""
             }
-            mTipDialog.setTip(str)
-            mTipDialog.setType(TipDialog.TYPE_ALL)
-            mTipDialog.setConfirmListener {
-                BusinessManager.sendLoadingEventMsg(getString(R.string.is_processing_please_wait))
-                when (step) {
-                    4 -> {
-                        presenter?.updateStep(mStepList[2].stepDetail?.stepId!!, "1") {
-                            presenter?.updateStep(mStepList[3].stepDetail?.stepId!!, "1") {
-                                BusinessManager.sendLoadingEventMsg(null, false)
+            if (step == 8 && presenter?.checkCrossJobUnlockData(
+                    requireContext(),
+                    mTicketDetailData
+                ) == true
+            ) {
+                mTipDialog.setTip(getString(R.string.all_point_have_other_job_not_finish))
+                mTipDialog.setType(TipDialog.TYPE_HINT)
+                mTipDialog.setConfirmListener {
+                    mTicketDetailData?.noUnlockTicketPointsVOSet?.let {
+                        presenter?.updateCoincideToUnLock(it) {
+                            if (it) {
+                                presenter?.updateStep(
+                                    mStepList.find { it.index == step }?.stepDetail?.stepId!!,
+                                    "1"
+                                ) {
+                                    mChangePage?.let {
+                                        refreshPage(it)
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                mTipDialog.showCancelCountdown(10)
+            } else {
+                mTipDialog.setTip(str)
+                mTipDialog.setType(TipDialog.TYPE_ALL)
+                mTipDialog.setConfirmListener {
+                    BusinessManager.sendLoadingEventMsg(getString(R.string.is_processing_please_wait))
+                    when (step) {
+                        4 -> {
+                            presenter?.updateStep(mStepList[2].stepDetail?.stepId!!, "1") {
+                                presenter?.updateStep(mStepList[3].stepDetail?.stepId!!, "1") {
+                                    BusinessManager.sendLoadingEventMsg(null, false)
+                                    refreshPage(mChangePage!!)
+                                    if (presenter?.jumpJobProgressPageCheck(
+                                            requireContext(),
+                                            step
+                                        ) == true
+                                    ) {
+                                        // 自动跳转
+                                        changePage(
+                                            PageChangeBO(
+                                                2,
+                                                mChangePage?.workstationId,
+                                                mChangePage?.ticketId,
+                                                mChangePage?.machineryId,
+                                                mChangePage?.machineryName
+                                            )
+                                        )
+                                    }
+                                }
+                            }
+                        }
+
+                        else -> {
+                            presenter?.updateStep(
+                                mStepList.find { it.index == step }?.stepDetail?.stepId!!,
+                                "1"
+                            ) {
                                 refreshPage(mChangePage!!)
                                 if (presenter?.jumpJobProgressPageCheck(
                                         requireContext(),
@@ -373,28 +423,6 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
                             }
                         }
                     }
-
-                    else -> {
-                        presenter?.updateStep(
-                            mStepList.find { it.index == step }?.stepDetail?.stepId!!,
-                            "1"
-                        ) {
-                            refreshPage(mChangePage!!)
-                            if (presenter?.jumpJobProgressPageCheck(
-                                    requireContext(),
-                                    step
-                                ) == true
-                            ) {
-                                // 自动跳转
-                                changePage(
-                                    PageChangeBO(
-                                        2, mChangePage?.workstationId, mChangePage?.ticketId,
-                                        mChangePage?.machineryId, mChangePage?.machineryName
-                                    )
-                                )
-                            }
-                        }
-                    }
                 }
             }
         } else {

+ 26 - 4
app/src/main/java/com/grkj/iscs/view/presenter/JobProgressPresenter.kt

@@ -280,7 +280,9 @@ class JobProgressPresenter : BasePresenter<IJobProgressView>() {
                             ticketId,
                             keyPair.second?.rfid!!
                         )
-
+                        ticketDetail.noUnlockTicketPointsVOSet?.let { noUnlockTicketPointsVOSet ->
+                            updateCoincideToUnLock(noUnlockTicketPointsVOSet)
+                        }
                         BusinessManager.getCurrentStatus(
                             5,
                             BusinessManager.getBleDeviceByMac(keyPair.second?.mac)!!.bleDevice
@@ -332,7 +334,8 @@ class JobProgressPresenter : BasePresenter<IJobProgressView>() {
         mPointList: MutableList<TicketDetailMonitorRespVO.IsJobTicketPointsVO>,
         mUserList: MutableList<TicketDetailMonitorRespVO.IsJobTicketUser>
     ): Boolean {
-        return IStepMode.getStepMode(context)?.showGoToUnlock(mTicketDetail,mPointList, mUserList) == true
+        return IStepMode.getStepMode(context)
+            ?.showGoToUnlock(mTicketDetail, mPointList, mUserList) == true
     }
 
     /**
@@ -349,8 +352,12 @@ class JobProgressPresenter : BasePresenter<IJobProgressView>() {
     /**
      * 是否共锁人可以上锁
      */
-    fun canHandleColockerLock(context: Context, mStep: Int): Boolean {
-        return IStepMode.getStepMode(context)?.canHandleColockerLock(mStep) == true
+    fun canHandleColockerLock(
+        context: Context,
+        mStep: Int,
+        mTicketDetail: TicketDetailRespVO?
+    ): Boolean {
+        return IStepMode.getStepMode(context)?.canHandleColockerLock(mStep, mTicketDetail) == true
     }
 
     /**
@@ -369,4 +376,19 @@ class JobProgressPresenter : BasePresenter<IJobProgressView>() {
     ): String? {
         return IStepMode.getStepMode(context)?.checkUnlock(mUserList)
     }
+
+
+    /**
+     * 重合点位数据解锁
+     */
+    fun updateCoincideToUnLock(
+        noUnlockTicketPointsVOSet: MutableList<TicketDetailRespVO.JobTicketPointsVO>,
+        callBack: ((Boolean) -> Unit)? = null
+    ) {
+        NetApi.updateCoincideToUnLock(noUnlockTicketPointsVOSet) {
+            Executor.runOnMain {
+                callBack?.invoke(it)
+            }
+        }
+    }
 }

+ 27 - 2
app/src/main/java/com/grkj/iscs/view/presenter/StepPresenter.kt

@@ -116,7 +116,32 @@ class StepPresenter : BasePresenter<IStepView>() {
     /**
      * 检查弹窗是否需要进入进度页面
      */
-    fun tipToJobProgressPageCheck(context: Context,mStep: Int, checked: () -> Unit) {
-        IStepMode.getStepMode(context)?.tipToJobProgressPageCheck(mStep,checked)
+    fun tipToJobProgressPageCheck(context: Context, mStep: Int, checked: () -> Unit) {
+        IStepMode.getStepMode(context)?.tipToJobProgressPageCheck(mStep, checked)
+    }
+
+    /**
+     * 检查当前步骤的解锁数据是否满足继续
+     * 主要是第8步的交叉作业的数据检查
+     */
+    fun checkCrossJobUnlockData(
+        context: Context,
+        mTicketDetailData: TicketDetailRespVO?
+    ): Boolean {
+        return IStepMode.getStepMode(context)?.checkCrossJobUnlockData(mTicketDetailData) == true
+    }
+
+    /**
+     * 重合点位数据解锁
+     */
+    fun updateCoincideToUnLock(
+        noUnlockTicketPointsVOSet: MutableList<TicketDetailRespVO.JobTicketPointsVO>,
+        callBack: (Boolean) -> Unit
+    ) {
+        NetApi.updateCoincideToUnLock(noUnlockTicketPointsVOSet) {
+            Executor.runOnMain {
+                callBack(it)
+            }
+        }
     }
 }

+ 7 - 1
app/src/main/java/com/grkj/iscs/view/step_mode/IStepMode.kt

@@ -78,7 +78,7 @@ interface IStepMode {
     /**
      * 是否可以处理共锁人上锁
      */
-    fun canHandleColockerLock(mStep: Int): Boolean
+    fun canHandleColockerLock(mStep: Int, mTicketDetail: TicketDetailRespVO?): Boolean
 
     /**
      * 是否共锁人可以解锁
@@ -105,6 +105,12 @@ interface IStepMode {
      */
     fun getMinColockerSize(): Int
 
+    /**
+     * 检查当前步骤的解锁数据是否满足继续
+     * 主要是第8步的交叉作业的数据检查
+     */
+    fun checkCrossJobUnlockData(mTicketDetailData: TicketDetailRespVO?): Boolean
+
     companion object {
         /**
          * 根据存储的模式获取模式

+ 6 - 2
app/src/main/java/com/grkj/iscs/view/step_mode/StepMode1.kt

@@ -63,7 +63,7 @@ class StepMode1 : IStepMode {
         return mStep >= 6
     }
 
-    override fun canHandleColockerLock(mStep: Int): Boolean {
+    override fun canHandleColockerLock(mStep: Int, mTicketDetail: TicketDetailRespVO?): Boolean {
         return mStep == 6
     }
 
@@ -84,6 +84,10 @@ class StepMode1 : IStepMode {
     }
 
     override fun getMinColockerSize(): Int {
-        return  1
+        return 1
+    }
+
+    override fun checkCrossJobUnlockData(mTicketDetailData: TicketDetailRespVO?): Boolean {
+        return false
     }
 }

+ 12 - 2
app/src/main/java/com/grkj/iscs/view/step_mode/StepMode2.kt

@@ -12,6 +12,9 @@ import com.grkj.iscs.model.vo.user.UserListRespVO
 import com.grkj.iscs.util.NetApi
 import com.grkj.iscs.util.log.LogUtil
 
+/**
+ * 玛氏流程
+ */
 class StepMode2 : IStepMode {
     override fun canModifyColocker(step: Int): Boolean {
         return step in 3..7
@@ -138,8 +141,8 @@ class StepMode2 : IStepMode {
         return (mStep >= 4 && mPointList.all { it.pointStatus == "1" }) || mStep >= 6
     }
 
-    override fun canHandleColockerLock(mStep: Int): Boolean {
-        return mStep == 4 || mStep == 5
+    override fun canHandleColockerLock(mStep: Int, mTicketDetail: TicketDetailRespVO?): Boolean {
+        return (mStep == 4 || mStep == 5) && mTicketDetail?.ticketPointsVOList?.all { it.pointStatus == "1" } == true
     }
 
     override fun canHandleColockerUnlock(mStep: Int): Boolean {
@@ -170,4 +173,11 @@ class StepMode2 : IStepMode {
     override fun getMinColockerSize(): Int {
         return 1
     }
+
+    override fun checkCrossJobUnlockData(mTicketDetailData: TicketDetailRespVO?): Boolean {
+        return mTicketDetailData?.ticketPointsVOList?.all {
+            it.pointId in (mTicketDetailData.noUnlockTicketPointsVOSet?.map { it.pointId }
+                ?: mutableListOf())
+        } == true
+    }
 }