Bläddra i källkod

feat(数据管理):
- 新增数据导出功能
- 优化系统设置中自动登出时间设置,单位调整为秒,并增加范围限制
- 优化弹窗和表单中的必填项显示
- 优化人脸识别,降低检测失败时的日志频率
- 修复其他已知问题和UI细节调整

周文健 8 månader sedan
förälder
incheckning
b32332ea37
28 ändrade filer med 573 tillägg och 311 borttagningar
  1. 11 1
      app/src/main/assets/i18n/en-US.json
  2. 31 1
      app/src/main/assets/i18n/zh-CN.json
  3. BIN
      app/src/main/assets/themes/Default/icons/icon_data_export.png
  4. 3 6
      app/src/main/java/com/grkj/iscs/features/main/dialog/CheckFaceDialog.kt
  5. 3 1
      app/src/main/java/com/grkj/iscs/features/main/entity/QuickEntranceMenuItemEntity.kt
  6. 23 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/DataExportFragment.kt
  7. 10 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/DataManageHomeFragment.kt
  8. 1 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/SwitchLayoutFragment.kt
  9. 7 3
      app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/SettingsFragment.kt
  10. 29 39
      app/src/main/res/layout-land/fragment_edit_sop.xml
  11. 12 4
      app/src/main/res/layout/dialog_add_card.xml
  12. 15 5
      app/src/main/res/layout/dialog_add_key.xml
  13. 12 4
      app/src/main/res/layout/dialog_add_lock.xml
  14. 1 1
      app/src/main/res/layout/dialog_add_rfid_token.xml
  15. 12 4
      app/src/main/res/layout/dialog_update_card.xml
  16. 15 5
      app/src/main/res/layout/dialog_update_key.xml
  17. 12 4
      app/src/main/res/layout/dialog_update_lock.xml
  18. 12 4
      app/src/main/res/layout/dialog_update_rfid_token.xml
  19. 3 3
      app/src/main/res/layout/dialog_update_role.xml
  20. 14 6
      app/src/main/res/layout/dialog_update_user.xml
  21. 131 0
      app/src/main/res/layout/fragment_data_export.xml
  22. 58 68
      app/src/main/res/layout/fragment_edit_sop.xml
  23. 39 55
      app/src/main/res/layout/fragment_exception_report.xml
  24. 7 0
      app/src/main/res/navigation/nav_data_manage.xml
  25. 1 1
      data/src/main/java/com/grkj/data/data/CommonConstants.kt
  26. 2 0
      data/src/main/java/com/grkj/data/enums/RoleFunctionalPermissionsEnum.kt
  27. 108 94
      shared/src/main/java/com/grkj/shared/utils/ArcSoftUtil.kt
  28. 1 1
      ui-base/src/main/java/com/grkj/ui_base/config/ISCSConfig.kt

+ 11 - 1
app/src/main/assets/i18n/en-US.json

@@ -2379,6 +2379,11 @@
     "type": "text",
     "value": "Add Role"
   },
+  "role_manage_update_title": {
+    "key": "role_manage_update_title",
+    "type": "text",
+    "value": "Update Role"
+  },
   "role_manage_delete_failed": {
     "key": "role_manage_delete_failed",
     "type": "text",
@@ -4011,7 +4016,7 @@
   "auto_logout_time": {
     "key": "auto_logout_time",
     "type": "text",
-    "value": "Auto logout time(ms):"
+    "value": "Auto logout time (min 60, max 1800, unit: s):"
   },
   "please_input_max_fingerprint_entries_size": {
     "key": "please_input_max_fingerprint_entries_size",
@@ -4022,5 +4027,10 @@
     "key": "please_input_auto_logout_time",
     "type": "text",
     "value": "Please input auto logout time"
+  },
+  "please_input_auto_logout_time_correct": {
+    "key": "please_input_auto_logout_time_correct",
+    "type": "text",
+    "value": "Please input auto logout time correct"
   }
 }

+ 31 - 1
app/src/main/assets/i18n/zh-CN.json

@@ -2379,6 +2379,11 @@
     "type": "text",
     "value": "添加角色"
   },
+  "role_manage_update_title": {
+    "key": "role_manage_update_title",
+    "type": "text",
+    "value": "修改角色"
+  },
   "role_manage_delete_failed": {
     "key": "role_manage_delete_failed",
     "type": "text",
@@ -4007,7 +4012,7 @@
   "auto_logout_time": {
     "key": "auto_logout_time",
     "type": "text",
-    "value": "自动登出时间(ms):"
+    "value": "自动登出时间(最低60,最高1800,单位:s):"
   },
   "please_input_max_fingerprint_entries_size": {
     "key": "please_input_max_fingerprint_entries_size",
@@ -4018,5 +4023,30 @@
     "key": "please_input_auto_logout_time",
     "type": "text",
     "value": "请输入自动登出时间"
+  },
+  "data_export": {
+    "key": "data_export",
+    "type": "text",
+    "value": "数据导出"
+  },
+  "data_export_tip": {
+    "key": "data_export",
+    "type": "text",
+    "value": "请选择您要导出的表,然后点击导出。"
+  },
+  "data_table": {
+    "key": "data_table",
+    "type": "text",
+    "value": "数据表"
+  },
+  "last_export_datetime": {
+    "key": "last_export_datetime",
+    "type": "text",
+    "value": "上次导出时间"
+  },
+  "please_input_auto_logout_time_correct": {
+    "key": "please_input_auto_logout_time_correct",
+    "type": "text",
+    "value": "请设置正确的自动登出时间"
   }
 }

BIN
app/src/main/assets/themes/Default/icons/icon_data_export.png


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

