소스 검색

feat(作业管理)
- 我的待办、作业执行、异常作业的步骤确认权限调整
- 异常上报选择作业时,同步更新作业状态为“异常”
- 异常处理作业异常时,增加共锁、交叉作业校验

refactor(作业管理)
- 优化我的待办数据处理逻辑
- 优化异常作业流程步骤获取逻辑
- 优化作业执行、异常作业步骤提示语
- 作业执行、编辑SOP作业、新建SOP作业的工作站选择器修改为树形下拉框
- 异常详情页面代码结构优化

fix(作业管理)
- 修复进行中作业管理列表异常状态显示错误的问题
- 修复异常作业全屏时背景色未切换的问题

周文健 3 달 전
부모
커밋
c3c2eb29c9
21개의 변경된 파일479개의 추가작업 그리고 277개의 파일을 삭제
  1. 7 3
      app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt
  2. 258 0
      app/src/main/java/com/grkj/iscs/features/main/entity/TodoDataExtension.kt
  3. 85 54
      app/src/main/java/com/grkj/iscs/features/main/fragment/exception_manage/ExceptionDetailFragment.kt
  4. 7 8
      app/src/main/java/com/grkj/iscs/features/main/fragment/exception_manage/ExceptionJobFragment.kt
  5. 1 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/CreateSopJobFragment.kt
  6. 1 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/EditSopFragment.kt
  7. 1 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/EditSopJobFragment.kt
  8. 4 1
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/InProgressJobManageFragment.kt
  9. 8 3
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/JobExecuteFragment.kt
  10. 7 5
      app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/MyTodoListFragment.kt
  11. 8 23
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/exception_manage/ExceptionJobViewModel.kt
  12. 8 2
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/exception_manage/ExceptionViewModel.kt
  13. 27 1
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/home/HomeViewModel.kt
  14. 9 4
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobExecuteViewModel.kt
  15. 32 4
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobManageHomeViewModel.kt
  16. 3 161
      app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/MyTodoViewModel.kt
  17. 2 2
      data/src/main/java/com/grkj/data/dao/JobTicketDao.kt
  18. 1 1
      data/src/main/java/com/grkj/data/model/local/TodoStepJoin.kt
  19. 8 1
      data/src/main/java/com/grkj/data/repository/impl/standard/ExceptionRepository.kt
  20. 1 0
      data/src/main/java/com/grkj/data/repository/impl/standard/JobTicketRepository.kt
  21. 1 1
      ui-base/src/main/java/com/grkj/ui_base/base/BaseActivity.kt

+ 7 - 3
app/src/main/java/com/grkj/iscs/features/main/activity/MainActivity.kt

@@ -143,13 +143,17 @@ class MainActivity() : BaseActivity<ActivityMainBinding>() {
                 binding.navBar.selectedItemId = firstId
                 MainDomainData.fromQuickEntry = false
             }
-            if (navController.graph.id != userInfoNavGraph) {
-                userInfoNavGraph = 0
-            }
             binding.navBar.isVisible = bottomNavDestinations.contains(destination.id)
         }
     }
 
