Prechádzať zdrojové kódy

refactor(更新)
- 作业的共锁人的事件取消
- 异常作业管理和异常作业详情界面完成,逻辑待测

周文健 4 mesiacov pred
rodič
commit
a6fdd9be2e
32 zmenil súbory, kde vykonal 729 pridanie a 176 odobranie
  1. 5 0
      app/src/main/java/com/grkj/iscs/common/DataTransferConstants.kt
  2. 5 6
      app/src/main/java/com/grkj/iscs/features/init/fragment/InitDeviceRegistrationKeyAndLockFragment.kt
  3. 287 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/exception_manage/ExceptionJobFragment.kt
  4. 2 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/exception_manage/ExceptionManageFragment.kt
  5. 1 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/exception_manage/ExceptionManageHomeFragment.kt
  6. 10 0
      app/src/main/java/com/grkj/iscs/features/main/fragment/hardware_manage/SlotsManageFragment.kt
  7. 30 50
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/ExceptionJobManageFragment.kt
  8. 0 6
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobExecuteFragment.kt
  9. 1 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobManageHomeFragment.kt
  10. 176 0
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/exception_manage/ExceptionJobViewModel.kt
  11. 18 0
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/exception_manage/ExceptionViewModel.kt
  12. 8 2
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobManageViewModel.kt
  13. 4 2
      app/src/main/res/layout/fragment_exception_detail.xml
  14. 46 47
      app/src/main/res/layout/fragment_exception_job.xml
  15. 9 19
      app/src/main/res/layout/fragment_exception_job_manage.xml
  16. 37 0
      app/src/main/res/layout/item_exception_job_manage.xml
  17. 19 0
      app/src/main/res/navigation/nav_exception_job_manage.xml
  18. 4 14
      app/src/main/res/navigation/nav_exception_manage.xml
  19. 12 23
      app/src/main/res/navigation/nav_job_manage.xml
  20. 3 1
      app/src/main/res/values-en/strings.xml
  21. 2 0
      app/src/main/res/values-zh/strings.xml
  22. 2 0
      app/src/main/res/values/strings.xml
  23. 7 0
      data/src/main/java/com/grkj/data/dao/ExceptionDao.kt
  24. 6 2
      data/src/main/java/com/grkj/data/dao/JobTicketDao.kt
  25. 1 1
      data/src/main/java/com/grkj/data/model/dos/IsExceptionSourceStandard.kt
  26. 6 0
      data/src/main/java/com/grkj/data/model/vo/IsExceptionStandardVo.kt
  27. 5 0
      data/src/main/java/com/grkj/data/model/vo/JobTicketManageVo.kt
  28. 5 0
      data/src/main/java/com/grkj/data/repository/IExceptionRepository.kt
  29. 4 0
      data/src/main/java/com/grkj/data/repository/impl/network/NetworkExceptionRepository.kt
  30. 4 0
      data/src/main/java/com/grkj/data/repository/impl/standard/ExceptionRepository.kt
  31. 2 1
      ui-base/src/main/java/com/grkj/ui_base/utils/ble/BleConnectionManager.kt
  32. 8 0
      ui-base/src/main/res/drawable/common_btn_white_board.xml

+ 5 - 0
app/src/main/java/com/grkj/iscs/common/DataTransferConstants.kt

