Forráskód Böngészése

refactor(更新)
- 锁仓管理新增界面
- 初始化的时候增加锁柜数据和锁仓数据

周文健 4 hónapja
szülő
commit
9a1bac29ba

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

@@ -9,6 +9,10 @@ import com.drake.brv.utils.dividerSpace
 import com.drake.brv.utils.linear
 import com.drake.brv.utils.models
 import com.drake.brv.utils.setup
+import com.google.android.flexbox.AlignItems
+import com.google.android.flexbox.FlexDirection
+import com.google.android.flexbox.FlexboxLayoutManager
+import com.google.android.flexbox.JustifyContent
 import com.grkj.data.data.EventConstants
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentInitDeviceRegistrationKeyAndLockBinding
@@ -17,11 +21,9 @@ import com.grkj.iscs.databinding.ItemDeviceRegistrationKeyLayoutBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationLockBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationLockLayoutBinding
 import com.grkj.iscs.features.init.model.DockData
-import com.grkj.iscs.features.init.model.DockData.KeyDock
 import com.grkj.iscs.features.init.viewmodel.InitDeviceRegistrationKeyAndLockViewModel
 import com.grkj.shared.model.EventBean
 import com.grkj.ui_base.base.BaseFragment
-import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.utils.modbus.DeviceConst
 import com.grkj.ui_base.utils.modbus.DockBean
 import com.grkj.ui_base.utils.modbus.ModBusController
@@ -86,7 +88,7 @@ class InitDeviceRegistrationKeyAndLockFragment :
                     R.string.init_device_registration_key_and_lock_complete_step_hint
                 )
             binding.reRecognize.isVisible = it
