Ver código fonte

refactor(更新)
- 下发作业票和还钥匙读取完成

周文健 4 meses atrás
pai
commit
60f9e7e5b1
83 arquivos alterados com 2345 adições e 456 exclusões
  1. 1 1
      app/src/main/assets/logback.xml
  2. 2 1
      app/src/main/java/com/grkj/iscs/ISCSApplication.kt
  3. 29 6
      app/src/main/java/com/grkj/iscs/features/init/viewmodel/InitDeviceRegistrationKeyAndLockViewModel.kt
  4. 1 0
      app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt
  5. 15 2
      app/src/main/java/com/grkj/iscs/features/main/dialog/TextDropDownDialog.kt
  6. 4 4
      app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/AddUserDialog.kt
  7. 3 3
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/CreateJobFragment.kt
  8. 3 3
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/CreateSopFragment.kt
  9. 2 2
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/EditJobFragment.kt
  10. 2 2
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/EditSopFragment.kt
  11. 2 2
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/InProgressJobManageFragment.kt
  12. 2 2
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobManageFragment.kt
  13. 68 0
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/MainViewModel.kt
  14. 7 5
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/data_manage/UserManageViewModel.kt
  15. 9 1
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobExecuteViewModel.kt
  16. 12 12
      app/src/main/java/com/grkj/iscs/features/splash/activity/SplashActivity.kt
  17. 9 0
      app/src/main/res/drawable-land/bg_job_execute_step.xml
  18. 1 1
      app/src/main/res/drawable/bg_card_item_land.xml
  19. 2 3
      app/src/main/res/layout-land/activity_login.xml
  20. 1 1
      app/src/main/res/layout-land/activity_main.xml
  21. 10 10
      app/src/main/res/layout-land/dialog_login.xml
  22. 3 2
      app/src/main/res/layout-land/fragment_create_job.xml
  23. 3 2
      app/src/main/res/layout-land/fragment_create_sop.xml
  24. 1 0
      app/src/main/res/layout-land/fragment_create_sop_job.xml
  25. 3 2
      app/src/main/res/layout-land/fragment_edit_job.xml
  26. 393 0
      app/src/main/res/layout-land/fragment_edit_sop.xml
  27. 389 0
      app/src/main/res/layout-land/fragment_edit_sop_job.xml
  28. 1 1
      app/src/main/res/layout-land/fragment_home.xml
  29. 246 0
      app/src/main/res/layout-land/fragment_job_execute.xml
  30. 2 0
      app/src/main/res/layout-land/fragment_select_memeber.xml
  31. 62 0
      app/src/main/res/layout-land/item_job_execute_point.xml
  32. 54 0
      app/src/main/res/layout-land/item_job_execute_step.xml
  33. 31 37
      app/src/main/res/layout-land/item_login_method.xml
  34. 1 1
      app/src/main/res/layout/activity_main.xml
  35. 19 5
      app/src/main/res/layout/dialog_drop_down_list.xml
  36. 10 10
      app/src/main/res/layout/dialog_login.xml
  37. 2 2
      app/src/main/res/layout/fragment_create_job.xml
  38. 2 2
      app/src/main/res/layout/fragment_create_sop.xml
  39. 2 2
      app/src/main/res/layout/fragment_edit_job.xml
  40. 2 2
      app/src/main/res/layout/fragment_edit_sop.xml
  41. 1 1
      app/src/main/res/layout/fragment_home.xml
  42. 6 6
      app/src/main/res/layout/fragment_job_execute.xml
  43. 1 0
      app/src/main/res/layout/fragment_select_memeber.xml
  44. 1 1
      app/src/main/res/layout/item_job_execute_point.xml
  45. 6 6
      app/src/main/res/layout/item_job_execute_step.xml
  46. 3 2
      app/src/main/res/values-en/strings.xml
  47. 19 6
      app/src/main/res/values-land/dimens.xml
  48. 3 2
      app/src/main/res/values-zh/strings.xml
  49. 15 2
      app/src/main/res/values/dimens.xml
  50. 4 3
      app/src/main/res/values/strings.xml
  51. 26 1
      data/src/main/java/com/grkj/data/dao/HardwareDao.kt
  52. 12 0
      data/src/main/java/com/grkj/data/dao/IsolationPointDao.kt
  53. 74 7
      data/src/main/java/com/grkj/data/dao/JobTicketDao.kt
  54. 6 0
      data/src/main/java/com/grkj/data/data/MainDomainData.kt
  55. 4 1
      data/src/main/java/com/grkj/data/model/dos/IsJobTicketKey.kt
  56. 11 7
      data/src/main/java/com/grkj/data/model/res/KeyInfoRes.kt
  57. 12 7
      data/src/main/java/com/grkj/data/model/res/LockInfoRes.kt
  58. 10 6
      data/src/main/java/com/grkj/data/model/res/StepDetailRes.kt
  59. 129 104
      data/src/main/java/com/grkj/data/model/res/TicketDetailRes.kt
  60. 1 1
      data/src/main/java/com/grkj/data/model/vo/AddUserDataVo.kt
  61. 3 1
      data/src/main/java/com/grkj/data/model/vo/IsJobTicketLockDataVo.kt
  62. 111 0
      data/src/main/java/com/grkj/data/model/vo/IsJobTicketPointsVo.kt
  63. 120 0
      data/src/main/java/com/grkj/data/model/vo/PointDetailVO.kt
  64. 6 0
      data/src/main/java/com/grkj/data/repository/IJobTicketRepository.kt
  65. 13 11
      data/src/main/java/com/grkj/data/repository/impl/HardwareRepository.kt
  66. 79 5
      data/src/main/java/com/grkj/data/repository/impl/JobTicketRepository.kt
  67. 2 0
      data/src/main/java/com/grkj/data/repository/impl/UserRepository.kt
  68. 23 9
      shared/src/main/java/com/grkj/shared/config/Constants.kt
  69. 5 6
      ui-base/src/main/java/com/grkj/ui_base/base/BaseActivity.kt
  70. 2 2
      ui-base/src/main/java/com/grkj/ui_base/base/BaseFragment.kt
  71. 78 50
      ui-base/src/main/java/com/grkj/ui_base/business/BleBusinessManager.kt
  72. 12 4
      ui-base/src/main/java/com/grkj/ui_base/business/DataBusiness.kt
  73. 32 6
      ui-base/src/main/java/com/grkj/ui_base/business/ModbusBusinessManager.kt
  74. 5 0
      ui-base/src/main/java/com/grkj/ui_base/config/ISCSConfig.kt
  75. 47 30
      ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConnectionManager.kt
  76. 1 1
      ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConst.kt
  77. 1 0
      ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleUtil.kt
  78. 1 1
      ui-base/src/main/java/com/grkj/ui_base/utils/event/LoadingEvent.kt
  79. 6 10
      ui-base/src/main/java/com/grkj/ui_base/utils/extension/Context.kt
  80. 3 2
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/DockBean.kt
  81. 33 18
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusController.kt
  82. 1 2
      ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusManager.kt
  83. 6 6
      ui-base/src/main/res/layout-land/common_dialog_loading_progress.xml

+ 1 - 1
app/src/main/assets/logback.xml

@@ -34,7 +34,7 @@
     </logger>
 
     <!-- 根日志器,默认级别为 INFO -->
-    <root level="INFO">
+    <root level="DEBUG">
         <appender-ref ref="FILE" />
         <appender-ref ref="LOGCAT" />
     </root>

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

@@ -1,6 +1,5 @@
 package com.grkj.iscs
 
-import android.R
 import android.app.Application
 import android.content.Context
 import com.grkj.data.data.EventConstants
@@ -23,6 +22,7 @@ import com.sik.sikcore.SIKCore
 import com.sik.sikcore.thread.ThreadUtils
 import dagger.hilt.android.HiltAndroidApp
 import kotlinx.coroutines.delay
+import me.jessyan.autosize.AutoSizeConfig
 import org.greenrobot.eventbus.EventBus
 import org.greenrobot.eventbus.Subscribe
 import org.greenrobot.eventbus.ThreadMode
@@ -50,6 +50,7 @@ class ISCSApplication : Application() {
             EventBus.getDefault().register(this)
         }
         BleUtil.instance?.initBle(this)
+        AutoSizeConfig.getInstance().isCustomFragment = true
         ThreadUtils.runOnIO {
             ModbusBusinessManager.registerMainListener()
             RepositoryManager.init(this@ISCSApplication)

+ 29 - 6
app/src/main/java/com/grkj/iscs/features/init/viewmodel/InitDeviceRegistrationKeyAndLockViewModel.kt

@@ -133,7 +133,7 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
     /**
      * 打开充电并扫描蓝牙
      */
-    suspend fun openChargeAndScanMac(addr: Byte, keyBean: DockBean.KeyBean): Boolean {
+    suspend fun openChargeAndScanMac(addr: Byte, keyBean: DockBean.KeyBean,retryCount: Int = 3): Boolean {
         return suspendCancellableCoroutine<Boolean> { cont ->
             logger.info("设备录入-关闭充电:${addr},${keyBean.idx}")
             ModBusController.controlKeyCharge(false, keyBean.idx, addr) {
@@ -151,17 +151,34 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
                                     }"
                                 )
                                 if (isDestroy) {
+                                    logger.info(
+                                        "设备录入-界面已销毁"
+                                    )
                                     cont.cancel()
                                     return@scanOnlineKeyLockMac
                                 }
                                 if (bleDevice == null) {
+                                    logger.info(
+                                        "设备录入-设备空:${keyBean.rfid}"
+                                    )
                                     ThreadUtils.runOnIO {
-                                        openChargeAndScanMac(addr, keyBean)
+                                        if (retryCount>0){
+                                            openChargeAndScanMac(addr, keyBean,retryCount-1)
+                                        }else{
+                                            cont.resume(false)
+                                        }
                                     }
                                 } else {
                                     if (bleDevice.mac == null) {
+                                        logger.info(
+                                            "设备录入-设备mac空:${keyBean.rfid}"
+                                        )
                                         ThreadUtils.runOnIO {
-                                            openChargeAndScanMac(addr, keyBean)
+                                            if (retryCount>0){
+                                                openChargeAndScanMac(addr, keyBean,retryCount-1)
+                                            }else{
+                                                cont.resume(false)
+                                            }
                                         }
                                         return@scanOnlineKeyLockMac
                                     }
@@ -172,7 +189,9 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
                                     )
                                     keyBean.mac = bleDevice.mac
                                     alreadyUsedMac.add(bleDevice.mac)
-                                    cont.resume(true)
+                                    if (cont.isActive) {
+                                        cont.resume(true)
+                                    }
                                 }
                             }
                         }
@@ -195,7 +214,9 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
     private suspend fun deviceInputKeySuspend(keyNfc: String, keyMacAddress: String): Boolean {
         return suspendCancellableCoroutine<Boolean> { cont ->
             hardwareRepository.saveKeyInfo(keyNfc, keyMacAddress)
-            cont.resume(true)
+            if (cont.isActive) {
+                cont.resume(true)
+            }
         }
     }
 