@@ -36,14 +36,11 @@ class CheckFaceDialog(
     private var dialog: CustomDialog? = null
     private val mPairList = mutableListOf(
         Pair(
-            CommonUtils.getStr("please_scan_face"),
-            "face-id-svgrepo-com.svg"
+            CommonUtils.getStr("please_scan_face"), "face-id-svgrepo-com.svg"
         ), Pair(
-            CommonUtils.getStr("please_scan_fingerprint"),
-            "fingerprint.svg"
+            CommonUtils.getStr("please_scan_fingerprint"), "fingerprint.svg"
         ), Pair(
-            CommonUtils.getStr("please_swipe_card"),
-            "icon_login_menu_card.png"
+            CommonUtils.getStr("please_swipe_card"), "icon_login_menu_card.png"
         )
     )
 

+ 3 - 1
app/src/main/java/com/grkj/iscs/features/main/entity/QuickEntranceMenuItemEntity.kt

@@ -31,6 +31,7 @@ data class QuickEntranceMenuItemEntity(
                 RoleFunctionalPermissionsEnum.ROLE_MANAGE -> "users-alt.svg"
                 RoleFunctionalPermissionsEnum.WORKSTATION_MANAGE -> "land-location.png"
                 RoleFunctionalPermissionsEnum.SWITCH_LAYOUT -> "icon_data_manage_switch_layout.svg"
+                RoleFunctionalPermissionsEnum.DATA_EXPORT -> "icon_data_export.png"
                 RoleFunctionalPermissionsEnum.POINT_MANAGE -> "location-crosshairs.svg"
                 RoleFunctionalPermissionsEnum.TODO_LIST -> "to-do.svg"
                 RoleFunctionalPermissionsEnum.IN_PROGRESS_JOB -> "ballot-check.svg"
@@ -65,7 +66,7 @@ data class QuickEntranceMenuItemEntity(
             return when (permission) {
                 RoleFunctionalPermissionsEnum.USER_MANAGE, RoleFunctionalPermissionsEnum.ROLE_MANAGE,
                 RoleFunctionalPermissionsEnum.WORKSTATION_MANAGE, RoleFunctionalPermissionsEnum.POINT_MANAGE,
-                     RoleFunctionalPermissionsEnum.SWITCH_LAYOUT-> R.navigation.nav_data_manage
+                RoleFunctionalPermissionsEnum.SWITCH_LAYOUT, RoleFunctionalPermissionsEnum.DATA_EXPORT -> R.navigation.nav_data_manage
 
                 RoleFunctionalPermissionsEnum.TODO_LIST,
                 RoleFunctionalPermissionsEnum.IN_PROGRESS_JOB,
@@ -108,6 +109,7 @@ data class QuickEntranceMenuItemEntity(
                 RoleFunctionalPermissionsEnum.WORKSTATION_MANAGE -> R.id.action_dataManageHomeFragment_to_workstationManageFragment
                 RoleFunctionalPermissionsEnum.POINT_MANAGE -> R.id.action_dataManageHomeFragment_to_pointMangeFragment
                 RoleFunctionalPermissionsEnum.SWITCH_LAYOUT -> R.id.action_dataManageHomeFragment_to_nav_switch_layout
+                RoleFunctionalPermissionsEnum.DATA_EXPORT -> R.id.action_dataManageHomeFragment_to_dataExportFragment
                 RoleFunctionalPermissionsEnum.TODO_LIST -> R.id.action_jobManageHomeFragment_to_myTodoListFragment
                 RoleFunctionalPermissionsEnum.IN_PROGRESS_JOB -> R.id.action_jobManageHomeFragment_to_inProgressJobManageFragment
                 RoleFunctionalPermissionsEnum.CREATE_SOP -> R.id.action_jobManageHomeFragment_to_createSopFragment

+ 23 - 0
app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/DataExportFragment.kt

@@ -0,0 +1,23 @@
+package com.grkj.iscs.features.main.fragment.data_manage
+
+import com.grkj.iscs.R
+import com.grkj.iscs.databinding.FragmentDataExportBinding
+import com.grkj.ui_base.base.BaseFragment
+import com.sik.sikcore.extension.setDebouncedClickListener
+import dagger.hilt.android.AndroidEntryPoint
+
+/**
+ * 数据导出
+ */
+@AndroidEntryPoint
+class DataExportFragment : BaseFragment<FragmentDataExportBinding>() {
+    override fun getLayoutId(): Int {
+        return R.layout.fragment_data_export
+    }
+
+    override fun initView() {
+        binding.back.setDebouncedClickListener {
+            navController.popBackStack()
+        }
+    }
+}

+ 10 - 0
app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/DataManageHomeFragment.kt

@@ -64,6 +64,12 @@ class DataManageHomeFragment : BaseFragment<FragmentDataManageHomeBinding>() {
         ),
         MenuItemEntity(
             5,
+            "icon_data_export.png",
+            I18nManager.t(RoleFunctionalPermissionsEnum.DATA_EXPORT.description),
+            RoleFunctionalPermissionsEnum.DATA_EXPORT.functionalPermission
+        ),
+        MenuItemEntity(
+            6,
             "icon_data_manage_switch_layout.svg",
             I18nManager.t(RoleFunctionalPermissionsEnum.SWITCH_LAYOUT.description),
             RoleFunctionalPermissionsEnum.SWITCH_LAYOUT.functionalPermission
@@ -141,6 +147,10 @@ class DataManageHomeFragment : BaseFragment<FragmentDataManageHomeBinding>() {
             }
 
             5 -> {
+                navController.navigate(R.id.action_dataManageHomeFragment_to_dataExportFragment)
+            }
+
+            6 -> {
                 navController.navigate(R.id.action_dataManageHomeFragment_to_nav_switch_layout)
             }
         }

+ 1 - 1
app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/SwitchLayoutFragment.kt

@@ -298,8 +298,8 @@ class SwitchLayoutFragment : BaseFragment<FragmentSwitchLayoutBinding>() {
                     binding.mapview.refresh()
                     ThreadUtils.runOnMainDelayed(500) {
                         if (positionPointId != null) {
-                            stationLayer?.selectPoint(positionPointId)
                             binding.mapview.refresh()
+                            stationLayer?.selectPoint(positionPointId)
                         }
                     }
                 }

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

@@ -37,7 +37,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding>() {
             "${
                 MMKVConstants.KEY_AUTO_LOGOUT_TIME.getMMKVData(
                     CommonConstants.DEFAULT_AUTO_LOGOUT_TIME
-                )
+                ) / 1000
             }"
         )
         binding.confirm.setDebouncedClickListener {
@@ -46,7 +46,7 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding>() {
                     binding.maxFingerprintInsert.text.toString().toInt()
                 )
                 val autoLogoutTime =
-                    binding.autoLogoutTime.text.toString().toLong()
+                    binding.autoLogoutTime.text.toString().toLong() * 1000
                 MMKVConstants.KEY_AUTO_LOGOUT_TIME.saveMMKVData(
                     autoLogoutTime
                 )
@@ -68,6 +68,10 @@ class SettingsFragment : BaseFragment<FragmentSettingsBinding>() {
             showToast(CommonUtils.getStr("please_input_auto_logout_time"))
             return false
         }
-        return true
+        if (binding.autoLogoutTime.text.toString().toLong() !in 60..1800){
+            showToast(CommonUtils.getStr("please_input_auto_logout_time_correct"))
+            return false
+        }
+            return true
     }
 }

+ 29 - 39
app/src/main/res/layout-land/fragment_edit_sop.xml

@@ -93,20 +93,24 @@
                         android:background="?attr/colorDivider" />
 
 
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="@dimen/iscs_space_2"
-                        android:gravity="center_vertical"
-                        android:orientation="horizontal"
-                        android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+                    <com.grkj.ui_base.widget.FormLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:clipToPadding="false"
+                        android:minWidth="0dp"
+                        android:orientation="vertical"
+                        android:padding="@dimen/dialog_content_normal_padding_horizontal"
+                        app:columnSpacing="@dimen/iscs_space_2"
+                        app:rowSpacing="@dimen/iscs_space_2">
 
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            app:i18nKey='@{"sop_workstation"}'
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="label"
+                            app:i18nKey='@{"sop_workstation"}' />
 
                         <TextView
                             android:id="@+id/workstation_tv"
@@ -115,29 +119,22 @@
                             android:layout_marginLeft="@dimen/iscs_space_2"
                             android:background="@drawable/bg_common_input"
                             android:drawableRight="@mipmap/icon_drop_down"
-                            app:i18nHint='@{"please_select_sop_workstation"}'
                             android:maxLines="1"
                             android:paddingHorizontal="@dimen/iscs_space_2"
                             android:paddingVertical="2dp"
                             android:singleLine="true"
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
-                    </LinearLayout>
-
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="@dimen/iscs_space_2"
-                        android:gravity="center_vertical"
-                        android:orientation="horizontal"
-                        android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="field"
+                            app:i18nHint='@{"please_select_sop_workstation"}' />
 
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            app:i18nKey='@{"workflow_mode"}'
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="label"
+                            app:i18nKey='@{"workflow_mode"}' />
 
                         <TextView
                             android:id="@+id/lock_mode_tv"
@@ -146,30 +143,22 @@
                             android:layout_marginLeft="@dimen/iscs_space_2"
                             android:background="@drawable/bg_common_input"
                             android:drawableRight="@mipmap/icon_drop_down"
-                            app:i18nHint='@{"please_select_flow_mode"}'
                             android:maxLines="1"
                             android:paddingHorizontal="@dimen/iscs_space_2"
                             android:paddingVertical="2dp"
                             android:singleLine="true"
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
-                    </LinearLayout>
-
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="@dimen/iscs_space_2"
-                        android:layout_marginBottom="@dimen/iscs_space_2"
-                        android:gravity="center_vertical"
-                        android:orientation="horizontal"
-                        android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="field"
+                            app:i18nHint='@{"please_select_flow_mode"}' />
 
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            app:i18nKey='@{"create_sop_name"}'
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="label"
+                            app:i18nKey='@{"create_sop_name"}' />
 
                         <EditText
                             android:id="@+id/sop_name_et"
@@ -177,14 +166,15 @@
                             android:layout_height="wrap_content"
                             android:layout_marginLeft="@dimen/iscs_space_2"
                             android:background="@drawable/bg_common_input"
-                            app:i18nHint='@{"please_input_sop_name"}'
                             android:maxLines="1"
                             android:paddingHorizontal="@dimen/iscs_space_2"
                             android:paddingVertical="2dp"
                             android:singleLine="true"
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
-                    </LinearLayout>
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="field"
+                            app:i18nHint='@{"please_input_sop_name"}' />
+                    </com.grkj.ui_base.widget.FormLayout>
                 </LinearLayout>
 
                 <LinearLayout

+ 12 - 4
app/src/main/res/layout/dialog_add_card.xml

@@ -54,13 +54,15 @@
             app:rowSpacing="@dimen/iscs_space_2">
 
             <!-- 卡片 NFC -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/card_nfc_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"card_nfc"}' />
 
             <EditText
@@ -79,13 +81,15 @@
                 app:i18nHint='@{"please_input_card_nfc"}' />
 
             <!-- 卡片昵称 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/username_title_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"username"}' />
 
             <TextView
