Просмотр исходного кода

refactor(更新)
- 人脸录入完成

周文健 4 месяцев назад
Родитель
Сommit
164cb5b65e

+ 2 - 1
app/src/main/java/com/grkj/iscs/ISCSApplication.kt

@@ -11,6 +11,7 @@ import com.grkj.data.data.EventConstants
 import com.grkj.data.di.RepositoryManager
 import com.grkj.iscs.features.splash.activity.SplashActivity
 import com.grkj.shared.model.EventBean
+import com.grkj.shared.utils.ArcSoftUtil
 import com.grkj.ui_base.business.ModbusBusinessManager
 import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.utils.ble.BleUtil
@@ -54,7 +55,7 @@ class ISCSApplication : Application() {
         DialogX.init(this)
         SIKCore.init(this)
         //todo 模拟器不支持
-//        ArcSoftUtil.checkActiveStatus(this)
+        ArcSoftUtil.checkActiveStatus(this)
         if (!EventBus.getDefault().isRegistered(this)) {
             EventBus.getDefault().register(this)
         }

+ 1 - 2
app/src/main/java/com/grkj/iscs/features/main/dialog/user_info/AddFingerprintDialog.kt

@@ -1,6 +1,5 @@
 package com.grkj.iscs.features.main.dialog.user_info
 
-import android.view.Gravity
 import android.view.View
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.DialogAddFingerprintBinding
@@ -30,7 +29,7 @@ class AddFingerprintDialog(val onCancel: () -> Unit) :
             return CustomDialog.show(
                 AddFingerprintDialog(onCancel),
                 CustomDialog.ALIGN.CENTER
-            )
+            ).setCancelable(false)
         }
     }
 }

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

@@ -14,6 +14,8 @@ import com.google.android.flexbox.AlignItems
 import com.google.android.flexbox.FlexDirection
 import com.google.android.flexbox.FlexboxLayoutManager
 import com.google.android.flexbox.JustifyContent
+import com.grkj.data.data.MainDomainData
+import com.grkj.data.enums.RoleEnum
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentSlotsManageBinding
 import com.grkj.iscs.databinding.ItemDeviceRegistrationKeyLayoutBinding
@@ -37,12 +39,20 @@ import dagger.hilt.android.AndroidEntryPoint
 @AndroidEntryPoint
 class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
     private val viewModel: SlotsManageViewModel by viewModels()
