Sfoglia il codice sorgente

refactor(更新)
- 锁仓界面的异常逻辑增加

周文健 4 mesi fa
parent
commit
31cc297ac3
25 ha cambiato i file con 367 aggiunte e 163 eliminazioni
  1. 44 43
      app/src/main/java/com/grkj/iscs/features/init/fragment/InitDeviceRegistrationKeyAndLockFragment.kt
  2. 11 2
      app/src/main/java/com/grkj/iscs/features/init/viewmodel/InitDeviceRegistrationKeyAndLockViewModel.kt
  3. 2 2
      app/src/main/java/com/grkj/iscs/features/login/dialog/LoginDialog.kt
  4. 1 0
      app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt
  5. 142 33
      app/src/main/java/com/grkj/iscs/features/main/fragment/hardware_manage/SlotsManageFragment.kt
  6. 1 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SetFingerprintFragment.kt
  7. 24 10
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/MainViewModel.kt
  8. 22 1
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/hardware_manage/SlotsManageViewModel.kt
  9. 1 1
      app/src/main/res/layout-land/item_job_execute_colock.xml
  10. 8 7
      app/src/main/res/layout/item_device_registration_key.xml
  11. 3 3
      app/src/main/res/layout/item_device_registration_lock.xml
  12. 4 2
      app/src/main/res/layout/item_device_slot_manage_key.xml
  13. 3 4
      app/src/main/res/layout/item_device_slot_manage_lock.xml
  14. 1 1
      app/src/main/res/layout/item_job_execute_colock.xml
  15. 1 0
      app/src/main/res/values-en/strings.xml
  16. 4 4
      app/src/main/res/values-land/dimens.xml
  17. 1 0
      app/src/main/res/values-zh/strings.xml
  18. 1 0
      app/src/main/res/values/strings.xml
  19. 24 0
      data/src/main/java/com/grkj/data/dao/HardwareDao.kt
  20. 0 4
      data/src/main/java/com/grkj/data/model/vo/SysBiometricDataVo.kt
  21. 10 0
      data/src/main/java/com/grkj/data/repository/IHardwareRepository.kt
  22. 25 1
      data/src/main/java/com/grkj/data/repository/impl/HardwareRepository.kt
  23. 0 24
      ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt
  24. 25 18
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/DockBean.kt
  25. 9 2
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusController.kt

+ 44 - 43
app/src/main/java/com/grkj/iscs/features/init/fragment/InitDeviceRegistrationKeyAndLockFragment.kt

@@ -62,7 +62,11 @@ class InitDeviceRegistrationKeyAndLockFragment :
                 navController.navigate(R.id.action_initDeviceRegistrationKeyAndLockFragment_to_initCardRegistrationFragment)
             }
         }
-        binding.dockRv.linear().dividerSpace(10, DividerOrientation.GRID).setup {
+        binding.dockRv.linear().dividerSpace(
+            requireContext().resources.getDimension(com.grkj.ui_base.R.dimen.common_spacing_2x)
+                .toInt(),
+            DividerOrientation.GRID
+        ).setup {
             addType<DockData.KeyDock>(R.layout.item_device_registration_key_layout)
             addType<DockData.LockDock>(R.layout.item_device_registration_lock_layout)
             addType<DockData.PortableDock>(R.layout.item_device_registration_portable_layout)
@@ -129,16 +133,15 @@ class InitDeviceRegistrationKeyAndLockFragment :
             justifyContent = JustifyContent.SPACE_EVENLY     // 等间距居中
             alignItems = AlignItems.CENTER               // 垂直居中对齐
         }
-        itemBinding.rvLockLayout.linear(LinearLayout.HORIZONTAL)
-            .setup {
-                addType<DockBean.LockBean>(R.layout.item_device_registration_lock)
-                onBind {
-                    val itemLockBinding = getBinding<ItemDeviceRegistrationLockBinding>()
-                    val itemLock = getModel<DockBean.LockBean>()
-                    itemLockBinding.tvNewDevice.isVisible = itemLock.newHardware
-                    itemLockBinding.root.isSelected = itemLock.isExist
-                }
-            }.models = lockDock.lockData
+        itemBinding.rvLockLayout.setup {
+            addType<DockBean.LockBean>(R.layout.item_device_registration_lock)
+            onBind {
+                val itemLockBinding = getBinding<ItemDeviceRegistrationLockBinding>()
+                val itemLock = getModel<DockBean.LockBean>()
+//                    itemLockBinding.tvNewDevice.isVisible = itemLock.newHardware
+                itemLockBinding.root.isSelected = itemLock.isExist
+            }
+        }.models = lockDock.lockData
     }
 
     private fun BindingAdapter.BindingViewHolder.onKeyDockRVListBinding(
@@ -150,18 +153,17 @@ class InitDeviceRegistrationKeyAndLockFragment :
             justifyContent = JustifyContent.SPACE_EVENLY     // 等间距居中
             alignItems = AlignItems.CENTER               // 垂直居中对齐
         }
-        itemBinding.rvKeyLayout.linear(LinearLayout.HORIZONTAL)
-            .setup {
-                addType<DockBean.KeyBean>(R.layout.item_device_registration_key)
-                onBind {
-                    val itemKeyBinding = getBinding<ItemDeviceRegistrationKeyBinding>()
-                    val itemKey = getModel<DockBean.KeyBean>()
-                    itemKeyBinding.tvNewDevice.isVisible = itemKey.newHardware
-                    itemKeyBinding.tvNewDeviceMac.isVisible = itemKey.mac?.isNotEmpty() == true
-                    itemKeyBinding.tvNewDeviceMac.text = itemKey.mac
-                    itemKeyBinding.ivKey.isSelected = itemKey.isExist
-                }
-            }.models = keyDock.keyData
+        itemBinding.rvKeyLayout.setup {
+            addType<DockBean.KeyBean>(R.layout.item_device_registration_key)
+            onBind {
+                val itemKeyBinding = getBinding<ItemDeviceRegistrationKeyBinding>()
+                val itemKey = getModel<DockBean.KeyBean>()
+//                    itemKeyBinding.tvNewDevice.isVisible = itemKey.newHardware
+//                    itemKeyBinding.tvNewDeviceMac.isVisible = itemKey.mac?.isNotEmpty() == true
+                itemKeyBinding.tvNewDeviceMac.text = itemKey.mac
+                itemKeyBinding.ivKey.isSelected = itemKey.isExist
+            }
+        }.models = keyDock.keyData
     }
 
     private fun BindingAdapter.BindingViewHolder.onPortableDockRVListBinding(
@@ -173,29 +175,28 @@ class InitDeviceRegistrationKeyAndLockFragment :
             justifyContent = JustifyContent.SPACE_EVENLY     // 等间距居中
             alignItems = AlignItems.CENTER               // 垂直居中对齐
         }