+    override fun replaceNavGraph(graphId: Int) {
+        super.replaceNavGraph(graphId)
+        if (navController.graph.id != userInfoNavGraph) {
+            userInfoNavGraph = 0
+        }
+    }
+
     override fun onEvent(event: EventBean<Any>) {
         super.onEvent(event)
         when (event.code) {

+ 258 - 0
app/src/main/java/com/grkj/iscs/features/main/entity/TodoDataExtension.kt

@@ -0,0 +1,258 @@
+package com.grkj.iscs.features.main.entity
+
+import com.grkj.data.data.MainDomainData
+import com.grkj.data.enums.JobTicketStatusEnum
+import com.grkj.data.enums.OperationTypeEnum
+import com.grkj.data.enums.TodoStatusEnum
+import com.grkj.data.model.local.TodoStepJoin
+import com.grkj.data.model.vo.TodoItemVo
+import kotlin.collections.contains
+
+/**
+ * 转换todo数据
+ */
+fun TodoStepJoin.toTodoVo(sameTicketStepJoinData: List<TodoStepJoin>): TodoItemVo {
+    val isCreator = createBy == MainDomainData.userInfo?.userName
+    val type = OperationTypeEnum.fromJoin(this, isCreator)
+    val temp = this
+    return TodoItemVo().apply {
+        this.todoId = temp.stepId
+        this.ticketId = temp.ticketId
+        this.ticketName = temp.ticketName
+        this.ticketStatus = temp.ticketStatus
+        this.stepId = temp.stepId
+        this.workflowStepId = temp.workflowStepId
+        this.stepIndex = temp.stepIndex
+        this.isCurrentStep =
+            sameTicketStepJoinData.filter { it.stepStatus == "0" }
+                .minByOrNull { it.stepIndex }?.stepIndex == temp.stepIndex || (sameTicketStepJoinData.none {
+                it.stepStatus == "0"
+            } && temp.enableEndJob)
+        this.todoTitle = temp.stepTitleShort ?: temp.stepTitle
+        this.todoContent = temp.stepDescription
+        this.todoType = type
+        this.groupId = temp.groupId
+        this.groupName = temp.groupName
+        this.stepStatus = temp.stepStatus
+        this.stepUpdateTime = temp.stepUpdateTime
+        this.colockerStatus = temp.colockerStatus
+        this.pointStatus = temp.pointStatus
+        this.createTime = temp.ticketStartTime
+        this.enableSetLocker = temp.enableSetLocker
+        this.enableSetColocker = temp.enableSetColocker
+        this.enableAddColocker = temp.enableAddColocker
+        this.enableReduceColocker = temp.enableReduceColocker
+        this.enableLock = temp.enableLock
+        this.enableColock = temp.enableColock
+        this.enableReleaseColock = temp.enableReleaseColock
+        this.enableUnlock = temp.enableUnlock
+        this.enableEndJob = temp.enableEndJob
+        this.confirmUser = temp.confirmUser
+        this.confirmRoleCode = temp.confirmRoleCode
+        this.stepTitle = temp.stepTitle
+        this.stepTitleShort = temp.stepTitleShort
+        this.stepDescription = temp.stepDescription
+    }
+}
+
+fun splitTodoSteps(
+    all: List<TodoItemVo>,
+    waitLimit: Int = Int.MAX_VALUE        // 限制“批次”数量
+): Int {
+    val tempTodo = mutableListOf<TodoItemVo>()
+    val tempWait = mutableListOf<TodoItemVo>()
+    val tempDone = mutableListOf<TodoItemVo>()
+
+    /* —— 1. 按 ticketId 分组 —— */
+    val grouped = all.groupBy { it.ticketId }
+
+    for ((_, steps) in grouped) {
+        var doneSteps =
+            steps.filter {
+                it.stepStatus == "1" && (!it.enableEndJob && it.ticketStatus in listOf(
+                    JobTicketStatusEnum.SELECT_MEMBER.status,
+                    JobTicketStatusEnum.LOCKING.status,
+                    JobTicketStatusEnum.COLOCKING.status,
+                    JobTicketStatusEnum.UNLOCKING.status,
+                    JobTicketStatusEnum.PROGRESSING.status,
+                ) || it.ticketStatus == JobTicketStatusEnum.FINISHED.status)
+            }
+        val pendingSteps =
+            steps.filter {
+                it.stepStatus == "0" || (it.stepStatus == "1" && it.enableEndJob && it.ticketStatus in listOf(
+                    JobTicketStatusEnum.SELECT_MEMBER.status,
+                    JobTicketStatusEnum.LOCKING.status,
+                    JobTicketStatusEnum.COLOCKING.status,
+                    JobTicketStatusEnum.UNLOCKING.status,
+                    JobTicketStatusEnum.PROGRESSING.status,
+                ))
+            }
+
+        /* —— 当前步骤 → todoData —— */
+        val todoStep =
+            pendingSteps.filter { it.isCurrentStep }.findPredecessors()
+        tempTodo += todoStep.second
+        doneSteps = doneSteps.toMutableList().apply {
+            addAll(todoStep.third)
+        }
+
+        /* —— 其它待办 → waitData —— */
+        val otherPending = pendingSteps.filter { it !in (todoStep.second + todoStep.third) }
+
+        /* ① 按 (stepIndex, actionKey) 分批 —— */
+        val byBatch = otherPending
+            .groupBy { it.stepIndex to actionKey(it) }             // <─ 新增动作维度
+            .toSortedMap(
+                compareBy<Pair<Int, Int>> { it.first }          // stepIndex 升序
+                    .thenBy { it.second }                          // actionKey 字典序
+            )
+
+        var pickedBatch = 0
+        for ((_, batchList) in byBatch) {
+            if (pickedBatch >= waitLimit) break
+            if (batchList.isEmpty()) continue
+
+            val action = actionKey(batchList[0])  // 同批次动作一致,取任意一条判断即可
+
+            if (action == 1 || action == 4) {
+                // ✅ 上锁/解锁 → 同一 stepIndex 下多个 group 要全部保留
+                tempWait += batchList
+            } else {
+                // ✅ 其他类型 → 只保留一条代表
+                tempWait.add(batchList.first())
+            }
+
+            pickedBatch++
+        }
+
+        tempDone += doneSteps
+    }
+    tempTodo.forEach {
+        it.todoStatus = TodoStatusEnum.TODO
+    }
+    tempWait.forEach {
+        it.todoStatus = TodoStatusEnum.WAIT
+        it.previousTodoItem = tempTodo.filter { todoData -> it.ticketId == todoData.ticketId }
+    }
+    tempDone.forEach {
+        it.todoStatus = TodoStatusEnum.DONE
+    }
+    /* —— 结果赋值 —— */
+    return tempTodo.size + tempWait.size
+}
+
+/**
+ * 处理前置
+ */
+fun List<TodoItemVo>.findPredecessors(): Triple<List<TodoItemVo>, List<TodoItemVo>, List<TodoItemVo>> {
+    return when {
+        any { it.enableLock } && any { it.enableColock } -> {
+            if (this.any { it.pointStatus.any { it == "0" } }) {
+                Triple(filter { it.enableColock }, filter { it.enableLock }, mutableListOf())
+            } else if (this.any { it.pointStatus.all { it == "1" } } && this.any { it.colockerStatus.any { it == "0" } }) {
+                Triple(
+                    filter { it.todoType == OperationTypeEnum.CONFIRM },
+                    filter { it.enableColock },
+                    filter { it.enableLock })
+            } else {
+                Triple(
+                    mutableListOf(),
+                    filter { it.todoType == OperationTypeEnum.CONFIRM },
+                    filter { it.enableLock || it.enableColock })
+            }
+        }
+
+        any { it.enableColock } && any { it.enableReleaseColock } -> {
+            if (this.any { it.colockerStatus.any { it == "0" } }) {
+                Triple(
+                    filter { it.enableReleaseColock },
+                    filter { it.enableColock },
+                    mutableListOf()
+                )
+            } else if (this.all { it.colockerStatus.all { it == "1" } }) {
+                Triple(
+                    filter { it.todoType == OperationTypeEnum.CONFIRM },
+                    filter { it.enableReleaseColock },
+                    filter { it.enableColock })
+            } else {
+                Triple(
+                    mutableListOf(),
+                    filter { it.todoType == OperationTypeEnum.CONFIRM },
+                    filter { it.enableReleaseColock || it.enableColock })
+            }
+        }
+
+        any { it.enableReleaseColock } && any { it.enableUnlock } && any { it.enableEndJob } -> {
+            if (this.any { it.colockerStatus.any { it != "2" } }) {
+                Triple(
+                    filter { it.enableUnlock },
+                    filter { it.enableReleaseColock },
+                    mutableListOf()
+                )
+            } else if (this.all { it.colockerStatus.all { it == "2" } } && this.any { it.pointStatus.any { it != "2" } }) {
+                Triple(
+                    filter { it.todoType == OperationTypeEnum.CONFIRM },
+                    filter { it.enableUnlock },
+                    filter { it.enableReleaseColock })
+            } else if (this.all { it.stepStatus == "0" } && this.all { it.pointStatus.all { it == "2" } }) {
+                Triple(
+                    filter { it.enableEndJob },
+                    filter { it.todoType == OperationTypeEnum.CONFIRM },
+                    filter { it.enableUnlock || it.enableReleaseColock })
+            } else {
+                Triple(
+                    mutableListOf(),
+                    filter { it.enableEndJob },
+                    filter { it.enableUnlock || it.enableReleaseColock || it.todoType == OperationTypeEnum.CONFIRM }
+                )
+            }
+        }
+
+        any { it.enableReleaseColock } && any { it.enableUnlock } -> {
+            if (this.any { it.colockerStatus.any { it != "2" } }) {
+                Triple(
+                    filter { it.enableUnlock },
+                    filter { it.enableReleaseColock },
+                    mutableListOf()
+                )
+            } else if (this.all { it.colockerStatus.all { it == "2" } } && this.any { it.pointStatus.any { it != "2" } }) {
+                Triple(
+                    filter { it.todoType == OperationTypeEnum.CONFIRM },
+                    filter { it.enableUnlock },
+                    filter { it.enableReleaseColock })
+            } else {
+                Triple(
+                    mutableListOf(),
+                    filter { it.todoType == OperationTypeEnum.CONFIRM },
+                    filter { it.enableUnlock || it.enableReleaseColock })
+            }
+        }
+
+        any { it.enableUnlock } && any { it.enableEndJob } -> {
+            if (this.any { it.pointStatus.any { it != "2" } }) {
+                Triple(filter { it.enableEndJob }, filter { it.enableUnlock }, mutableListOf())
+            } else {
+                Triple(
+                    mutableListOf(),
+                    filter { it.enableEndJob },
+                    filter { it.enableUnlock })
+            }
+        }
+
+        else -> Triple(
+            filter { it.todoType == OperationTypeEnum.CONFIRM }, this, mutableListOf()
+        )
+    }
+}
+
+/* -------------------------------------------------------------
+ * 根据唯一的 enableXXX 返回动作标识
+ * ----------------------------------------------------------- */
+fun actionKey(item: TodoItemVo): Int = when {
+    item.enableLock -> 1
+    item.enableUnlock -> 4
+    item.enableColock -> 2
+    item.enableReleaseColock -> 3
+    item.enableEndJob -> 6
+    else -> 5
+}

+ 85 - 54
app/src/main/java/com/grkj/iscs/features/main/fragment/exception_manage/ExceptionDetailFragment.kt

@@ -31,64 +31,14 @@ class ExceptionDetailFragment : BaseFragment<FragmentExceptionDetailBinding>() {
     override fun initView() {
         binding.back.setDebouncedClickListener { navController.popBackStack() }
         binding.handleException.setDebouncedClickListener {
-            if (viewModel.exceptionData?.exceptionType.toString() == viewModel.exceptionType.find { it.dictLabel == "作业异常" }?.dictValue) {
+            if (isJobException()) {
                 if (exceptionJobViewModel.jobApplicationUseMasterKey()) {
                     handleExceptionCheck()
                 } else {
-                    exceptionJobViewModel.checkJobHasCoLockAndCrossJob().observe(this) {
-                        if (it.first) {
-                            TipDialog.show(
-                                title = getString(R.string.warn),
-                                msg = getString(R.string.handle_exception_will_release_all_colock),
-                                dialogType = TipDialog.DialogType.ERROR,
-                                onConfirmClick = {
-                                    if (it.second) {
-                                        TipDialog.show(
-                                            title = getString(R.string.warn),
-                                            msg = getString(R.string.current_job_has_cross_job),
-                                            dialogType = TipDialog.DialogType.ERROR,
-                                            onConfirmClick = {
-                                                handleExceptionCheck()
-                                            })
-                                    }
-                                })
-                        } else {
-                            if (it.second) {
-                                TipDialog.show(
-                                    title = getString(R.string.warn),
-                                    msg = getString(R.string.current_job_has_cross_job),
-                                    dialogType = TipDialog.DialogType.ERROR,
-                                    onConfirmClick = {
-                                        handleExceptionCheck()
-                                    })
-                            } else {
-                                handleExceptionCheck()
-                            }
-                        }
-
-                    }
+                    checkLockAndCrossJobThenHandle()
                 }
             } else {
-                TipDialog.showInfo(
-                    getString(R.string.confirm_handle_exception),
-                    onConfirmClick = {
-                        viewModel.handleException().observe(this) {
-                            if (it.first) {
-                                TipDialog.showSuccess(
-                                    getString(R.string.handle_exception_success),
-                                    onConfirmClick = {
-                                        binding.handleException.isVisible = false
-                                        binding.cancelException.isVisible = false
-                                    },
-                                    onCancelClick = {
-                                        binding.handleException.isVisible = false
-                                        binding.cancelException.isVisible = false
-                                    })
-                            } else {
-                                TipDialog.showError(it.second)
-                            }
-                        }
-                    })
+                showSimpleConfirmHandleDialog()
             }
         }
         binding.cancelException.setDebouncedClickListener {
@@ -113,6 +63,87 @@ class ExceptionDetailFragment : BaseFragment<FragmentExceptionDetailBinding>() {
         }
     }
 
+    private fun isJobException(): Boolean {
+        val exceptionTypeValue = viewModel.exceptionType.find { it.dictLabel == "作业异常" }?.dictValue
+        return viewModel.exceptionData?.exceptionType.toString() == exceptionTypeValue
+    }
+
+    private fun showSimpleConfirmHandleDialog() {
+        TipDialog.showInfo(
+            getString(R.string.confirm_handle_exception),
+            onConfirmClick = {
+                viewModel.handleException().observe(this) { result ->
+                    if (result.first) {
+                        showHandleSuccessDialog()
+                    } else {
+                        TipDialog.showError(result.second)
+                    }
+                }
+            }
+        )
+    }
+
+    private fun showHandleSuccessDialog() {
+        TipDialog.showSuccess(
+            getString(R.string.handle_exception_success),
+            onConfirmClick = ::hideHandleButtons,
+            onCancelClick = ::hideHandleButtons
+        )
+    }
+
+    private fun hideHandleButtons() {
+        binding.handleException.isVisible = false
+        binding.cancelException.isVisible = false
+    }
+
+    private fun checkLockAndCrossJobThenHandle() {
+        exceptionJobViewModel.checkJobHasCoLockAndCrossJob().observe(this) { (hasCoLock, hasCrossJob) ->
+            when {
+                hasCoLock && hasCrossJob -> {
+                    showCoLockReleaseWarning {
+                        showCrossJobWarning {
+                            handleExceptionCheck()
+                        }
+                    }
+                }
+
+                hasCoLock -> {
+                    showCoLockReleaseWarning {
+                        handleExceptionCheck()
+                    }
+                }
+
+                hasCrossJob -> {
+                    showCrossJobWarning {
+                        handleExceptionCheck()
+                    }
+                }
+
+                else -> {
+                    handleExceptionCheck()
+                }
+            }
+        }
+    }
+
+    private fun showCoLockReleaseWarning(onConfirm: () -> Unit) {
+        TipDialog.show(
+            title = getString(R.string.warn),
+            msg = getString(R.string.handle_exception_will_release_all_colock),
+            dialogType = TipDialog.DialogType.ERROR,
+            onConfirmClick = onConfirm
+        )
+    }
+
+    private fun showCrossJobWarning(onConfirm: () -> Unit) {
+        TipDialog.show(
+            title = getString(R.string.warn),
+            msg = getString(R.string.current_job_has_cross_job),
+            dialogType = TipDialog.DialogType.ERROR,
+            onConfirmClick = onConfirm
+        )
+    }
+
     private fun handleExceptionCheck() {
         exceptionJobViewModel.checkJobNeedLockOrUnlock().observe(this) {
             when (it) {
@@ -270,7 +301,7 @@ class ExceptionDetailFragment : BaseFragment<FragmentExceptionDetailBinding>() {
             if (it) {
                 exceptionJobViewModel.isUnlockFirst(exceptionJobViewModel.ticketData?.ticketId!!)
                     .observe(this) {}
-                exceptionJobViewModel.getWorkflowSteps(exceptionJobViewModel.ticketData?.modeId!!)
+                exceptionJobViewModel.getWorkflowSteps()
                     .observe(this) {
 
                     }

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

@@ -51,6 +51,7 @@ class ExceptionJobFragment : BaseFragment<FragmentExceptionJobBinding>() {
                 binding.spaceView.isVisible = false
                 toggleExpandView(binding.fullScreenRootLayout, binding.dataLayout, true)
                 binding.fullScreen.isVisible = true
+                binding.dataLayout.setBackgroundResource(com.grkj.ui_base.R.drawable.common_layout_bg)
             } else {
                 navController.popBackStack()
             }
@@ -147,6 +148,7 @@ class ExceptionJobFragment : BaseFragment<FragmentExceptionJobBinding>() {
         }
         binding.fullScreen.setDebouncedClickListener {
             toggleExpandView(binding.fullScreenRootLayout, binding.dataLayout, false)
+            binding.dataLayout.setBackgroundColor(requireContext().getColor(R.color.white))
             binding.fullScreen.isVisible = false
             binding.spaceView.isVisible = true
         }
@@ -296,8 +298,7 @@ class ExceptionJobFragment : BaseFragment<FragmentExceptionJobBinding>() {
         val itemBinding = holder.getBinding<ItemJobExecuteStepBinding>()
         val item = holder.getModel<IsJobTicketStepDataVo>()
         itemBinding.stepIconIv.setImageResource(getStepIcon(item))
-        itemBinding.stepNameTv.text =
-            viewModel.currentStepData?.stepTitleShort
+        itemBinding.stepNameTv.text = item.stepTitleShort
         itemBinding.stepIndexTv.text = item.stepIndex.toString()
         itemBinding.dividerIv.isVisible = item.stepId != viewModel.ticketStep.last().stepId
         val bg = itemBinding.stepLayout.background
@@ -411,11 +412,9 @@ class ExceptionJobFragment : BaseFragment<FragmentExceptionJobBinding>() {
             navController.popBackStack()
             return
         }
-        viewModel.getWorkflowModes().observe(this) {
-            viewModel.ticketId = ticketId
-            viewModel.exceptionId = exceptionId
-            getData()
-        }
+        viewModel.ticketId = ticketId
+        viewModel.exceptionId = exceptionId
+        getData()
     }
 
     private fun getData() {
@@ -430,7 +429,7 @@ class ExceptionJobFragment : BaseFragment<FragmentExceptionJobBinding>() {
         viewModel.getJobTicketData().observe(this) {
             if (it) {
                 viewModel.isUnlockFirst(viewModel.ticketData?.modeId!!).observe(this) {}
-                viewModel.getWorkflowSteps(viewModel.ticketData?.modeId!!).observe(this) {
+                viewModel.getWorkflowSteps().observe(this) {
                     binding.exceptionJob.text = viewModel.ticketData!!.ticketName
                     binding.jobNameTv.text = getString(R.string.exception_job_title)
                     binding.listRv.models = viewModel.ticketPoints

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

@@ -440,7 +440,7 @@ class CreateSopJobFragment : BaseFormFragment<FragmentCreateSopJobBinding>() {
      */
     private fun setWorkstationData() {
         viewModel.getWorkstationData().observe(this) {
-            TextDropDownDialog.showSingle(
+            TextDropDownDialog.showSingleTree(
                 viewModel.workstationData.map {
                     TextDropDownDialog.SimpleTextDropDownEntity(
                         dataId = it.workstationId,

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

@@ -486,7 +486,7 @@ class EditSopFragment : BaseFormFragment<FragmentEditSopBinding>() {
 
     private fun setWorkstationData() {
         viewModel.getWorkstationData().observe(this) {
-            TextDropDownDialog.showSingle(
+            TextDropDownDialog.showSingleTree(
                 viewModel.workstationData.map {
                     TextDropDownDialog.SimpleTextDropDownEntity(
                         dataId = it.workstationId,

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

@@ -458,7 +458,7 @@ class EditSopJobFragment : BaseFormFragment<FragmentEditSopJobBinding>() {
      */
     private fun setWorkstationData() {
         viewModel.getWorkstationData().observe(this) {
-            TextDropDownDialog.showSingle(
+            TextDropDownDialog.showSingleTree(
                 viewModel.workstationData.map {
                     TextDropDownDialog.SimpleTextDropDownEntity(
                         dataId = it.workstationId,

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

@@ -60,7 +60,10 @@ class InProgressJobManageFragment : BaseFragment<FragmentInProgressJobManageBind
         val itemBinding = holder.getBinding<ItemJobManageBinding>()
         val item = holder.getModel<JobTicketManageVo>()
         itemBinding.jobName.text = item.ticketName
-        itemBinding.status.text = JobTicketStatusEnum.getTicketStatusStr(item.ticketStatus)
+        itemBinding.status.text =
+            if (item.exStatus != null) CommonUtils.getStr(R.string.abnormal) else JobTicketStatusEnum.getTicketStatusStr(
+                item.ticketStatus
+            )
         itemBinding.select.isVisible = false
         itemBinding.view.setDebouncedClickListener {
             GlobalDataTempStore.getInstance()

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

@@ -273,7 +273,7 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                     //自动确认并且是设置上锁人或者共锁人
                     if (workflowStep?.confirmType != 0 && (workflowStep?.enableSetLocker == true || workflowStep?.enableSetColocker == true)) {
                         stepClickConfirm(adapter, item, workflowStep)
-                    } else if (workflowStep?.confirmType == 0 && (viewModel.ticketData?.createBy == MainDomainData.userInfo?.userName || workflowStep.currentUserCanConfirm())) {//手动确认 需要时创建者或者指定人员
+                    } else if (workflowStep?.confirmType == 0 && ((viewModel.ticketData?.createBy == MainDomainData.userInfo?.userName && workflowStep.confirmUser == null) || workflowStep.currentUserCanConfirm())) {//手动确认 需要时创建者或者指定人员
                         if (workflowStep.currentUserCanConfirm()) {
                             CheckFaceDialog.show(viewLifecycleOwner, viewModel, 0) {
                                 if (it in listOf(
@@ -285,8 +285,13 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
                                     stepClickConfirm(adapter, item, workflowStep)
                                 }
                             }
-                        } else {
+                        } else if (viewModel.ticketData?.createBy == MainDomainData.userInfo?.userName && workflowStep.confirmUser == null) {
                             stepClickConfirm(adapter, item, workflowStep)
+                        } else {
+                            showToast(
+                                CommonUtils.getStr(com.grkj.ui_base.R.string.no_permission_to_handle)
+                                    .toString()
+                            )
                         }
                     } else {
                         val errorTipData = viewModel.getStepErrorTip(workflowStep)
@@ -714,7 +719,7 @@ class JobExecuteFragment : BaseFragment<FragmentJobExecuteBinding>() {
             viewModel.updateLockerAndColockerData().observe(this) {
                 val workflowStep = viewModel.currentStepData
                 if (workflowStep?.confirmType != 0 ||//自动确认
-                    (viewModel.ticketData?.createBy == MainDomainData.userInfo?.userName || workflowStep.currentUserCanConfirm())
+                    ((viewModel.ticketData?.createBy == MainDomainData.userInfo?.userName && workflowStep.confirmUser == null) || workflowStep.currentUserCanConfirm())
                 ) {
                     viewModel.currentStepData?.stepStatus = "1"
                     viewModel.currentStepData?.updateTime =

+ 7 - 5
app/src/main/java/com/grkj/iscs/features/main/fragment/job_manage/MyTodoListFragment.kt

@@ -30,7 +30,6 @@ import com.grkj.iscs.features.main.dialog.job_manage.TodoPointDetailDialog
 import com.grkj.iscs.features.main.viewmodel.job_manage.JobExecuteViewModel
 import com.grkj.iscs.features.main.viewmodel.job_manage.MyTodoViewModel
 import com.grkj.shared.model.EventBean
-import com.grkj.shared.utils.ArcSoftUtil
 import com.grkj.ui_base.base.BaseFragment
 import com.grkj.ui_base.dialog.TipDialog
 import com.grkj.ui_base.dialog.WheelDateRangePickerDialog
@@ -41,12 +40,10 @@ import com.grkj.ui_base.utils.extension.tip
 import com.kongzue.dialogx.dialogs.CustomDialog
 import com.kongzue.dialogx.dialogs.PopTip
 import com.kongzue.dialogx.interfaces.DialogLifecycleCallback
-import com.loper7.date_time_picker.dialog.CardDatePickerDialog
 import com.sik.sikcore.data.GlobalDataTempStore
 import com.sik.sikcore.date.TimeUtils
 import com.sik.sikcore.extension.setDebouncedClickListener
 import dagger.hilt.android.AndroidEntryPoint
-import java.util.Date
 
 /**
  * 我的待办
@@ -612,7 +609,7 @@ class MyTodoListFragment : BaseFragment<FragmentMyTodoListBinding>() {
                 jobExecuteViewModel.updateLockerAndColockerData().observe(this) {
                     val workflowStep = jobExecuteViewModel.currentStepData
                     if (workflowStep?.confirmType != 0 ||//自动确认
-                        (jobExecuteViewModel.ticketData?.createBy == MainDomainData.userInfo?.userName || workflowStep.currentUserCanConfirm())
+                        ((jobExecuteViewModel.ticketData?.createBy == MainDomainData.userInfo?.userName && workflowStep.confirmUser==null) || workflowStep.currentUserCanConfirm())
                     ) {
                         if (workflowStep?.currentUserCanConfirm() == true) {
                             CheckFaceDialog.show(viewLifecycleOwner, viewModel, 0) {
@@ -624,7 +621,7 @@ class MyTodoListFragment : BaseFragment<FragmentMyTodoListBinding>() {
                                         }
                                 }
                             }
-                        } else {
+                        } else if (jobExecuteViewModel.ticketData?.createBy == MainDomainData.userInfo?.userName && workflowStep?.currentUserCanConfirm() == false) {
                             jobExecuteViewModel.currentStepData?.stepStatus = "1"
                             jobExecuteViewModel.currentStepData?.let {
                                 jobExecuteViewModel.updateStepStatus(it)
@@ -632,6 +629,11 @@ class MyTodoListFragment : BaseFragment<FragmentMyTodoListBinding>() {
                                         getData()
                                     }
                             }
+                        } else {
+                            showToast(
+                                CommonUtils.getStr(com.grkj.ui_base.R.string.no_permission_to_handle)
+                                    .toString()
+                            )
                         }
                     }
                     if (workflowStep?.enableAddColocker == true || workflowStep?.enableReduceColocker == true) {

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

@@ -41,7 +41,6 @@ import javax.inject.Inject
 class ExceptionJobViewModel @Inject constructor(
     val exceptionRepository: IExceptionRepository,
     val jobTicketRepository: IJobTicketRepository,
-    val workflowRepository: IWorkflowRepository,
     override val userRepository: IUserRepository
 ) : BaseViewModel(userRepository) {
     var ticketId: Long = 0
@@ -55,8 +54,6 @@ class ExceptionJobViewModel @Inject constructor(
     var selectedLockerData: List<JobUserVo> = mutableListOf()
     var selecteColockerData: List<JobUserVo> = mutableListOf()
     var currentStepData: IsJobTicketStepDataVo? = null
-    var workflowModes: List<WorkflowMode> = mutableListOf()
-    var workflowSteps: List<WorkflowStep> = mutableListOf()
     var isUnlockFirst: Boolean = false
 
     /**
@@ -99,40 +96,27 @@ class ExceptionJobViewModel @Inject constructor(
         }
     }
 
-    /**
-     * 获取流程模式列表
-     */
-    fun getWorkflowModes(): LiveData<Boolean> {
-        return liveData(Dispatchers.IO) {
-            workflowModes = workflowRepository.getWorkflowModes()
-            emit(true)
-        }
-    }
-
     /**
      * 获取流程步骤列表
      */
-    fun getWorkflowSteps(modeId: Long): LiveData<Boolean> {
+    fun getWorkflowSteps(): LiveData<Boolean> {
         return liveData(Dispatchers.IO) {
-            workflowSteps = workflowRepository.getStepsByMode(modeId)
             for (stepDataVo in ticketStep) {
-                val workflowStep = stepDataVo
                 //如果是自动确认并且没有操作的功能,则更新步骤
-                if (workflowStep?.confirmType != 0 && workflowStep?.hasAnyOperationFunction() == false) {
+                if (stepDataVo.confirmType != 0 && !stepDataVo.hasAnyOperationFunction() && stepDataVo.stepStatus == "0") {
                     stepDataVo.stepStatus = "1"
-                    stepDataVo.updateTime = TimeUtils.nowString(TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT)
+                    stepDataVo.updateTime =
+                        TimeUtils.nowString(TimeUtils.DEFAULT_DATE_HOUR_MIN_SEC_FORMAT)
                     BeanUtils.copyProperties(
                         stepDataVo, IsJobTicketStep::class.java
                     )?.let { jobTicketStep ->
                         jobTicketRepository.updateTicketStepData(jobTicketStep)
                         currentStepData =
                             ticketStep.find { it.stepIndex == jobTicketStep.stepIndex + 1 }
-                        val currentWorkflowStep = ticketStep.firstOrNull { it.stepStatus == "0" }
-                        ticketData?.ticketStatus =
-                            currentWorkflowStep?.getTicketStatus() ?: ""
+                        ticketData?.ticketStatus = currentStepData?.getTicketStatus() ?: ""
                         jobTicketRepository.updateTicketDataStatus(
                             ticketId,
-                            currentWorkflowStep?.getTicketStatus()?.toInt()
+                            currentStepData?.getTicketStatus()?.toInt()
                                 ?: JobTicketStatusEnum.PROGRESSING.status.toInt()
                         )
                     }
@@ -321,7 +305,8 @@ class ExceptionJobViewModel @Inject constructor(
      */
     fun checkJobHasCoLockAndCrossJob(): LiveData<Pair<Boolean, Boolean>> {
         return liveData(Dispatchers.IO) {
-            val hasCoLock = workflowSteps.any { it.enableColock }
+            val hasCoLock =
+                ticketStep.any { it.enableColock } && ticketUser.any { it.jobStatus == "1" }
             val isJobCross = jobTicketRepository.hasJobCross(ticketId)
             emit(hasCoLock to isJobCross)
         }

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

@@ -349,13 +349,19 @@ class ExceptionViewModel @Inject constructor(
             exceptionData.exceptionDescription = selectedExceptionDescription
             exceptionData.processApplication = selectedProcessApplication
             val exceptionId = exceptionRepository.reportException(exceptionData)
-            logger.info("异常数据源:${selectedSourceData.joinToString(",") { it.sourceDataText }}")
-            logger.info("异常id:${exceptionId}")
             selectedSourceData.forEach {
                 val isExceptionSourceStandard = IsExceptionSourceStandard()
                 isExceptionSourceStandard.exceptionId = exceptionId
                 isExceptionSourceStandard.sourceDataId = it.sourceDataId
                 isExceptionSourceStandard.sourceDataType = it.sourceDataType
+                if (it.sourceDataType == exceptionSourceDataType.find { it.dictLabel == "作业" }?.dictValue?.toInt()) {
+                    val ticketData = jobTicketRepository.getTicketRawDataByTicketId(it.sourceDataId)
+                    ticketData?.exStatus =
+                        jobTicketStatus.find { it.dictLabel == "异常" }?.dictValue?.toInt()
+                    ticketData?.let {
+                        jobTicketRepository.updateTicketData(it)
+                    }
+                }
                 exceptionRepository.saveExceptionSourceData(isExceptionSourceStandard)
             }
             emit(true)

+ 27 - 1
app/src/main/java/com/grkj/iscs/features/main/viewmodel/home/HomeViewModel.kt

@@ -3,18 +3,29 @@ package com.grkj.iscs.features.main.viewmodel.home
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
 import com.grkj.data.data.MainDomainData
+import com.grkj.data.enums.JobTicketStatusEnum
+import com.grkj.data.enums.OperationTypeEnum
+import com.grkj.data.enums.TodoStatusEnum
 import com.grkj.data.model.dos.IsWorkstation
 import com.grkj.data.model.dos.WorkflowMode
+import com.grkj.data.model.local.TodoStepJoin
+import com.grkj.data.model.local.isMyTodo
+import com.grkj.data.model.vo.TodoItemVo
 import com.grkj.data.model.vo.WorkstationManageVo
 import com.grkj.data.repository.IHardwareRepository
 import com.grkj.data.repository.IJobTicketRepository
 import com.grkj.data.repository.IUserRepository
 import com.grkj.data.repository.IWorkflowRepository
 import com.grkj.data.repository.IWorkstationRepository
+import com.grkj.iscs.features.main.entity.actionKey
+import com.grkj.iscs.features.main.entity.findPredecessors
+import com.grkj.iscs.features.main.entity.splitTodoSteps
+import com.grkj.iscs.features.main.entity.toTodoVo
 import com.grkj.ui_base.base.BaseViewModel
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.Dispatchers
 import javax.inject.Inject
+import kotlin.collections.contains
 
 /**
  * 主界面界面模型
@@ -36,6 +47,8 @@ class HomeViewModel @Inject constructor(
     var allPointNum = 0
     var allHardwareNum = 0
 
+    var todoItemVos: MutableList<TodoItemVo> = mutableListOf()
+
     /**
      * 实时数据区域id
      */
@@ -122,7 +135,20 @@ class HomeViewModel @Inject constructor(
      */
     fun getMyToDoListJobCount(): LiveData<Int> {
         return liveData(Dispatchers.IO) {
-            emit(jobTicketRepository.getMyToDoListJobCount())
+            val userInfo = MainDomainData.userInfo
+            if (userInfo == null) {
+                emit(0) // or emit(false) 根据语义定义
+                return@liveData
+            }
+
+            val userId = userInfo.userId
+            val userName = userInfo.userName
+            val todoItemData = jobTicketRepository.getMyTodoList()
+            val myTodoStepJoin = todoItemData.filter { it.isMyTodo(userId, userName) }
+            todoItemVos =
+                myTodoStepJoin.map { it.toTodoVo(todoItemData.filter { temp -> it.ticketId == temp.ticketId }) }
+                    .toMutableList()
+            emit(splitTodoSteps(todoItemVos, 1))
         }
     }
 }

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

@@ -667,11 +667,14 @@ class JobExecuteViewModel @Inject constructor(
      */
     fun getStepErrorTip(workflowStep: IsJobTicketStepDataVo?): Pair<String, Int?> {
         return when {
-            workflowStep?.enableSetLocker == true || workflowStep?.enableSetColocker == true -> {
+
+            ((ticketData?.createBy == MainDomainData.userInfo?.userName && workflowStep?.confirmUser == null) || workflowStep?.currentUserCanConfirm() == true) &&
+                    (workflowStep?.enableSetLocker == true || workflowStep?.enableSetColocker == true) -> {
                 CommonUtils.getStr(R.string.please_select_member).toString() to null
             }
 
-            workflowStep?.enableLock == true || workflowStep?.enableColock == true || workflowStep?.enableReleaseColock == true || workflowStep?.enableUnlock == true -> {
+            ((ticketData?.createBy == MainDomainData.userInfo?.userName && workflowStep?.confirmUser == null) || workflowStep?.currentUserCanConfirm() == true) &&
+                    (workflowStep?.enableLock == true || workflowStep?.enableColock == true || workflowStep?.enableReleaseColock == true || workflowStep?.enableUnlock == true) -> {
                 var tip = ""
                 var index: Int? = null
                 if (workflowStep.enableLock) {
@@ -733,11 +736,13 @@ class JobExecuteViewModel @Inject constructor(
     fun getCurrentStepTip(): String {
         val currentWorkflowStep = currentStepData
         return when {
-            currentWorkflowStep?.enableSetLocker == true || currentWorkflowStep?.enableSetColocker == true -> {
+            ((ticketData?.createBy == MainDomainData.userInfo?.userName && currentWorkflowStep?.confirmUser == null) || currentWorkflowStep?.currentUserCanConfirm() == true) &&
+                    (currentWorkflowStep?.enableSetLocker == true || currentWorkflowStep?.enableSetColocker == true) -> {
                 CommonUtils.getStr(R.string.please_select_member).toString()
             }
 
-            currentWorkflowStep?.enableLock == true || currentWorkflowStep?.enableColock == true || currentWorkflowStep?.enableReleaseColock == true || currentWorkflowStep?.enableUnlock == true -> {
+            ((ticketData?.createBy == MainDomainData.userInfo?.userName && currentWorkflowStep?.confirmUser == null) || currentWorkflowStep?.currentUserCanConfirm() == true) &&
+                    (currentWorkflowStep?.enableLock == true || currentWorkflowStep?.enableColock == true || currentWorkflowStep?.enableReleaseColock == true || currentWorkflowStep?.enableUnlock == true) -> {
                 var tip = ""
                 if (currentWorkflowStep.enableLock) {
                     if (ticketPoints.any { it.pointStatus != "1" } && ticketKey.isEmpty()) {

+ 32 - 4
app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/JobManageHomeViewModel.kt

@@ -2,21 +2,35 @@ package com.grkj.iscs.features.main.viewmodel.job_manage
 
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.liveData
+import com.grkj.data.data.MainDomainData
+import com.grkj.data.enums.JobTicketStatusEnum
+import com.grkj.data.enums.OperationTypeEnum
+import com.grkj.data.enums.TodoStatusEnum
+import com.grkj.data.model.local.TodoStepJoin
+import com.grkj.data.model.local.isMyTodo
+import com.grkj.data.model.vo.TodoItemVo
 import com.grkj.data.repository.IJobTicketRepository
+import com.grkj.iscs.features.main.entity.actionKey
+import com.grkj.iscs.features.main.entity.findPredecessors
+import com.grkj.iscs.features.main.entity.splitTodoSteps
+import com.grkj.iscs.features.main.entity.toTodoVo
 import com.grkj.ui_base.base.BaseViewModel
 import dagger.hilt.android.lifecycle.HiltViewModel
 import kotlinx.coroutines.Dispatchers
 import javax.inject.Inject
+import kotlin.collections.contains
 
 @HiltViewModel
 class JobManageHomeViewModel @Inject constructor(
     val jobTicketRepository: IJobTicketRepository
-): BaseViewModel() {
+) : BaseViewModel() {
+    var todoItemVos: MutableList<TodoItemVo> = mutableListOf()
+
     /**
      * 获取正在进行中的作业
      */
-    fun getInProgressJobCount(): LiveData<Int>{
-        return liveData(Dispatchers.IO){
+    fun getInProgressJobCount(): LiveData<Int> {
+        return liveData(Dispatchers.IO) {
             emit(jobTicketRepository.getInProgressJobSize())
         }
     }
@@ -26,7 +40,21 @@ class JobManageHomeViewModel @Inject constructor(
      */
     fun getMyToDoListJobCount(): LiveData<Int> {
         return liveData(Dispatchers.IO) {
-            emit(jobTicketRepository.getMyToDoListJobCount())
+            val userInfo = MainDomainData.userInfo
+            if (userInfo == null) {
+                emit(0) // or emit(false) 根据语义定义
+                return@liveData
+            }
+
+            val userId = userInfo.userId
+            val userName = userInfo.userName
+            val todoItemData = jobTicketRepository.getMyTodoList()
+            val myTodoStepJoin = todoItemData.filter { it.isMyTodo(userId, userName) }
+            todoItemVos =
+                myTodoStepJoin.map { it.toTodoVo(todoItemData.filter { temp -> it.ticketId == temp.ticketId }) }
+                    .toMutableList()
+
+            emit(splitTodoSteps(todoItemVos, 1))
         }
     }
 }

+ 3 - 161
app/src/main/java/com/grkj/iscs/features/main/viewmodel/job_manage/MyTodoViewModel.kt

@@ -14,6 +14,9 @@ import com.grkj.data.model.vo.IsJobTicketPointsDataVo
 import com.grkj.data.model.vo.TodoItemVo
 import com.grkj.data.repository.IJobTicketRepository
 import com.grkj.iscs.R
+import com.grkj.iscs.features.main.entity.actionKey
+import com.grkj.iscs.features.main.entity.findPredecessors
+import com.grkj.iscs.features.main.entity.toTodoVo
 import com.grkj.ui_base.base.BaseViewModel
 import com.grkj.ui_base.business.DataBusiness
 import com.grkj.ui_base.utils.CommonUtils
@@ -172,167 +175,6 @@ class MyTodoViewModel @Inject constructor(
             .toMutableList()
     }
 
-    /**
-     * 处理前置
-     */
-    private fun List<TodoItemVo>.findPredecessors(): Triple<List<TodoItemVo>, List<TodoItemVo>, List<TodoItemVo>> {
-        return when {
-            any { it.enableLock } && any { it.enableColock } -> {
-                if (this.any { it.pointStatus.any { it == "0" } }) {
-                    Triple(filter { it.enableColock }, filter { it.enableLock }, mutableListOf())
-                } else if (this.any { it.pointStatus.all { it == "1" } } && this.any { it.colockerStatus.any { it == "0" } }) {
-                    Triple(
-                        filter { it.todoType == OperationTypeEnum.CONFIRM },
-                        filter { it.enableColock },
-                        filter { it.enableLock })
-                } else {
-                    Triple(
-                        mutableListOf(),
-                        filter { it.todoType == OperationTypeEnum.CONFIRM },
-                        filter { it.enableLock || it.enableColock })
-                }
-            }
-
-            any { it.enableColock } && any { it.enableReleaseColock } -> {
-                if (this.any { it.colockerStatus.any { it == "0" } }) {
-                    Triple(
-                        filter { it.enableReleaseColock },
-                        filter { it.enableColock },
-                        mutableListOf()
-                    )
-                } else if (this.all { it.colockerStatus.all { it == "1" } }) {
-                    Triple(
-                        filter { it.todoType == OperationTypeEnum.CONFIRM },
-                        filter { it.enableReleaseColock },
-                        filter { it.enableColock })
-                } else {
-                    Triple(
-                        mutableListOf(),
-                        filter { it.todoType == OperationTypeEnum.CONFIRM },
-                        filter { it.enableReleaseColock || it.enableColock })
-                }
-            }
-
-            any { it.enableReleaseColock } && any { it.enableUnlock } && any { it.enableEndJob } -> {
-                if (this.any { it.colockerStatus.any { it != "2" } }) {
-                    Triple(
-                        filter { it.enableUnlock },
-                        filter { it.enableReleaseColock },
-                        mutableListOf()
-                    )
-                } else if (this.all { it.colockerStatus.all { it == "2" } } && this.any { it.pointStatus.any { it != "2" } }) {
-                    Triple(
-                        filter { it.todoType == OperationTypeEnum.CONFIRM },
-                        filter { it.enableUnlock },
-                        filter { it.enableReleaseColock })
-                } else if (this.all { it.stepStatus == "0" } && this.all { it.pointStatus.all { it == "2" } }) {
-                    Triple(
-                        filter { it.enableEndJob },
-                        filter { it.todoType == OperationTypeEnum.CONFIRM },
-                        filter { it.enableUnlock || it.enableReleaseColock })
-                } else {
-                    Triple(
-                        mutableListOf(),
-                        filter { it.enableEndJob },
-                        filter { it.enableUnlock || it.enableReleaseColock || it.todoType == OperationTypeEnum.CONFIRM }
-                    )
-                }
-            }
-
-            any { it.enableReleaseColock } && any { it.enableUnlock } -> {
-                if (this.any { it.colockerStatus.any { it != "2" } }) {
-                    Triple(
-                        filter { it.enableUnlock },
-                        filter { it.enableReleaseColock },
-                        mutableListOf()
-                    )
-                } else if (this.all { it.colockerStatus.all { it == "2" } } && this.any { it.pointStatus.any { it != "2" } }) {
-                    Triple(
-                        filter { it.todoType == OperationTypeEnum.CONFIRM },
-                        filter { it.enableUnlock },
-                        filter { it.enableReleaseColock })
-                } else {
-                    Triple(
-                        mutableListOf(),
-                        filter { it.todoType == OperationTypeEnum.CONFIRM },
-                        filter { it.enableUnlock || it.enableReleaseColock })
-                }
-            }
-
-            any { it.enableUnlock } && any { it.enableEndJob } -> {
-                if (this.any { it.pointStatus.any { it != "2" } }) {
-                    Triple(filter { it.enableEndJob }, filter { it.enableUnlock }, mutableListOf())
-                } else {
-                    Triple(
-                        mutableListOf(),
-                        filter { it.enableEndJob },
-                        filter { it.enableUnlock })
-                }
-            }
-
-            else -> Triple(
-                filter { it.todoType == OperationTypeEnum.CONFIRM }, this, mutableListOf()
-            )
-        }
-    }
-
-    /* -------------------------------------------------------------
-     * 根据唯一的 enableXXX 返回动作标识
-     * ----------------------------------------------------------- */
-    private fun actionKey(item: TodoItemVo): Int = when {
-        item.enableLock -> 1
-        item.enableUnlock -> 4
-        item.enableColock -> 2
-        item.enableReleaseColock -> 3
-        item.enableEndJob -> 6
-        else -> 5
-    }
-
-
-    fun TodoStepJoin.toTodoVo(sameTicketStepJoinData: List<TodoStepJoin>): TodoItemVo {
-        val isCreator = createBy == MainDomainData.userInfo?.userName
-        val type = OperationTypeEnum.fromJoin(this, isCreator)
-        val temp = this
-        return TodoItemVo().apply {
-            this.todoId = temp.stepId
-            this.ticketId = temp.ticketId
-            this.ticketName = temp.ticketName
-            this.ticketStatus = temp.ticketStatus
-            this.stepId = temp.stepId
-            this.workflowStepId = temp.workflowStepId
-            this.stepIndex = temp.stepIndex
-            this.isCurrentStep =
-                sameTicketStepJoinData.filter { it.stepStatus == "0" }
-                    .minByOrNull { it.stepIndex }?.stepIndex == temp.stepIndex || (sameTicketStepJoinData.none {
-                    it.stepStatus == "0"
-                } && temp.enableEndJob)
-            this.todoTitle = temp.stepTitleShort ?: temp.stepTitle
-            this.todoContent = temp.stepDescription
-            this.todoType = type
-            this.groupId = temp.groupId
-            this.groupName = temp.groupName
-            this.stepStatus = temp.stepStatus
-            this.stepUpdateTime = temp.stepUpdateTime
-            this.colockerStatus = temp.colockerStatus
-            this.pointStatus = temp.pointStatus
-            this.createTime = temp.ticketStartTime
-            this.enableSetLocker = temp.enableSetLocker
-            this.enableSetColocker = temp.enableSetColocker
-            this.enableAddColocker = temp.enableAddColocker
-            this.enableReduceColocker = temp.enableReduceColocker
-            this.enableLock = temp.enableLock
-            this.enableColock = temp.enableColock
-            this.enableReleaseColock = temp.enableReleaseColock
-            this.enableUnlock = temp.enableUnlock
-            this.enableEndJob = temp.enableEndJob
-            this.confirmUser = temp.confirmUser
-            this.confirmRoleCode = temp.confirmRoleCode
-            this.stepTitle = temp.stepTitle
-            this.stepTitleShort = temp.stepTitleShort
-            this.stepDescription = temp.stepDescription
-        }
-    }
-
     /**
      * 获取处理提醒
      */

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

@@ -620,7 +620,7 @@ interface JobTicketDao {
         select ijt.ticket_id
         from is_job_ticket ijt
         left join is_job_ticket_points ijtp on ijt.ticket_id = ijtp.ticket_id
-        where ijtp.point_id in (:pointIds) and ijtp.ticket_id != :ticketId
+        where ijtp.point_id in (:pointIds) and ijtp.ticket_id != :ticketId and ijt.ticket_status in ('1','2','3','4','7')
     """
     )
     fun getProgressTicketIdsByPointsAndExceptTicketId(
@@ -686,7 +686,7 @@ interface JobTicketDao {
         FROM is_job_ticket ijt
         LEFT JOIN sys_user su ON ijt.create_by = su.user_name
         LEFT JOIN is_job_ticket_user ijtu ON ijtu.ticket_id = ijt.ticket_id
-        WHERE ijt.ticket_status not IN ('6')
+        WHERE ijt.ticket_status not IN ('6') and ijt.ex_status is null
           AND (
                 su.user_id = :userId         -- 是创建者
              OR ijtu.user_id = :userId       -- 是参与人

+ 1 - 1
data/src/main/java/com/grkj/data/model/local/TodoStepJoin.kt

@@ -69,7 +69,7 @@ fun TodoStepJoin.isMyTodo(currentUserId: Long, currentUserName: String): Boolean
 
     // ---- 普通步骤确认 ----
     val confirmToCurrentUser =
-        confirmUser == currentUserId || isCreator
+        confirmUser == currentUserId || (isCreator && confirmUser == null)
 
     return !hasAnyHardwareOperationFunction() && confirmToCurrentUser
 }

+ 8 - 1
data/src/main/java/com/grkj/data/repository/impl/standard/ExceptionRepository.kt

@@ -14,6 +14,7 @@ import com.grkj.data.repository.IExceptionRepository
 import com.grkj.data.repository.IHardwareRepository
 import com.sik.sikcore.data.BeanUtils
 import com.sik.sikcore.date.TimeUtils
+import com.sik.sikcore.extension.toJson
 import javax.inject.Inject
 import javax.inject.Singleton
 
@@ -130,11 +131,17 @@ class ExceptionRepository @Inject constructor(
                         jobTicketData?.exStatus =
                             CommonDictDataEnum.JOB_TICKET_STATUS.commonDictRes.find { it.dictLabel == "异常" }?.dictValue?.toInt()
                         jobTicketData?.remark = exceptionSource.remark
+                        logger.info("异常处理作业票1:${exceptionDataItem.toJson()}")
+                        logger.info("异常处理作业票2:${CommonDictDataEnum.EXCEPTION_PROCESS_APPLICATION_JOB.commonDictRes.find {
+                            it.dictLabel.contains(
+                                "结束作业"
+                            )
+                        }?.dictValue}")
                         if (exceptionDataItem.processApplication == CommonDictDataEnum.EXCEPTION_PROCESS_APPLICATION_JOB.commonDictRes.find {
                                 it.dictLabel.contains(
                                     "结束作业"
                                 )
-                            }?.dictLabel) {
+                            }?.dictValue) {
                             jobTicketData?.ticketStatus = JobTicketStatusEnum.FINISHED.status
                         }
                         jobTicketData?.let {

+ 1 - 0
data/src/main/java/com/grkj/data/repository/impl/standard/JobTicketRepository.kt

@@ -598,6 +598,7 @@ class JobTicketRepository @Inject constructor(
         }
         tempWait.forEach {
             it.todoStatus = TodoStatusEnum.WAIT
+            it.previousTodoStepJoin = tempTodo.filter { todoData -> it.ticketId == todoData.ticketId }
         }
         tempDone.forEach {
             it.todoStatus = TodoStatusEnum.DONE

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

@@ -100,7 +100,7 @@ abstract class BaseActivity<V : ViewDataBinding> : AppCompatActivity(), CustomAd
     }
 
     /** 动态切换 Nav Graph */
-    protected fun replaceNavGraph(graphId: Int) {
+    open protected fun replaceNavGraph(graphId: Int) {
         navController.setGraph(graphId)
     }