@@ -105,13 +109,15 @@
                 app:i18nHint='@{"please_select_card_username"}' />
 
             <!-- 状态 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/status_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"manage_filter_status"}' />
 
             <RadioGroup
@@ -143,13 +149,15 @@
             </RadioGroup>
 
             <!-- 备注 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/remark_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="false"
                 app:i18nKey='@{"remark"}' />
 
             <EditText

+ 15 - 5
app/src/main/res/layout/dialog_add_key.xml

@@ -51,13 +51,15 @@
             app:columnSpacing="@dimen/iscs_space_2"
             app:rowSpacing="@dimen/iscs_space_2">
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/key_code_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"key_name"}' />
 
             <EditText
@@ -76,13 +78,15 @@
                 app:i18nHint='@{"please_input_key_name"}' />
 
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/key_nfc_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"key_nfc"}' />
 
             <EditText
@@ -101,13 +105,15 @@
                 app:i18nHint='@{"please_input_key_nfc"}' />
 
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/key_mac_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"key_mac"}' />
 
             <EditText
@@ -124,13 +130,15 @@
                 app:i18nHint='@{"please_input_key_mac"}' />
 
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/status_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"manage_filter_status"}' />
 
             <RadioGroup
@@ -162,13 +170,15 @@
             </RadioGroup>
 
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/remark_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="false"
                 app:i18nKey='@{"remark"}' />
 
             <EditText

+ 12 - 4
app/src/main/res/layout/dialog_add_lock.xml

@@ -54,13 +54,15 @@
             app:rowSpacing="@dimen/iscs_space_2">
 
             <!-- 挂锁编号 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/lock_code_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"lock_code"}' />
 
             <EditText
@@ -79,12 +81,14 @@
                 app:i18nHint='@{"please_input_key_nfc"}' />
 
             <!-- 挂锁 NFC -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/lock_nfc_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
+                app:markPosition="start"
+                app:required="true"
                 app:formRole="label"
                 app:i18nKey='@{"lock_nfc"}' />
 
@@ -104,13 +108,15 @@
                 app:i18nHint='@{"please_input_key_nfc"}' />
 
             <!-- 状态 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/status_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"manage_filter_status"}' />
 
             <RadioGroup
@@ -142,13 +148,15 @@
             </RadioGroup>
 
             <!-- 备注 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/remark_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="false"
                 app:i18nKey='@{"remark"}' />
 
             <EditText

+ 1 - 1
app/src/main/res/layout/dialog_add_rfid_token.xml

@@ -155,7 +155,7 @@
                 app:formRole="label"
                 app:i18nKey='@{"remark"}'
                 app:markPosition="start"
-                app:required="true" />
+                app:required="false" />
 
             <EditText
                 android:id="@+id/remark_et"

+ 12 - 4
app/src/main/res/layout/dialog_update_card.xml

@@ -54,13 +54,15 @@
             app:rowSpacing="@dimen/iscs_space_2">
 
             <!-- 卡片 NFC -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/card_nfc_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"card_nfc"}' />
 
             <EditText
@@ -78,13 +80,15 @@
                 app:i18nHint='@{"please_input_card_nfc"}' />
 
             <!-- 卡片昵称 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/username_title_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"username"}' />
 
             <TextView
@@ -103,12 +107,14 @@
                 app:i18nHint='@{"please_select_card_username"}' />
 
             <!-- 状态 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/status_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
+                app:markPosition="start"
+                app:required="true"
                 app:formRole="label"
                 app:i18nKey='@{"manage_filter_status"}' />
 
@@ -141,13 +147,15 @@
             </RadioGroup>
 
             <!-- 备注 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/remark_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="false"
                 app:i18nKey='@{"remark"}' />
 
             <EditText

+ 15 - 5
app/src/main/res/layout/dialog_update_key.xml

@@ -51,13 +51,15 @@
             app:columnSpacing="@dimen/iscs_space_2"
             app:rowSpacing="@dimen/iscs_space_2">
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/key_code_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"key_name"}' />
 
             <EditText
@@ -76,13 +78,15 @@
                 app:i18nHint='@{"please_input_key_name"}' />
 
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/key_nfc_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"key_nfc"}' />
 
             <EditText
@@ -101,13 +105,15 @@
                 app:i18nHint='@{"please_input_key_nfc"}' />
 
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/key_mac_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"key_mac"}' />
 
             <EditText
@@ -124,13 +130,15 @@
                 app:i18nHint='@{"please_input_key_mac"}' />
 
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/status_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"manage_filter_status"}' />
 
             <RadioGroup
@@ -162,13 +170,15 @@
             </RadioGroup>
 
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/remark_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="false"
                 app:i18nKey='@{"remark"}' />
 
             <EditText

+ 12 - 4
app/src/main/res/layout/dialog_update_lock.xml

@@ -54,13 +54,15 @@
             app:rowSpacing="@dimen/iscs_space_2">
 
             <!-- 挂锁编号 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/lock_code_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"lock_code"}' />
 
             <EditText
@@ -78,13 +80,15 @@
                 app:i18nHint='@{"please_input_lock_code"}' />
 
             <!-- 挂锁 NFC -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/lock_nfc_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"lock_nfc"}' />
 
             <EditText
@@ -102,13 +106,15 @@
                 app:i18nHint='@{"please_input_lock_nfc"}' />
 
             <!-- 状态 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/status_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"manage_filter_status"}' />
 
             <RadioGroup
@@ -140,13 +146,15 @@
             </RadioGroup>
 
             <!-- 备注 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/remark_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="false"
                 app:i18nKey='@{"remark"}' />
 
             <EditText

+ 12 - 4
app/src/main/res/layout/dialog_update_rfid_token.xml

@@ -55,13 +55,15 @@
 
 
             <!-- RFID 编号 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/rfid_code_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"rfid_code"}' />
 
             <EditText
@@ -79,13 +81,15 @@
                 app:i18nHint='@{"please_input_rfid_code"}' />
 
             <!-- RFID 值 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/rfid_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"rfid"}' />
 
             <EditText
@@ -103,13 +107,15 @@
                 app:i18nHint='@{"please_input_rfid"}' />
 
             <!-- 状态 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/status_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"manage_filter_status"}' />
 
             <RadioGroup
@@ -141,13 +147,15 @@
             </RadioGroup>
 
             <!-- 备注 -->
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/remark_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="false"
                 app:i18nKey='@{"remark"}' />
 
             <EditText