@@ -48,6 +48,11 @@ object DataTransferConstants {
      */
     const val KEY_JOB_TICKET_ID = "key_job_ticket_id"
 
+    /**
+     * 异常id
+     */
+    const val KEY_EXCEPTION_ID = "key_exception_id"
+
     /**
      * 异常数据
      */

+ 5 - 6
app/src/main/java/com/grkj/iscs/features/init/fragment/InitDeviceRegistrationKeyAndLockFragment.kt

@@ -64,8 +64,7 @@ class InitDeviceRegistrationKeyAndLockFragment :
         }
         binding.dockRv.linear().dividerSpace(
             requireContext().resources.getDimension(com.grkj.ui_base.R.dimen.common_spacing_2x)
-                .toInt(),
-            DividerOrientation.GRID
+                .toInt(), DividerOrientation.GRID
         ).setup {
             addType<DockData.KeyDock>(R.layout.item_device_registration_key_layout)
             addType<DockData.LockDock>(R.layout.item_device_registration_lock_layout)
@@ -122,11 +121,11 @@ class InitDeviceRegistrationKeyAndLockFragment :
                     (newKeyDockList + portableDock + lockDock).isNotEmpty()
                 val allDevice = newKeyDockList + portableDock + lockDock
                 val newKeyCount =
-                    newKeyDock.keyData.count { it.newHardware } + portableDock.map { it.deviceData }
-                        .count { it is DockBean.KeyBean }
+                    newKeyDock.keyData.count { it.newHardware && it.rfid != null && it.mac != null } + portableDock.map { it.deviceData }
+                        .count { it is DockBean.KeyBean&& it.newHardware && it.rfid != null&& it.mac != null  }
                 val newLockCount = lockDock.map { it.lockData }.flatten()
-                    .count { it.newHardware } + portableDock.map { it.deviceData }
-                    .count { it is DockBean.LockBean }
+                    .count { it.newHardware && it.rfid != null } + portableDock.map { it.deviceData }
+                    .count { it is DockBean.LockBean && it.newHardware && it.rfid != null }
                 binding.checkDeviceInfo.text =
                     getString(R.string.check_device_info, newKeyCount, newLockCount)
                 binding.dockRv.models = allDevice

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

@@ -1,18 +1,305 @@
 package com.grkj.iscs.features.main.fragment.exception_manage
 
+import android.graphics.drawable.GradientDrawable
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import androidx.core.view.isVisible
+import androidx.fragment.app.viewModels
+import com.drake.brv.BindingAdapter
+import com.drake.brv.annotaion.DividerOrientation
+import com.drake.brv.utils.dividerSpace
+import com.drake.brv.utils.grid
+import com.drake.brv.utils.linear
+import com.drake.brv.utils.models
+import com.drake.brv.utils.setup
+import com.grkj.data.enums.RoleEnum
+import com.grkj.data.model.dos.WorkflowStep
+import com.grkj.data.model.vo.IsJobTicketPointsDataVo
+import com.grkj.data.model.vo.IsJobTicketStepDataVo
+import com.grkj.data.model.vo.IsJobTicketUserDataVo
 import com.grkj.iscs.R
+import com.grkj.iscs.common.DataTransferConstants
 import com.grkj.iscs.databinding.FragmentExceptionJobBinding
+import com.grkj.iscs.databinding.ItemJobExecuteColockBinding
+import com.grkj.iscs.databinding.ItemJobExecutePointBinding
+import com.grkj.iscs.databinding.ItemJobExecuteStepBinding
+import com.grkj.iscs.features.main.viewmodel.exception_manage.ExceptionJobViewModel
 import com.grkj.ui_base.base.BaseFragment
+import com.grkj.ui_base.dialog.TipDialog
+import com.grkj.ui_base.utils.CommonUtils
+import com.grkj.ui_base.utils.extension.toggleExpandView
+import com.kongzue.dialogx.dialogs.PopTip
+import com.sik.sikcore.data.GlobalDataTempStore
+import com.sik.sikcore.extension.setDebouncedClickListener
 
 /**
  * 异常作业界面
  */
 class ExceptionJobFragment : BaseFragment<FragmentExceptionJobBinding>() {
+    private val viewModel: ExceptionJobViewModel by viewModels()
+    private var currentTab: Int = 0
     override fun getLayoutId(): Int {
         return R.layout.fragment_exception_job
     }
 
     override fun initView() {
+        binding.back.setDebouncedClickListener {
+            if ((binding.dataLayout.parent as ViewGroup).id == binding.fullScreenRootLayout.id) {
+                binding.spaceView.isVisible = false
+                toggleExpandView(binding.fullScreenRootLayout, binding.dataLayout, true)
+                binding.fullScreen.isVisible = true
+            } else {
+                navController.popBackStack()
+            }
+        }
+        binding.listRv.linear().setup {
+            addType<IsJobTicketPointsDataVo>(R.layout.item_job_execute_point)
+            onBind {
+                onPointsRVListBinding(this)
+            }
+        }
+        binding.stepRv.linear(orientation = LinearLayout.HORIZONTAL).setup {
+            addType<IsJobTicketStepDataVo>(R.layout.item_job_execute_step)
+            onBind {
+                onStepRVListBinding(this)
+            }
+        }
+        binding.cancelException.setDebouncedClickListener {
+            viewModel.cancelException().observe(this) {
+                navController.popBackStack()
+            }
+        }
+        binding.handleException.setDebouncedClickListener {
+            viewModel.handleException().observe(this) {
+                navController.popBackStack()
+            }
+        }
+        binding.waitToColockRv.grid(3).dividerSpace(10, DividerOrientation.GRID).setup {
+            addType<IsJobTicketUserDataVo>(R.layout.item_job_execute_colock)
+            onBind {
+                onColockerRVListBinding(this)
+            }
+        }
 
+        binding.alreadyColockRv.grid(3).dividerSpace(10, DividerOrientation.GRID).setup {
+            addType<IsJobTicketUserDataVo>(R.layout.item_job_execute_colock)
+            onBind {
+                onColockerRVListBinding(this)
+            }
+        }
+
+        binding.alreadyUncolockRv.grid(3).dividerSpace(10, DividerOrientation.GRID).setup {
+            addType<IsJobTicketUserDataVo>(R.layout.item_job_execute_colock)
+            onBind {
+                onColockerRVListBinding(this)
+            }
+        }
+        binding.fullScreen.setDebouncedClickListener {
+            toggleExpandView(binding.fullScreenRootLayout, binding.dataLayout, false)
+            binding.fullScreen.isVisible = false
+            binding.spaceView.isVisible = true
+        }
+        binding.descriptionTab.setDebouncedClickListener {
+            checkLayout(0)
+        }
+        binding.lockerTab.setDebouncedClickListener {
+            checkLayout(1)
+        }
+        binding.colockerTab.setDebouncedClickListener {
+            checkLayout(2)
+        }
+    }
+
+    /**
+     * 检查界面
+     */
+    private fun checkLayout(index: Int) {
+        currentTab = index
+        binding.descriptionTab.isSelected = index == 0
+        binding.lockerTab.isSelected = index == 1
+        binding.colockerTab.isSelected = index == 2
+        binding.stepDescriptionTv.isVisible = index == 0
+        binding.lockStatusLayout.isVisible = index == 1
+        binding.colockerLayout.isVisible = index == 2
+        binding.dataTitleTv.text = when (index) {
+            0 -> CommonUtils.getStr(
+                R.string.job_execute_step_description,
+                viewModel.workflowSteps.find { it.stepId == viewModel.currentStepData?.workflowStepId }?.stepTitle
+                    ?: ""
+            ).toString()
+
+            1 -> CommonUtils.getStr(R.string.job_execute_lock_status_title).toString()
+            2 -> CommonUtils.getStr(R.string.job_execute_colocker_colock_status_title).toString()
+            else -> ""
+        }
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onStepRVListBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemJobExecuteStepBinding>()
+        val item = holder.getModel<IsJobTicketStepDataVo>()
+        itemBinding.stepIconIv.setImageResource(getStepIcon(viewModel.workflowSteps.find { it.stepId == item.workflowStepId }))
+        itemBinding.stepNameTv.text =
+            viewModel.workflowSteps.find { it.stepId == item.workflowStepId }?.stepTitleShort
+        itemBinding.stepIndexTv.text = item.stepIndex.toString()
+        itemBinding.dividerIv.isVisible = item.stepId != viewModel.ticketStep.last().stepId
+        val bg = itemBinding.stepLayout.background
+        when (item.stepStatus) {
+            "1" -> {
+                if (bg is GradientDrawable) {
+                    bg.mutate()  // 拷贝一份,避免影响到其它引用了同一个 drawable 的 view
+                    bg.setColor(requireContext().getColor(R.color.color_b2f2bb))
+                }
+            }
+
+            "0" -> {
+                if (item.stepId == viewModel.currentStepData?.stepId) {
+                    if (bg is GradientDrawable) {
+                        bg.mutate()  // 拷贝一份,避免影响到其它引用了同一个 drawable 的 view
+                        bg.setColor(requireContext().getColor(R.color.color_ffec99))
+                    }
+                } else {
+                    itemBinding.stepLayout.backgroundTintList = null
+                }
+            }
+        }
+    }
+
+    private fun onColockerRVListBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemJobExecuteColockBinding>()
+        val item = holder.getModel<IsJobTicketUserDataVo>()
+        itemBinding.name.text = item.nickName
+    }
+
+    private fun getStepIcon(workflowStep: WorkflowStep?): Int {
+        if (workflowStep == null) {
+            return 0
+        }
+        return when {
+            workflowStep.stepTitleShort?.contains(
+                CommonUtils.getStr(com.grkj.ui_base.R.string.recognize_work_content).toString()
+            ) == true -> R.mipmap.icon_loto_step_1
+
+            workflowStep.stepTitleShort?.contains(
+                CommonUtils.getStr(com.grkj.ui_base.R.string.power_isolation_way).toString()
+            ) == true -> R.mipmap.icon_loto_step_2
+
+            workflowStep.stepTitleShort?.contains(
+                CommonUtils.getStr(com.grkj.ui_base.R.string.shutdown).toString()
+            ) == true -> R.mipmap.icon_loto_step_4
+
+            workflowStep.stepTitleShort?.contains(
+                CommonUtils.getStr(com.grkj.ui_base.R.string.ensure_power_isolation).toString()
+            ) == true -> R.mipmap.icon_loto_step_6
+
+            workflowStep.stepTitleShort?.contains(
+                CommonUtils.getStr(com.grkj.ui_base.R.string.check_before_unlocking).toString()
+            ) == true -> R.mipmap.icon_loto_step_7
+
+            workflowStep.stepTitleShort?.contains(
+                CommonUtils.getStr(com.grkj.ui_base.R.string.unlock_and_restore_switch).toString()
+            ) == true -> R.mipmap.icon_loto_step_8
+
+            workflowStep.enableSetLocker || workflowStep.enableSetColocker -> R.mipmap.icon_step_select_member
+            workflowStep.enableLock -> R.mipmap.icon_step_lock
+            workflowStep.enableColock -> R.mipmap.icon_step_colock
+            workflowStep.enableUnlock -> R.mipmap.icon_step_unlock
+            else -> 0
+        }
+    }
+
+    private fun BindingAdapter.BindingViewHolder.onPointsRVListBinding(holder: BindingAdapter.BindingViewHolder) {
+        val itemBinding = holder.getBinding<ItemJobExecutePointBinding>()
+        val item = holder.getModel<IsJobTicketPointsDataVo>()
+        itemBinding.pointName.text = item.pointName
+        itemBinding.pointFunction.text = item.pointFunction
+        itemBinding.lockStatusLayout.isVisible = item.pointStatus != "0"
+        if (item.pointStatus == "1") {
+            itemBinding.lockStatusLayout.setBackgroundResource(R.drawable.bg_btn_job_execute_go_locking)
+            itemBinding.lockStatusIv.setImageResource(R.drawable.icon_ticket_lock)
+            itemBinding.lockStatusTv.text =
+                requireContext().getText(com.grkj.ui_base.R.string.has_locked)
+        } else if (item.pointStatus == "2") {
+            itemBinding.lockStatusLayout.setBackgroundResource(R.drawable.bg_btn_job_execute_go_unlocking)
+            itemBinding.lockStatusIv.setImageResource(R.drawable.icon_ticket_unlock)
+            itemBinding.lockStatusTv.text =
+                requireContext().getText(com.grkj.ui_base.R.string.unlocked)
+        }
+    }
+
+    override fun initData() {
+        super.initData()
+        if (!GlobalDataTempStore.getInstance().hasData(DataTransferConstants.KEY_JOB_TICKET_ID)) {
+            PopTip.tip(R.string.job_lost)
+            navController.popBackStack()
+            return
+        }
+        if (!GlobalDataTempStore.getInstance().hasData(DataTransferConstants.KEY_EXCEPTION_ID)) {
+            PopTip.tip(R.string.exception_lost)
+            navController.popBackStack()
+            return
+        }
+        viewModel.getWorkflowModes().observe(this) {
+            viewModel.ticketId = GlobalDataTempStore.getInstance()
+                .getData(DataTransferConstants.KEY_JOB_TICKET_ID) as Long
+            viewModel.exceptionId = GlobalDataTempStore.getInstance()
+                .getData(DataTransferConstants.KEY_EXCEPTION_ID) as Long
+            getData()
+        }
+    }
+
+    private fun getData() {
+        viewModel.getExceptionData().observe(this) {
+            binding.exceptionDescription.text =
+                viewModel.exceptionData?.exceptionDescription?.joinToString(",")
+        }
+        viewModel.getJobTicketData().observe(this) {
+            if (it) {
+                viewModel.isUnlockFirst(viewModel.ticketData?.modeId!!).observe(this) {}
+                viewModel.getWorkflowSteps(viewModel.ticketData?.modeId!!).observe(this) {
+                    binding.exceptionJob.text = viewModel.ticketData!!.ticketName
+                    binding.jobNameTv.text = getString(R.string.exception_job_title)
+                    binding.listRv.models = viewModel.ticketPoints
+                    binding.stepRv.models = viewModel.ticketStep
+                    viewModel.currentStepData =
+                        viewModel.ticketStep.firstOrNull { it.stepStatus == "0" }
+                    binding.stepDescriptionTv.text =
+                        viewModel.workflowSteps.find { it.stepId == viewModel.currentStepData?.workflowStepId }?.stepDescription
+                    refreshTicketUser()
+                    checkLayout(currentTab)
+                }
+            } else {
+                TipDialog.showError(
+                    msg = CommonUtils.getStr(com.grkj.ui_base.R.string.ticket_lost).toString(),
+                    onConfirmClick = {
+                        navController.popBackStack()
+                    },
+                    onCancelClick = {
+                        navController.popBackStack()
+                    })
+            }
+        }
+    }
+
+    private fun refreshTicketUser() {
+        viewModel.ticketUser.let {
+            binding.waitToColockRv.models =
+                it.filter { it.jobStatus == "0" && it.userRole == RoleEnum.JTCOLOCKER.roleKey }
+            binding.waitToColock.text =
+                getString(
+                    R.string.wait_to_colock,
+                    it.count { it.jobStatus == "0" && it.userRole == RoleEnum.JTCOLOCKER.roleKey })
+            binding.alreadyColockRv.models =
+                it.filter { it.jobStatus == "1" && it.userRole == RoleEnum.JTCOLOCKER.roleKey }
+            binding.alreadyColock.text =
+                getString(
+                    R.string.already_colock,
+                    it.count { it.jobStatus == "1" && it.userRole == RoleEnum.JTCOLOCKER.roleKey })
+            binding.alreadyUncolockRv.models =
+                it.filter { it.jobStatus == "2" && it.userRole == RoleEnum.JTCOLOCKER.roleKey }
+            binding.alreadyUncolock.text =
+                getString(
+                    R.string.already_uncolock,
+                    it.count { it.jobStatus == "2" && it.userRole == RoleEnum.JTCOLOCKER.roleKey })
+        }
     }
 }

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

