Ver código fonte

feat(作业票):
- `JobExecuteViewModel`: 新增`canCoLock`方法,判断当前是否可以执行共锁/解锁操作,条件为步骤允许共锁/解锁且所有风险点已上锁。
- `JobExecuteViewModel`: 新增`coLockByUserId`方法,根据用户ID执行共锁或解锁操作,并包含相应的成功、失败回调。
- `JobExecuteViewModel`: 新增`getFaceByUserId`方法,根据用户ID获取人脸数据。
- `JobExecuteFragment`: 在共锁人员列表项点击时,增加人脸识别验证流程。先检查用户是否已录入人脸数据,然后弹出`CheckFaceDialog`进行验证,验证通过后调用`coLockByUserId`执行共锁/解锁。
- `JobExecuteFragment`: 优化共锁/解锁逻辑,当通过刷卡触发时,也统一调用`coLockByUserId`方法处理。

refactor(用户):
- `IUserLogic`和其实现类`UserLogic`、`NetworkUserLogic`中的`checkFace`方法增加`userId`参数,允许校验指定用户的人脸信息,而非仅限当前登录用户。
- `JobExecuteViewModel`的构造函数中`userRepository`参数类型从`UserLogic`改为`IUserLogic`接口,提升代码的灵活性和可测试性。
- `BaseViewModel`中的`checkFace`方法同步修改,增加`userId`参数。
- `CheckFaceDialog`: 构造函数增加`userId`参数,用于指定人脸识别的目标用户。
- `CheckFaceDialog`: `show`静态方法增加`userId`参数,传递给构造函数。
- `CheckFaceDialog`: `startFace`方法中调用`viewModel.checkFace`时传递`userId`。

fix(UI):
- `dialog_check_face.xml`: 为`iv_icon`设置`android:tint="?attr/colorPrimary"`,使其颜色与主题一致。
- `UpdateUserDialog`: 修复当`userVo.faceSavePath`不为空时,`faceData`列表未正确添加人脸路径的问题,改为直接添加`userVo.faceSavePath`。

fix(数据):
- `JobUserVo`: 将`cardNfc`的数据类型从`String`修改为`String?`,允许其为空。

周文健 1 mês atrás
pai
commit
ac977c44f7

+ 7 - 3
app/src/main/java/com/grkj/iscs/features/main/dialog/CheckFaceDialog.kt

@@ -3,6 +3,7 @@ package com.grkj.iscs.features.main.dialog
 import android.graphics.Bitmap
 import android.view.View
 import androidx.lifecycle.LifecycleOwner