+ 3 - 3
app/src/main/res/layout/dialog_update_role.xml

@@ -24,7 +24,7 @@
                 android:layout_weight="1"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
-                app:i18nKey='@{"user_manage_filter_title"}' />
+                app:i18nKey='@{"role_manage_update_title"}' />
 
             <ImageView
                 android:id="@+id/close_iv"
@@ -121,6 +121,7 @@
                 android:id="@+id/status_rg"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/normal_margin_left"
                 android:orientation="horizontal"
                 app:formRole="field">
 
@@ -128,7 +129,6 @@
                     android:id="@+id/activate_rb"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginLeft="@dimen/normal_margin_left"
                     android:textColor="?attr/colorTextPrimary"
                     android:textSize="@dimen/iscs_text_md"
                     app:i18nKey='@{"user_manage_filter_activate"}'
@@ -156,7 +156,7 @@
 
             <LinearLayout
                 android:id="@+id/function_permission_operation_layout"
-                android:layout_width="0dp"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="@dimen/iscs_space_2"
                 android:orientation="horizontal"

+ 14 - 6
app/src/main/res/layout/dialog_update_user.xml

@@ -62,7 +62,7 @@
 
             <EditText
                 android:id="@+id/username_et"
-                android:layout_width="0dp"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="@dimen/iscs_space_2"
                 android:background="@drawable/bg_common_input"
@@ -75,13 +75,15 @@
                 app:formRole="field"
                 app:i18nHint='@{"please_input_username"}' />
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/nickname_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"nickname"}' />
 
             <EditText
@@ -122,13 +124,15 @@
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="field" />
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/role_title_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"user_manage_role"}' />
 
             <TextView
@@ -147,18 +151,20 @@
                 app:formRole="field"
                 app:i18nHint='@{"please_select_role"}' />
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/workstation_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"user_manage_area"}' />
 
             <TextView
                 android:id="@+id/workstation_name_tv"
-                android:layout_width="0dp"
+                android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="@dimen/iscs_space_2"
                 android:background="@drawable/bg_common_input"
@@ -170,13 +176,15 @@
                 app:formRole="field"
                 app:i18nHint='@{"please_select_area"}' />
 
-            <TextView
+            <com.grkj.ui_base.widget.RequiredTextView
                 android:id="@+id/status_tv"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
                 app:formRole="label"
+                app:markPosition="start"
+                app:required="true"
                 app:i18nKey='@{"manage_filter_status"}' />
 
             <RadioGroup

+ 131 - 0
app/src/main/res/layout/fragment_data_export.xml

@@ -0,0 +1,131 @@
+<?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">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="@dimen/iscs_space_2"
+        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/iscs_space_2">
+
+            <ImageView
+                android:layout_width="@dimen/title_icon_size"
+                android:layout_height="@dimen/title_icon_size"
+                android:tint="?attr/colorPrimary"
+                app:skinSrc='@{"ballot.svg"}' />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/iscs_space_2"
+                android:layout_weight="1"
+                android:textColor="?attr/colorTextPrimary"
+                android:textSize="@dimen/iscs_text_md"
+                android:textStyle="bold"
+                app:i18nKey='@{"sop_manage_title"}' />
+
+            <TextView
+                android:id="@+id/back"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="5dp"
+                android:layout_marginLeft="@dimen/iscs_space_2"
+                android:background="@drawable/common_btn_secondary"
+                android:drawableLeft="@mipmap/icon_back"
+                android:drawablePadding="@dimen/iscs_space_2"
+                android:drawableTint="?attr/colorPrimary"
+                android:gravity="center"
+                android:minHeight="@dimen/common_btn_height"
+                android:paddingHorizontal="@dimen/iscs_space_4"
+                android:textColor="?attr/colorTextPrimary"
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"back"}' />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/divider_line_space"
+            android:background="?attr/colorBlack" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/iscs_space_2"
+            android:paddingVertical="@dimen/iscs_space_2">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/iscs_space_2"
+                android:layout_weight="1"
+                android:textColor="?attr/colorTextPrimary"
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"data_export_tip"}' />
+
+            <TextView
+                android:id="@+id/export"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/iscs_space_2"
+                android:layout_marginRight="@dimen/iscs_space_2"
+                android:background="@drawable/common_btn_secondary"
+                android:paddingHorizontal="@dimen/iscs_space_4"
+                android:textColor="?attr/colorTextPrimary"
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"common_export"}' />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="@dimen/iscs_space_4"
+            android:layout_marginTop="@dimen/iscs_space_2"
+            android:background="@drawable/common_card_header_bg"
+            android:divider="@drawable/divider_table"
+            android:showDividers="middle">
+
+            <com.google.android.material.checkbox.MaterialCheckBox
+                android:id="@+id/select_all"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                app:useMaterialThemeColors="true" />
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:textColor="?attr/colorTextPrimary"
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"data_table"}' />
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:textColor="?attr/colorTextPrimary"
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"last_export_datetime"}' />
+        </LinearLayout>
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/sop_list_rv"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginHorizontal="@dimen/iscs_space_4"
+            android:layout_marginBottom="@dimen/iscs_space_2"
+            android:background="@drawable/common_card_bg" />
+    </LinearLayout>
+</layout>

+ 58 - 68
app/src/main/res/layout/fragment_edit_sop.xml

@@ -5,8 +5,8 @@
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:background="@drawable/home_card_bg"
         android:layout_margin="@dimen/iscs_space_2"
+        android:background="@drawable/home_card_bg"
         android:orientation="vertical">
 
         <LinearLayout
@@ -21,17 +21,17 @@
                 android:layout_width="@dimen/title_icon_size"
                 android:layout_height="@dimen/title_icon_size"
                 android:tint="?attr/colorPrimary"
-                app:skinSrc='@{"new_sop.svg"}'/>
+                app:skinSrc='@{"new_sop.svg"}' />
 
             <TextView
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="@dimen/iscs_space_2"
                 android:layout_weight="1"
-                app:i18nKey='@{"edit_sop_title"}'
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
-                android:textStyle="bold" />
+                android:textStyle="bold"
+                app:i18nKey='@{"edit_sop_title"}' />
 
             <TextView
                 android:id="@+id/back"
@@ -41,14 +41,14 @@
                 android:layout_marginLeft="@dimen/iscs_space_2"
                 android:background="@drawable/common_btn_secondary"
                 android:drawableLeft="@mipmap/icon_back"
-                android:drawableTint="?attr/colorPrimary"
                 android:drawablePadding="@dimen/iscs_space_2"
+                android:drawableTint="?attr/colorPrimary"
                 android:gravity="center"
                 android:minHeight="@dimen/common_btn_height"
                 android:paddingHorizontal="@dimen/iscs_space_4"
-                app:i18nKey='@{"back"}'
                 android:textColor="?attr/colorTextPrimary"
-                android:textSize="@dimen/iscs_text_md" />
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"back"}' />
         </LinearLayout>
 
         <View
@@ -83,9 +83,9 @@
                         android:layout_height="wrap_content"
                         android:layout_marginLeft="@dimen/iscs_space_2"
                         android:layout_weight="1"
-                        app:i18nKey='@{"base_info_title"}'
                         android:textColor="?attr/colorTextPrimary"
-                        android:textSize="@dimen/iscs_text_md" />
+                        android:textSize="@dimen/iscs_text_md"
+                        app:i18nKey='@{"base_info_title"}' />
 
                     <View
                         android:layout_width="match_parent"
