Browse Source

refactor(更新) :
- 钥匙和挂锁的录入半完成,目前只是钥匙全关闭状态好使

周文健 5 tháng trước cách đây
mục cha
commit
94fe378b8d

+ 27 - 1
app/src/main/java/com/grkj/iscs/BusinessManager.kt

@@ -421,7 +421,9 @@ object BusinessManager {
                                                     )
                                                 } else {
                                                     LogUtil.e("Get key info fail : $rfid")
-                                                    ToastUtils.tip(R.string.get_key_info_fail)
+                                                    if (!ISCSDomainData.isDeviceEnter) {
+                                                        ToastUtils.tip(R.string.get_key_info_fail)
+                                                    }
                                                     ModBusController.controlKeyBuckle(
                                                         true, keyBean.isLeft, dockBean.addr
                                                     )
@@ -1096,6 +1098,30 @@ object BusinessManager {
         return jsonStr
     }
 
+    /**
+     * 生成下空发工作票Json
+     *
+     * @param vo 工作票详情
+     */
+    fun generateEmptyTicketSendJson(): String {
+        // 构造一个所有字段都为空/默认值的 WorkTicketSendBO
+        val bo = WorkTicketSendBO(
+            cardNo = "",          // 空卡号
+            effectiveTime = 0,    // 默认有效时长
+            password = ""         // 空密码
+        ).apply {
+            // data 列表留空
+            data = mutableListOf()
+            // lockList 留空(如果字段非空,再设置为 emptyList())
+            lockList = mutableListOf()
+        }
+
+        // 转成 JSON 并返回
+        val jsonStr = Gson().toJson(bo)
+        LogUtil.i("generateEmptyTicketJson: $jsonStr")
+        return jsonStr
+    }
+
     fun handleRsp(
         bleBean: BleBean,
         byteArray: ByteArray,

+ 88 - 48
app/src/main/java/com/grkj/iscs/ble/BleConnectionManager.kt

@@ -21,7 +21,6 @@ import com.grkj.iscs.model.Constants.PERMISSION_REQUEST_CODE
 import com.grkj.iscs.model.eventmsg.LoadingMsg
 import com.grkj.iscs.model.eventmsg.MsgEvent
 import com.grkj.iscs.model.eventmsg.MsgEventConstants.MSG_EVENT_LOADING
-import com.grkj.iscs.model.eventmsg.SwitchModeMsg
 import com.grkj.iscs.util.ActivityUtils
 import com.grkj.iscs.util.CommonUtils
 import com.grkj.iscs.util.Executor
@@ -179,22 +178,6 @@ object BleConnectionManager {
         }
     }
 
-    /**
-     * 添加到待机队列并断开最旧超出连接
-     */
-    private fun addToStandby(mac: String) {
-        synchronized(standbyQueue) {
-            standbyQueue.addLast(mac)
-            while (standbyQueue.size > maxStandbyCount) {
-                val oldMac = standbyQueue.removeFirst()
-                deviceList.find { it.bleDevice.mac == oldMac }?.let { oldBean ->
-                    LogUtil.i("断开最旧待机设备: $oldMac")
-                    BleManager.getInstance().disconnect(oldBean.bleDevice)
-                }
-            }
-        }
-    }
-
     /**
      * @param loadingCallBack 是否显示loading、loading文字、流程是否结束
      * @param prepareDoneCallBack 蓝牙连接是否成功、蓝牙连接对象
@@ -582,7 +565,6 @@ object BleConnectionManager {
      */
     suspend fun scanOnlineKeyLockMacAndSwitchModeToClose(): Boolean {
         return suspendCancellableCoroutine { parentCont ->
-            val keyMacs: MutableList<BleDevice> = mutableListOf()
             BleUtil.instance?.scan(object : CustomBleScanCallback() {
                 override fun onPrompt(promptStr: String?) {
                     // 蓝牙未启动重试
@@ -605,42 +587,16 @@ object BleConnectionManager {
                 override fun onScanning(bleDevice: BleDevice?) {
                     val mac = bleDevice?.mac ?: return
                     LogUtil.i("设备录入-onScanning:$mac")
-                    keyMacs.add(bleDevice)
                 }
 
                 override fun onScanFinished(scanResultList: MutableList<BleDevice>?) {
+                    val devicesSnapshot = scanResultList?.toList().orEmpty()
                     ThreadUtils.runOnIO {
-                        keyMacs.forEach {
+                        devicesSnapshot.forEach {
                             val connected = tryConnectWithOptionalCharge(it.mac, false)
                             if (connected) {
-                                suspend fun switchReadyMode(bleDevice: BleDevice): Boolean {
-                                    return suspendCancellableCoroutine<Boolean> { cont ->
-                                        BleCmdManager.switchMode(
-                                            BleConst.STATUS_READY,
-                                            bleDevice,
-                                            object : CustomBleWriteCallback() {
-                                                override fun onWriteSuccess(
-                                                    current: Int,
-                                                    total: Int,
-                                                    justWrite: ByteArray?
-                                                ) {
-                                                    BleManager.getInstance().disconnect(bleDevice)
-                                                    cont.resume(true)
-                                                    LogUtil.i("设备录入-切换模式发送成功 : ${bleDevice.mac}")
-                                                }
-
-                                                override fun onWriteFailure(exception: BleException?) {
-                                                    LogUtil.e("设备录入-切换模式发送失败 : ${bleDevice.mac}")
-                                                    ThreadUtils.runOnMainDelayed(300) {
-                                                        cont.resume(switchReadyMode(bleDevice))
-                                                    }
-                                                }
-                                            })
-                                    }
-                                }
-
-                                val sendSuccess = switchReadyMode(it)
-                                LogUtil.i("设备录入-发送切换待机模式:${it.mac},${sendSuccess}")
+                                val sendSuccess = sendEmptyTicketJson(it)
+                                LogUtil.i("设备录入-发送切换工作模式:${it.mac},${sendSuccess}")
                             }
                         }
                         parentCont.resume(true)
@@ -650,6 +606,90 @@ object BleConnectionManager {
         }
     }
 
+    /**
+     * 发送空作业票
+     */
+    private suspend fun sendEmptyTicketJson(bleDevice: BleDevice): Boolean {
+        return suspendCancellableCoroutine<Boolean> { cont ->
+            BleCmdManager.sendWorkTicket(
+                BusinessManager.generateEmptyTicketSendJson(),
+                bleDevice = bleDevice,
+                callback = object : CustomBleWriteCallback() {
+                    override fun onWriteSuccess(
+                        current: Int,
+                        total: Int,
+                        justWrite: ByteArray?
+                    ) {
+                        ThreadUtils.runOnIO {
+                            delay(3000)
+                            cont.resume(switchWorkMode(bleDevice))
+                        }
+                    }
+
+                    override fun onWriteFailure(exception: BleException?) {
+                        ThreadUtils.runOnMainDelayed(300) {
+                            cont.resume(sendEmptyTicketJson(bleDevice))
+                        }
+                    }
+                })
+        }
+    }
+
+    /**
+     * 切换工作模式
+     */
+    private suspend fun switchWorkMode(bleDevice: BleDevice): Boolean {
+        return suspendCancellableCoroutine<Boolean> { cont ->
+            BleCmdManager.switchMode(
+                BleConst.STATUS_WORK,
+                bleDevice,
+                object : CustomBleWriteCallback() {
+                    override fun onWriteSuccess(
+                        current: Int,
+                        total: Int,
+                        justWrite: ByteArray?
+                    ) {
+                        BleManager.getInstance().disconnect(bleDevice)
+                        ThreadUtils.runOnIO {
+                            delay(800)
+                            cont.resume(true)
+                        }
+                        LogUtil.i("设备录入-切换模式发送成功 : ${bleDevice.mac}")
+                    }
+
+                    override fun onWriteFailure(exception: BleException?) {
+                        LogUtil.e("设备录入-切换模式发送失败 : ${bleDevice.mac}")
+                        ThreadUtils.runOnMainDelayed(300) {
+                            cont.resume(sendEmptyTicketJson(bleDevice))
+                        }
+                    }
+                })
+        }
+    }
+
+    /**
+     * 切换待机模式
+     */
+    fun switchReadyMode(bleDevice: BleDevice) {
+        BleCmdManager.switchMode(
+            BleConst.STATUS_READY,
+            bleDevice,
+            object : CustomBleWriteCallback() {
+                override fun onWriteSuccess(
+                    current: Int,
+                    total: Int,
+                    justWrite: ByteArray?
+                ) {
+                    BleManager.getInstance().disconnect(bleDevice)
+                    LogUtil.i("设备录入-切换模式发送成功 : ${bleDevice.mac}")
+                }
+
+                override fun onWriteFailure(exception: BleException?) {
+                    LogUtil.e("设备录入-切换模式发送失败 : ${bleDevice.mac}")
+                }
+            })
+    }
+
     /**
      * 扫描在线的蓝牙
      */

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

@@ -4,10 +4,10 @@ object UrlConsts {
     //    const val BASE_URL = "http://192.168.28.82:9190"  // 本地
 //    const val BASE_URL = "http://192.168.28.97:9190"    // 车
 //    const val BASE_URL = "http://36.133.174.236:9190"    // 外
-    const val BASE_URL = "http://192.168.0.10:9190"    // 外
+//    const val BASE_URL = "http://192.168.0.10:9190"    // 外
 //    const val BASE_URL = "http://192.168.1.121:9190"    // 外
 
-    //    const val BASE_URL = "http://120.27.232.27:9190"    // 外
+    const val BASE_URL = "http://120.27.232.27:9190"    // 外
     const val WEB_SOCKET = "ws://192.168.1.127:9090/websocket/iot/127"
 
     const val AUTOCODE_TICKET_NUMBER = "JOB_TICKET_CODE"

+ 3 - 2
app/src/main/java/com/grkj/iscs/view/fragment/DeviceInputKeyAndLockFragment.kt

@@ -54,7 +54,7 @@ class DeviceInputKeyAndLockFragment :
         LogUtil.d("设备录入-打开所有钥匙仓并关闭充电")
         ModBusController.controlAllKeyBuckleOpen()
         viewModel.registerInitListener().observe(this) {
-            LogUtil.d("设备录入-初始化检测完成")
+            LogUtil.d("设备录入-初始化检测任务分发完成")
         }
         viewModel.initData(mRowList)
         binding.cbBack.setDebouncedClickListener {
@@ -62,8 +62,9 @@ class DeviceInputKeyAndLockFragment :
         }
         viewModel.isLoadComplete.observe(this) {
             binding.scanTip.isVisible = !it
-            binding.rvDock.isVisible = it
+            binding.rvDockLayout.isVisible = it
             binding.cbRescanOrInput.isVisible = it
+            binding.scanResultTip.text = requireContext().getString(R.string.device_input_scan_result_tip,viewModel.newHardwareKeySize,viewModel.newHardwareLockSize)
         }
         binding.cbRescanOrInput.setDebouncedClickListener {
             if (isAlreadyInput) {

+ 84 - 24
app/src/main/java/com/grkj/iscs/view/viewmodel/DeviceInputKeyAndLockViewModel.kt

@@ -3,6 +3,7 @@ package com.grkj.iscs.view.viewmodel
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.liveData
+import com.clj.fastble.BleManager
 import com.google.gson.Gson
 import com.google.gson.reflect.TypeToken
 import com.grkj.iscs.BusinessManager
@@ -22,6 +23,7 @@ import com.sik.sikcore.thread.ThreadUtils
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.suspendCancellableCoroutine
+import java.util.concurrent.atomic.AtomicInteger
 import kotlin.collections.iterator
 import kotlin.coroutines.resume
 
@@ -30,13 +32,17 @@ class DeviceInputKeyAndLockViewModel : BaseViewModel() {
     val isLoadComplete: MutableLiveData<Boolean> = MutableLiveData(false)
     var isStartCheckKey: Boolean = false
     var isDestroy: Boolean = false
+    var newHardwareKeySize: Int = 0
+    var newHardwareLockSize: Int = 0
     private val newHardwareKeyBean: MutableMap<Byte, MutableList<DockBean.KeyBean>> = mutableMapOf()
 
     fun initData(rowList: MutableList<DockStatusBO>) {
-        val dockConfigJson = SPUtils.getDockConfig(MyApplication.Companion.instance?.applicationContext!!)
+        val dockConfigJson =
+            SPUtils.getDockConfig(MyApplication.Companion.instance?.applicationContext!!)
         if (!dockConfigJson.isNullOrEmpty()) {
             val tempList: MutableList<DockTestFragment.DockTestBean> = Gson().fromJson(
-                dockConfigJson, object : TypeToken<MutableList<DockTestFragment.DockTestBean>>() {}.type
+                dockConfigJson,
+                object : TypeToken<MutableList<DockTestFragment.DockTestBean>>() {}.type
             )
             if (tempList.isNotEmpty()) {
                 tempList.forEach { dock ->
@@ -65,6 +71,20 @@ class DeviceInputKeyAndLockViewModel : BaseViewModel() {
         }
     }
 
+    fun checkNewHardware(device: DockBean.DeviceBean, callback: () -> Unit) {
+        if (device is DockBean.KeyBean) {
+            NetApi.getKeyInfo(device.rfid.toString()) {
+                device.newHardware = it == null
+                callback()
+            }
+        } else if (device is DockBean.LockBean) {
+            NetApi.getLockInfo(device.rfid.toString()) {
+                device.newHardware = it == null
+                callback()
+            }
+        }
+    }
+
     fun registerInitListener(): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
             isStartCheckKey = false
@@ -73,36 +93,59 @@ class DeviceInputKeyAndLockViewModel : BaseViewModel() {
             val allDeviceCloseCmdSend =
                 BleConnectionManager.scanOnlineKeyLockMacAndSwitchModeToClose()
             LogUtil.i("设备录入-是否所有关闭命令发送成功:${allDeviceCloseCmdSend}")
+            BleManager.getInstance().disconnectAllDevice()
             BusinessManager.registerInitListener {
                 if (isStartCheckKey) {
                     return@registerInitListener
                 }
                 isStartCheckKey = true
                 val dockList = ModBusController.dockList
-
-                newHardwareKeyBean.putAll(dockList.filter { it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
-                    .associate {
-                        it.addr to it.deviceList.filterIsInstance<DockBean.KeyBean>()
-                            .filter { it.newHardware && it.isExist }
-                            .toMutableList()
-                    })
-                LogUtil.d("设备录入-新设备:${newHardwareKeyBean}")
                 ThreadUtils.runOnIO {
-                    for ((addr, keyBeans) in newHardwareKeyBean) {
-                        for (keyBean in keyBeans) {
-                            if (isDestroy) {
-                                return@runOnIO
+                    val allDevice = ModBusController.dockList.map { it.deviceList }.flatten()
+                        .filter { it is DockBean.KeyBean || it is DockBean.LockBean }
+                        .filter { it.isExist }
+                    var currentCheckDevices = AtomicInteger(0)
+                    allDevice.forEach { device ->
+                        checkNewHardware(device) {
+                            currentCheckDevices.addAndGet(1)
+                            if (currentCheckDevices.get() == allDevice.size) {
+                                checkNewHardwareKey(dockList)
                             }
-                            openChargeAndScanMac(addr, keyBean)
                         }
                     }
-                    isLoadComplete.postValue(true)
                     emit(true)
                 }
             }
         }
     }
 
+    private fun checkNewHardwareKey(dockList: MutableList<DockBean>) {
+        ThreadUtils.runOnIO {
+            LogUtil.i("设备录入-重新检测是否是新设备完成")
+            newHardwareKeyBean.putAll(dockList.filter { it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
+                .associate {
+                    it.addr to it.deviceList.filterIsInstance<DockBean.KeyBean>()
+                        .filter { it.newHardware && it.isExist }
+                        .toMutableList()
+                })
+            LogUtil.d("设备录入-新设备:${newHardwareKeyBean}")
+            for ((addr, keyBeans) in newHardwareKeyBean) {
+                for (keyBean in keyBeans) {
+                    if (isDestroy) {
+                        return@runOnIO
+                    }
+                    openChargeAndScanMac(addr, keyBean)
+                }
+            }
+            newHardwareKeySize = newHardwareKeyBean.map { it.value }.flatten().size
+            newHardwareLockSize =
+                ModBusController.dockList.filter { it.type == DeviceConst.DOCK_TYPE_LOCK || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
+                    .map { it.deviceList }.flatten().filterIsInstance<DockBean.LockBean>()
+                    .count { it.newHardware && it.isExist }
+            isLoadComplete.postValue(true)
+        }
+    }
+
     /**
      * 打开充电并扫描蓝牙
      */
@@ -111,7 +154,7 @@ class DeviceInputKeyAndLockViewModel : BaseViewModel() {
             LogUtil.i("设备录入-关闭充电:${addr},${keyBean.idx}")
             ModBusController.controlKeyCharge(false, keyBean.isLeft, addr) {
                 ThreadUtils.runOnIO {
-                    delay(3000)
+                    delay(800)
                     LogUtil.i("设备录入-打开充电:${addr},${keyBean.idx}")
                     ModBusController.controlKeyLockAndCharge(true, keyBean.isLeft, addr) {
                         ThreadUtils.runOnIO {
@@ -125,11 +168,12 @@ class DeviceInputKeyAndLockViewModel : BaseViewModel() {
                                         ) { it.mac }
                                     }"
                                 )
+                                if (isDestroy) {
+                                    cont.cancel()
+                                    return@scanOnlineKeyLockMac
+                                }
                                 if (bleDevices?.isEmpty() == true) {
                                     ThreadUtils.runOnIO {
-                                        if (isDestroy) {
-                                            return@runOnIO
-                                        }
                                         openChargeAndScanMac(addr, keyBean)
                                     }
                                 } else {
@@ -142,10 +186,23 @@ class DeviceInputKeyAndLockViewModel : BaseViewModel() {
                                             }?.mac
                                         }"
                                     )
-                                    keyBean.mac = bleDevices?.find {
+                                    val bleDevice = bleDevices?.find {
                                         it.mac !in newHardwareKeyBean.map { it.value }.flatten()
                                             .map { it.mac }
-                                    }?.mac
+                                    }
+                                    keyBean.mac = bleDevice?.mac
+                                    ThreadUtils.runOnIO {
+                                        keyBean.mac?.let {
+                                            val connected =
+                                                BleConnectionManager.tryConnectWithOptionalCharge(it)
+                                            if (connected) {
+                                                bleDevice?.let {
+                                                    BleConnectionManager.switchReadyMode(it)
+                                                }
+                                            }
+                                        }
+                                    }
+
                                     cont.resume(true)
                                 }
                             }
@@ -198,8 +255,11 @@ class DeviceInputKeyAndLockViewModel : BaseViewModel() {
                 .filterIsInstance<DockBean.LockBean>().filter { it.newHardware == true }
             val keyDevice = deviceList.filter { it.type == DeviceConst.DEVICE_TYPE_KEY }
                 .filterIsInstance<DockBean.KeyBean>().filter { it.newHardware == true }
-            lockDevice.filter { it.rfid?.isNotEmpty() == true }.map { it.rfid }.forEach { rfid ->
-                deviceInputLockSuspend(rfid.toString())
+            lockDevice.filter { it.rfid?.isNotEmpty() == true }.forEach { lockDevice ->
+                val isBind = deviceInputLockSuspend(lockDevice.rfid.toString())
+                if (isBind) {
+                    lockDevice.newHardware = false
+                }
             }
             keyDevice.filter { it.rfid?.isNotEmpty() == true && it.mac?.isNotEmpty() == true }
                 .forEach { keyDevice ->

+ 22 - 6
app/src/main/res/layout/fragment_device_input_key_and_lock.xml

@@ -10,12 +10,28 @@
         android:padding="@dimen/common_spacing"
         tools:context=".view.fragment.DeviceStatusFragment">
 
-        <androidx.recyclerview.widget.RecyclerView
-            android:id="@+id/rv_dock"
-            style="@style/CommonRecyclerView"
+        <LinearLayout
+            android:id="@+id/rv_dock_layout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
             android:layout_above="@+id/cb_back"
             android:layout_marginBottom="10dp"
-            android:visibility="gone"/>
+            android:orientation="vertical"
+            android:visibility="gone">
+
+            <TextView
+                android:id="@+id/scan_result_tip"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:textColor="@color/color_d7d2d2"
+                android:textSize="18sp" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_dock"
+                style="@style/CommonRecyclerView"
+                android:layout_above="@+id/cb_back"
+                android:layout_marginBottom="10dp" />
+        </LinearLayout>
 
         <TextView
             android:id="@+id/scan_tip"
@@ -23,9 +39,9 @@
             android:layout_height="wrap_content"
             android:layout_centerInParent="true"
             android:gravity="center"
+            android:text="@string/device_input_scan_key_and_lock_tip"
             android:textColor="@color/color_d7d2d2"
-            android:textSize="18sp"
-            android:text="@string/device_input_scan_key_and_lock_tip"/>
+            android:textSize="18sp" />
 
         <com.grkj.iscs.view.widget.CommonBtn
             android:id="@+id/cb_rescan_or_input"

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

@@ -381,4 +381,5 @@
     <string name="input_to_system">Enter to system</string>
     <string name="already_input_device_tip">%1$d keys and %2$d padlocks have been entered</string>
     <string name="input_device_error">entered error</string>
+    <string name="device_input_scan_result_tip">Identified unrecorded keys (%1$d) and padlocks (%2$d).</string>
 </resources>

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

@@ -381,4 +381,5 @@
     <string name="input_to_system">录入系统</string>
     <string name="already_input_device_tip">已录入%1$d把钥匙与%2$d把挂锁</string>
     <string name="input_device_error">录入失败</string>
+    <string name="device_input_scan_result_tip">已识别未录入的钥匙 (%1$d把)与挂锁(%2$d把)。</string>
 </resources>

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

@@ -381,4 +381,5 @@
     <string name="input_to_system">录入系统</string>
     <string name="already_input_device_tip">已录入%1$d把钥匙与%2$d把挂锁</string>
     <string name="input_device_error">录入失败</string>
+    <string name="device_input_scan_result_tip">已识别未录入的钥匙 (%1$d把)与挂锁(%2$d把)。</string>
 </resources>