Эх сурвалжийг харах

refactor(更新)
- 首页菜单搭建
- 用户管理搭建

周文健 5 сар өмнө
parent
commit
608bd18e40
89 өөрчлөгдсөн 3460 нэмэгдсэн , 77 устгасан
  1. 1 0
      app/build.gradle.kts
  2. BIN
      app/src/main/assets/data.db
  3. 41 1
      app/src/main/java/com/grkj/iscs/ISCSApplication.kt
  4. 56 2
      app/src/main/java/com/grkj/iscs/features/login/activity/LoginActivity.kt
  5. 3 0
      app/src/main/java/com/grkj/iscs/features/login/dialog/LoginDialog.kt
  6. 1 0
      app/src/main/java/com/grkj/iscs/features/login/viewmodel/LoginViewModel.kt
  7. 5 8
      app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt
  8. 76 0
      app/src/main/java/com/grkj/iscs/features/main/dialog/AddUserDialog.kt
  9. 50 0
      app/src/main/java/com/grkj/iscs/features/main/dialog/FilterUserDialog.kt
  10. 79 0
      app/src/main/java/com/grkj/iscs/features/main/dialog/TextDropDownDialog.kt
  11. 12 0
      app/src/main/java/com/grkj/iscs/features/main/entity/MenuItemEntity.kt
  12. 7 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/AreaManageFragment.kt
  13. 89 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/DataManageHomeFragment.kt
  14. 7 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/PointMangeFragment.kt
  15. 7 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/RoleManageFragment.kt
  16. 164 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/data_manage/UserManageFragment.kt
  17. 72 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/exception_manage/ExceptionManageHomeFragment.kt
  18. 89 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/hardware_manage/HardwareManageHomeFragment.kt
  19. 51 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/home/HomeFragment.kt
  20. 9 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/home/HomeViewModel.kt
  21. 95 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobManageHomeFragment.kt
  22. 145 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/user_info/UserInfoHomeFragment.kt
  23. 60 0
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/user_manage/UserManageViewModel.kt
  24. 6 0
      app/src/main/res/drawable/bg_common_input.xml
  25. 6 0
      app/src/main/res/drawable/bg_common_input_land.xml
  26. 6 0
      app/src/main/res/drawable/bg_home_card_num.xml
  27. 6 0
      app/src/main/res/drawable/bg_home_card_num_land.xml
  28. 5 0
      app/src/main/res/drawable/bg_home_menu_item.xml
  29. 5 0
      app/src/main/res/drawable/bg_home_menu_item_land.xml
  30. 8 0
      app/src/main/res/drawable/divider_table.xml
  31. 8 0
      app/src/main/res/drawable/home_card_bg.xml
  32. 5 0
      app/src/main/res/drawable/icon_close.xml
  33. 5 0
      app/src/main/res/drawable/icon_drop_down.xml
  34. 443 0
      app/src/main/res/layout-land/fragment_home.xml
  35. 32 0
      app/src/main/res/layout-land/item_home_quick_entrance.xml
  36. 232 0
      app/src/main/res/layout/dialog_add_user.xml
  37. 14 0
      app/src/main/res/layout/dialog_drop_down_list.xml
  38. 204 0
      app/src/main/res/layout/dialog_filter_user.xml
  39. 7 0
      app/src/main/res/layout/fragment_data_manage_home.xml
  40. 8 1
      app/src/main/res/layout/fragment_exception_manage_home.xml
  41. 7 1
      app/src/main/res/layout/fragment_hardware_manage_home.xml
  42. 440 5
      app/src/main/res/layout/fragment_home.xml
  43. 7 1
      app/src/main/res/layout/fragment_job_manage_home.xml
  44. 15 0
      app/src/main/res/layout/fragment_user_info_home.xml
  45. 154 0
      app/src/main/res/layout/fragment_user_manage.xml
  46. 31 0
      app/src/main/res/layout/item_home_menu.xml
  47. 32 0
      app/src/main/res/layout/item_home_quick_entrance.xml
  48. 12 0
      app/src/main/res/layout/item_home_text_drop_down.xml
  49. 41 0
      app/src/main/res/layout/item_user_manage_user.xml
  50. 9 1
      app/src/main/res/navigation/nav_data_manage.xml
  51. 11 0
      app/src/main/res/navigation/nav_user_info.xml
  52. 38 0
      app/src/main/res/values-en/strings.xml
  53. 38 0
      app/src/main/res/values-zh/strings.xml
  54. 4 0
      app/src/main/res/values/colors.xml
  55. 38 0
      app/src/main/res/values/strings.xml
  56. 35 0
      data/src/main/java/com/grkj/data/dao/UserDao.kt
  57. 4 2
      data/src/main/java/com/grkj/data/database/ISCSDatabase.kt
  58. 4 4
      data/src/main/java/com/grkj/data/model/dos/IsJobCardDo.kt
  59. 75 0
      data/src/main/java/com/grkj/data/model/dos/SysRole.kt
  60. 9 5
      data/src/main/java/com/grkj/data/model/dos/SysUserCharacteristicDo.kt
  61. 4 4
      data/src/main/java/com/grkj/data/model/dos/SysUserDo.kt
  62. 16 0
      data/src/main/java/com/grkj/data/model/dos/SysUserRole.kt
  63. 27 0
      data/src/main/java/com/grkj/data/model/vo/UserManageVo.kt
  64. 20 4
      data/src/main/java/com/grkj/data/repository/UserRepository.kt
  65. 12 0
      domain/src/main/java/com/grkj/domain/entity/vo/AddUserDataVo.kt
  66. 11 0
      domain/src/main/java/com/grkj/domain/entity/vo/UserManageFilterVo.kt
  67. 12 0
      domain/src/main/java/com/grkj/domain/repository/IUserRepository.kt
  68. 1 0
      settings.gradle.kts
  69. 4 0
      ui-base/build.gradle.kts
  70. 19 8
      ui-base/src/main/java/com/grkj/ui_base/base/BaseFragment.kt
  71. 17 22
      ui-base/src/main/java/com/grkj/ui_base/dialog/LoadingDialog.kt
  72. 13 1
      ui-base/src/main/java/com/grkj/ui_base/dialog/TipDialog.kt
  73. 101 0
      ui-base/src/main/java/com/grkj/ui_base/ext/ViewBadgeExtensions.kt
  74. 1 0
      ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConnectionManager.kt
  75. 23 0
      ui-base/src/main/java/com/grkj/ui_base/utils/extension/DialogXExtension.kt
  76. 7 0
      ui-base/src/main/res/drawable/black_stroke_bg.xml
  77. 6 0
      ui-base/src/main/res/drawable/common_back_btn.xml
  78. 0 0
      ui-base/src/main/res/drawable/common_card_bg.xml
  79. 6 0
      ui-base/src/main/res/drawable/common_divider_normal_space_horizontal_land.xml
  80. 6 0
      ui-base/src/main/res/drawable/common_divider_normal_space_vertical_land.xml
  81. 6 0
      ui-base/src/main/res/drawable/common_divider_small_space_horizontal.xml
  82. 6 0
      ui-base/src/main/res/drawable/common_divider_small_space_horizontal_land.xml
  83. 1 1
      ui-base/src/main/res/layout-land/dialog_tip.xml
  84. 8 3
      ui-base/src/main/res/layout/common_dialog_loading_progress.xml
  85. 1 1
      ui-base/src/main/res/layout/dialog_tip.xml
  86. 2 0
      ui-base/src/main/res/values-en/strings.xml
  87. 2 0
      ui-base/src/main/res/values-zh/strings.xml
  88. 3 0
      ui-base/src/main/res/values/colors.xml
  89. 2 0
      ui-base/src/main/res/values/strings.xml

+ 1 - 0
app/build.gradle.kts

@@ -82,6 +82,7 @@ dependencies {
     implementation(libs.android.navigation.dynamic.features.fragment)
     implementation(libs.kotlinx.serialization.json)
     implementation(libs.sik.camera)
+    implementation("com.github.loper7:DateTimePicker:0.6.3")
     implementation(project(":sync"))
     implementation(project(":ui-base"))
     implementation(project(":data"))

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


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

@@ -1,10 +1,20 @@
 package com.grkj.iscs
 
+import android.R
 import android.app.Application
-import com.grkj.shared.utils.ArcSoftUtil
+import android.content.Context
 import com.kongzue.dialogx.DialogX
+import com.scwang.smart.refresh.footer.ClassicsFooter
+import com.scwang.smart.refresh.header.ClassicsHeader
+import com.scwang.smart.refresh.layout.SmartRefreshLayout
+import com.scwang.smart.refresh.layout.api.RefreshFooter
+import com.scwang.smart.refresh.layout.api.RefreshHeader
+import com.scwang.smart.refresh.layout.api.RefreshLayout
+import com.scwang.smart.refresh.layout.listener.DefaultRefreshFooterCreator
+import com.scwang.smart.refresh.layout.listener.DefaultRefreshHeaderCreator
 import com.sik.sikcore.SIKCore
 
+
 /**
  * 启动入口
  */
@@ -19,4 +29,34 @@ class ISCSApplication : Application() {
         //todo 模拟器不支持
 //        ArcSoftUtil.checkActiveStatus(this)
     }
+
+    //static 代码段可以防止内存泄露
+    init {
+
+        //设置全局的Header构建器
+        SmartRefreshLayout.setDefaultRefreshHeaderCreator(object : DefaultRefreshHeaderCreator {
+            override fun createRefreshHeader(
+                context: Context,
+                layout: RefreshLayout
+            ): RefreshHeader {
+                layout.setPrimaryColorsId(
+                    com.grkj.ui_base.R.color.common_tip_dialog_info,
+                    R.color.white
+                ) //全局设置主题颜色
+                return ClassicsHeader(context) //.setTimeFormat(new DynamicTimeFormat("更新于 %s"));//指定为经典Header,默认是 贝塞尔雷达Header
+            }
+        })
+
+        //设置全局的Footer构建器
+        SmartRefreshLayout.setDefaultRefreshFooterCreator(object : DefaultRefreshFooterCreator {
+            override fun createRefreshFooter(
+                context: Context,
+                p1: RefreshLayout
+            ): RefreshFooter {
+                //指定为经典Footer,默认是 BallPulseFooter
+                return ClassicsFooter(context).setDrawableSize(20f)
+            }
+
+        })
+    }
 }

+ 56 - 2
app/src/main/java/com/grkj/iscs/features/login/activity/LoginActivity.kt

@@ -1,19 +1,23 @@
 package com.grkj.iscs.features.login.activity
 
 import android.content.Intent
+import android.graphics.Bitmap
+import android.view.InputDevice
+import android.view.KeyEvent
 import android.widget.LinearLayout
 import androidx.core.view.isVisible
 import androidx.lifecycle.ViewModelProvider
 import com.drake.brv.BindingAdapter
 import com.drake.brv.annotaion.DividerOrientation
+import com.drake.brv.annotaion.ItemOrientation
 import com.drake.brv.utils.divider
 import com.drake.brv.utils.grid
 import com.drake.brv.utils.linear
 import com.drake.brv.utils.models
 import com.drake.brv.utils.setup
+import com.grkj.data.data.MainDomainData
 import com.grkj.domain.entity.local.LoginMenuEntity
 import com.grkj.iscs.R
-import com.grkj.data.data.MainDomainData
 import com.grkj.iscs.databinding.ActivityLoginBinding
 import com.grkj.iscs.databinding.ItemLoginMethodBinding
 import com.grkj.iscs.features.login.dialog.LoginDialog
@@ -22,14 +26,19 @@ import com.grkj.iscs.features.main.activity.MainActivity
 import com.grkj.shared.config.Constants
 import com.grkj.ui_base.base.BaseActivity
 import com.grkj.ui_base.utils.CommonUtils
+import com.grkj.ui_base.utils.event.LoadingEvent
 import com.grkj.ui_base.utils.extension.getAppVersionName
+import com.grkj.ui_base.utils.extension.toByteArrays
+import com.grkj.ui_base.utils.extension.toHexStrings
 import com.grkj.ui_base.utils.fingerprint.FingerprintUtil
+import com.kongzue.dialogx.dialogs.PopTip
+import com.sik.sikimage.ImageConvertUtils
 
 /**
  * 登录页
  */
 class LoginActivity : BaseActivity<ActivityLoginBinding>() {
-    private val viewModel: LoginViewModel by lazy { ViewModelProvider(this)[LoginViewModel::class.java] }
+    private val viewModel: LoginViewModel by lazy { ViewModelProvider(this)[LoginViewModel::class] }
 
     //登录方式列表
     private val loginMenuList: MutableList<LoginMenuEntity> = mutableListOf()
@@ -70,8 +79,11 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
         itemBinding.loginMethodIv.setBackgroundResource(item.menuIconId)
         holder.itemView.setOnClickListener {
             LoginDialog.show(this@LoginActivity, viewModel, item.loginType) {
+                LoadingEvent.sendLoadingEvent()
                 if (it) {
                     startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                } else {
+                    PopTip.tip(CommonUtils.getStr(R.string.login_failed))
                 }
             }
         }
@@ -127,6 +139,23 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
     override fun onResume() {
         super.onResume()
         MainDomainData.clear()
+
+        FingerprintUtil.init(this)
+        FingerprintUtil.start()
+        FingerprintUtil.setScanListener(object : FingerprintUtil.OnScanListener {
+            override fun onScan(bitmap: Bitmap) {
+                LoadingEvent.sendLoadingEvent(CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),true)
+                viewModel.loginWithFingerprint(ImageConvertUtils.bitmapToBase64(bitmap).toString())
+                    .observe(this@LoginActivity) { isSuccess ->
+                        LoadingEvent.sendLoadingEvent()
+                        if (isSuccess) {
+                            startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                        } else {
+                            PopTip.tip(CommonUtils.getStr(R.string.login_failed))
+                        }
+                    }
+            }
+        })
     }
 
     override fun onStop() {
@@ -135,4 +164,29 @@ class LoginActivity : BaseActivity<ActivityLoginBinding>() {
         FingerprintUtil.stop()
         FingerprintUtil.unInit()
     }
+
+    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        if (event.action == KeyEvent.ACTION_UP && event.source == InputDevice.SOURCE_KEYBOARD) {
+            // 检测到回车开始处理
+            if (event.keyCode == 66) {
+                logger.info("Swipe card login Origin: $cardNo")
+                cardNo = cardNo.toLong().toByteArrays().toHexStrings(false)
+                logger.info("Swipe card login: $cardNo")
+                LoadingEvent.sendLoadingEvent(CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),true)
+                viewModel.loginWithCard(cardNo).observe(this) { isSuccess ->
+                    LoadingEvent.sendLoadingEvent()
+                    if (isSuccess) {
+                        startActivity(Intent(this@LoginActivity, MainActivity::class.java))
+                    } else {
+                        PopTip.tip(CommonUtils.getStr(R.string.login_failed))
+                    }
+                }
+                // 重置cardNo
+                cardNo = ""
+                return super.dispatchKeyEvent(event)
+            }
+            cardNo += event.keyCharacterMap.getDisplayLabel(event.keyCode)
+        }
+        return super.dispatchKeyEvent(event)
+    }
 }

