Prechádzať zdrojové kódy

refactor(更新)
- 分组上锁和分组解锁完成
- 交叉作业的交叉点位的虚拟锁解锁完成

周文健 10 mesiacov pred
rodič
commit
39fcce2f7e
27 zmenil súbory, kde vykonal 432 pridanie a 253 odobranie
  1. BIN
      app/src/main/assets/data.db
  2. 76 66
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobExecuteFragment.kt
  3. 84 45
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobExecuteViewModel.kt
  4. 1 1
      app/src/main/res/layout-land/fragment_create_job.xml
  5. 1 0
      app/src/main/res/layout-land/item_locker_group.xml
  6. 1 0
      app/src/main/res/layout/item_locker_group.xml
  7. 2 0
      app/src/main/res/values-en/strings.xml
  8. 2 0
      app/src/main/res/values-zh/strings.xml
  9. 2 0
      app/src/main/res/values/strings.xml
  10. 22 5
      data/src/main/java/com/grkj/data/dao/JobTicketDao.kt
  11. 7 0
      data/src/main/java/com/grkj/data/data/MainDomainData.kt
  12. 4 0
      data/src/main/java/com/grkj/data/model/dos/IsJobTicketKey.kt
  13. 3 0
      data/src/main/java/com/grkj/data/model/dos/IsJobTicketLock.kt
  14. 1 1
      data/src/main/java/com/grkj/data/model/local/DeviceTakeUpdate.kt
  15. 7 0
      data/src/main/java/com/grkj/data/model/res/TicketDetailRes.kt
  16. 6 0
      data/src/main/java/com/grkj/data/model/vo/IsJobTicketPointsVo.kt
  17. 4 0
      data/src/main/java/com/grkj/data/model/vo/IsJobTicketUserDataVo.kt
  18. 5 0
      data/src/main/java/com/grkj/data/repository/IHardwareRepository.kt
  19. 9 2
      data/src/main/java/com/grkj/data/repository/IJobTicketRepository.kt
  20. 4 0
      data/src/main/java/com/grkj/data/repository/impl/network/NetworkHardwareRepository.kt
  21. 11 1
      data/src/main/java/com/grkj/data/repository/impl/network/NetworkJobTicketRepository.kt
  22. 12 5
      data/src/main/java/com/grkj/data/repository/impl/standard/HardwareRepository.kt
  23. 56 23
      data/src/main/java/com/grkj/data/repository/impl/standard/JobTicketRepository.kt
  24. 16 0
      ui-base/src/main/java/com/grkj/ui_base/base/BaseViewModel.kt
  25. 74 73
      ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt
  26. 6 3
      ui-base/src/main/java/com/grkj/ui_base/business/ModbusBusinessManager.kt
  27. 16 28
      ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleUtil.kt

BIN
app/src/main/assets/data.db


+ 76 - 66
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobExecuteFragment.kt

@@ -1,6 +1,7 @@
 package com.grkj.iscs.features.main.fragment.job_manage
 
 import android.graphics.drawable.GradientDrawable
+import android.view.Gravity
 import android.view.ViewGroup
 import android.widget.LinearLayout
 import androidx.core.view.isVisible
@@ -29,16 +30,17 @@ import com.grkj.shared.model.EventBean
 import com.grkj.ui_base.base.BaseFragment
 import com.grkj.data.data.EventConstants
 import com.grkj.data.data.MainDomainData
+import com.grkj.data.data.Type
 import com.grkj.data.model.dos.WorkflowStep
+import com.grkj.data.model.vo.JobTicketGroupInfoVo
 import com.grkj.iscs.features.main.dialog.CheckFaceDialog
-import com.grkj.ui_base.business.ModbusBusinessManager
 import com.grkj.ui_base.dialog.TipDialog
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.event.RFIDCardReadEvent
 import com.grkj.ui_base.utils.event.UiEvent
 import com.grkj.ui_base.utils.extension.tip
 import com.grkj.ui_base.utils.extension.toggleExpandView
-import com.grkj.ui_base.utils.modbus.DeviceConst
+import com.kongzue.dialogx.dialogs.PopMenu
 import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikcore.data.GlobalDataTempStore
 import com.sik.sikcore.extension.setDebouncedClickListener
@@ -89,66 +91,42 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
             }
         }
         binding.toLock.setDebouncedClickListener {
-            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
-                    DeviceConst.DEVICE_TYPE_LOCK,
-                    viewModel.ticketId
-                )
-            ) {
-                showLoading(getString(com.grkj.ui_base.R.string.please_take_out_ready_device_first))
+            if (viewModel.groupInfo.isEmpty()){
+                showToast(CommonUtils.getStr(R.string.not_group_can_lock).toString())
                 return@setDebouncedClickListener
             }
-            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
-                    DeviceConst.DEVICE_TYPE_KEY,
-                    viewModel.ticketId
-                )
-            ) {
-                showLoading(getString(com.grkj.ui_base.R.string.check_key_and_lock))
-                val rfid = ModbusBusinessManager.getWaitTakeDeviceByTicketId(
-                    DeviceConst.DEVICE_TYPE_KEY,
-                    viewModel.ticketId
-                )?.nfc
-                rfid?.let {
-                    val keyMac = ModbusBusinessManager.getKeyMacByRfid(it)
-                    ModbusBusinessManager.checkTicketAndSendTicket(keyMac)
-                    return@setDebouncedClickListener
-                } ?: run {
-                    hideLoading()
+            PopMenu.build().setBaseView(binding.toLock)
+                .setAlignGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL)
+                .apply {
+                    isOverlayBaseView = false
                 }
-            }
-            viewModel.toLock().observe(this) {
-
-            }
+                .setWidth(220)
+                .setMenuList(viewModel.groupInfo.map { it.groupName })
+                .setOnMenuItemClickListener { popMenu, itemText, position ->
+                    popMenu.dismiss()
+                    toLock(viewModel.groupInfo[position].groupId)
+                    true
+                }
+                .show(requireActivity())
         }
         binding.toUnlock.setDebouncedClickListener {
-            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
-                    DeviceConst.DEVICE_TYPE_LOCK,
-                    viewModel.ticketId
-                )
-            ) {
-                showLoading(getString(com.grkj.ui_base.R.string.please_take_out_ready_device_first))
+            if (viewModel.groupInfo.isEmpty()){
+                showToast(CommonUtils.getStr(R.string.not_group_can_unlock).toString())
                 return@setDebouncedClickListener
             }
-            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
-                    DeviceConst.DEVICE_TYPE_KEY,
-                    viewModel.ticketId
-                )
-            ) {
-                showLoading(getString(com.grkj.ui_base.R.string.check_key_and_lock))
-                val rfid = ModbusBusinessManager.getWaitTakeDeviceByTicketId(
-                    DeviceConst.DEVICE_TYPE_KEY,
-                    viewModel.ticketId
-                )?.nfc
-                rfid?.let {
-                    val keyMac = ModbusBusinessManager.getKeyMacByRfid(it)
-                    ModbusBusinessManager.checkTicketAndSendTicket(keyMac)
-                    return@setDebouncedClickListener
-                } ?: run {
-                    hideLoading()
+            PopMenu.build().setBaseView(binding.toUnlock)
+                .setAlignGravity(Gravity.TOP or Gravity.CENTER_HORIZONTAL)
+                .apply {
+                    isOverlayBaseView = false
                 }
-            }
-            viewModel.toUnLock().observe(this) {
-
-            }
+                .setWidth(220)
+                .setMenuList(viewModel.groupInfo.map { it.groupName })
+                .setOnMenuItemClickListener { popMenu, itemText, position ->
+                    popMenu.dismiss()
+                    toUnLock(viewModel.groupInfo[position].groupId)
+                    true
+                }
+                .show(requireActivity())
         }
         binding.waitToColockRv.grid(3).dividerSpace(10, DividerOrientation.GRID).setup {
             addType<IsJobTicketUserDataVo>(R.layout.item_job_execute_colock)
@@ -186,6 +164,18 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
         }
     }
 
+    private fun toLock(groupId: Long) {
+        viewModel.toLock(groupId).observe(this) {
+
+        }
+    }
+
+    private fun toUnLock(groupId: Long) {
+        viewModel.toUnLock(groupId).observe(this) {
+
+        }
+    }
+
     override suspend fun initObservers() {
         super.initObservers()
         repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -460,16 +450,18 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                                         TipDialog.showInfo(
                                             msg = CommonUtils.getStr(
                                                 com.grkj.ui_base.R.string.confirm_to_colock,
-                                                colocker.nickName?:""
+                                                colocker.nickName ?: ""
                                             ).toString(), countDownTime = 10, onConfirmClick = {
                                                 colocker.jobStatus = "1"
                                                 viewModel.colockerStatusChange(colocker)
                                                     .observe(this) {
                                                         if (it) {
-                                                            PopTip.build().tip(R.string.colock_complete)
+                                                            PopTip.build()
+                                                                .tip(R.string.colock_complete)
                                                             checkStepComplete()
                                                         } else {
-                                                            PopTip.build().tip(R.string.colock_failed)
+                                                            PopTip.build()
+                                                                .tip(R.string.colock_failed)
                                                         }
                                                         refreshTicketUser()
                                                     }
@@ -479,22 +471,25 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                                         TipDialog.showInfo(
                                             msg = CommonUtils.getStr(
                                                 com.grkj.ui_base.R.string.confirm_to_uncolock,
-                                                colocker.nickName?:""
+                                                colocker.nickName ?: ""
                                             ).toString(), countDownTime = 10, onConfirmClick = {
                                                 colocker.jobStatus = "2"
                                                 viewModel.colockerStatusChange(colocker)
                                                     .observe(this) {
                                                         if (it) {
-                                                            PopTip.build().tip(R.string.uncolock_complete)
+                                                            PopTip.build()
+                                                                .tip(R.string.uncolock_complete)
                                                             checkStepComplete()
                                                         } else {
-                                                            PopTip.build().tip(R.string.uncolock_failed)
+                                                            PopTip.build()
+                                                                .tip(R.string.uncolock_failed)
                                                         }
                                                         refreshTicketUser()
                                                     }
                                             })
                                     } else {
-                                        PopTip.build().tip(R.string.currently_unable_to_lock_together)
+                                        PopTip.build()
+                                            .tip(R.string.currently_unable_to_lock_together)
                                     }
                                 } ?: PopTip.build().tip(R.string.invalid_user)
                             } ?: PopTip.build().tip(R.string.invalid_card)