@@ -19,10 +19,12 @@ import com.grkj.ui_base.dialog.TipDialog
 import com.kongzue.dialogx.dialogs.PopTip
 import com.sik.sikcore.data.GlobalDataTempStore
 import com.sik.sikcore.extension.setDebouncedClickListener
+import dagger.hilt.android.AndroidEntryPoint
 
 /**
  * 异常管理界面
  */
+@AndroidEntryPoint
 class ExceptionManageFragment : BaseFragment<FragmentExceptionManageBinding>() {
     private val viewModel: ExceptionViewModel by viewModels()
     override fun getLayoutId(): Int {

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

@@ -98,7 +98,7 @@ class ExceptionManageHomeFragment : BaseFragment<FragmentExceptionManageHomeBind
             }
 
             2 -> {
-                navController.navigate(R.id.action_exceptionManageHomeFragment_to_exceptionJobManageFragment2)
+                navController.navigate(R.id.action_exceptionManageHomeFragment_to_nav_exception_job_manage)
             }
         }
     }

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

@@ -75,6 +75,11 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
                 }
             }
         }.models = dockDataList
+        if (MainDomainData.roleKeys?.contains(RoleEnum.ADMIN.roleKey) == true ||
+            MainDomainData.roleKeys?.contains(RoleEnum.SYSCONFIG.roleKey) == true
+        ) {
+            ISCSConfig.isDeviceRegistration = true
+        }
         ModBusController.controlAllKeyChargeDown()
         viewModel.isDestroy = false
     }