@@ -93,20 +93,24 @@
                         android:background="?attr/colorDivider" />
 
 
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="@dimen/iscs_space_4"
-                        android:gravity="center_vertical"
-                        android:orientation="horizontal"
-                        android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+                    <com.grkj.ui_base.widget.FormLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:clipToPadding="false"
+                        android:minWidth="0dp"
+                        android:orientation="vertical"
+                        android:padding="@dimen/dialog_content_normal_padding_horizontal"
+                        app:columnSpacing="@dimen/iscs_space_2"
+                        app:rowSpacing="@dimen/iscs_space_2">
 
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            app:i18nKey='@{"sop_workstation"}'
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="label"
+                            app:i18nKey='@{"sop_workstation"}' />
 
                         <TextView
                             android:id="@+id/workstation_tv"
@@ -115,29 +119,22 @@
                             android:layout_marginLeft="@dimen/iscs_space_2"
                             android:background="@drawable/bg_common_input"
                             android:drawableRight="@mipmap/icon_drop_down"
-                            app:i18nHint='@{"please_select_sop_workstation"}'
                             android:maxLines="1"
                             android:paddingHorizontal="@dimen/iscs_space_2"
                             android:paddingVertical="2dp"
                             android:singleLine="true"
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
-                    </LinearLayout>
-
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="@dimen/iscs_space_4"
-                        android:gravity="center_vertical"
-                        android:orientation="horizontal"
-                        android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="field"
+                            app:i18nHint='@{"please_select_sop_workstation"}' />
 
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            app:i18nKey='@{"workflow_mode"}'
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="label"
+                            app:i18nKey='@{"workflow_mode"}' />
 
                         <TextView
                             android:id="@+id/lock_mode_tv"
@@ -146,30 +143,22 @@
                             android:layout_marginLeft="@dimen/iscs_space_2"
                             android:background="@drawable/bg_common_input"
                             android:drawableRight="@mipmap/icon_drop_down"
-                            app:i18nHint='@{"please_select_flow_mode"}'
                             android:maxLines="1"
                             android:paddingHorizontal="@dimen/iscs_space_2"
                             android:paddingVertical="2dp"
                             android:singleLine="true"
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
-                    </LinearLayout>
-
-                    <LinearLayout
-                        android:layout_width="match_parent"
-                        android:layout_height="wrap_content"
-                        android:layout_marginTop="@dimen/iscs_space_4"
-                        android:layout_marginBottom="@dimen/iscs_space_4"
-                        android:gravity="center_vertical"
-                        android:orientation="horizontal"
-                        android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="field"
+                            app:i18nHint='@{"please_select_flow_mode"}' />
 
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            app:i18nKey='@{"create_sop_name"}'
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="label"
+                            app:i18nKey='@{"create_sop_name"}' />
 
                         <EditText
                             android:id="@+id/sop_name_et"
@@ -177,14 +166,15 @@
                             android:layout_height="wrap_content"
                             android:layout_marginLeft="@dimen/iscs_space_2"
                             android:background="@drawable/bg_common_input"
-                            app:i18nHint='@{"please_input_sop_name"}'
                             android:maxLines="1"
                             android:paddingHorizontal="@dimen/iscs_space_2"
                             android:paddingVertical="2dp"
                             android:singleLine="true"
                             android:textColor="?attr/colorTextPrimary"
-                            android:textSize="@dimen/iscs_text_md" />
-                    </LinearLayout>
+                            android:textSize="@dimen/iscs_text_md"
+                            app:formRole="field"
+                            app:i18nHint='@{"please_input_sop_name"}' />
+                    </com.grkj.ui_base.widget.FormLayout>
                 </LinearLayout>
 
                 <LinearLayout
@@ -214,9 +204,9 @@
                                 android:layout_height="wrap_content"
                                 android:layout_marginLeft="@dimen/iscs_space_2"
                                 android:layout_weight="1"
-                                app:i18nKey='@{"workflow_mode"}'
                                 android:textColor="?attr/colorTextPrimary"
-                                android:textSize="@dimen/iscs_text_md" />
+                                android:textSize="@dimen/iscs_text_md"
+                                app:i18nKey='@{"workflow_mode"}' />
 
                             <TextView
                                 android:id="@+id/workflow_mode_setting_tv"
@@ -226,9 +216,9 @@
                                 android:layout_marginRight="@dimen/iscs_space_2"
                                 android:background="@drawable/common_btn_secondary"
                                 android:paddingHorizontal="@dimen/iscs_space_4"
-                                app:i18nKey='@{"settings"}'
                                 android:textColor="?attr/colorTextPrimary"
-                                android:textSize="@dimen/iscs_text_md" />
+                                android:textSize="@dimen/iscs_text_md"
+                                app:i18nKey='@{"settings"}' />
                         </LinearLayout>
 
                         <View
@@ -271,9 +261,9 @@
                                 android:layout_height="wrap_content"
                                 android:layout_marginLeft="@dimen/iscs_space_2"
                                 android:layout_weight="1"
-                                app:i18nKey='@{"point_info_title"}'
                                 android:textColor="?attr/colorTextPrimary"
-                                android:textSize="@dimen/iscs_text_md" />
+                                android:textSize="@dimen/iscs_text_md"
+                                app:i18nKey='@{"point_info_title"}' />
 
                             <TextView
                                 android:id="@+id/select_point_tv"
@@ -283,9 +273,9 @@
                                 android:layout_marginRight="@dimen/iscs_space_2"
                                 android:background="@drawable/common_btn_secondary"
                                 android:paddingHorizontal="@dimen/iscs_space_4"
-                                app:i18nKey='@{"select"}'
                                 android:textColor="?attr/colorTextPrimary"
-                                android:textSize="@dimen/iscs_text_md" />
+                                android:textSize="@dimen/iscs_text_md"
+                                app:i18nKey='@{"select"}' />
                         </LinearLayout>
 
                         <View
@@ -323,9 +313,9 @@
                                 android:layout_height="wrap_content"
                                 android:layout_marginLeft="@dimen/iscs_space_2"
                                 android:layout_weight="1"
-                                app:i18nKey='@{"member_info_title"}'
                                 android:textColor="?attr/colorTextPrimary"
-                                android:textSize="@dimen/iscs_text_md" />
+                                android:textSize="@dimen/iscs_text_md"
+                                app:i18nKey='@{"member_info_title"}' />
 
                             <TextView
                                 android:id="@+id/select_member_tv"
@@ -335,9 +325,9 @@
                                 android:layout_marginRight="@dimen/iscs_space_2"
                                 android:background="@drawable/common_btn_secondary"
                                 android:paddingHorizontal="@dimen/iscs_space_4"
-                                app:i18nKey='@{"select"}'
                                 android:textColor="?attr/colorTextPrimary"
-                                android:textSize="@dimen/iscs_text_md" />
+                                android:textSize="@dimen/iscs_text_md"
+                                app:i18nKey='@{"select"}' />
                         </LinearLayout>
 
                         <View
@@ -365,9 +355,9 @@
                                     android:gravity="center"
                                     android:paddingHorizontal="@dimen/iscs_space_4"
                                     android:paddingVertical="@dimen/iscs_space_2"
-                                    app:i18nKey='@{"locker"}'
                                     android:textColor="?attr/colorTextPrimary"
-                                    android:textSize="@dimen/iscs_text_md" />
+                                    android:textSize="@dimen/iscs_text_md"
+                                    app:i18nKey='@{"locker"}' />
 
                                 <View
                                     android:layout_width="match_parent"
@@ -397,9 +387,9 @@
                                     android:gravity="center"
                                     android:paddingHorizontal="@dimen/iscs_space_4"
                                     android:paddingVertical="@dimen/iscs_space_2"
-                                    app:i18nKey='@{"colocker"}'
                                     android:textColor="?attr/colorTextPrimary"
-                                    android:textSize="@dimen/iscs_text_md" />
+                                    android:textSize="@dimen/iscs_text_md"
+                                    app:i18nKey='@{"colocker"}' />
 
                                 <View
                                     android:layout_width="match_parent"