@@ -205,7 +226,9 @@ class InitDeviceRegistrationKeyAndLockViewModel @Inject constructor(val hardware
     private suspend fun deviceInputLockSuspend(cardNo: String): Boolean {
         return suspendCancellableCoroutine<Boolean> { cont ->
             hardwareRepository.saveLockInfo(cardNo)
-            cont.resume(true)
+            if (cont.isActive) {
+                cont.resume(true)
+            }
         }
     }
 

+ 1 - 0
app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt

@@ -146,6 +146,7 @@ class MainActivity() : BaseActivity<ActivityMainBinding>() {
     override fun initData() {
         super.initData()
         viewModel.bleIndicate()
+        viewModel.registerStatusListener()
     }
 
     override fun dispatchKeyEvent(event: KeyEvent): Boolean {

+ 15 - 2
app/src/main/java/com/grkj/iscs/features/main/dialog/TextDropDownDialog.kt

@@ -3,6 +3,7 @@ package com.grkj.iscs.features.main.dialog
 import android.view.Gravity
 import android.view.View
 import androidx.core.view.isVisible
+import androidx.core.widget.addTextChangedListener
 import com.drake.brv.BindingAdapter
 import com.drake.brv.utils.linear
 import com.drake.brv.utils.models
@@ -23,6 +24,7 @@ import com.kongzue.dialogx.interfaces.OnBindView
 class TextDropDownDialog(
     private val dataList: List<TextDropDownEntity>,
     private val multiSelect: Boolean,
+    private val showSearchView: Boolean = false,
     private val onSelect: (TextDropDownEntity) -> Unit,
     private val onMultiSelect: (List<TextDropDownEntity>?) -> Unit
 ) : OnBindView<CustomDialog>(R.layout.dialog_drop_down_list) {
@@ -31,6 +33,11 @@ class TextDropDownDialog(
 
     override fun onBind(dialog: CustomDialog?, v: View) {
         binding = DialogDropDownListBinding.bind(v)
+        binding.searchKey.isVisible = showSearchView
+        binding.searchKey.addTextChangedListener(onTextChanged = { text, _, _, _ ->
+            binding.dropDownRv.models =
+                dataList.filter { it.getShowText().contains(text.toString()) }
+        })
         binding.dropDownRv.linear().setup {
             addType<TextDropDownEntity>(R.layout.item_home_text_drop_down)
             onBind {
@@ -64,10 +71,11 @@ class TextDropDownDialog(
         fun showSingle(
             data: List<TextDropDownEntity>,
             view: View,
+            showSearchView: Boolean = false,
             onSelect: (TextDropDownEntity) -> Unit
         ) {
             CustomDialog.show(
-                TextDropDownDialog(data, false, onSelect) { }
+                TextDropDownDialog(data, false, showSearchView, onSelect) { }
             ).setAlignBaseViewGravity(view, Gravity.BOTTOM or Gravity.CENTER).setWidth(view.width)
         }
 
@@ -78,10 +86,15 @@ class TextDropDownDialog(
         fun showMulti(
             data: List<TextDropDownEntity>,
             view: View,
+            showSearchView: Boolean = false,
             onMultiSelect: (List<TextDropDownEntity>?) -> Unit
         ) {
             CustomDialog.show(
-                TextDropDownDialog(data, true, {}) { selected -> onMultiSelect(selected) }
+                TextDropDownDialog(data, true, showSearchView, {}) { selected ->
+                    onMultiSelect(
+                        selected
+                    )
+                }
             ).setAlignBaseViewGravity(view, Gravity.BOTTOM or Gravity.CENTER).setWidth(view.width)
         }
     }

+ 4 - 4
app/src/main/java/com/grkj/iscs/features/main/dialog/data_manage/AddUserDialog.kt

@@ -78,10 +78,10 @@ class AddUserDialog(
             PopTip.build().tipDialog(R.string.please_input_nickname)
             return false
         }
-        if (binding.cardcodeEt.text.isNullOrBlank()) {
-            PopTip.build().tipDialog(R.string.please_input_card_code)
-            return false
-        }
+//        if (binding.cardcodeEt.text.isNullOrBlank()) {
+//            PopTip.build().tipDialog(R.string.please_input_card_code)
+//            return false
+//        }
         if (selectedRoles.isEmpty()) {
             PopTip.build().tipDialog(R.string.please_select_role)
             return false

+ 3 - 3
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/CreateJobFragment.kt

@@ -135,7 +135,7 @@ class CreateJobFragment : BaseFragment<FragmentCreateJobBinding>() {
                 return@setDebouncedClickListener
             }
             if (selectedLockMode == null) {
-                PopTip.tip(R.string.please_select_lock_mode)
+                PopTip.tip(R.string.please_select_flow_mode)
                 return@setDebouncedClickListener
             }
             GlobalDataTempStore.getInstance().saveData(
@@ -201,7 +201,7 @@ class CreateJobFragment : BaseFragment<FragmentCreateJobBinding>() {
                 return@setDebouncedClickListener
             }
             if (selectedLockMode == null) {
-                PopTip.tip(R.string.please_select_lock_mode)
+                PopTip.tip(R.string.please_select_flow_mode)
                 return@setDebouncedClickListener
             }
             GlobalDataTempStore.getInstance().saveData(
@@ -349,7 +349,7 @@ class CreateJobFragment : BaseFragment<FragmentCreateJobBinding>() {
             return false
         }
         if (selectedLockMode == null) {
-            PopTip.tip(R.string.please_select_lock_mode)
+            PopTip.tip(R.string.please_select_flow_mode)
             return false
         }
         if (binding.jobNameEt.text.isEmpty()) {

+ 3 - 3
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/CreateSopFragment.kt

@@ -116,7 +116,7 @@ class CreateSopFragment : BaseFragment<FragmentCreateSopBinding>() {
                 return@setDebouncedClickListener
             }
             if (selectedLockMode == null) {
-                PopTip.tip(R.string.please_select_lock_mode)
+                PopTip.tip(R.string.please_select_flow_mode)
                 return@setDebouncedClickListener
             }
             GlobalDataTempStore.getInstance().saveData(
@@ -182,7 +182,7 @@ class CreateSopFragment : BaseFragment<FragmentCreateSopBinding>() {
                 return@setDebouncedClickListener
             }
             if (selectedLockMode == null) {
-                PopTip.tip(R.string.please_select_lock_mode)
+                PopTip.tip(R.string.please_select_flow_mode)
                 return@setDebouncedClickListener
             }
             GlobalDataTempStore.getInstance().saveData(
@@ -287,7 +287,7 @@ class CreateSopFragment : BaseFragment<FragmentCreateSopBinding>() {
             return false
         }
         if (selectedLockMode == null) {
-            PopTip.tip(R.string.please_select_lock_mode)
+            PopTip.tip(R.string.please_select_flow_mode)
             return false
         }
         if (binding.sopNameEt.text.isEmpty()) {

+ 2 - 2
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/EditJobFragment.kt

@@ -130,7 +130,7 @@ class EditJobFragment : BaseFragment<FragmentEditJobBinding>() {
                 return@setDebouncedClickListener
             }
             if (selectedLockMode == null) {
-                PopTip.tip(R.string.please_select_lock_mode)
+                PopTip.tip(R.string.please_select_flow_mode)
                 return@setDebouncedClickListener
             }
             GlobalDataTempStore.getInstance().saveData(
@@ -244,7 +244,7 @@ class EditJobFragment : BaseFragment<FragmentEditJobBinding>() {
             return false
         }
         if (selectedLockMode == null) {
-            PopTip.tip(R.string.please_select_lock_mode)
+            PopTip.tip(R.string.please_select_flow_mode)
             return false
         }
         if (binding.jobNameEt.text.isEmpty()) {

+ 2 - 2
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/EditSopFragment.kt

@@ -118,7 +118,7 @@ class EditSopFragment : BaseFragment<FragmentEditSopBinding>() {
                 return@setDebouncedClickListener
             }
             if (selectedLockMode == null) {
-                PopTip.tip(R.string.please_select_lock_mode)
+                PopTip.tip(R.string.please_select_flow_mode)
                 return@setDebouncedClickListener
             }
             GlobalDataTempStore.getInstance().saveData(
@@ -205,7 +205,7 @@ class EditSopFragment : BaseFragment<FragmentEditSopBinding>() {
             return false
         }
         if (selectedLockMode == null) {
-            PopTip.tip(R.string.please_select_lock_mode)
+            PopTip.tip(R.string.please_select_flow_mode)
             return false
         }
         if (binding.sopNameEt.text.isEmpty()) {

+ 2 - 2
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/InProgressJobManageFragment.kt

@@ -82,8 +82,8 @@ class InProgressJobManageFragment : BaseFragment<FragmentInProgressJobManageBind
         }
     }
 
-    override fun initData() {
-        super.initData()
+    override fun onResume() {
+        super.onResume()
         getData(nextPage = false)
     }
 

+ 2 - 2
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobManageFragment.kt

@@ -137,8 +137,8 @@ class JobManageFragment : BaseFragment<FragmentJobManageBinding>() {
         }
     }
 
-    override fun initData() {
-        super.initData()
+    override fun onResume() {
+        super.onResume()
         getData(nextPage = false)
     }
 

+ 68 - 0
app/src/main/java/com/grkj/iscs/features/main/viewmodel/MainViewModel.kt

@@ -1,11 +1,21 @@
 package com.grkj.iscs.features.main.viewmodel
 
+import com.grkj.data.data.MainDomainData
+import com.grkj.iscs.R
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.business.BleBusinessManager
+import com.grkj.ui_base.business.ModbusBusinessManager
+import com.grkj.ui_base.config.ISCSConfig
+import com.grkj.ui_base.utils.CommonUtils
+import com.grkj.ui_base.utils.Executor
 import com.grkj.ui_base.utils.ble.BleBean
 import com.grkj.ui_base.utils.ble.BleConnectionManager
 import com.grkj.ui_base.utils.ble.BleIndicateListener
+import com.grkj.ui_base.utils.event.LoadingEvent
+import com.grkj.ui_base.utils.modbus.DeviceConst
+import com.sik.sikcore.thread.ThreadUtils
 import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.delay
 import javax.inject.Inject
 
 /**
@@ -29,4 +39,62 @@ class MainViewModel @Inject constructor() : BaseViewModel() {
 
         })
     }
+
+    fun registerStatusListener() {
+        ModbusBusinessManager.registerStatusListener(this) { dockBean ->
+            if (MainDomainData.userInfo == null || ISCSConfig.isDeviceRegistration) {
+                return@registerStatusListener
+            }
+            when (dockBean.type) {
+                DeviceConst.DOCK_TYPE_KEY -> {
+                    dockBean.getKeyList().forEach { keyBean ->
+                        if (keyBean.isExist) {
+                            Executor.repeatOnMain({
+                                keyBean.mac?.let { mac ->
+                                    ThreadUtils.runOnMain {
+                                        LoadingEvent.sendLoadingEvent(
+                                            CommonUtils.getStr(com.grkj.ui_base.R.string.loading_msg_return_key_start),
+                                            true
+                                        )
+                                    }
+                                    ThreadUtils.runOnIO {
+                                        suspend fun readJobTicket(mac: String) {
+                                            val isConnect =
+                                                BleConnectionManager.tryConnectWithOptionalCharge(
+                                                    mac
+                                                )
+                                            if (isConnect) {
+                                                val bleBean =
+                                                    BleConnectionManager.getBleDeviceByMac(mac)
+                                                Executor.delayOnMain(300) {
+                                                    bleBean?.let {
+                                                        LoadingEvent.sendLoadingEvent(
+                                                            CommonUtils.getStr(com.grkj.ui_base.R.string.loading_msg_get_ticket_status_start),
+                                                            true
+                                                        )
+                                                        BleConnectionManager.getCurrentStatus(
+                                                            4,
+                                                            it.bleDevice
+                                                        )
+                                                        BleConnectionManager.getBatteryPower(it.bleDevice)
+                                                    }
+                                                }
+                                            } else {
+                                                delay(500)
+                                                readJobTicket(mac)
+                                            }
+                                        }
+                                        if (!ISCSConfig.isDeviceRegistration) {
+                                            readJobTicket(mac)
+                                        }
+                                    }
+                                }
+                                return@repeatOnMain keyBean.mac == null
+                            }, 1000, true)
+                        }
+                    }
+                }
+            }
+        }
+    }
 }

+ 7 - 5
app/src/main/java/com/grkj/iscs/features/main/viewmodel/data_manage/UserManageViewModel.kt

@@ -76,11 +76,13 @@ class UserManageViewModel @Inject constructor(
                 workstationRepository.addUserWorkstationData(userId, it)
             }
             roleRepository.addUserRoleData(userId, userData.roleId)
-            hardwareRepository.addCard(
-                userId,
-                userData.cardCode,
-                userData.nickname
-            )
+            userData.cardCode?.let {
+                hardwareRepository.addCard(
+                    userId,
+                    it,
+                    userData.nickname
+                )
+            }
             emit(true)
         }
     }

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

@@ -122,7 +122,6 @@ class JobExecuteViewModel @Inject constructor(val jobTicketRepository: IJobTicke
                     ticketData.lockMode.toString()
                 ))
             }, true) { keyMap, lockMap ->
-                LoadingEvent.sendLoadingEvent()
                 if (lockMap.isEmpty()) {
                     TipDialog.show(
                         CommonUtils.getStr(com.grkj.ui_base.R.string.action_failed).toString(),
@@ -152,6 +151,10 @@ class JobExecuteViewModel @Inject constructor(val jobTicketRepository: IJobTicke
                         }
                     )
                     return@checkEquipCount
+                }else{
+                    ModbusBusinessManager.addDeviceTake(
+                        DeviceConst.DEVICE_TYPE_KEY, ticketId, keyMap.second?.rfid!!
+                    )
                 }
                 val waitOpenLockDockSize = lockMap.keys.size
                 val openedLockDockSize = AtomicInteger(0)
@@ -207,6 +210,11 @@ class JobExecuteViewModel @Inject constructor(val jobTicketRepository: IJobTicke
                         )
                         return@checkEquipCount
                     }
+                    ModbusBusinessManager.addDeviceTake(
+                        DeviceConst.DEVICE_TYPE_KEY,
+                        ticketId,
+                        keyMap.second?.rfid ?: ""
+                    )
                     val deviceTakeUpdate = DeviceTakeUpdate(
                         DeviceConst.DEVICE_TYPE_KEY,
                         ticketId,

+ 12 - 12
app/src/main/java/com/grkj/iscs/features/splash/activity/SplashActivity.kt

@@ -38,17 +38,17 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>() {
         DialogX.titleTextInfo = dialogXTextInfo
         StartModbusEvent.sendStartModbusEvent()
         //todo 测试用,直接进入,不初始化
-        startActivity(Intent(this, LoginActivity::class.java))
-        finish()
-//        viewModel.checkSysMenuAndRole().observe(this) {
-//            val isAppInit = MMKVConstants.APP_INIT.getMMKVData(false)
-//            if (isAppInit) {
-//                startActivity(Intent(this, LoginActivity::class.java))
-//                finish()
-//            } else {
-//                startActivity(Intent(this, InitActivity::class.java))
-//                finish()
-//            }
-//        }
+//        startActivity(Intent(this, LoginActivity::class.java))
+//        finish()
+        viewModel.checkSysMenuAndRole().observe(this) {
+            val isAppInit = MMKVConstants.APP_INIT.getMMKVData(false)
+            if (isAppInit) {
+                startActivity(Intent(this, LoginActivity::class.java))
+                finish()
+            } else {
+                startActivity(Intent(this, InitActivity::class.java))
+                finish()
+            }
+        }
     }
 }

+ 9 - 0
app/src/main/res/drawable-land/bg_job_execute_step.xml

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

+ 1 - 1
app/src/main/res/drawable/bg_card_item_land.xml

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

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

@@ -84,15 +84,14 @@
             <LinearLayout
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
-                android:layout_marginVertical="@dimen/common_spacing_2x"
-                android:gravity="center_vertical"
+                android:gravity="center"
                 android:orientation="vertical">
 
                 <androidx.recyclerview.widget.RecyclerView
                     android:id="@+id/login_type_rv"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:layout_gravity="center_horizontal" />
+                    tools:listitem="@layout/item_login_method" />
 
                 <LinearLayout
                     android:layout_width="wrap_content"

+ 1 - 1
app/src/main/res/layout-land/activity_main.xml

@@ -74,7 +74,7 @@
 
         <com.google.android.material.navigationrail.NavigationRailView
             android:id="@+id/navRail"
-            android:layout_width="@dimen/home_bottom_nav_height"
+            android:layout_width="@dimen/home_bottom_nav_size"
             android:layout_below="@+id/header_line"
             android:layout_height="match_parent"
             android:background="@color/white"

+ 10 - 10
app/src/main/res/layout-land/dialog_login.xml

@@ -3,8 +3,8 @@
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <com.google.android.material.card.MaterialCardView
-        android:layout_width="497dp"
-        android:layout_height="438dp"
+        android:layout_width="@dimen/login_dialog_width"
+        android:layout_height="@dimen/login_dialog_height"
         android:gravity="center"
         app:cardBackgroundColor="@color/dialog_card_login_bg"
         app:strokeColor="@color/common_transparent">
@@ -54,38 +54,38 @@
                 android:id="@+id/et_account"
                 style="@style/CommonEdit"
                 android:layout_width="match_parent"
-                android:layout_height="68dp"
+                android:layout_height="@dimen/login_dialog_input_height"
                 android:layout_marginBottom="@dimen/common_spacing"
                 android:hint="@string/please_input_account"
-                android:textSize="25sp" />
+                android:textSize="@dimen/login_dialog_text_size" />
 
             <EditText
                 android:id="@+id/et_password"
                 style="@style/CommonEdit"
                 android:layout_width="match_parent"
-                android:layout_height="68dp"
+                android:layout_height="@dimen/login_dialog_input_height"
                 android:layout_marginBottom="@dimen/common_spacing"
                 android:hint="@string/please_input_password"
                 android:inputType="textPassword"
-                android:textSize="25sp" />
+                android:textSize="@dimen/login_dialog_text_size" />
 
             <TextView
                 android:id="@+id/tv_login"
                 style="@style/CommonBtn"
                 android:layout_width="match_parent"
-                android:layout_height="60dp"
+                android:layout_height="@dimen/login_dialog_btn_height"
                 android:layout_marginBottom="@dimen/common_spacing"
                 android:text="@string/login"
-                android:textSize="25sp" />
+                android:textSize="@dimen/login_dialog_text_size" />
 
             <TextView
                 android:id="@+id/tv_cancel"
                 style="@style/CommonBtn"
                 android:layout_width="match_parent"
-                android:layout_height="60dp"
+                android:layout_height="@dimen/login_dialog_btn_height"
                 android:background="@drawable/white_stroke_bg"
                 android:text="@string/cancel"
-                android:textSize="25sp" />
+                android:textSize="@dimen/login_dialog_text_size" />
         </LinearLayout>
     </com.google.android.material.card.MaterialCardView>
 </layout>

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

@@ -51,6 +51,7 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_weight="1"
             android:orientation="horizontal">
 
             <LinearLayout
@@ -124,7 +125,7 @@
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:text="@string/lock_mode"
+                            android:text="@string/flow_mode"
                             android:textColor="@color/black"
                             android:textSize="@dimen/common_text_size" />
 
@@ -135,7 +136,7 @@
                             android:layout_marginLeft="@dimen/common_spacing"
                             android:background="@drawable/bg_common_input"
                             android:drawableRight="@drawable/icon_drop_down"
-                            android:hint="@string/please_select_lock_mode"
+                            android:hint="@string/please_select_flow_mode"
                             android:maxLines="1"
                             android:paddingHorizontal="@dimen/common_spacing"
                             android:paddingVertical="2dp"

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

@@ -51,6 +51,7 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_weight="1"
             android:orientation="horizontal">
 
             <LinearLayout
@@ -125,7 +126,7 @@
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:text="@string/lock_mode"
+                            android:text="@string/flow_mode"
                             android:textColor="@color/black"
                             android:textSize="@dimen/common_text_size" />
 
@@ -136,7 +137,7 @@
                             android:layout_marginLeft="@dimen/common_spacing"
                             android:background="@drawable/bg_common_input"
                             android:drawableRight="@drawable/icon_drop_down"
-                            android:hint="@string/please_select_lock_mode"
+                            android:hint="@string/please_select_flow_mode"
                             android:maxLines="1"
                             android:paddingHorizontal="@dimen/common_spacing"
                             android:paddingVertical="2dp"

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

@@ -51,6 +51,7 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_weight="1"
             android:orientation="horizontal">
 
             <LinearLayout

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

@@ -51,6 +51,7 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_weight="1"
             android:orientation="horizontal">
 
             <LinearLayout
@@ -125,7 +126,7 @@
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:text="@string/lock_mode"
+                            android:text="@string/flow_mode"
                             android:textColor="@color/black"
                             android:textSize="@dimen/common_text_size" />
 
@@ -136,7 +137,7 @@
                             android:layout_marginLeft="@dimen/common_spacing"
                             android:background="@drawable/bg_common_input"
                             android:drawableRight="@drawable/icon_drop_down"
-                            android:hint="@string/please_select_lock_mode"
+                            android:hint="@string/please_select_flow_mode"
                             android:maxLines="1"
                             android:paddingHorizontal="@dimen/common_spacing"
                             android:paddingVertical="2dp"

+ 393 - 0
app/src/main/res/layout-land/fragment_edit_sop.xml

@@ -0,0 +1,393 @@
+<?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="@dimen/common_spacing_2x"
+        android:background="@drawable/home_card_bg"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/title_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/common_spacing"
+            android:paddingVertical="@dimen/common_spacing_small">
+
+            <ImageView
+                android:layout_width="@dimen/common_spacing_2x"
+                android:layout_height="@dimen/common_spacing_2x"
+                android:src="@mipmap/icon_data_manage_menu_user_manage" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:layout_weight="1"
+                android:text="@string/edit_sop_title"
+                android:textColor="@color/black"
+                android:textSize="@dimen/normal_text_size_24" />
+
+            <TextView
+                android:id="@+id/back"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/common_btn"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/back"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/divider_line_space"
+            android:background="@color/black" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:orientation="horizontal">
+
+            <LinearLayout
+                android:id="@+id/base_info_layout"
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_marginHorizontal="@dimen/common_spacing"
+                android:layout_marginTop="@dimen/common_spacing"
+                android:layout_marginBottom="@dimen/common_spacing"
+                android:layout_weight="1"
+                android:background="@drawable/home_card_bg"
+                android:orientation="vertical">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="@dimen/common_spacing"
+                    android:text="@string/base_info_title"
+                    android:textColor="@color/black"
+                    android:textSize="@dimen/normal_text_size_24" />
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/divider_line_space"
+                    android:background="@color/black" />
+
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/common_spacing_2x"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/sop_workstation"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+
+                    <TextView
+                        android:id="@+id/workstation_tv"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="@dimen/common_spacing"
+                        android:background="@drawable/bg_common_input"
+                        android:drawableRight="@drawable/icon_drop_down"
+                        android:hint="@string/please_select_sop_workstation"
+                        android:maxLines="1"
+                        android:paddingHorizontal="@dimen/common_spacing"
+                        android:paddingVertical="2dp"
+                        android:singleLine="true"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/common_spacing_2x"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/flow_mode"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+
+                    <TextView
+                        android:id="@+id/lock_mode_tv"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="@dimen/common_spacing"
+                        android:background="@drawable/bg_common_input"
+                        android:drawableRight="@drawable/icon_drop_down"
+                        android:hint="@string/please_select_flow_mode"
+                        android:maxLines="1"
+                        android:paddingHorizontal="@dimen/common_spacing"
+                        android:paddingVertical="2dp"
+                        android:singleLine="true"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/common_spacing_2x"
+                    android:layout_marginBottom="@dimen/common_spacing_2x"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/create_sop_name"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+
+                    <EditText
+                        android:id="@+id/sop_name_et"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="@dimen/common_spacing"
+                        android:background="@drawable/bg_common_input"
+                        android:hint="@string/please_input_sop_name"
+                        android:maxLines="1"
+                        android:paddingHorizontal="@dimen/common_spacing"
+                        android:paddingVertical="2dp"
+                        android:singleLine="true"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+                </LinearLayout>
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:orientation="vertical">
+
+                <LinearLayout
+                    android:id="@+id/point_info_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_marginHorizontal="@dimen/common_spacing"
+                    android:layout_marginVertical="@dimen/common_spacing"
+                    android:layout_weight="1"
+                    android:background="@drawable/home_card_bg"
+                    android:gravity="center_vertical"
+                    android:orientation="vertical">
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="@dimen/common_spacing"
+                            android:layout_weight="1"
+                            android:text="@string/point_info_title"
+                            android:textColor="@color/black"
+                            android:textSize="@dimen/normal_text_size_24" />
+
+                        <TextView
+                            android:id="@+id/select_point_tv"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="@dimen/common_spacing"
+                            android:layout_marginRight="@dimen/common_spacing"
+                            android:background="@drawable/common_btn"
+                            android:paddingHorizontal="@dimen/common_spacing_2x"
+                            android:text="@string/select"
+                            android:textColor="@color/black"
+                            android:textSize="@dimen/common_btn_text_size" />
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/divider_line_space"
+                        android:background="@color/black" />
+
+
+                    <androidx.recyclerview.widget.RecyclerView
+                        android:id="@+id/point_rv"
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:paddingBottom="@dimen/common_spacing" />
+
+                </LinearLayout>
+
+                <LinearLayout
+                    android:id="@+id/member_info_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_marginHorizontal="@dimen/common_spacing"
+                    android:layout_marginVertical="@dimen/common_spacing"
+                    android:layout_weight="1"
+                    android:background="@drawable/home_card_bg"
+                    android:gravity="center_vertical"
+                    android:orientation="vertical">
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="@dimen/common_spacing"
+                            android:layout_weight="1"
+                            android:text="@string/member_info_title"
+                            android:textColor="@color/black"
+                            android:textSize="@dimen/normal_text_size_24" />
+
+                        <TextView
+                            android:id="@+id/select_member_tv"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="@dimen/common_spacing"
+                            android:layout_marginRight="@dimen/common_spacing"
+                            android:background="@drawable/common_btn"
+                            android:paddingHorizontal="@dimen/common_spacing_2x"
+                            android:text="@string/select"
+                            android:textColor="@color/black"
+                            android:textSize="@dimen/common_btn_text_size" />
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/divider_line_space"
+                        android:background="@color/black" />
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:gravity="center"
+                        android:orientation="horizontal">
+
+                        <LinearLayout
+                            android:layout_width="wrap_content"
+                            android:layout_height="match_parent"
+                            android:background="@drawable/home_card_bg"
+                            android:orientation="vertical">
+
+                            <TextView
+                                android:layout_width="wrap_content"
+                                android:layout_height="wrap_content"
+                                android:gravity="center"
+                                android:paddingHorizontal="@dimen/common_spacing_2x"
+                                android:paddingVertical="@dimen/common_spacing"
+                                android:text="@string/locker"
+                                android:textColor="@color/black"
+                                android:textSize="@dimen/normal_text_size_24" />
+
+                            <View
+                                android:layout_width="match_parent"
+                                android:layout_height="@dimen/divider_line_space"
+                                android:background="@color/black" />
+
+                            <LinearLayout
+                                android:layout_width="match_parent"
+                                android:layout_height="match_parent"
+                                android:gravity="center"
+                                android:orientation="vertical"
+                                android:paddingBottom="@dimen/common_spacing">
+
+                                <ImageView
+                                    android:layout_width="50dp"
+                                    android:layout_height="50dp"
+                                    android:layout_marginTop="@dimen/common_spacing"
+                                    android:src="@mipmap/icon_data_manage_menu_user_manage"
+                                    android:tint="@color/black" />
+
+                                <TextView
+                                    android:id="@+id/locker_name"
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:gravity="center"
+                                    android:textColor="@color/black"
+                                    android:textSize="@dimen/common_btn_text_size" />
+                            </LinearLayout>
+                        </LinearLayout>
+
+                        <LinearLayout
+                            android:id="@+id/select_colocker_layout"
+                            android:layout_width="match_parent"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/home_card_bg"
+                            android:orientation="vertical">
+
+                            <TextView
+                                android:layout_width="match_parent"
+                                android:layout_height="wrap_content"
+                                android:gravity="center"
+                                android:paddingHorizontal="@dimen/common_spacing_2x"
+                                android:paddingVertical="@dimen/common_spacing"
+                                android:text="@string/colocker"
+                                android:textColor="@color/black"
+                                android:textSize="@dimen/normal_text_size_24" />
+
+                            <View
+                                android:layout_width="match_parent"
+                                android:layout_height="@dimen/divider_line_space"
+                                android:background="@color/black" />
+
+                            <androidx.recyclerview.widget.RecyclerView
+                                android:id="@+id/colocker_rv"
+                                android:layout_width="wrap_content"
+                                android:layout_height="match_parent" />
+                        </LinearLayout>
+
+                    </LinearLayout>
+                </LinearLayout>
+            </LinearLayout>
+
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right"
+            android:orientation="horizontal"
+            android:padding="@dimen/common_spacing">
+
+            <TextView
+                android:id="@+id/confirm"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/common_btn"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/confirm"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+
+            <TextView
+                android:id="@+id/cancel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/common_btn"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/cancel"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+        </LinearLayout>
+    </LinearLayout>
+</layout>

+ 389 - 0
app/src/main/res/layout-land/fragment_edit_sop_job.xml

@@ -0,0 +1,389 @@
+<?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="@dimen/common_spacing_2x"
+        android:background="@drawable/home_card_bg"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/title_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/common_spacing"
+            android:paddingVertical="@dimen/common_spacing_small">
+
+            <ImageView
+                android:layout_width="@dimen/common_spacing_2x"
+                android:layout_height="@dimen/common_spacing_2x"
+                android:src="@mipmap/icon_data_manage_menu_user_manage" />
+
+            <TextView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:layout_weight="1"
+                android:text="@string/edit_sop_job_title"
+                android:textColor="@color/black"
+                android:textSize="@dimen/normal_text_size_24" />
+
+            <TextView
+                android:id="@+id/back"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/common_btn"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/back"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/divider_line_space"
+            android:background="@color/black" />
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:orientation="horizontal">
+
+            <LinearLayout
+                android:id="@+id/base_info_layout"
+                android:layout_width="0dp"
+                android:layout_weight="1"
+                android:layout_height="match_parent"
+                android:layout_marginHorizontal="@dimen/common_spacing"
+                android:layout_marginTop="@dimen/common_spacing"
+                android:layout_marginBottom="@dimen/common_spacing"
+                android:background="@drawable/home_card_bg"
+                android:orientation="vertical">
+
+                <TextView
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="@dimen/common_spacing"
+                    android:text="@string/base_info_title"
+                    android:textColor="@color/black"
+                    android:textSize="@dimen/normal_text_size_24" />
+
+                <View
+                    android:layout_width="match_parent"
+                    android:layout_height="@dimen/divider_line_space"
+                    android:background="@color/black" />
+
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/common_spacing_2x"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/sop_workstation"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+
+                    <TextView
+                        android:id="@+id/workstation_tv"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="@dimen/common_spacing"
+                        android:background="@drawable/bg_common_input"
+                        android:drawableRight="@drawable/icon_drop_down"
+                        android:hint="@string/please_select_sop_workstation"
+                        android:maxLines="1"
+                        android:paddingHorizontal="@dimen/common_spacing"
+                        android:paddingVertical="2dp"
+                        android:singleLine="true"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="36dp"
+                    android:layout_marginTop="@dimen/common_spacing_2x"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/create_sop_job_sop"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+
+                    <TextView
+                        android:id="@+id/sop_tv"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="@dimen/common_spacing"
+                        android:background="@drawable/bg_common_input"
+                        android:drawableRight="@drawable/icon_drop_down"
+                        android:hint="@string/please_select_sop"
+                        android:maxLines="1"
+                        android:paddingHorizontal="@dimen/common_spacing"
+                        android:paddingVertical="2dp"
+                        android:singleLine="true"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+                </LinearLayout>
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginTop="@dimen/common_spacing_2x"
+                    android:layout_marginBottom="@dimen/common_spacing_2x"
+                    android:gravity="center_vertical"
+                    android:orientation="horizontal"
+                    android:paddingHorizontal="@dimen/dialog_content_normal_padding_horizontal">
+
+                    <TextView
+                        android:layout_width="wrap_content"
+                        android:layout_height="wrap_content"
+                        android:text="@string/job_name"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+
+                    <EditText
+                        android:id="@+id/job_name_et"
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:layout_marginLeft="@dimen/common_spacing"
+                        android:background="@drawable/bg_common_input"
+                        android:hint="@string/please_input_job_name"
+                        android:maxLines="1"
+                        android:paddingHorizontal="@dimen/common_spacing"
+                        android:paddingVertical="2dp"
+                        android:singleLine="true"
+                        android:textColor="@color/black"
+                        android:textSize="@dimen/common_text_size" />
+                </LinearLayout>
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:orientation="vertical">
+
+                <LinearLayout
+                    android:id="@+id/point_info_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_marginHorizontal="@dimen/common_spacing"
+                    android:layout_marginVertical="@dimen/common_spacing"
+                    android:layout_weight="1"
+                    android:background="@drawable/home_card_bg"
+                    android:gravity="center_vertical"
+                    android:orientation="vertical">
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="@dimen/common_spacing"
+                            android:text="@string/point_info_title"
+                            android:textColor="@color/black"
+                            android:textSize="@dimen/normal_text_size_24" />
+
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/divider_line_space"
+                        android:background="@color/black" />
+
+                    <androidx.recyclerview.widget.RecyclerView
+                        android:id="@+id/point_rv"
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:paddingBottom="@dimen/common_spacing" />
+
+                </LinearLayout>
+
+                <LinearLayout
+                    android:id="@+id/member_info_layout"
+                    android:layout_width="match_parent"
+                    android:layout_height="0dp"
+                    android:layout_marginHorizontal="@dimen/common_spacing"
+                    android:layout_marginVertical="@dimen/common_spacing"
+                    android:layout_weight="1"
+                    android:background="@drawable/home_card_bg"
+                    android:gravity="center_vertical"
+                    android:orientation="vertical">
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="wrap_content"
+                        android:orientation="horizontal">
+
+                        <TextView
+                            android:layout_width="match_parent"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="@dimen/common_spacing"
+                            android:layout_weight="1"
+                            android:text="@string/member_info_title"
+                            android:textColor="@color/black"
+                            android:textSize="@dimen/normal_text_size_24" />
+
+                        <TextView
+                            android:id="@+id/select_member_tv"
+                            android:layout_width="wrap_content"
+                            android:layout_height="wrap_content"
+                            android:layout_marginLeft="@dimen/common_spacing"
+                            android:layout_marginRight="@dimen/common_spacing"
+                            android:background="@drawable/common_btn"
+                            android:paddingHorizontal="@dimen/common_spacing_2x"
+                            android:text="@string/select"
+                            android:textColor="@color/black"
+                            android:textSize="@dimen/common_btn_text_size" />
+                    </LinearLayout>
+
+                    <View
+                        android:layout_width="match_parent"
+                        android:layout_height="@dimen/divider_line_space"
+                        android:background="@color/black" />
+
+                    <LinearLayout
+                        android:layout_width="match_parent"
+                        android:layout_height="match_parent"
+                        android:gravity="center"
+                        android:orientation="horizontal">
+
+                        <LinearLayout
+                            android:layout_width="wrap_content"
+                            android:layout_height="match_parent"
+                            android:background="@drawable/home_card_bg"
+                            android:orientation="vertical">
+
+                            <TextView
+                                android:layout_width="wrap_content"
+                                android:layout_height="wrap_content"
+                                android:gravity="center"
+                                android:paddingHorizontal="@dimen/common_spacing_2x"
+                                android:paddingVertical="@dimen/common_spacing"
+                                android:text="@string/locker"
+                                android:textColor="@color/black"
+                                android:textSize="@dimen/normal_text_size_24" />
+
+                            <View
+                                android:layout_width="match_parent"
+                                android:layout_height="@dimen/divider_line_space"
+                                android:background="@color/black" />
+
+                            <LinearLayout
+                                android:layout_width="match_parent"
+                                android:layout_height="match_parent"
+                                android:gravity="center"
+                                android:orientation="vertical"
+                                android:paddingBottom="@dimen/common_spacing">
+
+                                <ImageView
+                                    android:layout_width="50dp"
+                                    android:layout_height="50dp"
+                                    android:layout_marginTop="@dimen/common_spacing"
+                                    android:src="@mipmap/icon_data_manage_menu_user_manage"
+                                    android:tint="@color/black" />
+
+                                <TextView
+                                    android:id="@+id/locker_name"
+                                    android:layout_width="wrap_content"
+                                    android:layout_height="wrap_content"
+                                    android:gravity="center"
+                                    android:textColor="@color/black"
+                                    android:textSize="@dimen/common_btn_text_size" />
+                            </LinearLayout>
+                        </LinearLayout>
+
+                        <LinearLayout
+                            android:id="@+id/select_colocker_layout"
+                            android:layout_width="match_parent"
+                            android:layout_height="match_parent"
+                            android:layout_weight="1"
+                            android:background="@drawable/home_card_bg"
+                            android:orientation="vertical">
+
+                            <TextView
+                                android:layout_width="match_parent"
+                                android:layout_height="wrap_content"
+                                android:gravity="center"
+                                android:paddingHorizontal="@dimen/common_spacing_2x"
+                                android:paddingVertical="@dimen/common_spacing"
+                                android:text="@string/colocker"
+                                android:textColor="@color/black"
+                                android:textSize="@dimen/normal_text_size_24" />
+
+                            <View
+                                android:layout_width="match_parent"
+                                android:layout_height="@dimen/divider_line_space"
+                                android:background="@color/black" />
+
+                            <androidx.recyclerview.widget.RecyclerView
+                                android:id="@+id/colocker_rv"
+                                android:layout_width="wrap_content"
+                                android:layout_height="match_parent" />
+                        </LinearLayout>
+
+                    </LinearLayout>
+                </LinearLayout>
+            </LinearLayout>
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right"
+            android:orientation="horizontal"
+            android:padding="@dimen/common_spacing">
+
+            <TextView
+                android:id="@+id/save_and_execute"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginRight="@dimen/common_spacing"
+                android:background="@drawable/common_btn"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/save_and_execute"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+
+            <TextView
+                android:id="@+id/save"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="@drawable/common_btn"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/save"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+
+            <TextView
+                android:id="@+id/cancel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginHorizontal="@dimen/common_spacing"
+                android:background="@drawable/common_btn"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/cancel"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+        </LinearLayout>
+    </LinearLayout>
+</layout>

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

@@ -104,7 +104,7 @@
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:text="@string/lock_mode"
+                            android:text="@string/flow_mode"
                             android:textColor="@color/black"
                             android:textSize="22sp" />
 

+ 246 - 0
app/src/main/res/layout-land/fragment_job_execute.xml

@@ -0,0 +1,246 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_margin="@dimen/common_spacing_2x"
+        android:background="@drawable/home_card_bg"
+        android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/title_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:paddingHorizontal="@dimen/common_spacing"
+            android:paddingVertical="@dimen/common_spacing_small">
+
+            <ImageView
+                android:layout_width="@dimen/common_spacing_2x"
+                android:layout_height="@dimen/common_spacing_2x"
+                android:src="@mipmap/icon_data_manage_menu_user_manage" />
+
+            <TextView
+                android:id="@+id/job_name_tv"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:layout_weight="1"
+                android:text="@string/job_manage_title"
+                android:textColor="@color/black"
+                android:textSize="@dimen/normal_text_size_24" />
+
+            <TextView
+                android:id="@+id/back"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/common_btn"
+                android:paddingHorizontal="@dimen/common_spacing_2x"
+                android:text="@string/back"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size" />
+        </LinearLayout>
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/divider_line_space"
+            android:background="@color/black" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/step_rv"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/step_rv_height"
+            android:layout_marginHorizontal="@dimen/common_spacing"
+            android:layout_marginTop="@dimen/common_spacing_2x" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/point_header_height"
+            android:layout_marginHorizontal="@dimen/common_spacing_2x"
+            android:layout_marginTop="@dimen/common_spacing"
+            android:background="@drawable/common_card_bg"
+            android:divider="@drawable/divider_table"
+            android:showDividers="middle">
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/point_name_tv"
+                android:textSize="@dimen/common_text_size" />
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/point_manage_point_function"
+                android:textSize="@dimen/common_text_size" />
+
+            <TextView
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_weight="1"
+                android:gravity="center"
+                android:text="@string/lock_status"
+                android:textSize="@dimen/common_text_size" />
+        </LinearLayout>
+
+        <com.grkj.iscs.view.MaxHeightRecyclerView
+            android:id="@+id/list_rv"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginHorizontal="@dimen/common_spacing_2x"
+            android:background="@drawable/common_card_bg"
+            app:maxHeight="@dimen/point_rv_height" />
+
+        <LinearLayout
+            android:id="@+id/colocker_layout"
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_marginHorizontal="@dimen/common_spacing_2x"
+            android:layout_marginTop="@dimen/common_spacing"
+            android:layout_marginBottom="@dimen/common_spacing"
+            android:layout_weight="1"
+            android:divider="@drawable/divider_table"
+            android:orientation="vertical"
+            android:showDividers="middle"
+            android:visibility="gone">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/colocker_layout_height"
+                android:background="@drawable/common_card_bg"
+                android:divider="@drawable/divider_table"
+                android:showDividers="middle">
+
+                <TextView
+                    android:id="@+id/wait_to_colock"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1"
+                    android:gravity="center"
+                    android:text="@string/wait_to_colock"
+                    android:textSize="@dimen/common_text_size" />
+
+                <TextView
+                    android:id="@+id/already_colock"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1"
+                    android:gravity="center"
+                    android:text="@string/already_colock"
+                    android:textSize="@dimen/common_text_size" />
+
+                <TextView
+                    android:id="@+id/already_uncolock"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:layout_weight="1"
+                    android:gravity="center"
+                    android:text="@string/already_uncolock"
+                    android:textSize="@dimen/common_text_size" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:background="@drawable/common_card_bg"
+                android:divider="@drawable/divider_table"
+                android:orientation="horizontal"
+                android:showDividers="middle">
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/wait_to_colock_rv"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:padding="@dimen/common_spacing"
+                    android:layout_weight="1" />
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/already_colock_rv"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:padding="@dimen/common_spacing"
+                    android:layout_weight="1" />
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/already_uncolock_rv"
+                    android:layout_width="0dp"
+                    android:layout_height="match_parent"
+                    android:padding="@dimen/common_spacing"
+                    android:layout_weight="1" />
+            </LinearLayout>
+        </LinearLayout>
+
+        <View
+            android:id="@+id/space_view"
+            android:layout_width="0dp"
+            android:layout_height="@dimen/divider_line_space"
+            android:layout_weight="1" />
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="right"
+            android:minHeight="@dimen/btn_layout_min_height"
+            android:orientation="horizontal"
+            android:padding="@dimen/common_spacing">
+
+            <TextView
+                android:id="@+id/to_lock"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/bg_btn_job_execute_go_locking"
+                android:drawableLeft="@drawable/icon_ticket_lock"
+                android:paddingHorizontal="@dimen/common_spacing"
+                android:text="@string/go_locking"
+                android:textColor="@color/white"
+                android:textSize="@dimen/common_btn_text_size"
+                android:visibility="gone" />
+
+            <TextView
+                android:id="@+id/to_unlock"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/bg_btn_job_execute_go_unlocking"
+                android:drawableLeft="@drawable/icon_ticket_unlock"
+                android:paddingHorizontal="@dimen/common_spacing"
+                android:text="@string/go_unlocking"
+                android:textColor="@color/white"
+                android:textSize="@dimen/common_btn_text_size"
+                android:visibility="gone" />
+
+            <TextView
+                android:id="@+id/cancel_job"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/bg_btn_job_execute_normal"
+                android:paddingHorizontal="@dimen/common_spacing"
+                android:text="@string/cancel_the_job"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size"
+                android:visibility="gone" />
+
+            <TextView
+                android:id="@+id/finish_job"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:background="@drawable/bg_btn_job_execute_normal"
+                android:paddingHorizontal="@dimen/common_spacing"
+                android:text="@string/finish_the_job"
+                android:textColor="@color/black"
+                android:textSize="@dimen/common_btn_text_size"
+                android:visibility="gone" />
+        </LinearLayout>
+    </LinearLayout>
+</layout>

+ 2 - 0
app/src/main/res/layout-land/fragment_select_memeber.xml

@@ -75,6 +75,7 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_weight="1"
             android:orientation="horizontal">
 
             <LinearLayout
@@ -196,6 +197,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="0dp"
                     android:layout_marginBottom="@dimen/common_spacing_2x"
+                    android:layout_marginTop="@dimen/common_spacing"
                     android:layout_weight="1"
                     android:background="@drawable/home_card_bg" />
             </LinearLayout>

+ 62 - 0
app/src/main/res/layout-land/item_job_execute_point.xml

@@ -0,0 +1,62 @@
+<?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="@dimen/point_header_height"
+        android:background="@drawable/common_card_bg"
+        android:divider="@drawable/divider_table"
+        android:showDividers="middle">
+
+        <TextView
+            android:id="@+id/point_name"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:text="@string/point_name_tv"
+            android:textSize="@dimen/common_text_size" />
+
+        <TextView
+            android:id="@+id/point_function"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:text="@string/point_manage_point_function"
+            android:textSize="@dimen/common_text_size" />
+
+        <FrameLayout
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1">
+
+            <LinearLayout
+                android:id="@+id/lock_status_layout"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:background="@drawable/bg_btn_job_execute_go_locking"
+                android:gravity="center"
+                android:orientation="horizontal"
+                android:paddingHorizontal="@dimen/common_spacing"
+                android:paddingVertical="2dp">
+
+                <ImageView
+                    android:id="@+id/lock_status_iv"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:src="@drawable/icon_ticket_lock" />
+
+                <TextView
+                    android:id="@+id/lock_status_tv"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginLeft="@dimen/common_spacing_small"
+                    android:text="@string/has_locked"
+                    android:textColor="@color/white"
+                    android:textSize="@dimen/common_text_size" />
+            </LinearLayout>
+        </FrameLayout>
+    </LinearLayout>
+</layout>

+ 54 - 0
app/src/main/res/layout-land/item_job_execute_step.xml

@@ -0,0 +1,54 @@
+<?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="wrap_content"
+        android:layout_height="wrap_content"
+        android:gravity="center"
+        android:orientation="horizontal">
+        <LinearLayout
+            android:id="@+id/step_layout"
+            android:layout_width="@dimen/step_item_width"
+            android:layout_height="@dimen/step_item_height"
+            android:layout_marginLeft="@dimen/common_spacing"
+            android:background="@drawable/bg_job_execute_step"
+            android:gravity="center"
+            android:orientation="vertical">
+
+            <ImageView
+                android:id="@+id/step_icon_iv"
+                android:layout_width="@dimen/step_item_icon_size"
+                android:layout_height="@dimen/step_item_icon_size"
+                android:layout_marginTop="@dimen/common_spacing" />
+
+            <TextView
+                android:id="@+id/step_name_tv"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginTop="@dimen/common_spacing"
+                android:gravity="center"
+                android:text="@string/point_name_tv"
+                android:textSize="@dimen/common_text_size" />
+
+            <TextView
+                android:id="@+id/step_index_tv"
+                android:layout_width="@dimen/step_item_index_size"
+                android:layout_height="@dimen/step_item_index_size"
+                android:layout_marginTop="@dimen/common_spacing"
+                android:background="@drawable/bg_job_execute_step_index"
+                android:gravity="center"
+                android:includeFontPadding="false"
+                android:padding="@dimen/common_spacing_small"
+                android:textSize="@dimen/common_text_size"
+                tools:text="1" />
+        </LinearLayout>
+
+        <ImageView
+            android:id="@+id/divider_iv"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="@dimen/common_spacing"
+            android:src="@drawable/icon_job_execute_arrow_right"/>
+    </LinearLayout>
+
+</layout>

+ 31 - 37
app/src/main/res/layout-land/item_login_method.xml

@@ -1,44 +1,38 @@
 <?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">
+    <RelativeLayout
+        android:layout_width="@dimen/login_method_item_layout_width"
+        android:layout_height="@dimen/login_method_item_layout_height"
+        android:background="@drawable/bg_card_item_land">
 
-        <RelativeLayout
-            android:layout_width="@dimen/login_method_item_layout_width"
-            android:layout_height="@dimen/login_method_item_layout_height"
-            android:layout_gravity="center"
-            android:background="@drawable/bg_card_item_land">
+        <View
+            android:id="@+id/login_tip_v"
+            android:layout_width="@dimen/common_spacing"
+            android:layout_height="@dimen/common_spacing"
+            android:layout_alignParentRight="true"
+            android:layout_marginTop="@dimen/item_login_tip_v_margin_top"
+            android:layout_marginRight="@dimen/item_login_tip_v_margin_right"
+            android:background="@drawable/login_tip_circle"
+            android:visibility="gone" />
 
-            <View
-                android:id="@+id/login_tip_v"
-                android:layout_width="@dimen/common_spacing"
-                android:layout_height="@dimen/common_spacing"
-                android:layout_alignParentRight="true"
-                android:layout_marginTop="@dimen/item_login_tip_v_margin_top"
-                android:layout_marginRight="@dimen/item_login_tip_v_margin_right"
-                android:background="@drawable/login_tip_circle"
-                android:visibility="gone" />
+        <ImageView
+            android:id="@+id/login_method_iv"
+            android:layout_width="@dimen/login_method_item_iv_size"
+            android:layout_height="@dimen/login_method_item_iv_size"
+            android:layout_centerHorizontal="true"
+            android:layout_marginTop="@dimen/login_method_item_iv_margin"
+            android:adjustViewBounds="false"
+            android:scaleType="center"/>
 
-            <ImageView
-                android:id="@+id/login_method_iv"
-                android:layout_width="@dimen/login_method_item_iv_size"
-                android:layout_height="@dimen/login_method_item_iv_size"
-                android:layout_centerHorizontal="true"
-                android:layout_marginTop="@dimen/login_method_item_iv_margin"
-                android:adjustViewBounds="false"
-                android:scaleType="center"/>
-
-            <TextView
-                android:id="@+id/login_method_tv"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@+id/login_method_iv"
-                android:layout_marginTop="@dimen/common_spacing_2x"
-                android:gravity="center_horizontal"
-                android:textColor="@color/login_method_tv_color"
-                android:textSize="@dimen/login_method_item_tv_text_size" />
-        </RelativeLayout>
-    </FrameLayout>
+        <TextView
+            android:id="@+id/login_method_tv"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_below="@+id/login_method_iv"
+            android:layout_marginTop="@dimen/common_spacing_2x"
+            android:gravity="center_horizontal"
+            android:textColor="@color/login_method_tv_color"
+            android:textSize="@dimen/login_method_item_tv_text_size" />
+    </RelativeLayout>
 </layout>

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

@@ -77,7 +77,7 @@
         <com.google.android.material.bottomnavigation.BottomNavigationView
             android:id="@+id/bottom_nav"
             android:layout_width="match_parent"
-            android:layout_height="@dimen/home_bottom_nav_height"
+            android:layout_height="@dimen/home_bottom_nav_size"
             android:layout_alignParentBottom="true"
             android:layout_gravity="bottom"
             android:background="@color/white"

+ 19 - 5
app/src/main/res/layout/dialog_drop_down_list.xml

@@ -1,14 +1,28 @@
 <?xml version="1.0" encoding="utf-8"?>
 <layout xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <FrameLayout
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="wrap_content">
+        android:layout_height="wrap_content"
+        android:background="@drawable/bg_text_drop_down"
+        android:orientation="vertical">
+
+        <EditText
+            android:id="@+id/search_key"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_margin="@dimen/common_spacing"
+            android:background="@drawable/bg_common_input"
+            android:hint="@string/please_input_key_word"
+            android:maxLines="1"
+            android:paddingHorizontal="@dimen/common_spacing"
+            android:singleLine="true"
+            android:textSize="@dimen/common_text_size"
+            android:visibility="gone" />
 
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/drop_down_rv"
             android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:background="@drawable/bg_text_drop_down" />
-    </FrameLayout>
+            android:layout_height="wrap_content" />
+    </LinearLayout>
 </layout>

+ 10 - 10
app/src/main/res/layout/dialog_login.xml

@@ -3,8 +3,8 @@
     xmlns:app="http://schemas.android.com/apk/res-auto">
 
     <com.google.android.material.card.MaterialCardView
-        android:layout_width="497dp"
-        android:layout_height="438dp"
+        android:layout_width="@dimen/login_dialog_width"
+        android:layout_height="@dimen/login_dialog_height"
         android:gravity="center"
         app:cardBackgroundColor="@color/dialog_card_login_bg"
         app:strokeColor="@color/common_transparent">
@@ -54,38 +54,38 @@
                 android:id="@+id/et_account"
                 style="@style/CommonEdit"
                 android:layout_width="match_parent"
-                android:layout_height="68dp"
+                android:layout_height="@dimen/login_dialog_input_height"
                 android:layout_marginBottom="@dimen/common_spacing"
                 android:hint="@string/please_input_account"
-                android:textSize="25sp" />
+                android:textSize="@dimen/login_dialog_text_size" />
 
             <EditText
                 android:id="@+id/et_password"
                 style="@style/CommonEdit"
                 android:layout_width="match_parent"
-                android:layout_height="68dp"
+                android:layout_height="@dimen/login_dialog_input_height"
                 android:layout_marginBottom="@dimen/common_spacing"
                 android:hint="@string/please_input_password"
                 android:inputType="textPassword"
-                android:textSize="25sp" />
+                android:textSize="@dimen/login_dialog_text_size" />
 
             <TextView
                 android:id="@+id/tv_login"
                 style="@style/CommonBtn"
                 android:layout_width="match_parent"
-                android:layout_height="60dp"
+                android:layout_height="@dimen/login_dialog_btn_height"
                 android:layout_marginBottom="@dimen/common_spacing"
                 android:text="@string/login"
-                android:textSize="25sp" />
+                android:textSize="@dimen/login_dialog_text_size" />
 
             <TextView
                 android:id="@+id/tv_cancel"
                 style="@style/CommonBtn"
                 android:layout_width="match_parent"
-                android:layout_height="60dp"
+                android:layout_height="@dimen/login_dialog_btn_height"
                 android:background="@drawable/white_stroke_bg"
                 android:text="@string/cancel"
-                android:textSize="25sp" />
+                android:textSize="@dimen/login_dialog_text_size" />
         </LinearLayout>
     </com.google.android.material.card.MaterialCardView>
 </layout>

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

@@ -116,7 +116,7 @@
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/lock_mode"
+                    android:text="@string/flow_mode"
                     android:textColor="@color/black"
                     android:textSize="@dimen/common_text_size" />
 
@@ -127,7 +127,7 @@
                     android:layout_marginLeft="@dimen/common_spacing"
                     android:background="@drawable/bg_common_input"
                     android:drawableRight="@drawable/icon_drop_down"
-                    android:hint="@string/please_select_lock_mode"
+                    android:hint="@string/please_select_flow_mode"
                     android:maxLines="1"
                     android:paddingHorizontal="@dimen/common_spacing"
                     android:paddingVertical="2dp"

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

@@ -116,7 +116,7 @@
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/lock_mode"
+                    android:text="@string/flow_mode"
                     android:textColor="@color/black"
                     android:textSize="@dimen/common_text_size" />
 
@@ -127,7 +127,7 @@
                     android:layout_marginLeft="@dimen/common_spacing"
                     android:background="@drawable/bg_common_input"
                     android:drawableRight="@drawable/icon_drop_down"
-                    android:hint="@string/please_select_lock_mode"
+                    android:hint="@string/please_select_flow_mode"
                     android:maxLines="1"
                     android:paddingHorizontal="@dimen/common_spacing"
                     android:paddingVertical="2dp"

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

@@ -119,7 +119,7 @@
                     <TextView
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
-                        android:text="@string/lock_mode"
+                        android:text="@string/flow_mode"
                         android:textColor="@color/black"
                         android:textSize="@dimen/common_text_size" />
 
@@ -130,7 +130,7 @@
                         android:layout_marginLeft="@dimen/common_spacing"
                         android:background="@drawable/bg_common_input"
                         android:drawableRight="@drawable/icon_drop_down"
-                        android:hint="@string/please_select_lock_mode"
+                        android:hint="@string/please_select_flow_mode"
                         android:maxLines="1"
                         android:paddingHorizontal="@dimen/common_spacing"
                         android:paddingVertical="2dp"

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

@@ -116,7 +116,7 @@
                 <TextView
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:text="@string/lock_mode"
+                    android:text="@string/flow_mode"
                     android:textColor="@color/black"
                     android:textSize="@dimen/common_text_size" />
 
@@ -127,7 +127,7 @@
                     android:layout_marginLeft="@dimen/common_spacing"
                     android:background="@drawable/bg_common_input"
                     android:drawableRight="@drawable/icon_drop_down"
-                    android:hint="@string/please_select_lock_mode"
+                    android:hint="@string/please_select_flow_mode"
                     android:maxLines="1"
                     android:paddingHorizontal="@dimen/common_spacing"
                     android:paddingVertical="2dp"

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

@@ -104,7 +104,7 @@
                         <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
-                            android:text="@string/lock_mode"
+                            android:text="@string/flow_mode"
                             android:textColor="@color/black"
                             android:textSize="22sp" />
 

+ 6 - 6
app/src/main/res/layout/fragment_job_execute.xml

@@ -53,13 +53,13 @@
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/step_rv"
             android:layout_width="match_parent"
-            android:layout_height="190dp"
+            android:layout_height="@dimen/step_rv_height"
             android:layout_marginHorizontal="@dimen/common_spacing"
-            android:layout_marginTop="30dp" />
+            android:layout_marginTop="@dimen/common_spacing_2x" />
 
         <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="50dp"
+            android:layout_height="@dimen/point_header_height"
             android:layout_marginHorizontal="@dimen/common_spacing_2x"
             android:layout_marginTop="@dimen/common_spacing"
             android:background="@drawable/common_card_bg"
@@ -97,7 +97,7 @@
             android:layout_height="wrap_content"
             android:layout_marginHorizontal="@dimen/common_spacing_2x"
             android:background="@drawable/common_card_bg"
-            app:maxHeight="240dp" />
+            app:maxHeight="@dimen/point_rv_height" />
 
         <LinearLayout
             android:id="@+id/colocker_layout"
@@ -114,7 +114,7 @@
 
             <LinearLayout
                 android:layout_width="match_parent"
-                android:layout_height="50dp"
+                android:layout_height="@dimen/colocker_layout_height"
                 android:background="@drawable/common_card_bg"
                 android:divider="@drawable/divider_table"
                 android:showDividers="middle">
@@ -188,7 +188,7 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:gravity="right"
-            android:minHeight="60dp"
+            android:minHeight="@dimen/btn_layout_min_height"
             android:orientation="horizontal"
             android:padding="@dimen/common_spacing">
 

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

@@ -75,6 +75,7 @@
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_weight="1"
             android:orientation="vertical">
 
             <LinearLayout

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

@@ -3,7 +3,7 @@
 
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="50dp"
+        android:layout_height="@dimen/point_header_height"
         android:background="@drawable/common_card_bg"
         android:divider="@drawable/divider_table"
         android:showDividers="middle">

+ 6 - 6
app/src/main/res/layout/item_job_execute_step.xml

@@ -8,8 +8,8 @@
         android:orientation="horizontal">
         <LinearLayout
             android:id="@+id/step_layout"
-            android:layout_width="120dp"
-            android:layout_height="180dp"
+            android:layout_width="@dimen/step_item_width"
+            android:layout_height="@dimen/step_item_height"
             android:layout_marginLeft="@dimen/common_spacing"
             android:background="@drawable/bg_job_execute_step"
             android:gravity="center"
@@ -17,8 +17,8 @@
 
             <ImageView
                 android:id="@+id/step_icon_iv"
-                android:layout_width="70dp"
-                android:layout_height="70dp"
+                android:layout_width="@dimen/step_item_icon_size"
+                android:layout_height="@dimen/step_item_icon_size"
                 android:layout_marginTop="@dimen/common_spacing" />
 
             <TextView
@@ -32,8 +32,8 @@
 
             <TextView
                 android:id="@+id/step_index_tv"
-                android:layout_width="30dp"
-                android:layout_height="30dp"
+                android:layout_width="@dimen/step_item_index_size"
+                android:layout_height="@dimen/step_item_index_size"
                 android:layout_marginTop="@dimen/common_spacing"
                 android:background="@drawable/bg_job_execute_step_index"
                 android:gravity="center"

+ 3 - 2
app/src/main/res/values-en/strings.xml

@@ -9,7 +9,7 @@
     <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="flow_mode">Flow 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>
@@ -90,7 +90,7 @@
     <string name="point_info_title">Point info</string>
     <string name="member_info_title">Member info</string>
     <string name="please_select_sop_workstation">please select sop workstation</string>
-    <string name="please_select_lock_mode">please select lock mode</string>
+    <string name="please_select_flow_mode">please select flow mode</string>
     <string name="please_input_sop_name">please input sop name</string>
     <string name="please_select_member">please select member</string>
     <string name="please_must_select_at_least_one_point">You need to add at least one point</string>
@@ -324,5 +324,6 @@
     <string name="point_manage_update_title">Update point</string>
     <string name="update_point_succeed">Update point success</string>
     <string name="update_point_failed">Update point failed</string>
+    <string name="please_input_key_word">Please input keyword</string>
 
 </resources>

+ 19 - 6
app/src/main/res/values-land/dimens.xml

@@ -22,10 +22,9 @@
     <dimen name="home_user_icon_margin">3dp</dimen>
     <dimen name="home_nickname_margin">10dp</dimen>
     <dimen name="home_nickname_text_size">20sp</dimen>
-    <dimen name="home_bottom_nav_height">90dp</dimen>
-    <dimen name="home_bottom_nav_text_size">34sp</dimen>
-    <dimen name="home_bottom_nav_icon_size">68dp</dimen>
-    <dimen name="home_bottom_nav_width">90dp</dimen>
+    <dimen name="home_bottom_nav_size">52dp</dimen>
+    <dimen name="home_bottom_nav_text_size">11sp</dimen>
+    <dimen name="home_bottom_nav_icon_size">23dp</dimen>
     <dimen name="dialog_common_root_width">680dp</dimen>
     <dimen name="dialog_common_root_height_big">1020dp</dimen>
     <dimen name="dialog_common_root_height_small">340dp</dimen>
@@ -36,7 +35,7 @@
     <dimen name="divider_line_space">1dp</dimen>
     <dimen name="dialog_normal_margin_top">20dp</dimen>
     <dimen name="dialog_content_normal_padding_horizontal">16dp</dimen>
-    <dimen name="normal_text_size">18sp</dimen>
+    <dimen name="normal_text_size">30sp</dimen>
     <dimen name="normal_input_padding_horizontal">10dp</dimen>
     <dimen name="normal_input_padding_vertical">2dp</dimen>
     <dimen name="normal_radio_root_layout_padding">56dp</dimen>
@@ -47,7 +46,7 @@
     <dimen name="common_spacing_7x">70dp</dimen>
     <dimen name="common_spacing_1_5x">15dp</dimen>
     <dimen name="init_margin_space">120dp</dimen>
-    <dimen name="init_set_admin_account_et_height">30dp</dimen>
+    <dimen name="init_set_admin_account_et_height">51dp</dimen>
     <dimen name="init_key_iv_width">50dp</dimen>
     <dimen name="init_key_iv_height">35dp</dimen>
     <dimen name="init_lock_iv_width">20dp</dimen>
@@ -65,4 +64,18 @@
     <dimen name="item_login_tip_v_margin_top">32dp</dimen>
     <dimen name="item_login_tip_v_margin_right">23dp</dimen>
     <dimen name="normal_text_size_24">24sp</dimen>
+    <dimen name="login_dialog_width">844dp</dimen>
+    <dimen name="login_dialog_height">744dp</dimen>
+    <dimen name="login_dialog_text_size">42sp</dimen>
+    <dimen name="login_dialog_input_height">115dp</dimen>
+    <dimen name="login_dialog_btn_height">102dp</dimen>
+    <dimen name="step_rv_height">323dp</dimen>
+    <dimen name="point_header_height">85dp</dimen>
+    <dimen name="point_rv_height">408dp</dimen>
+    <dimen name="colocker_layout_height">85dp</dimen>
+    <dimen name="btn_layout_min_height">112dp</dimen>
+    <dimen name="step_item_width">204dp</dimen>
+    <dimen name="step_item_height">306dp</dimen>
+    <dimen name="step_item_icon_size">119dp</dimen>
+    <dimen name="step_item_index_size">51dp</dimen>
 </resources>

+ 3 - 2
app/src/main/res/values-zh/strings.xml

@@ -9,7 +9,7 @@
     <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="flow_mode">流程模式</string>
     <string name="login_failed">登录失败</string>
     <string name="ongoing_job_tv">进行中\n的作业</string>
     <string name="hardware_in_use_tv">使用中\n的硬件</string>
@@ -90,7 +90,7 @@
     <string name="point_info_title">点位信息</string>
     <string name="member_info_title">人员信息</string>
     <string name="please_select_sop_workstation">请选择SOP区域</string>
-    <string name="please_select_lock_mode">请选择锁定模式</string>
+    <string name="please_select_flow_mode">请选择流程模式</string>
     <string name="please_input_sop_name">请输入SOP名称</string>
     <string name="please_select_member">您可以选择添加人员</string>
     <string name="please_must_select_at_least_one_point">您至少需要添加一个点位</string>
@@ -324,5 +324,6 @@
     <string name="point_manage_update_title">修改点位</string>
     <string name="update_point_succeed">保存点位成功</string>
     <string name="update_point_failed">保存点位失败</string>
+    <string name="please_input_key_word">请输入关键字</string>
 
 </resources>

+ 15 - 2
app/src/main/res/values/dimens.xml

@@ -22,10 +22,9 @@
     <dimen name="home_user_icon_margin">3dp</dimen>
     <dimen name="home_nickname_margin">10dp</dimen>
     <dimen name="home_nickname_text_size">20sp</dimen>
-    <dimen name="home_bottom_nav_height">90dp</dimen>
+    <dimen name="home_bottom_nav_size">90dp</dimen>
     <dimen name="home_bottom_nav_text_size">20sp</dimen>
     <dimen name="home_bottom_nav_icon_size">40dp</dimen>
-    <dimen name="home_bottom_nav_width">45dp</dimen>
     <dimen name="dialog_common_root_width">400dp</dimen>
     <dimen name="dialog_common_root_height_big">600dp</dimen>
     <dimen name="dialog_common_root_height_small">200dp</dimen>
@@ -65,4 +64,18 @@
     <dimen name="item_login_tip_v_margin_top">19dp</dimen>
     <dimen name="item_login_tip_v_margin_right">14dp</dimen>
     <dimen name="normal_text_size_24">24sp</dimen>
+    <dimen name="login_dialog_width">497dp</dimen>
+    <dimen name="login_dialog_height">438dp</dimen>
+    <dimen name="login_dialog_text_size">25sp</dimen>
+    <dimen name="login_dialog_input_height">68dp</dimen>
+    <dimen name="login_dialog_btn_height">60dp</dimen>
+    <dimen name="step_rv_height">190dp</dimen>
+    <dimen name="point_header_height">50dp</dimen>
+    <dimen name="point_rv_height">240dp</dimen>
+    <dimen name="colocker_layout_height">50dp</dimen>
+    <dimen name="btn_layout_min_height">60dp</dimen>
+    <dimen name="step_item_width">120dp</dimen>
+    <dimen name="step_item_height">180dp</dimen>
+    <dimen name="step_item_icon_size">70dp</dimen>
+    <dimen name="step_item_index_size">30dp</dimen>
 </resources>

+ 4 - 3
app/src/main/res/values/strings.xml

@@ -8,7 +8,7 @@
     <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="flow_mode">流程模式</string>
     <string name="login_failed">登录失败</string>
     <string name="ongoing_job_tv">进行中\n的作业</string>
     <string name="hardware_in_use_tv">使用中\n的硬件</string>
@@ -89,7 +89,7 @@
     <string name="point_info_title">点位信息</string>
     <string name="member_info_title">人员信息</string>
     <string name="please_select_sop_workstation">请选择SOP区域</string>
-    <string name="please_select_lock_mode">请选择锁定模式</string>
+    <string name="please_select_flow_mode">请选择流程模式</string>
     <string name="please_input_sop_name">请输入SOP名称</string>
     <string name="please_select_member">您可以选择添加人员</string>
     <string name="please_must_select_at_least_one_point">您至少需要添加一个点位</string>
@@ -168,7 +168,7 @@
     <string name="job_manage_delete_failed">无法删除选中的作业</string>
     <string name="please_select_job">请选择作业</string>
     <string name="check_delete_job">您确认要删除作业吗</string>
-    <string name="please_wait_ticket_name_lock_complete">请等待[%1$d]上锁完成</string>
+    <string name="please_wait_ticket_name_lock_complete">请等待[%1$s]上锁完成</string>
     <string name="user_info_title">个人信息</string>
     <string name="user_name">登录名</string>
     <string name="please_input_phone">请输入电话</string>
@@ -327,5 +327,6 @@
     <string name="point_manage_update_title">修改点位</string>
     <string name="update_point_succeed">保存点位成功</string>
     <string name="update_point_failed">保存点位失败</string>
+    <string name="please_input_key_word">请输入关键字</string>
 
 </resources>

+ 26 - 1
data/src/main/java/com/grkj/data/dao/HardwareDao.kt

@@ -52,7 +52,20 @@ interface HardwareDao {
     /**
      * 更新挂锁取出
      */
-    @Query("update is_job_ticket_lock set lock_status = '1',update_time = :updateTime where ticket_id = :ticketId and lock_id = :lockId")
+    @Query("""
+        UPDATE is_job_ticket_lock
+        SET
+          lock_status = '1',
+          update_time = :updateTime,
+          lock_id     = :lockId
+        WHERE record_id = (
+          SELECT record_id
+          FROM is_job_ticket_lock
+          WHERE ticket_id = :ticketId
+            AND lock_id IS NULL
+          LIMIT 1
+        );
+    """)
     fun updateLockTake(
         ticketId: Long?, lockId: Long, updateTime: String = TimeUtils.nowString(
             TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT
@@ -370,4 +383,16 @@ interface HardwareDao {
      */
     @Query("delete from is_rfid_token where 1=1")
     fun removeRfidTokenData()
+
+    /**
+     * 根据用户id获取工卡数据
+     */
+    @Query("select * from is_job_card where user_id = :userId")
+    fun getIsJobCardByUserId(userId: Long): List<IsJobCard>
+
+    /**
+     * 根据锁id获取锁数据
+     */
+    @Query("select * from is_lock where lock_id in (:lockIds)")
+    fun getLockDataByLockIds(lockIds: List<Long>): List<IsLock>
 }

+ 12 - 0
data/src/main/java/com/grkj/data/dao/IsolationPointDao.kt

@@ -6,6 +6,7 @@ import androidx.room.OnConflictStrategy
 import androidx.room.Query
 import androidx.room.Update
 import com.grkj.data.model.dos.IsIsolationPoint
+import com.grkj.data.model.vo.PointDetailVO
 import com.grkj.data.model.vo.PointManageVo
 
 /**
@@ -18,6 +19,7 @@ interface IsolationPointDao {
      */
     @Insert(onConflict = OnConflictStrategy.REPLACE)
     fun addIsolationPoint(isolationPoint: IsIsolationPoint)
+
     /**
      * 更新隔离点
      */
@@ -102,4 +104,14 @@ interface IsolationPointDao {
     @Query("select iip.* from is_isolation_point iip left join is_rfid_token irt on iip.rfid_id=irt.rfid_id where irt.rfid = :pointNfc")
     fun getPointByPointNfc(pointNfc: String?): IsIsolationPoint?
 
+    /**
+     * 根据点位id获取点位数据
+     */
+    @Query("""select p.*,
+                r.rfid as point_nfc
+                from is_isolation_point p
+                left join is_rfid_token r on r.rfid_id = p.rfid_id
+                where point_id in (:pointIds)""")
+    fun getPointDataListByPointIds(pointIds: List<Long>): List<PointDetailVO>
+
 }

+ 74 - 7
data/src/main/java/com/grkj/data/dao/JobTicketDao.kt

@@ -17,6 +17,7 @@ import com.grkj.data.model.vo.IsJobTicketDataVo
 import com.grkj.data.model.vo.IsJobTicketKeyDataVo
 import com.grkj.data.model.vo.IsJobTicketLockDataVo
 import com.grkj.data.model.vo.IsJobTicketPointsDataVo
+import com.grkj.data.model.vo.IsJobTicketPointsVO
 import com.grkj.data.model.vo.IsJobTicketStepDataVo
 import com.grkj.data.model.vo.IsJobTicketUserDataVo
 import com.grkj.data.model.vo.JobTicketManageVo
@@ -220,7 +221,7 @@ interface JobTicketDao {
     /**
      * 根据作业id获取作业挂锁详细数据
      */
-    @Query("select * from is_job_ticket_lock where ticket_id = :ticketId")
+    @Query("select ijtl.*,il.lock_nfc as lockNfc from is_job_ticket_lock ijtl left join is_lock il on ijtl.lock_id = il.lock_id  where ticket_id = :ticketId")
     fun getJobTicketLockDataByTicketId(ticketId: Long): List<IsJobTicketLockDataVo>
 
     /**
@@ -236,6 +237,28 @@ interface JobTicketDao {
     )
     fun getJobTicketPointsDataByTicketId(ticketId: Long): List<IsJobTicketPointsDataVo>
 
+    @Query(
+        """
+        SELECT
+            j.*,
+            i.point_name,
+            r.rfid as point_nfc,
+            i.point_serial_number,
+            l.lock_name,
+            l.lock_nfc
+        FROM
+            is_job_ticket_points j
+                LEFT JOIN is_isolation_point i ON j.point_id = i.point_id
+                left join is_rfid_token r on r.rfid_id = i.rfid_id
+                LEFT JOIN is_lock l ON j.lock_id = l.lock_id
+        WHERE
+            j.ticket_id = :ticketId
+        ORDER BY
+            j.record_id ASC
+    """
+    )
+    fun getJobTicketDetailPointsDataByTicketId(ticketId: Long): List<IsJobTicketPointsVO>
+
     /**
      * 根据作业id获取作业步骤详细数据
      */
@@ -324,13 +347,24 @@ interface JobTicketDao {
      */
     @Query(
         """
-        select ijt.* 
-        from is_job_ticket ijt 
-        left join is_job_ticket_points ijtp on ijt.ticket_id = ijtp.ticket_id
-        where ijt.ticket_status = "2" and ijtp.point_id in (:pointIds)
+        SELECT
+        j.*
+        FROM
+        `is_job_ticket` j
+        LEFT JOIN is_job_ticket_points p ON p.ticket_id = j.ticket_id
+        LEFT JOIN is_job_ticket_key k ON k.ticket_id = j.ticket_id
+        WHERE
+        j.ticket_status < 5
+        AND p.point_id IN (:pointIds)
+        AND k.collect_time is not null
+        and k.give_back_time is null
+        and k.ticket_type = 0
+        and j.ticket_id != :ticketId
+        GROUP BY
+        j.ticket_id
     """
     )
-    fun getLockingTicketByPointId(pointIds: List<Long>): List<IsJobTicketDataVo>
+    fun getLockingTicketByPointId(ticketId: Long,pointIds: List<Long>): List<IsJobTicketDataVo>
 
     /**
      * 更新点位信息
@@ -348,5 +382,38 @@ interface JobTicketDao {
      * 更新锁信息
      */
     @Query("update is_lock set update_time = :updateTime where lock_nfc = :rfid")
-    fun updateLockReturn(rfid: String, updateTime: String = TimeUtils.nowString(TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT))
+    fun updateLockReturn(
+        rfid: String,
+        updateTime: String = TimeUtils.nowString(TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT)
+    )
+
+    /**
+     * 获取虚拟冲突点位
+     */
+    @Query(
+        """
+        SELECT
+            p.*
+        FROM
+            is_job_ticket_points p
+                LEFT JOIN is_job_ticket t ON t.ticket_id = p.ticket_id
+                LEFT JOIN is_job_ticket_key k ON k.ticket_id = p.ticket_id and k.ticket_type = "1"
+        WHERE
+            t.ticket_status < 5
+          AND p.point_status = "1"
+          AND p.unlocked_by_key_id IS NULL
+          AND p.point_id =:pointId
+          AND p.lock_id = :lockId
+          AND p.ticket_id != :ticketId
+          AND k.collect_time IS NULL
+    """
+    )
+    fun getVirtualLockConflictPoint(
+        pointId: Long?,
+        lockId: Long?,
+        ticketId: Long
+    ): List<IsJobTicketPoints>
+
+    @Update
+    fun updateTicketStepData(step: IsJobTicketStep)
 }

+ 6 - 0
data/src/main/java/com/grkj/data/data/MainDomainData.kt

@@ -1,5 +1,6 @@
 package com.grkj.data.data
 
+import com.grkj.data.model.dos.IsJobCard
 import com.grkj.data.model.dos.SysUserDo
 
 /**
@@ -12,6 +13,11 @@ object MainDomainData {
     @Volatile
     var userInfo: SysUserDo? = null
 
+    /**
+     * 用户卡片
+     */
+    var userCardList: List<IsJobCard> = mutableListOf()
+
     /**
      * 角色关键字
      */

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

@@ -39,6 +39,9 @@ open class IsJobTicketKey : BaseBean() {
 
     @ColumnInfo("del_flag")
     var delFlag: String? = "0"
-	
+    override fun toString(): String {
+        return "IsJobTicketKey(recordId=$recordId, ticketId=$ticketId, keyId=$keyId, fromHardwareId=$fromHardwareId, toHardwareId=$toHardwareId, collectTime=$collectTime, giveBackTime=$giveBackTime, keyStatus=$keyStatus, ticketType=$ticketType, delFlag=$delFlag)"
+    }
+
 
 }

+ 11 - 7
data/src/main/java/com/grkj/data/model/res/KeyInfoRes.kt

@@ -4,11 +4,15 @@ package com.grkj.data.model.res
  * 钥匙信息
  */
 class KeyInfoRes {
-    val keyId: Long? = 0
-    val keyCode: String? = ""
-    val keyName: String? = ""
-    val hardwareId: Long? = 0
-    val keyNfc: String? = ""
-    val macAddress: String? = ""
-    val delFlag: String? = ""
+    var keyId: Long = 0
+    var keyCode: String = ""
+    var keyName: String = ""
+    var hardwareId: Long? = 0
+    var keyNfc: String? = ""
+    var macAddress: String? = ""
+    var delFlag: String? = ""
+    override fun toString(): String {
+        return "KeyInfoRes(keyId=$keyId, keyCode=$keyCode, keyName=$keyName, hardwareId=$hardwareId, keyNfc=$keyNfc, macAddress=$macAddress, delFlag=$delFlag)"
+    }
+
 }

+ 12 - 7
data/src/main/java/com/grkj/data/model/res/LockInfoRes.kt

@@ -4,11 +4,16 @@ package com.grkj.data.model.res
  * 锁信息
  */
 class LockInfoRes{
-    val lockId: Long? = 0
-    val lockCode: String? = ""
-    val lockName: String? = ""
-    val lockTypeId: Long? = 0
-    val hardwareId: Long? = 0
-    val lockNfc: String? = ""
-    val delFlag: String? = ""
+    var lockId: Long = 0
+    var lockCode: String = ""
+    var lockName: String = ""
+    var lockTypeId: Long? = 0
+    var hardwareId: Long? = 0
+    var lockNfc: String? = ""
+    var delFlag: String? = ""
+    override fun toString(): String {
+        return "LockInfoRes(lockId=$lockId, lockCode=$lockCode, lockName=$lockName, lockTypeId=$lockTypeId, hardwareId=$hardwareId, lockNfc=$lockNfc, delFlag=$delFlag)"
+    }
+
+
 }

+ 10 - 6
data/src/main/java/com/grkj/data/model/res/StepDetailRes.kt

@@ -1,16 +1,20 @@
 package com.grkj.data.model.res
 
 class StepDetailRes {
-    val stepId: Long? = 0
+    var stepId: Long = 0
 
-    val ticketId: Long? = 0
+    var ticketId: Long = 0
 
-    val stepIndex: Int? = 0
+    var stepIndex: Int = 0
 
-    val stepStatus: String? = ""
+    var stepStatus: String = ""
 
-    val stepContent: String? = ""
+    var stepContent: String? = ""
+
+    var androidStepContent: String? = ""
+    override fun toString(): String {
+        return "StepDetailRes(stepId=$stepId, ticketId=$ticketId, stepIndex=$stepIndex, stepStatus=$stepStatus, stepContent=$stepContent, androidStepContent=$androidStepContent)"
+    }
 
-    val androidStepContent: String? = ""
 
 }

+ 129 - 104
data/src/main/java/com/grkj/data/model/res/TicketDetailRes.kt

@@ -1,111 +1,136 @@
 package com.grkj.data.model.res
 
-data class TicketDetailRes(
-    val ticketId: Long?,
-    val ticketCode: String?,
-    val ticketName: String?,
-    val workshopId: Long?,
-    val workareaId: Long?,
-    val sopId: Long?,
-    val ticketType: String?,
-    val ticketContent: String?,
-    val ticketStatus: String?,
-    val ticketStartTime: String?,
-    val ticketEndTime: String?,
-    val delFlag: String?,
-    val createBy: String?,
-    val ticketKeyVOList: MutableList<JobTicketKeyVO>?,
-    val ticketLockVOList: MutableList<JobTicketLockVO>?,
-    val ticketLocksetVOList: MutableList<JobTicketLocksetVO>?,
-    val ticketUserVOList: MutableList<JobTicketUserVO>?,
-    val ticketPointsVOList: MutableList<JobTicketPointsVO>?,
-    val noUnlockTicketPointsVOSet: MutableList<JobTicketPointsVO>?
-) {
-    data class JobTicketKeyVO(
-        val recordId: Long?,
-        val ticketId: Long?,
-        val keyId: Long?,
-        val fromHardwareId: Long?,
-        val toHardwareId: Long?,
-        val collectTime: String?,
-        val giveBackTime: String?,
-        val keyStatus: String?,
-        val delFlag: String?,
-        val ticketType: Int?
-    )
+class TicketDetailRes {
+    var ticketId: Long = 0
+    var ticketCode: String? = null
+    var ticketName: String = ""
+    var workshopId: Long? = null
+    var workareaId: Long? = null
+    var sopId: Long? = null
+    var ticketType: String? = null
+    var ticketContent: String? = null
+    var ticketStatus: String? = null
+    var ticketStartTime: String? = null
+    var ticketEndTime: String? = null
+    var delFlag: String? = null
+    var createBy: String? = null
+    var ticketKeyVOList: MutableList<JobTicketKeyVO>? = null
+    var ticketLockVOList: MutableList<JobTicketLockVO>? = null
+    var ticketLocksetVOList: MutableList<JobTicketLocksetVO>? = null
+    var ticketUserVOList: MutableList<JobTicketUserVO>? = null
+    var ticketPointsVOList: MutableList<JobTicketPointsVO>? = null
+    var noUnlockTicketPointsVOSet: MutableList<JobTicketPointsVO>? = null
 
-    data class JobTicketLockVO(
-        val recordId: Long?,
-        val ticketId: Long?,
-        val lockId: Long?,
-        val lockNfc: String?,
-        val fromHardwareId: Long?,
-        val toHardwareId: Long?,
-        val isolationPointId: Long?,
-        val lockStatus: String?,
-        val delFlag: String?
-    )
 
-    data class JobTicketLocksetVO(
-        val recordId: Long?,
-        val jobTicketId: Long?,
-        val pointId: Long?,
-        val locksetId: Long?,
-        val fromHardwareId: Long?,
-        val toHardwareId: Long?,
-        val locksetTypeId: Long?,
-        val locksetStatus: String?,
-        val collectTime: String?,
-        val giveBackTime: String?,
-        val delFlag: String?
-    )
+    class JobTicketKeyVO {
+        var recordId: Long = 0
+        var ticketId: Long = 0
+        var keyId: Long? = null
+        var fromHardwareId: Long? = null
+        var toHardwareId: Long? = null
+        var collectTime: String? = null
+        var giveBackTime: String? = null
+        var keyStatus: String? = null
+        var delFlag: String? = null
+        var ticketType: Int? = null
+        override fun toString(): String {
+            return "JobTicketKeyVO(recordId=$recordId, ticketId=$ticketId, keyId=$keyId, fromHardwareId=$fromHardwareId, toHardwareId=$toHardwareId, collectTime=$collectTime, giveBackTime=$giveBackTime, keyStatus=$keyStatus, delFlag=$delFlag, ticketType=$ticketType)"
+        }
 
-    data class JobTicketUserVO(
-        val recordId: Long?,
-        val ticketId: Long?,
-        val userId: Long?,
-        val userName: String?,
-        val userType: String?,
-        val userRole: String?,
-        val jobStatus: Int?,//作业状态(0未开始,1 取锁具, 2取钥匙, 3待上锁(待共锁),4 已上锁(已共锁),5 已解锁)
-    )
+    }
 
-    data class JobTicketPointsVO(
-        val recordId: Long?,
-        val ticketId: Long?,
-        val workshopId: Long?,
-        val workareaId: Long?,
-        val pointId: Long?,
-        val pointStatus: String?,
-        val delFlag: String?,
-        val lockId: Long?,
-        val lockedByKeyId: Long?,
-        val unlockedByKeyId: Long?,
-        val lockTime: String?,
-        val unlockTime: String?,
-        val prePointId: Long?,
-        val pointCode: String?,
-        val pointName: String?,
-        val pointType: String?,
-        val pointTypeName: String?,
-        val pointNfc: String?,
-        val workshopName: String?,
-        val workareaName: String?,
-        val workstationId: Long?,
-        val workstationName: String?,
-        val lotoId: Long?,
-        val lotoName: String?,
-        val powerType: String?,
-        val powerTypeName: String?,
-        val isolationMethod: String?,
-        val pointIcon: String?,
-        val pointPicture: String?,
-        val lockTypeId: Long?,
-        val lockTypeCode: String?,
-        val lockTypeName: String?,
-        val lockTypeIcon: String?,
-        val lockTypeImg: String?,
-        val lockNfc: String?,
-        val locksetTypeId: Long?,
-    )
+    class JobTicketLockVO {
+        var recordId: Long = 0
+        var ticketId: Long = 0
+        var lockId: Long? = null
+        var lockNfc: String? = ""
+        var fromHardwareId: Long? = null
+        var toHardwareId: Long? = null
+        var isolationPointId: Long? = null
+        var lockStatus: String? = null
+        var delFlag: String? = null
+        override fun toString(): String {
+            return "JobTicketLockVO(recordId=$recordId, ticketId=$ticketId, lockId=$lockId, lockNfc='$lockNfc', fromHardwareId=$fromHardwareId, toHardwareId=$toHardwareId, isolationPointId=$isolationPointId, lockStatus=$lockStatus, delFlag=$delFlag)"
+        }
+
+    }
+
+    class JobTicketLocksetVO {
+        var recordId: Long? = null
+        var jobTicketId: Long? = null
+        var pointId: Long? = null
+        var locksetId: Long? = null
+        var fromHardwareId: Long? = null
+        var toHardwareId: Long? = null
+        var locksetTypeId: Long? = null
+        var locksetStatus: String? = null
+        var collectTime: String? = null
+        var giveBackTime: String? = null
+        var delFlag: String? = null
+        override fun toString(): String {
+            return "JobTicketLocksetVO(recordId=$recordId, jobTicketId=$jobTicketId, pointId=$pointId, locksetId=$locksetId, fromHardwareId=$fromHardwareId, toHardwareId=$toHardwareId, locksetTypeId=$locksetTypeId, locksetStatus=$locksetStatus, collectTime=$collectTime, giveBackTime=$giveBackTime, delFlag=$delFlag)"
+        }
+
+    }
+
+    class JobTicketUserVO {
+        var recordId: Long = 0
+        var ticketId: Long = 0
+        var userId: Long = 0
+        var userName: String = ""
+        var userType: String? = null
+        var userRole: String? = null
+        var jobStatus: Int? = null//作业状态(0未开始,1 取锁具, 2取钥匙, 3待上锁(待共锁),4 已上锁(已共锁),5 已解锁)
+        override fun toString(): String {
+            return "JobTicketUserVO(recordId=$recordId, ticketId=$ticketId, userId=$userId, userName='$userName', userType=$userType, userRole=$userRole, jobStatus=$jobStatus)"
+        }
+
+    }
+
+    class JobTicketPointsVO {
+        var recordId: Long = 0
+        var ticketId: Long = 0
+        var workshopId: Long? = null
+        var workareaId: Long? = null
+        var pointId: Long? = null
+        var pointStatus: String? = null
+        var delFlag: String? = null
+        var lockId: Long? = null
+        var lockedByKeyId: Long? = null
+        var unlockedByKeyId: Long? = null
+        var lockTime: String? = null
+        var unlockTime: String? = null
+        var prePointId: Long? = null
+        var pointCode: String? = null
+        var pointName: String? = null
+        var pointType: String? = null
+        var pointTypeName: String? = null
+        var pointNfc: String? = null
+        var workshopName: String? = null
+        var workareaName: String? = null
+        var workstationId: Long? = null
+        var workstationName: String? = null
+        var lotoId: Long? = null
+        var lotoName: String? = null
+        var powerType: String? = null
+        var powerTypeName: String? = null
+        var isolationMethod: String? = null
+        var pointIcon: String? = null
+        var pointPicture: String? = null
+        var lockTypeId: Long? = null
+        var lockTypeCode: String? = null
+        var lockTypeName: String? = null
+        var lockTypeIcon: String? = null
+        var lockTypeImg: String? = null
+        var lockNfc: String? = null
+        var locksetTypeId: Long? = null
+        override fun toString(): String {
+            return "JobTicketPointsVO(recordId=$recordId, ticketId=$ticketId, workshopId=$workshopId, workareaId=$workareaId, pointId=$pointId, pointStatus=$pointStatus, delFlag=$delFlag, lockId=$lockId, lockedByKeyId=$lockedByKeyId, unlockedByKeyId=$unlockedByKeyId, lockTime=$lockTime, unlockTime=$unlockTime, prePointId=$prePointId, pointCode=$pointCode, pointName=$pointName, pointType=$pointType, pointTypeName=$pointTypeName, pointNfc=$pointNfc, workshopName=$workshopName, workareaName=$workareaName, workstationId=$workstationId, workstationName=$workstationName, lotoId=$lotoId, lotoName=$lotoName, powerType=$powerType, powerTypeName=$powerTypeName, isolationMethod=$isolationMethod, pointIcon=$pointIcon, pointPicture=$pointPicture, lockTypeId=$lockTypeId, lockTypeCode=$lockTypeCode, lockTypeName=$lockTypeName, lockTypeIcon=$lockTypeIcon, lockTypeImg=$lockTypeImg, lockNfc=$lockNfc, locksetTypeId=$locksetTypeId)"
+        }
+
+    }
+
+    override fun toString(): String {
+        return "TicketDetailRes(ticketId=$ticketId, ticketCode=$ticketCode, ticketName='$ticketName', workshopId=$workshopId, workareaId=$workareaId, sopId=$sopId, ticketType=$ticketType, ticketContent=$ticketContent, ticketStatus=$ticketStatus, ticketStartTime=$ticketStartTime, ticketEndTime=$ticketEndTime, delFlag=$delFlag, createBy=$createBy, ticketKeyVOList=$ticketKeyVOList, ticketLockVOList=$ticketLockVOList, ticketLocksetVOList=$ticketLocksetVOList, ticketUserVOList=$ticketUserVOList, ticketPointsVOList=$ticketPointsVOList, noUnlockTicketPointsVOSet=$noUnlockTicketPointsVOSet)"
+    }
 }

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

@@ -5,7 +5,7 @@ package com.grkj.data.model.vo
  */
 data class AddUserDataVo(
     val nickname: String,
-    val cardCode: String,
+    val cardCode: String?,
     val roleId: List<Long>,
     val workstationId: List<Long>?,
     val status: Boolean

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

@@ -5,4 +5,6 @@ import com.grkj.data.model.dos.IsJobTicketLock
 /**
  * 作业挂锁详细数据实体
  */
-class IsJobTicketLockDataVo : IsJobTicketLock()
+class IsJobTicketLockDataVo : IsJobTicketLock() {
+    var lockNfc: String? = ""
+}

+ 111 - 0
data/src/main/java/com/grkj/data/model/vo/IsJobTicketPointsVo.kt

@@ -0,0 +1,111 @@
+package com.grkj.data.model.vo
+
+import androidx.room.ColumnInfo
+import com.grkj.data.model.dos.BaseBean
+
+/**
+ * 作业票隔离点对象 is_job_ticket_points
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+class IsJobTicketPointsVO : BaseBean() {
+    /** 记录ID  */
+    //@ApiModelProperty(varue = "记录ID")
+    @ColumnInfo(name = "record_id")
+    var recordId: Long = 0
+
+    /** 作业票ID  */
+    //@ApiModelProperty(varue = "作业票ID")
+    ////@Excel(name = "作业票ID")
+    @ColumnInfo(name = "ticket_id")
+    var ticketId: Long = 0
+
+    /** 所属车间ID  */
+    //@ApiModelProperty(varue = "所属车间ID")
+    ////@Excel(name = "所属车间ID")
+    @ColumnInfo(name = "workshop_id")
+    var workshopId: Long? = null
+
+    /** 所属区域ID  */
+    //@ApiModelProperty(varue = "所属区域ID")
+    //@Excel(name = "所属区域ID")
+    @ColumnInfo(name = "workarea_id")
+    var workareaId: Long? = null
+
+    /** 隔离点ID  */
+    //@ApiModelProperty(varue = "隔离点ID")
+    ////@Excel(name = "隔离点ID")
+    @ColumnInfo(name = "point_id")
+    var pointId: Long? = null
+
+    //@ApiModelProperty(varue = "隔离点nfc")
+    ////@Excel(name = "隔离点nfc")
+    @ColumnInfo(name = "point_nfc")
+    var pointNfc: String? = null
+
+    //@ApiModelProperty(varue = "隔离点序列号")
+    ////@Excel(name = "隔离点序列号")
+    @ColumnInfo(name = "point_serial_number")
+    var pointSerialNumber: String? = null
+
+    //@ApiModelProperty(varue = "隔离点Name")
+    @ColumnInfo(name = "point_name")
+    var pointName: String? = null
+
+    /** 隔离点状态  */
+    //@ApiModelProperty(varue = "隔离点状态(0-未上锁 1-已上锁 2-已解锁)")
+    //@Excel(name = "隔离点状态")
+    @ColumnInfo(name = "point_status")
+    var pointStatus: String? = null
+
+    /** 删除标志(0代表存在 2代表删除)  */
+    //@ApiModelProperty(varue = "删除标志(0代表存在 2代表删除)")
+    @ColumnInfo(name = "del_flag")
+    var delFlag: String? = null
+
+    //@ApiModelProperty(varue = "挂锁ID")
+    @ColumnInfo(name = "lock_id")
+    var lockId: Long? = null
+
+    //@ApiModelProperty(varue = "挂锁Name")
+    @ColumnInfo(name = "lock_name")
+    var lockName: String? = null
+
+    //@ApiModelProperty(varue = "挂锁NFC")
+    @ColumnInfo(name = "lock_nfc")
+    var lockNfc: String? = null
+
+    //@ApiModelProperty(varue = "上锁钥匙ID")
+    @ColumnInfo(name = "locked_by_key_id")
+    var lockedByKeyId: Long? = null
+
+    //@ApiModelProperty(varue = "解锁钥匙ID")
+    @ColumnInfo(name = "unlocked_by_key_id")
+    var unlockedByKeyId: Long? = null
+
+    //@Schema(description = "上锁时间")
+    @ColumnInfo(name = "lock_time")
+    var lockTime: String? = null
+
+    //@Schema(description = "解锁时间")
+    @ColumnInfo(name = "unlock_time")
+    var unlockTime: String? = null
+
+    //@ApiModelProperty(varue = "前置隔离点ID")
+    @ColumnInfo(name = "pre_point_id")
+    var prePointId: Long? = null
+
+    //@ApiModelProperty(varue = "锁具Name")
+    @ColumnInfo(name = "lockset_name")
+    var locksetName: String? = null
+
+    //@ApiModelProperty(varue = "开关状态")
+    @ColumnInfo(name = "switch_status")
+    var switchStatus: String? = null
+
+    //@ApiModelProperty(varue = "开关状态最近更新时间")
+    @ColumnInfo(name = "switch_last_update_time")
+    var switchLastUpdateTime: String? = null
+
+}

+ 120 - 0
data/src/main/java/com/grkj/data/model/vo/PointDetailVO.kt

@@ -0,0 +1,120 @@
+package com.grkj.data.model.vo
+
+import androidx.room.ColumnInfo
+import com.grkj.data.model.dos.BaseBean
+
+/**
+ * 隔离点对象 is_isolation_point
+ *
+ * @author cgj
+ * @date 2024-10-18
+ */
+class PointDetailVO : BaseBean() {
+    //@ApiModelProperty(varue = "隔离点ID")
+    @ColumnInfo(name = "point_id")
+    var pointId: Long? = null
+
+    //@ApiModelProperty(varue = "隔离点编号")
+    @ColumnInfo(name = "point_code")
+    var pointCode: String? = null
+
+    //@ApiModelProperty(varue = "隔离点名称")
+    @ColumnInfo(name = "point_name")
+    var pointName: String? = null
+
+    //@ApiModelProperty(varue = "隔离点类型")
+    @ColumnInfo(name = "point_type")
+    var pointType: String? = null
+
+    //@ApiModelProperty(varue = "隔离点nfc")
+    @ColumnInfo(name = "point_nfc")
+    var pointNfc: String? = null
+
+    //@ApiModelProperty(varue = "所属车间ID")
+    @ColumnInfo(name = "workshop_id")
+    var workshopId: Long? = null
+
+    //@ApiModelProperty(varue = "所属车间Name")
+    @ColumnInfo(name = "workshop_name")
+    var workshopName: String? = null
+
+    //@ApiModelProperty(varue = "所属区域ID")
+    @ColumnInfo(name = "workarea_id")
+    var workareaId: Long? = null
+
+    //@ApiModelProperty(varue = "所属区域Name")
+    @ColumnInfo(name = "workarea_name")
+    var workareaName: String? = null
+
+    //@ApiModelProperty(varue = "所属mars岗位ID")
+    @ColumnInfo(name = "workstation_id")
+    var workstationId: Long? = null
+
+    //@ApiModelProperty(varue = "所属mars岗位Name")
+    @ColumnInfo(name = "workstation_name")
+    var workstationName: String? = null
+
+    //@ApiModelProperty(varue = "所属电柜ID")
+    @ColumnInfo(name = "loto_id")
+    var lotoId: Long? = null
+
+    //@ApiModelProperty(varue = "所属电柜Name")
+    @ColumnInfo(name = "loto_name")
+    var lotoName: String? = null
+
+    //@ApiModelProperty(varue = "危险能量类型")
+    @ColumnInfo(name = "power_type")
+    var powerType: String? = null
+
+    //@ApiModelProperty(varue = "隔离方式")
+    @ColumnInfo(name = "isolation_method")
+    var isolationMethod: String? = null
+
+    //@ApiModelProperty(varue = "隔离点图标")
+    @ColumnInfo(name = "point_icon")
+    var pointIcon: String? = null
+
+    //@ApiModelProperty(varue = "隔离点图片")
+    @ColumnInfo(name = "point_picture")
+    var pointPicture: String? = null
+
+    //@ApiModelProperty(varue = "删除标志(0代表存在 2代表删除)")
+    @ColumnInfo(name = "del_flag")
+    var delFlag: String? = null
+
+    //@ApiModelProperty(varue = "锁具类型id")
+    @ColumnInfo(name = "lock_type_id")
+    var lockTypeId: Long? = null
+
+    //@ApiModelProperty(varue = "锁具类型编码")
+    @ColumnInfo(name = "lock_type_code")
+    var lockTypeCode: String? = null
+
+    //@ApiModelProperty(varue = "锁具类型名称")
+    @ColumnInfo(name = "lock_type_name")
+    var lockTypeName: String? = null
+
+    //@ApiModelProperty(varue = "锁具类型图标")
+    @ColumnInfo(name = "lock_type_icon")
+    var lockTypeIcon: String? = null
+
+    //@ApiModelProperty(varue = "锁具类型图片")
+    @ColumnInfo(name = "lock_type_img")
+    var lockTypeImg: String? = null
+
+    //@ApiModelProperty(varue = "挂锁ID")
+    @ColumnInfo(name = "lock_id")
+    var lockId: Long? = null
+
+    //@ApiModelProperty(varue = "挂锁NFC")
+    @ColumnInfo(name = "lock_nfc")
+    var lockNfc: String? = null
+
+    //@ApiModelProperty(varue = "辅件类型ID")
+    @ColumnInfo(name = "lockset_type_id")
+    var locksetTypeId: Long? = null
+
+    //@ApiModelProperty(varue = "前置隔离点ID")
+    @ColumnInfo(name = "pre_point_id")
+    var prePointId: Long? = null
+}

+ 6 - 0
data/src/main/java/com/grkj/data/repository/IJobTicketRepository.kt

@@ -1,5 +1,6 @@
 package com.grkj.data.repository
 
+import com.grkj.data.model.dos.IsJobTicketStep
 import com.grkj.data.model.req.LockPointUpdateReq
 import com.grkj.data.model.res.StepDetailRes
 import com.grkj.data.model.res.TicketDetailRes
@@ -188,4 +189,9 @@ interface IJobTicketRepository {
      * 上报锁具归还
      */
     fun updateLockReturn(rfid: String, serialNo: String, callback: () -> Unit)
+
+    /**
+     * 更新步骤数据
+     */
+    fun updateTicketStepData(step: IsJobTicketStep)
 }

+ 13 - 11
data/src/main/java/com/grkj/data/repository/impl/HardwareRepository.kt

@@ -55,10 +55,8 @@ class HardwareRepository @Inject constructor(
      */
     private fun getLockInfo(rfid: String): LockInfoRes? {
         val isLock = hardwareDao.getLockInfoByRfid(rfid)
-        var lockInfoRes = LockInfoRes()
-        isLock?.let {
-            lockInfoRes = BeanUtils.copyData<LockInfoRes>(it,lockInfoRes)
-        }
+        var lockInfoRes = BeanUtils.copyProperties(isLock, LockInfoRes::class.java)
+        logger.info("lockInfo:${isLock},${lockInfoRes}")
         return lockInfoRes
     }
 
@@ -74,11 +72,8 @@ class HardwareRepository @Inject constructor(
 
     private fun getKeyInfo(rfid: String): KeyInfoRes? {
         val isKey = hardwareDao.getKeyInfoByRfid(rfid)
-        var keyInfoRes = KeyInfoRes()
-        isKey?.let {
-            logger.info("钥匙信息:${isKey}")
-            keyInfoRes = BeanUtils.copyData<KeyInfoRes>(it,keyInfoRes)
-        }
+        var keyInfoRes = BeanUtils.copyProperties(isKey, KeyInfoRes::class.java)
+        logger.info("keyInfo:${isKey},${keyInfoRes}")
         return keyInfoRes
     }
 
@@ -122,6 +117,7 @@ class HardwareRepository @Inject constructor(
         callback: (Boolean) -> Unit
     ) {
         lockTakeList.forEach { lockTakeInfo ->
+            logger.info("取出的挂锁信息:${lockTakeInfo}")
             lockTakeInfo.lockNfc?.let {
                 val lockInfo = getLockInfo(it)
                 lockInfo?.lockId?.let { lockId ->
@@ -177,6 +173,8 @@ class HardwareRepository @Inject constructor(
             val isJobCard = IsJobCard()
             isJobCard.cardCode = "CARD_${defaultCardCodeSize + index + 1}"
             isJobCard.cardNfc = cardCode
+            isJobCard.exStatus =
+                CommonDictDataEnum.JOB_CARD_STATUS.commonDictRes.find { it.dictLabel == "正常" }?.dictValue
             isJobCard
         }
         hardwareDao.addCard(isJobCard)
@@ -200,6 +198,8 @@ class HardwareRepository @Inject constructor(
             val isRfidToken = IsRfidToken()
             isRfidToken.rfidCode = "RFID_${defaultRfidTokenCodeSize + index + 1}"
             isRfidToken.rfid = rfid
+            isRfidToken.status =
+                CommonDictDataEnum.RFID_TOKEN_STATUS.commonDictRes.find { it.dictLabel == "正常" }?.dictValue
             isRfidToken
         }
         hardwareDao.addRfidToken(isRfidToken)
@@ -212,7 +212,8 @@ class HardwareRepository @Inject constructor(
         isKey.keyCode = "KEY_${defaultKeyCodeSize + 1}"
         isKey.keyNfc = keyNfc
         isKey.macAddress = keyMacAddress
-        isKey.exStatus = CommonDictDataEnum.KEY_STATUS.commonDictRes.find { it.dictLabel=="正常" }?.dictValue
+        isKey.exStatus =
+            CommonDictDataEnum.KEY_STATUS.commonDictRes.find { it.dictLabel == "正常" }?.dictValue
         hardwareDao.addKeyInfo(isKey)
     }
 
@@ -221,7 +222,8 @@ class HardwareRepository @Inject constructor(
         var defaultLockCodeSize = hardwareDao.getDefaultLockNameCount()
         isLock.lockCode = "LOCK_${defaultLockCodeSize + 1}"
         isLock.lockNfc = lockNfc
-        isLock.exStatus = CommonDictDataEnum.PADLOCK_STATUS.commonDictRes.find { it.dictLabel=="正常" }?.dictValue
+        isLock.exStatus =
+            CommonDictDataEnum.PADLOCK_STATUS.commonDictRes.find { it.dictLabel == "正常" }?.dictValue
         hardwareDao.addLockInfo(isLock)
     }
 

+ 79 - 5
data/src/main/java/com/grkj/data/repository/impl/JobTicketRepository.kt

@@ -2,7 +2,9 @@ package com.grkj.data.repository.impl
 
 import com.grkj.data.check_data.ICheckDataMode
 import com.grkj.data.dao.HardwareDao
+import com.grkj.data.dao.IsolationPointDao
 import com.grkj.data.dao.JobTicketDao
+import com.grkj.data.enums.IsolationPointPowerTypeEnum
 import com.grkj.data.enums.JobTicketStatusEnum
 import com.grkj.data.enums.LockModeEnum
 import com.grkj.data.enums.LockStepEnum
@@ -31,6 +33,7 @@ import com.sik.sikcore.data.BeanUtils
 import com.sik.sikcore.date.TimeUtils
 import javax.inject.Inject
 import javax.inject.Singleton
+import kotlin.math.log
 
 /**
  * 作业票实现
@@ -38,7 +41,8 @@ import javax.inject.Singleton
 @Singleton
 class JobTicketRepository @Inject constructor(
     val jobTicketDao: JobTicketDao,
-    val hardwareDao: HardwareDao
+    val hardwareDao: HardwareDao,
+    val isolationPointDao: IsolationPointDao
 ) : BaseRepository(),
     IJobTicketRepository {
     override fun createJob(
@@ -187,7 +191,66 @@ class JobTicketRepository @Inject constructor(
         ticketId: Long,
         callback: (TicketDetailRes?) -> Unit
     ) {
-
+        val ticketData = getJobTicketDataByTicketId(ticketId)
+        val ticketDetailRes = BeanUtils.copyProperties(ticketData, TicketDetailRes::class.java)
+        val ticketKeyData = getJobTicketKeyDataByTicketId(ticketId)
+        val jobTicketKeyDataList =
+            BeanUtils.copyList(ticketKeyData, TicketDetailRes.JobTicketKeyVO::class.java)
+        ticketDetailRes?.ticketKeyVOList =
+            jobTicketKeyDataList?.filterIsInstance<TicketDetailRes.JobTicketKeyVO>() as MutableList<TicketDetailRes.JobTicketKeyVO>?
+        val ticketLockData = getJobTicketLockDataByTicketId(ticketId)
+        val jobTicketLockDataList =
+            BeanUtils.copyList(ticketLockData, TicketDetailRes.JobTicketLockVO::class.java)
+        ticketDetailRes?.ticketLockVOList =
+            jobTicketLockDataList?.filterIsInstance<TicketDetailRes.JobTicketLockVO>() as MutableList<TicketDetailRes.JobTicketLockVO>?
+        val ticketUserData = getJobTicketUserDataByTicketId(ticketId)
+        val jobTicketUserDataList =
+            BeanUtils.copyList(ticketUserData, TicketDetailRes.JobTicketUserVO::class.java)
+        ticketDetailRes?.ticketUserVOList =
+            jobTicketUserDataList?.filterIsInstance<TicketDetailRes.JobTicketUserVO>() as MutableList<TicketDetailRes.JobTicketUserVO>?
+        val ticketPointData = jobTicketDao.getJobTicketDetailPointsDataByTicketId(ticketId)
+        val jobTicketPointDataList =
+            BeanUtils.copyList(ticketPointData, TicketDetailRes.JobTicketPointsVO::class.java)
+        if (jobTicketPointDataList?.isEmpty() == false) {
+            val pointIds = jobTicketPointDataList.mapNotNull { it?.pointId }
+            val pointDetailData = isolationPointDao.getPointDataListByPointIds(pointIds)
+            jobTicketPointDataList.filterNotNull().forEach { ticketPointData ->
+                val pointDetail = pointDetailData.find { it.pointId == ticketPointData.pointId }
+                pointDetail?.let {
+                    ticketPointData.pointCode = it.pointCode
+                    ticketPointData.pointName = it.pointName
+                    ticketPointData.pointType = it.pointType
+                    ticketPointData.pointTypeName = ""
+                    ticketPointData.pointNfc = it.pointNfc
+                    ticketPointData.workshopName = it.workshopName
+                    ticketPointData.workareaName = it.workareaName
+                    ticketPointData.workstationId = it.workstationId
+                    ticketPointData.workstationName = it.workstationName
+                    ticketPointData.lotoId = it.lotoId
+                    ticketPointData.lotoName = it.lotoName
+                    ticketPointData.powerType = it.powerType
+                    ticketPointData.powerTypeName = IsolationPointPowerTypeEnum.values()
+                        .find { enum -> enum.name == it.powerType }?.description
+                    ticketPointData.isolationMethod = it.isolationMethod
+                    ticketPointData.pointIcon = it.pointIcon
+                    ticketPointData.pointPicture = it.pointPicture
+                    ticketPointData.lockTypeId = it.lockTypeId
+                    ticketPointData.lockTypeCode = it.lockTypeCode
+                    ticketPointData.lockTypeName = it.lockTypeName
+                    ticketPointData.lockTypeIcon = it.lockTypeIcon
+                    ticketPointData.lockTypeImg = it.lockTypeImg
+                    ticketPointData.locksetTypeId = it.locksetTypeId
+                }
+            }
+        }
+        ticketDetailRes?.ticketPointsVOList =
+            jobTicketPointDataList?.filterNotNull() as MutableList<TicketDetailRes.JobTicketPointsVO>
+        ticketDetailRes?.noUnlockTicketPointsVOSet =
+            ticketDetailRes.ticketPointsVOList?.mapNotNull {
+                jobTicketDao.getVirtualLockConflictPoint(it.pointId, it.lockId, ticketId)
+            }
+                ?.filterIsInstance<TicketDetailRes.JobTicketPointsVO>() as MutableList<TicketDetailRes.JobTicketPointsVO>
+        callback(ticketDetailRes)
     }
 
     override fun deleteTicketByTicketIds(ticketIds: List<Long>) {
@@ -282,7 +345,7 @@ class JobTicketRepository @Inject constructor(
     ) {
         val stepDataList = jobTicketDao.getJobTicketStepDataByTicketId(ticketId)
         callback(stepDataList.map {
-            BeanUtils.convert<StepDetailRes>(it)
+            BeanUtils.copyProperties(it, StepDetailRes::class.java)!!
         })
     }
 
@@ -323,7 +386,7 @@ class JobTicketRepository @Inject constructor(
 
     override fun samePointLockingTicket(ticketId: Long): List<IsJobTicketDataVo> {
         val points = jobTicketDao.getTicketPointsByTicketId(ticketId)
-        return jobTicketDao.getLockingTicketByPointId(points.map { it.pointId })
+        return jobTicketDao.getLockingTicketByPointId(ticketId, points.map { it.pointId })
     }
 
     override fun updateLockPointBatch(
@@ -425,6 +488,10 @@ class JobTicketRepository @Inject constructor(
         callback()
     }
 
+    override fun updateTicketStepData(step: IsJobTicketStep) {
+        jobTicketDao.updateTicketStepData(step)
+    }
+
     override fun updateKeyReturn(
         ticketId: Long,
         keyNfc: String,
@@ -433,6 +500,7 @@ class JobTicketRepository @Inject constructor(
     ) {
         val jobTicketData = jobTicketDao.getTicketDataByTicketId(ticketId)
         val keyData = hardwareDao.getKeyDataByKeyRfid(keyNfc)
+        logger.info("钥匙信息:${keyData}")
         if (keyData == null) {
             logger.info("钥匙信息不存在")
             callback(false, "钥匙信息不存在", 500)
@@ -440,7 +508,11 @@ class JobTicketRepository @Inject constructor(
         }
 
         val isJobTicketKeys = jobTicketDao.getJobTicketKeyDataByTicketId(ticketId)
-        val isJobTicketKey = isJobTicketKeys.firstOrNull { it.keyId == keyData.keyId }
+        logger.info("作业票钥匙信息:${isJobTicketKeys}")
+        val isJobTicketKey = BeanUtils.copyProperties(
+            isJobTicketKeys.firstOrNull { it.keyId == keyData.keyId },
+            IsJobTicketKey::class.java
+        )
         if (isJobTicketKey == null) {
             logger.info("作业的钥匙信息不存在")
             callback(false, "作业的钥匙信息不存在", 500)
@@ -449,6 +521,8 @@ class JobTicketRepository @Inject constructor(
         isJobTicketKey.keyStatus = "1"
         isJobTicketKey.giveBackTime =
             TimeUtils.nowString(TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT)
+        logger.info("要更新的作业票钥匙信息:${isJobTicketKey}")
         jobTicketDao.updateIsJobTicketKey(listOf(isJobTicketKey))
+        callback(true, "", 200)
     }
 }

+ 2 - 0
data/src/main/java/com/grkj/data/repository/impl/UserRepository.kt

@@ -44,7 +44,9 @@ class UserRepository @Inject constructor(
         logger.info("密码是否匹配:${password},${sysUserDo.password},${matched}")
         if (matched) {
             MainDomainData.userInfo = sysUserDo
+            val userCardList = hardwareDao.getIsJobCardByUserId(sysUserDo.userId)
             val roleDatas = roleDao.getRoleDataByUserId(sysUserDo.userId)
+            MainDomainData.userCardList = userCardList
             MainDomainData.roleKeys = roleDatas.joinToString(",") { it.roleKey }
             MainDomainData.permissions =
                 if (sysUserDo.nickName == "罗成") RoleFunctionalPermissionsEnum.values()

+ 23 - 9
shared/src/main/java/com/grkj/shared/config/Constants.kt

@@ -1,6 +1,12 @@
 package com.grkj.shared.config
 
 import android.Manifest
+import android.Manifest.permission.ACCESS_COARSE_LOCATION
+import android.Manifest.permission.ACCESS_FINE_LOCATION
+import android.Manifest.permission.BLUETOOTH_ADVERTISE
+import android.Manifest.permission.BLUETOOTH_CONNECT
+import android.Manifest.permission.BLUETOOTH_SCAN
+import android.os.Build
 
 /**
  * 常量参数
@@ -9,20 +15,28 @@ object Constants {
     /**
      * 需要的权限
      */
-    val needPermission = listOf<String>(
-        Manifest.permission.BLUETOOTH,
-        Manifest.permission.BLUETOOTH_ADMIN,
-        Manifest.permission.BLUETOOTH_CONNECT,
-        Manifest.permission.BLUETOOTH_SCAN,
-        Manifest.permission.BLUETOOTH_ADVERTISE,
-        Manifest.permission.BLUETOOTH_PRIVILEGED,
+    val needPermission = arrayOf(
+        *if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            arrayOf(
+                Manifest.permission.BLUETOOTH_SCAN,
+                Manifest.permission.BLUETOOTH_ADVERTISE,
+                Manifest.permission.BLUETOOTH_CONNECT,
+                Manifest.permission.ACCESS_FINE_LOCATION,
+                Manifest.permission.ACCESS_COARSE_LOCATION
+            )
+        } else {
+            arrayOf(
+                Manifest.permission.ACCESS_FINE_LOCATION,
+                Manifest.permission.ACCESS_COARSE_LOCATION
+            )
+        },
         Manifest.permission.READ_EXTERNAL_STORAGE,
         Manifest.permission.WRITE_EXTERNAL_STORAGE,
         Manifest.permission.READ_PHONE_STATE,
         Manifest.permission.ACCESS_FINE_LOCATION,
         Manifest.permission.ACCESS_COARSE_LOCATION,
-        Manifest.permission.CAMERA,
-    ).toTypedArray()
+        Manifest.permission.CAMERA
+    )
 
     const val USER_TYPE_LOCKER = "0"                // 上锁人
     const val USER_TYPE_COLOCKER = "1"              // 共锁人

+ 5 - 6
ui-base/src/main/java/com/grkj/ui_base/base/BaseActivity.kt

@@ -20,6 +20,7 @@ import com.grkj.ui_base.config.ISCSConfig
 import com.grkj.ui_base.dialog.LoadingDialog
 import com.grkj.ui_base.utils.event.JumpViewEvent
 import com.grkj.ui_base.utils.event.LoadingEvent
+import com.grkj.ui_base.utils.extension.checkPermissions
 import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikandroid.permission.PermissionUtils
 import me.jessyan.autosize.internal.CustomAdapt
@@ -90,10 +91,8 @@ abstract class BaseActivity<V : ViewDataBinding> : AppCompatActivity(), CustomAd
         vararg permissions: String,
         permissionCallback: PermissionUtils.PermissionCallback
     ) {
-        PermissionUtils.checkAndRequestPermissions(
-            permissions.toList().toTypedArray(),
-            permissionCallback
-        )
+        logger.info("权限检查结果:${checkPermissions(permissions.toList().toTypedArray())}")
+        PermissionUtils.checkAndRequestPermissions(permissions.toList().toTypedArray(),permissionCallback)
     }
 
     /** 动态切换 Nav Graph */
@@ -184,12 +183,12 @@ abstract class BaseActivity<V : ViewDataBinding> : AppCompatActivity(), CustomAd
 
     // 是否以“宽度”为基准适配,false 则按“高度”来算缩放比例
     override fun isBaseOnWidth(): Boolean {
-        return resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
+        return isPortrait()
     }
 
     // 设计图的尺寸 dp。竖屏时用 600dp 作为基准宽度;横屏时用 1024dp 作为基准高度
     override fun getSizeInDp(): Float {
-        return if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
+        return if (isPortrait()) {
             ISCSConfig.designWidth
         } else {
             ISCSConfig.desginHeight

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

@@ -133,12 +133,12 @@ abstract class BaseFragment<V : ViewDataBinding> : Fragment(), CustomAdapt {
 
     // 是否以“宽度”为基准适配,false 则按“高度”来算缩放比例
     override fun isBaseOnWidth(): Boolean {
-        return resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
+        return isPortrait()
     }
 
     // 设计图的尺寸 dp。竖屏时用 600dp 作为基准宽度;横屏时用 1024dp 作为基准高度
     override fun getSizeInDp(): Float {
-        return if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
+        return if (isPortrait()) {
             ISCSConfig.designWidth
         } else {
             ISCSConfig.desginHeight

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

@@ -12,10 +12,12 @@ import com.grkj.data.model.local.WorkTicketSend
 import com.grkj.data.model.local.WorkTicketSend.LockListBO
 import com.grkj.data.model.req.LockPointUpdateReq
 import com.grkj.data.model.res.TicketDetailRes
-import com.grkj.shared.config.Constants
 import com.grkj.ui_base.R
 import com.grkj.data.data.DictConstants
+import com.grkj.data.data.MainDomainData
 import com.grkj.data.enums.LockStepEnum
+import com.grkj.data.enums.RoleEnum
+import com.grkj.data.model.dos.IsJobTicketStep
 import com.grkj.ui_base.dialog.TipDialog
 import com.grkj.ui_base.utils.CommonUtils
 import com.grkj.ui_base.utils.Executor
@@ -36,7 +38,7 @@ import com.grkj.ui_base.utils.modbus.DeviceConst
 import com.grkj.ui_base.utils.modbus.ModBusController
 import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikcore.SIKCore
-import com.sik.sikcore.activity.ActivityTracker
+import com.sik.sikcore.data.BeanUtils
 import com.sik.sikcore.thread.ThreadUtils
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.async
@@ -91,6 +93,7 @@ object BleBusinessManager {
 
             byteArray.startsWith(BleConst.RSP_POWER_STATUS) -> {
                 val power = byteArray[4].toInt()
+                ModBusController.updateKeyPower(power, bleBean.bleDevice.mac)
                 if (power < 50) {//如果电量小于50就打开仓位充电
                     ModBusController.controlKeyCharge(true, bleBean.bleDevice.mac) {
                         logger.info("钥匙: ${bleBean.bleDevice.mac} 开始充电")
@@ -351,38 +354,45 @@ object BleBusinessManager {
                     // 判断是否有待取的钥匙
                     val updateBo =
                         ModbusBusinessManager.mDeviceTakeList.find { it.deviceType == DeviceConst.DEVICE_TYPE_KEY && key.rfid == it.nfc }
+                    logger.info("是否有代取的钥匙:${updateBo}")
                     updateBo?.let { itBO ->
-                        RepositoryManager.jobTicketRepo.getStepDetail(itBO.ticketId) {
-                            var step = 0
-                            it?.filter { it.stepStatus == "1" }
-                                ?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
-                                    step = it
-                                }
-                            RepositoryManager.jobTicketRepo.getTicketDetail(itBO.ticketId) { ticketDetail ->
-                                val role = ticketDetail?.ticketUserVOList?.find {
-                                    it.userId == SPUtils.getLoginUser(SIKCore.getApplication())?.userId && it.userType == Constants.USER_TYPE_LOCKER
-                                }
-                                if (role == null) {
-                                    PopTip.tip(CommonUtils.getStr(R.string.you_are_not_locker_tip))
-                                    return@getTicketDetail
-                                }
-                                if (step == 4) {    // 上锁工作票
-                                    sendTicketBusiness(
-                                        true,
-                                        currentModeEvent.bleBean.bleDevice.mac,
-                                        ticketDetail,
-                                        ticketDetail.ticketLockVOList?.filter { it.lockStatus != "2" }
-                                            ?.map { it.lockNfc }?.toMutableList(),
-                                        true
-                                    )
-                                } else if (step == 7) { // 解锁工作票
-                                    sendTicketBusiness(
-                                        false,
-                                        currentModeEvent.bleBean.bleDevice.mac,
-                                        ticketDetail,
-                                        null,
-                                        true
-                                    )
+                        ThreadUtils.runOnIO {
+                            RepositoryManager.jobTicketRepo.getStepDetail(itBO.ticketId) {
+                                logger.info("步骤数据:${it}")
+                                var step =
+                                    it?.firstOrNull { it.stepStatus == "0" }?.stepIndex ?: 0
+                                logger.info("当前步骤:${step}")
+                                RepositoryManager.jobTicketRepo.getTicketDetail(itBO.ticketId) { ticketDetail ->
+                                    logger.info("步骤详情:${ticketDetail}")
+                                    val role = ticketDetail?.ticketUserVOList?.find {
+                                        it.userId == MainDomainData.userInfo?.userId && MainDomainData.roleKeys?.contains(
+                                            RoleEnum.JTLOCKER.roleKey
+                                        ) == true
+                                    }
+                                    if (role == null) {
+                                        ThreadUtils.runOnMain {
+                                            PopTip.tip(CommonUtils.getStr(R.string.you_are_not_locker_tip))
+                                        }
+                                        return@getTicketDetail
+                                    }
+                                    if (step == LockStepEnum.LOCK.type) {    // 上锁工作票
+                                        sendTicketBusiness(
+                                            true,
+                                            currentModeEvent.bleBean.bleDevice.mac,
+                                            ticketDetail,
+                                            ticketDetail.ticketLockVOList?.filter { it.lockStatus != "2" }
+                                                ?.map { it.lockNfc }?.toMutableList(),
+                                            true
+                                        )
+                                    } else if (step == LockStepEnum.UNLOCK.type) { // 解锁工作票
+                                        sendTicketBusiness(
+                                            false,
+                                            currentModeEvent.bleBean.bleDevice.mac,
+                                            ticketDetail,
+                                            null,
+                                            true
+                                        )
+                                    }
                                 }
                             }
                         }
@@ -495,6 +505,7 @@ object BleBusinessManager {
             } catch (e: Exception) {
                 null
             }
+            logger.info("作业票信息:${workTicketGet}")
             if (workTicketGet == null) {
                 PopTip.tip(R.string.ticket_data_error)
                 return@handleTicketStatus
@@ -506,8 +517,10 @@ object BleBusinessManager {
                 val finishedStatus = workTicketGet.hasFinished()
                 logger.info("作业票结束情况:${finishedStatus}")
                 if (finishedStatus.first) {
-                    Executor.delayOnMain(500) {
+                    Executor.delayOnIO(500) {
                         handleKeyReturn(bleDevice, workTicketGet, finishedStatus.second)
+                        //是否存在代发工作票
+                        ModbusBusinessManager.checkTicketAndSendTicket(bleDevice.mac)
                     }
                 } else {
                     // 当前策略:作业票未完成禁止归还钥匙
@@ -575,6 +588,7 @@ object BleBusinessManager {
                             keyNfc!!,
                             SIKCore.getApplication().serialNo()
                         ) { isSuccess, msg, code ->
+                            logger.info("钥匙归还:${isSuccess},${msg},${code}")
                             if (!isSuccess && msg != SIKCore.getApplication().getString(
                                     R.string.ticket_lost
                                 )
@@ -595,14 +609,29 @@ object BleBusinessManager {
                                     data.taskCode?.toLong()!!,
                                     if (data.dataList?.any { it.status == 0 } == true) LockStepEnum.COLOCK.type else LockStepEnum.UNLOCKED.type
                                 )
+                                val ticketStepDataVo =
+                                    RepositoryManager.jobTicketRepo.getJobTicketStepDataByTicketId(
+                                        data.taskCode?.toLong()!!
+                                    )
+                                        .firstOrNull { it.stepStatus == "0" }
+                                ticketStepDataVo?.stepStatus = "1"
+                                val isTicketStepData = BeanUtils.copyProperties(
+                                    ticketStepDataVo,
+                                    IsJobTicketStep::class.java
+                                )
+                                isTicketStepData?.let {
+                                    logger.info("更新步骤:${it}")
+                                    RepositoryManager.jobTicketRepo.updateTicketStepData(it)
+                                }
+                                data.taskCode?.toLong()?.let {
+                                    logger.info("刷新界面:${it}")
+                                    UpdateTicketProgressEvent.sendUpdateTicketProgressEvent(it)
+                                }
+                                // 确认归还,切换为待机模式
+                                switchReadyMode(bleDevice)
                                 PopTip.tip(R.string.key_return_success)
                             }
                         }
-                        data.taskCode?.toLong()?.let {
-                            UpdateTicketProgressEvent.sendUpdateTicketProgressEvent(it)
-                        }
-                        // 确认归还,切换为待机模式
-                        switchReadyMode(bleDevice)
                     } else {
                         ThreadUtils.runOnMain {
                             // 当前策略:作业票未完成禁止归还钥匙
@@ -654,23 +683,22 @@ object BleBusinessManager {
      */
     private fun checkStepAndTicketDetailThenSendTicket(ticketId: Long, mac: String) {
         RepositoryManager.jobTicketRepo.getStepDetail(ticketId) {
-            var step = 0
-            it?.filter { it.stepStatus == "1" }
-                ?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
-                    step = it
-                }
+            var step =
+                it?.firstOrNull { it.stepStatus == "0" }?.stepIndex ?: 0
             RepositoryManager.jobTicketRepo.getTicketDetail(ticketId) { ticketDetail ->
                 if (ticketDetail == null) {
                     return@getTicketDetail
                 }
-                val role = ticketDetail?.ticketUserVOList?.find {
-                    it.userId == SPUtils.getLoginUser(SIKCore.getApplication())?.userId && it.userType == Constants.USER_TYPE_LOCKER
+                val role = ticketDetail.ticketUserVOList?.find {
+                    it.userId == MainDomainData.userInfo?.userId && MainDomainData.roleKeys?.contains(
+                        RoleEnum.JTLOCKER.roleKey
+                    ) == true
                 }
                 if (role == null) {
                     PopTip.tip(R.string.you_are_not_locker_tip)
                     return@getTicketDetail
                 }
-                if (step == 4) {    // 上锁工作票
+                if (step == LockStepEnum.LOCK.type) {    // 上锁工作票
                     sendTicketBusiness(
                         true,
                         mac,
@@ -679,7 +707,7 @@ object BleBusinessManager {
                             ?.map { it.lockNfc }?.toMutableList(),
                         true
                     )
-                } else if (step == 7) { // 解锁工作票
+                } else if (step == LockStepEnum.UNLOCK.type) { // 解锁工作票
                     sendTicketBusiness(
                         false,
                         mac,
@@ -828,14 +856,14 @@ object BleBusinessManager {
     ): String {
         logger.info("generateTicketSendJson : $lockList")
         val bo = WorkTicketSend(
-            cardNo = SPUtils.getLoginUser(SIKCore.getApplication())?.userCardList?.get(0),
+            cardNo = MainDomainData.userCardList.getOrNull(0)?.cardNfc ?: "123456",
         )
         CommonUtils.getDiffHours(vo.ticketEndTime)?.let {
             bo.effectiveTime = it
         }
         // 有配置则用配置,没用则填充默认密码
         bo.password =
-            SPUtils.getLoginUser(SIKCore.getApplication())?.keyCode ?: "123456"
+            MainDomainData.userInfo?.keyCode ?: "123456"
         val dataBO = WorkTicketSend.DataBO(
             taskCode = vo.ticketId.toString(), codeId = 1
         )

+ 12 - 4
ui-base/src/main/java/com/grkj/ui_base/business/DataBusiness.kt

@@ -15,26 +15,34 @@ object DataBusiness {
     // 1. 把 NetApi.get…Page 包成 suspend 函数
     suspend fun getSlotsPage(): CabinetSlotsRes? = suspendCancellableCoroutine { cont ->
         RepositoryManager.hardwareRepo.getIsLockCabinetSlotsPage { slots ->
-            cont.resume(slots)
+            if (cont.isActive) {
+                cont.resume(slots)
+            }
         }
     }
 
     suspend fun getLocksPage(): LockPageRes? = suspendCancellableCoroutine { cont ->
         RepositoryManager.hardwareRepo.getIsLockPage { locks ->
-            cont.resume(locks)
+            if (cont.isActive) {
+                cont.resume(locks)
+            }
         }
     }
 
     suspend fun getKeyPage(): KeyPageRes? = suspendCancellableCoroutine { cont ->
         RepositoryManager.hardwareRepo.getIsKeyPage { keys ->
-            cont.resume(keys)
+            if (cont.isActive) {
+                cont.resume(keys)
+            }
         }
     }
 
     // 2. 把原本同步的字典查询留在 IO 线程
     suspend fun fetchDict(key: String): List<com.grkj.data.model.res.CommonDictRes> =suspendCancellableCoroutine { cont ->
         RepositoryManager.hardwareRepo.getDictData(key) { dictData ->
-            cont.resume(dictData)
+            if (cont.isActive) {
+                cont.resume(dictData)
+            }
         }
     }
 }

+ 32 - 6
ui-base/src/main/java/com/grkj/ui_base/business/ModbusBusinessManager.kt

@@ -30,6 +30,7 @@ import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.async
 import kotlinx.coroutines.withContext
 import org.slf4j.LoggerFactory
+import kotlin.math.log
 import kotlin.plus
 
 /**
@@ -39,6 +40,7 @@ object ModbusBusinessManager {
     private val logger = LoggerFactory.getLogger(ModbusBusinessManager::class.java)
 
     // 设备待取列表(需要报给后台的列表,等实际取完再上报)
+    @JvmStatic
     val mDeviceTakeList = mutableListOf<DeviceTakeUpdate>()
 
     private val listeners = ArrayList<DeviceListener>()
@@ -176,6 +178,7 @@ object ModbusBusinessManager {
                                     return@runOnMain
                                 }
                                 // 检查有无当前工作票的钥匙
+                                logger.info("检查有无当前工作票的钥匙:${info.ticketId},${mDeviceTakeList.find { it.deviceType == DeviceConst.DEVICE_TYPE_KEY && it.ticketId == info.ticketId }}")
                                 mDeviceTakeList.find { it.deviceType == DeviceConst.DEVICE_TYPE_KEY && it.ticketId == info.ticketId }
                                     ?.let { itKey ->
                                         LoadingEvent.sendLoadingEvent(
@@ -405,8 +408,10 @@ object ModbusBusinessManager {
                                 ?.find { it.row?.toInt() == dockBean.row && (lockBean.idx + 1) == it.col?.toInt() } != null) {
                             PopTip.tip(R.string.slot_exception_tag)
                         } else {
+                            logger.info("挂锁归还:${lockBean.rfid}")
                             RepositoryManager.hardwareRepo.getLockInfo(rfid) {
-                                if (it != null && it?.lockNfc?.isNotEmpty() == true) {
+                                logger.info("挂锁信息:${it}")
+                                if (it != null && it.lockNfc?.isNotEmpty() == true) {
                                     // TODO 考虑快速拿取
                                     ModBusController.controlLockBuckle(
                                         false, dockBean.addr, lockBean.idx
@@ -427,7 +432,10 @@ object ModbusBusinessManager {
             }
         } else {
             logger.info("挂锁取出-:${lockBean.rfid}")
-            handleDeviceTake(DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_LOCK, lockBean.rfid),lockBean.rfid)
+            handleDeviceTake(
+                DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_LOCK, lockBean.rfid),
+                lockBean.rfid
+            )
         }
     }
 
@@ -438,6 +446,7 @@ object ModbusBusinessManager {
         dockBean: DockBean,
         keyBean: DockBean.KeyBean
     ) {
+        logger.info("钥匙状态变化DeviceKeyHandler:${keyBean}")
         if (keyBean.isExist) {
             // 放回钥匙,读取rfid
             ModBusController.readKeyRfid(
@@ -454,9 +463,11 @@ object ModbusBusinessManager {
                 }
                 val rfid =
                     res.copyOfRange(3, 11).toHexStrings(false).removeLeadingZeros()
+                logger.info("读取到的rfid:${rfid}")
                 ModBusController.updateKeyRfid(
                     dockBean.addr, keyBean.idx, rfid
                 )
+                logger.info("更新rfid完成:${keyBean}")
                 ThreadUtils.runOnIO {
                     val slotStatus =
                         async { DataBusiness.fetchDict(DictConstants.KEY_SLOT_STATUS) }
@@ -497,14 +508,14 @@ object ModbusBusinessManager {
                                     ModBusController.updateKeyMac(
                                         dockBean.addr,
                                         keyBean.idx,
-                                        it.macAddress ?: ""
+                                        it.macAddress!!
                                     )
                                     ModBusController.updateKeyReadyStatus(
-                                        it.macAddress ?: "", false, 5
+                                        it.macAddress!!, false, 5
                                     )
                                 } else {
                                     logger.error("Get key info fail : $rfid")
-                                    if (!ISCSConfig.isInit) {
+                                    if (ISCSConfig.isInit) {
                                         PopTip.tip(R.string.get_key_info_fail)
                                     }
                                     ModBusController.controlKeyBuckle(
@@ -521,7 +532,10 @@ object ModbusBusinessManager {
             keyBean.mac?.let {
                 BleConnectionManager.unregisterConnectListener(it)
             }
-            handleDeviceTake(DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_KEY, keyBean.rfid),keyBean.rfid)
+            handleDeviceTake(
+                DeviceTakeUpdateEvent(DeviceConst.DEVICE_TYPE_KEY, keyBean.rfid),
+                keyBean.rfid
+            )
         }
     }
 
@@ -533,4 +547,16 @@ object ModbusBusinessManager {
             deviceStatusHandle(res)
         }
     }
+
+    /**
+     * 是否存在工作票
+     */
+    fun checkTicketAndSendTicket(keyMac: String) {
+        logger.info("开始检查是否存在作业票")
+        val keyBean = ModBusController.getKeyByMac(keyMac)
+        mDeviceTakeList.find { it.nfc == keyBean?.rfid }?.let { itKey ->
+            logger.info("存在作业票,下发作业票")
+            BleBusinessManager.handleGiveKey(itKey)
+        }
+    }
 }

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

@@ -12,6 +12,11 @@ object ISCSConfig {
      */
     var isTestMode: Boolean = false
 
+    /**
+     * 是否在注册设备
+     */
+    var isDeviceRegistration: Boolean = false
+
     /**
      * 是否初始化中
      */

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

@@ -186,7 +186,7 @@ object BleConnectionManager {
     private fun connectKey() {
         if (connectListeners.isEmpty()) return
         if (isPreparing || BleManager.getInstance().allConnectedDevice.size >= maxStandbyCount) {
-            logger.info("暂时不能连接:${isPreparing},${BleManager.getInstance().allConnectedDevice.size > maxStandbyCount}")
+            logger.info("暂时不能连接:${isPreparing},${BleManager.getInstance().allConnectedDevice.size >= maxStandbyCount}")
             ThreadUtils.runOnMainDelayed(1000) { connectKey() }
             return
         }
@@ -210,7 +210,7 @@ object BleConnectionManager {
                 currentConnectingMac = null
                 if (!isDone) {
                     // 判断是否仍然待连,防止拿走;移到末尾,防止循环影响
-                    if (checkProcess(listener.mac)) {
+                    if (checkProcess(listener.mac,false)) {
                         listener.callBack?.invoke(false, null)
                         unregisterConnectListener(listener.mac)
                     }
@@ -236,7 +236,7 @@ object BleConnectionManager {
         isNeedLoading: Boolean = false,
         prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
     ) {
-        if (!checkProcess(mac)) {
+        if (!checkProcess(mac,false)) {
             logger.error("蓝牙连接-Prepare is canceled : $mac")
             return
         }
@@ -251,7 +251,7 @@ object BleConnectionManager {
         prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
     ) {
         logger.info("蓝牙连接-doScanBle:$mac")
-        if (!checkProcess(mac)) {
+        if (!checkProcess(mac,false)) {
             logger.error("蓝牙连接-Prepare is canceled : $mac")
             return
         }
@@ -310,7 +310,7 @@ object BleConnectionManager {
         prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
     ) {
         logger.info("蓝牙连接-doConnect : ${bleDevice.mac}")
-        if (!checkProcess(bleDevice.mac)) {
+        if (!checkProcess(bleDevice.mac,false)) {
             logger.error("蓝牙连接-Prepare is canceled : ${bleDevice.mac}")
             return
         }
@@ -354,7 +354,7 @@ object BleConnectionManager {
                             removeExceptionKey(it.mac)
                             // 设置MTU
                             ThreadUtils.runOnMainDelayed(200) {
-                                if (!checkProcess(bleDevice.mac)) {
+                                if (!checkProcess(bleDevice.mac,false)) {
                                     logger.error("Prepare is canceled : ${bleDevice.mac}")
                                     return@runOnMainDelayed
                                 }
@@ -390,15 +390,16 @@ object BleConnectionManager {
                                 return
                             }
                             // 断开和重连之间最好间隔一段时间,否则可能会出现长时间连接不上的情况
-                            ThreadUtils.runOnMainDelayed(300) {
-                                registerConnectListener(bleDevice.mac) { isDone, bleBean ->
-                                    if (isDone && bleBean != null) {
-                                        ThreadUtils.runOnMainDelayed(300) {
-                                            getCurrentStatus(6, bleBean.bleDevice)
-                                        }
-                                    }
-                                }
-                            }
+//                            ThreadUtils.runOnMainDelayed(300) {
+//                                registerConnectListener(bleDevice.mac) { isDone, bleBean ->
+//                                    if (isDone && bleBean != null) {
+//                                        ThreadUtils.runOnMainDelayed(300) {
+//                                            getCurrentStatus(6, bleBean.bleDevice)
+//                                        }
+//                                    }
+//                                }
+//                            }
+                            ModBusController.updateKeyReadyStatus(bleDevice.mac, false, 3)
                         } else {
                             ModBusController.updateKeyReadyStatus(bleDevice.mac, false, 3)
                         }
@@ -501,7 +502,7 @@ object BleConnectionManager {
         isNeedLoading: Boolean = false,
         prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
     ) {
-        if (!checkProcess(bleBean?.bleDevice?.mac)) {
+        if (!checkProcess(bleBean?.bleDevice?.mac,false)) {
             logger.error("蓝牙连接-Prepare is canceled : ${bleBean?.bleDevice?.mac}")
             return
         }
@@ -605,9 +606,13 @@ object BleConnectionManager {
                     if (isDone) {
                         // 连接成功后,把电关掉(以防万一)
                         ModBusController.controlKeyCharge(false, mac) { }
-                        cont.resume(true)
+                        if (cont.isActive) {
+                            cont.resume(true)
+                        }
                     } else {
-                        cont.resume(false)
+                        if (cont.isActive) {
+                            cont.resume(false)
+                        }
                     }
                     cont.cancel()
                 }
@@ -645,8 +650,9 @@ object BleConnectionManager {
                     isCalled = true
                     // 无论成功或失败,都先把电关掉
                     ModBusController.controlKeyCharge(false, mac) { }
-                    cont.resume(isDone)
-                    cont.cancel()
+                    if (cont.isActive) {
+                        cont.resume(isDone)
+                    }
                 }
             }
             return@withContext secondTry
@@ -695,7 +701,9 @@ object BleConnectionManager {
                                 logger.debug("设备录入-发送切换工作模式:${it.mac},${sendSuccess}")
                             }
                         }
-                        parentCont.resume(true)
+                        if (parentCont.isActive) {
+                            parentCont.resume(true)
+                        }
                     }
                 }
             })
@@ -718,13 +726,17 @@ object BleConnectionManager {
                     ) {
                         ThreadUtils.runOnIO {
                             delay(3000)
-                            cont.resume(switchWorkMode(bleDevice))
+                            if (cont.isActive) {
+                                cont.resume(switchWorkMode(bleDevice))
+                            }
                         }
                     }
 
                     override fun onWriteFailure(exception: BleException?) {
                         ThreadUtils.runOnMainDelayed(300) {
-                            cont.resume(sendEmptyTicketJson(bleDevice))
+                            if (cont.isActive) {
+                                cont.resume(sendEmptyTicketJson(bleDevice))
+                            }
                         }
                     }
                 })
@@ -748,7 +760,9 @@ object BleConnectionManager {
                         BleManager.getInstance().disconnect(bleDevice)
                         ThreadUtils.runOnIO {
                             delay(800)
-                            cont.resume(true)
+                            if (cont.isActive) {
+                                cont.resume(true)
+                            }
                         }
                         logger.debug("设备录入-切换模式发送成功 : ${bleDevice.mac}")
                     }
@@ -756,7 +770,9 @@ object BleConnectionManager {
                     override fun onWriteFailure(exception: BleException?) {
                         logger.debug("设备录入-切换模式发送失败 : ${bleDevice.mac}")
                         ThreadUtils.runOnMainDelayed(300) {
-                            cont.resume(sendEmptyTicketJson(bleDevice))
+                            if (cont.isActive) {
+                                cont.resume(sendEmptyTicketJson(bleDevice))
+                            }
                         }
                     }
                 })
@@ -793,7 +809,7 @@ object BleConnectionManager {
         BleUtil.instance?.scan(object : CustomBleScanCallback() {
             override fun onPrompt(promptStr: String?) {
                 // 蓝牙未启动重试
-                logger.debug("设备录入-参数:${promptStr}")
+                logger.info("设备录入-参数:${promptStr}")
                 BleManager.getInstance().enableBluetooth()
                 ThreadUtils.runOnMainDelayed(300) {
                     scanOnlineKeyLockMac(existsMac, callback)
@@ -801,7 +817,7 @@ object BleConnectionManager {
             }
 
             override fun onScanStarted(success: Boolean) {
-                logger.debug("设备录入-onScanStarted:${success}")
+                logger.info("设备录入-onScanStarted:${success}")
                 if (!success) {
                     ThreadUtils.runOnMainDelayed(300) {
                         scanOnlineKeyLockMac(existsMac, callback)
@@ -811,14 +827,15 @@ object BleConnectionManager {
 
             override fun onScanning(bleDevice: BleDevice?) {
                 val mac = bleDevice?.mac ?: return
-                logger.debug("设备录入-onScanning:$mac")
+                logger.info("设备录入-onScanning:$mac")
                 if (mac !in existsMac) {
-                    callback(bleDevice)
+                    BleManager.getInstance().cancelScan()
                 }
             }
 
             override fun onScanFinished(scanResultList: MutableList<BleDevice>?) {
-                logger.debug("设备录入-扫描完成:$scanResultList")
+                logger.info("设备录入-扫描完成:${scanResultList?.joinToString(","){it.mac}}")
+                callback(scanResultList?.find { it.mac !in existsMac })
             }
         })
     }

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

@@ -7,7 +7,7 @@ object BleConst {
 
     const val BLE_LOCAL_NAME = "keyLock"
 
-    const val MAX_KEY_STAND_BY: Int = 1
+    const val MAX_KEY_STAND_BY: Int = 2
     const val MAX_KEY_CONNECT_COUNT: Int = 2
 
     const val MTU = 500

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

@@ -58,6 +58,7 @@ class BleUtil private constructor() {
             if (BleManager.getInstance().isBlueEnable) {
                 BleManager.getInstance().scan(bleScanCallback)
             } else {
+                BleManager.getInstance().enableBluetooth()
                 bleScanCallback.onPrompt("请打开您的蓝牙后重试")
             }
         } else {

+ 1 - 1
ui-base/src/main/java/com/grkj/ui_base/utils/event/LoadingEvent.kt

@@ -12,7 +12,7 @@ class LoadingEvent(val msg: String? = null, val isShow: Boolean = false) {
          * 发送加载通知
          */
         @JvmStatic
-        fun sendLoadingEvent(msg: String? = null, isShow: Boolean = false) {
+        fun sendLoadingEvent(msg: String? = null, isShow: Boolean = !msg.isNullOrEmpty()) {
             val loadingEventBean = EventBean<LoadingEvent>(
                 EventConstants.EVENT_LOADING_CODE,
                 LoadingEvent(msg, isShow)

+ 6 - 10
ui-base/src/main/java/com/grkj/ui_base/utils/extension/Context.kt

@@ -39,17 +39,13 @@ fun Context.serialNo(): String {
 /**
  * 检查权限
  */
-fun Context.checkPermissions(permissions: Array<String>): Boolean {
-    for (permission in permissions) {
-        if (ContextCompat.checkSelfPermission(
-                this,
-                permission
-            ) != PackageManager.PERMISSION_GRANTED
-        ) {
-            return false
-        }
+fun Context.checkPermissions(permissions: Array<String>): List<Boolean> {
+    return permissions.map {
+        ContextCompat.checkSelfPermission(
+            this,
+            it
+        ) != PackageManager.PERMISSION_GRANTED
     }
-    return true
 }
 
 /**

+ 3 - 2
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/DockBean.kt

@@ -549,10 +549,11 @@ class DockBean(
         lockEnabled: Boolean = false,
         var rfid: String?,
         var mac: String?,
-        var isReady: Boolean = false    // 钥匙是否准备好(连接上且为待机模式)
+        var isReady: Boolean = false,    // 钥匙是否准备好(连接上且为待机模式)
+        var power: Int = 0 //电量
     ) : DeviceBean(DeviceConst.DEVICE_TYPE_KEY, idx, isExist, lockEnabled) {
         override fun toString(): String {
-            return "KeyBean( isCharging=$isCharging, rfid=$rfid, mac=$mac, isReady=$isReady, idx=$idx, isExist=$isExist)"
+            return "KeyBean( isCharging=$isCharging, rfid=$rfid, mac=$mac, isReady=$isReady, idx=$idx, isExist=$isExist, power=$power)"
         }
 
         fun clone(): KeyBean {

+ 33 - 18
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusController.kt

@@ -12,6 +12,7 @@ import com.grkj.ui_base.utils.event.ModbusInitCompleteEvent
 import com.grkj.ui_base.utils.extension.removeLeadingZeros
 import com.grkj.ui_base.utils.extension.toHexStrings
 import com.kongzue.dialogx.dialogs.PopTip
+import com.sik.sikcore.thread.ThreadUtils
 import org.slf4j.Logger
 import org.slf4j.LoggerFactory
 import java.util.concurrent.atomic.AtomicInteger
@@ -210,34 +211,40 @@ object ModBusController {
                             // 更新rfid
                             updateKeyRfid(dockBean.addr, key.idx, rfid)
                             // 蓝牙准备操作
-                            RepositoryManager.hardwareRepo.getKeyInfo(rfid) {
-                                logger.info("getKeyInfo : $rfid - ${it?.macAddress}")
+                            RepositoryManager.hardwareRepo.getKeyInfo(rfid) { keyInfo ->
+                                logger.info("getKeyInfo : $rfid - ${keyInfo?.macAddress}")
                                 updateKeyNewHardware(
                                     dockBean.addr,
                                     key.idx,
-                                    it?.keyNfc?.isEmpty() == true || it?.macAddress?.isEmpty() == true
+                                    keyInfo?.keyNfc?.isEmpty() == true || keyInfo?.macAddress?.isEmpty() == true
                                 )
-                                if (it != null && !it.macAddress.isNullOrEmpty()) {
+                                if (keyInfo != null && !keyInfo.macAddress.isNullOrEmpty()) {
                                     // 更新mac
-                                    updateKeyMac(dockBean.addr, key.idx, it.macAddress!!)
+                                    updateKeyMac(dockBean.addr, key.idx, keyInfo.macAddress!!)
                                     //已经初始化完成才会去连接
                                     if (ISCSConfig.isInit) {
-                                        BleConnectionManager.registerConnectListener(
-                                            it.macAddress!!
-                                        ) { isDone, bleBean ->
-                                            if (isDone && bleBean?.bleDevice != null) {
-                                                Executor.delayOnMain(500) {
-                                                    BleConnectionManager.getCurrentStatus(
-                                                        3, bleBean.bleDevice
-                                                    )
-                                                    BleConnectionManager.getBatteryPower(bleBean.bleDevice)
+                                        ThreadUtils.runOnIO {
+                                            val isConnect =
+                                                BleConnectionManager.tryConnectWithOptionalCharge(
+                                                    keyInfo.macAddress!!
+                                                )
+                                            if (isConnect) {
+                                                val bleBean =
+                                                    BleConnectionManager.getBleDeviceByMac(keyInfo.macAddress)
+                                                bleBean?.let {
+                                                    Executor.delayOnMain(500) {
+                                                        BleConnectionManager.getCurrentStatus(
+                                                            3, it.bleDevice
+                                                        )
+                                                        BleConnectionManager.getBatteryPower(it.bleDevice)
+                                                    }
                                                 }
                                             }
                                         }
                                     }
                                     controlKeyBuckle(false, key.idx, dockBean.addr)
                                 } else {
-                                    if (!ISCSConfig.isInit) {
+                                    if (ISCSConfig.isInit) {
                                         PopTip.tip(CommonUtils.getStr(R.string.get_key_info_fail))
                                     }
                                     controlKeyBuckle(true, key.idx, dockBean.addr)
@@ -993,14 +1000,14 @@ object ModBusController {
         }.filterIsInstance<DockBean.KeyBean>()
             .filterIndexed { idx, _ -> (idx + 1) !in slotCols }.filter { kb ->
                 !kb.rfid.isNullOrEmpty() && kb.rfid !in exceptionKeysRfid && kb.mac !in exceptionKeysMac && !kb.mac.isNullOrEmpty() && kb.isExist
-            }.shuffled()
+            }
 
         logger.info("蓝牙连接-获取到钥匙信息:${keyList}")
         if (keyList.isEmpty()) {
-            PopTip.tip(R.string.no_available_key)
             return null
         }
-        keyList.sortedBy { BleConnectionManager.getBleDeviceByMac(it.mac)?.token != null }
+        keyList.sortedByDescending { it.power }
+            .sortedBy { BleConnectionManager.getBleDeviceByMac(it.mac)?.token != null }
 
         for (kb in keyList) {
             val mac = kb.mac ?: continue
@@ -1089,4 +1096,12 @@ object ModBusController {
             }
         }
     }
+
+    /**
+     * 更新钥匙电量
+     */
+    fun updateKeyPower(power: Int, keyMac: String) {
+        val keyBean = getKeyByMac(keyMac)
+        keyBean?.power = power
+    }
 }

+ 1 - 2
ui-base/src/main/java/com/grkj/ui_base/utils/modbus/ModBusManager.kt

@@ -183,8 +183,7 @@ class ModBusManager(
         listener: (List<ByteArray>) -> Unit,
         delayMills: Long
     ): ModBusManager {
-        val keep = interrupt?.invoke()?.run { this.isEmpty() || !this[0] } ?: false
-        logger.info("是否中断:${!keep}")
+        val keep = interrupt?.invoke()?.run { this.isEmpty() || !this[0] } == true
         if (keep) {
             sendToAll(frame) {
                 if (running) {

+ 6 - 6
ui-base/src/main/res/layout-land/common_dialog_loading_progress.xml

@@ -17,7 +17,7 @@
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:textColor="@android:color/white"
-            android:textSize="28sp"
+            android:textSize="@dimen/loading_text_size"
             android:visibility="gone"
             tools:text="title"
             tools:visibility="visible" />
@@ -28,17 +28,17 @@
             android:layout_height="wrap_content"
             app:indicatorColor="@android:color/white"
             app:indicatorName="PacmanIndicator"
-            app:maxHeight="152dp"
-            app:maxWidth="152dp"
-            app:minHeight="152dp"
-            app:minWidth="152dp" />
+            app:maxHeight="@dimen/loading_size"
+            app:maxWidth="@dimen/loading_size"
+            app:minHeight="@dimen/loading_size"
+            app:minWidth="@dimen/loading_size" />
 
         <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:textSize="@dimen/loading_text_size"
             android:visibility="gone"
             tools:text="adjfksadfj"
             tools:visibility="visible" />