+import com.grkj.data.data.MainDomainData
 import com.grkj.data.enums.LoginResultEnum
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.DialogCheckFaceBinding
@@ -27,6 +28,7 @@ import com.sik.sikimage.ImageConvertUtils
 class CheckFaceDialog(
     private var lifecycleOwner: LifecycleOwner,
     private var viewModel: BaseViewModel,
+    private var userId: Long? = 0,
     private var callBack: ((LoginResultEnum) -> Unit)? = null
 ) : OnBindView<CustomDialog>(R.layout.dialog_check_face) {
     private var mLoginType = 0 // 0:人脸 1:指纹 2:工卡 3:账号
@@ -134,9 +136,10 @@ class CheckFaceDialog(
             lifecycleOwner: LifecycleOwner,
             viewModel: BaseViewModel,
             loginType: Int,
+            userId: Long? = MainDomainData.userInfo?.userId,
             callBack: ((LoginResultEnum) -> Unit)?
         ) {
-            CustomDialog.show(CheckFaceDialog(lifecycleOwner, viewModel, callBack).apply {
+            CustomDialog.show(CheckFaceDialog(lifecycleOwner, viewModel, userId, callBack).apply {
                 showByType(loginType)
             })
         }
@@ -146,7 +149,8 @@ class CheckFaceDialog(
     private fun startFace() {
         ArcSoftUtil.inDetecting = false
         ActivityTracker.getCurrentActivity()?.let { context ->
-            ArcSoftUtil.initCamera(mBinding.preview!!
+            ArcSoftUtil.initCamera(
+                mBinding.preview!!,
             ) { bitmap, faceSize, alive ->
                 bitmap?.let { itBitmap ->
                     if (faceSize == 0) {
@@ -159,7 +163,7 @@ class CheckFaceDialog(
                     }
                     inFaceChecking = true
                     viewModel.checkFace(
-                        ImageConvertUtils.bitmapToBase64(itBitmap).toString()
+                        ImageConvertUtils.bitmapToBase64(itBitmap).toString(), userId
                     ).observe(lifecycleOwner) {
                         LoadingEvent.sendLoadingEvent()
                         if (it == LoginResultEnum.FACE_VERIFY_FAILED) {

+ 2 - 2
app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/UpdateUserDialog.kt

@@ -72,9 +72,9 @@ class UpdateUserDialog(
         binding.workstationNameTv.text = userVo.workstationNames.filterNotNull().joinToString(",")
         binding.activateRb.isChecked = userVo.getStatus()
         binding.deactivateRb.isChecked = !userVo.getStatus()
-        if (userVo.faceSavePath != null) {
+        userVo.faceSavePath?.let {
             faceData.clear()
-            faceData.add(CommonUtils.getStr(R.string.face))
+            faceData.add(it)
         }
         if (userVo.fingerprintData.isNotEmpty()) {
             fingerprintGroupData.clear()

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

@@ -328,8 +328,7 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                             stepClickConfirm(adapter, item, workflowStep)
                         } else {
                             showToast(
-                                CommonUtils.getStr("no_permission_to_handle")
-                                    .toString()
+                                CommonUtils.getStr("no_permission_to_handle").toString()
                             )
                         }
                     } else {
@@ -354,8 +353,7 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
             if (viewModel.stepConditionsComplete(workflowStep)) {
                 TipDialog.showInfo(
                     msg = CommonUtils.getStr(
-                        "action_confirm_content",
-                        workflowStep?.stepTitleShort.toString()
+                        "action_confirm_content", workflowStep?.stepTitleShort.toString()
                     ).toString(), onConfirmClick = {
                         item.stepStatus = "1"
                         item.updateTime =
@@ -407,8 +405,7 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                 DataTransferConstants.KEY_PREVIEW_STEP_TITLE_DATA, viewModel.ticketData!!.ticketName
             )
             GlobalDataTempStore.getInstance().saveData(
-                DataTransferConstants.KEY_PREVIEW_STEP_ICON_DATA,
-                "arrow-progress-alt.svg"
+                DataTransferConstants.KEY_PREVIEW_STEP_ICON_DATA, "arrow-progress-alt.svg"
             )
             GlobalDataTempStore.getInstance()
                 .saveData(DataTransferConstants.KEY_JOB_TICKET_ID, viewModel.ticketId)
@@ -422,6 +419,25 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
         val itemBinding = holder.getBinding<ItemJobExecuteColockBinding>()
         val item = holder.getModel<IsJobTicketUserDataVo>()
         itemBinding.name.text = item.nickName
+        itemBinding.root.setDebouncedClickListener {
+            if (viewModel.canCoLock()) {
+                viewModel.getFaceByUserId(item.userId).observe(this) {
+                    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))
+                            }
+                        }
+                    }
+                }
+            } else {
+                showToast(CommonUtils.getStr("currently_unable_to_lock_together"))
+            }
+        }
     }
 
     private fun BindingAdapter.BindingViewHolder.onPointsRVListBinding(holder: BindingAdapter.BindingViewHolder) {
@@ -468,66 +484,17 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                     )
                 ) {
                     showToast(
-                        CommonUtils.getStr("no_permission_to_handle")
-                            .toString()
+                        CommonUtils.getStr("no_permission_to_handle").toString()
                     )
                     return
                 }
                 checkLayout(2)
                 (event.data as RFIDCardReadEvent).let {
-                    val currentWorkflowStep = viewModel.currentStepData
                     //当前步骤能加共锁并且锁已经上锁或者当前步骤能解共锁并且锁已经上锁
-                    if ((currentWorkflowStep?.enableColock == true || currentWorkflowStep?.enableReleaseColock == true) && viewModel.ticketPoints.all { it.pointStatus == "1" }) {
+                    if (viewModel.canCoLock()) {
                         viewModel.getUserIdByCardRfid(it.rfidNo).observe(this) { userId ->
                             userId?.let {
-                                val isJobCardUser = viewModel.ticketUser.filter {
-                                    it.userRole?.contains(
-                                        RoleEnum.JTCOLOCKER.roleKey
-                                    ) == true
-                                }.find { it.userId == userId }
-                                isJobCardUser?.let { colocker ->
-                                    if (colocker.jobStatus == "0" && currentWorkflowStep.enableColock) {
-                                        logger.info("添加共锁")
-                                        TipDialog.showInfo(
-                                            msg = CommonUtils.getStr(
-                                                "confirm_to_colock",
-                                                colocker.nickName ?: ""
-                                            ).toString(), countDownTime = 10, onConfirmClick = {
-                                                colocker.jobStatus = "1"
-                                                viewModel.colockerStatusChange(colocker)
-                                                    .observe(this) {
-                                                        if (it) {
-                                                            showToast(CommonUtils.getStr("colock_complete"))
-                                                            checkStepComplete()
-                                                        } else {
-                                                            showToast(CommonUtils.getStr("colock_failed"))
-                                                        }
-                                                        refreshTicketUser()
-                                                    }
-                                            })
-                                    } else if (colocker.jobStatus == "1" && currentWorkflowStep.enableReleaseColock) {
-                                        logger.info("解除共锁")
-                                        TipDialog.showInfo(
-                                            msg = CommonUtils.getStr(
-                                                "confirm_to_uncolock",
-                                                colocker.nickName ?: ""
-                                            ).toString(), countDownTime = 10, onConfirmClick = {
-                                                colocker.jobStatus = "2"
-                                                viewModel.colockerStatusChange(colocker)
-                                                    .observe(this) {
-                                                        if (it) {
-                                                            showToast(CommonUtils.getStr("uncolock_complete"))
-                                                            checkStepComplete()
-                                                        } else {
-                                                            showToast(CommonUtils.getStr("uncolock_failed"))
-                                                        }
-                                                        refreshTicketUser()
-                                                    }
-                                            })
-                                    } else {
-                                        showToast(CommonUtils.getStr("currently_unable_to_lock_together"))
-                                    }
-                                } ?: showToast(CommonUtils.getStr("invalid_user"))
+                                coLockByUserId(it)
                             } ?: showToast(CommonUtils.getStr("invalid_card"))
                         }
                     } else {
@@ -554,6 +521,48 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
         }
     }
 
+    private fun coLockByUserId(userId: Long) {
+        viewModel.coLockByUserId(userId, { colocker ->
+            logger.info("添加共锁")
+            TipDialog.showInfo(
+                msg = CommonUtils.getStr(
+                    "confirm_to_colock", colocker.nickName ?: ""
+                ).toString(), countDownTime = 10, onConfirmClick = {
+                    colocker.jobStatus = "1"
+                    viewModel.colockerStatusChange(colocker).observe(this) {
+                        if (it) {
+                            showToast(CommonUtils.getStr("colock_complete"))
+                            checkStepComplete()
+                        } else {
+                            showToast(CommonUtils.getStr("colock_failed"))
+                        }
+                        refreshTicketUser()
+                    }
+                })
+        }, { colocker ->
+            logger.info("解除共锁")
+            TipDialog.showInfo(
+                msg = CommonUtils.getStr(
+                    "confirm_to_uncolock", colocker.nickName ?: ""
+                ).toString(), countDownTime = 10, onConfirmClick = {
+                    colocker.jobStatus = "2"
+                    viewModel.colockerStatusChange(colocker).observe(this) {
+                        if (it) {
+                            showToast(CommonUtils.getStr("uncolock_complete"))
+                            checkStepComplete()
+                        } else {
+                            showToast(CommonUtils.getStr("uncolock_failed"))
+                        }
+                        refreshTicketUser()
+                    }
+                })
+        }, {
+            showToast(CommonUtils.getStr("currently_unable_to_lock_together"))
+        }, {
+            showToast(CommonUtils.getStr("invalid_user"))
+        })
+    }
+
     /**
      * 检查流程是否完成
      */
@@ -663,8 +672,7 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                 }
             } else {
                 TipDialog.showError(
-                    msg = CommonUtils.getStr("ticket_lost").toString(),
-                    onConfirmClick = {
+                    msg = CommonUtils.getStr("ticket_lost").toString(), onConfirmClick = {
                         navController.popBackStack()
                     })
             }

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

@@ -9,8 +9,8 @@ import com.grkj.data.enums.JobTicketStatusEnum
 import com.grkj.data.enums.RoleEnum
 import com.grkj.data.hardware.modbus.DeviceConst
 import com.grkj.data.logic.IJobTicketLogic
+import com.grkj.data.logic.IUserLogic
 import com.grkj.data.logic.IWorkflowLogic
-import com.grkj.data.logic.impl.standard.UserLogic
 import com.grkj.data.model.dos.IsJobTicketStep
 import com.grkj.data.model.dos.WorkflowMode
 import com.grkj.data.model.local.DeviceTakeUpdate
@@ -49,8 +49,8 @@ import javax.inject.Inject
 class JobExecuteViewModel @Inject constructor(
     val jobTicketRepository: IJobTicketLogic,
     val workflowRepository: IWorkflowLogic,
-    userRepository: UserLogic
-) : BaseViewModel(userRepository) {
+    override val userLogic: IUserLogic,
+) : BaseViewModel(userLogic) {
     var ticketId: Long = 0
     var ticketData: IsJobTicketDataVo? = null
     var ticketDataMap: MutableMap<Long, IsJobTicketDataVo?> = mutableMapOf()
@@ -859,4 +859,46 @@ class JobExecuteViewModel @Inject constructor(
                 .contains(RoleEnum.JTLOCKER.roleKey)) return true
         return false
     }
+
+    /**
+     * 是否可以共锁
+     */
+    fun canCoLock(): Boolean {
+        return (currentStepData?.enableColock == true || currentStepData?.enableReleaseColock == true) && ticketPoints.all { it.pointStatus == "1" }
+    }
+
+    /**
+     * 根据用户id共锁
+     */
+    fun coLockByUserId(
+        userId: Long,
+        coLockSuccess: (IsJobTicketUserDataVo) -> Unit,
+        releaseCoLockSuccess: (IsJobTicketUserDataVo) -> Unit,
+        coLockStepError: () -> Unit,
+        coLockerError: () -> Unit
+    ) {
+        val isJobCardUser = ticketUser.filter {
+            it.userRole?.contains(
+                RoleEnum.JTCOLOCKER.roleKey
+            ) == true
+        }.find { it.userId == userId }
+        isJobCardUser?.let { colocker ->
+            if (colocker.jobStatus == "0" && currentStepData?.enableColock == true) {
+                coLockSuccess(colocker)
+            } else if (colocker.jobStatus == "1" && currentStepData?.enableReleaseColock == true) {
+                releaseCoLockSuccess(colocker)
+            } else {
+                coLockStepError()
+            }
+        } ?: coLockerError()
+    }
+
+    /**
+     * 根据用户id获取用户数据
+     */
+    fun getFaceByUserId(userId: Long): LiveData<List<SysBiometricDataVo>> {
+        return liveData(Dispatchers.IO) {
+            emit(userLogic.getFaceDataByUserId(userId))
+        }
+    }
 }

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

@@ -22,6 +22,7 @@
                 android:id="@+id/iv_icon"
                 android:layout_width="@dimen/dialog_common_root_height_login_and_check"
                 android:layout_height="@dimen/dialog_common_root_height_login_and_check"
+                android:tint="?attr/colorPrimary"
                 android:layout_marginBottom="@dimen/iscs_space_1" />
 
             <TextView

+ 2 - 1
data/src/main/java/com/grkj/data/logic/IUserLogic.kt

@@ -1,5 +1,6 @@
 package com.grkj.data.logic
 
+import com.grkj.data.data.MainDomainData
 import com.grkj.data.enums.LoginResultEnum
 import com.grkj.data.model.dos.SysUserCharacteristicDo
 import com.grkj.data.model.dos.SysUserDo
@@ -48,7 +49,7 @@ interface IUserLogic {
     /**
      * 检查人脸
      */
-    fun checkFace(face: String): LoginResultEnum
+    fun checkFace(face: String, userId: Long? = MainDomainData.userInfo?.userId): LoginResultEnum
 
     /**
      * 退出登录

+ 1 - 1
data/src/main/java/com/grkj/data/logic/impl/network/NetworkUserLogic.kt

@@ -47,7 +47,7 @@ class NetworkUserLogic @Inject constructor() : BaseLogic(), IUserLogic {
         TODO("Not yet implemented")
     }
 
-    override fun checkFace(face: String): LoginResultEnum {
+    override fun checkFace(face: String, userId: Long?): LoginResultEnum {
         TODO("Not yet implemented")
     }
 

+ 6 - 4
data/src/main/java/com/grkj/data/logic/impl/standard/UserLogic.kt

@@ -108,7 +108,7 @@ class UserLogic @Inject constructor(
     }
 
     override fun deleteNoUseFingerprint(fingerprintData: List<String>, userId: Long) {
-        userRepository.deleteNoUseFingerprint(fingerprintData,userId)
+        userRepository.deleteNoUseFingerprint(fingerprintData, userId)
     }
 
     override fun clearNoUserFace() {
@@ -235,7 +235,7 @@ class UserLogic @Inject constructor(
         var userId: String? = null
         for (faceData in faceDataList) {
             if (faceData.content.isNotEmpty()) {
-                if (!faceData.content.exists()){
+                if (!faceData.content.exists()) {
                     continue
                 }
                 val fileData = faceData.content.file().readText()
@@ -271,8 +271,10 @@ class UserLogic @Inject constructor(
         return LoginResultEnum.FACE_VERIFY_FAILED
     }
 
-    override fun checkFace(face: String): LoginResultEnum {
-        val userId = MainDomainData.userInfo?.userId
+    override fun checkFace(
+        face: String,
+        userId: Long?
+    ): LoginResultEnum {
         if (userId == null) {
             return LoginResultEnum.FACE_VERIFY_FAILED
         }

+ 1 - 1
data/src/main/java/com/grkj/data/model/vo/JobUserVo.kt

@@ -12,7 +12,7 @@ class JobUserVo {
     var groupId: Long = 0
     var groupName: String? = ""
     var avatar: String? = null
-    var cardNfc: String = ""
+    var cardNfc: String? = ""
     var roleIds: List<Long?> = listOf()
     var roleNames: List<String?> = listOf()
     var roleKeys: List<String?> = listOf()

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

@@ -43,9 +43,9 @@ open class BaseViewModel constructor(
     /**
      * 检查人脸
      */
-    fun checkFace(faceB64: String): LiveData<LoginResultEnum> {
+    fun checkFace(faceB64: String, userId: Long?): LiveData<LoginResultEnum> {
         return liveData(Dispatchers.IO) {
-            emit(userLogic?.checkFace(faceB64) ?: LoginResultEnum.FACE_VERIFY_FAILED)
+            emit(userLogic?.checkFace(faceB64, userId) ?: LoginResultEnum.FACE_VERIFY_FAILED)
         }
     }