@@ -437,9 +427,9 @@
                 android:gravity="center"
                 android:minHeight="@dimen/common_btn_height"
                 android:paddingHorizontal="@dimen/iscs_space_4"
-                app:i18nKey='@{"confirm"}'
                 android:textColor="?attr/colorTextPrimary"
-                android:textSize="@dimen/iscs_text_md" />
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"confirm"}' />
 
             <TextView
                 android:id="@+id/cancel"
@@ -452,9 +442,9 @@
                 android:gravity="center"
                 android:minHeight="@dimen/common_btn_height"
                 android:paddingHorizontal="@dimen/iscs_space_4"
-                app:i18nKey='@{"cancel"}'
                 android:textColor="?attr/colorTextPrimary"
-                android:textSize="@dimen/iscs_text_md" />
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"cancel"}' />
         </LinearLayout>
     </LinearLayout>
 </layout>

+ 39 - 55
app/src/main/res/layout/fragment_exception_report.xml

@@ -29,10 +29,10 @@
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="@dimen/iscs_space_2"
                 android:layout_weight="1"
-                app:i18nKey='@{"exception_report"}'
                 android:textColor="?attr/colorTextPrimary"
                 android:textSize="@dimen/iscs_text_md"
-                android:textStyle="bold" />
+                android:textStyle="bold"
+                app:i18nKey='@{"exception_report"}' />
 
             <TextView
                 android:id="@+id/back"
@@ -42,14 +42,14 @@
                 android:layout_marginLeft="@dimen/iscs_space_2"
                 android:background="@drawable/common_btn_secondary"
                 android:drawableLeft="@mipmap/icon_back"
-                android:drawableTint="?attr/colorPrimary"
                 android:drawablePadding="@dimen/iscs_space_2"
+                android:drawableTint="?attr/colorPrimary"
                 android:gravity="center"
                 android:minHeight="@dimen/common_btn_height"
                 android:paddingHorizontal="@dimen/iscs_space_4"
-                app:i18nKey='@{"back"}'
                 android:textColor="?attr/colorTextPrimary"
-                android:textSize="@dimen/iscs_text_md" />
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"back"}' />
         </LinearLayout>
 
         <View
@@ -73,149 +73,133 @@
                 android:layout_height="wrap_content"
                 android:layout_marginLeft="@dimen/iscs_space_2"
                 android:paddingVertical="@dimen/iscs_space_1"
-                app:i18nKey='@{"exception_info"}'
                 android:textColor="?attr/colorTextPrimary"
-                android:textSize="@dimen/iscs_text_md" />
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"exception_info"}' />
 
             <View
                 android:layout_width="match_parent"
                 android:layout_height="@dimen/divider_line_space"
                 android:background="?attr/colorBlack" />
 
-            <androidx.constraintlayout.widget.ConstraintLayout
-                android:layout_width="match_parent"
+            <com.grkj.ui_base.widget.FormLayout
+                android:layout_width="wrap_content"
                 android:layout_height="match_parent"
                 android:layout_weight="1"
+                android:clipToPadding="false"
+                android:minWidth="0dp"
                 android:orientation="vertical"
-                android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+                android:padding="@dimen/dialog_content_normal_padding_horizontal"
+                app:columnSpacing="@dimen/iscs_space_2"
+                app:rowSpacing="@dimen/iscs_space_2">
 
                 <com.grkj.ui_base.widget.RequiredTextView
                     android:id="@+id/exception_type_tv"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="@dimen/iscs_space_4"
-                    app:i18nKey='@{"exception_type_tv"}'
                     android:textColor="?attr/colorTextPrimary"
                     android:textSize="@dimen/iscs_text_md"
-                    app:layout_constraintStart_toStartOf="parent"
-                    app:layout_constraintTop_toTopOf="parent"
+                    app:formRole="label"
+                    app:i18nKey='@{"exception_type_tv"}'
                     app:markPosition="start"
                     app:required="true" />
 
                 <TextView
                     android:id="@+id/exception_type"
-                    android:layout_width="0dp"
+                    android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginLeft="@dimen/iscs_space_2"
                     android:background="@drawable/bg_common_input"
                     android:drawableRight="@mipmap/icon_drop_down"
-                    app:i18nHint='@{"please_select_exception_type"}'
                     android:maxLines="1"
                     android:paddingHorizontal="@dimen/iscs_space_2"
                     android:paddingVertical="@dimen/iscs_space_1"
                     android:singleLine="true"
                     android:textColor="?attr/colorTextPrimary"
                     android:textSize="@dimen/iscs_text_md"
-                    app:layout_constraintBottom_toBottomOf="@+id/exception_type_tv"
-                    app:layout_constraintEnd_toEndOf="parent"
-                    app:layout_constraintStart_toEndOf="@+id/exception_type_tv"
-                    app:layout_constraintTop_toTopOf="@+id/exception_type_tv" />
+                    app:formRole="field"
+                    app:i18nHint='@{"please_select_exception_type"}' />
 
 
                 <com.grkj.ui_base.widget.RequiredTextView
                     android:id="@+id/exception_source_tv"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="@dimen/iscs_space_4"
-                    app:i18nKey='@{"exception_source_tv"}'
                     android:textColor="?attr/colorTextPrimary"
                     android:textSize="@dimen/iscs_text_md"
-                    app:layout_constraintEnd_toEndOf="@+id/exception_type_tv"
-                    app:layout_constraintTop_toBottomOf="@+id/exception_type_tv"
+                    app:formRole="label"
+                    app:i18nKey='@{"exception_source_tv"}'
                     app:markPosition="start"
                     app:required="true" />
 
                 <TextView
                     android:id="@+id/exception_source"
-                    android:layout_width="0dp"
+                    android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginLeft="@dimen/iscs_space_2"
                     android:background="@drawable/bg_common_input"
                     android:drawableRight="@mipmap/icon_drop_down"
-                    app:i18nHint='@{"please_select_exception_source"}'
                     android:maxLines="1"
                     android:paddingHorizontal="@dimen/iscs_space_2"
                     android:paddingVertical="@dimen/iscs_space_1"
                     android:singleLine="true"
                     android:textColor="?attr/colorTextPrimary"
                     android:textSize="@dimen/iscs_text_md"
-                    app:layout_constraintBottom_toBottomOf="@+id/exception_source_tv"
-                    app:layout_constraintEnd_toEndOf="parent"
-                    app:layout_constraintStart_toEndOf="@+id/exception_source_tv"
-                    app:layout_constraintTop_toTopOf="@+id/exception_source_tv" />
+                    app:formRole="field"
+                    app:i18nHint='@{"please_select_exception_source"}' />
 
 
                 <com.grkj.ui_base.widget.RequiredTextView
                     android:id="@+id/exception_description_tv"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="@dimen/iscs_space_4"
-                    app:i18nKey='@{"exception_description_tv"}'
                     android:textColor="?attr/colorTextPrimary"
                     android:textSize="@dimen/iscs_text_md"
-                    app:layout_constraintEnd_toEndOf="@+id/exception_source_tv"
-                    app:layout_constraintTop_toBottomOf="@+id/exception_source_tv"
+                    app:formRole="label"
+                    app:i18nKey='@{"exception_description_tv"}'
                     app:markPosition="start"
                     app:required="true" />
 
                 <TextView
                     android:id="@+id/exception_description"
-                    android:layout_width="0dp"
+                    android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginLeft="@dimen/iscs_space_2"
                     android:background="@drawable/bg_common_input"
                     android:drawableRight="@mipmap/icon_drop_down"
-                    app:i18nHint='@{"please_select_exception_description"}'
                     android:paddingHorizontal="@dimen/iscs_space_2"
                     android:paddingVertical="@dimen/iscs_space_1"
                     android:textColor="?attr/colorTextPrimary"
                     android:textSize="@dimen/iscs_text_md"