@@ -548,6 +553,11 @@ class SlotsManageFragment : BaseFragment<FragmentSlotsManageBinding>() {
 
     override fun onDestroyView() {
         viewModel.isDestroy = true
+        if (MainDomainData.roleKeys?.contains(RoleEnum.ADMIN.roleKey) == true ||
+            MainDomainData.roleKeys?.contains(RoleEnum.SYSCONFIG.roleKey) == true
+        ) {
+            ISCSConfig.isDeviceRegistration = false
+        }
         super.onDestroyView()
     }
 

+ 30 - 50
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/ExceptionJobManageFragment.kt

@@ -8,13 +8,14 @@ import com.drake.brv.utils.divider
 import com.drake.brv.utils.linear
 import com.drake.brv.utils.models
 import com.drake.brv.utils.setup
-import com.grkj.data.enums.JobTicketStatusEnum
-import com.grkj.data.model.vo.JobTicketManageVo
+import com.grkj.data.model.vo.IsExceptionStandardVo
 import com.grkj.iscs.R
+import com.grkj.iscs.common.DataTransferConstants
 import com.grkj.iscs.databinding.FragmentExceptionJobManageBinding
-import com.grkj.iscs.databinding.ItemJobManageBinding
-import com.grkj.iscs.features.main.viewmodel.job_manage.JobManageViewModel
+import com.grkj.iscs.databinding.ItemExceptionJobManageBinding
+import com.grkj.iscs.features.main.viewmodel.exception_manage.ExceptionViewModel
 import com.grkj.ui_base.base.BaseFragment
+import com.sik.sikcore.data.GlobalDataTempStore
 import com.sik.sikcore.extension.setDebouncedClickListener
 import dagger.hilt.android.AndroidEntryPoint
 
@@ -23,7 +24,7 @@ import dagger.hilt.android.AndroidEntryPoint
  */
 @AndroidEntryPoint
 class ExceptionJobManageFragment : BaseFragment<FragmentExceptionJobManageBinding>() {
-    private val viewModel: JobManageViewModel by viewModels()
+    private val viewModel: ExceptionViewModel by viewModels()
     override fun getLayoutId(): Int {
         return R.layout.fragment_exception_job_manage
     }
@@ -32,69 +33,48 @@ class ExceptionJobManageFragment : BaseFragment<FragmentExceptionJobManageBindin
         binding.back.setDebouncedClickListener {
             navController.popBackStack()
         }
-        binding.refreshLayout.setOnRefreshListener {
-            getData(nextPage = false)
-        }
-        binding.refreshLayout.setOnLoadMoreListener {
-            getData()
-        }
         binding.listRv.linear().divider {
             this.setColor(Color.BLACK)
             this.startVisible = false
             this.endVisible = true
             this.orientation = DividerOrientation.VERTICAL
         }.setup {
-            addType<JobTicketManageVo>(R.layout.item_job_manage)
+            addType<IsExceptionStandardVo>(R.layout.item_exception_job_manage)
             onBind {
                 onListDataBinding(this)
             }
         }
-        setSelectAllListener()
-    }
-
-    private fun setSelectAllListener() {
-        binding.selectAll.setOnCheckedChangeListener { v, checked ->
-            viewModel.jobManageDataList.forEach { it.isSelected = checked }
-            binding.listRv.adapter?.notifyDataSetChanged()
-        }
     }
 
     private fun onListDataBinding(holder: BindingAdapter.BindingViewHolder) {
-        val itemBinding = holder.getBinding<ItemJobManageBinding>()
-        val item = holder.getModel<JobTicketManageVo>()
-        itemBinding.jobName.text = item.ticketName
-        itemBinding.status.text = JobTicketStatusEnum.getTicketStatusStr(item.ticketStatus)
-        itemBinding.select.setOnCheckedChangeListener(null)
-        itemBinding.select.isChecked = item.isSelected
-        itemBinding.select.setOnCheckedChangeListener { _, checked ->
-            item.isSelected = checked
-            binding.selectAll.setOnCheckedChangeListener(null)
-            binding.selectAll.isChecked = viewModel.jobManageDataList.all { it.isSelected }
-            setSelectAllListener()
+        val itemBinding = holder.getBinding<ItemExceptionJobManageBinding>()
+        val item = holder.getModel<IsExceptionStandardVo>()
+        itemBinding.jobName.text = item.jobTicketData?.ticketName
+        //异常原因
+        itemBinding.exceptionDescription.text = item.exceptionDescription?.joinToString(",")
+        itemBinding.status.text =
+            viewModel.exceptionStatus.find { it.dictValue == item.exceptionStatus.toString() }?.dictLabel
+        itemBinding.root.setDebouncedClickListener {
+            GlobalDataTempStore.getInstance()
+                .saveData(DataTransferConstants.KEY_EXCEPTION_ID, item.exceptionId)
+            GlobalDataTempStore.getInstance()
+                .saveData(
+                    DataTransferConstants.KEY_JOB_TICKET_ID,
+                    item.jobTicketData?.ticketId ?: 0
+                )
+            navController.navigate(R.id.action_exceptionJobManageFragment_to_exceptionJobFragment)
         }
     }
 
-    override fun initData() {
-        super.initData()
-        getData(nextPage = false)
+    override fun onResume() {
+        super.onResume()
+        getData()
     }
 
-    private fun getData(nextPage: Boolean = true) {
-        viewModel.getData(nextPage).observe(this) {
-            if (!nextPage) {
-                binding.selectAll.setOnCheckedChangeListener(null)
-                binding.selectAll.isChecked = false
-                setSelectAllListener()
-            }
-            binding.refreshLayout.finishRefresh()
-            binding.refreshLayout.finishLoadMore()
-            binding.listRv.models = viewModel.jobManageDataList.filter {
-                it.ticketStatus in listOf(
-                    JobTicketStatusEnum.SELECT_MEMBER,
-                    JobTicketStatusEnum.LOCKING,
-                    JobTicketStatusEnum.COLOCKING,
-                    JobTicketStatusEnum.UNLOCKING
-                ).map { it.status }
+    private fun getData() {
+        viewModel.getDictData().observe(this) {
+            viewModel.getExceptionData().observe(this) {
+                binding.listRv.models = viewModel.exceptionDataList
             }
         }
     }

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

@@ -314,12 +314,6 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
         val itemBinding = holder.getBinding<ItemJobExecuteColockBinding>()
         val item = holder.getModel<IsJobTicketUserDataVo>()
         itemBinding.name.text = item.nickName
-        itemBinding.root.setOnClickListener {
-            item.jobStatus = ((item.jobStatus ?: "0").toInt() + 1).toString()
-            viewModel.colockerStatusChange(item).observe(this@JobExecuteFragment) {
-                getData()
-            }
-        }
     }
 
     private fun getStepIcon(workflowStep: WorkflowStep?): Int {

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

@@ -160,7 +160,7 @@ class JobManageHomeFragment : BaseFragment<FragmentJobManageHomeBinding>() {
             }
 
             3 -> {
-                navController.navigate(R.id.action_jobManageHomeFragment_to_exceptionJobManageFragment)
+                navController.navigate(R.id.action_jobManageHomeFragment_to_nav_exception_job_manage)
             }
 
             4 -> {

+ 176 - 0
app/src/main/java/com/grkj/iscs/features/main/viewmodel/exception_manage/ExceptionJobViewModel.kt

@@ -0,0 +1,176 @@
+package com.grkj.iscs.features.main.viewmodel.exception_manage
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.liveData
+import com.grkj.data.enums.RoleEnum
+import com.grkj.data.model.dos.IsJobTicketStep
+import com.grkj.data.model.dos.WorkflowMode
+import com.grkj.data.model.dos.WorkflowStep
+import com.grkj.data.model.vo.IsExceptionStandardVo
+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.IsJobTicketStepDataVo
+import com.grkj.data.model.vo.IsJobTicketUserDataVo
+import com.grkj.data.model.vo.UserManageVo
+import com.grkj.data.repository.IExceptionRepository
+import com.grkj.data.repository.IJobTicketRepository
+import com.grkj.data.repository.IWorkflowRepository
+import com.grkj.iscs.R
+import com.grkj.ui_base.base.BaseViewModel
+import com.grkj.ui_base.utils.CommonUtils
+import com.sik.sikcore.data.BeanUtils
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.Dispatchers
+import javax.inject.Inject
+
+/**
+ * 作业执行数据
+ */
+@HiltViewModel
+class ExceptionJobViewModel @Inject constructor(
+    val exceptionRepository: IExceptionRepository,
+    val jobTicketRepository: IJobTicketRepository,
+    val workflowRepository: IWorkflowRepository
+) : BaseViewModel() {
+    var ticketId: Long = 0
+    var exceptionId: Long = 0
+    var ticketData: IsJobTicketDataVo? = null
+    lateinit var ticketKey: List<IsJobTicketKeyDataVo>
+    lateinit var ticketLock: List<IsJobTicketLockDataVo>
+    lateinit var ticketPoints: List<IsJobTicketPointsDataVo>
+    lateinit var ticketStep: List<IsJobTicketStepDataVo>
+    lateinit var ticketUser: List<IsJobTicketUserDataVo>
+    var selectedLockerData: List<UserManageVo> = mutableListOf()
+    var selecteColockerData: List<UserManageVo> = mutableListOf()
+    var currentStepData: IsJobTicketStepDataVo? = null
+    var workflowModes: List<WorkflowMode> = mutableListOf()
+    var workflowSteps: List<WorkflowStep> = mutableListOf()
+    var isUnlockFirst: Boolean = false
+
+    /**
+     * 异常数据
+     */
+    var exceptionData: IsExceptionStandardVo? = null
+
+    /**
+     * 获取当前流程步骤数据
+     */
+    fun getCurrentWorkflowStep(): WorkflowStep? {
+        return workflowSteps.find { it.stepId == currentStepData?.workflowStepId }
+    }
+
+    /**
+     * 获取作业数据
+     */
+    fun getJobTicketData(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            ticketData = jobTicketRepository.getJobTicketDataByTicketId(ticketId)
+            if (ticketData == null) {
+                emit(false)
+                return@liveData
+            }
+            ticketKey = jobTicketRepository.getJobTicketKeyDataByTicketId(ticketId)
+            ticketLock = jobTicketRepository.getJobTicketLockDataByTicketId(ticketId)
+            ticketPoints = jobTicketRepository.getJobTicketPointsDataByTicketId(ticketId)
+            ticketStep = jobTicketRepository.getJobTicketStepDataByTicketId(ticketId)
+            ticketUser = jobTicketRepository.getJobTicketUserDataByTicketId(ticketId)
+            val tempJobTicketUserId = jobTicketRepository.getTicketUsersByTicketId(ticketId)
+            selectedLockerData =
+                tempJobTicketUserId.filter { it.roleKeys.contains(RoleEnum.JTLOCKER.roleKey) }
+            selecteColockerData =
+                tempJobTicketUserId.filter { it.roleKeys.contains(RoleEnum.JTCOLOCKER.roleKey) }
+            ticketStep.sortedBy { it.stepIndex }
+            emit(true)
+        }
+    }
+
+    /**
+     * 获取流程模式列表
+     */
+    fun getWorkflowModes(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            workflowModes = workflowRepository.getWorkflowModes()
+            emit(true)
+        }
+    }
+
+    /**
+     * 获取流程步骤列表
+     */
+    fun getWorkflowSteps(modeId: Long): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            workflowSteps = workflowRepository.getStepsByMode(modeId)
+            for (stepDataVo in ticketStep) {
+                val workflowStep = workflowSteps.find { it.stepId == stepDataVo.workflowStepId }
+                //如果是自动确认并且没有操作的功能,则更新步骤
+                if (workflowStep?.confirmType != 0 && workflowStep?.hasAnyOperationFunction() == false) {
+                    stepDataVo.stepStatus = "1"
+                    BeanUtils.copyProperties(
+                        stepDataVo, IsJobTicketStep::class.java
+                    )?.let { jobTicketStep ->
+                        jobTicketRepository.updateTicketStepData(jobTicketStep)
+                        currentStepData =
+                            ticketStep.find { it.stepIndex == jobTicketStep.stepIndex + 1 }
+                        val currentWorkflowStep = workflowSteps.find {
+                            it.stepId == ticketStep.firstOrNull { it.stepStatus == "0" }?.workflowStepId
+                        }
+                        ticketData?.ticketStatus =
+                            currentWorkflowStep?.getTicketStatus() ?: ""
+                        jobTicketRepository.updateTicketDataStatus(
+                            ticketId, currentWorkflowStep?.getTicketStatus()?.toInt() ?: 0
+                        )
+                    }
+                } else {
+                    break
+                }
+            }
+            emit(true)
+        }
+    }
+
+    /**
+     * 是否解锁优先
+     */
+    fun isUnlockFirst(modeId: Long): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            isUnlockFirst = workflowRepository.isUnlockBeforeLock(modeId)
+            emit(true)
+        }
+    }
+
+    /**
+     * 处理选中异常
+     */
+    fun handleException(): LiveData<Pair<Boolean, String>> {
+        return liveData(Dispatchers.IO) {
+            exceptionData?.let {
+                exceptionRepository.handleException(listOf(it))
+                emit(true to "")
+            } ?: emit(false to CommonUtils.getStr(R.string.exception_data_not_exists).toString())
+        }
+    }
+
+    /**
+     * 取消选中异常
+     */
+    fun cancelException(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            exceptionData?.let {
+                exceptionRepository.cancelException(listOf(it))
+                emit(true)
+            } ?: emit(false)
+        }
+    }
+
+    /**
+     * 获取异常数据
+     */
+    fun getExceptionData(): LiveData<Boolean> {
+        return liveData(Dispatchers.IO) {
+            exceptionData = exceptionRepository.getExceptionDataById(exceptionId)
+            emit(true)
+        }
+    }
+}

