Jelajahi Sumber

1. 解决485通信速度慢的问题
2. 解决人脸共锁验证失败和加载框不消失的问题
3. 归还挂锁和钥匙逻辑处理,支持不做作业归还和再次获取
4. 创建完作业一直执行不需要上锁和共锁解除共锁即可完成作业的问题
5. 人脸登录失败尝试次数限定3次

bjb 2 bulan lalu
induk
melakukan
28d973708c
18 mengubah file dengan 350 tambahan dan 297 penghapusan
  1. 14 10
      data/src/main/java/com/grkj/data/domain/logic/IHardwareLogic.kt
  2. 16 1
      data/src/main/java/com/grkj/data/domain/logic/impl/HardwareLogic.kt
  3. 15 6
      data/src/main/java/com/grkj/data/domain/logic/impl/JobTicketLogic.kt
  4. 1 0
      data/src/main/java/com/grkj/data/enums/OperationTypeEnum.kt
  5. 2 6
      data/src/main/java/com/grkj/data/hardware/face/FaceUtil.kt
  6. 7 2
      data/src/main/java/com/grkj/data/hardware/modbus/FrameTask.kt
  7. 42 25
      iscs_lock/src/main/java/com/grkj/iscs/features/login/activity/LoginActivity.kt
  8. 8 8
      iscs_lock/src/main/java/com/grkj/iscs/features/main/dialog/CheckFaceDialog.kt
  9. 21 10
      iscs_lock/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobExecuteFragment.kt
  10. 104 60
      iscs_lock/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/MyTodoListFragment.kt
  11. 11 6
      iscs_lock/src/main/java/com/grkj/iscs/features/main/viewmodel/data_manage/UserManageViewModel.kt
  12. 40 76
      iscs_lock/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobExecuteViewModel.kt
  13. 14 24
      iscs_lock/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/MyTodoViewModel.kt
  14. 20 20
      ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt
  15. 32 43
      ui-base/src/main/java/com/grkj/ui_base/business/HardwareBusinessManager.kt
  16. 1 0
      ui-base/src/main/res/values-en/strings.xml
  17. 1 0
      ui-base/src/main/res/values-zh/strings.xml
  18. 1 0
      ui-base/src/main/res/values/strings.xml

+ 14 - 10
data/src/main/java/com/grkj/data/domain/logic/IHardwareLogic.kt

@@ -1,5 +1,12 @@
 package com.grkj.data.domain.logic
 
+import com.grkj.data.domain.vo.CardManageFilterVo
+import com.grkj.data.domain.vo.KeyManageFilterVo
+import com.grkj.data.domain.vo.LockManageFilterVo
+import com.grkj.data.domain.vo.PointToMapVo
+import com.grkj.data.domain.vo.RfidTokenManageFilterVo
+import com.grkj.data.entity.local.LockData
+import com.grkj.data.entity.local.PointData
 import com.grkj.data.local.dos.IsIsolationPoint
 import com.grkj.data.local.dos.IsJobCard
 import com.grkj.data.local.dos.IsKey
@@ -7,8 +14,8 @@ import com.grkj.data.local.dos.IsLock
 import com.grkj.data.local.dos.IsLockCabinetSlots
 import com.grkj.data.local.dos.IsMapPoint
 import com.grkj.data.local.dos.IsRfidToken
-import com.grkj.data.entity.local.LockData
-import com.grkj.data.entity.local.PointData
+import com.grkj.data.local.dos.IsUserWorkstation
+import com.grkj.data.local.dos.IsWorkstation
 import com.grkj.data.net.req.LockPointUpdateReq
 import com.grkj.data.net.req.LockTakeUpdateReq
 import com.grkj.data.net.res.CabinetSlotsRes
@@ -17,14 +24,6 @@ import com.grkj.data.net.res.KeyInfoRes
 import com.grkj.data.net.res.KeyPageRes
 import com.grkj.data.net.res.LockInfoRes
 import com.grkj.data.net.res.LockPageRes
-import com.grkj.data.domain.vo.CardManageFilterVo
-import com.grkj.data.domain.vo.DataExportPointVo
-import com.grkj.data.domain.vo.KeyManageFilterVo
-import com.grkj.data.domain.vo.LockManageFilterVo
-import com.grkj.data.domain.vo.PointToMapVo
-import com.grkj.data.domain.vo.RfidTokenManageFilterVo
-import com.grkj.data.local.dos.IsUserWorkstation
-import com.grkj.data.local.dos.IsWorkstation
 
 /**
  * 硬件相关业务层
@@ -35,6 +34,11 @@ interface IHardwareLogic {
      */
     fun getLockInfo(rfid: String, callback: (LockInfoRes?) -> Unit)
 
+    /**
+     * 获取挂锁是否使用
+     */
+    fun getLockInUsed(lockRfid: String, callback: (Boolean?) -> Unit)
+
     /**
      * 获取锁信息
      */

+ 16 - 1
data/src/main/java/com/grkj/data/domain/logic/impl/HardwareLogic.kt

@@ -2,6 +2,7 @@ package com.grkj.data.domain.logic.impl
 
 import com.grkj.data.data.MMKVConstants
 import com.grkj.data.data.MainDomainData
+import com.grkj.data.di.LogicManager
 import com.grkj.data.domain.logic.BaseLogic
 import com.grkj.data.domain.logic.IHardwareLogic
 import com.grkj.data.domain.vo.CardManageFilterVo
@@ -71,12 +72,26 @@ class HardwareLogic @Inject constructor(
         callback(getLockInfo(rfid))
     }
 
+    override fun getLockInUsed(lockRfid: String, callback: (Boolean?) -> Unit) {
+        jobTicketRepository.getAllInProgressJob().forEach {
+            val ticket = LogicManager.jobTicketLogic.getTicketDetail(it.ticketId)
+            val keyIsReturn = ticket?.ticketKeyVOList?.any { it.keyStatus == "1" } ?: false
+            val lockInfo = jobTicketRepository.getJobTicketLockDataByTicketId(it.ticketId)
+            if (lockInfo.any { lock -> lock.lockNfc == lockRfid } && !keyIsReturn) {
+                logger.info("挂锁关联作业:${it.ticketName}")
+                callback(true)
+                return
+            }
+        }
+        callback(false)
+    }
+
     /**
      * 获取锁信息
      */
     override fun getLockInfo(rfid: String): LockInfoRes? {
         val isLock = hardwareRepository.getLockInfoByRfid(rfid)
-        var lockInfoRes = BeanUtils.copyProperties(isLock, LockInfoRes::class.java)
+        val lockInfoRes = BeanUtils.copyProperties(isLock, LockInfoRes::class.java)
         logger.info("lockInfo:${isLock},${lockInfoRes}")
         return lockInfoRes
     }

+ 15 - 6
data/src/main/java/com/grkj/data/domain/logic/impl/JobTicketLogic.kt

@@ -1,7 +1,5 @@
 package com.grkj.data.domain.logic.impl
 
-import android.util.Log
-import com.google.gson.Gson
 import com.grkj.data.check_data.ICheckDataMode
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.domain.logic.BaseLogic
@@ -390,7 +388,6 @@ class JobTicketLogic @Inject constructor(
                     .minByOrNull { isJobTicketStep -> isJobTicketStep.stepIndex }?.stepId
             val previousStepJoin: MutableList<TodoStepJoin> = mutableListOf()
             ticketSteps.sortedBy { it.stepIndex }.forEach { stepDef ->
-                Log.d("xiaoming", "ticket -> ${Gson().toJson(stepDef)}")
                 val stepJoins = mutableListOf<TodoStepJoin>()  // 本 step 产生的所有 待办
 
                 /** 工具:给待办挂上前置链并收集 **/
@@ -479,9 +476,11 @@ class JobTicketLogic @Inject constructor(
 
                 /* ⭐ 将本 step 的 Todo 归档,并维护前置链 ⭐ */
                 result += stepJoins
+
                 if (currentStepId == stepDef.stepId) {
                     previousStepJoin.addAll(stepJoins)
                 }
+
             }
         }
 
@@ -1107,19 +1106,29 @@ class JobTicketLogic @Inject constructor(
             callback(false)
             return
         }
-        val isJobTicketKey = IsJobTicketKey()
+        val isJobKeys = jobTicketRepository.getJobTicketKeyDataByTicketId(ticketId)
+        val isJobTicketKey = if (isJobKeys.size == 1) isJobKeys[0] else IsJobTicketKey()
         isJobTicketKey.ticketId = ticketId
         isJobTicketKey.keyId = keyId
         isJobTicketKey.groupId = MainDomainData.deviceTakeTicketGroupBound[ticketId]
         val ticketSteps = jobTicketRepository.getJobTicketStepDataByTicketId(ticketId)
         val currentStep = ticketSteps.firstOrNull { it.stepStatus == "0" }
         if (currentStep?.enableLock == true) {
+            // 标记位清除
             isJobTicketKey.ticketType = 0
+            isJobTicketKey.keyStatus = "0"
+            isJobTicketKey.giveBackTime = null
         } else if (currentStep?.enableUnlock == true) {
             isJobTicketKey.ticketType = 1
+            isJobTicketKey.keyStatus = "0"
+            isJobTicketKey.giveBackTime = null
         }
         isJobTicketKey.collectTime = TimeUtils.nowString(TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT)
-        jobTicketRepository.saveIsJobTicketKey(listOf(isJobTicketKey))
+        if (isJobKeys.size == 1) {
+            jobTicketRepository.updateIsJobTicketKey(listOf(isJobTicketKey))
+        } else {
+            jobTicketRepository.saveIsJobTicketKey(listOf(isJobTicketKey))
+        }
         callback(true)
     }
 