-                    app:layout_constraintBottom_toBottomOf="@+id/exception_description_tv"
-                    app:layout_constraintEnd_toEndOf="parent"
-                    app:layout_constraintStart_toEndOf="@+id/exception_description_tv"
-                    app:layout_constraintTop_toTopOf="@+id/exception_description_tv" />
+                    app:formRole="field"
+                    app:i18nHint='@{"please_select_exception_description"}' />
 
 
                 <com.grkj.ui_base.widget.RequiredTextView
                     android:id="@+id/process_application_tv"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_marginTop="@dimen/iscs_space_4"
-                    app:i18nKey='@{"process_application_tv"}'
                     android:textColor="?attr/colorTextPrimary"
                     android:textSize="@dimen/iscs_text_md"
-                    app:layout_constraintEnd_toEndOf="@+id/exception_description_tv"
-                    app:layout_constraintTop_toBottomOf="@+id/exception_description_tv"
+                    app:formRole="label"
+                    app:i18nKey='@{"process_application_tv"}'
                     app:markPosition="start"
                     app:required="true" />
 
                 <TextView
                     android:id="@+id/process_application"
-                    android:layout_width="0dp"
+                    android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:layout_marginLeft="@dimen/iscs_space_2"
                     android:background="@drawable/bg_common_input"
                     android:drawableRight="@mipmap/icon_drop_down"
-                    app:i18nHint='@{"please_select_process_application"}'
                     android:paddingHorizontal="@dimen/iscs_space_2"
                     android:paddingVertical="@dimen/iscs_space_1"
                     android:textColor="?attr/colorTextPrimary"
                     android:textSize="@dimen/iscs_text_md"
-                    app:layout_constraintBottom_toBottomOf="@+id/process_application_tv"
-                    app:layout_constraintEnd_toEndOf="parent"
-                    app:layout_constraintStart_toEndOf="@+id/process_application_tv"
-                    app:layout_constraintTop_toTopOf="@+id/process_application_tv" />
-            </androidx.constraintlayout.widget.ConstraintLayout>
+                    app:formRole="field"
+                    app:i18nHint='@{"please_select_process_application"}' />
+            </com.grkj.ui_base.widget.FormLayout>
         </LinearLayout>
 
         <LinearLayout
@@ -237,9 +221,9 @@
                 android:gravity="center"
                 android:minHeight="@dimen/common_btn_height"
                 android:paddingHorizontal="@dimen/iscs_space_4"
-                app:i18nKey='@{"confirm"}'
                 android:textColor="?attr/colorTextPrimary"
-                android:textSize="@dimen/iscs_text_md" />
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"confirm"}' />
 
             <TextView
                 android:id="@+id/cancel"
@@ -252,9 +236,9 @@
                 android:gravity="center"
                 android:minHeight="@dimen/common_btn_height"
                 android:paddingHorizontal="@dimen/iscs_space_4"
-                app:i18nKey='@{"cancel"}'
                 android:textColor="?attr/colorTextPrimary"
-                android:textSize="@dimen/iscs_text_md" />
+                android:textSize="@dimen/iscs_text_md"
+                app:i18nKey='@{"cancel"}' />
         </LinearLayout>
     </LinearLayout>
 </layout>

+ 7 - 0
app/src/main/res/navigation/nav_data_manage.xml

@@ -26,6 +26,9 @@
         <action
             android:id="@+id/action_dataManageHomeFragment_to_nav_switch_layout"
             app:destination="@id/nav_switch_layout" />
+        <action
+            android:id="@+id/action_dataManageHomeFragment_to_dataExportFragment"
+            app:destination="@id/dataExportFragment" />
     </fragment>
     <fragment
         android:id="@+id/userManageFragment"
@@ -48,4 +51,8 @@
         android:name="com.grkj.iscs.features.main.fragment.data_manage.BackupAndRestoreFragment"
         android:label="BackupAndRestoreFragment" />
     <include app:graph="@navigation/nav_switch_layout" />
+    <fragment
+        android:id="@+id/dataExportFragment"
+        android:name="com.grkj.iscs.features.main.fragment.data_manage.DataExportFragment"
+        android:label="DataExportFragment" />
 </navigation>

+ 1 - 1
data/src/main/java/com/grkj/data/data/CommonConstants.kt