+ 18 - 0
app/src/main/java/com/grkj/iscs/features/main/viewmodel/exception_manage/ExceptionViewModel.kt

@@ -7,6 +7,7 @@ import com.grkj.data.dao.JobTicketDao
 import com.grkj.data.data.DictConstants
 import com.grkj.data.model.res.CommonDictRes
 import com.grkj.data.model.vo.IsExceptionStandardVo
+import com.grkj.data.model.vo.JobTicketManageVo
 import com.grkj.data.repository.IExceptionRepository
 import com.grkj.data.repository.IHardwareRepository
 import com.grkj.data.repository.IJobTicketRepository
@@ -34,6 +35,11 @@ class ExceptionViewModel @Inject constructor(
      */
     var exceptionType: List<CommonDictRes> = mutableListOf()
 
+    /**
+     * 异常数据源类型
+     */
+    var exceptionSourceDataType: List<CommonDictRes> = mutableListOf()
+
     /**
      * 异常状态
      */
@@ -56,6 +62,8 @@ class ExceptionViewModel @Inject constructor(
         return liveData(Dispatchers.IO) {
             exceptionType = DataBusiness.fetchDict(DictConstants.KEY_EXCEPTION_TYPE)
             exceptionStatus = DataBusiness.fetchDict(DictConstants.KEY_EXCEPTION_STATUS)
+            exceptionSourceDataType =
+                DataBusiness.fetchDict(DictConstants.KEY_EXCEPTION_SOURCE_TYPE)
             emit(true)
         }
     }
@@ -66,6 +74,16 @@ class ExceptionViewModel @Inject constructor(
     fun getExceptionData(): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
             exceptionDataList = exceptionRepository.getExceptionData()
+            exceptionDataList.filter { it.exceptionType.toString() == exceptionType.find { it.dictLabel == "作业异常" }?.dictValue }
+                .forEach { item ->
+                    item.sourceData.find { it.sourceDataType.toString() == exceptionSourceDataType.find { it.dictLabel == "作业" }?.dictValue }
+                        ?.let { sourceData ->
+                            jobTicketRepository.getTicketDataByTicketId(sourceData.sourceDataId)
+                                ?.let {
+                                    item.jobTicketData = it
+                                }
+                        }
+                }
             emit(true)
         }
     }

+ 8 - 2
app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobManageViewModel.kt

@@ -2,9 +2,13 @@ package com.grkj.iscs.features.main.viewmodel.job_manage
 
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
+import com.grkj.data.data.DictConstants
+import com.grkj.data.model.res.CommonDictRes
 import com.grkj.data.model.vo.JobTicketManageVo
+import com.grkj.data.repository.IExceptionRepository
 import com.grkj.data.repository.IJobTicketRepository
 import com.grkj.ui_base.base.BaseViewModel
+import com.grkj.ui_base.business.DataBusiness
 import dagger.hilt.android.lifecycle.HiltViewModel
 import javax.inject.Inject
 import kotlinx.coroutines.Dispatchers
@@ -13,7 +17,9 @@ import kotlinx.coroutines.Dispatchers
  * 作业管理
  */
 @HiltViewModel