-    private val slotsLongClickMenu: List<String> = listOf(
-        getString(com.grkj.ui_base.R.string.exception_report),
-        getString(com.grkj.ui_base.R.string.turn_on),
-        getString(com.grkj.ui_base.R.string.turn_off),
-        getString(R.string.detect_slot)
-    )
+    private val slotsLongClickMenu: List<String> by lazy {
+        if (MainDomainData.roleKeys?.contains(RoleEnum.ADMIN.roleKey) == true ||
+            MainDomainData.roleKeys?.contains(RoleEnum.SYSCONFIG.roleKey) == true
+        ) {
+            listOf(
+                getString(com.grkj.ui_base.R.string.exception_report),
+                getString(com.grkj.ui_base.R.string.turn_on),
+                getString(com.grkj.ui_base.R.string.turn_off),
+                getString(R.string.detect_slot)
+            )
+        } else {
+            listOf(getString(com.grkj.ui_base.R.string.exception_report))
+        }
+    }
 
     override fun getLayoutId(): Int {
         return R.layout.fragment_slots_manage
@@ -85,16 +95,54 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
         PopMenu.show(v, slotsLongClickMenu)
             .setAlignGravity(Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL)
             .setOverlayBaseView(false)
-            .setOnMenuItemClickListener { dialog, _, index ->
-                when (index) {
+            .setOnMenuItemClickListener { dialog, str, index ->
+                when {
                     //异常上报
-                    0 -> {}
+                    str.toString() == getString(com.grkj.ui_base.R.string.exception_report) -> {}
                     //开
-                    1 -> {}
+                    str.toString() == getString(com.grkj.ui_base.R.string.turn_on) -> {
+                        when (deviceBean) {
+                            is DockBean.KeyBean -> {
+                                ModBusController.controlKeyCharge(
+                                    true, deviceBean.idx,
+                                    ModBusController.dockList.find { it.row == deviceBean.row }?.addr
+                                )
+                            }
+
+                            is DockBean.LockBean -> {
+                                ModBusController.controlLockBuckle(
+                                    true,
+                                    ModBusController.dockList.find { it.row == deviceBean.row }?.addr,
+                                    deviceBean.idx,
+                                )
+                            }
+
+                            else -> {}
+                        }
+                    }
                     //关
-                    2 -> {}
+                    str.toString() == getString(com.grkj.ui_base.R.string.turn_off) -> {
+                        when (deviceBean) {
+                            is DockBean.KeyBean -> {
+                                ModBusController.controlKeyCharge(
+                                    false, deviceBean.idx,
+                                    ModBusController.dockList.find { it.row == deviceBean.row }?.addr
+                                )
+                            }
+
+                            is DockBean.LockBean -> {
+                                ModBusController.controlLockBuckle(
+                                    false,
+                                    ModBusController.dockList.find { it.row == deviceBean.row }?.addr,
+                                    deviceBean.idx,
+                                )
+                            }
+
+                            else -> {}
+                        }
+                    }
                     //检查仓位
-                    3 -> {}
+                    str.toString() == getString(R.string.detect_slot) -> {}
                 }
                 false
             }

+ 20 - 10
app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SetFaceFragment.kt

@@ -15,8 +15,10 @@ import com.grkj.ui_base.base.BaseFragment
 import com.sik.sikcore.date.TimeUtils
 import com.sik.sikcore.extension.file
 import com.sik.sikcore.extension.setDebouncedClickListener
+import com.sik.sikcore.extension.toJson
 import com.sik.sikimage.ImageConvertUtils
 import dagger.hilt.android.AndroidEntryPoint
+import kotlin.math.log
 
 /**
  * 设置人脸
@@ -33,6 +35,7 @@ class SetFaceFragment : BaseFragment<FragmentSetFaceBinding>() {
     override fun initView() {
         binding.back.setDebouncedClickListener {
             releaseFace()
+            navController.popBackStack()
         }
         binding.setOrResetFace.setDebouncedClickListener {
             binding.faceViewLayout.isVisible = false
@@ -59,7 +62,7 @@ class SetFaceFragment : BaseFragment<FragmentSetFaceBinding>() {
                 ImageConvertUtils.bitmapToBase64(mCapturedBitmap).toString()
             )
             val savePath = FileStorageUtils.getFilePath(
-                CommonConstants.FINGERPRINT_FOLDER,
+                CommonConstants.FACE_FOLDER,
                 saveFileName
             )
             viewModel.saveUserFace(savePath).observe(this) {
@@ -87,10 +90,14 @@ class SetFaceFragment : BaseFragment<FragmentSetFaceBinding>() {
             if (viewModel.sysBiometricDataVo.isEmpty()) {
                 binding.setOrResetFace.text = getString(R.string.set_data_tv)
                 binding.faceSetTipTv.text = getString(R.string.face_not_set_tip)
-            }else{
-                val faceBase64 = viewModel.sysBiometricDataVo[0].content.file().readText()
-                val faceBitmap = ImageConvertUtils.base64ToBitmap(faceBase64)
-                binding.faceSetIv.setImageBitmap(faceBitmap)
+            } else {
+                logger.info("人脸图片地址:${viewModel.sysBiometricDataVo.toJson()}")
+                val faceFile = viewModel.sysBiometricDataVo[0].content.file()
+                if (faceFile.exists()) {
+                    val faceBase64 = faceFile.readText()
+                    val faceBitmap = ImageConvertUtils.base64ToBitmap(faceBase64)
+                    binding.faceSetIv.setImageBitmap(faceBitmap)
+                }
                 binding.setOrResetFace.text = getString(R.string.reset_data_tv)
                 binding.faceSetTipTv.text = getString(R.string.face_set_tip)
             }
@@ -98,27 +105,31 @@ class SetFaceFragment : BaseFragment<FragmentSetFaceBinding>() {
     }
 
     private fun startFace() {
+        binding.preview.isVisible = true
+        binding.image.isVisible = false
         ArcSoftUtil.initEngine(requireContext())
         ArcSoftUtil.initCamera(
             requireContext(),
             requireActivity().windowManager,
             binding.preview
         ) { bitmap, faceSize, alive ->
+            if (isFaceChecking) {
+                return@initCamera
+            }
+            isFaceChecking = true
             binding.tipTv.isVisible = faceSize > 1 || alive == false
             logger.info("人脸检测结果: ${bitmap == null},$faceSize,$alive")
             if (faceSize > 1) {
                 binding.tipTv.text = getString(R.string.only_one_person_allowed)
+                isFaceChecking = false
                 return@initCamera
             }
             if (alive == false) {
                 binding.tipTv.text =
                     getString(R.string.real_person_verification_required)
+                isFaceChecking = false
                 return@initCamera
             }
-            if (isFaceChecking) {
-                return@initCamera
-            }
-            isFaceChecking = true
             binding.preview.visibility = View.INVISIBLE
             binding.image.visibility = View.VISIBLE
             mCapturedBitmap = bitmap
@@ -129,7 +140,6 @@ class SetFaceFragment : BaseFragment<FragmentSetFaceBinding>() {
     }
 
     private fun releaseFace() {
-        mCapturedBitmap = null
         ArcSoftUtil.stop()
     }
 

+ 9 - 1
app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SetFingerprintFragment.kt

@@ -1,7 +1,10 @@
 package com.grkj.iscs.features.main.fragment.user_info
 
 import android.graphics.Bitmap
+import android.graphics.Color
 import androidx.fragment.app.viewModels
+import com.drake.brv.annotaion.DividerOrientation
+import com.drake.brv.utils.divider
 import com.drake.brv.utils.linear
 import com.drake.brv.utils.models
 import com.drake.brv.utils.setup
@@ -92,7 +95,12 @@ class SetFingerprintFragment : BaseFragment<FragmentSetFingerprintBinding>() {
                 }
             )
         }
-        binding.listRv.linear().setup {
+        binding.listRv.linear().divider {
+            this.setColor(Color.BLACK)
+            this.startVisible = false
+            this.endVisible = true
+            this.orientation = DividerOrientation.VERTICAL
+        }.setup {
             addType<SysBiometricDataVo>(R.layout.item_set_fingerprint)
             onBind {
                 val itemBinding = getBinding<ItemSetFingerprintBinding>()

+ 4 - 2
app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SetJobCardFragment.kt

@@ -70,8 +70,10 @@ class SetJobCardFragment : BaseFragment<FragmentSetJobCardBinding>() {
 
     private fun getData() {
         viewModel.getJobCardData().observe(this) {
-            binding.jobCardSetIv.isVisible == viewModel.jobCardDataVo.isNotEmpty()
-            binding.jobCardNotSetIv.isVisible == viewModel.jobCardDataVo.isEmpty()
+            binding.jobCardSetLayout.isVisible = false
+            binding.jobCardViewLayout.isVisible = true
+            binding.jobCardSetIv.isVisible = viewModel.jobCardDataVo.isNotEmpty()
+            binding.jobCardNotSetIv.isVisible = viewModel.jobCardDataVo.isEmpty()
             if (viewModel.jobCardDataVo.isEmpty()) {
                 binding.jobCardSetTipTv.text = getString(R.string.job_card_not_set_tip)
                 binding.setOrResetJobCard.text = getString(R.string.set_data_tv)

+ 3 - 3
app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/UserInfoHomeFragment.kt

@@ -37,19 +37,19 @@ class UserInfoHomeFragment : BaseFragment<FragmentUserInfoHomeBinding>() {
         ),
         MenuItemEntity(
             2,
-            R.mipmap.icon_data_manage_menu_area_manage,
+            R.mipmap.icon_login_menu_fingerprint,
             RoleFunctionalPermissionsEnum.FINGERPRINT_SETTING.description,
             RoleFunctionalPermissionsEnum.FINGERPRINT_SETTING.functionalPermission
         ),
         MenuItemEntity(
             3,
-            R.mipmap.icon_data_manage_menu_point_manage,
+            R.drawable.icon_login_menu_face,
             RoleFunctionalPermissionsEnum.FACE_SETTING.description,
             RoleFunctionalPermissionsEnum.FACE_SETTING.functionalPermission
         ),
         MenuItemEntity(
             4,
-            R.mipmap.icon_data_manage_menu_point_manage,
+            R.drawable.icon_login_menu_card,
             RoleFunctionalPermissionsEnum.CARD_SETTING.description,
             RoleFunctionalPermissionsEnum.CARD_SETTING.functionalPermission
         ),

+ 1 - 0
app/src/main/java/com/grkj/iscs/features/main/viewmodel/user_info/UserInfoViewModel.kt

@@ -112,6 +112,7 @@ class UserInfoViewModel @Inject constructor(
             sysUserCharacteristicDo.userId = MainDomainData.userInfo?.userId!!
             sysUserCharacteristicDo.content = savePath
             sysUserCharacteristicDo.type = "2"
+            logger.info("保存的人脸数据:${sysUserCharacteristicDo}")
             userRepository.saveUserCharacteristic(sysUserCharacteristicDo)
             emit(true)
         }

+ 259 - 0
app/src/main/res/layout-land/fragment_set_face.xml

@@ -0,0 +1,259 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="@dimen/common_spacing_2x"
+        android:background="@drawable/home_card_bg"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/title_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/common_spacing">
+
+            <ImageView
+                android:layout_width="@dimen/title_icon_size"
+                android:layout_height="@dimen/title_icon_size"
+                android:src="@drawable/icon_login_menu_face"
+                android:tint="@color/black" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:layout_weight="1"
+                android:text="@string/set_face_title"
+                android:textColor="@color/black"
+                android:textSize="@dimen/normal_text_size_25"
+                android:textStyle="bold" />
+
+            <TextView
+                android:id="@+id/back"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/common_btn"
+                android:drawableLeft="@mipmap/icon_back"
+                android:drawablePadding="@dimen/common_spacing"
+                android:gravity="center"
+                android:minHeight="@dimen/common_btn_height"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/back"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/divider_line_space"
+            android:background="@color/black" />
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent">
+
+            <LinearLayout
+                android:id="@+id/face_view_layout"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:gravity="center"
+                android:orientation="vertical">
+
+                <ImageView
+                    android:id="@+id/face_not_set_iv"
+                    android:layout_width="@dimen/login_method_item_iv_size"
+                    android:layout_height="@dimen/login_method_item_iv_size"
+                    android:src="@drawable/icon_add_box" />
+
+                <ImageView
+                    android:id="@+id/face_set_iv"
+                    android:layout_width="400dp"
+                    android:layout_height="300dp"
+                    android:scaleType="fitXY"
+                    android:src="@drawable/icon_add_box"
+                    android:visibility="gone" />
+
+                <TextView
+                    android:id="@+id/face_set_tip_tv"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/common_spacing_2x"
+                    android:textColor="@color/black"
+                    android:textSize="@dimen/common_text_size"
+                    tools:text="您尚未设置人脸数据" />
+
+                <TextView
+                    android:id="@+id/set_or_reset_face"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/common_spacing_2x"
+                    android:background="@drawable/common_btn"
+                    android:paddingHorizontal="@dimen/common_spacing_2x"
+                    android:paddingVertical="@dimen/common_spacing"
+                    android:textColor="@color/black"
+                    android:textSize="@dimen/common_text_size"
+                    tools:text="点击设置" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:id="@+id/face_set_layout"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1"
+                    android:orientation="horizontal">
+
+                    <FrameLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_marginHorizontal="@dimen/common_margin_spacing_big"
+                        android:layout_marginTop="@dimen/common_margin_spacing_big"
+                        android:layout_weight="1"
+                        android:background="@drawable/common_card_bg">
+
+                        <TextureView
+                            android:id="@+id/preview"
+                            android:layout_width="match_parent"
+                            android:layout_height="match_parent"
+                            android:visibility="invisible" />
+
+                        <ImageView
+                            android:id="@+id/image"
+                            android:layout_width="match_parent"
+                            android:layout_height="match_parent"
+                            android:scaleType="centerCrop" />
+
+                    </FrameLayout>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_marginHorizontal="@dimen/common_margin_spacing_big"
+                        android:layout_marginTop="@dimen/common_spacing_2x"
+                        android:layout_weight="1"
+                        android:background="@drawable/common_card_bg"
+                        android:orientation="vertical"
+                        android:padding="@dimen/common_spacing_small">
+
+                        <LinearLayout
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:gravity="center_vertical"
+                            android:orientation="horizontal">
+
+                            <ImageView
+                                android:layout_width="@dimen/common_icon_size"
+                                android:layout_height="@dimen/common_icon_size"
+                                android:background="@mipmap/tip" />
+
+                            <TextView
+                                style="@style/CommonTextView"
+                                android:layout_marginLeft="@dimen/common_spacing_small"
+                                android:text="@string/capture_tip_title"
+                                android:textColor="@color/black"
+                                android:textSize="@dimen/common_text_size_small" />
+                        </LinearLayout>
+
+                        <TextView
+                            style="@style/CommonTextView"
+                            android:layout_marginTop="@dimen/common_spacing"
+                            android:gravity="left"
+                            android:text="@string/capture_tip_content"
+                            android:textColor="@color/black"
+                            android:textSize="@dimen/common_text_size_small" />
+
+                        <TextView
+                            android:id="@+id/tip_tv"
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginTop="10dp"
+                            android:background="@color/common_status_red"
+                            android:gravity="center"
+                            android:text="@string/only_one_person_allowed"
+                            android:textColor="@color/white"
+                            android:textSize="@dimen/common_text_size_big"
+                            android:visibility="gone"
+                            tools:text="请保证画面中只有自己" />
+                    </LinearLayout>
+                </LinearLayout>
+
+                <androidx.constraintlayout.widget.ConstraintLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:paddingVertical="@dimen/common_spacing_2x">
+
+                    <TextView
+                        android:id="@+id/confirm"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:background="@drawable/common_btn_confirm"
+                        android:drawableLeft="@mipmap/icon_confirm"
+                        android:drawablePadding="@dimen/common_spacing"
+                        android:drawableTint="@color/white"
+                        android:paddingHorizontal="@dimen/common_spacing_2x"
+                        android:paddingVertical="@dimen/common_spacing"
+                        android:text="@string/confirm"
+                        android:textColor="@color/white"
+                        android:textSize="@dimen/common_btn_text_size"
+                        android:visibility="gone"
+                        app:layout_constraintEnd_toStartOf="@+id/recapture"
+                        app:layout_constraintHorizontal_bias="0.5"
+                        app:layout_constraintStart_toStartOf="parent"
+                        app:layout_constraintTop_toTopOf="parent" />
+
+                    <TextView
+                        android:id="@+id/recapture"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:background="@drawable/common_btn_cancel"
+                        android:backgroundTint="@color/dialogxColorBlue"
+                        android:drawableLeft="@drawable/icon_camera"
+                        android:drawablePadding="@dimen/common_spacing"
+                        android:drawableTint="@color/white"
+                        android:paddingHorizontal="@dimen/common_spacing_2x"
+                        android:paddingVertical="@dimen/common_spacing"
+                        android:text="@string/recapture"
+                        android:textColor="@color/white"
+                        android:textSize="@dimen/common_btn_text_size"
+                        android:visibility="gone"
+                        app:layout_constraintEnd_toStartOf="@+id/cancel"
+                        app:layout_constraintHorizontal_bias="0.5"
+                        app:layout_constraintStart_toEndOf="@+id/confirm"
+                        app:layout_constraintTop_toTopOf="@id/confirm" />
+
+                    <TextView
+                        android:id="@+id/cancel"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:background="@drawable/common_btn_cancel"
+                        android:drawableLeft="@drawable/icon_close"
+                        android:drawablePadding="@dimen/common_spacing"
+                        android:drawableTint="@color/white"
+                        android:paddingHorizontal="@dimen/common_spacing_2x"
+                        android:paddingVertical="@dimen/common_spacing"
+                        android:text="@string/cancel"
+                        android:textColor="@color/white"
+                        android:textSize="@dimen/common_btn_text_size"
+                        app:layout_constraintEnd_toEndOf="parent"
+                        app:layout_constraintHorizontal_bias="0.5"
+                        app:layout_constraintStart_toEndOf="@+id/recapture"
+                        app:layout_constraintTop_toTopOf="@id/recapture" />
+                </androidx.constraintlayout.widget.ConstraintLayout>
+
+            </LinearLayout>
+        </FrameLayout>
+    </LinearLayout>
+</layout>

+ 3 - 2
app/src/main/res/layout/dialog_add_fingerprint.xml

@@ -3,10 +3,11 @@
 
     <LinearLayout
         android:layout_width="@dimen/dialog_common_root_width"
-        android:layout_height="@dimen/dialog_common_root_height_medium"
+        android:layout_height="wrap_content"
         android:background="@drawable/common_card_bg"
         android:gravity="center"
-        android:orientation="vertical">
+        android:orientation="vertical"
+        android:paddingVertical="@dimen/common_spacing_2x">
 
         <ImageView
             android:layout_width="@dimen/login_method_item_layout_width"

+ 2 - 2
app/src/main/res/layout/fragment_set_face.xml

@@ -75,8 +75,8 @@
 
                 <ImageView
                     android:id="@+id/face_set_iv"
-                    android:layout_width="300dp"
-                    android:layout_height="400dp"
+                    android:layout_width="400dp"
+                    android:layout_height="300dp"
                     android:scaleType="fitXY"
                     android:src="@drawable/icon_add_box"
                     android:visibility="gone" />

+ 5 - 3
app/src/main/res/layout/fragment_set_job_card.xml

@@ -108,18 +108,20 @@
             <LinearLayout
                 android:id="@+id/job_card_set_layout"
                 android:layout_width="@dimen/dialog_common_root_width"
-                android:layout_height="@dimen/dialog_common_root_height_medium"
+                android:layout_height="wrap_content"
                 android:layout_gravity="center"
                 android:background="@drawable/common_card_bg"
                 android:gravity="center"
                 android:orientation="vertical"
+                android:paddingVertical="@dimen/common_spacing_2x"
                 android:visibility="gone">
 
                 <ImageView
                     android:layout_width="@dimen/login_method_item_layout_width"
                     android:layout_height="@dimen/login_method_item_layout_width"
-                    android:layout_gravity="center"
-                    android:src="@mipmap/icon_login_menu_fingerprint"
+                    android:background="@drawable/circle_image_bg"
+                    android:scaleType="center"
+                    android:src="@drawable/icon_login_menu_card"
                     android:tint="@color/black" />
 
                 <TextView

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

@@ -28,6 +28,7 @@
             android:layout_height="match_parent"
             android:layout_weight="1"
             android:gravity="center"
+            android:text="@string/delete"
             android:textSize="@dimen/common_text_size" />
     </LinearLayout>
 </layout>

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

@@ -6,4 +6,5 @@ import com.grkj.data.model.dos.SysUserCharacteristicDo
  * 生物数据
  */
 class SysBiometricDataVo : SysUserCharacteristicDo() {
+
 }

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

@@ -3,6 +3,7 @@ package com.grkj.data.repository.impl
 import com.grkj.data.dao.HardwareDao
 import com.grkj.data.dao.IsolationPointDao
 import com.grkj.data.data.MMKVConstants
+import com.grkj.data.data.MainDomainData
 import com.grkj.data.enums.CommonDictDataEnum
 import com.grkj.data.model.dos.IsJobCard
 import com.grkj.data.model.dos.IsKey
@@ -33,6 +34,7 @@ import com.sik.sikcore.data.BeanUtils
 import com.sik.sikcore.extension.saveMMKVData
 import javax.inject.Inject
 import javax.inject.Singleton
+import kotlin.math.log
 
 /**
  * 硬件仓储
@@ -369,25 +371,26 @@ class HardwareRepository @Inject constructor(
     override fun updateUserJobCard(rfidNo: String, userId: Long) {
         val userJobCardData = hardwareDao.getIsJobCardByUserId(userId)
         if (userJobCardData.any { it.cardNfc == rfidNo }) {
+            logger.info("检测到用户工卡")
             return
         }
         var jobCardData = hardwareDao.getCardDataByRfid(rfidNo)
-        userJobCardData.forEach {
-            it.userId = null
-            hardwareDao.updateCardInfo(it)
-        }
         if (jobCardData != null) {
+            logger.info("工卡存在,设置值")
             jobCardData.userId = userId
+            hardwareDao.updateCardInfo(jobCardData)
         } else {
+            logger.info("没有检测到工卡,重新创建工卡")
             jobCardData = IsJobCard()
             var defaultCardCodeSize = hardwareDao.getDefaultCardNameCount()
             jobCardData.cardCode = "CARD_${defaultCardCodeSize + 1}"
             jobCardData.userId = userId
             jobCardData.cardNfc = rfidNo
+            jobCardData.userName = MainDomainData.userInfo?.userName
             jobCardData.exStatus =
                 CommonDictDataEnum.JOB_CARD_STATUS.commonDictRes.find { it.dictLabel == "正常" }?.dictValue
+            hardwareDao.addCard(jobCardData)
         }
-        hardwareDao.updateCardInfo(jobCardData)
     }
 
     override fun getExceptionKey(): List<IsKey> {

+ 93 - 0
shared/src/main/java/com/grkj/shared/utils/ArcSoftUtil.kt

@@ -3,8 +3,10 @@ package com.grkj.shared.utils
 import android.Manifest
 import android.content.Context
 import android.graphics.Bitmap
+import android.graphics.BitmapFactory
 import android.graphics.Point
 import android.hardware.Camera
+import android.util.Base64
 import android.util.DisplayMetrics
 import android.view.View
 import android.view.WindowManager
@@ -13,7 +15,9 @@ import com.arcsoft.face.AgeInfo
 import com.arcsoft.face.ErrorInfo
 import com.arcsoft.face.Face3DAngle
 import com.arcsoft.face.FaceEngine
+import com.arcsoft.face.FaceFeature
 import com.arcsoft.face.FaceInfo
+import com.arcsoft.face.FaceSimilar
 import com.arcsoft.face.GenderInfo
 import com.arcsoft.face.LivenessInfo
 import com.arcsoft.face.enums.DetectFaceOrientPriority
@@ -24,6 +28,7 @@ import com.grkj.shared.utils.face.arcsoft.CameraListener
 import com.grkj.shared.utils.face.arcsoft.NV21ToBitmap
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
+import kotlin.math.log
 
 /**
  * 虹软工具类
@@ -212,4 +217,92 @@ object ArcSoftUtil {
         }
         unInitEngine()
     }
+
+    /**
+     * 比对两张 Base64 人脸,返回是否同人
+     * @param threshold 阈值,一般设置 0.7f 左右
+     */
+    fun verifyFaceArcSoft(
+        b64a: String,
+        b64b: String,
+        threshold: Float = 0.7f
+    ): Boolean {
+        // 1. 解码成 Bitmap
+        val bmpA = decodeBase64ToBitmap(b64a)
+        val bmpB = decodeBase64ToBitmap(b64b)
+
+        // 2. 人脸检测
+        val facesA = mutableListOf<FaceInfo>()
+        val facesB = mutableListOf<FaceInfo>()
+        val imgA = bitmapToBgr24(bmpA)
+        val imgB = bitmapToBgr24(bmpB)
+
+        faceEngine?.detectFaces(
+            imgA,
+            bmpA.width,
+            bmpA.height,
+            FaceEngine.CP_PAF_BGR24,
+            facesA
+        )
+        faceEngine?.detectFaces(
+            imgB,
+            bmpB.width,
+            bmpB.height,
+            FaceEngine.CP_PAF_BGR24,
+            facesB
+        )
+
+        if (facesA.isEmpty() || facesB.isEmpty()) {
+            return false
+        }
+
+        // 3. 特征提取
+        val ftA = FaceFeature()
+        val ftB = FaceFeature()
+        faceEngine?.extractFaceFeature(
+            imgA, bmpA.width, bmpA.height, FaceEngine.CP_PAF_BGR24,
+            facesA[0], ftA
+        )
+        faceEngine?.extractFaceFeature(
+            imgB, bmpB.width, bmpB.height, FaceEngine.CP_PAF_BGR24,
+            facesB[0], ftB
+        )
+
+        // 4. 特征比对
+        val compareResult = FaceSimilar()
+        val compareCode = faceEngine?.compareFaceFeature(ftA, ftB, compareResult)
+        if (compareCode != ErrorInfo.MOK) {
+            return false
+        }
+        logger.info("比对分数:${compareResult.score}")
+        // compareResult.score 在 [0,1],越大越像
+        return compareResult.score >= threshold
+    }
+
+
+    private fun decodeBase64ToBitmap(b64: String): Bitmap {
+        val bytes = Base64.decode(b64, Base64.DEFAULT)
+        return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
+    }
+
+    /** Bitmap ARGB_8888 -> BGR24 byte[] */
+    private fun bitmapToBgr24(bitmap: Bitmap): ByteArray {
+        val width = bitmap.width
+        val height = bitmap.height
+        val pixels = IntArray(width * height)
+        bitmap.getPixels(pixels, 0, width, 0, 0, width, height)
+
+        val bgr = ByteArray(width * height * 3)
+        var idx = 0
+        for (pixel in pixels) {
+            // pixel is ARGB
+            val r = (pixel shr 16 and 0xFF).toByte()
+            val g = (pixel shr 8 and 0xFF).toByte()
+            val b = (pixel and 0xFF).toByte()
+            bgr[idx++] = b
+            bgr[idx++] = g
+            bgr[idx++] = r
+        }
+        return bgr
+    }
 }

+ 1 - 117
shared/src/main/java/com/grkj/shared/utils/BiometricVerifier.kt

@@ -45,39 +45,6 @@ object BiometricVerifier {
         return score >= threshold
     }
 
-
-    // —— 人脸比对(ArcSoft) ——
-    private lateinit var faceEngine: FaceEngine
-    private val initDone = AtomicBoolean(false)
-
-    /** 初始化 ArcSoft SDK,只调用一次 */
-    fun initArcSoft(
-        context: Context = SIKCore.getApplication(),
-        appId: String = Constants.APP_ID,
-        sdkKey: String = Constants.SDK_KEY
-    ) {
-        if (initDone.compareAndSet(false, true)) {
-            faceEngine = FaceEngine()
-            val code = faceEngine.init(
-                context,
-                DetectMode.ASF_DETECT_MODE_IMAGE,
-                DetectFaceOrientPriority.ASF_OP_ALL_OUT,
-                16,    // 最大检测人脸数
-                16,    // 线程数
-                FaceEngine.ASF_FACE_RECOGNITION or
-                        FaceEngine.ASF_FACE_DETECT
-            )
-            if (code != ErrorInfo.MOK) {
-                throw RuntimeException("ArcSoft 初始化失败, code=$code")
-            }
-            // 激活:只需在首次运行时激活
-            val activeCode = FaceEngine.activeOnline(context, appId, sdkKey)
-            if (activeCode != ErrorInfo.MOK && activeCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED) {
-                throw RuntimeException("ArcSoft 激活失败, code=$activeCode")
-            }
-        }
-    }
-
     /**
      * 比对两张 Base64 人脸,返回是否同人
      * @param threshold 阈值,一般设置 0.7f 左右
@@ -87,90 +54,7 @@ object BiometricVerifier {
         b64b: String,
         threshold: Float = 0.7f
     ): Boolean {
-        // 1. 解码成 Bitmap
-        val bmpA = decodeBase64ToBitmap(b64a)
-        val bmpB = decodeBase64ToBitmap(b64b)
-
-        // 2. 人脸检测
-        val facesA = mutableListOf<FaceInfo>()
-        val facesB = mutableListOf<FaceInfo>()
-        val imgA = bitmapToBgr24(bmpA)
-        val imgB = bitmapToBgr24(bmpB)
-
-        faceEngine.detectFaces(
-            imgA,
-            bmpA.width,
-            bmpA.height,
-            FaceEngine.CP_PAF_BGR24,
-            facesA
-        )
-        faceEngine.detectFaces(
-            imgB,
-            bmpB.width,
-            bmpB.height,
-            FaceEngine.CP_PAF_BGR24,
-            facesB
-        )
-
-        if (facesA.isEmpty() || facesB.isEmpty()) {
-            return false
-        }
-
-        // 3. 特征提取
-        val ftA = FaceFeature()
-        val ftB = FaceFeature()
-        faceEngine.extractFaceFeature(
-            imgA, bmpA.width, bmpA.height, FaceEngine.CP_PAF_BGR24,
-            facesA[0], ftA
-        )
-        faceEngine.extractFaceFeature(
-            imgB, bmpB.width, bmpB.height, FaceEngine.CP_PAF_BGR24,
-            facesB[0], ftB
-        )
-
-        // 4. 特征比对
-        val compareResult = FaceSimilar()
-        val compareCode = faceEngine.compareFaceFeature(ftA, ftB, compareResult)
-        if (compareCode != ErrorInfo.MOK) {
-            return false
-        }
         // compareResult.score 在 [0,1],越大越像
-        return compareResult.score >= threshold
+        return ArcSoftUtil.verifyFaceArcSoft(b64a, b64b, threshold)
     }
-
-    /** Bitmap ARGB_8888 -> BGR24 byte[] */
-    private fun bitmapToBgr24(bitmap: Bitmap): ByteArray {
-        val width = bitmap.width
-        val height = bitmap.height
-        val pixels = IntArray(width * height)
-        bitmap.getPixels(pixels, 0, width, 0, 0, width, height)
-
-        val bgr = ByteArray(width * height * 3)
-        var idx = 0
-        for (pixel in pixels) {
-            // pixel is ARGB
-            val r = (pixel shr 16 and 0xFF).toByte()
-            val g = (pixel shr 8 and 0xFF).toByte()
-            val b = (pixel and 0xFF).toByte()
-            bgr[idx++] = b
-            bgr[idx++] = g
-            bgr[idx++] = r
-        }
-        return bgr
-    }
-
-    private fun decodeBase64ToBitmap(b64: String): Bitmap {
-        val bytes = Base64.decode(b64, Base64.DEFAULT)
-        return BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
-    }
-
-    /** 释放资源,Activity/Fragment 销毁时调用 */
-    @RequiresApi(Build.VERSION_CODES.O)
-    fun releaseArcSoft() {
-        if (initDone?.get() != null) {
-            faceEngine.unInit()
-            initDone.set(false)
-        }
-    }
-
 }