+ 3 - 0
app/src/main/java/com/grkj/iscs/features/login/dialog/LoginDialog.kt

@@ -47,6 +47,7 @@ class LoginDialog(
 
     override fun onBind(customDialog: CustomDialog, contentView: View) {
         mBinding = DialogLoginBinding.bind(contentView)
+        customDialog.setMaskColor(CommonUtils.getColor(com.grkj.ui_base.R.color.scrim))
         mBinding.tvLogin.setOnClickListener {
             if (mBinding.etAccount.text.toString().isEmpty()) {
                 PopTip.tip(CommonUtils.getStr(com.grkj.ui_base.R.string.please_input_account))
@@ -56,6 +57,7 @@ class LoginDialog(
                 PopTip.tip(CommonUtils.getStr(com.grkj.ui_base.R.string.please_input_password))
                 return@setOnClickListener
             }
+            LoadingEvent.sendLoadingEvent(CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),true)
             viewModel.loginWithAccount(
                 "罗成",
                 "123456"
@@ -110,6 +112,7 @@ class LoginDialog(
                     FingerprintUtil.start()
                     FingerprintUtil.setScanListener(object : FingerprintUtil.OnScanListener {
                         override fun onScan(bitmap: Bitmap) {
+                            LoadingEvent.sendLoadingEvent(CommonUtils.getStr(com.grkj.ui_base.R.string.doing_login),true)
                             viewModel.loginWithFingerprint(
                                 ImageConvertUtils.bitmapToBase64(bitmap).toString()
                             ).observe(lifecycleOwner) {

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

@@ -6,6 +6,7 @@ import androidx.lifecycle.liveData
 import com.grkj.data.repository.UserRepository
 import com.grkj.domain.repository.IUserRepository
 import com.grkj.ui_base.base.BaseViewModel
+import com.grkj.ui_base.utils.event.LoadingEvent
 import kotlinx.coroutines.Dispatchers
 
 /**

+ 5 - 8
app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt

@@ -74,24 +74,21 @@ class MainActivity() : BaseActivity<ActivityMainBinding>() {
         tabConfigs.forEachIndexed { index, cfg ->
             if (userPerms.contains(cfg.permission)) {
                 logger.info("菜单:${index},${cfg}")
-                binding.bottomNav.menu
-                    .add(Menu.NONE, cfg.id, index, cfg.title)
-                    .setIcon(cfg.icon)
+                binding.bottomNav.menu.add(Menu.NONE, cfg.id, index, cfg.title).setIcon(cfg.icon)
             }
         }
 
         // 构造 map: menuItemId -> navGraphId
-        val graphMap = tabConfigs
-            .filter { binding.bottomNav.menu.findItem(it.id) != null }
+        val graphMap = tabConfigs.filter { binding.bottomNav.menu.findItem(it.id) != null }
             .associate { it.id to it.graphRes }
-        logger.info("graphMap: ${graphMap}")
         // 把 BottomNavigationView 和 NavController 绑定
         setupBottomNavigation(binding.bottomNav, graphMap)
-
+        binding.nickname.setOnClickListener {
+            replaceNavGraph(R.navigation.nav_user_info)
+        }
         // 默认选中第一个
         if (binding.bottomNav.menu.isNotEmpty()) {
             val firstId = binding.bottomNav.menu[0].itemId
-            logger.info("菜单id: $firstId")
             binding.bottomNav.selectedItemId = firstId
         }
     }

+ 76 - 0
app/src/main/java/com/grkj/iscs/features/main/dialog/AddUserDialog.kt

@@ -0,0 +1,76 @@
+package com.grkj.iscs.features.main.dialog
+
+import android.content.Context
+import android.view.View
+import com.grkj.domain.entity.vo.AddUserDataVo
+import com.grkj.iscs.R
+import com.grkj.iscs.databinding.DialogAddUserBinding
+import com.grkj.ui_base.utils.extension.tipDialog
+import com.kongzue.dialogx.dialogs.PopTip
+import razerdp.basepopup.BasePopupWindow
+
+/**
+ * 新增用户
+ */
+class AddUserDialog(context: Context) : BasePopupWindow(context) {
+    private lateinit var binding: DialogAddUserBinding
+    private var onConfirm: (AddUserDataVo) -> Unit = {}
+
+    init {
+        setContentView(R.layout.dialog_add_user)
+    }
+
+    override fun onViewCreated(contentView: View) {
+        super.onViewCreated(contentView)
+        binding = DialogAddUserBinding.bind(contentView)
+        binding.cancel.setOnClickListener { dismiss() }
+        binding.closeIv.setOnClickListener { dismiss() }
+        binding.confirm.setOnClickListener {
+            if (checkData()) {
+                val addUserData = AddUserDataVo(
+                    binding.nicknameEt.text.toString(),
+                    binding.cardcodeEt.text.toString(),
+                    binding.roleTv.text.toString(),
+                    binding.areaTv.text.toString(),
+                    binding.statusRg.checkedRadioButtonId == binding.activateRb.id
+                )
+                onConfirm(addUserData)
+                dismiss()
+            }
+        }
+    }
+
+    /**
+     * 检查数据
+     */
+    private fun checkData(): Boolean {
+        if (binding.nicknameEt.text.trim().toString().isEmpty()) {
+            PopTip.build().tipDialog(R.string.please_input_nickname)
+            return false
+        }
+        if (binding.cardcodeEt.text.trim().toString().isEmpty()) {
+            PopTip.build().tipDialog(R.string.please_input_card_code)
+            return false
+        }
+        if (binding.roleTv.text.trim().toString().isEmpty()) {
+            PopTip.build().tipDialog(R.string.please_select_role)
+            return false
+        }
+        if (binding.areaTv.text.trim().toString().isEmpty()) {
+            PopTip.build().tipDialog(R.string.please_select_area)
+            return false
+        }
+        if (binding.statusRg.checkedRadioButtonId == -1) {
+            PopTip.build().tipDialog(R.string.please_select_status)
+            return false
+        }
+        return true
+    }
+
+    /**
+     * 设置确认监听
+     */
+    fun setOnConfirmListener(onConfirm: (AddUserDataVo) -> Unit) {
+        this.onConfirm = onConfirm
+    }
+}

+ 50 - 0
app/src/main/java/com/grkj/iscs/features/main/dialog/FilterUserDialog.kt

@@ -0,0 +1,50 @@
+package com.grkj.iscs.features.main.dialog
+
+import android.content.Context
+import android.view.View
+import com.grkj.domain.entity.vo.UserManageFilterVo
+import com.grkj.iscs.R
+import com.grkj.iscs.databinding.DialogFilterUserBinding
+import razerdp.basepopup.BasePopupWindow
+
+/**
+ * 筛选用户
+ */
+class FilterUserDialog(context: Context) : BasePopupWindow(context) {
+    private var onConfirm: (UserManageFilterVo) -> Unit = {}
+    private lateinit var binding: DialogFilterUserBinding
+
+    init {
+        setContentView(R.layout.dialog_filter_user)
+    }
+
+    override fun onViewCreated(contentView: View) {
+        super.onViewCreated(contentView)
+        binding = DialogFilterUserBinding.bind(contentView)
+        binding.closeIv.setOnClickListener { dismiss() }
+        binding.confirm.setOnClickListener {
+            val filterData = UserManageFilterVo(
+                binding.nicknameEt.text.toString(),
+                binding.cardcodeEt.text.toString(),
+                binding.areaEt.text.toString(),
+                if (binding.statusRg.checkedRadioButtonId == -1) {
+                    null
+                } else {
+                    binding.statusRg.checkedRadioButtonId == binding.activateRb.id
+                }
+            )
+            onConfirm(filterData)
+            dismiss()
+        }
+        binding.cancel.setOnClickListener {
+            dismiss()
+        }
+    }
+
+    /**
+     * 设置确认事件
+     */
+    fun setOnConfirmListener(onConfirm: (UserManageFilterVo) -> Unit) {
+        this.onConfirm = onConfirm
+    }
+}

+ 79 - 0
app/src/main/java/com/grkj/iscs/features/main/dialog/TextDropDownDialog.kt

@@ -0,0 +1,79 @@
+package com.grkj.iscs.features.main.dialog
+
+import android.content.Context
+import android.view.View
+import com.drake.brv.BindingAdapter
+import com.drake.brv.utils.linear
+import com.drake.brv.utils.models
+import com.drake.brv.utils.setup
+import com.grkj.iscs.R
+import com.grkj.iscs.databinding.DialogDropDownListBinding
+import com.grkj.iscs.databinding.ItemHomeTextDropDownBinding
+import me.jessyan.autosize.utils.AutoSizeUtils
+import razerdp.basepopup.BasePopupWindow
+
+/**
+ * 下拉文本选择框
+ */
+class TextDropDownDialog(context: Context) : BasePopupWindow(context) {
+    private lateinit var binding: DialogDropDownListBinding
+    private var textSize = AutoSizeUtils.dp2px(context, 12f)
+    private var onItemSelectedListener: (TextDropDownEntity) -> Unit = {}
+
+    init {
+        setContentView(R.layout.dialog_drop_down_list)
+    }
+
+    override fun onViewCreated(contentView: View) {
+        super.onViewCreated(contentView)
+        setBackgroundView(null)
+        binding = DialogDropDownListBinding.bind(contentView)
+        binding.dropDownRv.linear().setup {
+            addType<TextDropDownEntity>(R.layout.item_home_text_drop_down)
+            onBind {
+                onTextDropDownRVBinding(this)
+            }
+        }
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onTextDropDownRVBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemHomeTextDropDownBinding>()
+        val item = holder.getModel<TextDropDownEntity>()
+        itemBinding.dropDownText.text = item.getShowText()
+        itemBinding.root.setOnClickListener {
+            onItemSelectedListener(item)
+            dismiss()
+        }
+    }
+
+    /**
+     * 设置数据
+     */
+    fun setData(dropDownData: List<TextDropDownEntity> = emptyList<TextDropDownEntity>()) {
+        binding.dropDownRv.models = dropDownData
+    }
+
+    /**
+     * 设置文本大小
+     */
+    fun setTextSize(textSize: Float) {
+        this.textSize = AutoSizeUtils.dp2px(context, textSize)
+    }
+
+    /**
+     * 选择监听
+     */
+    fun setOnItemSelectListener(onItemSelected: (TextDropDownEntity) -> Unit) {
+        this.onItemSelectedListener = onItemSelected
+    }
+
+    /**
+     * 文本下拉弹窗数据实体接口
+     */
+    interface TextDropDownEntity {
+        /**
+         * 获取展示文本
+         */
+        fun getShowText(): String
+    }
+}

+ 12 - 0
app/src/main/java/com/grkj/iscs/features/main/entity/MenuItemEntity.kt

@@ -0,0 +1,12 @@
+package com.grkj.iscs.features.main.entity
+
+/**
+ * 菜单实体
+ * type 菜单类型 0-用户管理 1-角色管理 2-区域管理 3-点位管理
+ */
+data class MenuItemEntity(
+    val type: Int,
+    val menuIconId: Int,
+    val menuText: String,
+    val permission: String
+)

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

@@ -0,0 +1,7 @@
+package com.grkj.iscs.features.main.fragment.data_manage
+
+/**
+ * 区域管理
+ */
+class AreaManageFragment {
+}

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

@@ -1,18 +1,106 @@
 package com.grkj.iscs.features.main.fragment.data_manage
 
+import androidx.annotation.OptIn
+import com.drake.brv.BindingAdapter
+import com.drake.brv.annotaion.DividerOrientation
+import com.drake.brv.utils.dividerSpace
+import com.drake.brv.utils.grid
+import com.drake.brv.utils.linear
+import com.drake.brv.utils.models
+import com.drake.brv.utils.setup
+import com.google.android.material.badge.BadgeDrawable
+import com.google.android.material.badge.BadgeUtils
+import com.google.android.material.badge.ExperimentalBadgeUtils
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentDataManageHomeBinding
+import com.grkj.iscs.databinding.ItemHomeMenuBinding
+import com.grkj.iscs.features.main.entity.MenuItemEntity
 import com.grkj.ui_base.base.BaseFragment
 
 /**
  * 数据管理首页
  */
-class DataManageHomeFragment: BaseFragment<FragmentDataManageHomeBinding>() {
+class DataManageHomeFragment : BaseFragment<FragmentDataManageHomeBinding>() {
+    private val menuData: MutableList<MenuItemEntity> = mutableListOf(
+        MenuItemEntity(
+            0,
+            R.mipmap.icon_data_manage_menu_user_manage,
+            "用户管理",
+            "data_manage:user_manage"
+        ),
+        MenuItemEntity(
+            1,
+            R.mipmap.icon_data_manage_menu_role_manage,
+            "角色管理",
+            "data_manage:role_manage"
+        ),
+        MenuItemEntity(
+            2,
+            R.mipmap.icon_data_manage_menu_area_manage,
+            "区域管理",
+            "data_manage:area_manage"
+        ),
+        MenuItemEntity(
+            3,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "点位管理",
+            "data_manage:point_manage"
+        ),
+    )
+
     override fun getLayoutId(): Int {
         return R.layout.fragment_data_manage_home
     }
 
     override fun initView() {
+        binding.homeMenuRv.apply {
+            if (isLandscape()) {
+                linear()
+            } else {
+                grid(3)
+            }
+            dividerSpace(40, DividerOrientation.GRID)
+        }.setup {
+            addType<MenuItemEntity>(R.layout.item_home_menu)
+            onBind {
+                onHomeMenuBinding(this)
+            }
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        binding.homeMenuRv.models = menuData
+    }
+
+    @OptIn(ExperimentalBadgeUtils::class)
+    private fun BindingAdapter.BindingViewHolder.onHomeMenuBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemHomeMenuBinding>()
+        val item = holder.getModel<MenuItemEntity>()
+        itemBinding.homeMenuIv.setImageResource(item.menuIconId)
+        itemBinding.homeMenuTv.text = item.menuText
+        itemBinding.root.setOnClickListener {
+            onMenuClick(item.type)
+        }
+    }
+
+    private fun onMenuClick(menuType: Int) {
+        when (menuType) {
+            0 -> {
+                navController.navigate(R.id.action_dataManageHomeFragment_to_userManageFragment)
+            }
+
+            1 -> {
+
+            }
+
+            2 -> {
+
+            }
+
+            3 -> {
 
+            }
+        }
     }
 }

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

@@ -0,0 +1,7 @@
+package com.grkj.iscs.features.main.fragment.data_manage
+
+/**
+ * 点位管理
+ */
+class PointMangeFragment {
+}

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

@@ -0,0 +1,7 @@
+package com.grkj.iscs.features.main.fragment.data_manage
+
+/**
+ * 角色管理
+ */
+class RoleManageFragment {
+}

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

@@ -0,0 +1,164 @@
+package com.grkj.iscs.features.main.fragment.data_manage
+
+import android.graphics.Color
+import android.view.Gravity
+import androidx.lifecycle.ViewModelProvider
+import com.drake.brv.BindingAdapter
+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
+import com.grkj.domain.entity.vo.UserManageFilterVo
+import com.grkj.data.model.vo.UserManageVo
+import com.grkj.iscs.R
+import com.grkj.iscs.databinding.FragmentUserManageBinding
+import com.grkj.iscs.databinding.ItemUserManageUserBinding
+import com.grkj.iscs.features.main.dialog.AddUserDialog
+import com.grkj.iscs.features.main.dialog.FilterUserDialog
+import com.grkj.iscs.features.main.viewmodel.user_manage.UserManageViewModel
+import com.grkj.ui_base.base.BaseFragment
+import com.grkj.ui_base.dialog.TipDialog
+import com.grkj.ui_base.utils.CommonUtils
+import com.kongzue.dialogx.dialogs.PopTip
+import com.sik.sikcore.extension.setDebouncedClickListener
+
+/**
+ * 用户管理
+ */
+class UserManageFragment : BaseFragment<FragmentUserManageBinding>() {
+    private val viewModel: UserManageViewModel by lazy { ViewModelProvider(this)[UserManageViewModel::class] }
+    private lateinit var addUserDialog: AddUserDialog
+    private lateinit var filterUserDialog: FilterUserDialog
+    override fun getLayoutId(): Int {
+        return R.layout.fragment_user_manage
+    }
+
+    override fun initView() {
+        addUserDialog = AddUserDialog(requireContext())
+        addUserDialog.popupGravity = Gravity.CENTER
+        filterUserDialog = FilterUserDialog(requireContext())
+        filterUserDialog.popupGravity = Gravity.CENTER
+        filterUserDialog.setOnConfirmListener {
+            getUserData(it)
+        }
+        addUserDialog.setOnConfirmListener {
+            viewModel.addUser(it).observe(this) {
+                if (it) {
+                    TipDialog.show(
+                        title = CommonUtils.getStr(com.grkj.ui_base.R.string.action_succeed)
+                            .toString(),
+                        dialogType = TipDialog.DialogType.SUCCESS,
+                        msg = CommonUtils.getStr(R.string.add_user_succeed).toString(),
+                        countDownTime = 10,
+                        showConfirm = false
+                    )
+                } else {
+                    TipDialog.show(
+                        title = CommonUtils.getStr(com.grkj.ui_base.R.string.action_failed)
+                            .toString(),
+                        dialogType = TipDialog.DialogType.ERROR,
+                        msg = CommonUtils.getStr(R.string.add_user_failed).toString(),
+                        countDownTime = 10,
+                        showConfirm = false
+                    )
+                }
+            }
+        }
+        binding.deleteUser.setDebouncedClickListener {
+            deleteSelectUser()
+        }
+        binding.addUser.setDebouncedClickListener {
+            addUserDialog.showPopupWindow()
+        }
+        binding.filterUser.setDebouncedClickListener {
+            filterUserDialog.showPopupWindow()
+        }
+        binding.refreshLayout.setOnRefreshListener {
+            getUserData(nextPage = false)
+        }
+        binding.refreshLayout.setOnLoadMoreListener {
+            getUserData()
+        }
+        binding.userListRv.linear().divider {
+                this.setColor(Color.BLACK)
+                this.startVisible = false
+                this.endVisible = false
+                this.orientation = DividerOrientation.VERTICAL
+            }.setup {
+                addType<UserManageVo>(R.layout.item_user_manage_user)
+                onBind {
+                    onUserDataBinding(this)
+                }
+            }
+        setSelectAllListener()
+    }
+
+    private fun setSelectAllListener() {
+        binding.selectAll.setOnCheckedChangeListener { v, checked ->
+            viewModel.userManageDataList.forEach { it.isSelected = checked }
+            binding.userListRv.adapter?.notifyDataSetChanged()
+        }
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onUserDataBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemUserManageUserBinding>()
+        val item = holder.getModel<UserManageVo>()
+        itemBinding.nickname.text = item.nickName
+        itemBinding.cardCode.text = item.cardCode
+        itemBinding.select.setOnCheckedChangeListener(null)
+        itemBinding.select.isChecked = item.isSelected
+        itemBinding.select.setOnCheckedChangeListener { _, checked ->
+            item.isSelected = checked
+            binding.selectAll.setOnCheckedChangeListener(null)
+            binding.selectAll.isChecked = viewModel.userManageDataList.all { it.isSelected }
+            setSelectAllListener()
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        getUserData(nextPage = false)
+    }
+
+    private fun getUserData(
+        filterData: UserManageFilterVo? = null, nextPage: Boolean = true
+    ) {
+        viewModel.getUserData(filterData, nextPage).observe(this) {
+            binding.refreshLayout.finishRefresh()
+            binding.refreshLayout.finishLoadMore()
+            binding.userListRv.models = viewModel.userManageDataList
+        }
+    }
+
+    private fun deleteSelectUser() {
+        if (viewModel.userManageDataList.none { it.isSelected }) {
+            PopTip.tip(R.string.please_select_user)
+            return
+        }
+        TipDialog.show(
+            msg = CommonUtils.getStr(R.string.check_delete_user).toString(),
+            countDownTime = 10,
+            onConfirmClick = {
+                viewModel.deleteSelectedUsers().observe(this) {
+                        if (it) {
+                            TipDialog.show(
+                                dialogType = TipDialog.DialogType.SUCCESS,
+                                msg = CommonUtils.getStr(R.string.user_manage_delete_succeed)
+                                    .toString(),
+                                showConfirm = false,
+                                countDownTime = 10
+                            )
+                        } else {
+                            TipDialog.show(
+                                dialogType = TipDialog.DialogType.ERROR,
+                                msg = CommonUtils.getStr(R.string.user_manage_delete_failed)
+                                    .toString(),
+                                showConfirm = false,
+                                countDownTime = 10
+                            )
+                        }
+                    }
+            })
+    }
+}

+ 72 - 0
app/src/main/java/com/grkj/iscs/features/main/fragment/exception_manage/ExceptionManageHomeFragment.kt

@@ -1,18 +1,90 @@
 package com.grkj.iscs.features.main.fragment.exception_manage
 
+import com.drake.brv.BindingAdapter
+import com.drake.brv.annotaion.DividerOrientation
+import com.drake.brv.utils.dividerSpace
+import com.drake.brv.utils.grid
+import com.drake.brv.utils.linear
+import com.drake.brv.utils.models
+import com.drake.brv.utils.setup
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentExceptionManageHomeBinding
+import com.grkj.iscs.databinding.ItemHomeMenuBinding
+import com.grkj.iscs.features.main.entity.MenuItemEntity
 import com.grkj.ui_base.base.BaseFragment
 
 /**
  * 异常管理首页
  */
 class ExceptionManageHomeFragment : BaseFragment<FragmentExceptionManageHomeBinding>() {
+    private val menuData: MutableList<MenuItemEntity> = mutableListOf(
+        MenuItemEntity(
+            0,
+            R.mipmap.icon_data_manage_menu_user_manage,
+            "异常上报",
+            "exception_manage:exception_report"
+        ),
+        MenuItemEntity(
+            1,
+            R.mipmap.icon_data_manage_menu_role_manage,
+            "异常管理",
+            "exception_manage:exception_manage"
+        ),
+        MenuItemEntity(
+            2,
+            R.mipmap.icon_data_manage_menu_area_manage,
+            "异常作业",
+            "exception_manage:exception_job"
+        ),
+    )
     override fun getLayoutId(): Int {
         return R.layout.fragment_exception_manage_home
     }
 
     override fun initView() {
+        binding.homeMenuRv.apply {
+            if (isLandscape()) {
+                linear()
+            } else {
+                grid(3)
+            }
+            dividerSpace(40, DividerOrientation.GRID)
+        }.setup {
+            addType<MenuItemEntity>(R.layout.item_home_menu)
+            onBind {
+                onHomeMenuBinding(this)
+            }
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        binding.homeMenuRv.models = menuData
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onHomeMenuBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemHomeMenuBinding>()
+        val item = holder.getModel<MenuItemEntity>()
+        itemBinding.homeMenuIv.setImageResource(item.menuIconId)
+        itemBinding.homeMenuTv.text = item.menuText
+        itemBinding.root.setOnClickListener {
+            onMenuClick(item.type)
+        }
+    }
+
+    private fun onMenuClick(menuType: Int) {
+        when (menuType) {
+            0 -> {
+
+            }
+
+            1 -> {
+
+            }
+
+            2 -> {
 
+            }
+        }
     }
 }

+ 89 - 0
app/src/main/java/com/grkj/iscs/features/main/fragment/hardware_manage/HardwareManageHomeFragment.kt

@@ -1,18 +1,107 @@
 package com.grkj.iscs.features.main.fragment.hardware_manage
 
+import com.drake.brv.BindingAdapter
+import com.drake.brv.annotaion.DividerOrientation
+import com.drake.brv.utils.dividerSpace
+import com.drake.brv.utils.grid
+import com.drake.brv.utils.linear
+import com.drake.brv.utils.models
+import com.drake.brv.utils.setup
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentHardwareManageHomeBinding
+import com.grkj.iscs.databinding.ItemHomeMenuBinding
+import com.grkj.iscs.features.main.entity.MenuItemEntity
 import com.grkj.ui_base.base.BaseFragment
 
 /**
  * 硬件管理首页
  */
 class HardwareManageHomeFragment : BaseFragment<FragmentHardwareManageHomeBinding>() {
+    private val menuData: MutableList<MenuItemEntity> = mutableListOf(
+        MenuItemEntity(
+            0,
+            R.mipmap.icon_data_manage_menu_user_manage,
+            "仓位管理",
+            "hardware_manage:slot_manage"
+        ),
+        MenuItemEntity(
+            1,
+            R.mipmap.icon_data_manage_menu_role_manage,
+            "钥匙管理",
+            "hardware_manage:key_manage"
+        ),
+        MenuItemEntity(
+            2,
+            R.mipmap.icon_data_manage_menu_area_manage,
+            "挂锁管理",
+            "hardware_manage:lock_manage"
+        ),
+        MenuItemEntity(
+            3,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "卡片管理",
+            "hardware_manage:card_manage"
+        ),
+        MenuItemEntity(
+            4,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "RFID管理",
+            "hardware_manage:rfid_manage"
+        ),
+    )
+
     override fun getLayoutId(): Int {
         return R.layout.fragment_hardware_manage_home
     }
 
     override fun initView() {
+        binding.homeMenuRv.apply {
+            if (isLandscape()) {
+                linear()
+            } else {
+                grid(3)
+            }
+            dividerSpace(40, DividerOrientation.GRID)
+        }.setup {
+            addType<MenuItemEntity>(R.layout.item_home_menu)
+            onBind {
+                onHomeMenuBinding(this)
+            }
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        binding.homeMenuRv.models = menuData
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onHomeMenuBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemHomeMenuBinding>()
+        val item = holder.getModel<MenuItemEntity>()
+        itemBinding.homeMenuIv.setImageResource(item.menuIconId)
+        itemBinding.homeMenuTv.text = item.menuText
+        itemBinding.root.setOnClickListener {
+            onMenuClick(item.type)
+        }
+    }
+
+    private fun onMenuClick(menuType: Int) {
+        when (menuType) {
+            0 -> {
+
+            }
+
+            1 -> {
+
+            }
+
+            2 -> {
+
+            }
+
+            3 -> {
 
+            }
+        }
     }
 }

+ 51 - 1
app/src/main/java/com/grkj/iscs/features/main/fragment/home/HomeFragment.kt

@@ -1,18 +1,68 @@
 package com.grkj.iscs.features.main.fragment.home
 
+import android.widget.LinearLayout
+import androidx.lifecycle.ViewModelProvider
+import com.drake.brv.BindingAdapter
+import com.drake.brv.annotaion.ItemOrientation
+import com.drake.brv.utils.linear
+import com.drake.brv.utils.models
+import com.drake.brv.utils.setup
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentHomeBinding
+import com.grkj.iscs.databinding.ItemHomeMenuBinding
+import com.grkj.iscs.databinding.ItemHomeQuickEntranceBinding
+import com.grkj.iscs.features.main.entity.MenuItemEntity
 import com.grkj.ui_base.base.BaseFragment
 
 /**
  * 首页
  */
-class HomeFragment: BaseFragment<FragmentHomeBinding>(){
+class HomeFragment : BaseFragment<FragmentHomeBinding>() {
+    private val viewModel: HomeViewModel by lazy { ViewModelProvider(this)[HomeViewModel::class] }
+    private val quickEntranceList = mutableListOf<MenuItemEntity>(
+        MenuItemEntity(
+            0,
+            R.mipmap.icon_data_manage_menu_user_manage,
+            "新建作业",
+            "quick_entrance:create_job"
+        )
+    )
+
     override fun getLayoutId(): Int {
         return R.layout.fragment_home
     }
 
     override fun initView() {
+        binding.quickEntranceRv.apply {
+            linear(orientation = LinearLayout.HORIZONTAL)
+        }.setup {
+            addType<MenuItemEntity>(R.layout.item_home_quick_entrance)
+            onBind {
+                onQuickEntranceBinding(this)
+            }
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        binding.quickEntranceRv.models = quickEntranceList
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onQuickEntranceBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemHomeQuickEntranceBinding>()
+        val item = holder.getModel<MenuItemEntity>()
+        itemBinding.homeMenuIv.setImageResource(item.menuIconId)
+        itemBinding.homeMenuTv.text = item.menuText
+        itemBinding.root.setOnClickListener {
+            onMenuClick(item.type)
+        }
+    }
+
+    private fun onMenuClick(menuType: Int) {
+        when (menuType) {
+            0 -> {
 
+            }
+        }
     }
 }

+ 9 - 0
app/src/main/java/com/grkj/iscs/features/main/fragment/home/HomeViewModel.kt

@@ -0,0 +1,9 @@
+package com.grkj.iscs.features.main.fragment.home
+
+import com.grkj.ui_base.base.BaseViewModel
+
+/**
+ * 主界面界面模型
+ */
+class HomeViewModel : BaseViewModel() {
+}

+ 95 - 0
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobManageHomeFragment.kt

@@ -1,18 +1,113 @@
 package com.grkj.iscs.features.main.fragment.job_manage
 
+import com.drake.brv.BindingAdapter
+import com.drake.brv.annotaion.DividerOrientation
+import com.drake.brv.utils.dividerSpace
+import com.drake.brv.utils.grid
+import com.drake.brv.utils.linear
+import com.drake.brv.utils.models
+import com.drake.brv.utils.setup
 import com.grkj.iscs.R
 import com.grkj.iscs.databinding.FragmentJobManageHomeBinding
+import com.grkj.iscs.databinding.ItemHomeMenuBinding
+import com.grkj.iscs.features.main.entity.MenuItemEntity
 import com.grkj.ui_base.base.BaseFragment
 
 /**
  * 作业管理首页
  */
 class JobManageHomeFragment : BaseFragment<FragmentJobManageHomeBinding>() {
+    private val menuData: MutableList<MenuItemEntity> = mutableListOf(
+        MenuItemEntity(
+            0,
+            R.mipmap.icon_data_manage_menu_user_manage,
+            "进行中的作业",
+            "job_manage:ongoing_job"
+        ),
+        MenuItemEntity(
+            1,
+            R.mipmap.icon_data_manage_menu_role_manage,
+            "新建SOP",
+            "job_manage:create_sop"
+        ),
+        MenuItemEntity(
+            2,
+            R.mipmap.icon_data_manage_menu_area_manage,
+            "SOP管理",
+            "job_manage:sop_manage"
+        ),
+        MenuItemEntity(
+            3,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "异常作业",
+            "job_manage:exception_job"
+        ),
+        MenuItemEntity(
+            4,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "新建作业",
+            "job_manage:create_job"
+        ),
+        MenuItemEntity(
+            5,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "作业管理",
+            "job_manage:job_manage"
+        ),
+    )
+
     override fun getLayoutId(): Int {
         return R.layout.fragment_job_manage_home
     }
 
     override fun initView() {
+        binding.homeMenuRv.apply {
+            if (isLandscape()) {
+                linear()
+            } else {
+                grid(3)
+            }
+            dividerSpace(40, DividerOrientation.GRID)
+        }.setup {
+            addType<MenuItemEntity>(R.layout.item_home_menu)
+            onBind {
+                onHomeMenuBinding(this)
+            }
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        binding.homeMenuRv.models = menuData
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onHomeMenuBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemHomeMenuBinding>()
+        val item = holder.getModel<MenuItemEntity>()
+        itemBinding.homeMenuIv.setImageResource(item.menuIconId)
+        itemBinding.homeMenuTv.text = item.menuText
+        itemBinding.root.setOnClickListener {
+            onMenuClick(item.type)
+        }
+    }
+
+    private fun onMenuClick(menuType: Int) {
+        when (menuType) {
+            0 -> {
+
+            }
+
+            1 -> {
+
+            }
+
+            2 -> {
+
+            }
+
+            3 -> {
 
+            }
+        }
     }
 }

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

@@ -0,0 +1,145 @@
+package com.grkj.iscs.features.main.fragment.user_info
+
+import android.content.Intent
+import com.drake.brv.BindingAdapter
+import com.drake.brv.annotaion.DividerOrientation
+import com.drake.brv.utils.dividerSpace
+import com.drake.brv.utils.grid
+import com.drake.brv.utils.linear
+import com.drake.brv.utils.models
+import com.drake.brv.utils.setup
+import com.grkj.data.data.MainDomainData
+import com.grkj.iscs.R
+import com.grkj.iscs.databinding.FragmentUserInfoHomeBinding
+import com.grkj.iscs.databinding.ItemHomeMenuBinding
+import com.grkj.iscs.features.login.activity.LoginActivity
+import com.grkj.iscs.features.main.entity.MenuItemEntity
+import com.grkj.ui_base.base.BaseFragment
+import com.sik.sikcore.activity.ActivityTracker
+
+/**
+ * 用户信息菜单
+ */
+class UserInfoHomeFragment : BaseFragment<FragmentUserInfoHomeBinding>() {
+    private val menuData: MutableList<MenuItemEntity> = mutableListOf(
+        MenuItemEntity(
+            0,
+            R.mipmap.icon_data_manage_menu_user_manage,
+            "个人信息",
+            "user_info:user_info"
+        ),
+        MenuItemEntity(
+            1,
+            R.mipmap.icon_data_manage_menu_role_manage,
+            "重置密码",
+            "user_info:reset_password"
+        ),
+        MenuItemEntity(
+            2,
+            R.mipmap.icon_data_manage_menu_area_manage,
+            "设置指纹",
+            "user_info:fingerprint_setting"
+        ),
+        MenuItemEntity(
+            3,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "设置人脸",
+            "user_info:face_setting"
+        ),
+        MenuItemEntity(
+            4,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "设置工卡",
+            "user_info:card_setting"
+        ),
+        MenuItemEntity(
+            5,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "更多设置",
+            "user_info:more_setting"
+        ),
+        MenuItemEntity(
+            6,
+            R.mipmap.icon_data_manage_menu_point_manage,
+            "退出登录",
+            "user_info:logout"
+        ),
+    )
+
+    override fun getLayoutId(): Int {
+        return R.layout.fragment_user_info_home
+    }
+
+    override fun initView() {
+        binding.homeMenuRv.apply {
+            if (isLandscape()) {
+                linear()
+            } else {
+                grid(3)
+            }
+            dividerSpace(40, DividerOrientation.GRID)
+        }.setup {
+            addType<MenuItemEntity>(R.layout.item_home_menu)
+            onBind {
+                onHomeMenuBinding(this)
+            }
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        binding.homeMenuRv.models = menuData
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onHomeMenuBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemHomeMenuBinding>()
+        val item = holder.getModel<MenuItemEntity>()
+        itemBinding.homeMenuIv.setImageResource(item.menuIconId)
+        itemBinding.homeMenuTv.text = item.menuText
+        itemBinding.root.setOnClickListener {
+            onMenuClick(item.type)
+        }
+    }
+
+    private fun onMenuClick(menuType: Int) {
+        when (menuType) {
+            0 -> {
+
+            }
+
+            1 -> {
+
+            }
+
+            2 -> {
+
+            }
+
+            3 -> {
+
+            }
+
+            4 -> {
+
+            }
+
+            5 -> {
+
+            }
+
+            6 -> {
+                logout()
+            }
+        }
+    }
+
+    /**
+     * 退出登录
+     */
+    private fun logout() {
+        startActivity(Intent(requireActivity(), LoginActivity::class.java).apply {
+            flags = Intent.FLAG_ACTIVITY_NEW_TASK
+        })
+        requireActivity().finish()
+    }
+}

+ 60 - 0
app/src/main/java/com/grkj/iscs/features/main/viewmodel/user_manage/UserManageViewModel.kt

@@ -0,0 +1,60 @@
+package com.grkj.iscs.features.main.viewmodel.user_manage
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.liveData
+import com.grkj.domain.entity.vo.UserManageFilterVo
+import com.grkj.domain.entity.vo.AddUserDataVo
+import com.grkj.data.model.vo.UserManageVo
+import com.grkj.data.repository.UserRepository
+import com.grkj.domain.repository.IUserRepository
+import com.grkj.ui_base.base.BaseViewModel
+import kotlinx.coroutines.Dispatchers
+
+/**
+ * 用户管理界面模型
+ */
+class UserManageViewModel : BaseViewModel() {
+    private val userRepository: IUserRepository by lazy { UserRepository() }
+    private var current: Int = 0
+    private var size: Int = 50
+    var userManageDataList: MutableList<UserManageVo> = mutableListOf()
+
+    /**
+     * 删除选中用户
+     */
+    fun deleteSelectedUsers(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            emit(true)
+        }
+    }
+
+    /**
+     * 获取用户数据
+     */
+    fun getUserData(
+        filterData: UserManageFilterVo? = null,
+        nextPage: Boolean = true
+    ): LiveData<Boolean> {
+        if (nextPage) {
+            current += 1
+        } else {
+            current = 0
+            userManageDataList.clear()
+        }
+        return liveData(Dispatchers.IO) {
+            val userManageDataPage = userRepository.getUserManagerData(filterData, current, size)
+                .map { it as UserManageVo }
+            userManageDataList.addAll(userManageDataPage)
+            emit(true)
+        }
+    }
+
+    /**
+     * 添加用户
+     */
+    fun addUser(userData: AddUserDataVo): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            emit(true)
+        }
+    }
+}

+ 6 - 0
app/src/main/res/drawable/bg_common_input.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <stroke
+        android:width="1dp"
+        android:color="@color/black" />
+</shape>

+ 6 - 0
app/src/main/res/drawable/bg_common_input_land.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <stroke
+        android:width="0.5dp"
+        android:color="@color/black" />
+</shape>

+ 6 - 0
app/src/main/res/drawable/bg_home_card_num.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners android:radius="10dp" />
+    <solid android:color="@color/white30" />
+</shape>

+ 6 - 0
app/src/main/res/drawable/bg_home_card_num_land.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <corners android:radius="5dp" />
+    <solid android:color="@color/white30" />
+</shape>

+ 5 - 0
app/src/main/res/drawable/bg_home_menu_item.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/white30" />
+    <corners android:radius="20dp" />
+</shape>

+ 5 - 0
app/src/main/res/drawable/bg_home_menu_item_land.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <solid android:color="@color/white30" />
+    <corners android:radius="10dp" />
+</shape>

+ 8 - 0
app/src/main/res/drawable/divider_table.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/black" />
+    <size
+        android:width="1dp"
+        android:height="1dp" />
+</shape>

+ 8 - 0
app/src/main/res/drawable/home_card_bg.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <stroke
+        android:width="1dp"
+        android:color="@color/black" />
+    <solid android:color="@color/white80" />
+</shape>

+ 5 - 0
app/src/main/res/drawable/icon_close.xml

@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
+      
+    <path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
+    
+</vector>

+ 5 - 0
app/src/main/res/drawable/icon_drop_down.xml

@@ -0,0 +1,5 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:autoMirrored="true" android:height="24dp" android:tint="#000000" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
+      
+    <path android:fillColor="@android:color/white" android:pathData="M7,10l5,5 5,-5z"/>
+    
+</vector>

+ 443 - 0
app/src/main/res/layout-land/fragment_home.xml

@@ -0,0 +1,443 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <com.grkj.ui_base.widget.ShadowTextView
+            android:id="@+id/title_cn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="20dp"
+            android:text="@string/loto"
+            android:textColor="@color/white"
+            android:textSize="20sp"
+            android:textStyle="bold" />
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="90dp"
+            android:layout_marginHorizontal="10dp"
+            android:layout_marginTop="20dp"
+            android:background="@drawable/home_card_bg">
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/quick_entrance_rv"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_vertical"
+                android:layout_margin="10dp"
+                tools:listitem="@layout/item_home_quick_entrance" />
+        </FrameLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginHorizontal="10dp"
+            android:layout_marginVertical="20dp"
+            android:divider="@drawable/common_divider_large_space_grid_land"
+            android:orientation="vertical"
+            android:showDividers="middle">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:background="@drawable/home_card_bg"
+                android:orientation="vertical">
+
+                <TextView
+                    android:id="@+id/realtime_data_title"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:background="@color/home_card_title_bg"
+                    android:paddingVertical="5dp"
+                    android:paddingLeft="5dp"
+                    android:text="@string/home_realtime_data_title"
+                    android:textColor="@color/white"
+                    android:textSize="12sp" />
+
+                <LinearLayout
+                    android:id="@+id/realtime_data_filter_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    android:padding="5dp">
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/zone"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/real_time_data_zone"
+                            android:layout_width="180dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="5dp"
+                            android:background="@drawable/bg_common_input"
+                            android:drawableRight="@drawable/icon_drop_down"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="5dp"
+                            android:paddingVertical="1dp"
+                            android:textSize="11sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="10dp"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/lock_mode"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/lock_mode"
+                            android:layout_width="180dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="10dp"
+                            android:background="@drawable/bg_common_input"
+                            android:drawableRight="@drawable/icon_drop_down"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="5dp"
+                            android:paddingVertical="1dp"
+                            android:textSize="11sp" />
+                    </LinearLayout>
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="40dp"
+                    android:layout_marginBottom="5dp"
+                    android:divider="@drawable/common_divider_normal_space_horizontal_land"
+                    android:orientation="horizontal"
+                    android:layout_marginTop="10dp"
+                    android:paddingHorizontal="5dp"
+                    android:showDividers="middle">
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal_land"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/ongoing_job_tv"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/ongoing_job_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_ffec99"
+                            android:gravity="center"
+                            android:padding="10dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="15sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal_land"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/locked_points_tv"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/locked_points_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_ffc9c9"
+                            android:gravity="center"
+                            android:padding="10dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="15sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal_land"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/hardware_in_use_tv"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/hardware_in_use_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_a5d8ff"
+                            android:gravity="center"
+                            android:padding="10dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="15sp" />
+                    </LinearLayout>
+                </LinearLayout>
+
+            </LinearLayout>
+
+            <RelativeLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:background="@drawable/home_card_bg">
+
+                <TextView
+                    android:id="@+id/overview_data_title"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:background="@color/home_card_title_bg"
+                    android:paddingVertical="2.5dp"
+                    android:paddingLeft="5dp"
+                    android:text="@string/home_overview_data_title"
+                    android:textColor="@color/white"
+                    android:textSize="12sp" />
+
+                <LinearLayout
+                    android:id="@+id/overview_data_filter_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@+id/overview_data_title"
+                    android:gravity="center_vertical"
+                    android:orientation="vertical"
+                    android:padding="5dp">
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/time_frame_tv"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/start_time"
+                            android:layout_width="210dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="5dp"
+                            android:background="@drawable/bg_common_input"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="10dp"
+                            android:paddingVertical="5dp"
+                            android:textSize="11sp"
+                            tools:text="2025-04-01 12:00" />
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="2.5dp"
+                            android:gravity="center_vertical"
+                            android:text="-"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/end_time"
+                            android:layout_width="210dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="5dp"
+                            android:background="@drawable/bg_common_input"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="5dp"
+                            android:paddingVertical="2.5dp"
+                            android:textSize="11sp"
+                            tools:text="2025-04-01 12:00" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="5dp"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/zone"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/overview_data_zone"
+                            android:layout_width="210dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="5dp"
+                            android:background="@drawable/bg_common_input"
+                            android:drawableRight="@drawable/icon_drop_down"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="10dp"
+                            android:paddingVertical="2dp"
+                            android:textSize="11sp" />
+                    </LinearLayout>
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="40dp"
+                    android:layout_below="@+id/overview_data_filter_layout"
+                    android:layout_marginBottom="5dp"
+                    android:layout_marginTop="10dp"
+                    android:divider="@drawable/common_divider_normal_space_horizontal"
+                    android:orientation="horizontal"
+                    android:paddingHorizontal="5dp"
+                    android:showDividers="middle">
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/all_job_tv"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/all_job_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_ffec99"
+                            android:gravity="center"
+                            android:padding="5dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="15sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/all_points_tv"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/all_points_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_ffc9c9"
+                            android:gravity="center"
+                            android:padding="5dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="15sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/all_hardware_tv"
+                            android:textColor="@color/black"
+                            android:textSize="11sp" />
+
+                        <TextView
+                            android:id="@+id/all_hardware_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_a5d8ff"
+                            android:gravity="center"
+                            android:padding="5dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="15sp" />
+                    </LinearLayout>
+                </LinearLayout>
+            </RelativeLayout>
+        </LinearLayout>
+    </LinearLayout>
+</layout>

+ 32 - 0
app/src/main/res/layout-land/item_home_quick_entrance.xml

@@ -0,0 +1,32 @@
+<?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="70dp"
+        android:layout_height="70dp"
+        android:gravity="center_horizontal"
+        android:orientation="vertical">
+
+        <FrameLayout
+            android:layout_width="50dp"
+            android:layout_height="50dp"
+            android:background="@drawable/bg_home_menu_item">
+
+            <ImageView
+                android:id="@+id/home_menu_iv"
+                android:layout_width="40dp"
+                android:layout_height="40dp"
+                android:layout_gravity="center"
+                app:tint="@color/black" />
+        </FrameLayout>
+
+        <TextView
+            android:id="@+id/home_menu_tv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="2.5dp"
+            android:textColor="@color/black"
+            android:textSize="12sp" />
+    </LinearLayout>
+</layout>

+ 232 - 0
app/src/main/res/layout/dialog_add_user.xml

@@ -0,0 +1,232 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="400dp"
+        android:layout_height="600dp"
+        android:background="@drawable/common_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="10dp"
+            android:paddingVertical="5dp">
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/user_manage_new_user_title"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+
+            <ImageView
+                android:id="@+id/close_iv"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingHorizontal="10dp"
+                android:src="@drawable/icon_close" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="@color/black" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="16dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/user_manage_nickname"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+
+                <EditText
+                    android:id="@+id/nickname_et"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dp"
+                    android:background="@drawable/bg_common_input"
+                    android:hint="@string/please_input_nickname"
+                    android:maxLines="1"
+                    android:paddingHorizontal="10dp"
+                    android:paddingVertical="2dp"
+                    android:singleLine="true"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="16dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/user_manage_card_code"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+
+                <EditText
+                    android:id="@+id/cardcode_et"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dp"
+                    android:background="@drawable/bg_common_input"
+                    android:hint="@string/please_input_card_code"
+                    android:maxLines="1"
+                    android:paddingHorizontal="10dp"
+                    android:paddingVertical="2dp"
+                    android:singleLine="true"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="16dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/user_manage_role"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+
+                <TextView
+                    android:id="@+id/role_tv"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dp"
+                    android:background="@drawable/bg_common_input"
+                    android:drawableRight="@drawable/icon_drop_down"
+                    android:hint="@string/please_select_role"
+                    android:paddingHorizontal="10dp"
+                    android:paddingVertical="2dp"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="16dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/user_manage_area"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+
+                <TextView
+                    android:id="@+id/area_tv"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dp"
+                    android:background="@drawable/bg_common_input"
+                    android:drawableRight="@drawable/icon_drop_down"
+                    android:hint="@string/please_select_area"
+                    android:paddingHorizontal="10dp"
+                    android:paddingVertical="2dp"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="16dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/user_manage_filter_status"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+
+                <RadioGroup
+                    android:id="@+id/status_rg"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <RadioButton
+                        android:id="@+id/activate_rb"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="10dp"
+                        android:text="@string/user_manage_filter_activate" />
+
+                    <RadioButton
+                        android:id="@+id/deactivate_rb"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="10dp"
+                        android:text="@string/user_manage_filter_deactivate" />
+                </RadioGroup>
+            </LinearLayout>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right"
+            android:orientation="horizontal"
+            android:padding="10dp">
+
+            <TextView
+                android:id="@+id/confirm"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:background="@drawable/common_dialog_btn"
+                android:paddingHorizontal="20dp"
+                android:text="@string/confirm"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+
+            <TextView
+                android:id="@+id/cancel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:background="@drawable/common_dialog_btn"
+                android:paddingHorizontal="20dp"
+                android:text="@string/cancel"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+        </LinearLayout>
+    </LinearLayout>
+</layout>

+ 14 - 0
app/src/main/res/layout/dialog_drop_down_list.xml

@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <FrameLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content">
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/drop_down_rv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/black_stroke_bg" />
+    </FrameLayout>
+</layout>

+ 204 - 0
app/src/main/res/layout/dialog_filter_user.xml

@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="400dp"
+        android:layout_height="300dp"
+        android:background="@drawable/common_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="10dp"
+            android:paddingVertical="5dp">
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_weight="1"
+                android:text="@string/user_manage_filter_title"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+
+            <ImageView
+                android:id="@+id/close_iv"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:paddingHorizontal="10dp"
+                android:src="@drawable/icon_close" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="@color/black" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="16dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/user_manage_nickname"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+
+                <EditText
+                    android:id="@+id/nickname_et"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dp"
+                    android:background="@drawable/bg_common_input"
+                    android:hint="@string/please_input_nickname"
+                    android:maxLines="1"
+                    android:paddingHorizontal="10dp"
+                    android:paddingVertical="2dp"
+                    android:singleLine="true"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="16dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/user_manage_card_code"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+
+                <EditText
+                    android:id="@+id/cardcode_et"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dp"
+                    android:background="@drawable/bg_common_input"
+                    android:hint="@string/please_input_card_code"
+                    android:maxLines="1"
+                    android:paddingHorizontal="10dp"
+                    android:paddingVertical="2dp"
+                    android:singleLine="true"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="16dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/user_manage_area"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+
+                <EditText
+                    android:id="@+id/area_et"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="10dp"
+                    android:background="@drawable/bg_common_input"
+                    android:hint="@string/please_input_area"
+                    android:maxLines="1"
+                    android:paddingHorizontal="10dp"
+                    android:paddingVertical="2dp"
+                    android:singleLine="true"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="20dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="16dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="@string/user_manage_filter_status"
+                    android:textColor="@color/black"
+                    android:textSize="18sp" />
+
+                <RadioGroup
+                    android:id="@+id/status_rg"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal">
+
+                    <RadioButton
+                        android:id="@+id/activate_rb"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="10dp"
+                        android:text="@string/user_manage_filter_activate" />
+
+                    <RadioButton
+                        android:id="@+id/deactivate_rb"
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="10dp"
+                        android:text="@string/user_manage_filter_deactivate" />
+                </RadioGroup>
+            </LinearLayout>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right"
+            android:orientation="horizontal"
+            android:padding="10dp">
+
+            <TextView
+                android:id="@+id/confirm"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:background="@drawable/common_dialog_btn"
+                android:paddingHorizontal="20dp"
+                android:text="@string/confirm"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+
+            <TextView
+                android:id="@+id/cancel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:background="@drawable/common_dialog_btn"
+                android:paddingHorizontal="20dp"
+                android:text="@string/cancel"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+        </LinearLayout>
+    </LinearLayout>
+</layout>

+ 7 - 0
app/src/main/res/layout/fragment_data_manage_home.xml

@@ -1,8 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layout xmlns:android="http://schemas.android.com/apk/res/android">
+
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/home_menu_rv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="40dp"
+            android:layout_marginTop="40dp" />
     </RelativeLayout>
 </layout>

+ 8 - 1
app/src/main/res/layout/fragment_exception_manage_home.xml

@@ -1,8 +1,15 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layout xmlns:android="http://schemas.android.com/apk/res/android">
+
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
-        
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/home_menu_rv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="40dp"
+            android:layout_marginTop="40dp" />
     </RelativeLayout>
 </layout>

+ 7 - 1
app/src/main/res/layout/fragment_hardware_manage_home.xml

@@ -3,6 +3,12 @@
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
-        
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/home_menu_rv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="40dp"
+            android:layout_marginTop="40dp" />
     </RelativeLayout>
 </layout>

+ 440 - 5
app/src/main/res/layout/fragment_home.xml

@@ -1,8 +1,443 @@
 <?xml version="1.0" encoding="utf-8"?>
-<layout xmlns:android="http://schemas.android.com/apk/res/android">
-    <RelativeLayout
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools">
+
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-        
-    </RelativeLayout>
+        android:layout_height="match_parent"
+        android:orientation="vertical">
+
+        <com.grkj.ui_base.widget.ShadowTextView
+            android:id="@+id/title_cn"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="40dp"
+            android:text="@string/loto"
+            android:textColor="@color/white"
+            android:textSize="40sp"
+            android:textStyle="bold" />
+
+        <FrameLayout
+            android:layout_width="match_parent"
+            android:layout_height="180dp"
+            android:layout_marginHorizontal="20dp"
+            android:layout_marginTop="40dp"
+            android:background="@drawable/home_card_bg">
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/quick_entrance_rv"
+                android:layout_width="wrap_content"
+                android:layout_height="match_parent"
+                android:layout_gravity="center_vertical"
+                android:layout_margin="20dp"
+                tools:listitem="@layout/item_home_quick_entrance" />
+        </FrameLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginHorizontal="20dp"
+            android:layout_marginVertical="10dp"
+            android:divider="@drawable/common_divider_normal_space_vertical"
+            android:orientation="vertical"
+            android:showDividers="middle">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:background="@drawable/home_card_bg"
+                android:orientation="vertical">
+
+                <TextView
+                    android:id="@+id/realtime_data_title"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:background="@color/home_card_title_bg"
+                    android:paddingVertical="5dp"
+                    android:paddingLeft="10dp"
+                    android:text="@string/home_realtime_data_title"
+                    android:textColor="@color/white"
+                    android:textSize="24sp" />
+
+                <LinearLayout
+                    android:id="@+id/realtime_data_filter_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:gravity="center_vertical"
+                    android:orientation="vertical"
+                    android:padding="10dp">
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/zone"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/real_time_data_zone"
+                            android:layout_width="180dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="10dp"
+                            android:background="@drawable/bg_common_input"
+                            android:drawableRight="@drawable/icon_drop_down"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="10dp"
+                            android:paddingVertical="2dp"
+                            android:textSize="22sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="10dp"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/lock_mode"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/lock_mode"
+                            android:layout_width="180dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="10dp"
+                            android:background="@drawable/bg_common_input"
+                            android:drawableRight="@drawable/icon_drop_down"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="10dp"
+                            android:paddingVertical="2dp"
+                            android:textSize="22sp" />
+                    </LinearLayout>
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="80dp"
+                    android:layout_marginBottom="10dp"
+                    android:layout_marginTop="20dp"
+                    android:divider="@drawable/common_divider_normal_space_horizontal"
+                    android:orientation="horizontal"
+                    android:paddingHorizontal="10dp"
+                    android:showDividers="middle">
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/ongoing_job_tv"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/ongoing_job_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_ffec99"
+                            android:gravity="center"
+                            android:padding="10dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="30sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/locked_points_tv"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/locked_points_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_ffc9c9"
+                            android:gravity="center"
+                            android:padding="10dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="30sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/hardware_in_use_tv"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/hardware_in_use_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_a5d8ff"
+                            android:gravity="center"
+                            android:padding="10dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="30sp" />
+                    </LinearLayout>
+                </LinearLayout>
+
+            </LinearLayout>
+
+            <RelativeLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:background="@drawable/home_card_bg">
+
+                <TextView
+                    android:id="@+id/overview_data_title"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:background="@color/home_card_title_bg"
+                    android:paddingVertical="5dp"
+                    android:paddingLeft="10dp"
+                    android:text="@string/home_overview_data_title"
+                    android:textColor="@color/white"
+                    android:textSize="24sp" />
+
+                <LinearLayout
+                    android:id="@+id/overview_data_filter_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_below="@+id/overview_data_title"
+                    android:gravity="center_vertical"
+                    android:orientation="vertical"
+                    android:padding="10dp">
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/time_frame_tv"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/start_time"
+                            android:layout_width="210dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="10dp"
+                            android:background="@drawable/bg_common_input"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="10dp"
+                            android:paddingVertical="5dp"
+                            android:textSize="22sp"
+                            tools:text="2025-04-01 12:00" />
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="5dp"
+                            android:gravity="center_vertical"
+                            android:text="-"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/end_time"
+                            android:layout_width="210dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="5dp"
+                            android:background="@drawable/bg_common_input"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="10dp"
+                            android:paddingVertical="5dp"
+                            android:textSize="22sp"
+                            tools:text="2025-04-01 12:00" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginTop="10dp"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:text="@string/zone"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/overview_data_zone"
+                            android:layout_width="180dp"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="10dp"
+                            android:background="@drawable/bg_common_input"
+                            android:drawableRight="@drawable/icon_drop_down"
+                            android:gravity="center_vertical"
+                            android:paddingHorizontal="10dp"
+                            android:paddingVertical="2dp"
+                            android:textSize="22sp" />
+                    </LinearLayout>
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="80dp"
+                    android:layout_below="@+id/overview_data_filter_layout"
+                    android:layout_marginBottom="10dp"
+                    android:layout_marginTop="20dp"
+                    android:divider="@drawable/common_divider_normal_space_horizontal"
+                    android:orientation="horizontal"
+                    android:paddingHorizontal="10dp"
+                    android:showDividers="middle">
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/all_job_tv"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/all_job_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_ffec99"
+                            android:gravity="center"
+                            android:padding="10dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="30sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/all_points_tv"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/all_points_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_ffc9c9"
+                            android:gravity="center"
+                            android:padding="10dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="30sp" />
+                    </LinearLayout>
+
+                    <LinearLayout
+                        android:layout_width="0dp"
+                        android:layout_height="match_parent"
+                        android:layout_weight="1"
+                        android:divider="@drawable/common_divider_small_space_horizontal"
+                        android:gravity="center_vertical"
+                        android:orientation="horizontal"
+                        android:showDividers="middle">
+
+                        <TextView
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:gravity="center"
+                            android:text="@string/all_hardware_tv"
+                            android:textColor="@color/black"
+                            android:textSize="22sp" />
+
+                        <TextView
+                            android:id="@+id/all_hardware_num"
+                            android:layout_width="0dp"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/bg_home_card_num"
+                            android:backgroundTint="@color/color_a5d8ff"
+                            android:gravity="center"
+                            android:padding="10dp"
+                            android:text="2"
+                            android:textColor="@color/black"
+                            android:textSize="30sp" />
+                    </LinearLayout>
+                </LinearLayout>
+            </RelativeLayout>
+        </LinearLayout>
+    </LinearLayout>
 </layout>

+ 7 - 1
app/src/main/res/layout/fragment_job_manage_home.xml

@@ -3,6 +3,12 @@
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent">
-        
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/home_menu_rv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="40dp"
+            android:layout_marginTop="40dp" />
     </RelativeLayout>
 </layout>

+ 15 - 0
app/src/main/res/layout/fragment_user_info_home.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/home_menu_rv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="40dp"
+            android:layout_marginTop="40dp" />
+    </RelativeLayout>
+</layout>

+ 154 - 0
app/src/main/res/layout/fragment_user_manage.xml

@@ -0,0 +1,154 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="20dp"
+        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="10dp"
+            android:paddingVertical="5dp">
+
+            <ImageView
+                android:layout_width="20dp"
+                android:layout_height="20dp"
+                android:src="@mipmap/icon_data_manage_menu_user_manage" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:layout_weight="1"
+                android:text="@string/user_manage_title"
+                android:textColor="@color/black"
+                android:textSize="24sp" />
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:background="@drawable/common_dialog_btn"
+                android:paddingHorizontal="20dp"
+                android:text="@string/back"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="@color/black" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingHorizontal="10dp"
+            android:paddingVertical="10dp">
+
+
+            <TextView
+                android:id="@+id/add_user"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:background="@drawable/common_dialog_btn"
+                android:paddingHorizontal="20dp"
+                android:text="@string/insert"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+
+
+            <TextView
+                android:id="@+id/delete_user"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:background="@drawable/common_dialog_btn"
+                android:paddingHorizontal="20dp"
+                android:text="@string/delete"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+
+
+            <View
+                android:layout_width="0dp"
+                android:layout_height="0dp"
+                android:layout_weight="1" />
+
+            <TextView
+                android:id="@+id/filter_user"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="10dp"
+                android:background="@drawable/common_dialog_btn"
+                android:paddingHorizontal="20dp"
+                android:text="@string/filter"
+                android:textColor="@color/black"
+                android:textSize="20sp" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="20dp"
+            android:layout_marginTop="10dp"
+            android:background="@drawable/common_card_bg"
+            android:divider="@drawable/divider_table"
+            android:showDividers="middle">
+
+            <CheckBox
+                android:id="@+id/select_all"
+                android:layout_width="30dp"
+                android:layout_height="30dp"
+                android:layout_gravity="center"
+                android:layout_margin="10dp" />
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/user_manage_nickname"
+                android:textSize="18sp" />
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/user_manage_card_code"
+                android:textSize="18sp" />
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/user_manage_detail"
+                android:textSize="18sp" />
+        </LinearLayout>
+
+        <com.scwang.smart.refresh.layout.SmartRefreshLayout
+            android:id="@+id/refresh_layout"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_marginHorizontal="20dp"
+            android:layout_marginBottom="10dp">
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/user_list_rv"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:background="@drawable/common_card_bg" />
+        </com.scwang.smart.refresh.layout.SmartRefreshLayout>
+    </LinearLayout>
+</layout>

+ 31 - 0
app/src/main/res/layout/item_home_menu.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="160dp"
+        android:layout_height="160dp"
+        android:gravity="center_horizontal"
+        android:orientation="vertical">
+
+        <FrameLayout
+            android:id="@+id/home_menu_layout"
+            android:layout_width="120dp"
+            android:layout_height="120dp"
+            android:background="@drawable/bg_home_menu_item">
+
+            <ImageView
+                android:id="@+id/home_menu_iv"
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:layout_gravity="center" />
+        </FrameLayout>
+
+        <TextView
+            android:id="@+id/home_menu_tv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="5dp"
+            android:textColor="@color/color_d7d2d2"
+            android:textSize="25sp" />
+    </LinearLayout>
+</layout>

+ 32 - 0
app/src/main/res/layout/item_home_quick_entrance.xml

@@ -0,0 +1,32 @@
+<?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="140dp"
+        android:layout_height="140dp"
+        android:gravity="center_horizontal"
+        android:orientation="vertical">
+
+        <FrameLayout
+            android:layout_width="100dp"
+            android:layout_height="100dp"
+            android:background="@drawable/bg_home_menu_item">
+
+            <ImageView
+                android:id="@+id/home_menu_iv"
+                android:layout_width="80dp"
+                android:layout_height="80dp"
+                android:layout_gravity="center"
+                app:tint="@color/black" />
+        </FrameLayout>
+
+        <TextView
+            android:id="@+id/home_menu_tv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="5dp"
+            android:textColor="@color/black"
+            android:textSize="24sp" />
+    </LinearLayout>
+</layout>

+ 12 - 0
app/src/main/res/layout/item_home_text_drop_down.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <TextView
+        android:id="@+id/drop_down_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:paddingHorizontal="8dp"
+        android:paddingVertical="4dp"
+        android:textColor="@color/black"
+        android:textSize="12sp" />
+</layout>

+ 41 - 0
app/src/main/res/layout/item_user_manage_user.xml

@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:divider="@drawable/divider_table"
+        android:showDividers="middle">
+
+        <CheckBox
+            android:id="@+id/select"
+            android:layout_width="30dp"
+            android:layout_height="30dp"
+            android:layout_gravity="center"
+            android:layout_margin="10dp" />
+
+        <TextView
+            android:id="@+id/nickname"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textSize="18sp" />
+
+        <TextView
+            android:id="@+id/card_code"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textSize="18sp" />
+
+        <TextView
+            android:id="@+id/view"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:text="@string/user_manage_view"
+            android:textSize="18sp" />
+    </LinearLayout>
+</layout>

+ 9 - 1
app/src/main/res/navigation/nav_data_manage.xml

@@ -7,5 +7,13 @@
     <fragment
         android:id="@+id/dataManageHomeFragment"
         android:name="com.grkj.iscs.features.main.fragment.data_manage.DataManageHomeFragment"
-        android:label="DataManageHomeFragment" />
+        android:label="DataManageHomeFragment" >
+        <action
+            android:id="@+id/action_dataManageHomeFragment_to_userManageFragment"
+            app:destination="@id/userManageFragment" />
+    </fragment>
+    <fragment
+        android:id="@+id/userManageFragment"
+        android:name="com.grkj.iscs.features.main.fragment.data_manage.UserManageFragment"
+        android:label="UserManageFragment" />
 </navigation>

+ 11 - 0
app/src/main/res/navigation/nav_user_info.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/nav_user_info"
+    app:startDestination="@id/userInfoHomeFragment">
+
+    <fragment
+        android:id="@+id/userInfoHomeFragment"
+        android:name="com.grkj.iscs.features.main.fragment.user_info.UserInfoHomeFragment"
+        android:label="UserInfoHomeFragment" />
+</navigation>

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

@@ -6,4 +6,42 @@
     <string name="card_login">card login</string>
     <string name="fingerprint_login">fingerprint login</string>
     <string name="account_login">account login</string>
+    <string name="home_realtime_data_title">Real-time data</string>
+    <string name="home_overview_data_title">Overview data</string>
+    <string name="zone">Zone</string>
+    <string name="lock_mode">Lock mode</string>
+    <string name="login_failed">login failed</string>
+    <string name="ongoing_job_tv">ongoing\njob</string>
+    <string name="hardware_in_use_tv">Hardware \nin use</string>
+    <string name="locked_points_tv">Locked\npoints</string>
+    <string name="all_hardware_tv">All\nhardware</string>
+    <string name="all_points_tv">All\npoints</string>
+    <string name="all_job_tv">All\njob</string>
+    <string name="time_frame_tv">Time frame</string>
+    <string name="user_manage_title">User manage</string>
+    <string name="filter">filter</string>
+    <string name="insert">new</string>
+    <string name="please_select_user">please select user</string>
+    <string name="check_delete_user">Do you want to delete selected users?</string>
+    <string name="user_manage_delete_succeed">user delete succeed</string>
+    <string name="user_manage_delete_failed">user delete failed</string>
+    <string name="user_manage_filter_title">Filter</string>
+    <string name="user_manage_nickname">nickname</string>
+    <string name="please_input_nickname">please input nickname</string>
+    <string name="please_input_card_code">please input card code</string>
+    <string name="user_manage_card_code">Card code</string>
+    <string name="user_manage_area">Area</string>
+    <string name="please_input_area">please input area</string>
+    <string name="user_manage_filter_status">Status</string>
+    <string name="user_manage_filter_activate">activate</string>
+    <string name="user_manage_filter_deactivate">deactivate</string>
+    <string name="user_manage_new_user_title">New user</string>
+    <string name="please_select_role">please select role</string>
+    <string name="please_select_area">please select area</string>
+    <string name="user_manage_role">Role</string>
+    <string name="please_select_status">please select status</string>
+    <string name="add_user_succeed">New user succeed</string>
+    <string name="add_user_failed">New user failed</string>
+    <string name="user_manage_detail">Detail</string>
+    <string name="user_manage_view">View</string>
 </resources>

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

@@ -6,4 +6,42 @@
     <string name="card_login">刷卡登录</string>
     <string name="fingerprint_login">指纹登录</string>
     <string name="account_login">用户名登录</string>
+    <string name="home_realtime_data_title">实时数据</string>
+    <string name="home_overview_data_title">总览数据</string>
+    <string name="zone">区域范围</string>
+    <string name="lock_mode">锁定模式</string>
+    <string name="login_failed">登录失败</string>
+    <string name="ongoing_job_tv">进行中\n的作业</string>
+    <string name="hardware_in_use_tv">使用中\n的硬件</string>
+    <string name="locked_points_tv">锁定中\n的点位</string>
+    <string name="all_hardware_tv">全部\n硬件</string>
+    <string name="all_points_tv">全部\n点位</string>
+    <string name="all_job_tv">全部\n作业</string>
+    <string name="time_frame_tv">时间范围</string>
+    <string name="user_manage_title">用户管理</string>
+    <string name="filter">筛选</string>
+    <string name="insert">新增</string>
+    <string name="please_select_user">请选择用户</string>
+    <string name="check_delete_user">您确认要删除用户吗?</string>
+    <string name="user_manage_delete_succeed">用户已删除</string>
+    <string name="user_manage_delete_failed">无法删除用户</string>
+    <string name="user_manage_filter_title">筛选条件</string>
+    <string name="user_manage_nickname">姓名</string>
+    <string name="please_input_nickname">请输入姓名</string>
+    <string name="please_input_card_code">请输入工卡</string>
+    <string name="user_manage_card_code">工卡</string>
+    <string name="user_manage_area">区域</string>
+    <string name="please_input_area">请输入区域</string>
+    <string name="user_manage_filter_status">状态</string>
+    <string name="user_manage_filter_activate">正常</string>
+    <string name="user_manage_filter_deactivate">停用</string>
+    <string name="user_manage_new_user_title">新增用户</string>
+    <string name="please_select_role">请选择角色</string>
+    <string name="please_select_area">请选择区域</string>
+    <string name="user_manage_role">角色</string>
+    <string name="please_select_status">请选择状态</string>
+    <string name="add_user_succeed">新增用户成功</string>
+    <string name="add_user_failed">新增用户失败</string>
+    <string name="user_manage_detail">详情</string>
+    <string name="user_manage_view">查看</string>
 </resources>

+ 4 - 0
app/src/main/res/values/colors.xml

@@ -6,4 +6,8 @@
     <color name="login_method_tv_color">#D7D2D2</color>
     <color name="color_7b7d7e">#7b7d7e</color>
     <color name="color_1daeff">#1daeff</color>
+    <color name="color_d7d2d2">#d7d2d2</color>
+    <color name="color_ffec99">#ffec99</color>
+    <color name="color_ffc9c9">#ffc9c9</color>
+    <color name="color_a5d8ff">#a5d8ff</color>
 </resources>

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

@@ -5,4 +5,42 @@
     <string name="card_login">刷卡登录</string>
     <string name="fingerprint_login">指纹登录</string>
     <string name="account_login">用户名登录</string>
+    <string name="home_realtime_data_title">实时数据</string>
+    <string name="home_overview_data_title">总览数据</string>
+    <string name="zone">区域范围</string>
+    <string name="lock_mode">锁定模式</string>
+    <string name="login_failed">登录失败</string>
+    <string name="ongoing_job_tv">进行中\n的作业</string>
+    <string name="hardware_in_use_tv">使用中\n的硬件</string>
+    <string name="locked_points_tv">锁定中\n的点位</string>
+    <string name="all_hardware_tv">全部\n硬件</string>
+    <string name="all_points_tv">全部\n点位</string>
+    <string name="all_job_tv">全部\n作业</string>
+    <string name="time_frame_tv">时间范围</string>
+    <string name="user_manage_title">用户管理</string>
+    <string name="filter">筛选</string>
+    <string name="insert">新增</string>
+    <string name="please_select_user">请选择用户</string>
+    <string name="check_delete_user">您确认要删除用户吗?</string>
+    <string name="user_manage_delete_succeed">用户已删除</string>
+    <string name="user_manage_delete_failed">无法删除用户</string>
+    <string name="user_manage_filter_title">筛选条件</string>
+    <string name="user_manage_nickname">姓名</string>
+    <string name="please_input_nickname">请输入姓名</string>
+    <string name="please_input_card_code">请输入工卡</string>
+    <string name="user_manage_card_code">工卡</string>
+    <string name="user_manage_area">区域</string>
+    <string name="please_input_area">请输入区域</string>
+    <string name="user_manage_filter_status">状态</string>
+    <string name="user_manage_filter_activate">正常</string>
+    <string name="user_manage_filter_deactivate">停用</string>
+    <string name="user_manage_new_user_title">新增用户</string>
+    <string name="please_select_role">请选择角色</string>
+    <string name="please_select_area">请选择区域</string>
+    <string name="user_manage_role">角色</string>
+    <string name="please_select_status">请选择状态</string>
+    <string name="add_user_succeed">新增用户成功</string>
+    <string name="add_user_failed">新增用户失败</string>
+    <string name="user_manage_detail">详情</string>
+    <string name="user_manage_view">查看</string>
 </resources>

+ 35 - 0
data/src/main/java/com/grkj/data/dao/UserDao.kt

@@ -1,9 +1,12 @@
 package com.grkj.data.dao
 
+import androidx.annotation.Size
 import androidx.room.Dao
 import androidx.room.Query
 import com.grkj.data.model.dos.SysUserCharacteristicDo
 import com.grkj.data.model.dos.SysUserDo
+import com.grkj.data.model.vo.UserManageVo
+import com.grkj.domain.entity.vo.UserManageFilterVo
 
 /**
  * 用户数据库查询
@@ -33,4 +36,36 @@ interface UserDao {
      */
     @Query("select * from sys_user_characteristic where type = 2")
     fun getFaceData(): List<SysUserCharacteristicDo>
+
+    /**
+     * 获取用户数据
+     */
+    @Query("""
+          SELECT
+              su.user_id   AS userId,
+              su.nick_name AS nickName,
+              sr.role_id   AS roleId,
+              sr.role_name AS roleName,
+              ijc.card_code AS cardCode,
+              su.status,
+              NULL AS workAreaId,
+              NULL AS workAreaName
+            FROM sys_user su
+            LEFT JOIN sys_user_role sur ON su.user_id = sur.user_id
+            LEFT JOIN sys_role       sr  ON sur.role_id   = sr.role_id
+            LEFT JOIN is_job_card   ijc ON ijc.user_id     = su.user_id
+            WHERE (:nickname  IS NULL OR su.nick_name LIKE '%' || :nickname  || '%')
+              AND (:cardCode  IS NULL OR ijc.card_code   LIKE '%' || :cardCode  || '%')
+              AND (:status    IS NULL OR su.status       = :status)
+              AND su.del_flag = 0
+            LIMIT  :size
+            OFFSET :offset
+    """)
+    fun getUserManagerData(
+        nickname: String?,
+        cardCode: String?,
+        status: Boolean?,
+        offset: Int,
+        size: Int
+    ): List<UserManageVo>
 }

+ 4 - 2
data/src/main/java/com/grkj/data/database/ISCSDatabase.kt

@@ -7,15 +7,17 @@ import androidx.room.RoomDatabase
 import com.grkj.data.dao.HardwareDao
 import com.grkj.data.dao.UserDao
 import com.grkj.data.model.dos.IsJobCardDo
+import com.grkj.data.model.dos.SysRole
 import com.grkj.data.model.dos.SysUserCharacteristicDo
 import com.grkj.data.model.dos.SysUserDo
+import com.grkj.data.model.dos.SysUserRole
 import com.sik.sikcore.SIKCore
 
 /**
  * 本地数据库
  */
 @Database(
-    entities = [IsJobCardDo::class, SysUserDo::class, SysUserCharacteristicDo::class],
+    entities = [IsJobCardDo::class, SysUserDo::class, SysUserCharacteristicDo::class, SysRole::class, SysUserRole::class],
     version = ISCSMigrations.VERSION
 )
 abstract class ISCSDatabase : RoomDatabase() {
@@ -29,7 +31,7 @@ abstract class ISCSDatabase : RoomDatabase() {
                 SIKCore.getApplication(),
                 ISCSDatabase::class.java,
                 "iscs_database"
-            )
+            ).createFromAsset("data.db")
                 // 如需在主线程查询,可取消下行注释(不推荐):
                 // .allowMainThreadQueries()
                 .fallbackToDestructiveMigration(true)

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

@@ -12,22 +12,22 @@ import com.sik.sikcore.date.TimeUtils
 class IsJobCardDo : BaseBean() {
     @PrimaryKey
     @ColumnInfo("card_id")
-    var cardId: Int = 0
+    var cardId: Long = 0
 
     @ColumnInfo("card_code")
     var cardCode: String = ""
 
     @ColumnInfo("hardware_id")
-    var hardwareId: Int? = null
+    var hardwareId: Long? = null
 
     @ColumnInfo("card_nfc")
-    var cardNfc: String? = null
+    var cardNfc: String = ""
 
     @ColumnInfo("card_type")
     var cardType: Int? = null
 
     @ColumnInfo("user_id")
-    var userId: Int? = null
+    var userId: Long? = null
 
     @ColumnInfo("user_name")
     var userName: String? = null

+ 75 - 0
data/src/main/java/com/grkj/data/model/dos/SysRole.kt

@@ -0,0 +1,75 @@
+package com.grkj.data.model.dos
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+import androidx.room.PrimaryKey
+
+
+/**
+ * 角色表 sys_role
+ *
+ * @author ruoyi
+ */
+@Entity(tableName = "sys_role")
+class SysRole : BaseBean() {
+    /**
+     * 角色ID
+     */
+    @PrimaryKey
+    @ColumnInfo("role_id")
+    var roleId: Long = 0
+
+    /**
+     * 角色名称
+     */
+    @ColumnInfo("role_name")
+    var roleName: String = ""
+
+    /**
+     * 角色权限
+     */
+    @ColumnInfo("role_key")
+    var roleKey: String = ""
+
+    /**
+     * 角色排序
+     */
+    @ColumnInfo("role_sort")
+    var roleSort: Int = 0
+
+    /**
+     * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)
+     */
+    @ColumnInfo("data_scope")
+    var dataScope: String? = null
+
+    /**
+     * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示)
+     */
+    @ColumnInfo("menu_check_strictly")
+    var menuCheckStrictly: Int? = null
+
+    /**
+     * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 )
+     */
+    @ColumnInfo("dept_check_strictly")
+    var deptCheckStrictly: Int? = null
+
+    /**
+     * 角色状态(0正常 1停用)
+     */
+    var status: String = "0"
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @ColumnInfo("del_flag")
+    var delFlag: String? = null
+
+    @ColumnInfo("mars_data_scope")
+    var marsDataScope: String? = null
+
+    companion object {
+        const val serialVersionUID = 1L
+    }
+}

+ 9 - 5
data/src/main/java/com/grkj/data/model/dos/SysUserCharacteristicDo.kt

@@ -2,6 +2,7 @@ package com.grkj.data.model.dos
 
 import androidx.room.ColumnInfo
 import androidx.room.Entity
+import androidx.room.Index
 import androidx.room.PrimaryKey
 
 /**
@@ -10,20 +11,23 @@ import androidx.room.PrimaryKey
  * @author cgj
  * @date 2025-03-10
  */
-@Entity("sys_user_characteristic")
+@Entity(
+    tableName = "sys_user_characteristic",
+    indices = [Index("type", name = "type_seq", orders = [Index.Order.ASC])]
+)
 class SysUserCharacteristicDo : BaseBean() {
     @PrimaryKey
     @ColumnInfo("record_id")
-    var recordId: Long? = null
+    var recordId: Long = 0
 
     @ColumnInfo("user_id")
-    var userId: Long? = null
+    var userId: Long = 0
 
     @ColumnInfo("type")
-    var type: String? = null
+    var type: String = ""
 
     @ColumnInfo("content")
-    var content: String? = null
+    var content: String = ""
 
     @ColumnInfo("image_url")
     var imageUrl: String? = null

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

@@ -6,19 +6,19 @@ import androidx.room.PrimaryKey
 import com.sik.sikcore.date.TimeUtils
 
 @Entity(tableName = "sys_user")
-class SysUserDo {
+class SysUserDo : BaseBean() {
     @PrimaryKey
     @ColumnInfo("user_id")
-    var userId: Int = 0
+    var userId: Long = 0
 
     @ColumnInfo("dept_id")
-    var deptId: Int? = 0
+    var deptId: Long? = 0
 
     @ColumnInfo("user_name")
     var userName: String = ""
 
     @ColumnInfo("nick_name")
-    var nickName: String? = null
+    var nickName: String = ""
 
     @ColumnInfo("user_type")
     var userType: String? = ""

+ 16 - 0
data/src/main/java/com/grkj/data/model/dos/SysUserRole.kt

@@ -0,0 +1,16 @@
+package com.grkj.data.model.dos
+
+import androidx.room.ColumnInfo
+import androidx.room.Entity
+
+/**
+ * 用户角色关联
+ */
+@Entity(tableName = "sys_user_role", primaryKeys = ["user_id", "role_id"])
+class SysUserRole {
+    @ColumnInfo("user_id")
+    var userId: Int = 0
+
+    @ColumnInfo("role_id")
+    var roleId: Int = 0
+}

+ 27 - 0
data/src/main/java/com/grkj/data/model/vo/UserManageVo.kt

@@ -0,0 +1,27 @@
+package com.grkj.data.model.vo
+
+import androidx.room.Ignore
+
+/**
+ * 用户管理显示
+ */
+class UserManageVo {
+    var userId: Long = 0
+    var nickName: String = ""
+    var cardCode: String? = ""
+    var roleId: Long = 0
+    var roleName: String? = ""
+    var workAreaId: Long? = null
+    var workAreaName: String? = null
+    var status: String? = null
+
+    @Ignore
+    var isSelected: Boolean = false
+
+    /**
+     * 获取状态
+     */
+    fun getStatus(): Boolean {
+        return status == "0"
+    }
+}

+ 20 - 4
data/src/main/java/com/grkj/data/repository/UserRepository.kt

@@ -6,6 +6,8 @@ import com.grkj.data.dao.UserDao
 import com.grkj.data.data.MainDomainData
 import com.grkj.data.database.ISCSDatabase
 import com.grkj.data.model.dos.SysUserDo
+import com.grkj.data.model.vo.UserManageVo
+import com.grkj.domain.entity.vo.UserManageFilterVo
 import com.grkj.domain.repository.IUserRepository
 import com.grkj.shared.utils.BCryptUtils
 import com.grkj.shared.utils.BiometricVerifier
@@ -23,10 +25,10 @@ class UserRepository : IUserRepository {
     override fun loginWithAccount(
         username: String, password: String
     ): Boolean {
-        MainDomainData.userInfo = SysUserDo().apply {
-            nickName = "罗成"
-        }
-        return true
+//        MainDomainData.userInfo = SysUserDo().apply {
+//            nickName = "罗成"
+//        }
+//        return true
         var sysUserDo = userDao.getUserInfoByUsername(username)
         if (sysUserDo == null) {
             return false
@@ -113,4 +115,18 @@ class UserRepository : IUserRepository {
         MainDomainData.clear()
         return true
     }
+
+    override fun getUserManagerData(
+        userManageFilterData: UserManageFilterVo?,
+        current: Int,
+        size: Int
+    ): List<UserManageVo> {
+        return userDao.getUserManagerData(
+            userManageFilterData?.nickname,
+            userManageFilterData?.cardCode,
+            userManageFilterData?.status,
+            current * size,
+            size
+        )
+    }
 }

+ 12 - 0
domain/src/main/java/com/grkj/domain/entity/vo/AddUserDataVo.kt

@@ -0,0 +1,12 @@
+package com.grkj.domain.entity.vo
+
+/**
+ * 添加用户
+ */
+data class AddUserDataVo(
+    val nickname: String,
+    val cardCode: String,
+    val role: String,
+    val area: String,
+    val status: Boolean
+)

+ 11 - 0
domain/src/main/java/com/grkj/domain/entity/vo/UserManageFilterVo.kt

@@ -0,0 +1,11 @@
+package com.grkj.domain.entity.vo
+
+/**
+ * 筛选用户
+ */
+data class UserManageFilterVo(
+    val nickname: String,
+    val cardCode: String,
+    val area: String,
+    val status: Boolean?
+)

+ 12 - 0
domain/src/main/java/com/grkj/domain/repository/IUserRepository.kt

@@ -1,5 +1,8 @@
 package com.grkj.domain.repository
 
+import com.grkj.domain.entity.vo.UserManageFilterVo
+import javax.print.attribute.standard.MediaSize
+
 /**
  * 用户仓储层
  */
@@ -28,4 +31,13 @@ interface IUserRepository {
      * 退出登录
      */
     fun logout(): Boolean
+
+    /**
+     * 获取用户数据
+     */
+    fun getUserManagerData(
+        userManageFilterData: UserManageFilterVo?,
+        current: Int,
+        size: Int
+    ): List<*>
 }

+ 1 - 0
settings.gradle.kts

@@ -9,6 +9,7 @@ pluginManagement {
         }
         mavenCentral()
         gradlePluginPortal()
+        maven("https://jitpack.io")
     }
 }
 dependencyResolutionManagement {

+ 4 - 0
ui-base/build.gradle.kts

@@ -57,6 +57,10 @@ dependencies {
     api(libs.sik.extension.android)
     api(libs.dialogx)
     api(libs.fastble)
+    api("io.github.razerdp:BasePopup:3.2.1")
+    api("io.github.scwang90:refresh-layout-kernel:3.0.0-alpha")
+    api("io.github.scwang90:refresh-header-classics:3.0.0-alpha")
+    api("io.github.scwang90:refresh-footer-classics:3.0.0-alpha")
     implementation(project(":data"))
     implementation(project(":shared"))
     testImplementation(libs.junit)

+ 19 - 8
ui-base/src/main/java/com/grkj/ui_base/base/BaseFragment.kt

@@ -1,5 +1,7 @@
 package com.grkj.ui_base.base
 
+import android.content.res.Configuration
+import android.content.res.Resources
 import android.os.Bundle
 import android.view.LayoutInflater
 import android.view.View
@@ -25,9 +27,7 @@ abstract class BaseFragment<V : ViewDataBinding> : Fragment() {
 
     protected lateinit var binding: V
 
-    /** 是否启用 Navigation */
-    protected open fun enableNavigation(): Boolean = false
-    protected lateinit var navController: NavController
+    protected val navController: NavController get() = findNavController()
 
     override fun onCreateView(
         inflater: LayoutInflater,
@@ -47,11 +47,6 @@ abstract class BaseFragment<V : ViewDataBinding> : Fragment() {
             EventBus.getDefault().register(this)
         }
 
-        // Navigation 初始化
-        if (enableNavigation()) {
-            navController = findNavController()
-        }
-
         initView()
         initData()
         initListeners()
@@ -96,6 +91,22 @@ abstract class BaseFragment<V : ViewDataBinding> : Fragment() {
         PopTip.tip(msg)
     }
 
+    /**
+     * 判断当前屏幕方向
+     * @return true: 横屏;false: 竖屏
+     */
+    protected fun isLandscape(resources: Resources = this.resources): Boolean {
+        return resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
+    }
+
+    /**
+     * 判断当前屏幕方向
+     * @return true: 竖屏;false: 横屏
+     */
+    protected fun isPortrait(resources: Resources = this.resources): Boolean {
+        return resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
+    }
+
     /** 获取布局资源 ID */
     @LayoutRes
     protected abstract fun getLayoutId(): Int

+ 17 - 22
ui-base/src/main/java/com/grkj/ui_base/dialog/LoadingDialog.kt

@@ -4,49 +4,44 @@ import android.view.View
 import androidx.core.view.isVisible
 import com.grkj.ui_base.R
 import com.grkj.ui_base.databinding.CommonDialogLoadingProgressBinding
+import com.grkj.ui_base.utils.CommonUtils
 import com.kongzue.dialogx.dialogs.CustomDialog
+import com.kongzue.dialogx.interfaces.DialogLifecycleCallback
 import com.kongzue.dialogx.interfaces.OnBindView
 
 class LoadingDialog : OnBindView<CustomDialog>(R.layout.common_dialog_loading_progress) {
     private lateinit var binding: CommonDialogLoadingProgressBinding
+    private var content: String? = null
     override fun onBind(p0: CustomDialog?, p1: View) {
         binding = CommonDialogLoadingProgressBinding.bind(p1)
-    }
-
-    fun setMessage(msg: String?) {
-        binding.tvCommonProgress.isVisible = msg == null
-        binding.tvCommonProgress.text = msg
-    }
-
-    fun startAnimation() {
+        p0?.setMaskColor(CommonUtils.getColor(R.color.scrim))
+        binding.tvCommonProgress.isVisible = content != null
+        binding.tvCommonProgress.text = content
+        p0?.setDialogLifecycleCallback(object : DialogLifecycleCallback<CustomDialog>() {
+            override fun onDismiss(dialog: CustomDialog?) {
+                binding.avlivCommon.smoothToHide()
+                super.onDismiss(dialog)
+            }
+        })
         binding.avlivCommon.smoothToShow()
     }
 
-    fun stopAnimation() {
-        binding.avlivCommon.smoothToHide()
+    fun setMessage(msg: String?) {
+        this.content = msg
     }
 
     companion object {
-        private val loadingDialogView by lazy { LoadingDialog() }
         private var loadingDialog: CustomDialog? = null
 
         @JvmStatic
         fun show(msg: String? = null) {
-            if (loadingDialog == null) {
-                loadingDialog = CustomDialog.show(loadingDialogView.apply {
-                    setMessage(msg)
-                    startAnimation()
-                }, CustomDialog.ALIGN.CENTER)
-            } else {
-                loadingDialogView.setMessage(msg)
-                loadingDialogView.startAnimation()
-                loadingDialog?.show()
-            }
+            loadingDialog = CustomDialog.show(LoadingDialog().apply {
+                setMessage(msg)
+            }, CustomDialog.ALIGN.CENTER)
         }
 
         @JvmStatic
         fun hide() {
-            loadingDialogView.stopAnimation()
             loadingDialog?.dismiss()
         }
     }

+ 13 - 1
ui-base/src/main/java/com/grkj/ui_base/dialog/TipDialog.kt

@@ -28,6 +28,7 @@ class TipDialog : OnBindView<CustomDialog>(R.layout.dialog_tip) {
     private var title: String = ""
     private var content: String = ""
     private var dialogType: DialogType = DialogType.INFO
+    private var showConfirm: Boolean = true
     private var showCancel: Boolean = true
     private var countDownTime: Int = -1
 
@@ -38,6 +39,7 @@ class TipDialog : OnBindView<CustomDialog>(R.layout.dialog_tip) {
     override fun onBind(dialog: CustomDialog?, contentView: View) {
         this.dialog = dialog
         binding = DialogTipBinding.bind(contentView)
+        dialog?.setMaskColor(CommonUtils.getColor(R.color.scrim))
         // 确定按钮
         binding.confirmBtn.setOnClickListener {
             countDownJob?.cancel()
@@ -52,6 +54,7 @@ class TipDialog : OnBindView<CustomDialog>(R.layout.dialog_tip) {
         }
         binding.title.text = title
         binding.content.text = content
+        binding.confirmBtn.isVisible = showConfirm
         when (dialogType) {
             DialogType.INFO -> {
                 binding.title.setBackgroundColor(CommonUtils.getColor(R.color.common_tip_dialog_info))
@@ -121,6 +124,13 @@ class TipDialog : OnBindView<CustomDialog>(R.layout.dialog_tip) {
         this.showCancel = showCancel
     }
 
+    /**
+     * 是否显示确认
+     */
+    fun showConfirm(showConfirm: Boolean) {
+        this.showConfirm = showConfirm
+    }
+
     /**
      * 设置倒计时
      */
@@ -150,10 +160,11 @@ class TipDialog : OnBindView<CustomDialog>(R.layout.dialog_tip) {
          */
         @JvmStatic
         fun show(
-            title: String = "操作确认",
+            title: String = CommonUtils.getStr(R.string.action_confirm).toString(),
             msg: String,
             dialogType: DialogType = DialogType.INFO,
             showCancel: Boolean = true,
+            showConfirm: Boolean = true,
             countDownTime: Int = -1,
             onConfirmClick: () -> Unit = {},
             onCancelClick: () -> Unit = {}
@@ -162,6 +173,7 @@ class TipDialog : OnBindView<CustomDialog>(R.layout.dialog_tip) {
                 setTitle(title)
                 setMessage(msg)
                 setDialogType(dialogType)
+                showConfirm(showConfirm)
                 showCancel(showCancel)
                 setCountDownTime(countDownTime)
                 setOnConfirmClickListener(onConfirmClick)

+ 101 - 0
ui-base/src/main/java/com/grkj/ui_base/ext/ViewBadgeExtensions.kt

@@ -0,0 +1,101 @@
+package com.grkj.ui_base.ext
+
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.OptIn
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
+import com.google.android.material.badge.BadgeDrawable
+import com.google.android.material.badge.BadgeUtils
+import com.google.android.material.badge.ExperimentalBadgeUtils
+
+private const val TAG_BADGE_WRAPPER = -1001
+
+private class BadgeWrapper(
+    val badge: BadgeDrawable,
+    val attachListener: View.OnAttachStateChangeListener,
+    val lifecycleObserver: DefaultLifecycleObserver?
+)
+
+/**
+ * 在任意 View 上显示 Badge(数字或小红点),并自动在 View 回收或 LifecycleOwner 销毁时移除。
+ *
+ * @param number       数字,传 0 则显示小红点;传负数则隐藏。
+ * @param background   可选:角标背景色资源 ID,如 R.color.red。
+ * @param textColor    可选:数字颜色资源 ID,如 R.color.white。
+ * @param parent       可选:用于附着角标的父容器,默认取 view.parent(必须是 ViewGroup)。
+ * @param lifecycleOwner 可选:若传入,会在其 onDestroy 时自动移除 Badge;
+ *                      若不传且 view.context 是 LifecycleOwner,会自动绑定。
+ * @return BadgeDrawable 你可以用它来后续隐藏或更新数字。
+ */
+@OptIn(ExperimentalBadgeUtils::class)
+fun View.showBadge(
+    number: Int = 0,
+    background: Int? = null,
+    textColor: Int? = null,
+    parent: ViewGroup? = null,
+    lifecycleOwner: LifecycleOwner? = null
+): BadgeDrawable {
+    // 如果已有 badge, 先移除
+    removeBadge()
+
+    // 准备 BadgeDrawable
+    val badge = BadgeDrawable.create(context).apply {
+        isVisible = number >= 0
+        if (number > 0) this.number = number
+        background?.let { this.backgroundColor = ContextCompat.getColor(context, it) }
+        textColor?.let { this.badgeTextColor = ContextCompat.getColor(context, it) }
+    }
+
+    // 附加到父容器
+    val anchorParent = parent ?: (this.parent as? ViewGroup
+        ?: throw IllegalStateException("View(${this.id}) 的 parent 不是 ViewGroup,无法附加 Badge"))
+    BadgeUtils.attachBadgeDrawable(badge, this)
+
+    // 监听 View 分离,自动移除 badge
+    val attachListener = object : View.OnAttachStateChangeListener {
+        override fun onViewAttachedToWindow(v: View) {}
+        override fun onViewDetachedFromWindow(v: View) {
+            removeBadge()
+        }
+    }
+    addOnAttachStateChangeListener(attachListener)
+
+    // 监听 LifecycleOwner 销毁
+    val owner = lifecycleOwner ?: (context as? LifecycleOwner)
+    val lifecycleObserver = owner?.let { lcOwner ->
+        val obs = object : DefaultLifecycleObserver {
+            override fun onDestroy(owner: LifecycleOwner) {
+                removeBadge()
+                owner.lifecycle.removeObserver(this)
+            }
+        }
+        lcOwner.lifecycle.addObserver(obs)
+        obs
+    }
+
+    // 存储 wrapper
+    setTag(TAG_BADGE_WRAPPER, BadgeWrapper(badge, attachListener, lifecycleObserver))
+    return badge
+}
+
+/**
+ * 从 View 上移除 Badge,并取消自动管理。
+ */
+@OptIn(ExperimentalBadgeUtils::class)
+fun View.removeBadge() {
+    val wrapper = getTag(TAG_BADGE_WRAPPER) as? BadgeWrapper ?: return
+    // detach badge
+    val anchorParent = parent as? ViewGroup
+    anchorParent?.let { BadgeUtils.detachBadgeDrawable(wrapper.badge, this) }
+    // remove listener
+    removeOnAttachStateChangeListener(wrapper.attachListener)
+    // remove lifecycle observer
+    wrapper.lifecycleObserver?.let { obs ->
+        (context as? LifecycleOwner)?.lifecycle?.removeObserver(obs)
+    }
+    // remove tag
+    setTag(TAG_BADGE_WRAPPER, null)
+}

+ 1 - 0
ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConnectionManager.kt

@@ -250,6 +250,7 @@ object BleConnectionManager {
                 // 没有扫描到
                 if (scanResultList?.none { it.mac == mac } == true) {
                     logger.warn("$mac is not scanned")
+                    connectListeners.removeIf { it.mac == mac }
                     prepareDoneCallBack?.invoke(false, null)
                 }
             }

+ 23 - 0
ui-base/src/main/java/com/grkj/ui_base/utils/extension/DialogXExtension.kt

@@ -0,0 +1,23 @@
+package com.grkj.ui_base.utils.extension
+
+import com.kongzue.dialogx.DialogX
+import com.kongzue.dialogx.dialogs.PopTip
+
+/**
+ * 使用dialog模式显示
+ */
+fun PopTip.tipDialog(msg: String) {
+    dialogImplMode = DialogX.IMPL_MODE.DIALOG_FRAGMENT
+    message = msg
+    show()
+}
+
+
+/**
+ * 使用dialog模式显示
+ */
+fun PopTip.tipDialog(msg: Int) {
+    dialogImplMode = DialogX.IMPL_MODE.DIALOG_FRAGMENT
+    setMessage(msg)
+    show()
+}

+ 7 - 0
ui-base/src/main/res/drawable/black_stroke_bg.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <stroke
+        android:width="@dimen/divider_line_width"
+        android:color="@color/black" />
+</shape>

+ 6 - 0
ui-base/src/main/res/drawable/common_back_btn.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
+    <solid android:color="@color/white30" />
+    <corners android:radius="4dp" />
+</shape>

+ 0 - 0
ui-base/src/main/res/drawable/common_dialog_bg.xml → ui-base/src/main/res/drawable/common_card_bg.xml


+ 6 - 0
ui-base/src/main/res/drawable/common_divider_normal_space_horizontal_land.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <size
+        android:width="5dp"
+        android:height="1dp" />
+</shape>

+ 6 - 0
ui-base/src/main/res/drawable/common_divider_normal_space_vertical_land.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <size
+        android:width="1dp"
+        android:height="5dp" />
+</shape>

+ 6 - 0
ui-base/src/main/res/drawable/common_divider_small_space_horizontal.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <size
+        android:width="5dp"
+        android:height="1dp" />
+</shape>

+ 6 - 0
ui-base/src/main/res/drawable/common_divider_small_space_horizontal_land.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <size
+        android:width="2.5dp"
+        android:height="1dp" />
+</shape>

+ 1 - 1
ui-base/src/main/res/layout-land/dialog_tip.xml

@@ -5,7 +5,7 @@
     <RelativeLayout
         android:layout_width="250dp"
         android:layout_height="140dp"
-        android:background="@drawable/common_dialog_bg">
+        android:background="@drawable/common_card_bg">
 
         <TextView
             android:id="@+id/title"

+ 8 - 3
ui-base/src/main/res/layout/common_dialog_loading_progress.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<layout  xmlns:android="http://schemas.android.com/apk/res/android"
+<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">
 
@@ -17,23 +17,28 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textColor="@android:color/white"
+            android:textSize="28sp"
             android:visibility="gone"
             tools:text="title"
             tools:visibility="visible" />
 
         <com.wang.avi.AVLoadingIndicatorView
             android:id="@+id/avliv_common"
-            style="@style/AVLoadingIndicatorView.Large"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             app:indicatorColor="@android:color/white"
-            app:indicatorName="PacmanIndicator" />
+            app:indicatorName="PacmanIndicator"
+            app:maxHeight="152dp"
+            app:maxWidth="152dp"
+            app:minHeight="152dp"
+            app:minWidth="152dp" />
 
         <TextView
             android:id="@+id/tv_common_progress"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textColor="@android:color/white"
+            android:textSize="28sp"
             android:visibility="gone"
             tools:text="adjfksadfj"
             tools:visibility="visible" />

+ 1 - 1
ui-base/src/main/res/layout/dialog_tip.xml

@@ -5,7 +5,7 @@
     <RelativeLayout
         android:layout_width="500dp"
         android:layout_height="280dp"
-        android:background="@drawable/common_dialog_bg">
+        android:background="@drawable/common_card_bg">
 
         <TextView
             android:id="@+id/title"

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

@@ -358,4 +358,6 @@
     <string name="key_exception_tag">Key is tag for exception</string>
     <string name="slot_exception_tag">Slot is tag for exception</string>
     <string name="lock_exception_tag">Lock is tag for exception</string>
+    <string name="action_succeed">action succeed</string>
+    <string name="action_failed">action failed</string>
 </resources>

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

@@ -358,4 +358,6 @@
     <string name="key_exception_tag">该钥匙已被标记异常</string>
     <string name="slot_exception_tag">该锁仓已被标记异常</string>
     <string name="lock_exception_tag">该挂锁已被标记异常</string>
+    <string name="action_succeed">操作成功</string>
+    <string name="action_failed">操作失败</string>
 </resources>

+ 3 - 0
ui-base/src/main/res/values/colors.xml

@@ -25,6 +25,8 @@
     <color name="common_light_gray">#CCCCCC</color>
     <color name="common_dlg_bg">#535B67</color>
 
+    <color name="scrim">#99000000</color>
+
     <color name="selectable_input_prefix">#bd3124</color>
     <color name="switch_track_on">#298EFF</color>
     <color name="switch_track_off">#E9E9E9</color>
@@ -46,4 +48,5 @@
     <color name="common_tip_dialog_info">#228be6</color>
     <color name="common_tip_dialog_error">#e03131</color>
     <color name="common_tip_dialog_success">#099268</color>
+    <color name="home_card_title_bg">#228be6</color>
 </resources>

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

@@ -358,4 +358,6 @@
     <string name="key_exception_tag">该钥匙已被标记异常</string>
     <string name="slot_exception_tag">该锁仓已被标记异常</string>
     <string name="lock_exception_tag">该挂锁已被标记异常</string>
+    <string name="action_succeed">操作成功</string>
+    <string name="action_failed">操作失败</string>
 </resources>