-class JobManageViewModel @Inject constructor(val jobTicketRepository: IJobTicketRepository) : BaseViewModel() {
+class JobManageViewModel @Inject constructor(
+    val jobTicketRepository: IJobTicketRepository,
+) : BaseViewModel() {
     var jobManageDataList: MutableList<JobTicketManageVo> = mutableListOf()
     private var current: Int = 0
     private var size: Int = 50
@@ -30,7 +36,7 @@ class JobManageViewModel @Inject constructor(val jobTicketRepository: IJobTicket
     }
 
     /**
-     * 获取sop数据
+     * 获取数据
      */
     fun getData(nextPage: Boolean): LiveData<Boolean> {
         if (nextPage) {

+ 4 - 2
app/src/main/res/layout/fragment_exception_detail.xml

@@ -40,14 +40,15 @@
                 android:layout_height="wrap_content"
                 android:layout_marginVertical="5dp"
                 android:layout_marginLeft="@dimen/common_spacing"
-                android:background="@drawable/common_btn"
+                android:background="@drawable/common_btn_white_board"
                 android:drawableLeft="@mipmap/icon_back"
                 android:drawablePadding="@dimen/common_spacing"
+                android:drawableTint="@color/white"
                 android:gravity="center"
                 android:minHeight="@dimen/common_btn_height"
                 android:paddingHorizontal="@dimen/common_spacing_2x"
                 android:text="@string/back"
-                android:textColor="@color/black"
+                android:textColor="@color/white"
                 android:textSize="@dimen/common_btn_text_size" />
         </LinearLayout>
 
@@ -82,6 +83,7 @@
                 </TableRow>
 
                 <TableRow>
+
                     <TextView
                         style="@style/TableCellKey"
                         android:text="@string/exception_source" />

+ 46 - 47
app/src/main/res/layout/fragment_exception_job.xml

@@ -14,6 +14,7 @@
             android:id="@+id/title_layout"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:background="@color/common_status_red"
             android:gravity="center_vertical"
             android:orientation="horizontal"
             android:paddingHorizontal="@dimen/common_spacing">
@@ -29,8 +30,8 @@
                 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:text="@string/exception_job_title"
+                android:textColor="@color/white"
                 android:textSize="@dimen/normal_text_size_25"
                 android:textStyle="bold" />
 
@@ -40,14 +41,15 @@
                 android:layout_height="wrap_content"
                 android:layout_marginVertical="5dp"
                 android:layout_marginLeft="@dimen/common_spacing"
-                android:background="@drawable/common_btn"
+                android:background="@drawable/common_btn_white_board"
                 android:drawableLeft="@mipmap/icon_back"
                 android:drawablePadding="@dimen/common_spacing"
+                android:drawableTint="@color/white"
                 android:gravity="center"
                 android:minHeight="@dimen/common_btn_height"
                 android:paddingHorizontal="@dimen/common_spacing_2x"
                 android:text="@string/back"
-                android:textColor="@color/black"
+                android:textColor="@color/white"
                 android:textSize="@dimen/common_btn_text_size" />
         </LinearLayout>
 
@@ -66,6 +68,40 @@
                 android:layout_height="match_parent"
                 android:orientation="vertical">
 
+                <TableLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginHorizontal="@dimen/common_spacing_2x"
+                    android:layout_marginTop="@dimen/common_spacing_2x"
+                    android:background="@drawable/table_border"
+                    android:shrinkColumns="1"
+                    android:stretchColumns="1">
+
+                    <TableRow>
+
+                        <TextView
+                            style="@style/TableCellKey"
+                            android:text="@string/exception_job" />
+
+                        <TextView
+                            android:id="@+id/exception_job"
+                            style="@style/TableCellValue"
+                            tools:text="仓位异常" />
+                    </TableRow>
+
+                    <TableRow>
+
+                        <TextView
+                            style="@style/TableCellKey"
+                            android:text="@string/exception_description" />
+
+                        <TextView
+                            android:id="@+id/exception_description"
+                            style="@style/TableCellValue"
+                            tools:text="仓位2-7" />
+                    </TableRow>
+                </TableLayout>
+
                 <androidx.recyclerview.widget.RecyclerView
                     android:id="@+id/step_rv"
                     android:layout_width="match_parent"
@@ -382,72 +418,35 @@
                     android:paddingVertical="@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/common_btn_cancel"
-                        android:drawableLeft="@drawable/icon_ticket_lock"
-                        android:drawablePadding="@dimen/common_spacing"
-                        android:drawableTint="@color/white"
-                        android:gravity="center"
-                        android:minHeight="@dimen/common_btn_height"
-                        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:id="@+id/cancel_exception"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:layout_marginLeft="@dimen/common_spacing"
                         android:background="@drawable/common_btn_confirm"
-                        android:drawableLeft="@drawable/icon_ticket_unlock"
                         android:drawablePadding="@dimen/common_spacing"
                         android:drawableTint="@color/white"
                         android:gravity="center"
                         android:minHeight="@dimen/common_btn_height"
                         android:paddingHorizontal="@dimen/common_spacing"
-                        android:text="@string/go_unlocking"
+                        android:text="@string/cancel_exception"
                         android:textColor="@color/white"
-                        android:textSize="@dimen/common_btn_text_size"
-                        android:visibility="gone" />
+                        android:textSize="@dimen/common_btn_text_size" />
 
                     <TextView
-                        android:id="@+id/cancel_job"
+                        android:id="@+id/handle_exception"
                         android:layout_width="wrap_content"
                         android:layout_height="wrap_content"
                         android:layout_marginLeft="@dimen/common_spacing"
                         android:background="@drawable/common_btn_cancel"
-                        android:drawableLeft="@drawable/icon_close"
                         android:drawablePadding="@dimen/common_spacing"
                         android:drawableTint="@color/white"
                         android:gravity="center"
                         android:minHeight="@dimen/common_btn_height"
                         android:paddingHorizontal="@dimen/common_spacing"
-                        android:text="@string/cancel_the_job"
+                        android:text="@string/handle_exception"
                         android:textColor="@color/white"
-                        android:textSize="@dimen/common_btn_text_size"
-                        android:visibility="gone" />
+                        android:textSize="@dimen/common_btn_text_size" />
 
-                    <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/common_btn_confirm"
-                        android:drawableLeft="@mipmap/icon_confirm"
-                        android:drawablePadding="@dimen/common_spacing"
-                        android:drawableTint="@color/white"
-                        android:gravity="center"
-                        android:minHeight="@dimen/common_btn_height"
-                        android:paddingHorizontal="@dimen/common_spacing"
-                        android:text="@string/finish_the_job"
-                        android:textColor="@color/white"
-                        android:textSize="@dimen/common_btn_text_size"
-                        android:visibility="gone" />
                 </LinearLayout>
             </LinearLayout>
         </FrameLayout>

+ 9 - 19
app/src/main/res/layout/fragment_exception_job_manage.xml

@@ -28,8 +28,8 @@
                 android:layout_weight="1"
                 android:text="@string/exception_job_title"
                 android:textColor="@color/black"
-                android:textStyle="bold"
-                android:textSize="@dimen/normal_text_size_25" />
+                android:textSize="@dimen/normal_text_size_25"
+                android:textStyle="bold" />
 
             <TextView
                 android:id="@+id/back"
@@ -62,18 +62,12 @@
             android:divider="@drawable/divider_table"
             android:showDividers="middle">
 
-            <CheckBox
-                android:id="@+id/select_all"
-                android:layout_width="30dp"
-                android:layout_height="30dp"
-                android:layout_gravity="center"
-                android:layout_margin="@dimen/common_spacing" />
-
             <TextView
                 android:layout_width="0dp"
                 android:layout_height="match_parent"
                 android:layout_weight="1"
                 android:gravity="center"
+                android:paddingVertical="@dimen/common_spacing"
                 android:text="@string/job_name"
                 android:textSize="@dimen/common_text_size" />
 
@@ -82,6 +76,7 @@
                 android:layout_height="match_parent"
                 android:layout_weight="1"
                 android:gravity="center"
+                android:paddingVertical="@dimen/common_spacing"
                 android:text="@string/exception_reason"
                 android:textSize="@dimen/common_text_size" />
 
@@ -90,22 +85,17 @@
                 android:layout_height="match_parent"
                 android:layout_weight="1"
                 android:gravity="center"
+                android:paddingVertical="@dimen/common_spacing"
                 android:text="@string/detail"
                 android:textSize="@dimen/common_text_size" />
         </LinearLayout>
 
-        <com.scwang.smart.refresh.layout.SmartRefreshLayout
-            android:id="@+id/refresh_layout"
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/list_rv"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_marginHorizontal="@dimen/common_spacing_2x"
-            android:layout_marginBottom="@dimen/common_spacing">
-
-            <androidx.recyclerview.widget.RecyclerView
-                android:id="@+id/list_rv"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:background="@drawable/common_card_bg" />
-        </com.scwang.smart.refresh.layout.SmartRefreshLayout>
+            android:layout_marginBottom="@dimen/common_spacing"
+            android:background="@drawable/common_card_bg" />
     </LinearLayout>
 </layout>

+ 37 - 0
app/src/main/res/layout/item_exception_job_manage.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:divider="@drawable/divider_table"
+        android:showDividers="middle">
+
+        <TextView
+            android:id="@+id/job_name"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:ellipsize="end"
+            android:gravity="center"
+            android:paddingVertical="@dimen/common_spacing"
+            android:singleLine="true"
+            android:textSize="@dimen/common_text_size" />
+
+        <TextView
+            android:id="@+id/exception_description"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textSize="@dimen/common_text_size" />
+
+        <TextView
+            android:id="@+id/status"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textSize="@dimen/common_text_size" />
+    </LinearLayout>
+</layout>

+ 19 - 0
app/src/main/res/navigation/nav_exception_job_manage.xml

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<navigation xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/nav_exception_job_manage"
+    app:startDestination="@id/exceptionJobManageFragment">
+
+    <fragment
+        android:id="@+id/exceptionJobManageFragment"
+        android:name="com.grkj.iscs.features.main.fragment.job_manage.ExceptionJobManageFragment"
+        android:label="ExceptionJobManageFragment" >
+        <action
+            android:id="@+id/action_exceptionJobManageFragment_to_exceptionJobFragment"
+            app:destination="@id/exceptionJobFragment" />
+    </fragment>
+    <fragment
+        android:id="@+id/exceptionJobFragment"
+        android:name="com.grkj.iscs.features.main.fragment.exception_manage.ExceptionJobFragment"
+        android:label="ExceptionJobFragment" />
+</navigation>

+ 4 - 14
app/src/main/res/navigation/nav_exception_manage.xml

@@ -15,8 +15,8 @@
             android:id="@+id/action_exceptionManageHomeFragment_to_exceptionReportFragment"
             app:destination="@id/exceptionReportFragment" />
         <action
-            android:id="@+id/action_exceptionManageHomeFragment_to_exceptionJobManageFragment2"
-            app:destination="@id/exceptionJobManageFragment2" />
+            android:id="@+id/action_exceptionManageHomeFragment_to_nav_exception_job_manage"
+            app:destination="@id/nav_exception_job_manage" />
     </fragment>
     <fragment
         android:id="@+id/exceptionManageFragment"
@@ -34,16 +34,6 @@
         android:id="@+id/exceptionDetailFragment"
         android:name="com.grkj.iscs.features.main.fragment.exception_manage.ExceptionDetailFragment"
         android:label="ExceptionDetailFragment" />
-    <fragment
-        android:id="@+id/exceptionJobFragment"
-        android:name="com.grkj.iscs.features.main.fragment.exception_manage.ExceptionJobFragment"
-        android:label="ExceptionJobFragment" />
-    <fragment
-        android:id="@+id/exceptionJobManageFragment2"
-        android:name="com.grkj.iscs.features.main.fragment.job_manage.ExceptionJobManageFragment"
-        android:label="ExceptionJobManageFragment" >
-        <action
-            android:id="@+id/action_exceptionJobManageFragment2_to_exceptionJobFragment"
-            app:destination="@id/exceptionJobFragment" />
-    </fragment>
+
+    <include app:graph="@navigation/nav_exception_job_manage" />
 </navigation>

+ 12 - 23
app/src/main/res/navigation/nav_job_manage.xml

@@ -4,6 +4,7 @@
     android:id="@+id/nav_job_manage"
     app:startDestination="@id/jobManageHomeFragment">
 
+    <include app:graph="@navigation/nav_exception_job_manage" />
     <fragment
         android:id="@+id/jobManageHomeFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.JobManageHomeFragment"
@@ -30,13 +31,13 @@
             android:id="@+id/action_jobManageHomeFragment_to_lockedPointsFragment"
             app:destination="@id/lockedPointsFragment" />
         <action
-            android:id="@+id/action_jobManageHomeFragment_to_exceptionJobManageFragment"
-            app:destination="@id/exceptionJobManageFragment" />
+            android:id="@+id/action_jobManageHomeFragment_to_nav_exception_job_manage"
+            app:destination="@id/nav_exception_job_manage" />
     </fragment>
     <fragment
         android:id="@+id/createJobFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.CreateJobFragment"
-        android:label="CreateJobFragment" >
+        android:label="CreateJobFragment">
         <action
             android:id="@+id/action_createJobFragment_to_selectPointFragment"
             app:destination="@id/selectPointFragment" />
@@ -87,7 +88,7 @@
     <fragment
         android:id="@+id/sopManageFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.SopManageFragment"
-        android:label="SopManageFragment" >
+        android:label="SopManageFragment">
         <action
             android:id="@+id/action_sopManageFragment_to_editSopFragment"
             app:destination="@id/editSopFragment" />
@@ -95,7 +96,7 @@
     <fragment
         android:id="@+id/editSopFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.EditSopFragment"
-        android:label="EditSopFragment" >
+        android:label="EditSopFragment">
         <action
             android:id="@+id/action_editSopFragment_to_selectMemberFragment"
             app:destination="@id/selectMemberFragment" />
@@ -109,7 +110,7 @@
     <fragment
         android:id="@+id/jobManageFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.JobManageFragment"
-        android:label="JobManageFragment" >
+        android:label="JobManageFragment">
         <action
             android:id="@+id/action_jobManageFragment_to_selectMemberFragment"
             app:destination="@id/selectMemberFragment" />
@@ -129,7 +130,7 @@
     <fragment
         android:id="@+id/editJobFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.EditJobFragment"
-        android:label="EditJobFragment" >
+        android:label="EditJobFragment">
         <action
             android:id="@+id/action_editJobFragment_to_selectMemberFragment"
             app:destination="@id/selectMemberFragment" />
@@ -140,7 +141,7 @@
             android:id="@+id/action_editJobFragment_to_jobExecuteFragment"
             app:destination="@id/jobExecuteFragment"
             app:popUpTo="@id/editJobFragment"
-            app:popUpToInclusive="true"  />
+            app:popUpToInclusive="true" />
         <action
             android:id="@+id/action_editJobFragment_to_workflowSettingFragment"
             app:destination="@id/workflowSettingFragment" />
@@ -148,7 +149,7 @@
     <fragment
         android:id="@+id/editSopJobFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.EditSopJobFragment"
-        android:label="EditSopJobFragment" >
+        android:label="EditSopJobFragment">
         <action
             android:id="@+id/action_editSopJobFragment_to_selectMemberFragment"
             app:destination="@id/selectMemberFragment" />
@@ -164,7 +165,7 @@
     <fragment
         android:id="@+id/jobExecuteFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.JobExecuteFragment"
-        android:label="JobExecuteFragment" >
+        android:label="JobExecuteFragment">
         <action
             android:id="@+id/action_jobExecuteFragment_to_selectMemberFragment"
             app:destination="@id/selectMemberFragment" />
@@ -172,7 +173,7 @@
     <fragment
         android:id="@+id/inProgressJobManageFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.InProgressJobManageFragment"
-        android:label="InProgressJobManageFragment" >
+        android:label="InProgressJobManageFragment">
         <action
             android:id="@+id/action_inProgressJobManageFragment_to_jobExecuteFragment"
             app:destination="@id/jobExecuteFragment" />
@@ -181,20 +182,8 @@
         android:id="@+id/lockedPointsFragment"
         android:name="com.grkj.iscs.features.main.fragment.job_manage.LockedPointsFragment"
         android:label="LockedPointsFragment" />
-    <fragment
-        android:id="@+id/exceptionJobManageFragment"
-        android:name="com.grkj.iscs.features.main.fragment.job_manage.ExceptionJobManageFragment"
-        android:label="ExceptionJobManageFragment" >
-        <action
-            android:id="@+id/action_exceptionJobManageFragment_to_exceptionJobFragment2"
-            app:destination="@id/exceptionJobFragment2" />
-    </fragment>
     <fragment
         android:id="@+id/workflowSettingFragment"
         android:name="com.grkj.iscs.features.main.fragment.common.WorkflowSettingFragment"
         android:label="WorkflowSettingFragment" />
-    <fragment
-        android:id="@+id/exceptionJobFragment2"
-        android:name="com.grkj.iscs.features.main.fragment.exception_manage.ExceptionJobFragment"
-        android:label="ExceptionJobFragment" />
 </navigation>

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

@@ -430,6 +430,8 @@
     <string name="handle_exception_success">Handle exception success</string>
     <string name="exception_data_not_exists">Exception data not exists</string>
     <string name="cancel_exception_failed">Cancel exception failed</string>
-    <string name="job_execute_title">作业执行</string>
+    <string name="job_execute_title">Job execute</string>
+    <string name="exception_lost">Exception lost</string>
+    <string name="exception_job">Exception job:</string>
 
 </resources>

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

@@ -431,5 +431,7 @@
     <string name="exception_data_not_exists">异常数据不存在</string>
     <string name="cancel_exception_failed">取消异常失败</string>
     <string name="job_execute_title">作业执行</string>
+    <string name="exception_lost">异常丢失</string>
+    <string name="exception_job">异常作业:</string>
 
 </resources>

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

@@ -434,5 +434,7 @@
     <string name="exception_data_not_exists">异常数据不存在</string>
     <string name="cancel_exception_failed">取消异常失败</string>
     <string name="job_execute_title">作业执行</string>
+    <string name="exception_lost">异常丢失</string>
+    <string name="exception_job">异常作业:</string>
 
 </resources>

+ 7 - 0
data/src/main/java/com/grkj/data/dao/ExceptionDao.kt

@@ -24,4 +24,11 @@ interface ExceptionDao {
     @Transaction
     @Query("select * from is_exception_standard")
     fun getExceptionData(): List<IsExceptionStandardVo>
+
+    /**
+     * 根据异常id获取异常数据
+     */
+    @Transaction
+    @Query("select * from is_exception_standard where exception_id = :exceptionId")
+    fun getExceptionDataById(exceptionId: Long): IsExceptionStandardVo?
 }

+ 6 - 2
data/src/main/java/com/grkj/data/dao/JobTicketDao.kt

@@ -121,7 +121,9 @@ interface JobTicketDao {
         ticket_status as ticketStatus,
         workstation_id as workstationId,
         sop_id as sopId,
-        mode_id
+        mode_id,
+        ex_status,
+        remark
         from is_job_ticket ijt
         order by update_time desc 
         limit :size offset :offset
@@ -186,7 +188,9 @@ interface JobTicketDao {
         ticket_status as ticketStatus,
         workstation_id as workstationId,
         sop_id as sopId,
-        mode_id
+        mode_id,
+        ex_status,
+        remark
         from is_job_ticket ijt
         where ticket_id = :ticketId
     """

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

@@ -3,7 +3,7 @@ package com.grkj.data.model.dos
 import androidx.room.*
 
 @Entity(tableName = "is_exception_source_standard")
-class IsExceptionSourceStandard : BaseBean() {
+open class IsExceptionSourceStandard : BaseBean() {
 
     @PrimaryKey(autoGenerate = true)
     @ColumnInfo(name = "source_id")

+ 6 - 0
data/src/main/java/com/grkj/data/model/vo/IsExceptionStandardVo.kt

@@ -34,6 +34,12 @@ class IsExceptionStandardVo {
     )
     var sourceData: List<IsExceptionSourceStandard> = listOf()
 
+    /**
+     * 作业票
+     */
+    @Ignore
+    var jobTicketData: JobTicketManageVo? = null
+
     @Relation(
         parentColumn = "reporter_id", entityColumn = "user_id"
     )

+ 5 - 0
data/src/main/java/com/grkj/data/model/vo/JobTicketManageVo.kt

@@ -30,6 +30,11 @@ class JobTicketManageVo {
     )
     var steps: List<WorkflowStep> = listOf()
 
+    @ColumnInfo(name = "ex_status")
+    var exStatus: Int? = null
+    
+    var remark: String? = null
+
     @Ignore
     var isSelected: Boolean = false
 }

+ 5 - 0
data/src/main/java/com/grkj/data/repository/IExceptionRepository.kt

@@ -20,4 +20,9 @@ interface IExceptionRepository {
      * 处理异常
      */
     fun handleException(exceptionData: List<IsExceptionStandardVo>)
+
+    /**
+     * 根据异常id获取异常数据
+     */
+    fun getExceptionDataById(exceptionId: Long): IsExceptionStandardVo?
 }

+ 4 - 0
data/src/main/java/com/grkj/data/repository/impl/network/NetworkExceptionRepository.kt

@@ -22,4 +22,8 @@ class NetworkExceptionRepository @Inject constructor() : BaseRepository(), IExce
     override fun handleException(exceptionData: List<IsExceptionStandardVo>) {
         TODO("Not yet implemented")
     }
+
+    override fun getExceptionDataById(exceptionId: Long): IsExceptionStandardVo? {
+        TODO("Not yet implemented")
+    }
 }

+ 4 - 0
data/src/main/java/com/grkj/data/repository/impl/standard/ExceptionRepository.kt

@@ -73,4 +73,8 @@ class ExceptionRepository @Inject constructor(
             exceptionDao.updateException(isExceptionData)
         }
     }
+
+    override fun getExceptionDataById(exceptionId: Long): IsExceptionStandardVo? {
+        return exceptionDao.getExceptionDataById(exceptionId)
+    }
 }

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

@@ -131,6 +131,7 @@ object BleConnectionManager {
      * - 如果 mac 已在待连接队列或正在连接,忽略重复请求
      * - 否则将 mac 添加到队列并触发连接流程
      */
+    @Synchronized
     fun registerConnectListener(
         mac: String,
         connectNow: Boolean = false,
@@ -156,7 +157,7 @@ object BleConnectionManager {
             unregisterConnectListener(mac)
         }
         // 重复注册检查
-        if (connectListeners.any { it.mac == mac } || currentConnectingMac == mac) {
+        if (currentConnectingMac == mac) {
             logger.warn("忽略重复注册 mac: $mac")
             callBack?.invoke(false, null)
             return

+ 8 - 0
ui-base/src/main/res/drawable/common_btn_white_board.xml

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