-        itemBinding.rvKeyLayout.linear(LinearLayout.HORIZONTAL)
-            .setup {
-                addType<DockBean.LockBean>(R.layout.item_device_registration_lock)
-                addType<DockBean.KeyBean>(R.layout.item_device_registration_key)
-                onBind {
-                    when (val itemPortable = getModel<Any>()) {
-                        is DockBean.KeyBean -> {
-                            val itemKeyBinding = getBinding<ItemDeviceRegistrationKeyBinding>()
-                            itemKeyBinding.tvNewDevice.isVisible = itemPortable.newHardware
-                            itemKeyBinding.tvNewDeviceMac.isVisible =
-                                itemPortable.mac?.isNotEmpty() == true
-                            itemKeyBinding.tvNewDeviceMac.text = itemPortable.mac
-                            itemKeyBinding.ivKey.isSelected = itemPortable.isExist
-                        }
+        itemBinding.rvKeyLayout.setup {
+            addType<DockBean.LockBean>(R.layout.item_device_registration_lock)
+            addType<DockBean.KeyBean>(R.layout.item_device_registration_key)
+            onBind {
+                when (val itemPortable = getModel<Any>()) {
+                    is DockBean.KeyBean -> {
+                        val itemKeyBinding = getBinding<ItemDeviceRegistrationKeyBinding>()
+//                            itemKeyBinding.tvNewDevice.isVisible = itemPortable.newHardware
+//                            itemKeyBinding.tvNewDeviceMac.isVisible =
+//                                itemPortable.mac?.isNotEmpty() == true
+                        itemKeyBinding.tvNewDeviceMac.text = itemPortable.mac
+                        itemKeyBinding.ivKey.isSelected = itemPortable.isExist
+                    }
 
-                        is DockBean.LockBean -> {
-                            val itemLockBinding = getBinding<ItemDeviceRegistrationLockBinding>()
-                            itemLockBinding.tvNewDevice.isVisible = itemPortable.newHardware
-                            itemLockBinding.root.isSelected = itemPortable.isExist
-                        }
+                    is DockBean.LockBean -> {
+                        val itemLockBinding = getBinding<ItemDeviceRegistrationLockBinding>()
+//                            itemLockBinding.tvNewDevice.isVisible = itemPortable.newHardware
+                        itemLockBinding.root.isSelected = itemPortable.isExist
                     }
                 }
-            }.models = portableDock.deviceData
+            }
+        }.models = portableDock.deviceData
     }
 
     override fun onEvent(event: EventBean<Any>) {

+ 11 - 2
app/src/main/java/com/grkj/iscs/features/init/viewmodel/InitDeviceRegistrationKeyAndLockViewModel.kt

@@ -200,11 +200,14 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
     /**
      * 仓位录入挂起任务
      */
-    private fun deviceInputSlotsSuspend(dockBean: DockBean) {
+    private fun deviceInputSlotsSuspend(dockBean: DockBean, startIndex: Int = 0): Int {
+        var lastIndex = startIndex
         when (dockBean.type) {
             DeviceConst.DOCK_TYPE_KEY -> {
                 val slots = dockBean.deviceList.mapIndexed { index, device ->
+                    lastIndex++
                     var isLockCabinetSlots = IsLockCabinetSlots()
+                    isLockCabinetSlots.slotCode = "CABINET_SLOTS_${lastIndex}"
                     isLockCabinetSlots.cabinetId = MMKVConstants.KEY_LOCK_CABINET_ID.getMMKVData(0)
                     isLockCabinetSlots.slotType = DeviceConst.DEVICE_TYPE_KEY.toString()
                     isLockCabinetSlots.row = dockBean.row.toString()
@@ -216,7 +219,9 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
 
             DeviceConst.DOCK_TYPE_LOCK -> {
                 val slots = dockBean.deviceList.mapIndexed { index, device ->
+                    lastIndex++
                     var isLockCabinetSlots = IsLockCabinetSlots()
+                    isLockCabinetSlots.slotCode = "CABINET_SLOTS_${lastIndex}"
                     isLockCabinetSlots.cabinetId = MMKVConstants.KEY_LOCK_CABINET_ID.getMMKVData(0)
                     isLockCabinetSlots.slotType = DeviceConst.DEVICE_TYPE_LOCK.toString()
                     isLockCabinetSlots.row = dockBean.row.toString()
@@ -228,7 +233,9 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
 
             DeviceConst.DOCK_TYPE_PORTABLE -> {
                 val slots = dockBean.deviceList.mapIndexed { index, device ->
+                    lastIndex++
                     var isLockCabinetSlots = IsLockCabinetSlots()
+                    isLockCabinetSlots.slotCode = "CABINET_SLOTS_${lastIndex}"
                     isLockCabinetSlots.cabinetId = MMKVConstants.KEY_LOCK_CABINET_ID.getMMKVData(0)
                     isLockCabinetSlots.row = dockBean.row.toString()
                     isLockCabinetSlots.col = (index + 1).toString()
@@ -242,6 +249,7 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
                 hardwareRepository.saveCabinetSlots(slots)
             }
         }
+        return lastIndex
     }
 
     /**
@@ -251,8 +259,9 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
         return liveData(Dispatchers.IO) {
             val dockList = ModBusController.dockList
             val deviceList = dockList.map { it.deviceList }.flatten()
+            var startIndex = 0
             dockList.forEach {
-                deviceInputSlotsSuspend(it)
+                startIndex = deviceInputSlotsSuspend(it, startIndex)
             }
             val lockDevice = deviceList.filter { it.type == DeviceConst.DEVICE_TYPE_LOCK }
                 .filterIsInstance<DockBean.LockBean>().filter { it.newHardware == true }

+ 2 - 2
app/src/main/java/com/grkj/iscs/features/login/dialog/LoginDialog.kt

@@ -149,8 +149,8 @@ class LoginDialog(
     private fun startFace() {
         ActivityTracker.getCurrentActivity()?.let { context ->
             ArcSoftUtil.initEngine(context)
-            ArcSoftUtil.initCamera(context, context.windowManager, mBinding?.preview!!) {
-                it?.let { itBitmap ->
+            ArcSoftUtil.initCamera(context, context.windowManager, mBinding.preview!!) {bitmap, faceSize, alive ->
+                bitmap?.let { itBitmap ->
                     viewModel.loginWithFace(
                         ImageConvertUtils.bitmapToBase64(itBitmap).toString()
                     ).observe(lifecycleOwner) {

+ 1 - 0
app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt

@@ -148,6 +148,7 @@ class MainActivity() : BaseActivity<ActivityMainBinding>() {
      * 退出登录
      */
     private fun logout() {
+        viewModel.removeBleIndicate()
         startActivity(Intent(this, LoginActivity::class.java).apply {
             flags = Intent.FLAG_ACTIVITY_NEW_TASK
         })

+ 142 - 33
app/src/main/java/com/grkj/iscs/features/main/fragment/hardware_manage/SlotsManageFragment.kt

@@ -1,6 +1,7 @@
 package com.grkj.iscs.features.main.fragment.hardware_manage
 
-import android.widget.LinearLayout
+import android.view.Gravity
+import android.view.View
 import androidx.core.view.isVisible
 import androidx.fragment.app.viewModels
 import com.drake.brv.BindingAdapter
@@ -15,18 +16,18 @@ import com.google.android.flexbox.FlexboxLayoutManager
 import com.google.android.flexbox.JustifyContent
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentSlotsManageBinding
-import com.grkj.iscs.databinding.ItemDeviceRegistrationKeyBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationKeyLayoutBinding
-import com.grkj.iscs.databinding.ItemDeviceRegistrationLockBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationLockLayoutBinding
 import com.grkj.iscs.databinding.ItemDeviceSlotManageKeyBinding
 import com.grkj.iscs.databinding.ItemDeviceSlotManageLockBinding
 import com.grkj.iscs.features.init.model.DockData
 import com.grkj.iscs.features.main.viewmodel.hardware_manage.SlotsManageViewModel
 import com.grkj.ui_base.base.BaseFragment
+import com.grkj.ui_base.dialog.TipDialog
 import com.grkj.ui_base.utils.modbus.DeviceConst
 import com.grkj.ui_base.utils.modbus.DockBean
 import com.grkj.ui_base.utils.modbus.ModBusController
+import com.kongzue.dialogx.dialogs.PopMenu
 import com.sik.sikcore.extension.setDebouncedClickListener
 import dagger.hilt.android.AndroidEntryPoint
 
@@ -36,6 +37,13 @@ import dagger.hilt.android.AndroidEntryPoint
 @AndroidEntryPoint
 class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
     private val viewModel: SlotsManageViewModel by viewModels()
+    private val slotsLongClickMenu: List<String> = listOf(
+        getString(com.grkj.ui_base.R.string.exception_report),
+        getString(com.grkj.ui_base.R.string.turn_on),
+        getString(com.grkj.ui_base.R.string.turn_off),
+        getString(R.string.detect_slot)
+    )
+
     override fun getLayoutId(): Int {
         return R.layout.fragment_slots_manage
     }
@@ -45,7 +53,10 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
             viewModel.unregisterStatusListener()
             navController.popBackStack()
         }
-        binding.dockRv.linear().dividerSpace(10, DividerOrientation.GRID).setup {
+        binding.dockRv.linear().dividerSpace(
+            requireContext().resources.getDimension(com.grkj.ui_base.R.dimen.common_spacing_2x)
+                .toInt(), DividerOrientation.GRID
+        ).setup {
             addType<DockData.KeyDock>(R.layout.item_device_registration_key_layout)
             addType<DockData.LockDock>(R.layout.item_device_registration_lock_layout)
             addType<DockData.PortableDock>(R.layout.item_device_registration_portable_layout)
@@ -67,6 +78,28 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
         }
     }
 
+    /**
+     * 显示长按菜单
+     */
+    private fun showLongClickMenu(v: View, deviceBean: DockBean.DeviceBean) {
+        PopMenu.show(v, slotsLongClickMenu)
+            .setAlignGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
+            .setOverlayBaseView(false)
+            .setOnMenuItemClickListener { dialog, _, index ->
+                when (index) {
+                    //异常上报
+                    0 -> {}
+                    //开
+                    1 -> {}
+                    //关
+                    2 -> {}
+                    //检查仓位
+                    3 -> {}
+                }
+                false
+            }
+    }
+
     private fun BindingAdapter.BindingViewHolder.onKeyDockRVListBinding(
         keyDock: DockData.KeyDock,
     ) {
@@ -76,15 +109,33 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
             justifyContent = JustifyContent.SPACE_EVENLY     // 等间距居中
             alignItems = AlignItems.CENTER               // 垂直居中对齐
         }
-        itemBinding.rvKeyLayout.linear(LinearLayout.HORIZONTAL)
-            .setup {
-                addType<DockBean.KeyBean>(R.layout.item_device_slot_manage_key)
-                onBind {
-                    val itemKeyBinding = getBinding<ItemDeviceSlotManageKeyBinding>()
-                    val itemKey = getModel<DockBean.KeyBean>()
-                    itemKeyBinding.ivKey.isSelected = itemKey.isExist
+        itemBinding.rvKeyLayout.setup {
+            addType<DockBean.KeyBean>(R.layout.item_device_slot_manage_key)
+            onBind {
+                val itemKeyBinding = getBinding<ItemDeviceSlotManageKeyBinding>()
+                val itemKey = getModel<DockBean.KeyBean>()
+                itemKeyBinding.exceptionIv.isVisible =
+                    viewModel.exceptionKeyData.find { it.keyNfc == itemKey.rfid } != null
+                itemKeyBinding.ivKey.isSelected = itemKey.isExist
+                itemKeyBinding.ivKey.setOnLongClickListener { v ->
+                    showLongClickMenu(v, itemKey)
+                    false
+                }
+                itemKeyBinding.exceptionIv.setOnClickListener {
+                    TipDialog.showError(
+                        msg = viewModel.exceptionKeyData.find { it.keyNfc == itemKey.rfid }?.remark
+                            ?: ""
+                    )
+                }
+                itemKeyBinding.exceptionIv.setOnLongClickListener {
+                    viewModel.removeSlotsException(itemKey.row, itemKey.idx)
+                        .observe(this@SlotsManageFragment) {
+                            adapter?.notifyDataSetChanged()
+                        }
+                    false
                 }
-            }.models = keyDock.keyData
+            }
+        }.models = keyDock.keyData
     }
 
 
@@ -97,15 +148,33 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
             justifyContent = JustifyContent.SPACE_EVENLY     // 等间距居中
             alignItems = AlignItems.CENTER               // 垂直居中对齐
         }
-        itemBinding.rvLockLayout.linear(LinearLayout.HORIZONTAL)
-            .setup {
-                addType<DockBean.LockBean>(R.layout.item_device_slot_manage_lock)
-                onBind {
-                    val itemLockBinding = getBinding<ItemDeviceSlotManageLockBinding>()
-                    val itemLock = getModel<DockBean.LockBean>()
-                    itemLockBinding.root.isSelected = itemLock.isExist
+        itemBinding.rvLockLayout.setup {
+            addType<DockBean.LockBean>(R.layout.item_device_slot_manage_lock)
+            onBind {
+                val itemLockBinding = getBinding<ItemDeviceSlotManageLockBinding>()
+                val itemLock = getModel<DockBean.LockBean>()
+                itemLockBinding.exceptionIv.isVisible =
+                    viewModel.exceptionLockData.find { it.lockNfc == itemLock.rfid } != null
+                itemLockBinding.root.isSelected = itemLock.isExist
+                itemLockBinding.root.setOnLongClickListener { v ->
+                    showLongClickMenu(v, itemLock)
+                    false
                 }
-            }.models = lockDock.lockData
+                itemLockBinding.exceptionIv.setOnClickListener {
+                    TipDialog.showError(
+                        msg = viewModel.exceptionLockData.find { it.lockNfc == itemLock.rfid }?.remark
+                            ?: ""
+                    )
+                }
+                itemLockBinding.exceptionIv.setOnLongClickListener {
+                    viewModel.removeSlotsException(itemLock.row, itemLock.idx)
+                        .observe(this@SlotsManageFragment) {
+                            adapter?.notifyDataSetChanged()
+                        }
+                    false
+                }
+            }
+        }.models = lockDock.lockData
     }
 
     private fun BindingAdapter.BindingViewHolder.onPortableDockRVListBinding(
@@ -117,28 +186,68 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
             justifyContent = JustifyContent.SPACE_EVENLY     // 等间距居中
             alignItems = AlignItems.CENTER               // 垂直居中对齐
         }
-        itemBinding.rvKeyLayout.linear(LinearLayout.HORIZONTAL)
-            .setup {
-                addType<DockBean.LockBean>(R.layout.item_device_slot_manage_lock)
-                addType<DockBean.KeyBean>(R.layout.item_device_slot_manage_key)
-                onBind {
-                    when (val itemPortable = getModel<Any>()) {
-                        is DockBean.KeyBean -> {
-                            val itemKeyBinding = getBinding<ItemDeviceSlotManageKeyBinding>()
-                            itemKeyBinding.ivKey.isSelected = itemPortable.isExist
+        itemBinding.rvKeyLayout.setup {
+            addType<DockBean.LockBean>(R.layout.item_device_slot_manage_lock)
+            addType<DockBean.KeyBean>(R.layout.item_device_slot_manage_key)
+            onBind {
+                when (val itemPortable = getModel<Any>()) {
+                    is DockBean.KeyBean -> {
+                        val itemKeyBinding = getBinding<ItemDeviceSlotManageKeyBinding>()
+                        itemKeyBinding.exceptionIv.isVisible =
+                            viewModel.exceptionKeyData.find { it.keyNfc == itemPortable.rfid } != null
+                        itemKeyBinding.ivKey.isSelected = itemPortable.isExist
+                        itemKeyBinding.ivKey.setOnLongClickListener { v ->
+                            showLongClickMenu(v, itemPortable)
+                            false
+                        }
+                        itemKeyBinding.exceptionIv.setOnClickListener {
+                            TipDialog.showError(
+                                msg = viewModel.exceptionKeyData.find { it.keyNfc == itemPortable.rfid }?.remark
+                                    ?: ""
+                            )
                         }
+                        itemKeyBinding.exceptionIv.setOnLongClickListener {
+                            viewModel.removeSlotsException(itemPortable.row, itemPortable.idx)
+                                .observe(this@SlotsManageFragment) {
+                                    adapter?.notifyDataSetChanged()
+                                }
+                            false
+                        }
+                    }
 
-                        is DockBean.LockBean -> {
-                            val itemLockBinding = getBinding<ItemDeviceSlotManageLockBinding>()
-                            itemLockBinding.root.isSelected = itemPortable.isExist
+                    is DockBean.LockBean -> {
+                        val itemLockBinding = getBinding<ItemDeviceSlotManageLockBinding>()
+                        itemLockBinding.exceptionIv.isVisible =
+                            viewModel.exceptionLockData.find { it.lockNfc == itemPortable.rfid } != null
+                        itemLockBinding.root.isSelected = itemPortable.isExist
+                        itemLockBinding.root.setOnLongClickListener { v ->
+                            showLongClickMenu(v, itemPortable)
+                            false
+                        }
+                        itemLockBinding.exceptionIv.setOnClickListener {
+                            TipDialog.showError(
+                                msg = viewModel.exceptionLockData.find { it.lockNfc == itemPortable.rfid }?.remark
+                                    ?: ""
+                            )
+                        }
+                        itemLockBinding.exceptionIv.setOnLongClickListener {
+                            viewModel.removeSlotsException(itemPortable.row, itemPortable.idx)
+                                .observe(this@SlotsManageFragment) {
+                                    adapter?.notifyDataSetChanged()
+                                }
+                            false
                         }
                     }
                 }
-            }.models = portableDock.deviceData
+            }
+        }.models = portableDock.deviceData
     }
 
     override fun initData() {
         super.initData()
+        viewModel.getExceptionData().observe(this) {
+            binding.dockRv.adapter?.notifyDataSetChanged()
+        }
         viewModel.registerStatusListener {
             getData()
         }

+ 1 - 1
app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SetFingerprintFragment.kt

@@ -78,7 +78,7 @@ class SetFingerprintFragment : BaseFragment<FragmentSetFingerprintBinding>() {
                 ).toString(),
                 countDownTime = 10,
                 onConfirmClick = {
-                    viewModel.sysBiometricDataVo.filter { it.selected }.forEach { item ->
+                    viewModel.sysBiometricDataVo.filter { it.isSelected }.forEach { item ->
                         if (item.content.isNotEmpty()) {
                             item.content.deleteIfExists()
                         }

+ 24 - 10
app/src/main/java/com/grkj/iscs/features/main/viewmodel/MainViewModel.kt

@@ -27,17 +27,31 @@ class MainViewModel @Inject constructor() : BaseViewModel() {
      * 蓝牙监听
      */
     fun bleIndicate() {
-        BleConnectionManager.addBLeIndicateListener(this, object : BleIndicateListener {
-            override fun handleRsp(
-                bleBean: BleBean,
-                byteArray: ByteArray,
-                isNeedLoading: Boolean,
-                prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
-            ) {
-                BleBusinessManager.handleRsp(bleBean, byteArray, isNeedLoading, prepareDoneCallBack)
-            }
+        BleConnectionManager.addBLeIndicateListener(
+            MainViewModel::class.java.simpleName,
+            object : BleIndicateListener {
+                override fun handleRsp(
+                    bleBean: BleBean,
+                    byteArray: ByteArray,
+                    isNeedLoading: Boolean,
+                    prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
+                ) {
+                    BleBusinessManager.handleRsp(
+                        bleBean,
+                        byteArray,
+                        isNeedLoading,
+                        prepareDoneCallBack
+                    )
+                }
+
+            })
+    }
 
-        })
+    /**
+     * 移除蓝牙监听
+     */
+    fun removeBleIndicate() {
+        BleConnectionManager.removeBleIndicateListener(MainViewModel::class.java.simpleName)
     }
 
     fun registerStatusListener() {

+ 22 - 1
app/src/main/java/com/grkj/iscs/features/main/viewmodel/hardware_manage/SlotsManageViewModel.kt

@@ -6,7 +6,6 @@ import com.grkj.data.model.dos.IsKey
 import com.grkj.data.model.dos.IsLock
 import com.grkj.data.model.dos.IsLockCabinetSlots
 import com.grkj.data.repository.IHardwareRepository
-import com.grkj.data.repository.impl.HardwareRepository
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.business.ModbusBusinessManager
 import dagger.hilt.android.lifecycle.HiltViewModel
@@ -62,4 +61,26 @@ class SlotsManageViewModel @Inject constructor(
             emit(true)
         }
     }
+
+    /**
+     * 移除锁仓异常
+     */
+    fun removeSlotsException(row: Int,col: Int): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            hardwareRepository.removeSlotsException(row,col)
+            exceptionSlotsData = hardwareRepository.getExceptionSlots()
+            emit(true)
+        }
+    }
+
+    /**
+     * 标记锁仓异常
+     */
+    fun tagSlotsException(row: Int,col: Int,remark: String): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            hardwareRepository.tagSlotsException(row,col,remark)
+            exceptionSlotsData = hardwareRepository.getExceptionSlots()
+            emit(true)
+        }
+    }
 }

+ 1 - 1
app/src/main/res/layout-land/item_job_execute_colock.xml

@@ -20,7 +20,7 @@
             android:layout_height="wrap_content"
             android:gravity="center"
             android:textColor="@color/black"
-            android:textSize="12sp"
+            android:textSize="@dimen/normal_text_size"
             tools:text="王俊杰" />
     </LinearLayout>
 </layout>

+ 8 - 7
app/src/main/res/layout/item_device_registration_key.xml

@@ -3,8 +3,9 @@
     xmlns:tools="http://schemas.android.com/tools">
 
     <RelativeLayout
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content">
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:gravity="center">
 
         <ImageView
             android:id="@+id/iv_key"
@@ -20,10 +21,10 @@
             android:layout_alignLeft="@+id/iv_key"
             android:layout_alignRight="@+id/iv_key"
             android:layout_marginTop="15dp"
-            android:textSize="@dimen/item_device_text_size"
             android:background="@drawable/common_btn_red_bg"
             android:text="@string/new_device"
-            android:visibility="visible" />
+            android:textSize="@dimen/item_device_text_size"
+            android:visibility="gone" />
 
         <TextView
             android:id="@+id/tv_new_device_mac"
@@ -32,10 +33,10 @@
             android:layout_alignLeft="@+id/iv_key"
             android:layout_alignRight="@+id/iv_key"
             android:layout_marginTop="15dp"
-            tools:text="AA:BB:CC:DD:EE:FF"
-            android:textSize="@dimen/item_device_text_size"
             android:background="@drawable/common_btn_green_bg"
-            android:visibility="visible" />
+            android:textSize="@dimen/item_device_text_size"
+            android:visibility="gone"
+            tools:text="AA:BB:CC:DD:EE:FF" />
 
         <View
             android:id="@+id/v_buckle_status"

+ 3 - 3
app/src/main/res/layout/item_device_registration_lock.xml

@@ -3,9 +3,9 @@
     xmlns:tools="http://schemas.android.com/tools">
 
     <RelativeLayout
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginHorizontal="@dimen/common_spacing_small"
+        android:gravity="center"
         android:orientation="horizontal">
 
         <FrameLayout
@@ -24,7 +24,7 @@
             android:background="@drawable/common_btn_red_bg"
             android:text="@string/new_device"
             android:textSize="@dimen/item_device_text_size"
-            android:visibility="visible" />
+            android:visibility="gone" />
     </RelativeLayout>
 
 </layout>

+ 4 - 2
app/src/main/res/layout/item_device_slot_manage_key.xml

@@ -1,10 +1,12 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
+    xmlns:tools="http://schemas.android.com/tools"
+    xmlns:flex="http://schemas.android.com/apk/res-auto">
 
     <RelativeLayout
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content">
+        android:layout_height="wrap_content"
+        android:gravity="center">
 
         <ImageView
             android:id="@+id/iv_key"

+ 3 - 4
app/src/main/res/layout/item_device_slot_manage_lock.xml

@@ -1,11 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
-<layout xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools">
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
 
     <RelativeLayout
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginHorizontal="@dimen/common_spacing_small"
+        android:gravity="center"
         android:orientation="horizontal">
 
         <FrameLayout
@@ -23,7 +22,7 @@
             android:layout_alignRight="@+id/root"
             android:layout_alignBottom="@+id/root"
             android:src="@mipmap/icon_exception"
-            android:visibility="gone"/>
+            android:visibility="gone" />
     </RelativeLayout>
 
 </layout>

+ 1 - 1
app/src/main/res/layout/item_job_execute_colock.xml

@@ -20,7 +20,7 @@
             android:layout_height="wrap_content"
             android:gravity="center"
             android:textColor="@color/black"
-            android:textSize="12sp"
+            android:textSize="@dimen/normal_text_size"
             tools:text="王俊杰" />
     </LinearLayout>
 </layout>

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

@@ -397,5 +397,6 @@
     <string name="set_job_card_title">Set work card</string>
     <string name="job_card_scan_tip">Please read the card on the card reader</string>
     <string name="slots_manage_title">Slots manage</string>
+    <string name="detect_slot">Detect slot</string>
 
 </resources>

+ 4 - 4
app/src/main/res/values-land/dimens.xml

@@ -49,10 +49,10 @@
     <dimen name="common_spacing_1_5x">15dp</dimen>
     <dimen name="init_margin_space">120dp</dimen>
     <dimen name="init_set_admin_account_et_height">51dp</dimen>
-    <dimen name="init_key_iv_width">85dp</dimen>
-    <dimen name="init_key_iv_height">60dp</dimen>
-    <dimen name="init_lock_iv_width">51dp</dimen>
-    <dimen name="init_lock_iv_height">119dp</dimen>
+    <dimen name="init_key_iv_width">170dp</dimen>
+    <dimen name="init_key_iv_height">120dp</dimen>
+    <dimen name="init_lock_iv_width">70dp</dimen>
+    <dimen name="init_lock_iv_height">180dp</dimen>
     <dimen name="login_method_item_layout_width">341dp</dimen>
     <dimen name="login_method_item_layout_height">384dp</dimen>
     <dimen name="login_method_item_iv_size">205dp</dimen>

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

@@ -397,5 +397,6 @@
     <string name="set_job_card_title">设置工卡</string>
     <string name="job_card_scan_tip">请在读卡器上读卡</string>
     <string name="slots_manage_title">仓位管理</string>
+    <string name="detect_slot">检测仓位</string>
 
 </resources>

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

@@ -400,5 +400,6 @@
     <string name="set_job_card_title">设置工卡</string>
     <string name="job_card_scan_tip">请在读卡器上读卡</string>
     <string name="slots_manage_title">仓位管理</string>
+    <string name="detect_slot">检测仓位</string>
 
 </resources>

+ 24 - 0
data/src/main/java/com/grkj/data/dao/HardwareDao.kt

@@ -422,4 +422,28 @@ interface HardwareDao {
      */
     @Insert(onConflict = OnConflictStrategy.REPLACE)
     fun createCabinetData(isLockCabinet: IsLockCabinet): Long
+
+    /**
+     * 新增锁仓数据
+     */
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun saveCabinetSlots(slots: List<IsLockCabinetSlots>)
+
+    /**
+     * 清除仓位数据
+     */
+    @Query("delete from is_lock_cabinet_slots where 1=1")
+    fun clearCabinetSlots()
+
+    /**
+     * 移除仓位异常
+     */
+    @Query("update is_lock_cabinet_slots set status = :dictValue where `row` = :row and `col` = :col")
+    fun removeSlotsException(row: Int, col: Int, dictValue: String?)
+
+    /**
+     * 标记锁仓异常
+     */
+    @Query("update is_lock_cabinet_slots set status = :dictValue,remark = :remark where `row` = :row and `col` = :col")
+    fun tagSlotsException(row: Int, col: Int, dictValue: String?, remark: String)
 }

+ 0 - 4
data/src/main/java/com/grkj/data/model/vo/SysBiometricDataVo.kt

@@ -1,13 +1,9 @@
 package com.grkj.data.model.vo
 
-import androidx.room.Ignore
 import com.grkj.data.model.dos.SysUserCharacteristicDo
 
 /**
  * 生物数据
  */
 class SysBiometricDataVo : SysUserCharacteristicDo() {
-
-    @Ignore
-    var selected: Boolean = false
 }

+ 10 - 0
data/src/main/java/com/grkj/data/repository/IHardwareRepository.kt

@@ -256,6 +256,11 @@ interface IHardwareRepository {
      */
     fun getExceptionSlots(): List<IsLockCabinetSlots>
 
+    /**
+     * 移除仓位异常
+     */
+    fun removeSlotsException(row: Int, col: Int)
+
     /**
      * 创建锁柜数据
      */
@@ -270,4 +275,9 @@ interface IHardwareRepository {
      * 清除锁仓数据
      */
     fun clearCabinetSlots()
+
+    /**
+     * 标记锁仓异常
+     */
+    fun tagSlotsException(row: Int, col: Int, remark: String)
 }

+ 25 - 1
data/src/main/java/com/grkj/data/repository/impl/HardwareRepository.kt

@@ -2,7 +2,6 @@ package com.grkj.data.repository.impl
 
 import com.grkj.data.dao.HardwareDao
 import com.grkj.data.dao.IsolationPointDao
-import com.grkj.data.data.DictConstants
 import com.grkj.data.data.MMKVConstants
 import com.grkj.data.enums.CommonDictDataEnum
 import com.grkj.data.model.dos.IsJobCard
@@ -406,6 +405,14 @@ class HardwareRepository @Inject constructor(
             .filter { it.status == CommonDictDataEnum.SLOT_STATUS.commonDictRes.find { it.dictLabel == "异常" }?.dictValue }
     }
 
+    override fun removeSlotsException(row: Int, col: Int) {
+        hardwareDao.removeSlotsException(
+            row,
+            col,
+            CommonDictDataEnum.SLOT_STATUS.commonDictRes.find { it.dictLabel == "可用" }?.dictValue
+        )
+    }
+
     override fun createCabinetData() {
         hardwareDao.clearCabinetData()
         val isLockCabinet = IsLockCabinet()
@@ -414,4 +421,21 @@ class HardwareRepository @Inject constructor(
         val lockCabinetId = hardwareDao.createCabinetData(isLockCabinet)
         MMKVConstants.KEY_LOCK_CABINET_ID.saveMMKVData(lockCabinetId)
     }
+
+    override fun saveCabinetSlots(isLockCabinetSlots: List<IsLockCabinetSlots>) {
+        hardwareDao.saveCabinetSlots(isLockCabinetSlots)
+    }
+
+    override fun clearCabinetSlots() {
+        hardwareDao.clearCabinetSlots()
+    }
+
+    override fun tagSlotsException(row: Int, col: Int, remark: String) {
+        hardwareDao.tagSlotsException(
+            row,
+            col,
+            CommonDictDataEnum.SLOT_STATUS.commonDictRes.find { it.dictLabel == "异常" }?.dictValue,
+            remark
+        )
+    }
 }

+ 0 - 24
ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt

@@ -7,7 +7,6 @@ import com.google.gson.Gson
 import com.grkj.data.data.DictConstants
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.di.RepositoryManager
-import com.grkj.data.enums.RoleEnum
 import com.grkj.data.model.dos.IsJobTicketStep
 import com.grkj.data.model.local.DeviceTakeUpdate
 import com.grkj.data.model.local.UpdateKeyReturn
@@ -60,14 +59,6 @@ object BleBusinessManager {
         prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
     ) {
         when {
-            // 获取令牌
-            byteArray.startsWith(BleConst.RSP_GET_TOKEN) -> BleCmdManager.handleToken(
-                bleBean.bleDevice, byteArray
-            ) { isSuccess ->
-                if (isSuccess) {
-                    prepareDoneCallBack?.invoke(true, bleBean)
-                }
-            }
             // 工作模式切换
             byteArray.startsWith(BleConst.RSP_SWITCH_MODE) -> {
                 handleSwitchModeResult(byteArray, isNeedLoading) { res, job ->
@@ -88,21 +79,6 @@ object BleBusinessManager {
             byteArray.startsWith(BleConst.RSP_WORK_TICKET_RESULT) && byteArray[3] == 0x02.toByte() -> handleTicketStatus(
                 bleBean.bleDevice, byteArray, isNeedLoading
             )
-            //电池电量返回
-            byteArray.startsWith(BleConst.RSP_POWER_STATUS) -> {
-                val power = byteArray[4].toInt()
-                ModBusController.updateKeyPower(power, bleBean.bleDevice.mac)
-                logger.info("电量:${power}")
-                if (power < 50) {//如果电量小于50就打开仓位充电
-                    ModBusController.controlKeyCharge(true, bleBean.bleDevice.mac) {
-                        logger.info("钥匙: ${bleBean.bleDevice.mac} 开始充电")
-                    }
-                } else if (power > 90) {
-                    ModBusController.controlKeyCharge(false, bleBean.bleDevice.mac) {
-                        logger.info("钥匙: ${bleBean.bleDevice.mac} 关闭充电")
-                    }
-                }
-            }
         }
     }
 

+ 25 - 18
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/DockBean.kt

@@ -54,12 +54,12 @@ class DockBean(
                     if (getKeyList().isEmpty()) {
                         deviceList.add(
                             KeyBean(
-                                0, leftHasKey, isLeftCharging, false, null, null
+                                row, 0, leftHasKey, isLeftCharging, false, null, null
                             )
                         )
                         deviceList.add(
                             KeyBean(
-                                1, rightHasKey, isRightCharging, false, null, null
+                                row, 1, rightHasKey, isRightCharging, false, null, null
                             )
                         )
                         return null
@@ -116,7 +116,7 @@ class DockBean(
 
                     if (getLockList().isEmpty()) {
                         for (i in 0 until tempList.size) {
-                            deviceList.add(LockBean(i, tempList[i], false, null))
+                            deviceList.add(LockBean(row, i, tempList[i], false, null))
                         }
                     }
 
@@ -158,7 +158,7 @@ class DockBean(
                     }
                     if (getLockList().isEmpty()) {
                         for (i in 0 until tempList.size) {
-                            deviceList.add(LockBean(i, tempList[i], false, null))
+                            deviceList.add(LockBean(row, i, tempList[i], false, null))
                         }
                     }
 
@@ -168,7 +168,7 @@ class DockBean(
                     if (getKeyList().isEmpty()) {
                         deviceList.add(
                             KeyBean(
-                                4, isKeyExist, isKeyCharging, false, null, null
+                                row, 4, isKeyExist, isKeyCharging, false, null, null
                             )
                         )
                     }
@@ -181,11 +181,11 @@ class DockBean(
 
                     // TODO 便携柜 list
                     if (getCardList().isEmpty()) {
-                        deviceList.add(CardBean(0, isCardExist))
+                        deviceList.add(CardBean(row, 0, isCardExist))
                     }
 
                     if (getFingerPrintList().isEmpty()) {
-                        deviceList.add(FingerPrintBean(0, isFingerPrintExist))
+                        deviceList.add(FingerPrintBean(row, 0, isFingerPrintExist))
                     }
 
                     val changeList = mutableListOf<DeviceBean>()
@@ -317,7 +317,7 @@ class DockBean(
                     }
                     if (getLockList().isEmpty()) {
                         for (i in 0 until tempList.size) {
-                            deviceList.add(LockBean(i, tempList[i], tempList[i], null))
+                            deviceList.add(LockBean(row, i, tempList[i], tempList[i], null))
                         }
                         return null
                     }
@@ -402,6 +402,7 @@ class DockBean(
                                     } ?: run {
                                     deviceList.add(
                                         SwitchBean(
+                                            row,
                                             idx,
                                             switchBoardAddr[1],
                                             switchStatus[idx]
@@ -528,13 +529,14 @@ class DockBean(
      */
     sealed class DeviceBean(
         var type: Int,
+        var row: Int,
         var idx: Int,
         var isExist: Boolean,
         var lockEnabled: Boolean = false,
         var newHardware: Boolean = false
     ) {
         override fun toString(): String {
-            return "DeviceBean(type=$type, idx=$idx, isExist=$isExist)"
+            return "DeviceBean(type=$type, row=$row, idx=$idx, isExist=$isExist)"
         }
     }
 
@@ -542,6 +544,7 @@ class DockBean(
      * 钥匙
      */
     class KeyBean(
+        row: Int,
         idx: Int,
         isExist: Boolean,
         var isCharging: Boolean,
@@ -550,13 +553,13 @@ class DockBean(
         var mac: String?,
         var isReady: Boolean = false,    // 钥匙是否准备好(连接上且为待机模式)
         var power: Int = 0 //电量
-    ) : DeviceBean(DeviceConst.DEVICE_TYPE_KEY, idx, isExist, lockEnabled) {
+    ) : DeviceBean(DeviceConst.DEVICE_TYPE_KEY, row, idx, isExist, lockEnabled) {
         override fun toString(): String {
-            return "KeyBean( isCharging=$isCharging, rfid=$rfid, mac=$mac, isReady=$isReady, idx=$idx, isExist=$isExist, power=$power)"
+            return "KeyBean( isCharging=$isCharging, rfid=$rfid, mac=$mac, isReady=$isReady, row=$row, idx=$idx, isExist=$isExist, power=$power)"
         }
 
         fun clone(): KeyBean {
-            return KeyBean(idx, isExist, isCharging, lockEnabled, rfid, mac, isReady)
+            return KeyBean(row, idx, isExist, isCharging, lockEnabled, rfid, mac, isReady)
         }
     }
 
@@ -566,17 +569,18 @@ class DockBean(
      * @param rfid 锁具的RFID(仅有关闭锁扣的时候读取并保存,否则为null)
      */
     class LockBean(
+        row: Int,
         idx: Int,
         isExist: Boolean,
         lockEnabled: Boolean = false,
         var rfid: String?,
-    ) : DeviceBean(DeviceConst.DEVICE_TYPE_LOCK, idx, isExist, lockEnabled) {
+    ) : DeviceBean(DeviceConst.DEVICE_TYPE_LOCK, row, idx, isExist, lockEnabled) {
         override fun toString(): String {
-            return "LockBean(rfid=$rfid, idx=$idx, isExist=$isExist)"
+            return "LockBean(rfid=$rfid, row=$row, idx=$idx, isExist=$isExist)"
         }
 
         fun clone(): LockBean {
-            return LockBean(idx, isExist, lockEnabled, rfid)
+            return LockBean(row, idx, isExist, lockEnabled, rfid)
         }
     }
 
@@ -584,26 +588,29 @@ class DockBean(
      * 卡
      */
     class CardBean(
+        row: Int,
         idx: Int,
         isExist: Boolean,
         lockEnabled: Boolean = false,
-    ) : DeviceBean(DeviceConst.DEVICE_TYPE_CARD, idx, isExist, lockEnabled)
+    ) : DeviceBean(DeviceConst.DEVICE_TYPE_CARD, row, idx, isExist, lockEnabled)
 
     /**
      * 指纹
      */
     class FingerPrintBean(
+        row: Int,
         idx: Int,
         isExist: Boolean,
         lockEnabled: Boolean = false,
-    ) : DeviceBean(DeviceConst.DEVICE_TYPE_FINGERPRINT, idx, isExist, lockEnabled)
+    ) : DeviceBean(DeviceConst.DEVICE_TYPE_FINGERPRINT, row, idx, isExist, lockEnabled)
 
     /**
      * 开关
      */
     class SwitchBean(
+        row: Int,
         idx: Int,
         val switchBoardAddr: Byte,
         var enabled: Boolean
-    ) : DeviceBean(DeviceConst.DEVICE_TYPE_SWITCH, idx, true)
+    ) : DeviceBean(DeviceConst.DEVICE_TYPE_SWITCH, row, idx, true)
 }

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

@@ -1111,8 +1111,15 @@ object ModBusController {
      */
     fun getSwitchData(): MutableList<DockBean.SwitchBean> {
         return dockList.filter { it.type == DeviceConst.DOCK_TYPE_COLLECT }.sortedBy { it.addr }
-            .flatMap { it.getSwitchList() }.mapIndexed { index, switchBean ->
-                DockBean.SwitchBean(index, switchBean.switchBoardAddr, switchBean.enabled)
+            .flatMapIndexed { row, dock ->
+                dock.getSwitchList().mapIndexed { idx, sw ->
+                    DockBean.SwitchBean(
+                        row,                // 来自 flatMapIndexed
+                        idx,
+                        sw.switchBoardAddr,
+                        sw.enabled
+                    )
+                }
             }.toMutableList()
     }