-            if (it){
+            if (it) {
                 val dockData =
                     ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
                 val keyDock = dockData.filter { it.type == DeviceConst.DOCK_TYPE_KEY }.map {
@@ -98,7 +100,7 @@ class InitDeviceRegistrationKeyAndLockFragment :
                 val newKeyDock = DockData.KeyDock()
                 newKeyDock.keyData.addAll(keyDatas)
                 val newKeyDockList = newKeyDock.keyData.chunked(4).map { subList ->
-                    KeyDock().apply { keyData.addAll(subList) }
+                    DockData.KeyDock().apply { keyData.addAll(subList) }
                 }
                 val lockDock = dockData.filter { it.type == DeviceConst.DOCK_TYPE_LOCK }.map {
                     DockData.LockDock().apply {
@@ -122,6 +124,11 @@ class InitDeviceRegistrationKeyAndLockFragment :
         lockDock: DockData.LockDock,
     ) {
         val itemBinding = getBinding<ItemDeviceRegistrationLockLayoutBinding>()
+        itemBinding.rvLockLayout.layoutManager = FlexboxLayoutManager(context).apply {
+            flexDirection = FlexDirection.ROW               // 横向
+            justifyContent = JustifyContent.SPACE_EVENLY     // 等间距居中
+            alignItems = AlignItems.CENTER               // 垂直居中对齐
+        }
         itemBinding.rvLockLayout.linear(LinearLayout.HORIZONTAL)
             .setup {
                 addType<DockBean.LockBean>(R.layout.item_device_registration_lock)
@@ -138,6 +145,11 @@ class InitDeviceRegistrationKeyAndLockFragment :
         keyDock: DockData.KeyDock,
     ) {
         val itemBinding = getBinding<ItemDeviceRegistrationKeyLayoutBinding>()
+        itemBinding.rvKeyLayout.layoutManager = FlexboxLayoutManager(context).apply {
+            flexDirection = FlexDirection.ROW               // 横向
+            justifyContent = JustifyContent.SPACE_EVENLY     // 等间距居中
+            alignItems = AlignItems.CENTER               // 垂直居中对齐
+        }
         itemBinding.rvKeyLayout.linear(LinearLayout.HORIZONTAL)
             .setup {
                 addType<DockBean.KeyBean>(R.layout.item_device_registration_key)
@@ -156,6 +168,11 @@ class InitDeviceRegistrationKeyAndLockFragment :
         portableDock: DockData.PortableDock,
     ) {
         val itemBinding = getBinding<ItemDeviceRegistrationKeyLayoutBinding>()
+        itemBinding.rvKeyLayout.layoutManager = FlexboxLayoutManager(context).apply {
+            flexDirection = FlexDirection.ROW               // 横向
+            justifyContent = JustifyContent.SPACE_EVENLY     // 等间距居中
+            alignItems = AlignItems.CENTER               // 垂直居中对齐
+        }
         itemBinding.rvKeyLayout.linear(LinearLayout.HORIZONTAL)
             .setup {
                 addType<DockBean.LockBean>(R.layout.item_device_registration_lock)
@@ -194,7 +211,8 @@ class InitDeviceRegistrationKeyAndLockFragment :
 
     override fun onResume() {
         super.onResume()
-        viewModel.clearKeyAndLock()
+        viewModel.clearLockCabinetSlots().observe(this) {}
+        viewModel.clearKeyAndLock().observe(this) {}
         viewModel.isDestroy = false
     }
 

+ 3 - 0
app/src/main/java/com/grkj/iscs/features/init/fragment/InitWelcomeFragment.kt

@@ -36,6 +36,9 @@ class InitWelcomeFragment : BaseFragment<FragmentInitWelcomeBinding>() {
         if (MMKVConstants.KEY_PORT_CONFIG.getMMKVData("").isEmpty()) {
             binding.startBtn.text = CommonUtils.getStr(R.string.detect_port)
         } else {
+            viewModel.createLockCabinetData().observe(this){
+
+            }
             binding.startBtn.text = CommonUtils.getStr(R.string.start)
             binding.startBtn.setDebouncedClickListener {
                 navController.navigate(R.id.action_initWelcomeFragment_to_initSetAdminAccountFragment)

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

@@ -1,11 +1,12 @@
 package com.grkj.iscs.features.init.viewmodel
 
-import android.bluetooth.BluetoothDevice
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.liveData
 import com.clj.fastble.BleManager
 import com.grkj.data.data.MMKVConstants
+import com.grkj.data.model.dos.IsLockCabinet
+import com.grkj.data.model.dos.IsLockCabinetSlots
 import com.grkj.data.repository.IHardwareRepository
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.business.ModbusBusinessManager
@@ -14,9 +15,7 @@ import com.grkj.ui_base.utils.ble.BleConnectionManager
 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.sik.sikcore.bluetooth.BLEScanner
-import com.sik.sikcore.bluetooth.BluetoothManager
-import com.sik.sikcore.bluetooth.IBluetoothScanCallback
+import com.sik.sikcore.extension.getMMKVData
 import com.sik.sikcore.thread.ThreadUtils
 import com.tencent.mmkv.MMKV
 import dagger.hilt.android.lifecycle.HiltViewModel
@@ -24,7 +23,6 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlinx.coroutines.withContext
-import java.util.concurrent.atomic.AtomicInteger
 import javax.inject.Inject
 import kotlin.coroutines.resume
 
@@ -39,23 +37,6 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
     private val newHardwareKeyBean: MutableMap<Byte, MutableList<DockBean.KeyBean>> = mutableMapOf()
     private val alreadyUsedMac: MutableList<String> = mutableListOf()
 
-    fun checkNewHardware(device: DockBean.DeviceBean, callback: () -> Unit) {
-        if (device is DockBean.KeyBean) {
-            device.mac = null
-            hardwareRepository.getKeyInfo(device.rfid.toString()) {
-                device.newHardware =
-                    it == null || it.keyNfc?.isEmpty() == true || it.macAddress?.isEmpty() == true
-                device.mac = it?.macAddress
-                callback()
-            }
-        } else if (device is DockBean.LockBean) {
-            hardwareRepository.getLockInfo(device.rfid.toString()) {
-                device.newHardware = it == null || it.lockNfc?.isEmpty() == true
-                callback()
-            }
-        }
-    }
-
     /**
      * 注册监听
      */
@@ -64,7 +45,7 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
             newHardwareKeyBean.clear()
             alreadyUsedMac.clear()
             isLoadComplete.postValue(false)
-            ModBusController.controlAllKeyBuckleOpen{
+            ModBusController.controlAllKeyBuckleOpen {
                 ModbusBusinessManager.registerInitListener {
                     if (!ISCSConfig.canInitDevice || isInDeviceInit) {
                         return@registerInitListener
@@ -141,7 +122,7 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
                         ThreadUtils.runOnIO {
                             delay(3000)
                             logger.info("设备录入-开始扫描在线蓝牙Mac")
-                            withContext(Dispatchers.Main){
+                            withContext(Dispatchers.Main) {
                                 BleConnectionManager.scanOnlineKeyLockMac(alreadyUsedMac) { mac ->
                                     logger.info(
                                         "设备录入-在线的蓝牙设备:${keyBean.rfid},${mac}"
@@ -216,13 +197,63 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
         }
     }
 
+    /**
+     * 仓位录入挂起任务
+     */
+    private fun deviceInputSlotsSuspend(dockBean: DockBean) {
+        when (dockBean.type) {
+            DeviceConst.DOCK_TYPE_KEY -> {
+                val slots = dockBean.deviceList.mapIndexed { index, device ->
+                    var isLockCabinetSlots = IsLockCabinetSlots()
+                    isLockCabinetSlots.cabinetId = MMKVConstants.KEY_LOCK_CABINET_ID.getMMKVData(0)
+                    isLockCabinetSlots.slotType = DeviceConst.DEVICE_TYPE_KEY.toString()
+                    isLockCabinetSlots.row = dockBean.row.toString()
+                    isLockCabinetSlots.col = (index + 1).toString()
+                    isLockCabinetSlots
+                }
+                hardwareRepository.saveCabinetSlots(slots)
+            }
+
+            DeviceConst.DOCK_TYPE_LOCK -> {
+                val slots = dockBean.deviceList.mapIndexed { index, device ->
+                    var isLockCabinetSlots = IsLockCabinetSlots()
+                    isLockCabinetSlots.cabinetId = MMKVConstants.KEY_LOCK_CABINET_ID.getMMKVData(0)
+                    isLockCabinetSlots.slotType = DeviceConst.DEVICE_TYPE_LOCK.toString()
+                    isLockCabinetSlots.row = dockBean.row.toString()
+                    isLockCabinetSlots.col = (index + 1).toString()
+                    isLockCabinetSlots
+                }
+                hardwareRepository.saveCabinetSlots(slots)
+            }
+
+            DeviceConst.DOCK_TYPE_PORTABLE -> {
+                val slots = dockBean.deviceList.mapIndexed { index, device ->
+                    var isLockCabinetSlots = IsLockCabinetSlots()
+                    isLockCabinetSlots.cabinetId = MMKVConstants.KEY_LOCK_CABINET_ID.getMMKVData(0)
+                    isLockCabinetSlots.row = dockBean.row.toString()
+                    isLockCabinetSlots.col = (index + 1).toString()
+                    if (device is DockBean.KeyBean) {
+                        isLockCabinetSlots.slotType = DeviceConst.DEVICE_TYPE_KEY.toString()
+                    } else if (device is DockBean.LockBean) {
+                        isLockCabinetSlots.slotType = DeviceConst.DEVICE_TYPE_LOCK.toString()
+                    }
+                    isLockCabinetSlots
+                }
+                hardwareRepository.saveCabinetSlots(slots)
+            }
+        }
+    }
+
     /**
      * 设备录入(钥匙和挂锁)
      */
     fun deviceRegistrationData(): LiveData<Triple<Boolean, Int, Int>> {
         return liveData(Dispatchers.IO) {
-            val deviceList =
-                ModBusController.dockList.map { it.deviceList }.flatten()
+            val dockList = ModBusController.dockList
+            val deviceList = dockList.map { it.deviceList }.flatten()
+            dockList.forEach {
+                deviceInputSlotsSuspend(it)
+            }
             val lockDevice = deviceList.filter { it.type == DeviceConst.DEVICE_TYPE_LOCK }
                 .filterIsInstance<DockBean.LockBean>().filter { it.newHardware == true }
             val keyDevice = deviceList.filter { it.type == DeviceConst.DEVICE_TYPE_KEY }
@@ -281,4 +312,23 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
             emit(true)
         }
     }
+
+    /**
+     * 清除锁仓数据
+     */
+    fun clearLockCabinetSlots(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            hardwareRepository.clearCabinetSlots()
+        }
+    }
+
+    /**
+     * 创建锁柜数据
+     */
+    fun createLockCabinetData(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            hardwareRepository.createCabinetData()
+            emit(true)
+        }
+    }
 }

+ 1 - 1
app/src/main/java/com/grkj/iscs/features/main/fragment/hardware_manage/HardwareManageHomeFragment.kt

@@ -102,7 +102,7 @@ class HardwareManageHomeFragment : BaseFragment<FragmentHardwareManageHomeBindin
         BottomNavVisibilityEvent.sendBottomNavVisibilityEvent(false)
         when (menuType) {
             0 -> {
-
+                navController.navigate(R.id.action_hardwareManageHomeFragment_to_slotsManageFragment)
             }
 
             1 -> {

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

@@ -0,0 +1,178 @@
+package com.grkj.iscs.features.main.fragment.hardware_manage
+
+import android.widget.LinearLayout
+import androidx.core.view.isVisible
+import androidx.fragment.app.viewModels
+import com.drake.brv.BindingAdapter
+import com.drake.brv.annotaion.DividerOrientation
+import com.drake.brv.utils.dividerSpace
+import com.drake.brv.utils.linear
+import com.drake.brv.utils.models
+import com.drake.brv.utils.setup
+import com.google.android.flexbox.AlignItems
+import com.google.android.flexbox.FlexDirection
+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.utils.modbus.DeviceConst
+import com.grkj.ui_base.utils.modbus.DockBean
+import com.grkj.ui_base.utils.modbus.ModBusController
+import com.sik.sikcore.extension.setDebouncedClickListener
+import dagger.hilt.android.AndroidEntryPoint
+
+/**
+ * 仓位管理
+ */
+@AndroidEntryPoint
+class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
+    private val viewModel: SlotsManageViewModel by viewModels()
+    override fun getLayoutId(): Int {
+        return R.layout.fragment_slots_manage
+    }
+
+    override fun initView() {
+        binding.back.setDebouncedClickListener {
+            viewModel.unregisterStatusListener()
+            navController.popBackStack()
+        }
+        binding.dockRv.linear().dividerSpace(10, 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)
+            onBind {
+                when (val model = getModel<Any>()) {
+                    is DockData.KeyDock -> {
+                        onKeyDockRVListBinding(model)
+                    }
+
+                    is DockData.LockDock -> {
+                        onLockDockRVListBinding(model)
+                    }
+
+                    is DockData.PortableDock -> {
+                        onPortableDockRVListBinding(model)
+                    }
+                }
+            }
+        }
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onKeyDockRVListBinding(
+        keyDock: DockData.KeyDock,
+    ) {
+        val itemBinding = getBinding<ItemDeviceRegistrationKeyLayoutBinding>()
+        itemBinding.rvKeyLayout.layoutManager = FlexboxLayoutManager(context).apply {
+            flexDirection = FlexDirection.ROW               // 横向
+            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
+                }
+            }.models = keyDock.keyData
+    }
+
+
+    private fun BindingAdapter.BindingViewHolder.onLockDockRVListBinding(
+        lockDock: DockData.LockDock,
+    ) {
+        val itemBinding = getBinding<ItemDeviceRegistrationLockLayoutBinding>()
+        itemBinding.rvLockLayout.layoutManager = FlexboxLayoutManager(context).apply {
+            flexDirection = FlexDirection.ROW               // 横向
+            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
+                }
+            }.models = lockDock.lockData
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onPortableDockRVListBinding(
+        portableDock: DockData.PortableDock,
+    ) {
+        val itemBinding = getBinding<ItemDeviceRegistrationKeyLayoutBinding>()
+        itemBinding.rvKeyLayout.layoutManager = FlexboxLayoutManager(context).apply {
+            flexDirection = FlexDirection.ROW               // 横向
+            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
+                        }
+
+                        is DockBean.LockBean -> {
+                            val itemLockBinding = getBinding<ItemDeviceSlotManageLockBinding>()
+                            itemLockBinding.root.isSelected = itemPortable.isExist
+                        }
+                    }
+                }
+            }.models = portableDock.deviceData
+    }
+
+    override fun initData() {
+        super.initData()
+        viewModel.registerStatusListener {
+            getData()
+        }
+    }
+
+    /**
+     * 获取并加载数据
+     */
+    private fun getData() {
+        val dockData =
+            ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
+        val keyDock = dockData.filter { it.type == DeviceConst.DOCK_TYPE_KEY }.map {
+            DockData.KeyDock().apply {
+                keyData.addAll(it.deviceList.filterIsInstance<DockBean.KeyBean>())
+            }
+        }
+        val keyDatas = keyDock.map { it.keyData }.flatten()
+        val newKeyDock = DockData.KeyDock()
+        newKeyDock.keyData.addAll(keyDatas)
+        val newKeyDockList = newKeyDock.keyData.chunked(4).map { subList ->
+            DockData.KeyDock().apply { keyData.addAll(subList) }
+        }
+        val lockDock = dockData.filter { it.type == DeviceConst.DOCK_TYPE_LOCK }.map {
+            DockData.LockDock().apply {
+                lockData.addAll(it.deviceList.filterIsInstance<DockBean.LockBean>())
+            }
+        }
+        val portableDock =
+            dockData.filter { it.type == DeviceConst.DOCK_TYPE_PORTABLE }.map {
+                DockData.PortableDock().apply {
+                    deviceData.addAll(it.deviceList.toList())
+                }
+            }
+        binding.dockRv.models = newKeyDockList + portableDock + lockDock
+    }
+
+}

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

@@ -0,0 +1,65 @@
+package com.grkj.iscs.features.main.viewmodel.hardware_manage
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.liveData
+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
+import kotlinx.coroutines.Dispatchers
+import javax.inject.Inject
+
+/**
+ * 仓位管理数据模型
+ */
+@HiltViewModel
+class SlotsManageViewModel @Inject constructor(
+    val hardwareRepository: IHardwareRepository
+) : BaseViewModel() {
+    /**
+     * 异常仓位
+     */
+    var exceptionSlotsData: List<IsLockCabinetSlots> = listOf()
+
+    /**
+     * 异常挂锁
+     */
+    var exceptionLockData: List<IsLock> = listOf()
+
+    /**
+     * 异常钥匙
+     */
+    var exceptionKeyData: List<IsKey> = listOf()
+
+    /**
+     * 注册监听
+     */
+    fun registerStatusListener(statusListener: () -> Unit) {
+        ModbusBusinessManager.registerStatusListener(this) {
+            statusListener()
+        }
+    }
+
+    /**
+     * 取消注册
+     */
+    fun unregisterStatusListener() {
+        ModbusBusinessManager.unregisterListener(this)
+    }
+
+    /**
+     * 获取异常数据
+     */
+    fun getExceptionData(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            exceptionSlotsData = hardwareRepository.getExceptionSlots()
+            exceptionLockData = hardwareRepository.getExceptionLock()
+            exceptionKeyData = hardwareRepository.getExceptionKey()
+            emit(true)
+        }
+    }
+}

+ 69 - 0
app/src/main/res/layout/fragment_slots_manage.xml

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="@dimen/common_spacing_2x"
+        android:background="@drawable/home_card_bg"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/title_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/common_spacing">
+
+            <ImageView
+                android:layout_width="@dimen/title_icon_size"
+                android:layout_height="@dimen/title_icon_size"
+                android:src="@mipmap/dock_no_key"
+                android:tint="@color/black" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:layout_weight="1"
+                android:text="@string/slots_manage_title"
+                android:textColor="@color/black"
+                android:textSize="@dimen/normal_text_size_25"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/back"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/common_btn"
+                android:drawableLeft="@mipmap/icon_back"
+                android:drawablePadding="@dimen/common_spacing"
+                android:gravity="center"
+                android:minHeight="@dimen/common_btn_height"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/back"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/divider_line_space"
+            android:background="@color/black" />
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_margin="@dimen/common_spacing_2x">
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/dock_rv"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_gravity="center" />
+        </FrameLayout>
+    </LinearLayout>
+</layout>

+ 34 - 0
app/src/main/res/layout/item_device_slot_manage_key.xml

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <ImageView
+            android:id="@+id/iv_key"
+            android:layout_width="@dimen/init_key_iv_width"
+            android:layout_height="@dimen/init_key_iv_height"
+            android:background="@drawable/dock_key_selector" />
+
+        <View
+            android:id="@+id/v_buckle_status"
+            android:layout_width="@dimen/common_status_circle_small"
+            android:layout_height="@dimen/common_status_circle_small"
+            android:layout_toRightOf="@+id/iv_key"
+            android:background="@drawable/common_status_circle"
+            android:visibility="invisible" />
+
+        <ImageView
+            android:id="@+id/exception_iv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignLeft="@+id/iv_key"
+            android:layout_alignTop="@+id/iv_key"
+            android:layout_alignRight="@+id/iv_key"
+            android:layout_alignBottom="@+id/iv_key"
+            android:src="@mipmap/icon_exception"
+            android:visibility="gone" />
+    </RelativeLayout>
+</layout>

+ 29 - 0
app/src/main/res/layout/item_device_slot_manage_lock.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginHorizontal="@dimen/common_spacing_small"
+        android:orientation="horizontal">
+
+        <FrameLayout
+            android:id="@+id/root"
+            android:layout_width="@dimen/init_lock_iv_width"
+            android:layout_height="@dimen/init_lock_iv_height"
+            android:background="@drawable/dock_lock_selector" />
+
+        <ImageView
+            android:id="@+id/exception_iv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignLeft="@+id/root"
+            android:layout_alignTop="@+id/root"
+            android:layout_alignRight="@+id/root"
+            android:layout_alignBottom="@+id/root"
+            android:src="@mipmap/icon_exception"
+            android:visibility="gone"/>
+    </RelativeLayout>
+
+</layout>

BIN
app/src/main/res/mipmap-xhdpi/icon_exception.png


+ 7 - 0
app/src/main/res/navigation/nav_hardware_manage.xml

@@ -20,6 +20,9 @@
         <action
             android:id="@+id/action_hardwareManageHomeFragment_to_keyManageFragment"
             app:destination="@id/keyManageFragment" />
+        <action
+            android:id="@+id/action_hardwareManageHomeFragment_to_slotsManageFragment"
+            app:destination="@id/slotsManageFragment" />
     </fragment>
     <fragment
         android:id="@+id/keyManageFragment"
@@ -37,4 +40,8 @@
         android:id="@+id/rfidTokenManageFragment"
         android:name="com.grkj.iscs.features.main.fragment.hardware_manage.RfidTokenManageFragment"
         android:label="RfidTokenManageFragment" />
+    <fragment
+        android:id="@+id/slotsManageFragment"
+        android:name="com.grkj.iscs.features.main.fragment.hardware_manage.SlotsManageFragment"
+        android:label="SlotsManageFragment" />
 </navigation>

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

@@ -396,5 +396,6 @@
     <string name="job_card_set_tip">You have set up work card data</string>
     <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>
 
 </resources>

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

@@ -396,5 +396,6 @@
     <string name="job_card_set_tip">您已设置了工卡数据</string>
     <string name="set_job_card_title">设置工卡</string>
     <string name="job_card_scan_tip">请在读卡器上读卡</string>
+    <string name="slots_manage_title">仓位管理</string>
 
 </resources>

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

@@ -399,5 +399,6 @@
     <string name="job_card_set_tip">您已设置了工卡数据</string>
     <string name="set_job_card_title">设置工卡</string>
     <string name="job_card_scan_tip">请在读卡器上读卡</string>
+    <string name="slots_manage_title">仓位管理</string>
 
 </resources>

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

@@ -8,6 +8,7 @@ import androidx.room.Update
 import com.grkj.data.model.dos.IsJobCard
 import com.grkj.data.model.dos.IsKey
 import com.grkj.data.model.dos.IsLock
+import com.grkj.data.model.dos.IsLockCabinet
 import com.grkj.data.model.dos.IsLockCabinetSlots
 import com.grkj.data.model.dos.IsRfidToken
 import com.grkj.data.model.local.LockData
@@ -409,4 +410,16 @@ interface HardwareDao {
      */
     @Query("select * from is_job_card where card_nfc = :rfidNo")
     fun getCardDataByRfid(rfidNo: String): IsJobCard?
+
+    /**
+     * 清除锁柜数据
+     */
+    @Query("delete from is_lock_cabinet where 1=1")
+    fun clearCabinetData()
+
+    /**
+     * 新增锁柜数据
+     */
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    fun createCabinetData(isLockCabinet: IsLockCabinet): Long
 }

+ 7 - 2
data/src/main/java/com/grkj/data/data/MMKVConstants.kt

@@ -23,15 +23,20 @@ object MMKVConstants {
     /**
      * 更新隔离点锁模式
      */
-    const val UPDATE_LOCK_POINT_MODE= "update_lock_point_mode"
+    const val UPDATE_LOCK_POINT_MODE = "update_lock_point_mode"
 
     /**
      * APP初始化
      */
-    const val APP_INIT= "app_init"
+    const val APP_INIT = "app_init"
 
     /**
      * 服务器地址
      */
     const val SERVER_ADDRESS = "server_address"
+
+    /**
+     * 锁柜id
+     */
+    const val KEY_LOCK_CABINET_ID = "key_lock_cabinet_id"
 }

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

@@ -3,6 +3,7 @@ package com.grkj.data.repository
 import com.grkj.data.model.dos.IsJobCard
 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.model.dos.IsRfidToken
 import com.grkj.data.model.local.LockData
 import com.grkj.data.model.local.PointData
@@ -239,4 +240,34 @@ interface IHardwareRepository {
      * 更新用户工卡
      */
     fun updateUserJobCard(rfidNo: String, userId: Long)
+
+    /**
+     * 获取异常钥匙
+     */
+    fun getExceptionKey(): List<IsKey>
+
+    /**
+     * 获取异常挂锁
+     */
+    fun getExceptionLock(): List<IsLock>
+
+    /**
+     * 获取异常锁仓
+     */
+    fun getExceptionSlots(): List<IsLockCabinetSlots>
+
+    /**
+     * 创建锁柜数据
+     */
+    fun createCabinetData()
+
+    /**
+     * 保存锁仓数据
+     */
+    fun saveCabinetSlots(isLockCabinetSlots: List<IsLockCabinetSlots>)
+
+    /**
+     * 清除锁仓数据
+     */
+    fun clearCabinetSlots()
 }

+ 29 - 0
data/src/main/java/com/grkj/data/repository/impl/HardwareRepository.kt

@@ -2,10 +2,14 @@ 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
 import com.grkj.data.model.dos.IsKey
 import com.grkj.data.model.dos.IsLock
+import com.grkj.data.model.dos.IsLockCabinet
+import com.grkj.data.model.dos.IsLockCabinetSlots
 import com.grkj.data.model.dos.IsRfidToken
 import com.grkj.data.model.local.LockData
 import com.grkj.data.model.local.PointData
@@ -27,6 +31,7 @@ import com.grkj.data.model.vo.LockManageFilterVo
 import com.grkj.data.model.vo.RfidTokenManageFilterVo
 import com.grkj.data.repository.BaseRepository
 import com.sik.sikcore.data.BeanUtils
+import com.sik.sikcore.extension.saveMMKVData
 import javax.inject.Inject
 import javax.inject.Singleton
 
@@ -385,4 +390,28 @@ class HardwareRepository @Inject constructor(
         }
         hardwareDao.updateCardInfo(jobCardData)
     }
+
+    override fun getExceptionKey(): List<IsKey> {
+        return hardwareDao.getAllKeyData()
+            .filter { it.exStatus == CommonDictDataEnum.KEY_STATUS.commonDictRes.find { it.dictLabel == "异常" }?.dictValue }
+    }
+
+    override fun getExceptionLock(): List<IsLock> {
+        return hardwareDao.getAllLockData()
+            .filter { it.exStatus == CommonDictDataEnum.PADLOCK_STATUS.commonDictRes.find { it.dictLabel == "异常" }?.dictValue }
+    }
+
+    override fun getExceptionSlots(): List<IsLockCabinetSlots> {
+        return hardwareDao.getAllLockCabinetSlots()
+            .filter { it.status == CommonDictDataEnum.SLOT_STATUS.commonDictRes.find { it.dictLabel == "异常" }?.dictValue }
+    }
+
+    override fun createCabinetData() {
+        hardwareDao.clearCabinetData()
+        val isLockCabinet = IsLockCabinet()
+        isLockCabinet.cabinetCode = "CABINET_001"
+        isLockCabinet.cabinetName = "锁柜1"
+        val lockCabinetId = hardwareDao.createCabinetData(isLockCabinet)
+        MMKVConstants.KEY_LOCK_CABINET_ID.saveMMKVData(lockCabinetId)
+    }
 }

+ 1 - 0
ui-base/build.gradle.kts

@@ -65,6 +65,7 @@ dependencies {
     api("io.github.scwang90:refresh-layout-kernel:3.0.0-alpha")
     api("io.github.scwang90:refresh-header-classics:3.0.0-alpha")
     api("io.github.scwang90:refresh-footer-classics:3.0.0-alpha")
+    api("com.google.android.flexbox:flexbox:3.0.0")
 //    api("com.licheedev:android-serialport:2.1.5")
     implementation(project(":data"))
     implementation(project(":shared"))