@@ -1163,7 +1172,7 @@ class JobTicketLogic @Inject constructor(
 
         val isJobTicketKeys = jobTicketRepository.getJobTicketKeyDataByTicketId(ticketId)
         logger.info("作业票钥匙信息:${isJobTicketKeys}")
-        val workflowSteps = workflowRepository.getStepsByMode(jobTicketData.modeId!!)
+        // val workflowSteps = workflowRepository.getStepsByMode(jobTicketData.modeId!!)
         val ticketSteps = jobTicketRepository.getJobTicketStepDataByTicketId(ticketId)
         val currentStep = ticketSteps.firstOrNull { it.stepStatus == "0" }
         val isJobTicketKey = BeanUtils.copyProperties(

+ 1 - 0
data/src/main/java/com/grkj/data/enums/OperationTypeEnum.kt

@@ -14,6 +14,7 @@ enum class OperationTypeEnum(val code: String, val desc: String, val todoTitle:
     COLOCK("colock", "待添加共锁", "colock"),
     RELEASE_COLOCK("release_colock", "待解除共锁", "release_colock"),
     CONFIRM("confirm", "步骤待确认", "confirm_exec"),
+
     END("end", "作业结束待确认", "end"),
     UNKNOWN("unknown", "未知", "unknown");
 

+ 2 - 6
data/src/main/java/com/grkj/data/hardware/face/FaceUtil.kt

@@ -567,7 +567,7 @@ object FaceUtil {
         faceOverlayView: FaceOverlayView? = null,
         callBack: (Bitmap?, face: Rect?, Long?) -> Unit
     ) {
-        retryCheckCount = 3
+        retryCheckCount = 6
         stashAppContext(preview.context)
         // 进入 checkCamera 时重置“命中即停”标记
         stopAfterHit.set(false)
@@ -626,11 +626,7 @@ object FaceUtil {
                             val data = nv21 ?: return@launch
                             val bmp = ImageConvertUtils.nv21ToBitmap(data, p.width, p.height)
                             ThreadUtils.runOnMain {
-                                callBack(
-                                    bmp,
-                                    lastFaceRectByHlk,
-                                    registerUserIdAndLocalUserId[lastUserIdByHlk]
-                                )
+                                callBack(bmp, lastFaceRectByHlk, registerUserIdAndLocalUserId[lastUserIdByHlk])
                             }
                         }
                     }

+ 7 - 2
data/src/main/java/com/grkj/data/hardware/modbus/FrameTask.kt

@@ -27,11 +27,16 @@ class FrameTask(
      */
     var minSendInterval: Int = MODBUS_MIN_SEND_INTERVAL
 
+    /**
+     * 摘出发送间隔等待时间为50ms
+     */
+    var sendSpace = 50_000_000
+
 
     fun waitIfNecessary() {
         val interval = System.nanoTime() - lastSent
-        if (interval < minSendInterval) {
-            Thread.sleep((minSendInterval - interval) / 1000_000)
+        if (interval < sendSpace) {
+            Thread.sleep((sendSpace - interval) / 1000_000)
         }
     }
 

+ 42 - 25
iscs_lock/src/main/java/com/grkj/iscs/features/login/activity/LoginActivity.kt

@@ -9,6 +9,7 @@ import android.widget.LinearLayout
 import androidx.activity.viewModels
 import androidx.core.view.isVisible
 import androidx.core.widget.ImageViewCompat
+import androidx.lifecycle.lifecycleScope
 import com.arcsoft.face.FaceEngine
 import com.arcsoft.face.model.ActiveDeviceInfo
 import com.drake.brv.BindingAdapter
@@ -19,17 +20,16 @@ import com.drake.brv.utils.linear
 import com.drake.brv.utils.models
 import com.drake.brv.utils.setup
 import com.grkj.data.data.MainDomainData
-import com.grkj.data.local.database.PresetData
-import com.grkj.data.enums.LoginResultEnum
 import com.grkj.data.entity.local.LoginMenuEntity
+import com.grkj.data.enums.LoginResultEnum
 import com.grkj.data.hardware.face.FaceUtil
-import com.grkj.data.hardware.face.hlk.Hlk223Client
-import com.grkj.data.hardware.face.hlk.Hlk223Config
+import com.grkj.data.local.database.PresetData
+import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.ActivityLoginBinding
 import com.grkj.iscs.databinding.ItemLoginMethodBinding
-import com.grkj.iscs.features.init.activity.SetRemoteServerActivity
 import com.grkj.iscs.features.common.dialog.ChangeLangDialog
+import com.grkj.iscs.features.init.activity.SetRemoteServerActivity
 import com.grkj.iscs.features.login.dialog.LoginDialog
 import com.grkj.iscs.features.login.viewmodel.LoginViewModel
 import com.grkj.iscs.features.main.activity.MainActivity
@@ -45,7 +45,6 @@ import com.grkj.ui_base.base.BaseActivity
 import com.grkj.ui_base.skin.loadSkinIcon
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.changeBgTint
-import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.extension.getAppVersionName
 import com.grkj.ui_base.utils.extension.serialNo
 import com.grkj.ui_base.utils.fingerprint.FingerprintUtil
@@ -56,6 +55,9 @@ import com.sik.sikcore.extension.setDebouncedClickListener
 import com.sik.sikcore.shell.ShellUtils
 import com.sik.sikimage.ImageConvertUtils
 import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 import java.util.Locale
 
 /**
@@ -132,6 +134,8 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
         }
     }
 
+    private var loginDialog: CustomDialog? = null
+
     private fun BindingAdapter.BindingViewHolder.onLoginMenuBinding(holder: BindingAdapter.BindingViewHolder) {
         val itemBinding = holder.getBinding<ItemLoginMethodBinding>()
         val item = holder.getModel<LoginMenuEntity>()
@@ -147,13 +151,17 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
             if (item.loginType == 3) {
                 inAccountLogin = true
             }
-            LoginDialog.show(this@LoginActivity, viewModel, item.loginType) {
+            loginDialog = LoginDialog.show(this@LoginActivity, viewModel, item.loginType) {
                 LoadingEvent.sendLoadingEvent()
+                loginDialog?.dismiss()
                 when (it) {
                     LoginResultEnum.FINGERPRINTER_VERIFY_SUCCESS -> {
-                        showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.fingerprint_login_success))
-                        startActivity(Intent(this@LoginActivity, MainActivity::class.java))
-                        finish()
+                        lifecycleScope.launch(Dispatchers.Main) {
+                            showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.fingerprint_login_success))
+                            delay(1500)
+                            startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                            finish()
+                        }
                     }
 
                     LoginResultEnum.FINGERPRINTER_VERIFY_FAILED -> showToast(
@@ -161,9 +169,12 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
                     )
 
                     LoginResultEnum.FACE_VERIFY_SUCCESS -> {
-                        showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.face_login_success))
-                        startActivity(Intent(this@LoginActivity, MainActivity::class.java))
-                        finish()
+                        lifecycleScope.launch(Dispatchers.Main) {
+                            showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.face_login_success))
+                            delay(1500)
+                            startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                            finish()
+                        }
                     }
 
                     LoginResultEnum.FACE_VERIFY_FAILED -> showToast(
@@ -171,11 +182,14 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
                     )
 
                     LoginResultEnum.USERNAME_PASSWORD_LOGIN_SUCCESS -> {
-                        showToast(
-                            CommonUtils.getStr(com.grkj.ui_base.R.string.username_passowrd_login_success)
-                        )
-                        startActivity(Intent(this@LoginActivity, MainActivity::class.java))
-                        finish()
+                        lifecycleScope.launch(Dispatchers.Main) {
+                            showToast(
+                                CommonUtils.getStr(com.grkj.ui_base.R.string.username_passowrd_login_success)
+                            )
+                            delay(1500)
+                            startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                            finish()
+                        }
                     }
 
                     LoginResultEnum.USERNAME_OR_PASSWORD_ERROR -> showToast(
@@ -187,14 +201,16 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
                     )
 
                     LoginResultEnum.JOB_CARD_LOGIN_SUCCESS -> {
-                        showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.job_card_login_success))
-                        startActivity(Intent(this@LoginActivity, MainActivity::class.java))
-                        finish()
+                        lifecycleScope.launch(Dispatchers.Main) {
+                            showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.job_card_login_success))
+                            delay(1500)
+                            startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                            finish()
+                        }
                     }
 
-                    LoginResultEnum.JOB_CARD_LOGIN_FAILED -> showToast(
-                        CommonUtils.getStr(com.grkj.ui_base.R.string.job_card_login_failed)
-                    )
+                    LoginResultEnum.JOB_CARD_LOGIN_FAILED -> showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.job_card_login_failed))
+
                     LoginResultEnum.LOGIN_FAILED_NO_ALLOW_COLOCKER -> showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.login_no_allow_colocker))
                 }
             }.setDialogLifecycleCallback(object : DialogLifecycleCallback<CustomDialog>() {
@@ -281,8 +297,9 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
                     true
                 )
             }
+
             override fun onScan(bitmap: Bitmap) {
-                if (FingerprintUtil.isZKDevice){
+                if (FingerprintUtil.isZKDevice) {
                     LoadingEvent.sendLoadingEvent(
                         CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),
                         true

+ 8 - 8
iscs_lock/src/main/java/com/grkj/iscs/features/main/dialog/CheckFaceDialog.kt

@@ -1,18 +1,19 @@
 package com.grkj.iscs.features.main.dialog
 
 import android.graphics.Bitmap
+import android.util.Log
 import android.view.View
 import androidx.lifecycle.LifecycleOwner
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.enums.LoginResultEnum
+import com.grkj.data.hardware.face.FaceUtil
+import com.grkj.data.utils.event.LoadingEvent
+import com.grkj.data.utils.event.ToastEvent
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.DialogCheckFaceBinding
-import com.grkj.data.hardware.face.FaceUtil
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.skin.loadSkinIcon
 import com.grkj.ui_base.utils.CommonUtils
-import com.grkj.data.utils.event.LoadingEvent
-import com.grkj.data.utils.event.ToastEvent
 import com.grkj.ui_base.utils.fingerprint.FingerprintUtil
 import com.kongzue.dialogx.dialogs.CustomDialog
 import com.kongzue.dialogx.dialogs.PopTip
@@ -159,9 +160,8 @@ class CheckFaceDialog(
     private fun startFace() {
         FaceUtil.inDetecting = false
         ActivityTracker.getCurrentActivity()?.let { context ->
-            FaceUtil.checkCamera(
-                mBinding.preview!!,
-            ) { bitmap,faceRect, userId ->
+            FaceUtil.checkCamera(mBinding.preview!!) { bitmap, faceRect, userId ->
+                Log.d("人脸库", "匹配到的userId -> $userId, 传入userId -> ${this.userId}")
                 if (bitmap == null || userId == null) {
                     ToastEvent.sendToastEvent(CommonUtils.getStr(com.grkj.ui_base.R.string.face_login_failed))
                     return@checkCamera
@@ -171,7 +171,7 @@ class CheckFaceDialog(
                     return@checkCamera
                 }
                 inFaceChecking = true
-                LoadingEvent.sendLoadingEvent()
+                LoadingEvent.sendLoadingEvent(CommonUtils.getStr("doing_checking"))
                 if (userId != this.userId) {
                     FaceUtil.stop()
                     dialog?.dismiss()
@@ -182,7 +182,7 @@ class CheckFaceDialog(
                     dialog?.dismiss()
                     callBack?.invoke(LoginResultEnum.FACE_VERIFY_SUCCESS)
                 }
-                LoadingEvent.sendLoadingEvent(CommonUtils.getStr("doing_checking"))
+                LoadingEvent.sendLoadingEvent()
             }
         }
     }

+ 21 - 10
iscs_lock/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobExecuteFragment.kt

@@ -6,6 +6,7 @@ import android.widget.LinearLayout
 import androidx.core.view.isVisible
 import androidx.fragment.app.viewModels
 import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
 import com.drake.brv.BindingAdapter
 import com.drake.brv.annotaion.DividerOrientation
@@ -28,6 +29,7 @@ import com.grkj.data.domain.vo.IsJobTicketUserDataVo
 import com.grkj.data.domain.vo.JobTicketGroupInfoVo
 import com.grkj.data.enums.LoginResultEnum
 import com.grkj.data.enums.RoleEnum
+import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.iscs.R
 import com.grkj.iscs.common.DataTransferConstants
 import com.grkj.iscs.databinding.FragmentJobExecuteBinding
@@ -55,6 +57,9 @@ import com.sik.sikcore.date.TimeUtils
 import com.sik.sikcore.extension.getMMKVData
 import com.sik.sikcore.extension.setDebouncedClickListener
 import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.launch
 
 /**
  * 作业执行界面
@@ -231,7 +236,7 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
 
     private fun toLock(groupId: Long) {
         val groupKey = viewModel.ticketKey.find { it.groupId == groupId && it.ticketType == 0 }
-        if (groupKey?.collectTime != null && groupKey.giveBackTime == null) {
+        if (groupKey?.collectTime != null && groupKey.giveBackTime.isNullOrEmpty()) {
             showToast(CommonUtils.getStr("group_job_in_progress"))
             return
         }
@@ -242,7 +247,7 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
 
     private fun toUnLock(groupId: Long) {
         val groupKey = viewModel.ticketKey.find { it.groupId == groupId && it.ticketType == 1 }
-        if (groupKey?.collectTime != null && groupKey.giveBackTime == null) {
+        if (groupKey?.collectTime != null && groupKey.giveBackTime.isNullOrEmpty()) {
             showToast(CommonUtils.getStr("group_job_in_progress"))
             return
         }
@@ -259,6 +264,8 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                     is UiEvent.FaceCheck -> {
                         CheckFaceDialog.show(viewLifecycleOwner, viewModel, 0) {
                             viewModel.onParamProvided(it)
+                            // 关闭加载中的动画
+                            LoadingEvent.sendLoadingEvent()
                         }
                     }
 
@@ -461,11 +468,15 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                     if (it.isEmpty()) {
                         showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.current_user_has_not_face_data))
                     } else {
-                        CheckFaceDialog.show(viewLifecycleOwner, viewModel, 0) {
-                            if (it == LoginResultEnum.FACE_VERIFY_SUCCESS) {
-                                coLockByUserId(item.userId)
-                            } else {
-                                showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.invalid_user))
+                        CheckFaceDialog.show(viewLifecycleOwner, viewModel, 0, userId = item.userId) { res ->
+                            lifecycleScope.launch(Dispatchers.Main) {
+                                delay(500)
+                                LoadingEvent.sendLoadingEvent()
+                                if (res == LoginResultEnum.FACE_VERIFY_SUCCESS) {
+                                    coLockByUserId(item.userId)
+                                } else {
+                                    showToast(CommonUtils.getStr(com.grkj.ui_base.R.string.invalid_user))
+                                }
                             }
                         }.setDialogLifecycleCallback(object :
                             DialogLifecycleCallback<CustomDialog>() {
@@ -567,9 +578,9 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
         viewModel.coLockByUserId(userId, { colocker ->
             logger.info("添加共锁")
             TipDialog.showInfo(
-                msg = CommonUtils.getStr(
-                    "confirm_to_colock", colocker.nickName ?: ""
-                ).toString(), countDownTime = 10, onConfirmClick = {
+                msg = CommonUtils.getStr("confirm_to_colock", colocker.nickName ?: ""),
+                countDownTime = 10,
+                onConfirmClick = {
                     colocker.jobStatus = "1"
                     viewModel.colockerStatusChange(colocker).observe(this) {
                         if (it) {

+ 104 - 60
iscs_lock/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/MyTodoListFragment.kt

@@ -37,6 +37,7 @@ import com.grkj.ui_base.base.BaseFragment
 import com.grkj.ui_base.dialog.TipDialog
 import com.grkj.ui_base.dialog.WheelDateRangePickerDialog
 import com.grkj.ui_base.utils.CommonUtils
+import com.grkj.ui_base.utils.event.InRFIDScanModeEvent
 import com.grkj.ui_base.utils.event.RFIDCardReadEvent
 import com.grkj.ui_base.utils.event.UiEvent
 import com.kongzue.dialogx.dialogs.CustomDialog
@@ -54,6 +55,9 @@ class MyTodoListFragment : BaseFragment<FragmentMyTodoListBinding>() {
     private val viewModel: MyTodoViewModel by viewModels()
     private val jobExecuteViewModel: JobExecuteViewModel by viewModels()
     private var isFirstEnter: Boolean = true
+
+    // 共锁人刷卡共锁Dialog
+    private var colockerCardDialog: CustomDialog? = null
     private val tabKey: List<String> by lazy {
         listOf(
             CommonUtils.getStr("wait_header"),
@@ -280,36 +284,67 @@ class MyTodoListFragment : BaseFragment<FragmentMyTodoListBinding>() {
             item.previousTodoItem?.joinToString(",") { itemData -> "${I18nManager.t(itemData.todoType.todoTitle)}${itemData.groupName?.let { if (it.isEmpty()) "(${itemData.todoContent})" else "(${it})" }}" }
         itemBinding.btnPointDetail.isVisible =
             item.todoType == OperationTypeEnum.LOCK_TAKE_KEY || item.todoType == OperationTypeEnum.UNLOCK_TAKE_KEY || item.todoType == OperationTypeEnum.LOCK_RETURN_KEY || item.todoType == OperationTypeEnum.UNLOCK_RETURN_KEY
-
         if (jobExecuteViewModel.ticketId != item.ticketId) {
             jobExecuteViewModel.getWorkflowModes().observe(this) {
                 jobExecuteViewModel.ticketId = item.ticketId
                 getJobTicketData {
                     itemBinding.btnHandle.isVisible =
                         if (item.todoType == OperationTypeEnum.UNLOCK_TAKE_KEY) {
-                            val canUnLock =
-                                jobExecuteViewModel.ticketPoints.filter { it.groupId == item.groupId }
-                                    .all { it.pointStatus == "1" } && (jobExecuteViewModel.workflowModes.find { it.modeId == jobExecuteViewModel.ticketData?.modeId }?.isColockSupport == false || (jobExecuteViewModel.workflowModes.find { it.modeId == jobExecuteViewModel.ticketData?.modeId }?.isColockSupport == true && jobExecuteViewModel.ticketUser.filter { it.userRole == RoleEnum.JTCOLOCKER.roleKey }
-                                    .all { it.jobStatus == "2" }))
+                            val canUnLock = jobExecuteViewModel.ticketPoints.filter { it.groupId == item.groupId }
+                                .all { it.pointStatus == "1" }
+                                    && (jobExecuteViewModel.workflowModes.find { it.modeId == jobExecuteViewModel.ticketData?.modeId }?.isColockSupport == false
+                                    || (jobExecuteViewModel.workflowModes.find { it.modeId == jobExecuteViewModel.ticketData?.modeId }?.isColockSupport == true
+                                    && jobExecuteViewModel.ticketUser.filter { it.userRole == RoleEnum.JTCOLOCKER.roleKey }
+                                .all { it.jobStatus == "2" }))
                             item.isCurrentStep && canUnLock
                         } else {
                             item.isCurrentStep && item.todoType != OperationTypeEnum.LOCK_RETURN_KEY && item.todoType != OperationTypeEnum.UNLOCK_RETURN_KEY
                         } && item.todoStatus == TodoStatusEnum.TODO
+                    // 如果钥匙已经归还,需要确认点位是否隔离完成或者解除隔离完成,如果没有,按钮依然要显示
+                    if (item.isCurrentStep && listOf(
+                            OperationTypeEnum.LOCK_RETURN_KEY,
+                            OperationTypeEnum.UNLOCK_RETURN_KEY
+                        ).contains(item.todoType)
+                    ) {
+                        itemBinding.btnHandle.isVisible = if (item.todoType == OperationTypeEnum.LOCK_RETURN_KEY) {
+                            // 上锁操作,校验点位是否都已隔离
+                            jobExecuteViewModel.ticketPoints.filter { it.groupId == item.groupId }
+                                .any { it.pointStatus == "0" }
+                        } else {
+                            // 解锁操作,校验点位是否都已解除隔离
+                            jobExecuteViewModel.ticketPoints.filter { it.groupId == item.groupId }
+                                .any { it.pointStatus == "1" }
+                        }
+                    }
                 }
             }
         } else {
-            itemBinding.btnHandle.isVisible =
-                if (item.todoType == OperationTypeEnum.UNLOCK_TAKE_KEY) {
-                    val canUnLock =
-                        jobExecuteViewModel.ticketPoints.filter { it.groupId == item.groupId }
-                            .all { it.pointStatus == "1" } && (jobExecuteViewModel.workflowModes.find { it.modeId == jobExecuteViewModel.ticketData?.modeId }?.isColockSupport == false || (jobExecuteViewModel.workflowModes.find { it.modeId == jobExecuteViewModel.ticketData?.modeId }?.isColockSupport == true && jobExecuteViewModel.ticketUser.filter { it.userRole == RoleEnum.JTCOLOCKER.roleKey }
-                            .all { it.jobStatus == "2" }))
-                    item.isCurrentStep && canUnLock
+            itemBinding.btnHandle.isVisible = if (item.todoType == OperationTypeEnum.UNLOCK_TAKE_KEY) {
+                val canUnLock = jobExecuteViewModel.ticketPoints.filter { it.groupId == item.groupId }
+                    .all { it.pointStatus == "1" }
+                        && (jobExecuteViewModel.workflowModes.find { it.modeId == jobExecuteViewModel.ticketData?.modeId }?.isColockSupport == false
+                        || (jobExecuteViewModel.workflowModes.find { it.modeId == jobExecuteViewModel.ticketData?.modeId }?.isColockSupport == true
+                        && jobExecuteViewModel.ticketUser.filter { it.userRole == RoleEnum.JTCOLOCKER.roleKey }
+                    .all { it.jobStatus == "2" }))
+                item.isCurrentStep && canUnLock
+            } else {
+                item.isCurrentStep && item.todoType != OperationTypeEnum.LOCK_RETURN_KEY && item.todoType != OperationTypeEnum.UNLOCK_RETURN_KEY
+            } && item.todoStatus == TodoStatusEnum.TODO
+            // 如果钥匙已经归还,需要确认点位是否隔离完成或者解除隔离完成,如果没有,按钮依然要显示
+            if (item.isCurrentStep && listOf(
+                    OperationTypeEnum.LOCK_RETURN_KEY,
+                    OperationTypeEnum.UNLOCK_RETURN_KEY
+                ).contains(item.todoType)
+            ) {
+                itemBinding.btnHandle.isVisible = if (item.todoType == OperationTypeEnum.LOCK_RETURN_KEY) {
+                    // 上锁操作,校验点位是否都已隔离
+                    jobExecuteViewModel.ticketPoints.filter { it.groupId == item.groupId }.any { it.pointStatus == "0" }
                 } else {
-                    item.isCurrentStep && item.todoType != OperationTypeEnum.LOCK_RETURN_KEY && item.todoType != OperationTypeEnum.UNLOCK_RETURN_KEY
-                } && item.todoStatus == TodoStatusEnum.TODO
+                    // 解锁操作,校验点位是否都已解除隔离
+                    jobExecuteViewModel.ticketPoints.filter { it.groupId == item.groupId }.any { it.pointStatus == "1" }
+                }
+            }
         }
-
         itemBinding.btnPointDetail.setDebouncedClickListener {
             viewModel.getTicketPointsData(item.ticketId).observe(this) {
                 TodoPointDetailDialog.show(it.filter { it.groupId == item.groupId })
@@ -320,41 +355,56 @@ class MyTodoListFragment : BaseFragment<FragmentMyTodoListBinding>() {
                 TipDialog.showError(CommonUtils.getStr("handle_unknown"))
                 return@setDebouncedClickListener
             }
+            if (item.todoType == OperationTypeEnum.LOCK_RETURN_KEY || item.todoType == OperationTypeEnum.UNLOCK_RETURN_KEY) {
+                val type = if (item.todoType == OperationTypeEnum.LOCK_RETURN_KEY) 0 else 1
+                val groupKey =
+                    jobExecuteViewModel.ticketKey.find { key -> key.groupId == item.groupId && key.ticketType == type }
+                if (groupKey?.collectTime != null && groupKey.giveBackTime.isNullOrEmpty()) {
+                    showToast(CommonUtils.getStr("group_job_in_progress"))
+                    return@setDebouncedClickListener
+                }
+            }
             TipDialog.showInfo(viewModel.getHandleTip(item), onConfirmClick = {
                 jobExecuteViewModel.getWorkflowModes().observe(this) {
                     jobExecuteViewModel.ticketId = item.ticketId
                     getJobTicketData(true) {
                         when (item.todoType) {
+                            OperationTypeEnum.LOCK_RETURN_KEY,
                             OperationTypeEnum.LOCK_TAKE_KEY -> item.groupId?.let {
                                 jobExecuteViewModel.toLock(it).observe(this) {}
                             } ?: showToast(CommonUtils.getStr("not_group_can_lock"))
 
+                            OperationTypeEnum.UNLOCK_RETURN_KEY,
                             OperationTypeEnum.UNLOCK_TAKE_KEY -> item.groupId?.let {
                                 jobExecuteViewModel.toUnLock(it).observe(this) {}
                             } ?: showToast(CommonUtils.getStr("not_group_can_unlock"))
 
                             OperationTypeEnum.COLOCK -> {
                                 viewModel.startReadCard = true
-                                SwipCardOperationTipDialog.show()
-                                    .setDialogLifecycleCallback(object :
-                                        DialogLifecycleCallback<CustomDialog>() {
-                                        override fun onDismiss(dialog: CustomDialog) {
-                                            viewModel.startReadCard = false
-                                            super.onDismiss(dialog)
-                                        }
-                                    })
+                                InRFIDScanModeEvent.sendInRFIDScanModeEvent(true)
+                                colockerCardDialog = SwipCardOperationTipDialog.show()
+                                colockerCardDialog?.setDialogLifecycleCallback(object :
+                                    DialogLifecycleCallback<CustomDialog>() {
+                                    override fun onDismiss(dialog: CustomDialog) {
+                                        viewModel.startReadCard = false
+                                        InRFIDScanModeEvent.sendInRFIDScanModeEvent(false)
+                                        super.onDismiss(dialog)
+                                    }
+                                })
                             }
 
                             OperationTypeEnum.RELEASE_COLOCK -> {
                                 viewModel.startReadCard = true
-                                SwipCardOperationTipDialog.show()
-                                    .setDialogLifecycleCallback(object :
-                                        DialogLifecycleCallback<CustomDialog>() {
-                                        override fun onDismiss(dialog: CustomDialog) {
-                                            viewModel.startReadCard = false
-                                            super.onDismiss(dialog)
-                                        }
-                                    })
+                                InRFIDScanModeEvent.sendInRFIDScanModeEvent(true)
+                                colockerCardDialog = SwipCardOperationTipDialog.show()
+                                colockerCardDialog?.setDialogLifecycleCallback(object :
+                                    DialogLifecycleCallback<CustomDialog>() {
+                                    override fun onDismiss(dialog: CustomDialog) {
+                                        viewModel.startReadCard = false
+                                        InRFIDScanModeEvent.sendInRFIDScanModeEvent(false)
+                                        super.onDismiss(dialog)
+                                    }
+                                })
                             }
 
                             OperationTypeEnum.CONFIRM -> {
@@ -418,39 +468,34 @@ class MyTodoListFragment : BaseFragment<FragmentMyTodoListBinding>() {
         super.onEvent(event)
         when (event.code) {
             EventConstants.EVENT_RFID_CARD_READ -> {
+                colockerCardDialog?.dismiss()
+                // 检查当前登录用户是否
                 if (MainDomainData.userInfo?.userName != jobExecuteViewModel.ticketData?.createBy) {
-                    showToast(
-                        CommonUtils.getStr("no_permission_to_handle")
-                            .toString()
-                    )
-                    return
-                }
-                if (!viewModel.startReadCard) {
+                    showToast(CommonUtils.getStr("no_permission_to_handle"))
                     return
                 }
+                // 校验是否正在读卡中,不是返回
+                if (!viewModel.startReadCard) return
                 (event.data as RFIDCardReadEvent).let {
-                    val currentWorkflowStep = jobExecuteViewModel.currentStepData
-                    //当前步骤能加共锁并且锁已经上锁或者当前步骤能解共锁并且锁已经上锁
-                    if ((currentWorkflowStep?.enableColock == true || currentWorkflowStep?.enableReleaseColock == true) && jobExecuteViewModel.ticketPoints.all { it.pointStatus == "1" }) {
+                    val currentStep = jobExecuteViewModel.currentStepData ?: return
+                    // 当前步骤能加共锁并且锁已经上锁或者当前步骤能解共锁并且锁已经上锁
+                    if ((currentStep.enableColock || currentStep.enableReleaseColock) && jobExecuteViewModel.ticketPoints.all { point -> point.pointStatus == "1" }) {
                         jobExecuteViewModel.getUserIdByCardRfid(it.rfidNo).observe(this) { userId ->
                             userId?.let {
-                                val isJobCardUser = jobExecuteViewModel.ticketUser.filter {
-                                    it.userRole?.contains(
-                                        RoleEnum.JTCOLOCKER.roleKey
-                                    ) == true
-                                }.find { it.userId == userId }
+                                val isJobCardUser = jobExecuteViewModel.ticketUser.filter { colocker ->
+                                    colocker.userRole?.contains(RoleEnum.JTCOLOCKER.roleKey) == true
+                                }.find { colocker -> colocker.userId == userId }
                                 isJobCardUser?.let { colocker ->
-                                    if (colocker.jobStatus == "0" && currentWorkflowStep.enableColock) {
+                                    if (colocker.jobStatus == "0" && currentStep.enableColock) {
                                         logger.info("添加共锁")
                                         TipDialog.showInfo(
-                                            msg = CommonUtils.getStr(
-                                                "confirm_to_colock",
-                                                colocker.nickName ?: ""
-                                            ).toString(), countDownTime = 10, onConfirmClick = {
+                                            msg = CommonUtils.getStr("confirm_to_colock", colocker.nickName ?: ""),
+                                            countDownTime = 10,
+                                            onConfirmClick = {
                                                 colocker.jobStatus = "1"
                                                 jobExecuteViewModel.colockerStatusChange(colocker)
-                                                    .observe(this) {
-                                                        if (it) {
+                                                    .observe(this) { rsp ->
+                                                        if (rsp) {
                                                             showToast(CommonUtils.getStr("colock_complete"))
                                                             checkStepComplete()
                                                             getData()
@@ -459,17 +504,16 @@ class MyTodoListFragment : BaseFragment<FragmentMyTodoListBinding>() {
                                                         }
                                                     }
                                             })
-                                    } else if (colocker.jobStatus == "1" && currentWorkflowStep.enableReleaseColock) {
+                                    } else if (colocker.jobStatus == "1" && currentStep.enableReleaseColock) {
                                         logger.info("解除共锁")
                                         TipDialog.showInfo(
-                                            msg = CommonUtils.getStr(
-                                                "confirm_to_uncolock",
-                                                colocker.nickName ?: ""
-                                            ).toString(), countDownTime = 10, onConfirmClick = {
+                                            msg = CommonUtils.getStr("confirm_to_uncolock", colocker.nickName ?: ""),
+                                            countDownTime = 10,
+                                            onConfirmClick = {
                                                 colocker.jobStatus = "2"
                                                 jobExecuteViewModel.colockerStatusChange(colocker)
-                                                    .observe(this) {
-                                                        if (it) {
+                                                    .observe(this) { rsp ->
+                                                        if (rsp) {
                                                             showToast(CommonUtils.getStr("uncolock_complete"))
                                                             checkStepComplete()
                                                             getData()

+ 11 - 6
iscs_lock/src/main/java/com/grkj/iscs/features/main/viewmodel/data_manage/UserManageViewModel.kt

@@ -1,18 +1,20 @@
 package com.grkj.iscs.features.main.viewmodel.data_manage
 
+import android.util.Log
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
-import com.grkj.data.local.dos.SysRole
-import com.grkj.data.domain.vo.AddUserDataVo
-import com.grkj.data.domain.vo.UpdateUserDataVo
-import com.grkj.data.domain.vo.UserManageFilterVo
-import com.grkj.data.domain.vo.UserManageVo
-import com.grkj.data.domain.vo.WorkstationManageVo
+import com.google.gson.Gson
 import com.grkj.data.domain.logic.IHardwareLogic
 import com.grkj.data.domain.logic.IJobTicketLogic
 import com.grkj.data.domain.logic.IRoleLogic
 import com.grkj.data.domain.logic.IUserLogic
 import com.grkj.data.domain.logic.IWorkstationLogic
+import com.grkj.data.domain.vo.AddUserDataVo
+import com.grkj.data.domain.vo.UpdateUserDataVo
+import com.grkj.data.domain.vo.UserManageFilterVo
+import com.grkj.data.domain.vo.UserManageVo
+import com.grkj.data.domain.vo.WorkstationManageVo
+import com.grkj.data.local.dos.SysRole
 import com.grkj.data.local.dos.SysUserCharacteristicDo
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.utils.CommonUtils
@@ -68,6 +70,9 @@ class UserManageViewModel @Inject constructor(
         }
         return liveData(Dispatchers.IO) {
             val userManageDataPage = userLogic.getUserManagerData(filterData, current, size)
+            userManageDataPage.forEach {
+                Log.d("UserManager", "${Gson().toJson(it)}")
+            }
             userManageDataList.addAll(userManageDataPage)
             emit(true)
         }

+ 40 - 76
iscs_lock/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobExecuteViewModel.kt

@@ -221,21 +221,14 @@ class JobExecuteViewModel @Inject constructor(
      */
     fun toLock(groupId: Long): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
-            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(
-                    DeviceConst.DEVICE_TYPE_LOCK, ticketId
-                )
-            ) {
+            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(DeviceConst.DEVICE_TYPE_LOCK, ticketId)) {
                 showLoading(CommonUtils.getStr("please_take_out_ready_device_first"))
                 return@liveData
             }
-            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(
-                    DeviceConst.DEVICE_TYPE_KEY, ticketId
-                )
-            ) {
+            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(DeviceConst.DEVICE_TYPE_KEY, ticketId)) {
                 showLoading(CommonUtils.getStr("check_key_and_lock"))
-                val rfid = HardwareBusinessManager.getWaitTakeDeviceByTicketId(
-                    DeviceConst.DEVICE_TYPE_KEY, ticketId
-                )?.nfc
+                val rfid =
+                    HardwareBusinessManager.getWaitTakeDeviceByTicketId(DeviceConst.DEVICE_TYPE_KEY, ticketId)?.nfc
                 if (rfid != null) {
                     val keyMac = HardwareBusinessManager.getKeyMacByRfid(rfid)
                     HardwareBusinessManager.checkTicketAndSendTicket(keyMac)
@@ -245,15 +238,13 @@ class JobExecuteViewModel @Inject constructor(
                 }
             }
             val ticketDetail = LogicManager.jobTicketLogic.getTicketDetail(ticketId)
-            val role =
-                ticketDetail?.ticketUserVOList?.filter { it.userRole == RoleEnum.JTLOCKER.roleKey }
-                    ?.find {
-                        it.userId == MainDomainData.userInfo?.userId && it.groupId == groupId
-                    }
+            val role = ticketDetail?.ticketUserVOList?.filter { it.userRole == RoleEnum.JTLOCKER.roleKey }?.find {
+                it.userId == MainDomainData.userInfo?.userId && it.groupId == groupId
+            }
             if (role == null) {
                 ThreadUtils.runOnMain {
-                    PopTip.build()
-                        .tip(CommonUtils.getStr("no_permission_to_handle"))
+                    LoadingEvent.sendLoadingEvent()
+                    PopTip.build().tip(CommonUtils.getStr("no_permission_to_handle"))
                 }
                 return@liveData
             }
@@ -268,32 +259,30 @@ class JobExecuteViewModel @Inject constructor(
             if (!verifySuccess) {
                 return@liveData
             }
-            HardwareBusinessManager.checkEquipCount(ticketId, ticketPoints.count {
+            // 查找点位信息,需要隔离的点位,计算所需要的挂锁数量
+            val needLockCount = ticketPoints.count {
                 it.groupId == groupId && (it.pointStatus == "0" || (it.pointStatus == "2" && isUnlockFirst))
-            }, true) { keyMap, lockMap ->
+            }
+            HardwareBusinessManager.checkEquipCount(ticketId, needLockCount, true) { keyMap, lockMap ->
                 if (lockMap.isEmpty()) {
                     TipDialog.show(
-                        CommonUtils.getStr("action_failed").toString(),
-                        CommonUtils.getStr("lock_is_not_enough").toString(),
+                        CommonUtils.getStr("action_failed"),
+                        CommonUtils.getStr("lock_is_not_enough"),
                         TipDialog.DialogType.ERROR,
-                        onConfirmClick = {
-                            LoadingEvent.sendLoadingEvent()
-                        })
+                        onConfirmClick = { LoadingEvent.sendLoadingEvent() },
+                        onCancelClick = { LoadingEvent.sendLoadingEvent() })
                     return@checkEquipCount
                 }
                 if (keyMap == null) {
                     TipDialog.show(
-                        CommonUtils.getStr("action_failed").toString(),
-                        CommonUtils.getStr("no_available_key").toString(),
+                        CommonUtils.getStr("action_failed"),
+                        CommonUtils.getStr("no_available_key"),
                         TipDialog.DialogType.ERROR,
-                        onConfirmClick = {
-                            LoadingEvent.sendLoadingEvent()
-                        })
+                        onConfirmClick = { LoadingEvent.sendLoadingEvent() },
+                        onCancelClick = { LoadingEvent.sendLoadingEvent() })
                     return@checkEquipCount
                 } else {
-                    HardwareBusinessManager.addDeviceTake(
-                        DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second!!
-                    )
+                    HardwareBusinessManager.addDeviceTake(DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second!!)
                 }
                 MainDomainData.deviceTakeTicketGroupBound.put(ticketId, groupId)
                 val waitOpenLockDockSize = lockMap.keys.size
@@ -312,13 +301,9 @@ class JobExecuteViewModel @Inject constructor(
                             }
                             openedLockDockSize.addAndGet(1)
                             if (openedLockDockSize.get() >= waitOpenLockDockSize) {
-                                LoadingEvent.sendLoadingEvent(
-                                    CommonUtils.getStr(
-                                        "take_out_lock_tip", args = listOf(
-                                            lockMap.values.flatten().count().toInt()
-                                        ).toTypedArray()
-                                    ), true
-                                )
+                                val args = listOf(lockMap.values.flatten().count()).toTypedArray()
+                                val msg = CommonUtils.getStr("take_out_lock_tip", args = args)
+                                LoadingEvent.sendLoadingEvent(msg, true)
                             }
                         }
                     }
@@ -333,21 +318,14 @@ class JobExecuteViewModel @Inject constructor(
      */
     fun toUnLock(groupId: Long): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
-            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(
-                    DeviceConst.DEVICE_TYPE_LOCK, ticketId
-                )
-            ) {
+            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(DeviceConst.DEVICE_TYPE_LOCK, ticketId)) {
                 showLoading(CommonUtils.getStr("please_take_out_ready_device_first"))
                 return@liveData
             }
-            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(
-                    DeviceConst.DEVICE_TYPE_KEY, ticketId
-                )
-            ) {
+            if (HardwareBusinessManager.hasAnyDeviceWaitTakeByTicketId(DeviceConst.DEVICE_TYPE_KEY, ticketId)) {
                 showLoading(CommonUtils.getStr("check_key_and_lock"))
-                val rfid = HardwareBusinessManager.getWaitTakeDeviceByTicketId(
-                    DeviceConst.DEVICE_TYPE_KEY, ticketId
-                )?.nfc
+                val rfid =
+                    HardwareBusinessManager.getWaitTakeDeviceByTicketId(DeviceConst.DEVICE_TYPE_KEY, ticketId)?.nfc
                 if (rfid != null) {
                     val keyMac = HardwareBusinessManager.getKeyMacByRfid(rfid)
                     HardwareBusinessManager.checkTicketAndSendTicket(keyMac)
@@ -357,15 +335,12 @@ class JobExecuteViewModel @Inject constructor(
                 }
             }
             val ticketDetail = LogicManager.jobTicketLogic.getTicketDetail(ticketId)
-            val role =
-                ticketDetail?.ticketUserVOList?.filter { it.userRole == RoleEnum.JTLOCKER.roleKey }
-                    ?.find {
-                        it.userId == MainDomainData.userInfo?.userId && it.groupId == groupId
-                    }
+            val role = ticketDetail?.ticketUserVOList?.filter { it.userRole == RoleEnum.JTLOCKER.roleKey }?.find {
+                it.userId == MainDomainData.userInfo?.userId && it.groupId == groupId
+            }
             if (role == null) {
                 ThreadUtils.runOnMain {
-                    PopTip.build()
-                        .tip(CommonUtils.getStr("no_permission_to_handle"))
+                    PopTip.build().tip(CommonUtils.getStr("no_permission_to_handle"))
                 }
                 return@liveData
             }
@@ -384,8 +359,7 @@ class JobExecuteViewModel @Inject constructor(
                 //全部或不分交叉点位重叠进行重叠点位解锁
                 jobTicketRepository.updateCoincideToUnLock(ticketDetail, groupId)
                 if (ticketDetail.ticketPointsVOList?.filter { it.groupId == groupId }?.all {
-                        it.pointId in (ticketDetail.noUnlockTicketPointsVOSet?.map { it.pointId }
-                            ?: mutableListOf())
+                        it.pointId in (ticketDetail.noUnlockTicketPointsVOSet?.map { it.pointId } ?: mutableListOf())
                     } == true) {
                     MainDomainData.deviceTakeTicketGroupBound.put(ticketId, groupId)
                     BleBusinessManager.handleUnlockVirtualKeyReturn(ticketId, groupId)
@@ -394,24 +368,17 @@ class JobExecuteViewModel @Inject constructor(
                         LoadingEvent.sendLoadingEvent()
                         if (keyMap == null) {
                             TipDialog.show(
-                                CommonUtils.getStr("action_failed")
-                                    .toString(),
-                                CommonUtils.getStr("no_available_key")
-                                    .toString(),
+                                CommonUtils.getStr("action_failed"),
+                                CommonUtils.getStr("no_available_key"),
                                 TipDialog.DialogType.ERROR,
                                 showCancel = false
                             )
                             return@checkEquipCount
                         }
                         MainDomainData.deviceTakeTicketGroupBound.put(ticketId, groupId)
-                        HardwareBusinessManager.addDeviceTake(
-                            DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second!!
-                        )
-                        val deviceTakeUpdate = DeviceTakeUpdate(
-                            DeviceConst.DEVICE_TYPE_KEY,
-                            ticketId,
-                            keyMap.second ?: "",
-                        )
+                        HardwareBusinessManager.addDeviceTake(DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second!!)
+                        val deviceTakeUpdate =
+                            DeviceTakeUpdate(DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second ?: "")
                         BleBusinessManager.handleGiveKey(deviceTakeUpdate)
                     }
                 }
@@ -428,10 +395,7 @@ class JobExecuteViewModel @Inject constructor(
         val tickets = jobTicketRepository.samePointLockingTicket(ticketId)
         tickets.firstOrNull()?.let {
             PopTip.build().tip(
-                CommonUtils.getStr(
-                    "please_wait_ticket_name_lock_complete",
-                    args = listOf<String>(it.ticketName).toTypedArray()
-                )
+                CommonUtils.getStr("please_wait_ticket_name_lock_complete", args = listOf(it.ticketName).toTypedArray())
             )
         }
         return tickets.isEmpty()

+ 14 - 24
iscs_lock/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/MyTodoViewModel.kt

@@ -1,9 +1,7 @@
 package com.grkj.iscs.features.main.viewmodel.job_manage
 
-import android.util.Log
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
-import com.google.gson.Gson
 import com.grkj.data.data.DictConstants
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.domain.logic.IJobTicketLogic
@@ -83,10 +81,7 @@ class MyTodoViewModel @Inject constructor(
         }
     }
 
-    private fun splitTodoSteps(
-        all: List<TodoItemVo>,
-        waitLimit: Int = Int.MAX_VALUE        // 限制“批次”数量
-    ) {
+    private fun splitTodoSteps(all: List<TodoItemVo>, waitLimit: Int = Int.MAX_VALUE) {
         val tempTodo = mutableListOf<TodoItemVo>()
         val tempWait = mutableListOf<TodoItemVo>()
         val tempDone = mutableListOf<TodoItemVo>()
@@ -95,16 +90,15 @@ class MyTodoViewModel @Inject constructor(
         val grouped = all.groupBy { it.ticketId }
 
         for ((_, steps) in grouped) {
-            var doneSteps =
-                steps.filter {
-                    it.stepStatus == "1" && (!it.enableEndJob && it.ticketStatus in listOf(
-                        JobTicketStatusEnum.SELECT_MEMBER.status,
-                        JobTicketStatusEnum.LOCKING.status,
-                        JobTicketStatusEnum.COLOCKING.status,
-                        JobTicketStatusEnum.UNLOCKING.status,
-                        JobTicketStatusEnum.PROGRESSING.status,
-                    ) || it.ticketStatus == JobTicketStatusEnum.FINISHED.status)
-                }
+            var doneSteps = steps.filter {
+                it.stepStatus == "1" && (!it.enableEndJob && it.ticketStatus in listOf(
+                    JobTicketStatusEnum.SELECT_MEMBER.status,
+                    JobTicketStatusEnum.LOCKING.status,
+                    JobTicketStatusEnum.COLOCKING.status,
+                    JobTicketStatusEnum.UNLOCKING.status,
+                    JobTicketStatusEnum.PROGRESSING.status,
+                ) || it.ticketStatus == JobTicketStatusEnum.FINISHED.status)
+            }
             val pendingSteps =
                 steps.filter {
                     it.stepStatus == "0" || (it.stepStatus == "1" && it.enableEndJob
@@ -183,23 +177,19 @@ class MyTodoViewModel @Inject constructor(
      */
     fun getHandleTip(item: TodoItemVo): String {
         return when (item.todoType) {
+            OperationTypeEnum.LOCK_RETURN_KEY,
             OperationTypeEnum.LOCK_TAKE_KEY -> CommonUtils.getStr("handle_lock_take_key")
-                .toString()
 
+            OperationTypeEnum.UNLOCK_RETURN_KEY,
             OperationTypeEnum.UNLOCK_TAKE_KEY -> CommonUtils.getStr("handle_unlock_take_key")
-                .toString()
 
             OperationTypeEnum.COLOCK -> CommonUtils.getStr("handle_colock")
-                .toString()
 
             OperationTypeEnum.RELEASE_COLOCK -> CommonUtils.getStr("handle_release_colock")
-                .toString()
 
-            OperationTypeEnum.CONFIRM -> CommonUtils.getStr(
-                "handle_step_confirm", item.todoTitle.toString()
-            ).toString()
+            OperationTypeEnum.CONFIRM -> CommonUtils.getStr("handle_step_confirm", item.todoTitle.toString())
 
-            OperationTypeEnum.END -> CommonUtils.getStr("finish_job_tip").toString()
+            OperationTypeEnum.END -> CommonUtils.getStr("finish_job_tip")
             else -> ""
         }
     }

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

@@ -6,6 +6,11 @@ import com.google.gson.Gson
 import com.grkj.data.data.DictConstants
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.di.LogicManager
+import com.grkj.data.entity.local.DeviceTakeUpdate
+import com.grkj.data.entity.local.UpdateKeyReturn
+import com.grkj.data.entity.local.WorkTicketGet
+import com.grkj.data.entity.local.WorkTicketSend
+import com.grkj.data.entity.local.WorkTicketSend.LockListBO
 import com.grkj.data.enums.HardwareMode
 import com.grkj.data.enums.JobTicketStatusEnum
 import com.grkj.data.enums.RoleEnum
@@ -18,11 +23,6 @@ import com.grkj.data.hardware.ble.BleSendDispatcher
 import com.grkj.data.hardware.ble.CustomBleWriteCallback
 import com.grkj.data.hardware.modbus.DeviceConst
 import com.grkj.data.local.dos.IsJobTicketStep
-import com.grkj.data.entity.local.DeviceTakeUpdate
-import com.grkj.data.entity.local.UpdateKeyReturn
-import com.grkj.data.entity.local.WorkTicketGet
-import com.grkj.data.entity.local.WorkTicketSend
-import com.grkj.data.entity.local.WorkTicketSend.LockListBO
 import com.grkj.data.net.req.LockPointUpdateReq
 import com.grkj.data.net.res.TicketDetailRes
 import com.grkj.data.utils.event.LoadingEvent
@@ -728,21 +728,20 @@ object BleBusinessManager {
             val keyNfc = HardwareMode.getCurrentHardwareMode().getRfidByKeyMac(bleDevice.mac)
             workTicketGet?.data?.forEach { data ->
                 val updateList = mutableListOf<LockPointUpdateReq>()
-                data.dataList?.filter { it.closed == 1 && it.status == it.target }
-                    ?.forEach { dataListDTO ->
-                        data.taskCode?.toLong()?.let {
-                            SPUtils.returnKey(it)
-                        }
-                        val updateVO = LockPointUpdateReq(
-                            data.taskCode?.toLong(),
-                            if (dataListDTO.target == 0) dataListDTO.infoRfidNo else "",
-                            dataListDTO.equipRfidNo,
-                            keyNfc!!,
-                            dataListDTO.target,
-                            dataListDTO.status
-                        )
-                        updateList.add(updateVO)
+                data.dataList?.filter { it.closed == 1 && it.status == it.target }?.forEach { dataListDTO ->
+                    data.taskCode?.toLong()?.let {
+                        SPUtils.returnKey(it)
                     }
+                    val updateVO = LockPointUpdateReq(
+                        data.taskCode?.toLong(),
+                        if (dataListDTO.target == 0) dataListDTO.infoRfidNo else "",
+                        dataListDTO.equipRfidNo,
+                        keyNfc!!,
+                        dataListDTO.target,
+                        dataListDTO.status
+                    )
+                    updateList.add(updateVO)
+                }
 
                 LoadingEvent.sendLoadingEvent()
                 val ticketId = data.taskCode?.toLong()
@@ -803,7 +802,8 @@ object BleBusinessManager {
                                 if ((currentWorkflowStep?.enableLock == true && currentWorkflowStep.enableColock) || (currentWorkflowStep?.enableReleaseColock == true && currentWorkflowStep.enableUnlock || ticketPoints?.all { it.pointStatus == ticketPoints.firstOrNull()?.pointStatus } == false)) {
                                     logger.info("当前上锁和共锁或者解锁和解除共锁在同一步骤,或者所有点位的状态不统一,不更新步骤状态")
                                 } else {
-                                    ticketStepDataVo?.stepStatus = "1"
+                                    // 强制归还,认为当前节点任务未完成
+                                    ticketStepDataVo?.stepStatus = if (forceReturn) "0" else "1"
                                     ticketStepDataVo?.updateTime =
                                         TimeUtils.nowString(TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT)
                                     val isTicketStepData = BeanUtils.copyProperties(

+ 32 - 43
ui-base/src/main/java/com/grkj/ui_base/business/HardwareBusinessManager.kt

@@ -6,17 +6,17 @@ import com.grkj.data.data.DictConstants
 import com.grkj.data.data.MMKVConstants
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.di.LogicManager
+import com.grkj.data.entity.local.DeviceTakeUpdate
 import com.grkj.data.enums.HardwareMode
 import com.grkj.data.hardware.ble.BleSendDispatcher
 import com.grkj.data.hardware.can.CanCommands
 import com.grkj.data.hardware.can.CanDeviceConst
 import com.grkj.data.hardware.can.CanHelper
 import com.grkj.data.hardware.can.DeviceModel
+import com.grkj.data.hardware.can.HandlerGate
 import com.grkj.data.hardware.modbus.DeviceConst
 import com.grkj.data.hardware.modbus.DockBean
 import com.grkj.data.hardware.modbus.ModBusController
-import com.grkj.data.entity.local.DeviceTakeUpdate
-import com.grkj.data.hardware.can.HandlerGate
 import com.grkj.data.net.req.LockTakeUpdateReq
 import com.grkj.data.utils.event.LoadingEvent
 import com.grkj.shared.utils.extension.removeLeadingZeros
@@ -515,9 +515,7 @@ object HardwareBusinessManager {
                     return@readLockRfid
                 }
                 val rfid = res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
-                ModBusController.updateLockRfid(
-                    dockBean.addr, lockBean.idx, rfid
-                )
+                ModBusController.updateLockRfid(dockBean.addr, lockBean.idx, rfid)
                 ThreadUtils.runOnIO {
                     val lockStatusReq =
                         async { DataBusiness.fetchDict(DictConstants.KEY_PAD_LOCK_STATUS) }
@@ -532,21 +530,15 @@ object HardwareBusinessManager {
                         //锁rfid未异常正常请求锁数据,关锁
                         if (rfid in (lockData?.records?.filter {
                                 it.exStatus == lockStatus.find {
-                                    I18nManager.t(it.dictLabel) == I18nManager.t(
-                                        "abnormal"
-                                    )
+                                    I18nManager.t(it.dictLabel) == I18nManager.t("abnormal")
                                 }?.dictValue
                             }?.map { it.lockNfc }?.toMutableList() ?: mutableListOf())) {
                             PopTip.build().tip(CommonUtils.getStr("lock_exception_tag"))
                         } else if (slotsPage?.records?.filter {
                                 it.slotType == slotTypeList.find { d ->
-                                    I18nManager.t(d.dictLabel) == I18nManager.t(
-                                        "lock"
-                                    )
+                                    I18nManager.t(d.dictLabel) == I18nManager.t("lock")
                                 }?.dictValue && it.status == slotStatusList.find { d ->
-                                    I18nManager.t(d.dictLabel) == I18nManager.t(
-                                        "abnormal"
-                                    )
+                                    I18nManager.t(d.dictLabel) == I18nManager.t("abnormal")
                                 }?.dictValue
                             }
                                 ?.find { it.row?.toInt() == dockBean.row && (lockBean.idx + 1) == it.col?.toInt() } != null) {
@@ -555,16 +547,25 @@ object HardwareBusinessManager {
                             logger.info("挂锁归还:${lockBean.rfid}")
                             LogicManager.hardwareLogic.getLockInfo(rfid) {
                                 logger.info("挂锁信息:${it}")
-                                if (it != null && it.lockNfc?.isNotEmpty() == true) {
-                                    // TODO 考虑快速拿取
-                                    ModBusController.controlLockBuckle(
-                                        false, dockBean.addr, lockBean.idx
-                                    ) { itRst ->
-                                        if (itRst.isNotEmpty()) {
-                                            // 上报锁具信息
-                                            LogicManager.jobTicketLogic.updateLockReturn(
-                                                rfid, SIKCore.getApplication().serialNo()
-                                            ) {}
+                                LogicManager.hardwareLogic.getLockInUsed(rfid) { lockInUse ->
+                                    logger.info("挂锁信息 - 是否使用:$lockInUse")
+                                    if (lockInUse == true) {
+                                        PopTip.build().tip(CommonUtils.getStr("lock_in_use_take_out"))
+                                    } else {
+                                        if (it != null && it.lockNfc?.isNotEmpty() == true) {
+                                            ModBusController.controlLockBuckle(
+                                                false,
+                                                dockBean.addr,
+                                                lockBean.idx
+                                            ) { itRst ->
+                                                if (itRst.isNotEmpty()) {
+                                                    // 上报锁具信息
+                                                    LogicManager.jobTicketLogic.updateLockReturn(
+                                                        rfid,
+                                                        SIKCore.getApplication().serialNo()
+                                                    ) {}
+                                                }
+                                            }
                                         }
                                     }
                                 }
@@ -867,29 +868,19 @@ object HardwareBusinessManager {
                         )
                     } else {
                         // 放回钥匙,上锁
-                        ModBusController.controlKeyBuckle(
-                            false, keyBean.idx, dockBean.addr
-                        ) {
+                        ModBusController.controlKeyBuckle(false, keyBean.idx, dockBean.addr) {
                             LogicManager.hardwareLogic.getKeyInfo(rfid) {
                                 logger.info("钥匙:${rfid},${it}")
                                 if (it != null && !it.macAddress.isNullOrEmpty()) {
-                                    ModBusController.updateKeyMac(
-                                        dockBean.addr, keyBean.idx, it.macAddress!!
-                                    )
-                                    it.macAddress?.let {
-                                        MainDomainData.returnKeyList.add(it)
-                                    }
-                                    ModBusController.updateKeyReadyStatus(
-                                        it.macAddress!!, false, 5
-                                    )
+                                    ModBusController.updateKeyMac(dockBean.addr, keyBean.idx, it.macAddress!!)
+                                    it.macAddress?.let { MainDomainData.returnKeyList.add(it) }
+                                    ModBusController.updateKeyReadyStatus(it.macAddress!!, false, 5)
                                 } else {
                                     logger.error("Get key info fail : $rfid")
                                     if (ISCSConfig.isInit) {
                                         PopTip.build().tip(CommonUtils.getStr("get_key_info_fail"))
                                     }
-                                    ModBusController.controlKeyBuckle(
-                                        true, keyBean.idx, dockBean.addr
-                                    )
+                                    ModBusController.controlKeyBuckle(true, keyBean.idx, dockBean.addr)
                                 }
                                 Executor.delayOnMain(200) {
                                     listeners.forEach { it.callBack(dockBean) }
@@ -899,10 +890,8 @@ object HardwareBusinessManager {
                     }
                 }
             }
-        } else if (!keyBean.isCharging) {//增加充电判断,防止无线充电干扰锁仓状态导致判断为取出
-            handleDeviceTake(
-                DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_KEY, keyBean.rfid), keyBean.rfid
-            )
+        } else if (!keyBean.isCharging) { // 增加充电判断,防止无线充电干扰锁仓状态导致判断为取出
+            handleDeviceTake(DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_KEY, keyBean.rfid), keyBean.rfid)
             Executor.delayOnMain(200) {
                 listeners.forEach { it.callBack(dockBean) }
             }

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

@@ -404,6 +404,7 @@
     <string name="lock_damage">Damaged Padlock</string>
     <string name="lock_exception_tag">This lock has been flagged as abnormal</string>
     <string name="lock_in_use">Lock is currently in use</string>
+    <string name="lock_in_use_take_out">Lock is currently in use and cannot be returned.</string>
     <string name="lock_is_not_enough">Insufficient lock quantity</string>
     <string name="lock_key_return_tip">Job ticket not completed; force upload data?</string>
     <string name="lock_manage">Locks</string>

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

@@ -404,6 +404,7 @@
     <string name="lock_damage">挂锁损坏</string>
     <string name="lock_exception_tag">该挂锁已被标记异常</string>
     <string name="lock_in_use">挂锁正在使用中</string>
+    <string name="lock_in_use_take_out">挂锁正在使用中,禁止归还</string>
     <string name="lock_is_not_enough">锁具数量不足</string>
     <string name="lock_key_return_tip">作业票尚未完成,是否强制上传数据</string>
     <string name="lock_manage">挂锁管理</string>

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

@@ -404,6 +404,7 @@
     <string name="lock_damage">挂锁损坏</string>
     <string name="lock_exception_tag">该挂锁已被标记异常</string>
     <string name="lock_in_use">挂锁正在使用中</string>
+    <string name="lock_in_use_take_out">挂锁正在使用中,禁止归还</string>
     <string name="lock_is_not_enough">锁具数量不足</string>
     <string name="lock_key_return_tip">作业票尚未完成,是否强制上传数据</string>
     <string name="lock_manage">挂锁管理</string>