@@ -28,7 +28,7 @@ object CommonConstants {
     /**
      * 默认自动登出时间
      */
-    const val DEFAULT_AUTO_LOGOUT_TIME = 120_000L
+    const val DEFAULT_AUTO_LOGOUT_TIME = 1800_000L
 
     /**
      * 人脸文件夹

+ 2 - 0
data/src/main/java/com/grkj/data/enums/RoleFunctionalPermissionsEnum.kt

@@ -27,6 +27,7 @@ enum class RoleFunctionalPermissionsEnum(
         listOf()
     ),
     SWITCH_LAYOUT("data_manage:switch_layout", "switch_layout", 1, listOf()),
+    DATA_EXPORT("data_manage:data_export", "data_export", 1, listOf()),
     IN_PROGRESS_JOB(
         "job_ticket_manage:in_progress_job",
         "in_progress_job",
@@ -132,6 +133,7 @@ enum class RoleFunctionalPermissionsEnum(
             WORKSTATION_MANAGE,
             POINT_MANAGE,
             BACKUP_AND_RESTORE,
+            DATA_EXPORT,
             SWITCH_LAYOUT
         )
     ),

+ 108 - 94
shared/src/main/java/com/grkj/shared/utils/ArcSoftUtil.kt

@@ -105,7 +105,9 @@ object ArcSoftUtil {
 
     private const val ACTION_REQUEST_PERMISSIONS: Int = 0x001
     var isActivated = false
-    @Volatile var inDetecting = false
+
+    @Volatile
+    var inDetecting = false
 
     // 新增:未检出人脸提示节流
     private var startDetectFaceTime = 0L
@@ -142,10 +144,12 @@ object ArcSoftUtil {
                 isActivated = true
                 logger.info("checkActiveStatus : active success (online=${cfg.activeOnline})")
             }
+
             ErrorInfo.MERR_ASF_ALREADY_ACTIVATED -> {
                 isActivated = true
                 logger.info("checkActiveStatus : already activated")
             }
+
             else -> {
                 isActivated = false
                 logger.error("checkActiveStatus : active failed $activeCode")
@@ -207,66 +211,71 @@ object ArcSoftUtil {
             override fun onPreview(nv21: ByteArray?, camera: Camera?) {
                 if (inDetecting) return
                 inDetecting = true
-                try {
-                    val faces: MutableList<FaceInfo> = ArrayList()
-                    val fe = faceEngine ?: run {
-                        inDetecting = false; return
-                    }
-                    val psize = previewSize ?: run {
-                        inDetecting = false; return
-                    }
-                    var code = fe.detectFaces(
-                        nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces
-                    )
-                    faceOverlayView?.setFaceRect(faces.map { it.rect })
+                val faces: MutableList<FaceInfo> = ArrayList()
+                val fe = faceEngine ?: run {
+                    inDetecting = false; return
+                }
+                val psize = previewSize ?: run {
+                    inDetecting = false; return
+                }
+                var code = fe.detectFaces(
+                    nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces
+                )
+                faceOverlayView?.setFaceRect(faces.map { it.rect })
+
+                if (code != ErrorInfo.MOK || faces.isEmpty()) {
+                    maybeLogNoFaceTip()
+                    inDetecting = false
+                    return
+                }
+
+                // 处理活体/口罩等
+                code = fe.process(
+                    nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces, processMask
+                )
+                if (code != ErrorInfo.MOK) {
+                    inDetecting = false
+                    return
+                }
 
-                    if (code != ErrorInfo.MOK || faces.isEmpty()) {
-                        maybeLogNoFaceTip()
-                        inDetecting = false
-                        return
-                    }
+                val liveList: MutableList<LivenessInfo> = ArrayList()
+                val livenessCode = fe.getLiveness(liveList)
+                if (livenessCode != ErrorInfo.MOK) {
+                    inDetecting = false
+                    return
+                }
+
+                // 仅 ALIVE 通过
+                if (liveList.none { it.liveness == LivenessInfo.ALIVE }) {
+                    callBack(null, faces.size, false)
+                    inDetecting = false
+                    return
+                }
 
-                    // 处理活体/口罩等
-                    code = fe.process(
-                        nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces, processMask
+                // 可选:中心区域约束
+                if (needCheckCenter && !faces[0].rect.isInCenterArea(
+                        psize.width,
+                        psize.height
                     )
-                    if (code != ErrorInfo.MOK) {
-                        inDetecting = false
-                        return
-                    }
-
-                    val liveList: MutableList<LivenessInfo> = ArrayList()
-                    val livenessCode = fe.getLiveness(liveList)
-                    if (livenessCode != ErrorInfo.MOK) {
-                        inDetecting = false
-                        return
-                    }
-
-                    // 仅 ALIVE 通过
-                    if (liveList.none { it.liveness == LivenessInfo.ALIVE }) {
-                        callBack(null, faces.size, false)
-                        inDetecting = false
-                        return
-                    }
-
-                    // 可选:中心区域约束
-                    if (needCheckCenter && !faces[0].rect.isInCenterArea(psize.width, psize.height)) {
-                        inDetecting = false
-                        return
-                    }
-
-                    val bmp = ImageConvertUtils.nv21ToBitmap(nv21, psize.width, psize.height)
-                    logger.debug("人脸检测结果-识别结果 : ${bmp == null} - $faces")
-                    callBack(bmp, faces.size, true)
-                } catch (_: Throwable) {
-                    // 忽略单帧异常,避免闪退
-                } finally {
+                ) {
                     inDetecting = false
+                    return
                 }
+
+                val bmp = ImageConvertUtils.nv21ToBitmap(nv21, psize.width, psize.height)
+                logger.debug("人脸检测结果-识别结果 : ${bmp == null} - $faces")
+                callBack(bmp, faces.size, true)
+
+            }
+
+            override fun onCameraClosed() {
+                logger.info("onCameraClosed")
+            }
+
+            override fun onCameraError(e: Exception) {
+                logger.info("onCameraError: ${e.message}")
             }
 
-            override fun onCameraClosed() { logger.info("onCameraClosed") }
-            override fun onCameraError(e: Exception) { logger.info("onCameraError: ${e.message}") }
             override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) {
                 logger.info("onCameraConfigurationChanged: $cameraID  $displayOrientation")
             }
@@ -306,48 +315,49 @@ object ArcSoftUtil {
             override fun onPreview(nv21: ByteArray?, camera: Camera?) {
                 if (inDetecting) return
                 inDetecting = true
-                try {
-                    val fe = faceEngine ?: run { return }
-                    val psize = previewSize ?: run { return }
+                val fe = faceEngine ?: run { return }
+                val psize = previewSize ?: run { return }
+
+                val faces: MutableList<FaceInfo> = ArrayList()
+                var code = fe.detectFaces(
+                    nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces
+                )
+                if (code != ErrorInfo.MOK || faces.isEmpty()) return
+
+                code = fe.process(
+                    nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces, processMask
+                )
+                if (code != ErrorInfo.MOK) return
+
+                val liveList: MutableList<LivenessInfo> = ArrayList()
+                val livenessCode = fe.getLiveness(liveList)
+                if (livenessCode != ErrorInfo.MOK) return
+                if (liveList.none { it.liveness == LivenessInfo.ALIVE }) {
+                    callBack(null, null); return
+                }
 
-                    val faces: MutableList<FaceInfo> = ArrayList()
-                    var code = fe.detectFaces(
-                        nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces
-                    )
-                    if (code != ErrorInfo.MOK || faces.isEmpty()) return
+                val ft = FaceFeature()
+                fe.extractFaceFeature(
+                    nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces[0],
+                    ExtractType.RECOGNIZE, 0, ft
+                )
+                val searchResult = runCatching {
+                    if (fe.faceCount > 0) fe.searchFaceFeature(ft) else null
+                }.onFailure { logger.info("搜索人脸异常") }.getOrNull()
+
+                logger.debug("人脸检测结果-识别结果 : ${searchResult?.faceFeatureInfo} - $faces")
+                val bmp = ImageConvertUtils.nv21ToBitmap(nv21, psize.width, psize.height)
+                callBack(bmp, searchResult?.faceFeatureInfo?.searchId?.toLong())
+            }
 
-                    code = fe.process(
-                        nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces, processMask
-                    )
-                    if (code != ErrorInfo.MOK) return
-
-                    val liveList: MutableList<LivenessInfo> = ArrayList()
-                    val livenessCode = fe.getLiveness(liveList)
-                    if (livenessCode != ErrorInfo.MOK) return
-                    if (liveList.none { it.liveness == LivenessInfo.ALIVE }) {
-                        callBack(null, null); return
-                    }
-
-                    val ft = FaceFeature()
-                    fe.extractFaceFeature(
-                        nv21, psize.width, psize.height, FaceEngine.CP_PAF_NV21, faces[0],
-                        ExtractType.RECOGNIZE, 0, ft
-                    )
-                    val searchResult = runCatching {
-                        if (fe.faceCount > 0) fe.searchFaceFeature(ft) else null
-                    }.onFailure { logger.info("搜索人脸异常") }.getOrNull()
-
-                    logger.debug("人脸检测结果-识别结果 : ${searchResult?.faceFeatureInfo} - $faces")
-                    val bmp = ImageConvertUtils.nv21ToBitmap(nv21, psize.width, psize.height)
-                    callBack(bmp, searchResult?.faceFeatureInfo?.searchId?.toLong())
-                } catch (_: Throwable) {
-                } finally {
-                    inDetecting = false
-                }
+            override fun onCameraClosed() {
+                logger.info("onCameraClosed")
+            }
+
+            override fun onCameraError(e: Exception) {
+                logger.info("onCameraError: ${e.message}")
             }
 
-            override fun onCameraClosed() { logger.info("onCameraClosed") }
-            override fun onCameraError(e: Exception) { logger.info("onCameraError: ${e.message}") }
             override fun onCameraConfigurationChanged(cameraID: Int, displayOrientation: Int) {
                 logger.info("onCameraConfigurationChanged: $cameraID  $displayOrientation")
             }
@@ -379,7 +389,7 @@ object ArcSoftUtil {
         cameraHelper?.release()
         cameraHelper = null
         // 新:对齐“新的”实现,释放引擎
-        unInitEngine()
+//        unInitEngine()
     }
 
     // ----------------- 下方原有注册/比对逻辑保持不变 -----------------
@@ -393,7 +403,11 @@ object ArcSoftUtil {
             val imageData = bitmapToBgr24(faceBitmap)
             val faceInfoList = mutableListOf<FaceInfo>()
             val code = faceEngine?.detectFaces(
-                imageData, faceBitmap.width, faceBitmap.height, FaceEngine.CP_PAF_BGR24, faceInfoList
+                imageData,
+                faceBitmap.width,
+                faceBitmap.height,
+                FaceEngine.CP_PAF_BGR24,
+                faceInfoList
             )
             logger.info("人脸检测结果:${code}")
             if (faceInfoList.isEmpty()) {

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/config/ISCSConfig.kt

@@ -15,7 +15,7 @@ object ISCSConfig {
     /**
      * Debug模式
      */
-    const val DEBUG: Boolean = false
+    const val DEBUG: Boolean = true
 
     /**
      * 是否在注册设备