@@ -564,6 +559,18 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
             "${viewModel.ticketPoints.size}/${viewModel.ticketPoints.count { it.pointStatus?.toInt() ?: 0 >= 1 }}/${viewModel.ticketPoints.count { it.pointStatus == "2" }}"
         binding.colockInfo.text =
             "${viewModel.ticketUser.filter { it.userRole == RoleEnum.JTCOLOCKER.roleKey }.size}/${viewModel.ticketUser.count { it.userRole == RoleEnum.JTCOLOCKER.roleKey && it.jobStatus?.toInt() ?: 0 >= 1 }}/${viewModel.ticketUser.count { it.userRole == RoleEnum.JTCOLOCKER.roleKey && it.jobStatus == "2" }}"
+        viewModel.groupInfo = viewModel.ticketPoints.groupBy { it.groupId to it.groupName }.filter {
+            val currentWorkflowStep = viewModel.workflowSteps.find { it.stepId == viewModel.currentStepData?.workflowStepId }
+            if (currentWorkflowStep?.enableLock == true) {
+                logger.info("当前步骤上锁:${it.value.all { it.pointStatus == "0" }}")
+                it.value.all { it.pointStatus == "0" }
+            } else if (currentWorkflowStep?.enableUnlock == true) {
+                logger.info("当前步骤解锁:${it.value.all { it.pointStatus == "1" }}")
+                it.value.all { it.pointStatus == "1" }
+            } else {
+                false
+            }
+        }.map { JobTicketGroupInfoVo(it.key.first, it.key.second) }.toMutableList()
         if (viewModel.currentStepData?.stepIndex == null) {
             binding.finishJob.isVisible = true
         } else {
@@ -576,12 +583,12 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                     //步骤开启上锁,并且点位都还没有上锁
                 (currentStep?.enableLock == true && viewModel.ticketPoints.any { it.pointStatus == "0" }) ||
                         //步骤开启共锁,并且点位都不存在没有上锁的
-                        (currentStep?.enableColock == true && viewModel.ticketPoints.all { it.pointStatus == "0" }) ||
+                        (currentStep?.enableColock == true && viewModel.ticketPoints.all { it.pointStatus == "1" }) ||
                         (currentStep?.enableLock == true && viewModel.isUnlockFirst && viewModel.ticketPoints.all { it.pointStatus == "2" })
             //步骤开启解锁,并且点位都已经上锁,并且如果支持共锁都已经解除
             binding.toUnlock.isVisible =
                 currentStep?.enableUnlock == true &&
-                        viewModel.ticketPoints.all { it.pointStatus == "1" } &&
+                        viewModel.ticketPoints.any { it.pointStatus == "1" } &&
                         (viewModel.workflowModes.find { it.modeId == viewModel.ticketData?.modeId }?.isColockSupport == false ||
                                 (viewModel.workflowModes.find { it.modeId == viewModel.ticketData?.modeId }?.isColockSupport == true &&
                                         viewModel.ticketUser.filter { it.userRole == RoleEnum.JTCOLOCKER.roleKey }
@@ -598,7 +605,7 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
         }
         viewModel.getWorkflowModes().observe(this) {
             viewModel.ticketId = GlobalDataTempStore.getInstance()
-                .getData(DataTransferConstants.KEY_JOB_TICKET_ID)?:0L
+                .getData(DataTransferConstants.KEY_JOB_TICKET_ID) ?: 0L
             getData()
         }
     }
@@ -658,14 +665,17 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                 .hasData(DataTransferConstants.KEY_SELECTED_MEMBER_LOCKER_DATA)
         ) {
             viewModel.selectedLockerData = GlobalDataTempStore.getInstance()
-                .getData(DataTransferConstants.KEY_SELECTED_MEMBER_LOCKER_DATA)?: listOf()
+                .getData(
+                    DataTransferConstants.KEY_SELECTED_MEMBER_LOCKER_DATA,
+                    Type.lockerGroupType
+                ) ?: listOf()
             viewModel.checkMemberFinish = true
         }
         if (GlobalDataTempStore.getInstance()
                 .hasData(DataTransferConstants.KEY_SELECTED_MEMBER_COLOCKER_DATA)
         ) {
             viewModel.selecteColockerData = GlobalDataTempStore.getInstance()
-                .getData(DataTransferConstants.KEY_SELECTED_MEMBER_COLOCKER_DATA)?: listOf()
+                .getData(DataTransferConstants.KEY_SELECTED_MEMBER_COLOCKER_DATA) ?: listOf()
             viewModel.checkMemberFinish = true
         }
         if (viewModel.checkMemberFinish) {

+ 84 - 45
app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobExecuteViewModel.kt

@@ -47,7 +47,8 @@ import java.util.concurrent.atomic.AtomicInteger
  */
 @HiltViewModel
 class JobExecuteViewModel @Inject constructor(
-    val jobTicketRepository: IJobTicketRepository, val workflowRepository: IWorkflowRepository,
+    val jobTicketRepository: IJobTicketRepository,
+    val workflowRepository: IWorkflowRepository,
     userRepository: UserRepository
 ) : BaseViewModel(userRepository) {
     var ticketId: Long = 0
@@ -57,6 +58,7 @@ class JobExecuteViewModel @Inject constructor(
     lateinit var ticketPoints: List<IsJobTicketPointsDataVo>
     lateinit var ticketStep: List<IsJobTicketStepDataVo>
     lateinit var ticketUser: List<IsJobTicketUserDataVo>
+    var groupInfo: MutableList<JobTicketGroupInfoVo> = mutableListOf()
     var selectedLockerData: List<JobTicketGroupDataVo<JobUserVo>> = mutableListOf()
     var selecteColockerData: List<JobUserVo> = mutableListOf()
     var checkMemberFinish: Boolean = false
@@ -118,10 +120,11 @@ class JobExecuteViewModel @Inject constructor(
             selectedLockerData =
                 tempJobTicketUserId.filter { it.roleKeys.contains(RoleEnum.JTLOCKER.roleKey) }
                     .groupBy { it.groupId to it.groupName }.map {
-                        JobTicketGroupDataVo(JobTicketGroupInfoVo(
-                            it.key.first,
-                            it.key.second
-                        ),it.value.toMutableList())
+                        JobTicketGroupDataVo(
+                            JobTicketGroupInfoVo(
+                                it.key.first, it.key.second
+                            ), it.value.toMutableList()
+                        )
                     }
             selecteColockerData =
                 tempJobTicketUserId.filter { it.roleKeys.contains(RoleEnum.JTCOLOCKER.roleKey) }
@@ -135,8 +138,7 @@ class JobExecuteViewModel @Inject constructor(
     fun cancelJob(): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
             val ticketDetail = RepositoryManager.jobTicketRepo.getTicketDetail(ticketId)
-            val workflowStep =
-                workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
+            val workflowStep = workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
             val role = ticketDetail?.ticketUserVOList?.find {
                 it.userId == MainDomainData.userInfo?.userId && workflowStep?.currentUserCanConfirm() == true
             }
@@ -169,9 +171,8 @@ class JobExecuteViewModel @Inject constructor(
     fun finishJob(): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
             val ticketDetail = RepositoryManager.jobTicketRepo.getTicketDetail(ticketId)
-            val workflowStep =
-                workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
-                    ?: workflowSteps.last()
+            val workflowStep = workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
+                ?: workflowSteps.last()
             val role = ticketDetail?.ticketUserVOList?.find {
                 it.userId == MainDomainData.userInfo?.userId
             }
@@ -201,13 +202,35 @@ class JobExecuteViewModel @Inject constructor(
     /**
      * 去上锁
      */
-    fun toLock(): LiveData<Boolean> {
+    fun toLock(groupId: Long): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
+            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
+                    DeviceConst.DEVICE_TYPE_LOCK, ticketId
+                )
+            ) {
+                showLoading(CommonUtils.getStr(com.grkj.ui_base.R.string.please_take_out_ready_device_first))
+                return@liveData
+            }
+            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
+                    DeviceConst.DEVICE_TYPE_KEY, ticketId
+                )
+            ) {
+                showLoading(CommonUtils.getStr(com.grkj.ui_base.R.string.check_key_and_lock))
+                val rfid = ModbusBusinessManager.getWaitTakeDeviceByTicketId(
+                    DeviceConst.DEVICE_TYPE_KEY, ticketId
+                )?.nfc
+                rfid?.let {
+                    val keyMac = ModbusBusinessManager.getKeyMacByRfid(it)
+                    ModbusBusinessManager.checkTicketAndSendTicket(keyMac)
+                    return@liveData
+                } ?: run {
+                    hideLoading()
+                }
+            }
             val ticketDetail = RepositoryManager.jobTicketRepo.getTicketDetail(ticketId)
-            val workflowStep =
-                workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
+            val workflowStep = workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
             val role = ticketDetail?.ticketUserVOList?.find {
-                it.userId == MainDomainData.userInfo?.userId && workflowStep?.currentUserCanConfirm() == true
+                it.userId == MainDomainData.userInfo?.userId && workflowStep?.currentUserCanConfirm() == true && it.groupId == groupId
             }
             if (role == null) {
                 ThreadUtils.runOnMain {
@@ -228,15 +251,14 @@ class JobExecuteViewModel @Inject constructor(
                 return@liveData
             }
             ModbusBusinessManager.checkEquipCount(ticketId, ticketPoints.count {
-                it.pointStatus == "0" || (it.pointStatus == "2" && workflowRepository.isUnlockBeforeLock(
+                it.groupId == groupId && (it.pointStatus == "0" || (it.pointStatus == "2" && workflowRepository.isUnlockBeforeLock(
                     ticketData?.modeId!!
-                ))
+                )))
             }, true) { keyMap, lockMap ->
                 if (lockMap.isEmpty()) {
                     TipDialog.show(
                         CommonUtils.getStr(com.grkj.ui_base.R.string.action_failed).toString(),
-                        CommonUtils.getStr(com.grkj.ui_base.R.string.lock_is_not_enough)
-                            .toString(),
+                        CommonUtils.getStr(com.grkj.ui_base.R.string.lock_is_not_enough).toString(),
                         TipDialog.DialogType.ERROR,
                         countDownTime = 10,
                         onConfirmClick = {
@@ -250,8 +272,7 @@ class JobExecuteViewModel @Inject constructor(
                 if (keyMap == null) {
                     TipDialog.show(
                         CommonUtils.getStr(com.grkj.ui_base.R.string.action_failed).toString(),
-                        CommonUtils.getStr(com.grkj.ui_base.R.string.no_available_key)
-                            .toString(),
+                        CommonUtils.getStr(com.grkj.ui_base.R.string.no_available_key).toString(),
                         TipDialog.DialogType.ERROR,
                         countDownTime = 10,
                         onConfirmClick = {
@@ -266,6 +287,7 @@ class JobExecuteViewModel @Inject constructor(
                         DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second?.rfid!!
                     )
                 }
+                MainDomainData.deviceTakeTicketGroupBound.put(ticketId, groupId)
                 val waitOpenLockDockSize = lockMap.keys.size
                 val openedLockDockSize = AtomicInteger(0)
                 lockMap.keys.forEach { lockDockAddr ->
@@ -282,8 +304,7 @@ class JobExecuteViewModel @Inject constructor(
                             if (openedLockDockSize.get() >= waitOpenLockDockSize) {
                                 LoadingEvent.sendLoadingEvent(
                                     CommonUtils.getStr(
-                                        com.grkj.ui_base.R.string.take_out_lock_tip,
-                                        args = listOf(
+                                        com.grkj.ui_base.R.string.take_out_lock_tip, args = listOf(
                                             lockMap.values.flatten().count().toInt()
                                         ).toTypedArray()
                                     ), true
@@ -300,13 +321,35 @@ class JobExecuteViewModel @Inject constructor(
     /**
      * 去解锁
      */
-    fun toUnLock(): LiveData<Boolean> {
+    fun toUnLock(groupId: Long): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
+            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
+                    DeviceConst.DEVICE_TYPE_LOCK, ticketId
+                )
+            ) {
+                showLoading(CommonUtils.getStr(com.grkj.ui_base.R.string.please_take_out_ready_device_first))
+                return@liveData
+            }
+            if (ModbusBusinessManager.hasAnyDeviceWaitTakeByTicketId(
+                    DeviceConst.DEVICE_TYPE_KEY, ticketId
+                )
+            ) {
+                showLoading(CommonUtils.getStr(com.grkj.ui_base.R.string.check_key_and_lock))
+                val rfid = ModbusBusinessManager.getWaitTakeDeviceByTicketId(
+                    DeviceConst.DEVICE_TYPE_KEY, ticketId
+                )?.nfc
+                rfid?.let {
+                    val keyMac = ModbusBusinessManager.getKeyMacByRfid(it)
+                    ModbusBusinessManager.checkTicketAndSendTicket(keyMac)
+                    return@liveData
+                } ?: run {
+                    hideLoading()
+                }
+            }
             val ticketDetail = RepositoryManager.jobTicketRepo.getTicketDetail(ticketId)
-            val workflowStep =
-                workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
+            val workflowStep = workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
             val role = ticketDetail?.ticketUserVOList?.find {
-                it.userId == MainDomainData.userInfo?.userId && workflowStep?.currentUserCanConfirm() == true
+                it.userId == MainDomainData.userInfo?.userId && workflowStep?.currentUserCanConfirm() == true && it.groupId == groupId
             }
             if (role == null) {
                 ThreadUtils.runOnMain {
@@ -328,12 +371,13 @@ class JobExecuteViewModel @Inject constructor(
             }
             if (checkBeforeToUnlock()) {
                 //全部或不分交叉点位重叠进行重叠点位解锁
-                jobTicketRepository.updateCoincideToUnLock(ticketDetail)
-                if (ticketDetail.ticketPointsVOList?.all {
+                jobTicketRepository.updateCoincideToUnLock(ticketDetail, groupId)
+                if (ticketDetail.ticketPointsVOList?.filter { it.groupId == groupId }?.all {
                         it.pointId in (ticketDetail.noUnlockTicketPointsVOSet?.map { it.pointId }
                             ?: mutableListOf())
                     } == true) {
-                    BleBusinessManager.handleUnlockVirtualKeyReturn(ticketId)
+                    MainDomainData.deviceTakeTicketGroupBound.put(ticketId, groupId)
+                    BleBusinessManager.handleUnlockVirtualKeyReturn(ticketId, groupId)
                 } else {
                     ModbusBusinessManager.checkEquipCount(ticketId, 0, true) { keyMap, _ ->
                         LoadingEvent.sendLoadingEvent()
@@ -348,11 +392,14 @@ class JobExecuteViewModel @Inject constructor(
                             )
                             return@checkEquipCount
                         }
+                        MainDomainData.deviceTakeTicketGroupBound.put(ticketId, groupId)
                         ModbusBusinessManager.addDeviceTake(
                             DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second?.rfid!!
                         )
                         val deviceTakeUpdate = DeviceTakeUpdate(
-                            DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second?.rfid ?: ""
+                            DeviceConst.DEVICE_TYPE_KEY,
+                            ticketId,
+                            keyMap.second?.rfid ?: "",
                         )
                         BleBusinessManager.handleGiveKey(deviceTakeUpdate)
                     }
@@ -429,8 +476,7 @@ class JobExecuteViewModel @Inject constructor(
                         val currentWorkflowStep = workflowSteps.find {
                             it.stepId == ticketStep.firstOrNull { it.stepStatus == "0" }?.workflowStepId
                         }
-                        ticketData?.ticketStatus =
-                            currentWorkflowStep?.getTicketStatus() ?: ""
+                        ticketData?.ticketStatus = currentWorkflowStep?.getTicketStatus() ?: ""
                         jobTicketRepository.updateTicketDataStatus(
                             ticketId,
                             currentWorkflowStep?.getTicketStatus()?.toInt()
@@ -521,8 +567,7 @@ class JobExecuteViewModel @Inject constructor(
                         RoleEnum.JTCOLOCKER.roleKey
                     ) == true
                 }.all { it.jobStatus == "1" }
-            }"
-        )
+            }")
         return workflowStep?.enableColock == true && ticketUser.filter {
             it.userRole?.contains(
                 RoleEnum.JTCOLOCKER.roleKey
@@ -541,8 +586,7 @@ class JobExecuteViewModel @Inject constructor(
                         RoleEnum.JTCOLOCKER.roleKey
                     ) == true
                 }.all { it.jobStatus == "2" }
-            }"
-        )
+            }")
         return workflowStep?.enableReleaseColock == true && ticketUser.filter {
             it.userRole?.contains(
                 RoleEnum.JTCOLOCKER.roleKey
@@ -617,8 +661,7 @@ class JobExecuteViewModel @Inject constructor(
                 CommonUtils.getStr(R.string.please_select_member).toString() to null
             }
 
-            workflowStep?.enableLock == true || workflowStep?.enableColock == true ||
-                    workflowStep?.enableReleaseColock == true || workflowStep?.enableUnlock == true -> {
+            workflowStep?.enableLock == true || workflowStep?.enableColock == true || workflowStep?.enableReleaseColock == true || workflowStep?.enableUnlock == true -> {
                 var tip = ""
                 var index: Int? = null
                 if (workflowStep.enableLock) {
@@ -673,9 +716,7 @@ class JobExecuteViewModel @Inject constructor(
     fun needShowTip(): Boolean {
         val currentWorkflowStep =
             workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
-        return currentWorkflowStep?.enableSetLocker == true || currentWorkflowStep?.enableSetColocker == true ||
-                currentWorkflowStep?.enableLock == true || currentWorkflowStep?.enableColock == true ||
-                currentWorkflowStep?.enableReleaseColock == true || currentWorkflowStep?.enableUnlock == true
+        return currentWorkflowStep?.enableSetLocker == true || currentWorkflowStep?.enableSetColocker == true || currentWorkflowStep?.enableLock == true || currentWorkflowStep?.enableColock == true || currentWorkflowStep?.enableReleaseColock == true || currentWorkflowStep?.enableUnlock == true
     }
 
     /**
@@ -689,8 +730,7 @@ class JobExecuteViewModel @Inject constructor(
                 CommonUtils.getStr(R.string.please_select_member).toString()
             }
 
-            currentWorkflowStep?.enableLock == true || currentWorkflowStep?.enableColock == true ||
-                    currentWorkflowStep?.enableReleaseColock == true || currentWorkflowStep?.enableUnlock == true -> {
+            currentWorkflowStep?.enableLock == true || currentWorkflowStep?.enableColock == true || currentWorkflowStep?.enableReleaseColock == true || currentWorkflowStep?.enableUnlock == true -> {
                 var tip = ""
                 if (currentWorkflowStep.enableLock) {
                     if (ticketPoints.any { it.pointStatus != "1" } && ticketKey.isEmpty()) {
@@ -737,8 +777,7 @@ class JobExecuteViewModel @Inject constructor(
     fun canCheckStep(): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
             val ticketDetail = RepositoryManager.jobTicketRepo.getTicketDetail(ticketId)
-            val workflowStep =
-                workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
+            val workflowStep = workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
             val role = ticketDetail?.ticketUserVOList?.find {
                 it.userId == MainDomainData.userInfo?.userId && workflowStep?.currentUserCanConfirm() == true
             }

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

@@ -427,7 +427,7 @@
 
                             <LinearLayout
                                 android:id="@+id/select_colocker_layout"
-                                android:layout_width="match_parent"
+                                android:layout_width="0dp"
                                 android:layout_height="match_parent"
                                 android:layout_weight="1"
                                 android:background="@drawable/home_card_bg"

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

@@ -31,6 +31,7 @@
                     android:background="@drawable/bg_group_name_input_selector"
                     android:enabled="false"
                     android:focusable="false"
+                    android:layout_gravity="center"
                     android:focusableInTouchMode="false"
                     android:gravity="center"
                     android:paddingHorizontal="@dimen/common_spacing"

+ 1 - 0
app/src/main/res/layout/item_locker_group.xml

@@ -33,6 +33,7 @@
                     android:focusable="false"
                     android:focusableInTouchMode="false"
                     android:gravity="center"
+                    android:layout_gravity="center"
                     android:paddingHorizontal="@dimen/common_spacing"
                     android:text="@string/selected_point_info_title"
                     android:textColor="@color/text_color_item_group_title_text"

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

@@ -472,5 +472,7 @@
     <string name="point_manage_point_group">Group name</string>
     <string name="please_select_group">Please select group</string>
     <string name="group_name_must_not_empty">Group name must not empty</string>
+    <string name="not_group_can_lock">There are currently no groups that can be locked</string>
+    <string name="not_group_can_unlock">There are currently no groups to unlock</string>
 
 </resources>

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

@@ -472,5 +472,7 @@
     <string name="point_manage_point_group">分组名称</string>
     <string name="please_select_group">请选择分组</string>
     <string name="group_name_must_not_empty">分组名称不能为空</string>
+    <string name="not_group_can_lock">当前无分组可上锁</string>
+    <string name="not_group_can_unlock">当前无分组可解锁</string>
 
 </resources>

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

@@ -475,5 +475,7 @@
     <string name="point_manage_point_group">分组名称</string>
     <string name="please_select_group">请选择分组</string>
     <string name="group_name_must_not_empty">分组名称不能为空</string>
+    <string name="not_group_can_lock">当前无分组可上锁</string>
+    <string name="not_group_can_unlock">当前无分组可解锁</string>
 
 </resources>

+ 22 - 5
data/src/main/java/com/grkj/data/dao/JobTicketDao.kt

@@ -26,8 +26,6 @@ import com.grkj.data.model.vo.JobPointVo
 import com.grkj.data.model.vo.JobTicketManageVo
 import com.grkj.data.model.vo.JobUserVo
 import com.grkj.data.model.vo.LockedPointVo
-import com.grkj.data.model.vo.PointManageVo
-import com.grkj.data.model.vo.UserManageVo
 import com.sik.sikcore.date.TimeUtils
 
 /**
@@ -281,12 +279,15 @@ interface JobTicketDao {
             r.rfid as point_nfc,
             i.point_serial_number,
             l.lock_name,
-            l.lock_nfc
+            l.lock_nfc,
+            g.group_name,
+            g.id as groupId
         FROM
             is_job_ticket_points j
                 LEFT JOIN is_isolation_point i ON j.point_id = i.point_id
                 left join is_rfid_token r on r.rfid_id = i.rfid_id
                 LEFT JOIN is_lock l ON j.lock_id = l.lock_id
+                left join is_job_ticket_group g on g.id = j.group_id
         WHERE
             j.ticket_id = :ticketId
         ORDER BY
@@ -304,7 +305,17 @@ interface JobTicketDao {
     /**
      * 根据作业id获取作业人员详细数据
      */
-    @Query("select ijtu.*,su.nick_name as nickName from is_job_ticket_user ijtu left join sys_user su on ijtu.user_id = su.user_id where ticket_id = :ticketId")
+    @Query(
+        """
+        select ijtu.*,
+        su.nick_name as nickName,
+        ijtg.group_name
+        from is_job_ticket_user ijtu 
+        left join sys_user su on ijtu.user_id = su.user_id 
+        left join is_job_ticket_group ijtg on ijtg.id = ijtu.group_id 
+        where ijtu.ticket_id = :ticketId
+    """
+    )
     fun getJobTicketUserDataByTicketId(ticketId: Long): List<IsJobTicketUserDataVo>
 
     /**
@@ -402,6 +413,7 @@ interface JobTicketDao {
         AND p.point_id IN (:pointIds)
         AND k.collect_time is not null
         and k.give_back_time is null
+        and k.group_id = p.group_id
         and k.ticket_type = 0
         and j.ticket_id != :ticketId
         GROUP BY
@@ -449,7 +461,6 @@ interface JobTicketDao {
           AND p.point_id =:pointId
           AND p.lock_id = :lockId
           AND p.ticket_id != :ticketId
-          AND k.collect_time IS NULL
     """
     )
     fun getVirtualLockConflictPoint(
@@ -632,4 +643,10 @@ interface JobTicketDao {
      */
     @Query("delete from is_job_ticket_group where ticket_id in (:ticketIds)")
     fun deleteJobTicketGroupByTicketIds(ticketIds: List<Long>)
+
+    /**
+     * 根据点位id和作业id获取分组id
+     */
+    @Query("select group_id from is_job_ticket_points where point_id = :pointId and ticket_id = :ticketId")
+    fun getGroupIdByPointIdAndTicketId(pointId: Long, ticketId: Long): Long
 }

+ 7 - 0
data/src/main/java/com/grkj/data/data/MainDomainData.kt

@@ -37,6 +37,12 @@ object MainDomainData {
     @Volatile
     var permissions: MutableList<String?> = mutableListOf()
 
+    /**
+     * 设备取出的票据分组绑定
+     */
+    @Volatile
+    var deviceTakeTicketGroupBound: MutableMap<Long, Long> = mutableMapOf()
+
     /**
      * 清除数据
      */
@@ -46,5 +52,6 @@ object MainDomainData {
         permissions.clear()
         userCardList.clear()
         userBiometricDataVo.clear()
+        deviceTakeTicketGroupBound.clear()
     }
 }

+ 4 - 0
data/src/main/java/com/grkj/data/model/dos/IsJobTicketKey.kt

@@ -39,6 +39,10 @@ open class IsJobTicketKey : BaseBean() {
 
     @ColumnInfo("del_flag")
     var delFlag: String? = "0"
+
+    @ColumnInfo("group_id")
+    var groupId: Long? = null
+
     override fun toString(): String {
         return "IsJobTicketKey(recordId=$recordId, ticketId=$ticketId, keyId=$keyId, fromHardwareId=$fromHardwareId, toHardwareId=$toHardwareId, collectTime=$collectTime, giveBackTime=$giveBackTime, keyStatus=$keyStatus, ticketType=$ticketType, delFlag=$delFlag)"
     }

+ 3 - 0
data/src/main/java/com/grkj/data/model/dos/IsJobTicketLock.kt

@@ -33,6 +33,9 @@ open class IsJobTicketLock : BaseBean() {
 
     @ColumnInfo("del_flag")
     var delFlag: String? = "0"
+
+    @ColumnInfo("group_id")
+    var groupId: Long? = null
 	
 
 }

+ 1 - 1
data/src/main/java/com/grkj/data/model/local/DeviceTakeUpdate.kt

@@ -6,5 +6,5 @@ package com.grkj.data.model.local
 data class DeviceTakeUpdate(
     val deviceType: Int,    // DeviceConst.DEVICE_TYPE_KEY or DeviceConst.DEVICE_TYPE_LOCK
     val ticketId: Long,
-    val nfc: String
+    val nfc: String,
 )

+ 7 - 0
data/src/main/java/com/grkj/data/model/res/TicketDetailRes.kt

@@ -33,6 +33,7 @@ class TicketDetailRes {
         var keyStatus: String? = null
         var delFlag: String? = null
         var ticketType: Int? = null
+        var groupId: Long? = null
         override fun toString(): String {
             return "JobTicketKeyVO(recordId=$recordId, ticketId=$ticketId, keyId=$keyId, fromHardwareId=$fromHardwareId, toHardwareId=$toHardwareId, collectTime=$collectTime, giveBackTime=$giveBackTime, keyStatus=$keyStatus, delFlag=$delFlag, ticketType=$ticketType)"
         }
@@ -48,6 +49,7 @@ class TicketDetailRes {
         var toHardwareId: Long? = null
         var isolationPointId: Long? = null
         var lockStatus: String? = null
+        var groupId: Long? = null
         var delFlag: String? = null
         override fun toString(): String {
             return "JobTicketLockVO(recordId=$recordId, ticketId=$ticketId, lockId=$lockId, lockNfc='$lockNfc', fromHardwareId=$fromHardwareId, toHardwareId=$toHardwareId, isolationPointId=$isolationPointId, lockStatus=$lockStatus, delFlag=$delFlag)"
@@ -66,6 +68,7 @@ class TicketDetailRes {
         var locksetStatus: String? = null
         var collectTime: String? = null
         var giveBackTime: String? = null
+        var groupId: Long? = null
         var delFlag: String? = null
         override fun toString(): String {
             return "JobTicketLocksetVO(recordId=$recordId, jobTicketId=$jobTicketId, pointId=$pointId, locksetId=$locksetId, fromHardwareId=$fromHardwareId, toHardwareId=$toHardwareId, locksetTypeId=$locksetTypeId, locksetStatus=$locksetStatus, collectTime=$collectTime, giveBackTime=$giveBackTime, delFlag=$delFlag)"
@@ -80,6 +83,8 @@ class TicketDetailRes {
         var userName: String = ""
         var userType: String? = null
         var userRole: String? = null
+        var groupId: Long? = 0L
+        var groupName: String? = ""
         var jobStatus: Int? = null//作业状态(0未开始,1 取锁具, 2取钥匙, 3待上锁(待共锁),4 已上锁(已共锁),5 已解锁)
         override fun toString(): String {
             return "JobTicketUserVO(recordId=$recordId, ticketId=$ticketId, userId=$userId, userName='$userName', userType=$userType, userRole=$userRole, jobStatus=$jobStatus)"
@@ -124,6 +129,8 @@ class TicketDetailRes {
         var lockTypeImg: String? = null
         var lockNfc: String? = null
         var locksetTypeId: Long? = null
+        var groupId: Long = 0L
+        var groupName: String? = ""
         override fun toString(): String {
             return "JobTicketPointsVO(recordId=$recordId, ticketId=$ticketId, workshopId=$workshopId, workareaId=$workareaId, pointId=$pointId, pointStatus=$pointStatus, delFlag=$delFlag, lockId=$lockId, lockedByKeyId=$lockedByKeyId, unlockedByKeyId=$unlockedByKeyId, lockTime=$lockTime, unlockTime=$unlockTime, prePointId=$prePointId, pointCode=$pointCode, pointName=$pointName, pointType=$pointType, pointTypeName=$pointTypeName, pointNfc=$pointNfc, workshopName=$workshopName, workareaName=$workareaName, workstationId=$workstationId, workstationName=$workstationName, lotoId=$lotoId, lotoName=$lotoName, powerType=$powerType, powerTypeName=$powerTypeName, isolationMethod=$isolationMethod, pointIcon=$pointIcon, pointPicture=$pointPicture, lockTypeId=$lockTypeId, lockTypeCode=$lockTypeCode, lockTypeName=$lockTypeName, lockTypeIcon=$lockTypeIcon, lockTypeImg=$lockTypeImg, lockNfc=$lockNfc, locksetTypeId=$locksetTypeId)"
         }

+ 6 - 0
data/src/main/java/com/grkj/data/model/vo/IsJobTicketPointsVo.kt

@@ -108,4 +108,10 @@ class IsJobTicketPointsVO : BaseBean() {
     @ColumnInfo(name = "switch_last_update_time")
     var switchLastUpdateTime: String? = null
 
+    //分组id
+    var groupId: Long = 0L
+
+    //分组名称
+    @ColumnInfo(name = "group_name")
+    var groupName: String? = null
 }

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

@@ -1,5 +1,6 @@
 package com.grkj.data.model.vo
 
+import androidx.room.ColumnInfo
 import com.grkj.data.model.dos.IsJobTicketUser
 
 /**
@@ -7,4 +8,7 @@ import com.grkj.data.model.dos.IsJobTicketUser
  */
 class IsJobTicketUserDataVo : IsJobTicketUser() {
     var nickName: String? = ""
+
+    @ColumnInfo(name = "group_name")
+    var groupName: String? = ""
 }

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

@@ -365,4 +365,9 @@ interface IHardwareRepository {
      * 根据rfid获取rfid数据
      */
     fun getRfidDataByRfid(rfid: String): IsRfidToken?
+
+    /**
+     * 根据点位rfid获取点位id
+     */
+    fun getPointIdByPointNfc(pointRfid: String?): Long
 }

+ 9 - 2
data/src/main/java/com/grkj/data/repository/IJobTicketRepository.kt

@@ -207,14 +207,16 @@ interface IJobTicketRepository {
     fun updateKeyReturn(
         ticketId: Long,
         keyNfc: String,
+        groupId: Long,
         serialNo: String,
+        virtualKey: Boolean = false,
         callback: (Boolean, String, Int) -> Unit
     )
 
     /**
      * 更新钥匙取出
      */
-    fun updateKeyTake(ticketId: Long, keyNfc: String, serialNo: String, callback: (Boolean) -> Unit)
+    fun updateKeyTake(ticketId: Long, keyNfc: String, serialNo: String, virtualKey: Boolean = false, callback: (Boolean) -> Unit)
 
     /**
      * 上报锁具归还
@@ -289,5 +291,10 @@ interface IJobTicketRepository {
     /**
      * 重合点位数据解锁
      */
-    fun updateCoincideToUnLock(ticketDetail: TicketDetailRes)
+    fun updateCoincideToUnLock(ticketDetail: TicketDetailRes, groupId: Long)
+
+    /**
+     * 根据点位id和作业id获取分组id
+     */
+    fun getGroupIdByPointIdAndTicketId(pointId: Long, ticketId: Long): Long
 }

+ 4 - 0
data/src/main/java/com/grkj/data/repository/impl/network/NetworkHardwareRepository.kt

@@ -264,6 +264,10 @@ class NetworkHardwareRepository  @Inject constructor() : BaseRepository(), IHard
         TODO("Not yet implemented")
     }
 
+    override fun getPointIdByPointNfc(pointRfid: String?): Long {
+        TODO("Not yet implemented")
+    }
+
     override fun clearCabinetSlots() {
         TODO("Not yet implemented")
     }

+ 11 - 1
data/src/main/java/com/grkj/data/repository/impl/network/NetworkJobTicketRepository.kt

@@ -197,7 +197,9 @@ class NetworkJobTicketRepository  @Inject constructor() : BaseRepository(), IJob
     override fun updateKeyReturn(
         ticketId: Long,
         keyNfc: String,
+        groupId: Long,
         serialNo: String,
+        virtualKey: Boolean,
         callback: (Boolean, String, Int) -> Unit
     ) {
         TODO("Not yet implemented")
@@ -207,6 +209,7 @@ class NetworkJobTicketRepository  @Inject constructor() : BaseRepository(), IJob
         ticketId: Long,
         keyNfc: String,
         serialNo: String,
+        virtualKey: Boolean,
         callback: (Boolean) -> Unit
     ) {
         TODO("Not yet implemented")
@@ -240,6 +243,13 @@ class NetworkJobTicketRepository  @Inject constructor() : BaseRepository(), IJob
         TODO("Not yet implemented")
     }
 
+    override fun getGroupIdByPointIdAndTicketId(
+        pointId: Long,
+        ticketId: Long
+    ): Long {
+        TODO("Not yet implemented")
+    }
+
     override fun isNextLockOrUnLock(ticketId: Long): NextJobPrompt {
         TODO("Not yet implemented")
     }
@@ -274,7 +284,7 @@ class NetworkJobTicketRepository  @Inject constructor() : BaseRepository(), IJob
         TODO("Not yet implemented")
     }
 
-    override fun updateCoincideToUnLock(ticketDetail: TicketDetailRes) {
+    override fun updateCoincideToUnLock(ticketDetail: TicketDetailRes, groupId: Long) {
         TODO("Not yet implemented")
     }
 }

+ 12 - 5
data/src/main/java/com/grkj/data/repository/impl/standard/HardwareRepository.kt

@@ -35,6 +35,7 @@ import com.grkj.data.repository.BaseRepository
 import com.sik.sikcore.data.BeanUtils
 import com.sik.sikcore.date.TimeUtils
 import com.sik.sikcore.extension.saveMMKVData
+import com.sik.sikcore.extension.toJson
 import javax.inject.Inject
 import javax.inject.Singleton
 
@@ -48,6 +49,7 @@ class HardwareRepository @Inject constructor(
     val jobTicketDao: JobTicketDao
 ) : BaseRepository(), IHardwareRepository {
     private val updateLock = Any()
+
     /**
      * 获取锁信息
      */
@@ -129,11 +131,12 @@ class HardwareRepository @Inject constructor(
     ) {
         synchronized(updateLock) {
             lockTakeList.forEach { lockTakeInfo ->
-                lockTakeInfo.ticketId?.let {
-                    val isJobTicketLock = jobTicketDao.getJobTicketLockDataByTicketId(it)
-                    logger.debug("作业票挂锁信息:${isJobTicketLock}")
-                    val emptyTicketLockInfo = isJobTicketLock.first()
-                    logger.debug("取出的挂锁信息:${lockTakeInfo}")
+                lockTakeInfo.ticketId?.let {ticketId->
+                    val isJobTicketLock = jobTicketDao.getJobTicketLockDataByTicketId(ticketId)
+                    logger.debug("作业票挂锁信息:${isJobTicketLock.toJson()}-${MainDomainData.deviceTakeTicketGroupBound[ticketId]}")
+                    val emptyTicketLockInfo =
+                        isJobTicketLock.first { it.groupId == MainDomainData.deviceTakeTicketGroupBound[ticketId] }
+                    logger.debug("取出的挂锁信息:${lockTakeInfo.toJson()}")
                     lockTakeInfo.lockNfc?.let {
                         val lockInfo = getLockInfo(it)
                         lockInfo?.lockId?.let { lockId ->
@@ -156,6 +159,10 @@ class HardwareRepository @Inject constructor(
         }
     }
 
+    override fun getPointIdByPointNfc(pointRfid: String?): Long {
+        return hardwareDao.getPointIdByPointNfc(pointRfid)
+    }
+
     override fun getIsLockCabinetSlotsPage(callback: (CabinetSlotsRes?) -> Unit) {
         val allLockCabinetSlots =
             hardwareDao.getAllLockCabinetSlots()

+ 56 - 23
data/src/main/java/com/grkj/data/repository/impl/standard/JobTicketRepository.kt

@@ -70,7 +70,7 @@ class JobTicketRepository @Inject constructor(
         val ticketPoints = selectedPointsData.map {
             val isJobTicketGroup = IsJobTicketGroup()
             isJobTicketGroup.ticketId = ticketId
-            isJobTicketGroup.groupName = it.jobTicketGroupInfo.groupName?:""
+            isJobTicketGroup.groupName = it.jobTicketGroupInfo.groupName ?: ""
             val groupId = jobTicketDao.saveIsJobTicketGroup(isJobTicketGroup)
             selectedLockerData.find { lockerGroup -> lockerGroup.jobTicketGroupInfo.groupId == it.jobTicketGroupInfo.groupId }?.jobTicketGroupMemberList?.forEach { locker ->
                 locker.groupId = groupId
@@ -87,6 +87,7 @@ class JobTicketRepository @Inject constructor(
             }
         }
         val ticketPointIds = jobTicketDao.saveIsJobTicketPoints(ticketPoints.flatten())
+        val ticketPointSaveData = jobTicketDao.getJobTicketPointsDataByTicketId(ticketId)
         val ticketLockerUsers = selectedLockerData.map {
             it.jobTicketGroupMemberList.map {
                 val isJobticketUser = IsJobTicketUser()
@@ -113,6 +114,7 @@ class JobTicketRepository @Inject constructor(
                 val isJobTicketLock = IsJobTicketLock()
                 isJobTicketLock.ticketId = ticketId
                 isJobTicketLock.isolationPointId = point
+                isJobTicketLock.groupId = ticketPointSaveData.find { it.recordId == point }?.groupId
                 add(isJobTicketLock)
             }
         }
@@ -165,7 +167,7 @@ class JobTicketRepository @Inject constructor(
             val isJobTicketGroup = IsJobTicketGroup()
             isJobTicketGroup.ticketId = ticketId
             isJobTicketGroup.id = it.jobTicketGroupInfo.groupId
-            isJobTicketGroup.groupName = it.jobTicketGroupInfo.groupName?:""
+            isJobTicketGroup.groupName = it.jobTicketGroupInfo.groupName ?: ""
             val groupId = jobTicketDao.saveIsJobTicketGroup(isJobTicketGroup)
             selectedLockerData.find { lockerGroup -> it.jobTicketGroupInfo.groupId == lockerGroup.jobTicketGroupInfo.groupId }?.jobTicketGroupMemberList?.forEach {
                 it.groupId = groupId
@@ -182,6 +184,7 @@ class JobTicketRepository @Inject constructor(
             }
         }
         val ticketPointIds = jobTicketDao.saveIsJobTicketPoints(ticketPoints.flatten())
+        val ticketPointSaveData = jobTicketDao.getJobTicketPointsDataByTicketId(ticketId)
         val ticketLockerUsers = selectedLockerData.map {
             it.jobTicketGroupMemberList.map {
                 val isJobticketUser = IsJobTicketUser()
@@ -208,6 +211,7 @@ class JobTicketRepository @Inject constructor(
                 val isJobTicketLock = IsJobTicketLock()
                 isJobTicketLock.ticketId = ticketId
                 isJobTicketLock.isolationPointId = point
+                isJobTicketLock.groupId = ticketPointSaveData.find { it.recordId == point }?.groupId
                 add(isJobTicketLock)
             }
         }
@@ -227,19 +231,20 @@ class JobTicketRepository @Inject constructor(
         jobTicketDao.saveIsJobTicketStep(ticketStep)
     }
 
-    override fun updateCoincideToUnLock(ticketDetail: TicketDetailRes) {
-        ticketDetail.noUnlockTicketPointsVOSet?.forEach { jobTicketPointsVO ->
-            jobTicketDao.updateJobTicketPointData(
-                jobTicketPointsVO.unlockedByKeyId ?: 0, TimeUtils.nowString(
-                    TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT
-                ), "2", jobTicketPointsVO.recordId
-            )
-            jobTicketDao.updateJobTicketLockData(
-                jobTicketPointsVO.ticketId,
-                jobTicketPointsVO.lockId ?: 0,
-                "2"
-            )
-        }
+    override fun updateCoincideToUnLock(ticketDetail: TicketDetailRes, groupId: Long) {
+        ticketDetail.noUnlockTicketPointsVOSet?.filter { it.groupId == groupId }
+            ?.forEach { jobTicketPointsVO ->
+                jobTicketDao.updateJobTicketPointData(
+                    jobTicketPointsVO.unlockedByKeyId ?: 0, TimeUtils.nowString(
+                        TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT
+                    ), "2", jobTicketPointsVO.recordId
+                )
+                jobTicketDao.updateJobTicketLockData(
+                    jobTicketPointsVO.ticketId,
+                    jobTicketPointsVO.lockId ?: 0,
+                    "2"
+                )
+            }
     }
 
     override fun getTicketDetail(
@@ -579,8 +584,16 @@ class JobTicketRepository @Inject constructor(
         } ?: callback(false, "作业票不存在", 500)
     }
 
+    override fun getGroupIdByPointIdAndTicketId(pointId: Long, ticketId: Long): Long {
+        return jobTicketDao.getGroupIdByPointIdAndTicketId(pointId, ticketId)
+    }
+
     override fun updateKeyTake(
-        ticketId: Long, keyNfc: String, serialNo: String, callback: (Boolean) -> Unit
+        ticketId: Long,
+        keyNfc: String,
+        serialNo: String,
+        virtualKey: Boolean,
+        callback: (Boolean) -> Unit
     ) {
         val jobTicketData = jobTicketDao.getTicketDataByTicketId(ticketId)
         val keyData = hardwareDao.getKeyDataByKeyRfid(keyNfc)
@@ -589,14 +602,16 @@ class JobTicketRepository @Inject constructor(
             callback(false)
             return
         }
-        if (keyData == null) {
+        val keyId = keyData?.keyId ?: -1L
+        if (keyId == -1L && !virtualKey) {
             logger.info("钥匙信息不存在")
             callback(false)
             return
         }
         val isJobTicketKey = IsJobTicketKey()
         isJobTicketKey.ticketId = ticketId
-        isJobTicketKey.keyId = keyData.keyId
+        isJobTicketKey.keyId = keyId
+        isJobTicketKey.groupId = MainDomainData.deviceTakeTicketGroupBound[ticketId]
         val workflowSteps = workflowStepDao.getStepsByMode(jobTicketData.modeId!!)
         val ticketSteps = jobTicketDao.getJobTicketStepDataByTicketId(ticketId)
         val currentStep =
@@ -627,7 +642,12 @@ class JobTicketRepository @Inject constructor(
     }
 
     override fun updateKeyReturn(
-        ticketId: Long, keyNfc: String, serialNo: String, callback: (Boolean, String, Int) -> Unit
+        ticketId: Long,
+        keyNfc: String,
+        groupId: Long,
+        serialNo: String,
+        virtualKey: Boolean,
+        callback: (Boolean, String, Int) -> Unit
     ) {
         val jobTicketData = jobTicketDao.getTicketDataByTicketId(ticketId)
         if (jobTicketData == null) {
@@ -637,7 +657,8 @@ class JobTicketRepository @Inject constructor(
         }
         val keyData = hardwareDao.getKeyDataByKeyRfid(keyNfc)
         logger.info("钥匙信息:${keyData}")
-        if (keyData == null) {
+        val keyId = keyData?.keyId ?: -1
+        if (keyId == -1L && !virtualKey) {
             logger.info("钥匙信息不存在")
             callback(false, "钥匙信息不存在", 500)
             return
@@ -645,8 +666,16 @@ class JobTicketRepository @Inject constructor(
 
         val isJobTicketKeys = jobTicketDao.getJobTicketKeyDataByTicketId(ticketId)
         logger.info("作业票钥匙信息:${isJobTicketKeys}")
+        val workflowSteps = workflowStepDao.getStepsByMode(jobTicketData.modeId!!)
+        val ticketSteps = jobTicketDao.getJobTicketStepDataByTicketId(ticketId)
+        val currentStep =
+            workflowSteps.find { it.stepId == ticketSteps.firstOrNull { it.stepStatus == "0" }?.workflowStepId }
         val isJobTicketKey = BeanUtils.copyProperties(
-            isJobTicketKeys.firstOrNull { it.keyId == keyData.keyId }, IsJobTicketKey::class.java
+            isJobTicketKeys.firstOrNull {
+                it.keyId == keyId && it.groupId == groupId && ((currentStep?.enableLock == true && it.ticketType == 0L) ||
+                        (currentStep?.enableUnlock == true && it.ticketType == 1L))
+            },
+            IsJobTicketKey::class.java
         )
         if (isJobTicketKey == null) {
             logger.info("作业的钥匙信息不存在")
@@ -729,7 +758,7 @@ class JobTicketRepository @Inject constructor(
         val ticketPoints = selectedPointsData.map {
             val isJobTicketGroup = IsJobTicketGroup()
             isJobTicketGroup.ticketId = ticketId
-            isJobTicketGroup.groupName = it.jobTicketGroupInfo.groupName?:""
+            isJobTicketGroup.groupName = it.jobTicketGroupInfo.groupName ?: ""
             isJobTicketGroup
             jobTicketDao.saveIsJobTicketGroup(isJobTicketGroup)
             it.jobTicketGroupMemberList.map {
@@ -743,6 +772,7 @@ class JobTicketRepository @Inject constructor(
             }
         }
         val ticketPointIds = jobTicketDao.saveIsJobTicketPoints(ticketPoints.flatten())
+        val ticketPointSaveData = jobTicketDao.getJobTicketPointsDataByTicketId(ticketId)
         val ticketLockerUsers = selectedLockerData.map {
             it.jobTicketGroupMemberList.map {
                 val isJobticketUser = IsJobTicketUser()
@@ -769,6 +799,7 @@ class JobTicketRepository @Inject constructor(
                 val isJobTicketLock = IsJobTicketLock()
                 isJobTicketLock.ticketId = ticketId
                 isJobTicketLock.isolationPointId = point
+                isJobTicketLock.groupId = ticketPointSaveData.find { it.recordId == point }?.groupId
                 add(isJobTicketLock)
             }
         }
@@ -808,7 +839,7 @@ class JobTicketRepository @Inject constructor(
         val ticketPoints = selectedPointsData.map {
             val isJobTicketGroup = IsJobTicketGroup()
             isJobTicketGroup.ticketId = ticketId
-            isJobTicketGroup.groupName = it.jobTicketGroupInfo.groupName?:""
+            isJobTicketGroup.groupName = it.jobTicketGroupInfo.groupName ?: ""
             isJobTicketGroup
             jobTicketDao.saveIsJobTicketGroup(isJobTicketGroup)
             it.jobTicketGroupMemberList.map {
@@ -822,6 +853,7 @@ class JobTicketRepository @Inject constructor(
             }
         }
         val ticketPointIds = jobTicketDao.saveIsJobTicketPoints(ticketPoints.flatten())
+        val ticketPointSaveData = jobTicketDao.getJobTicketPointsDataByTicketId(ticketId)
         val ticketLockerUsers = selectedLockerData.map {
             it.jobTicketGroupMemberList.map {
                 val isJobticketUser = IsJobTicketUser()
@@ -848,6 +880,7 @@ class JobTicketRepository @Inject constructor(
                 val isJobTicketLock = IsJobTicketLock()
                 isJobTicketLock.ticketId = ticketId
                 isJobTicketLock.isolationPointId = point
+                isJobTicketLock.groupId = ticketPointSaveData.find { it.recordId == point }?.groupId
                 add(isJobTicketLock)
             }
         }

+ 16 - 0
ui-base/src/main/java/com/grkj/ui_base/base/BaseViewModel.kt

@@ -5,9 +5,11 @@ import androidx.lifecycle.ViewModel
 import androidx.lifecycle.liveData
 import androidx.lifecycle.viewModelScope
 import com.grkj.data.repository.IUserRepository
+import com.grkj.ui_base.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.event.UiEvent
 import com.grkj.ui_base.utils.extension.tip
 import com.kongzue.dialogx.dialogs.PopTip
+import com.sik.sikcore.thread.ThreadUtils
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.channels.Channel
 import kotlinx.coroutines.flow.receiveAsFlow
@@ -84,5 +86,19 @@ open class BaseViewModel constructor(
     protected fun showTip(msg: String) {
         PopTip.build().tip(msg)
     }
+
+    /** 显示加载框,子类实现 */
+    protected fun showLoading(msg: String?) {
+        ThreadUtils.runOnMain {
+            LoadingEvent.sendLoadingEvent(msg)
+        }
+    }
+
+    /** 隐藏加载框,子类实现 */
+    protected fun hideLoading() {
+        ThreadUtils.runOnMain {
+            LoadingEvent.sendLoadingEvent()
+        }
+    }
 }
 

+ 74 - 73
ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt

@@ -374,7 +374,7 @@ object BleBusinessManager {
                                             true,
                                             currentModeEvent.bleBean.bleDevice.mac,
                                             ticketDetail,
-                                            ticketDetail.ticketLockVOList?.filter { it.lockStatus != "2" }
+                                            ticketDetail.ticketLockVOList?.filter { it.lockStatus != "2" && it.groupId == MainDomainData.deviceTakeTicketGroupBound[itBO.ticketId] }
                                                 ?.map { it.lockNfc }?.toMutableList(),
                                             true
                                         )
@@ -537,57 +537,68 @@ object BleBusinessManager {
     /**
      * 解锁虚拟钥匙归还
      */
-    fun handleUnlockVirtualKeyReturn(ticketId: Long) {
+    fun handleUnlockVirtualKeyReturn(ticketId: Long, groupId: Long) {
         SPUtils.returnKey(ticketId)
         // 上报钥匙归还
-        RepositoryManager.jobTicketRepo.updateKeyReturn(
-            ticketId, "virtualKey", SIKCore.getApplication().serialNo()
-        ) { isSuccess, msg, code ->
-            logger.info("虚拟钥匙归还:${isSuccess},${msg},${code}")
-            //更新作业票的状态
-            val jobTicketData =
-                RepositoryManager.jobTicketRepo.getTicketDataByTicketId(ticketId)
-            if (jobTicketData == null) {
-                TicketFinishedEvent.sendTicketFinishedEvent(ticketId)
-                PopTip.build().tip(R.string.key_return_success)
-                return@updateKeyReturn
-            }
-            val ticketStepDataVo =
-                RepositoryManager.jobTicketRepo.getJobTicketStepDataByTicketId(
-                    jobTicketData.ticketId
-                ).firstOrNull { it.stepStatus == "0" }
-            val workflowSteps =
-                RepositoryManager.workflowRepository.getStepsByMode(
-                    jobTicketData.modeId!!
-                )
-            var currentWorkflowStep =
-                workflowSteps.find { it.stepId == ticketStepDataVo?.workflowStepId }
-            if (currentWorkflowStep?.enableReleaseColock == true && currentWorkflowStep.enableUnlock == true) {
-                logger.info("当前解锁和解除共锁在同一步骤,不更新步骤状态")
-            } else {
-                ticketStepDataVo?.stepStatus = "1"
-                val isTicketStepData = BeanUtils.copyProperties(
-                    ticketStepDataVo, IsJobTicketStep::class.java
-                )
-                isTicketStepData?.let {
-                    logger.info("更新步骤:${it}")
-                    RepositoryManager.jobTicketRepo.updateTicketStepData(it)
+        RepositoryManager.jobTicketRepo.updateKeyTake(
+            ticketId,
+            "virtualKey",
+            SIKCore.getApplication().serialNo(), true
+        ) {
+            logger.info("虚拟钥匙取出:${it}")
+            RepositoryManager.jobTicketRepo.updateKeyReturn(
+                ticketId, "virtualKey", groupId, SIKCore.getApplication().serialNo(), true
+            ) { isSuccess, msg, code ->
+                logger.info("虚拟钥匙归还:${isSuccess},${msg},${code}")
+                //更新作业票的状态
+                val jobTicketData =
+                    RepositoryManager.jobTicketRepo.getTicketDataByTicketId(ticketId)
+                if (jobTicketData == null) {
+                    TicketFinishedEvent.sendTicketFinishedEvent(ticketId)
+                    PopTip.build().tip(R.string.key_return_success)
+                    return@updateKeyReturn
                 }
-                val ticketStep =
+                val ticketStepDataVo =
                     RepositoryManager.jobTicketRepo.getJobTicketStepDataByTicketId(
                         jobTicketData.ticketId
+                    ).firstOrNull { it.stepStatus == "0" }
+                val workflowSteps =
+                    RepositoryManager.workflowRepository.getStepsByMode(
+                        jobTicketData.modeId!!
+                    )
+                var currentWorkflowStep =
+                    workflowSteps.find { it.stepId == ticketStepDataVo?.workflowStepId }
+                val ticketPoints =
+                    RepositoryManager.jobTicketRepo.getTicketDetail(jobTicketData.ticketId)?.ticketPointsVOList
+                if (currentWorkflowStep?.enableReleaseColock == true && currentWorkflowStep.enableUnlock == true ||
+                    ticketPoints?.all { it.pointStatus == ticketPoints.firstOrNull()?.pointStatus } == false
+                ) {
+                    logger.info("当前解锁和解除共锁在同一步骤或者没有全部点位解锁,不更新步骤状态")
+                } else {
+                    ticketStepDataVo?.stepStatus = "1"
+                    val isTicketStepData = BeanUtils.copyProperties(
+                        ticketStepDataVo, IsJobTicketStep::class.java
+                    )
+                    isTicketStepData?.let {
+                        logger.info("更新步骤:${it}")
+                        RepositoryManager.jobTicketRepo.updateTicketStepData(it)
+                    }
+                    val ticketStep =
+                        RepositoryManager.jobTicketRepo.getJobTicketStepDataByTicketId(
+                            jobTicketData.ticketId
+                        )
+                    currentWorkflowStep = workflowSteps.find {
+                        it.stepId == ticketStep.firstOrNull { it.stepStatus == "0" }?.workflowStepId
+                    }
+                    RepositoryManager.jobTicketRepo.updateTicketDataStatus(
+                        ticketId,
+                        currentWorkflowStep?.getTicketStatus()?.toInt()
+                            ?: JobTicketStatusEnum.PROGRESSING.status.toInt()
                     )
-                currentWorkflowStep = workflowSteps.find {
-                    it.stepId == ticketStep.firstOrNull { it.stepStatus == "0" }?.workflowStepId
                 }
-                RepositoryManager.jobTicketRepo.updateTicketDataStatus(
-                    ticketId,
-                    currentWorkflowStep?.getTicketStatus()?.toInt()
-                        ?: JobTicketStatusEnum.PROGRESSING.status.toInt()
-                )
+                logger.info("刷新界面:${ticketId}")
+                UpdateTicketProgressEvent.sendUpdateTicketProgressEvent(ticketId)
             }
-            logger.info("刷新界面:${ticketId}")
-            UpdateTicketProgressEvent.sendUpdateTicketProgressEvent(ticketId)
         }
     }
 
@@ -628,11 +639,20 @@ object BleBusinessManager {
                 LoadingEvent.sendLoadingEvent()
                 // 上报点位钥匙绑定
                 RepositoryManager.jobTicketRepo.updateLockPointBatch(updateList) { isSuccess, msg, code ->
+                    val pointId =
+                        RepositoryManager.hardwareRepo.getPointIdByPointNfc(updateList.first().pointNfc)
+                    val groupId = RepositoryManager.jobTicketRepo.getGroupIdByPointIdAndTicketId(
+                        pointId,
+                        data.taskCode?.toLong()!!
+                    )
                     logger.info("还锁操作:${isSuccess},${msg},${code}")
                     if (isSuccess) {
                         // 上报钥匙归还
                         RepositoryManager.jobTicketRepo.updateKeyReturn(
-                            data.taskCode?.toLong()!!, keyNfc!!, SIKCore.getApplication().serialNo()
+                            data.taskCode?.toLong()!!,
+                            keyNfc!!,
+                            groupId,
+                            SIKCore.getApplication().serialNo()
                         ) { isSuccess, msg, code ->
                             logger.info("钥匙归还:${isSuccess},${msg},${code}")
                             if (!isSuccess && code != 500) {
@@ -665,12 +685,15 @@ object BleBusinessManager {
                                     RepositoryManager.workflowRepository.getStepsByMode(
                                         jobTicketData.modeId!!
                                     )
+                                val ticketPoints =
+                                    RepositoryManager.jobTicketRepo.getTicketDetail(data.taskCode?.toLong()!!)?.ticketPointsVOList
                                 var currentWorkflowStep =
                                     workflowSteps.find { it.stepId == ticketStepDataVo?.workflowStepId }
                                 if ((currentWorkflowStep?.enableLock == true && currentWorkflowStep.enableColock == true) ||
-                                    (currentWorkflowStep?.enableReleaseColock == true && currentWorkflowStep.enableUnlock == true)
+                                    (currentWorkflowStep?.enableReleaseColock == true && currentWorkflowStep.enableUnlock == true ||
+                                            ticketPoints?.all { it.pointStatus == ticketPoints.firstOrNull()?.pointStatus } == false)
                                 ) {
-                                    logger.info("当前上锁和共锁或者解锁和解除共锁在同一步骤,不更新步骤状态")
+                                    logger.info("当前上锁和共锁或者解锁和解除共锁在同一步骤,或者所有点位的状态不统一,不更新步骤状态")
                                 } else {
                                     ticketStepDataVo?.stepStatus = "1"
                                     val isTicketStepData = BeanUtils.copyProperties(
@@ -776,7 +799,7 @@ object BleBusinessManager {
                         true,
                         mac,
                         ticketDetail,
-                        ticketDetail.ticketLockVOList?.filter { it.lockStatus != "2" }
+                        ticketDetail.ticketLockVOList?.filter { it.lockStatus != "2" && it.groupId == MainDomainData.deviceTakeTicketGroupBound[it.ticketId] }
                             ?.map { it.lockNfc }?.toMutableList(),
                         true
                     )
@@ -916,6 +939,8 @@ object BleBusinessManager {
         isLock: Boolean, vo: TicketDetailRes, lockList: MutableList<String?>?
     ): String {
         logger.info("generateTicketSendJson : $lockList")
+        val groupId = MainDomainData.deviceTakeTicketGroupBound[vo.ticketId]
+        logger.info("当前作业票分组数据:${vo.ticketId}-${groupId}")
         val bo = WorkTicketSend(
             cardNo = MainDomainData.userCardList.getOrNull(0)?.cardNfc ?: "123456",
         )
@@ -928,7 +953,7 @@ object BleBusinessManager {
             taskCode = vo.ticketId.toString(), codeId = 1
         )
         val taskList = ArrayList<WorkTicketSend.DataBO.DataListBO>()
-        vo.ticketPointsVOList?.let { itList ->
+        vo.ticketPointsVOList?.filter { it.groupId == groupId }?.let { itList ->
             itList.forEach { pointVO ->
                 if (vo.noUnlockTicketPointsVOSet?.any { it.pointId == pointVO.pointId } == true) {
                     return@forEach
@@ -969,28 +994,4 @@ object BleBusinessManager {
         logger.info("json : $jsonStr")
         return jsonStr
     }
-
-    /**
-     * 生成下空发工作票Json
-     *
-     * @param vo 工作票详情
-     */
-    fun generateEmptyTicketSendJson(): String {
-        // 构造一个所有字段都为空/默认值的 WorkTicketSendBO
-        val bo = WorkTicketSend(
-            cardNo = "",          // 空卡号
-            effectiveTime = 0,    // 默认有效时长
-            password = ""         // 空密码
-        ).apply {
-            // data 列表留空
-            data = mutableListOf()
-            // lockList 留空(如果字段非空,再设置为 emptyList())
-            lockList = mutableListOf()
-        }
-
-        // 转成 JSON 并返回
-        val jsonStr = Gson().toJson(bo)
-        logger.info("generateEmptyTicketJson: $jsonStr")
-        return jsonStr
-    }
 }

+ 6 - 3
ui-base/src/main/java/com/grkj/ui_base/business/ModbusBusinessManager.kt

@@ -154,7 +154,7 @@ object ModbusBusinessManager {
                                         )
                                     }
                                 }
-                            }else{
+                            } else {
                                 logger.info("更新钥匙取出异常")
                             }
                         }
@@ -174,7 +174,8 @@ object ModbusBusinessManager {
                             Executor.runOnMain {
                                 if (isSuccess == false) {
                                     logger.error("Lock take report fail")
-                                    PopTip.build().tip(CommonUtils.getStr(R.string.lock_take_report_fail))
+                                    PopTip.build()
+                                        .tip(CommonUtils.getStr(R.string.lock_take_report_fail))
                                     SPUtils.saveTicketTakeLockException(info.ticketId)
                                     mDeviceTakeList.removeIf { it.deviceType == DeviceConst.DEVICE_TYPE_LOCK && it.nfc == info.nfc }
                                     mDeviceTakeList.removeIf { it.deviceType == DeviceConst.DEVICE_TYPE_KEY && it.ticketId == info.ticketId }
@@ -199,7 +200,8 @@ object ModbusBusinessManager {
                                     LoadingEvent.sendLoadingEvent()
                                 }
                                 if (SPUtils.getTicketTakeLockException(info.ticketId)) {
-                                    PopTip.build().tip(R.string.current_ticket_report_lock_take_exception_tip)
+                                    PopTip.build()
+                                        .tip(R.string.current_ticket_report_lock_take_exception_tip)
                                     return@runOnMain
                                 }
                                 // 检查有无当前工作票的钥匙
@@ -611,6 +613,7 @@ object ModbusBusinessManager {
         val keyData = ModBusController.getKeyByRfid(keyNfc)
         return "${keyData?.row}-${keyData?.idx}"
     }
+
     /**
      * 获取挂锁仓位位置
      */

+ 16 - 28
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleUtil.kt

@@ -11,6 +11,8 @@ import com.clj.fastble.data.BleDevice
 import com.clj.fastble.exception.BleException
 import com.clj.fastble.scan.BleScanRuleConfig
 import com.grkj.shared.utils.extension.toHexStrings
+import com.sik.sikcore.thread.ThreadUtils
+import kotlinx.coroutines.delay
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 
@@ -37,7 +39,7 @@ class BleUtil private constructor() {
             BleManager.getInstance().init(application)
             BleManager.getInstance().enableLog(false)
                 .setConnectOverTime(10 * 1000L)
-                .setReConnectCount(0,0)
+                .setReConnectCount(0, 0)
                 .setSplitWriteNum(500)
                 .operateTimeout =
                 OPERATE_TIMEOUT // 设置操作readRssi、setMtu、write、read、notify、indicate的超时时间(毫秒)
@@ -60,7 +62,7 @@ class BleUtil private constructor() {
                 if (inScan) {
                     BleManager.getInstance().cancelScan()
                 }
-                BleManager.getInstance().scan(object : CustomBleScanCallback(){
+                BleManager.getInstance().scan(object : CustomBleScanCallback() {
                     override fun onPrompt(promptStr: String?) {
                         bleScanCallback.onPrompt(promptStr)
                     }
@@ -202,33 +204,19 @@ class BleUtil private constructor() {
         if (BleManager.getInstance().isConnected(bleDevice.mac)) {
             BleManager.getInstance().write(bleDevice, serviceUUID, writeUUID, cmd, writeCallback)
         } else {
-            BleManager.getInstance().connect(bleDevice.mac, object : BleGattCallback() {
-                override fun onStartConnect() {}
-                override fun onConnectFail(bleDevice: BleDevice, exception: BleException) {
-                    BleManager.getInstance().removeConnectGattCallback(bleDevice)
-                    writeCallback?.onConnectPrompt("连接失败!请检查设备是否打开,并尝试重新连接 : $exception")
-                }
-
-                override fun onConnectSuccess(
-                    bleDevice: BleDevice,
-                    gatt: BluetoothGatt,
-                    status: Int
-                ) {
-                    BleManager.getInstance().removeConnectGattCallback(bleDevice)
-                    BleManager.getInstance()
-                        .write(bleDevice, serviceUUID, writeUUID, cmd, writeCallback)
-                }
-
-                override fun onDisConnected(
-                    isActiveDisConnected: Boolean,
-                    device: BleDevice,
-                    gatt: BluetoothGatt,
-                    status: Int
-                ) {
-                    BleManager.getInstance().removeConnectGattCallback(device)
-                    writeCallback?.onDisConnectPrompt("连接断开!请检查硬件状态,并尝试重新连接!")
+            fun connectAndWrite() {
+                ThreadUtils.runOnIO {
+                    val isConnect = BleConnectionManager.tryConnectWithOptionalCharge(bleDevice.mac)
+                    if (isConnect) {
+                        BleManager.getInstance()
+                            .write(bleDevice, serviceUUID, writeUUID, cmd, writeCallback)
+                    } else {
+                        delay(800)
+                        connectAndWrite()
+                    }
                 }
-            })
+            }
+            connectAndWrite()
         }
     }
 }