瀏覽代碼

主流程适配基本完成

bjb 5 月之前
父節點
當前提交
e9193ad222
共有 38 個文件被更改,包括 4267 次插入540 次删除
  1. 2 0
      app/src/main/java/com/grkj/iscs_mars/view/base/BaseDialog.kt
  2. 204 0
      app/src/main/java/com/grkj/iscs_mars/view/dialog/LockerSelectDialog.kt
  3. 8 2
      app/src/main/java/com/grkj/iscs_mars/view/fragment/JobExecutionFragment.kt
  4. 8 5
      app/src/main/java/com/grkj/iscs_mars/view/fragment/JobManagementFragment.kt
  5. 51 49
      app/src/main/java/com/grkj/iscs_mars/view/fragment/JobProgressFragment.kt
  6. 462 0
      app/src/main/java/com/grkj/iscs_mars/view/fragment/JobProgressFragmentLand.kt
  7. 58 110
      app/src/main/java/com/grkj/iscs_mars/view/fragment/StepFragment.kt
  8. 578 0
      app/src/main/java/com/grkj/iscs_mars/view/fragment/StepFragmentLand.kt
  9. 38 2
      app/src/main/java/com/grkj/iscs_mars/view/fragment/TechnologySopFragment.kt
  10. 57 210
      app/src/main/java/com/grkj/iscs_mars/view/fragment/WorkerFragment.kt
  11. 438 0
      app/src/main/java/com/grkj/iscs_mars/view/fragment/WorkerFragmentLand.kt
  12. 25 57
      app/src/main/java/com/grkj/iscs_mars/view/fragment/WorkshopFragment.kt
  13. 25 11
      app/src/main/java/com/grkj/iscs_mars/view/presenter/TechnologySopPresenter.kt
  14. 12 18
      app/src/main/java/com/grkj/iscs_mars/view/presenter/WorkerPresenter.kt
  15. 236 0
      app/src/main/java/com/grkj/iscs_mars/view/widget/CustomMarkLayerSample.kt
  16. 56 0
      app/src/main/res/layout-land/dialog_tip.xml
  17. 212 0
      app/src/main/res/layout-land/fragment_job_progress.xml
  18. 183 0
      app/src/main/res/layout-land/fragment_step.xml
  19. 297 0
      app/src/main/res/layout-land/fragment_worker.xml
  20. 22 0
      app/src/main/res/layout-land/item_rv_worker.xml
  21. 2 0
      app/src/main/res/layout/common_dialog_loading_progress.xml
  22. 100 0
      app/src/main/res/layout/dialog_locker_select.xml
  23. 29 19
      app/src/main/res/layout/dialog_tip.xml
  24. 334 2
      app/src/main/res/layout/fragment_job_progress.xml
  25. 268 8
      app/src/main/res/layout/fragment_step.xml
  26. 22 16
      app/src/main/res/layout/fragment_technology_sop.xml
  27. 184 4
      app/src/main/res/layout/fragment_worker.xml
  28. 14 12
      app/src/main/res/layout/fragment_workshop.xml
  29. 3 2
      app/src/main/res/layout/item_rv_jobs.xml
  30. 76 0
      app/src/main/res/layout/item_rv_point_list.xml
  31. 2 2
      app/src/main/res/layout/item_rv_sop_list.xml
  32. 44 0
      app/src/main/res/layout/item_rv_sop_type.xml
  33. 92 0
      app/src/main/res/layout/item_rv_step_list.xml
  34. 12 10
      app/src/main/res/layout/item_rv_worker.xml
  35. 108 0
      app/src/main/res/layout/item_rv_worker_status_list.xml
  36. 1 0
      app/src/main/res/values/colors.xml
  37. 2 0
      app/src/main/res/values/dimens.xml
  38. 2 1
      app/src/main/res/values/styles.xml

+ 2 - 0
app/src/main/java/com/grkj/iscs_mars/view/base/BaseDialog.kt

@@ -2,6 +2,8 @@ package com.grkj.iscs_mars.view.base
 
 import android.app.Dialog
 import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
 import android.os.Bundle
 import android.view.Gravity
 import android.view.ViewGroup

+ 204 - 0
app/src/main/java/com/grkj/iscs_mars/view/dialog/LockerSelectDialog.kt

@@ -0,0 +1,204 @@
+package com.grkj.iscs_mars.view.dialog
+
+import android.content.Context
+import android.graphics.Color
+import android.graphics.drawable.ColorDrawable
+import android.view.View
+import android.view.ViewGroup
+import com.grkj.iscs_mars.R
+import com.grkj.iscs_mars.databinding.DialogLockerSelectBinding
+import com.grkj.iscs_mars.model.Constants.USER_ROLE_COLOCKER
+import com.grkj.iscs_mars.model.Constants.USER_ROLE_LOCKER
+import com.grkj.iscs_mars.model.vo.ticket.TicketDetailRespVO
+import com.grkj.iscs_mars.model.vo.ticket.TicketUserReqVO
+import com.grkj.iscs_mars.model.vo.user.UserListRespVO
+import com.grkj.iscs_mars.util.ToastUtils
+import com.grkj.iscs_mars.view.base.BaseDialog
+import com.grkj.iscs_mars.view.presenter.WorkerPresenter
+import com.zhy.adapter.recyclerview.CommonAdapter
+import com.zhy.adapter.recyclerview.base.ViewHolder
+
+/**
+ * 用于选择上锁人和共锁人的Dialog
+ */
+class LockerSelectDialog(val ctx: Context, val presenter: WorkerPresenter?) : BaseDialog<DialogLockerSelectBinding>(ctx) {
+
+    // 列表1
+    private val list1: MutableList<UserListRespVO.Row> = mutableListOf()
+
+    // 列表2
+    private val list2: MutableList<UserListRespVO.Row> = mutableListOf()
+
+    // 已选的人员
+    private val selects: MutableList<TicketUserReqVO> = mutableListOf()
+
+    // 当前流程中已经选择的
+    private val ticketUserList: MutableList<TicketDetailRespVO.JobTicketUserVO> = mutableListOf()
+
+    // 是否选择上锁人,false表示共锁人
+    private var isSelectLocker = false
+
+    // 当前操作流程
+    private var step = -1
+
+    // 设置监听
+    private var func: (isLocker: Boolean, selects: MutableList<TicketUserReqVO>) -> Unit = { _, _ -> }
+
+    // 页面容器
+    override val viewBinding: DialogLockerSelectBinding get() = DialogLockerSelectBinding.inflate(layoutInflater)
+
+    /**
+     * View初始化操作
+     */
+    override fun initView() {
+        mBinding?.tvConfirm?.setOnClickListener { func(isSelectLocker, selects) }
+        mBinding?.tvCancel?.setOnClickListener { dismiss() }
+        // 设置列表1的适配器
+        mBinding?.list1?.adapter = object : CommonAdapter<UserListRespVO.Row>(ctx, R.layout.item_rv_worker, list1) {
+
+            override fun convert(holder: ViewHolder, t: UserListRespVO.Row, position: Int) {
+                val isFindInSelect = selects.find { t.userId == it.userId } != null
+                holder.setText(R.id.tv_name, t.nickName)
+                val resId = if (isFindInSelect) R.mipmap.worker_selected else R.mipmap.ticket_worker
+                holder.setImageResource(R.id.iv_photo, resId)
+                holder.setOnClickListener(R.id.root) {
+                    if (isSelectLocker) {
+                        // 上锁人选择
+                        if (selects.any { it.userId == t.userId }) {
+                            selects.removeIf { it.userId == t.userId }
+                        } else {
+                            selects.removeIf { it.userRole == USER_ROLE_LOCKER }
+                            selects.add(
+                                TicketUserReqVO(
+                                    t.userId!!,
+                                    t.nickName!!,
+                                    "0",
+                                    USER_ROLE_LOCKER,
+                                    ticketUserList.find { ticketUser -> ticketUser.userId == t.userId }?.jobStatus
+                                )
+                            )
+                        }
+                        notifyDataSetChanged()
+                    } else {
+                        if (presenter?.colockerInsideCanAdd(ctx, t, step) == true) {
+                            val addUser = TicketUserReqVO(
+                                t.userId!!,
+                                t.nickName!!,
+                                "0",
+                                USER_ROLE_COLOCKER,
+                                ticketUserList.find { ticketUser -> ticketUser.userId == t.userId }?.jobStatus
+                            )
+                            // 内部共锁人选择
+                            if (selects.any { it.userId == t.userId } && presenter.colockerCanRemove(ctx, addUser, step)) {
+                                val minColockerSize = presenter.getMinColockerSize(ctx) ?: 1
+                                if (selects.size == minColockerSize) {
+                                    ToastUtils.tip(ctx.getString(R.string.keep_at_least_colocker, minColockerSize))
+                                    return@setOnClickListener
+                                }
+                                selects.removeIf { it.userId == t.userId }
+                            } else {
+                                selects.add(addUser)
+                            }
+                            notifyDataSetChanged()
+                        } else {
+                            ToastUtils.tip(ctx.getString(R.string.current_step_not_allowed_to_add_colocker))
+                        }
+                    }
+                }
+            }
+
+        }
+        // 设置列表2的适配器
+        mBinding?.list2?.adapter = object : CommonAdapter<UserListRespVO.Row>(ctx, R.layout.item_rv_worker, list2) {
+
+            override fun convert(holder: ViewHolder, t: UserListRespVO.Row, position: Int) {
+                val isFindInSelect = selects.find { t.userId == it.userId } != null
+                holder.setText(R.id.tv_name, t.nickName)
+                val resId = if (isFindInSelect) R.mipmap.worker_selected else R.mipmap.ticket_worker
+                holder.setImageResource(R.id.iv_photo, resId)
+                holder.setOnClickListener(R.id.root) {
+                    if (presenter?.colockerOutsideCanAdd(ctx, t, step) == true) {
+                        val addUser = TicketUserReqVO(
+                            t.userId!!,
+                            t.nickName!!,
+                            "1",
+                            USER_ROLE_COLOCKER,
+                            ticketUserList.find { ticketUser -> ticketUser.userId == t.userId }?.jobStatus
+                        )
+                        // 外部共锁人选择
+                        if (selects.any { it.userId == t.userId } && presenter.colockerCanRemove(ctx, addUser, step)) {
+                            val minColockerSize = presenter.getMinColockerSize(ctx)
+                            if (selects.size == minColockerSize) {
+                                ToastUtils.tip(ctx.getString(R.string.keep_at_least_colocker, minColockerSize))
+                                return@setOnClickListener
+                            }
+                            selects.removeIf { it.userId == t.userId }
+                        } else {
+                            selects.add(addUser)
+                        }
+                        notifyDataSetChanged()
+                    } else {
+                        ToastUtils.tip(ctx.getString(R.string.current_step_not_allowed_to_add_colocker))
+                    }
+                }
+            }
+
+        }
+    }
+
+    /**
+     * 设置当前标题
+     *
+     * @param title
+     */
+    fun setTitle(title: String) {
+        mBinding?.tvTitle?.text = title
+    }
+
+    /**
+     * 设置当前已经选择的人员列表
+     */
+    fun setSelectList(list: ArrayList<TicketUserReqVO>, step: Int) {
+        this.step = step
+        this.selects.clear()
+        this.selects.addAll(list)
+        mBinding?.list1?.adapter?.notifyDataSetChanged()
+        mBinding?.list2?.adapter?.notifyDataSetChanged()
+    }
+
+    /**
+     * 设置数据源
+     *
+     * @param list1 上锁人的时候和共锁人的时候必传数据
+     * @param list2 共锁人的时候外部人员数据,上锁人时传null
+     */
+    fun setListData(list1: MutableList<UserListRespVO.Row>, list2: MutableList<UserListRespVO.Row>?) {
+        this.list1.clear()
+        this.list2.clear()
+        this.list1.addAll(list1)
+        if (list2 == null) {
+            isSelectLocker = true
+            mBinding?.tvInner?.visibility = View.GONE
+            mBinding?.tvOut?.visibility = View.GONE
+        } else {
+            isSelectLocker = false
+            mBinding?.tvInner?.visibility = View.VISIBLE
+            mBinding?.tvOut?.visibility = if (list2.isNotEmpty()) View.VISIBLE else View.GONE
+            this.list2.addAll(list2)
+        }
+        mBinding?.list1?.adapter?.notifyDataSetChanged()
+        mBinding?.list2?.adapter?.notifyDataSetChanged()
+    }
+
+    fun onConfirmClicked(func: (isLocker: Boolean, selects: MutableList<TicketUserReqVO>) -> Unit) {
+        this.func = func
+    }
+
+    override fun show() {
+        super.show()
+        val window = window ?: return
+        window.setLayout(520, ViewGroup.LayoutParams.WRAP_CONTENT)
+        window.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
+    }
+
+}

+ 8 - 2
app/src/main/java/com/grkj/iscs_mars/view/fragment/JobExecutionFragment.kt

@@ -2,6 +2,7 @@ package com.grkj.iscs_mars.view.fragment
 
 import com.grkj.iscs_mars.databinding.FragmentJobExecutionBinding
 import com.grkj.iscs_mars.model.bo.PageChangeBO
+import com.grkj.iscs_mars.util.AppUtils.isPortrait
 import com.grkj.iscs_mars.util.log.LogUtil
 import com.grkj.iscs_mars.view.activity.HomeActivity
 import com.grkj.iscs_mars.view.activity.HomeActivity.Menu
@@ -23,11 +24,16 @@ class JobExecutionFragment(val changePageCallback: (PageChangeBO) -> Unit) :
         get() = FragmentJobExecutionBinding.inflate(layoutInflater)
 
     override fun initView() {
+        val isPortrait = requireActivity().isPortrait()
         mMenuList = mutableListOf(
-            Menu(fragment = StepFragment({ changePage(PageChangeBO(-1)) }) {
+            Menu(fragment = if (isPortrait) StepFragment({ changePage(PageChangeBO(-1)) }) {
+                changePage(it)
+            } else StepFragmentLand({ changePage(PageChangeBO(-1)) }) {
                 changePage(it)
             }),
-            Menu(fragment = WorkerFragment({ refreshPage(mPageChangeBO!!) }) {
+            Menu(fragment = if (isPortrait) WorkerFragment({ refreshPage(mPageChangeBO!!) }) {
+                changePage(it)
+            } else WorkerFragmentLand({ refreshPage(mPageChangeBO!!) }) {
                 changePage(it)
             }),
             Menu(fragment = JobProgressFragment({ refreshPage(mPageChangeBO!!) }) {

+ 8 - 5
app/src/main/java/com/grkj/iscs_mars/view/fragment/JobManagementFragment.kt

@@ -26,11 +26,12 @@ class JobManagementFragment :
         get() = FragmentJobManagementBinding.inflate(layoutInflater)
 
     override fun initView() {
+        val isPortrait = requireActivity().isPortrait()
         mMenuList = mutableListOf(
             Menu(
                 getString(R.string.workshop),
                 R.mipmap.workshop,
-                if (requireActivity().isPortrait()) WorkshopFragment { pageChangeBO ->
+                if (isPortrait) WorkshopFragment { pageChangeBO ->
                     changePage(pageChangeBO)
                 } else WorkshopFragmentLand { pageChangeBO ->
                     changePage(pageChangeBO)
@@ -38,14 +39,16 @@ class JobManagementFragment :
             Menu(
                 getString(R.string.technology_sop),
                 R.mipmap.technology,
-                if (requireActivity().isPortrait()) TechnologySopFragment { pageChangeBO ->
+                if (isPortrait) TechnologySopFragment { pageChangeBO ->
                     changePage(pageChangeBO)
                 } else TechnologySopFragmentLand { pageChangeBO ->
                     changePage(pageChangeBO)
                 }),
-            Menu(getString(R.string.job_execution), R.mipmap.job_execution, JobExecutionFragment { pageChangeBO ->
-                changePage(pageChangeBO)
-            })
+            Menu(
+                getString(R.string.job_execution),
+                R.mipmap.job_execution, JobExecutionFragment { pageChangeBO ->
+                    changePage(pageChangeBO)
+                })
         )
 
         mBinding?.vp?.isUserInputEnabled = false

+ 51 - 49
app/src/main/java/com/grkj/iscs_mars/view/fragment/JobProgressFragment.kt

@@ -46,18 +46,36 @@ class JobProgressFragment(val goBack: () -> Unit, val changePage: (PageChangeBO)
         get() = FragmentJobProgressBinding.inflate(layoutInflater)
 
     override fun initView() {
-        mBinding?.cbBack?.setOnClickListener { goBack() }
+
+        mBinding?.llLockInfo?.setOnClickListener {
+            mBinding?.llLockInfo?.setBackgroundResource(R.color.dialog_card_login_bg)
+            mBinding?.llTogetherInfo?.setBackgroundResource(0)
+            mBinding?.cvLockInfo?.visibility = View.VISIBLE
+            mBinding?.cvTogetherInfo?.visibility = View.INVISIBLE
+        }
+
+        mBinding?.llTogetherInfo?.setOnClickListener {
+            mBinding?.llTogetherInfo?.setBackgroundResource(R.color.dialog_card_login_bg)
+            mBinding?.llLockInfo?.setBackgroundResource(0)
+            mBinding?.cvLockInfo?.visibility = View.INVISIBLE
+            mBinding?.cvTogetherInfo?.visibility = View.VISIBLE
+        }
+
+        mBinding?.rvLockPositionList?.adapter =
+            object : CommonAdapter<TicketDetailMonitorRespVO.IsJobTicketPointsVO>(requireActivity(), R.layout.item_rv_point_list, mPointList) {
+                override fun convert(holder: ViewHolder, point: TicketDetailMonitorRespVO.IsJobTicketPointsVO, position: Int) {
+                    holder.setText(R.id.tv_position, point.pointName)
+                    holder.setText(R.id.tv_func, point.effect)
+                }
+            }
+
+        
+        mBinding?.tvCancel?.setOnClickListener { goBack() }
+        
+        
         mBinding?.rvPoint?.adapter =
-            object : CommonAdapter<TicketDetailMonitorRespVO.IsJobTicketPointsVO>(
-                requireActivity(),
-                R.layout.item_rv_point,
-                mPointList
-            ) {
-                override fun convert(
-                    holder: ViewHolder,
-                    point: TicketDetailMonitorRespVO.IsJobTicketPointsVO,
-                    position: Int
-                ) {
+            object : CommonAdapter<TicketDetailMonitorRespVO.IsJobTicketPointsVO>(requireActivity(), R.layout.item_rv_point, mPointList) {
+                override fun convert(holder: ViewHolder, point: TicketDetailMonitorRespVO.IsJobTicketPointsVO, position: Int) {
                     holder.setText(R.id.tv_name, point.pointName)
                     holder.setText(R.id.tv_function, point.effect)
                     holder.setVisible(R.id.iv_status, point.switchStatus != null)
@@ -83,28 +101,16 @@ class JobProgressFragment(val goBack: () -> Unit, val changePage: (PageChangeBO)
                 }
             }
 
-        mBinding?.rvColocker?.adapter =
-            object : CommonAdapter<TicketDetailMonitorRespVO.IsJobTicketUser>(
-                requireActivity(),
-                R.layout.item_rv_worker_status,
-                mUserList
-            ) {
-                override fun convert(
-                    holder: ViewHolder,
-                    user: TicketDetailMonitorRespVO.IsJobTicketUser,
-                    position: Int
-                ) {
-                    holder.setText(R.id.tv_name, user.userName)
-                    holder.setVisible(
-                        R.id.iv_ready_to_lock,
-                        presenter?.needShowReadyToLock(requireContext(), mPointList, mStep) == true
-                    )
-                    holder.setVisible(R.id.iv_locked, user.jobStatus!! >= 4)
-                    holder.setVisible(R.id.iv_unlocked, user.jobStatus >= 5)
-                }
+        mBinding?.rvTogetherList?.adapter = object : CommonAdapter<TicketDetailMonitorRespVO.IsJobTicketUser>(requireActivity(), R.layout.item_rv_worker_status_list, mUserList) {
+            override fun convert(holder: ViewHolder, user: TicketDetailMonitorRespVO.IsJobTicketUser, position: Int) {
+                holder.setText(R.id.tv_personal, user.userName)
+                 holder.setVisible(R.id.iv_wait_lock, presenter?.needShowReadyToLock(requireContext(), mPointList, mStep) == true)
+                holder.setVisible(R.id.iv_locked, user.jobStatus!! >= 4)
+                holder.setVisible(R.id.iv_unlocked, user.jobStatus >= 5)
             }
+        }
 
-        mBinding?.cbAction?.debounce(2000) {
+        mBinding?.tvConfirm?.debounce(2000) {
             if (mStep == 4) {
                 presenter?.getTicketDetail(mPageChangeBO?.ticketId!!) {
                     if (it?.ticketKeyVOList?.any { it.keyStatus != "2" && it.ticketType == 0 && it.collectTime != null && it.giveBackTime == null } == true) {
@@ -150,7 +156,7 @@ class JobProgressFragment(val goBack: () -> Unit, val changePage: (PageChangeBO)
                         }
                         mTipDialog?.showCancelCountdown(10)
                     } else {
-                        presenter?.getTicketDetail(mPageChangeBO?.ticketId!!){
+                        presenter?.getTicketDetail(mPageChangeBO?.ticketId!!) {
                             if (it?.ticketKeyVOList?.any { it.keyStatus != "2" && it.ticketType == 1 && it.collectTime != null && it.giveBackTime == null } == true) {
                                 if (mTipDialog == null) {
                                     mTipDialog = TipDialog(requireContext())
@@ -226,6 +232,7 @@ class JobProgressFragment(val goBack: () -> Unit, val changePage: (PageChangeBO)
             when (it.code) {
                 MSG_EVENT_SWITCH_COLLECTION_UPDATE -> {
                     mBinding?.rvPoint?.adapter?.notifyDataSetChanged()
+                    mBinding?.rvLockPositionList?.adapter?.notifyDataSetChanged()
                 }
             }
         }
@@ -249,6 +256,7 @@ class JobProgressFragment(val goBack: () -> Unit, val changePage: (PageChangeBO)
                 mPointList.addAll(it?.ticketPointsList!!)
                 mUserList.addAll(it.colockUserList!!)
                 mBinding?.rvPoint?.adapter?.notifyDataSetChanged()
+                mBinding?.rvLockPositionList?.adapter?.notifyDataSetChanged()
                 mBinding?.rvColocker?.adapter?.notifyDataSetChanged()
                 handleActionBtnVisibility()
             }
@@ -365,36 +373,30 @@ class JobProgressFragment(val goBack: () -> Unit, val changePage: (PageChangeBO)
     private fun handleActionBtnVisibility() {
         when (mStep) {
             4 -> {
-                mBinding?.cbAction?.setText(getString(R.string.go_locking))
-                mBinding?.cbAction?.setIcon(R.mipmap.ticket_lock)
+                mBinding?.tvConfirm?.setText(getString(R.string.go_locking))
+                // mBinding?.tvConfirm?.setIcon(R.mipmap.ticket_lock)
                 if (mPointList.all { it.pointStatus == "1" }) {
-                    mBinding?.cbAction?.visibility = View.GONE
+                    mBinding?.tvConfirm?.visibility = View.GONE
                 } else {
-                    mBinding?.cbAction?.visibility = View.VISIBLE
+                    mBinding?.tvConfirm?.visibility = View.VISIBLE
                 }
             }
 
             7 -> {
-                if (presenter?.showGoToUnlock(
-                        requireContext(),
-                        mTicketDetail,
-                        mPointList,
-                        mUserList
-                    ) == true
-                ) {
-                    mBinding?.cbAction?.visibility = View.VISIBLE
-                    mBinding?.cbAction?.setIcon(R.mipmap.ticket_unlocked)
-                    mBinding?.cbAction?.setText(getString(R.string.go_unlocking))
+                if (presenter?.showGoToUnlock(requireContext(), mTicketDetail, mPointList, mUserList) == true) {
+                    mBinding?.tvConfirm?.visibility = View.VISIBLE
+                    // mBinding?.tvConfirm?.setIcon(R.mipmap.ticket_unlocked)
+                    mBinding?.tvConfirm?.setText(getString(R.string.go_unlocking))
                 } else {
-                    mBinding?.cbAction?.visibility = View.GONE
+                    mBinding?.tvConfirm?.visibility = View.GONE
                 }
             }
 
             else -> {
-                mBinding?.cbAction?.visibility = View.GONE
+                mBinding?.tvConfirm?.visibility = View.GONE
             }
         }
-        mBinding?.cbAction?.isEnabled = mBinding?.cbAction?.visibility == View.VISIBLE
+        mBinding?.tvConfirm?.isEnabled = mBinding?.tvConfirm?.visibility == View.VISIBLE
     }
 
     private fun handleBottomTip(ticketDetail: TicketDetailRespVO?) {

+ 462 - 0
app/src/main/java/com/grkj/iscs_mars/view/fragment/JobProgressFragmentLand.kt

@@ -0,0 +1,462 @@
+package com.grkj.iscs_mars.view.fragment
+
+import android.view.View
+import android.widget.ImageView
+import android.widget.LinearLayout
+import androidx.lifecycle.Observer
+import com.grkj.iscs_mars.BusinessManager
+import com.grkj.iscs_mars.R
+import com.grkj.iscs_mars.databinding.FragmentJobProgressBinding
+import com.grkj.iscs_mars.extentions.debounce
+import com.grkj.iscs_mars.model.bo.PageChangeBO
+import com.grkj.iscs_mars.model.eventmsg.MsgEvent
+import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants
+import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_SWITCH_COLLECTION_UPDATE
+import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_UPDATE_TICKET_PROGRESS
+import com.grkj.iscs_mars.model.eventmsg.UpdateTicketProgressMsg
+import com.grkj.iscs_mars.model.vo.ticket.TicketDetailMonitorRespVO
+import com.grkj.iscs_mars.model.vo.ticket.TicketDetailRespVO
+import com.grkj.iscs_mars.util.CommonUtils
+import com.grkj.iscs_mars.util.ToastUtils
+import com.grkj.iscs_mars.util.log.LogUtil
+import com.grkj.iscs_mars.view.base.BaseMvpFragment
+import com.grkj.iscs_mars.view.dialog.TipDialog
+import com.grkj.iscs_mars.view.iview.IJobProgressView
+import com.grkj.iscs_mars.view.presenter.JobProgressPresenter
+import com.zhy.adapter.recyclerview.CommonAdapter
+import com.zhy.adapter.recyclerview.base.ViewHolder
+
+/**
+ * 作业票工作进度页
+ */
+class JobProgressFragmentLand(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Unit) :
+    BaseMvpFragment<IJobProgressView, JobProgressPresenter, FragmentJobProgressBinding>() {
+
+    private val mPointList = mutableListOf<TicketDetailMonitorRespVO.IsJobTicketPointsVO>()
+    private val mUserList = mutableListOf<TicketDetailMonitorRespVO.IsJobTicketUser>()
+    private var mTicketDetail: TicketDetailRespVO? = null
+    private var mStep = 0
+    private var mCurrentStepId: Long? = null
+    private var mPageChangeBO: PageChangeBO? = null
+    private var mTipDialog: TipDialog? = null
+    private lateinit var observer: Observer<MsgEvent>
+    private var isVisible: Boolean = false
+
+    override val viewBinding: FragmentJobProgressBinding
+        get() = FragmentJobProgressBinding.inflate(layoutInflater)
+
+    override fun initView() {
+        mBinding?.cbBack?.setOnClickListener { goBack() }
+        mBinding?.rvPoint?.adapter =
+            object : CommonAdapter<TicketDetailMonitorRespVO.IsJobTicketPointsVO>(
+                requireActivity(),
+                R.layout.item_rv_point,
+                mPointList
+            ) {
+                override fun convert(
+                    holder: ViewHolder,
+                    point: TicketDetailMonitorRespVO.IsJobTicketPointsVO,
+                    position: Int
+                ) {
+                    holder.setText(R.id.tv_name, point.pointName)
+                    holder.setText(R.id.tv_function, point.effect)
+                    holder.setVisible(R.id.iv_status, point.switchStatus != null)
+                    holder.getView<ImageView>(R.id.iv_status)
+                        .setImageResource(if (point.switchStatus == "0") R.mipmap.switch_off else R.mipmap.switch_on)
+                    when (point.pointStatus) {
+                        "1" -> {
+                            holder.setVisible(R.id.ll_lock_status, true)
+                            holder.getView<LinearLayout>(R.id.ll_lock_status).isSelected = false
+                            holder.setText(R.id.tv_lock_status, getString(R.string.has_locked))
+                        }
+
+                        "2" -> {
+                            holder.setVisible(R.id.ll_lock_status, true)
+                            holder.getView<LinearLayout>(R.id.ll_lock_status).isSelected = true
+                            holder.setText(R.id.tv_lock_status, getString(R.string.unlocked))
+                        }
+
+                        else -> {
+                            holder.setVisible(R.id.ll_lock_status, false)
+                        }
+                    }
+                }
+            }
+
+        mBinding?.rvColocker?.adapter =
+            object : CommonAdapter<TicketDetailMonitorRespVO.IsJobTicketUser>(
+                requireActivity(),
+                R.layout.item_rv_worker_status,
+                mUserList
+            ) {
+                override fun convert(
+                    holder: ViewHolder,
+                    user: TicketDetailMonitorRespVO.IsJobTicketUser,
+                    position: Int
+                ) {
+                    holder.setText(R.id.tv_name, user.userName)
+                    holder.setVisible(
+                        R.id.iv_ready_to_lock,
+                        presenter?.needShowReadyToLock(requireContext(), mPointList, mStep) == true
+                    )
+                    holder.setVisible(R.id.iv_locked, user.jobStatus!! >= 4)
+                    holder.setVisible(R.id.iv_unlocked, user.jobStatus >= 5)
+                }
+            }
+
+        mBinding?.cbAction?.debounce(2000) {
+            if (mStep == 4) {
+                presenter?.getTicketDetail(mPageChangeBO?.ticketId!!) {
+                    if (it?.ticketKeyVOList?.any { it.keyStatus != "2" && it.ticketType == 0 && it.collectTime != null && it.giveBackTime == null } == true) {
+                        if (mTipDialog == null) {
+                            mTipDialog = TipDialog(requireContext())
+                        }
+                        mTipDialog?.setTip(getString(R.string.take_one_more_key_hint))
+                        mTipDialog?.setType(TipDialog.TYPE_HINT)
+                        mTipDialog?.setConfirmListener {
+                            BusinessManager.sendLoadingEventMsg(getString(R.string.system_is_processing))
+                            presenter?.handleLockProcess(mPageChangeBO?.ticketId!!)
+                        }
+                        mTipDialog?.showCancelCountdown(10)
+                    } else {
+                        BusinessManager.sendLoadingEventMsg(getString(R.string.system_is_processing))
+                        presenter?.handleLockProcess(mPageChangeBO?.ticketId!!)
+                    }
+                }
+            } else if (mStep == 7) {
+                val checkResult = presenter?.checkUnlock(requireContext(), mUserList)
+                if (checkResult?.isEmpty() == true) {
+                    //如果所有隔离点都有交叉作业,弹窗提醒确认就结束
+                    if (mTicketDetail?.ticketPointsVOList?.all {
+                            it.pointId in (mTicketDetail?.noUnlockTicketPointsVOSet?.map { it.pointId }
+                                ?: mutableListOf())
+                        } == true) {
+                        if (mTipDialog == null) {
+                            mTipDialog = TipDialog(requireContext())
+                        }
+                        mTipDialog?.setTip(getString(R.string.all_point_have_other_job_not_finish))
+                        mTipDialog?.setType(TipDialog.TYPE_HINT)
+                        mTipDialog?.setConfirmListener {
+                            mTicketDetail?.noUnlockTicketPointsVOSet?.let { noUnlockTicketPointsVOSet ->
+                                presenter?.updateCoincideToUnLock(noUnlockTicketPointsVOSet) {
+                                    mCurrentStepId?.let {
+                                        presenter?.updateStep(it, "1") {
+                                            goBack()
+                                        }
+                                    }
+                                        ?: ToastUtils.tip(getString(R.string.current_step_can_not_be_process))
+                                }
+                            }
+                        }
+                        mTipDialog?.showCancelCountdown(10)
+                    } else {
+                        presenter?.getTicketDetail(mPageChangeBO?.ticketId!!){
+                            if (it?.ticketKeyVOList?.any { it.keyStatus != "2" && it.ticketType == 1 && it.collectTime != null && it.giveBackTime == null } == true) {
+                                if (mTipDialog == null) {
+                                    mTipDialog = TipDialog(requireContext())
+                                }
+                                mTipDialog?.setTip(getString(R.string.take_one_more_key_hint))
+                                mTipDialog?.setType(TipDialog.TYPE_HINT)
+                                mTipDialog?.setConfirmListener {
+                                    BusinessManager.sendLoadingEventMsg(getString(R.string.system_is_processing))
+                                    if (mTicketDetail?.noUnlockTicketPointsVOSet?.isNotEmpty() == true) {
+                                        mTicketDetail?.noUnlockTicketPointsVOSet?.let { noUnlockTicketPointsVOSet ->
+                                            presenter?.updateCoincideToUnLock(
+                                                noUnlockTicketPointsVOSet
+                                            )
+                                        }
+                                    }
+                                    presenter?.handleUnlockProcess(mPageChangeBO?.ticketId!!)
+                                }
+                                mTipDialog?.showCancelCountdown(10)
+                            } else {
+                                BusinessManager.sendLoadingEventMsg(getString(R.string.system_is_processing))
+                                if (mTicketDetail?.noUnlockTicketPointsVOSet?.isNotEmpty() == true) {
+                                    mTicketDetail?.noUnlockTicketPointsVOSet?.let { noUnlockTicketPointsVOSet ->
+                                        presenter?.updateCoincideToUnLock(noUnlockTicketPointsVOSet)
+                                    }
+                                }
+                                presenter?.handleUnlockProcess(mPageChangeBO?.ticketId!!)
+                            }
+                        }
+                    }
+                } else {
+                    ToastUtils.tip(checkResult)
+                }
+            }
+        }
+
+        observer = Observer { newData ->
+            when (newData.code) {
+                MSG_EVENT_UPDATE_TICKET_PROGRESS -> {
+                    LogUtil.i("Update progress msg, isVisible : $isVisible")
+                    if (!isVisible) {
+                        return@Observer
+                    }
+                    val ticketId = (newData.data as UpdateTicketProgressMsg).ticketId
+                    LogUtil.i("Update progress msg, ticketId : $ticketId")
+                    if (ticketId == mPageChangeBO?.ticketId) {
+                        presenter?.checkMyTodoForHandleKey()
+                        mPageChangeBO?.let {
+                            refreshPage(it)
+                        }
+                    }
+                }
+
+                MsgEventConstants.MSG_EVENT_TICKET_FINISHED -> {
+                    if (mTipDialog == null) {
+                        mTipDialog = TipDialog(requireContext())
+                    }
+                    mTipDialog?.setType(TipDialog.TYPE_HINT)
+                    mTipDialog?.setTip(CommonUtils.getStr(R.string.job_already_finished).toString())
+                    mTipDialog?.setConfirmListener {
+                        changePage(PageChangeBO(-1))
+                    }
+                    mTipDialog?.show()
+                }
+            }
+        }
+
+        BusinessManager.mEventBus.observe(viewLifecycleOwner, observer)
+    }
+
+    override fun onResume() {
+        super.onResume()
+        BusinessManager.mEventBus.observe(this) {
+            when (it.code) {
+                MSG_EVENT_SWITCH_COLLECTION_UPDATE -> {
+                    mBinding?.rvPoint?.adapter?.notifyDataSetChanged()
+                }
+            }
+        }
+        isVisible = true
+    }
+
+    override fun refreshPage(pageChangeBO: PageChangeBO) {
+//        clearPage()
+        mPageChangeBO = pageChangeBO
+
+        presenter?.getTicketDetail(pageChangeBO.ticketId) {
+            mBinding?.tvTitle?.text = it?.ticketName
+            mTicketDetail = it
+            handleBottomTip(it)
+        }
+
+        getStepDetail(pageChangeBO.ticketId!!) {
+            presenter?.getTicketDetailMonitor(pageChangeBO.ticketId) {
+                mPointList.clear()
+                mUserList.clear()
+                mPointList.addAll(it?.ticketPointsList!!)
+                mUserList.addAll(it.colockUserList!!)
+                mBinding?.rvPoint?.adapter?.notifyDataSetChanged()
+                mBinding?.rvColocker?.adapter?.notifyDataSetChanged()
+                handleActionBtnVisibility()
+            }
+        }
+    }
+
+    /**
+     * 共锁和解除共锁
+     */
+    fun getCardNo(cardNo: String) {
+        getStepDetail(mPageChangeBO?.ticketId!!) {
+            presenter?.getCardInfoByNfc(cardNo) {
+                if (it == null) {
+                    return@getCardInfoByNfc
+                }
+                if (mTipDialog == null) {
+                    mTipDialog = TipDialog(requireContext())
+                }
+                val jobStatus = mUserList.find { itUser -> itUser.userId == it.userId }?.jobStatus
+                if (jobStatus == null || jobStatus >= 5) {
+                    val errorStr = if (jobStatus == null) {
+                        if (mStep == 4) {
+                            getString(R.string.current_user_does_not_have_the_authority_to_colock)
+                        } else {
+                            getString(R.string.current_user_does_not_have_the_authority_to_unlock_colock)
+                        }
+                    } else {
+                        getString(R.string.user_already_unlock)
+                    }
+                    ToastUtils.tip(errorStr)
+                    return@getCardInfoByNfc
+                }
+
+                //刷卡处理共锁的位置调整步骤主要在这块
+                if (presenter?.canHandleColockerLock(
+                        requireContext(),
+                        mStep, mTicketDetail
+                    ) == true
+                ) {
+                    if (presenter?.canHandleColockerUnlock(
+                            requireContext(),
+                            mStep
+                        ) == true && jobStatus == 4
+                    ) {
+                        mTipDialog?.setTip(getString(R.string.confirm_to_uncolock, it.nickName))
+                        mTipDialog?.setConfirmListener {
+                            presenter?.updateColockerStatus(
+                                mPageChangeBO?.ticketId!!,
+                                cardNo,
+                                "5"
+                            ) {
+                                refreshPage(mPageChangeBO!!)
+                            }
+                        }
+                        mTipDialog?.showCancelCountdown(10)
+                    } else if (jobStatus < 4) {
+                        mTipDialog?.setTip(getString(R.string.confirm_to_colock, it.nickName))
+                        mTipDialog?.setConfirmListener {
+                            presenter?.updateColockerStatus(
+                                mPageChangeBO?.ticketId!!,
+                                cardNo,
+                                "4"
+                            ) {
+                                refreshPage(mPageChangeBO!!)
+                            }
+                        }
+                        mTipDialog?.showCancelCountdown(10)
+                    } else {
+                        ToastUtils.tip(getString(R.string.current_colocker_already_locked))
+                        return@getCardInfoByNfc
+                    }
+                } else if (presenter?.canHandleColockerUnlock(requireContext(), mStep) == true) {
+                    if (jobStatus == 4) {
+                        mTipDialog?.setTip(getString(R.string.confirm_to_uncolock, it.nickName))
+                    } else {
+                        ToastUtils.tip(getString(R.string.current_colocker_already_unlocked))
+                        return@getCardInfoByNfc
+                    }
+                    mTipDialog?.setConfirmListener {
+                        presenter?.updateColockerStatus(
+                            mPageChangeBO?.ticketId!!,
+                            cardNo,
+                            "5"
+                        ) {
+                            presenter?.checkMyTodoForHandleKey()
+                            refreshPage(mPageChangeBO!!)
+                        }
+                    }
+                    mTipDialog?.showCancelCountdown(10)
+                } else {
+                    ToastUtils.tip(R.string.can_not_do_colock_action)
+                }
+            }
+        }
+    }
+
+    private fun getStepDetail(ticketId: Long, callback: (() -> Unit)? = null) {
+        presenter?.getStepDetail(ticketId) {
+            mBinding?.tvWorker?.text =
+                "${it?.get(2)?.userNum}/${it?.get(4)?.userNum}/${it?.get(7)?.userNum}"
+            mBinding?.tvLock?.text =
+                "${it?.get(2)?.lockNum}/${it?.get(4)?.lockNum}/${it?.get(7)?.lockNum}"
+
+            it?.filter { it.stepStatus == "1" }?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
+                mStep = it
+            }
+            mCurrentStepId =
+                it?.filter { it.stepStatus == "0" }?.minByOrNull { it.stepIndex!! }?.stepId
+            handleActionBtnVisibility()
+            callback?.invoke()
+        }
+    }
+
+    private fun handleActionBtnVisibility() {
+        when (mStep) {
+            4 -> {
+                mBinding?.cbAction?.setText(getString(R.string.go_locking))
+                mBinding?.cbAction?.setIcon(R.mipmap.ticket_lock)
+                if (mPointList.all { it.pointStatus == "1" }) {
+                    mBinding?.cbAction?.visibility = View.GONE
+                } else {
+                    mBinding?.cbAction?.visibility = View.VISIBLE
+                }
+            }
+
+            7 -> {
+                if (presenter?.showGoToUnlock(
+                        requireContext(),
+                        mTicketDetail,
+                        mPointList,
+                        mUserList
+                    ) == true
+                ) {
+                    mBinding?.cbAction?.visibility = View.VISIBLE
+                    mBinding?.cbAction?.setIcon(R.mipmap.ticket_unlocked)
+                    mBinding?.cbAction?.setText(getString(R.string.go_unlocking))
+                } else {
+                    mBinding?.cbAction?.visibility = View.GONE
+                }
+            }
+
+            else -> {
+                mBinding?.cbAction?.visibility = View.GONE
+            }
+        }
+        mBinding?.cbAction?.isEnabled = mBinding?.cbAction?.visibility == View.VISIBLE
+    }
+
+    private fun handleBottomTip(ticketDetail: TicketDetailRespVO?) {
+        when (mStep) {
+            4 -> {
+                val keyCount = ticketDetail?.ticketKeyVOList?.count { it.keyId != null }
+                if (keyCount == null || keyCount < 1) {
+                    mBinding?.llTip?.visibility = View.VISIBLE
+                    mBinding?.tvTip?.text = getString(R.string.please_go_locking)
+                } else if (keyCount == 1) {
+                    if (ticketDetail.ticketKeyVOList[0].keyStatus == "1") {
+                        mBinding?.llTip?.visibility = View.VISIBLE
+                        mBinding?.tvTip?.text = getString(R.string.please_return_key_after_locking)
+                    } else {
+                        mBinding?.llTip?.visibility = View.GONE
+                        mBinding?.tvTip?.text = ""
+                    }
+                }
+            }
+
+            6 -> {
+                mBinding?.llTip?.visibility = View.VISIBLE
+                mBinding?.tvTip?.text = getString(R.string.please_do_colock_and_remove_colock)
+            }
+
+            7 -> {
+                val keyCount = ticketDetail?.ticketKeyVOList?.count { it.keyId != null }
+                if (keyCount == 1) {
+                    mBinding?.llTip?.visibility = View.VISIBLE
+                    mBinding?.tvTip?.text = getString(R.string.please_go_unlocking)
+                } else if (keyCount == 2) {
+                    if (ticketDetail.ticketKeyVOList[1].keyStatus == "1") {
+                        mBinding?.llTip?.visibility = View.VISIBLE
+                        mBinding?.tvTip?.text =
+                            getString(R.string.please_return_key_after_unlocking)
+                    } else {
+                        mBinding?.llTip?.visibility = View.GONE
+                        mBinding?.tvTip?.text = ""
+                    }
+                }
+            }
+
+            else -> {
+                mBinding?.llTip?.visibility = View.GONE
+                mBinding?.tvTip?.text = ""
+            }
+        }
+    }
+
+    override fun onPause() {
+        super.onPause()
+        mStep = 0
+        mTipDialog?.dismiss()
+        isVisible = false
+    }
+
+    override fun onDestroy() {
+        super.onDestroy()
+        BusinessManager.mEventBus.removeObserver(observer)
+    }
+
+    override fun initPresenter(): JobProgressPresenter {
+        return JobProgressPresenter()
+    }
+}

+ 58 - 110
app/src/main/java/com/grkj/iscs_mars/view/fragment/StepFragment.kt

@@ -1,5 +1,6 @@
 package com.grkj.iscs_mars.view.fragment
 
+import android.util.Log
 import android.view.GestureDetector
 import android.view.MotionEvent
 import android.view.View
@@ -63,10 +64,10 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
             StepBO(R.mipmap.step2, getString(R.string.power_isolation_way), 2, "②"),
             StepBO(R.mipmap.step3, getString(R.string.notice_worker), 3, "③"),
             StepBO(R.mipmap.step4, getString(R.string.shutdown), 4, "④"),
-            StepBO(R.mipmap.step5, getString(R.string.unlock_and_restore_switch), 8, "⑧"),
-            StepBO(R.mipmap.step6, getString(R.string.check_before_unlocking), 7, "⑦"),
+            StepBO(R.mipmap.step8, getString(R.string.lock_and_hang_a_sign), 5, "⑤"),
             StepBO(R.mipmap.step7, getString(R.string.ensure_power_isolation), 6, "⑥"),
-            StepBO(R.mipmap.step8, getString(R.string.lock_and_hang_a_sign), 5, "⑤")
+            StepBO(R.mipmap.step6, getString(R.string.check_before_unlocking), 7, "⑦"),
+            StepBO(R.mipmap.step5, getString(R.string.unlock_and_restore_switch), 8, "⑧"),
         )
         mBinding?.rvStep?.adapter =
             object : CommonAdapter<StepBO>(requireContext(), R.layout.item_rv_step, mStepList) {
@@ -107,9 +108,40 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
                     }
                 }
             }
-        mBinding?.cbBack?.setOnClickListener { goBack() }
+
+        // 竖屏步骤流程
+        mBinding?.stepList?.adapter = object : CommonAdapter<StepBO>(requireContext(), R.layout.item_rv_step_list, mStepList) {
+
+            override fun convert(holder: ViewHolder, t: StepBO, position: Int) {
+                val status = t.stepDetail?.stepStatus ?: ""
+                // 步骤
+                holder.setText(R.id.tv_step, t.index.toString())
+                // 图标
+                holder.setImageResource(R.id.iv_icon, t.pic)
+                // 名称
+                holder.setText(R.id.tv_step_name, t.title)
+                // 处理流程状态,如果当前stepStatus = 1 表示当前流程已经完成
+                val statusIcon = if (status == "1") R.mipmap.step_executed else 0
+                holder.setImageResource(R.id.iv_status, statusIcon)
+                // 处理设置开锁和共锁人员界面
+                holder.setVisible(R.id.tv_setting, (mStep + 1) == t.index && status == "0")
+                // 设置上锁人和共锁人
+                holder.setOnClickListener(R.id.tv_setting) {
+                    mCanHandle ?: return@setOnClickListener
+                    if (mCanHandle == false) {
+                        ToastUtils.tip(R.string.no_permission_to_handle)
+                        return@setOnClickListener
+                    }
+                    handleStep(t.index)
+                }
+            }
+
+        }
+
+
+        mBinding?.tvBack?.setOnClickListener { goBack() }
         initMap()
-        mBinding?.cbAction?.setOnClickListener {
+        mBinding?.tvCancel?.setOnClickListener {
             mCanHandle ?: return@setOnClickListener
             if (mCanHandle == false) {
                 ToastUtils.tip(R.string.no_permission_to_handle)
@@ -232,7 +264,7 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
 
         presenter?.getTicketDetail(pageChangeBO.ticketId) {
             mTicketDetailData = it
-            mBinding?.tvTitle?.text = it?.ticketName
+            mBinding?.tvTicketName?.text = it?.ticketName
             it?.createBy?.let { itCreator ->
                 if (itCreator.isEmpty()) {
                     return@let
@@ -246,37 +278,38 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
 
         presenter?.getStepDetail(pageChangeBO.ticketId!!) {
             BusinessManager.sendLoadingEventMsg(null, false)
-            mBinding?.tvWorker?.text =
-                "${it?.get(2)?.userNum}/${it?.get(4)?.userNum}/${it?.get(7)?.userNum}"
-            mBinding?.tvLock?.text =
-                "${it?.get(2)?.lockNum}/${it?.get(4)?.lockNum}/${it?.get(7)?.lockNum}"
+
+            // 新设置锁信息和人员信息
+            mBinding?.tvLockPersonal?.text = "${it?.get(2)?.userNum}/${it?.get(4)?.userNum}/${it?.get(7)?.userNum} (带上锁/已上锁/已解锁)"
+            mBinding?.tvTogetherPersonal?.text = "${it?.get(2)?.lockNum}/${it?.get(4)?.lockNum}/${it?.get(7)?.lockNum} (待共锁/已共锁/已解除共锁)"
+
             mStepList.forEach { step ->
                 step.stepDetail = it?.find { it.stepIndex == step.index }
                 step.title =
                     it?.find { it.stepIndex == step.index }?.androidStepContent ?: step.title
             }
             mBinding?.rvStep?.adapter?.notifyDataSetChanged()
+            mBinding?.stepList?.adapter?.notifyDataSetChanged()
             it?.filter { it.stepStatus == "1" }?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
                 mStep = it
             }
             if (mStep <= 5) {
-                mBinding?.cbAction?.visibility = View.VISIBLE
-                mBinding?.cbAction?.setText(getString(R.string.cancel_the_job))
+                mBinding?.tvCancel?.visibility = View.VISIBLE
+                mBinding?.tvCancel?.setText(getString(R.string.cancel_the_job))
             } else if (mStep == 8) {
-                mBinding?.cbAction?.visibility = View.VISIBLE
-                mBinding?.cbAction?.setText(getString(R.string.finish_the_job))
+                mBinding?.tvCancel?.visibility = View.VISIBLE
+                mBinding?.tvCancel?.setText(getString(R.string.finish_the_job))
             } else {
-                mBinding?.cbAction?.visibility = View.GONE
+                mBinding?.tvCancel?.visibility = View.GONE
             }
             presenter?.preOpenKeyCharge(requireContext(), mStep)
             handleBottomTip()
         }
 
-        presenter?.getMachineryDetail(
-            pageChangeBO.machineryId!!, {
-                mMachineryDetail = it
-                Glide.with(this).load(it?.machineryImg).into(mBinding?.ivMachinery!!)
-            }) {
+        presenter?.getMachineryDetail(pageChangeBO.machineryId!!, {
+            mMachineryDetail = it
+            Glide.with(this).load(it?.machineryImg).into(mBinding?.ivMachinery!!)
+        }) {
             mLotoData = it
 
             if (!mLotoData.isNullOrEmpty()) {
@@ -295,81 +328,6 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
                                 }
                             }
                         }
-//                        // 如果没有图 URL,直接返回
-//                        val imageUrl = itMapInfo?.imageUrl ?: return@getMapInfo
-//
-//                        BitmapUtil.loadBitmapFromUrl(requireContext(), imageUrl) { mapBmp ->
-//                            if (mapBmp == null) {
-//                                LogUtil.e("Map pic is null")
-//                                return@loadBitmapFromUrl
-//                            }
-//
-//                            // 清空旧点
-//                            mStationList.clear()
-//
-//                            // 1 格 对应的像素
-//                            val cellPx = 50f
-//                            // 后端给的“逻辑”子图原始尺寸(像素)
-//                            val backendW = itMapInfo.width!!.toFloat()
-//                            val backendH = itMapInfo.height!!.toFloat()
-//                            // 实际下载回来的 Bitmap 尺寸(像素)
-//                            val actualW = mapBmp.width.toFloat()
-//                            val actualH = mapBmp.height.toFloat()
-//                            // 计算缩放比例
-//                            val ratioX = actualW / backendW
-//                            val ratioY = actualH / backendH
-//                            mapRatio = ratioX
-//                            // 子图在全局坐标系里的左上角偏移(像素)
-//                            val offsetX = itMapInfo.x!!.toFloat()
-//                            val offsetY = itMapInfo.y!!.toFloat()
-//                            // 图标请求尺寸:逻辑 45px * 缩放比
-//                            val iconReqPx = (45f * ratioX).toInt().coerceAtLeast(1)
-//
-//                            itMapInfo.pointList?.forEach { pt ->
-//                                // 1) 格数 → 全局像素
-//                                val globalX = pt.x!!.toFloat() * cellPx
-//                                val globalY = pt.y!!.toFloat() * cellPx
-//                                // 2) 全局像素 - 子图偏移 = 子图内像素
-//                                val localX = globalX - offsetX
-//                                val localY = globalY - offsetY
-//                                // 3) 再乘缩放比,得到真实 Bitmap 上的像素坐标
-//                                val finalX = localX * ratioX
-//                                val finalY = localY * ratioY
-//                                // 异步加载点位图标,固定请求尺寸
-//                                BitmapUtil.loadBitmapFromUrl(
-//                                    requireContext(),
-//                                    pt.pointIcon!!,
-//                                    reqWidth = iconReqPx,
-//                                    reqHeight = iconReqPx
-//                                ) { bmpIcon ->
-//                                    val icon = bmpIcon ?: BitmapUtil.getResizedBitmapFromMipmap(
-//                                        requireContext(),
-//                                        R.mipmap.ticket_type_placeholder,
-//                                        iconReqPx,
-//                                        iconReqPx
-//                                    )
-//
-//                                    mStationList.add(
-//                                        CustomStationLayer.IsolationPoint(
-//                                            PointF(finalX, finalY),
-//                                            pt.entityName!!,
-//                                            icon,
-//                                            pt.entityId!!.toLong(),
-//                                            pt.pointSerialNumber,
-//                                            mMachineryDetail?.pointIdList?.contains(pt.entityId) == true
-//                                        )
-//                                    )
-//
-//                                    // 全部点都加载完后,设置给 layer 并绘制
-//                                    if (mStationList.size == itMapInfo.pointList.size) {
-//                                        if (stationLayer?.inDraw == true) {
-//                                            return@loadBitmapFromUrl
-//                                        }
-//                                        mBinding?.mapview?.loadMap(mapBmp)
-//                                    }
-//                                }
-//                            }
-//                        }
                     }
                 }
             }
@@ -397,12 +355,10 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
 
             4, 5, 6, 7, 8 -> {
                 if (mStep != step - 1) {
-                    ToastUtils.tip(
-                        getString(
+                    ToastUtils.tip(getString(
                             R.string.please_done_operation,
                             mStepList.find { it.index == mStep + 1 }?.title
-                        )
-                    )
+                        ))
                     return
                 }
                 updateStep(step)
@@ -422,19 +378,14 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
                 8 -> getString(R.string.action_confirm_restore)
                 else -> ""
             }
-            if (step == 8 && presenter?.checkCrossJobUnlockData(
-                    requireContext(), mTicketDetailData
-                ) == true
-            ) {
+            if (step == 8 && presenter?.checkCrossJobUnlockData(requireContext(), mTicketDetailData) == true) {
                 mTipDialog.setTip(getString(R.string.all_point_have_other_job_not_finish))
                 mTipDialog.setType(TipDialog.TYPE_HINT)
                 mTipDialog.setConfirmListener {
                     mTicketDetailData?.noUnlockTicketPointsVOSet?.let {
                         presenter?.updateCoincideToUnLock(it) {
                             if (it) {
-                                presenter?.updateStep(
-                                    mStepList.find { it.index == step }?.stepDetail?.stepId!!, "1"
-                                ) {
+                                presenter?.updateStep(mStepList.find { it.index == step }?.stepDetail?.stepId!!, "1") {
                                     presenter?.checkMyTodoForHandleKey()
                                     mChangePage?.let {
                                         refreshPage(it)
@@ -456,10 +407,7 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
                                 presenter?.updateStep(mStepList[3].stepDetail?.stepId!!, "1") {
                                     BusinessManager.sendLoadingEventMsg(null, false)
                                     refreshPage(mChangePage!!)
-                                    if (presenter?.jumpJobProgressPageCheck(
-                                            requireContext(), step
-                                        ) == true
-                                    ) {
+                                    if (presenter?.jumpJobProgressPageCheck(requireContext(), step) == true) {
                                         // 自动跳转
                                         changePage(
                                             PageChangeBO(

+ 578 - 0
app/src/main/java/com/grkj/iscs_mars/view/fragment/StepFragmentLand.kt

@@ -0,0 +1,578 @@
+package com.grkj.iscs_mars.view.fragment
+
+import android.view.GestureDetector
+import android.view.MotionEvent
+import android.view.View
+import android.widget.ImageView
+import androidx.lifecycle.Observer
+import com.bumptech.glide.Glide
+import com.google.android.material.card.MaterialCardView
+import com.grkj.iscs_mars.BusinessManager
+import com.grkj.iscs_mars.R
+import com.grkj.iscs_mars.databinding.FragmentStepBinding
+import com.grkj.iscs_mars.model.bo.PageChangeBO
+import com.grkj.iscs_mars.model.eventmsg.MsgEvent
+import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_UPDATE_TICKET_PROGRESS
+import com.grkj.iscs_mars.model.eventmsg.UpdateTicketProgressMsg
+import com.grkj.iscs_mars.model.vo.machinery.MachineryDetailRespVO
+import com.grkj.iscs_mars.model.vo.ticket.LotoMapRespVO
+import com.grkj.iscs_mars.model.vo.ticket.StepDetailRespVO
+import com.grkj.iscs_mars.model.vo.ticket.TicketDetailRespVO
+import com.grkj.iscs_mars.util.SPUtils
+import com.grkj.iscs_mars.util.ToastUtils
+import com.grkj.iscs_mars.util.log.LogUtil
+import com.grkj.iscs_mars.view.base.BaseMvpFragment
+import com.grkj.iscs_mars.view.dialog.TipDialog
+import com.grkj.iscs_mars.view.iview.IStepView
+import com.grkj.iscs_mars.view.presenter.StepPresenter
+import com.grkj.iscs_mars.view.widget.CustomStationLayer
+import com.onlylemi.mapview.library.MapViewListener
+import com.sik.sikcore.extension.isNullOrEmpty
+import com.sik.sikcore.thread.ThreadUtils
+import com.zhy.adapter.recyclerview.CommonAdapter
+import com.zhy.adapter.recyclerview.base.ViewHolder
+
+/**
+ * 作业票执行步骤页 - 八大步骤
+ */
+class StepFragmentLand(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Unit) :
+    BaseMvpFragment<IStepView, StepPresenter, FragmentStepBinding>() {
+
+    private lateinit var mStepList: MutableList<StepBO>
+    private var mLotoData: LotoMapRespVO? = null
+    private var mChangePage: PageChangeBO? = null
+    private var mMachineryDetail: MachineryDetailRespVO? = null
+    private var mStep: Int = 0
+    private lateinit var mTipDialog: TipDialog
+    private var stationLayer: CustomStationLayer? = null
+    private val mStationList = mutableListOf<CustomStationLayer.IsolationPoint>()
+    private var mMapPicWidth = 1
+    private var mTicketDetailData: TicketDetailRespVO? = null
+    private lateinit var observer: Observer<MsgEvent>
+    private var mCanHandle: Boolean? = null // 是否可以操作,创建人、上锁人至少符合一个才可操作
+    private var mapRatio: Float = 1f
+    private lateinit var gestureDetector: GestureDetector
+
+    override val viewBinding: FragmentStepBinding
+        get() = FragmentStepBinding.inflate(layoutInflater)
+
+    override fun initView() {
+        mTipDialog = TipDialog(requireActivity())
+        mStepList = mutableListOf(
+            StepBO(R.mipmap.step1, getString(R.string.recognize_work_content), 1, "①"),
+            StepBO(R.mipmap.step2, getString(R.string.power_isolation_way), 2, "②"),
+            StepBO(R.mipmap.step3, getString(R.string.notice_worker), 3, "③"),
+            StepBO(R.mipmap.step4, getString(R.string.shutdown), 4, "④"),
+            StepBO(R.mipmap.step5, getString(R.string.unlock_and_restore_switch), 8, "⑧"),
+            StepBO(R.mipmap.step6, getString(R.string.check_before_unlocking), 7, "⑦"),
+            StepBO(R.mipmap.step7, getString(R.string.ensure_power_isolation), 6, "⑥"),
+            StepBO(R.mipmap.step8, getString(R.string.lock_and_hang_a_sign), 5, "⑤")
+        )
+        mBinding?.rvStep?.adapter =
+            object : CommonAdapter<StepBO>(requireContext(), R.layout.item_rv_step, mStepList) {
+                override fun convert(holder: ViewHolder, step: StepBO, position: Int) {
+                    if (step.stepDetail?.stepStatus == "1") {
+                        holder.getView<MaterialCardView>(R.id.cv_step)
+                            .setCardBackgroundColor(requireContext().getColor(R.color.item_rv_step_bg_done))
+                    } else {
+                        holder.getView<MaterialCardView>(R.id.cv_step).setCardBackgroundColor(
+                            if (mStep + 1 == step.index) requireContext().getColor(R.color.item_rv_step_bg_doing)
+                            else requireContext().getColor(R.color.common_bg_white_10)
+                        )
+                    }
+
+                    holder.setVisible(R.id.iv_arrow_right, step.index !in 4..5)
+                    holder.setVisible(R.id.iv_arrow_bottom, step.index == 4)
+                    holder.getView<ImageView>(R.id.iv_arrow_right).rotation =
+                        if (step.index > 5) 180f else 0f
+                    holder.getView<ImageView>(R.id.iv_icon).setImageResource(step.pic)
+                    holder.setText(R.id.tv_name, step.stepDetail?.androidStepContent)
+                    holder.setText(R.id.tv_index, step.indexStr)
+                    holder.getView<ImageView>(R.id.iv_status)
+                        .setImageResource(if (step.stepDetail?.stepStatus == "1") R.mipmap.step_executed else R.mipmap.step_not_executed)
+                    holder.setText(
+                        R.id.tv_status, if (step.stepDetail?.stepStatus == "1") {
+                            if (step.index == 3) getString(R.string.allocated) else getString(R.string.executed)
+                        } else {
+                            if (step.index == 3) getString(R.string.not_allocated) else getString(R.string.not_executed)
+                        }
+                    )
+                    holder.setOnClickListener(R.id.root) {
+                        mCanHandle ?: return@setOnClickListener
+                        if (mCanHandle == false) {
+                            ToastUtils.tip(R.string.no_permission_to_handle)
+                            return@setOnClickListener
+                        }
+                        handleStep(step.index)
+                    }
+                }
+            }
+        mBinding?.cbBack?.setOnClickListener { goBack() }
+        initMap()
+        mBinding?.cbAction?.setOnClickListener {
+            mCanHandle ?: return@setOnClickListener
+            if (mCanHandle == false) {
+                ToastUtils.tip(R.string.no_permission_to_handle)
+                return@setOnClickListener
+            }
+            if (mStep in 1..5) {
+                presenter?.cancelTicket(mChangePage?.ticketId!!) {
+                    if (it) {
+                        presenter?.checkMyTodoForHandleKey()
+                        changePage(PageChangeBO(-1))
+                    }
+                }
+            } else if (mStep == 8) {
+                if (mStepList.find { it.index == 8 }?.stepDetail?.conflictJobNum != 0) {
+                    mTipDialog.setTip(getString(R.string.action_confirm_finish_ticket))
+                    mTipDialog.setConfirmListener {
+                        presenter?.finishTicket(mChangePage?.ticketId!!) {
+                            if (it) changePage(PageChangeBO(-1))
+                        }
+                    }
+                    mTipDialog.show()
+                } else {
+                    presenter?.finishTicket(mChangePage?.ticketId!!) {
+                        if (it) changePage(PageChangeBO(-1))
+                    }
+                }
+            }
+        }
+
+        mBinding?.llDetail?.setOnClickListener {
+            mCanHandle ?: return@setOnClickListener
+            if (mCanHandle == false) {
+                ToastUtils.tip(R.string.no_permission_to_handle)
+                return@setOnClickListener
+            }
+            if (mStep >= 4) {
+                changePage(
+                    PageChangeBO(
+                        2,
+                        mChangePage?.workstationId,
+                        mChangePage?.ticketId,
+                        mChangePage?.machineryId,
+                        mChangePage?.machineryName
+                    )
+                )
+            }
+        }
+
+        observer = Observer { newData ->
+            if (newData.code != MSG_EVENT_UPDATE_TICKET_PROGRESS) {
+                return@Observer
+            }
+            LogUtil.i("Update progress msg, isVisible : $isVisible")
+            if (!isVisible) {
+                return@Observer
+            }
+            val ticketId = (newData.data as UpdateTicketProgressMsg).ticketId
+            LogUtil.i("Update progress msg, ticketId : $ticketId")
+            refreshPage(mChangePage!!)
+        }
+    }
+
+    override fun onResume() {
+        super.onResume()
+        mChangePage?.let {
+            refreshPage(it)
+        }
+    }
+
+
+    private fun initMap() {
+        gestureDetector =
+            GestureDetector(requireContext(), object : GestureDetector.SimpleOnGestureListener() {
+                override fun onDoubleTap(e: MotionEvent): Boolean {
+                    mBinding?.mapview?.currentRotateDegrees = 0f
+                    return super.onDoubleTap(e)
+                }
+
+                override fun onFling(
+                    e1: MotionEvent?,
+                    e2: MotionEvent,
+                    velocityX: Float,
+                    velocityY: Float
+                ): Boolean {
+                    mBinding?.mapview?.currentRotateDegrees = 0f
+                    return super.onFling(e1, e2, velocityX, velocityY)
+                }
+            })
+        mBinding?.mapview?.isScaleAndRotateTogether = false
+        mBinding?.mapview?.setOnTouchListener { _, event ->
+            gestureDetector.onTouchEvent(event)
+            false
+        }
+
+        // ★★★ 修正这里:== null,且创建后 setRatio 再 addLayer ★★★
+        if (stationLayer == null) {
+            stationLayer = CustomStationLayer(mBinding?.mapview, mStationList)
+            stationLayer?.setRatio(1f) // 没这句 bgBitmap 为 null,draw 不会画
+            mBinding?.mapview?.addLayer(stationLayer)
+        }
+
+        mBinding?.mapview?.setMapViewListener(object : MapViewListener {
+            override fun onMapLoadSuccess() {
+                mBinding?.mapview?.post {
+                    mBinding?.mapview?.currentRotateDegrees = 0f
+                    mBinding?.mapview?.refresh()
+                }
+            }
+
+            override fun onMapLoadFail() {
+                ToastUtils.tip("onMapLoadFail")
+            }
+        })
+    }
+
+    override fun refreshPage(pageChangeBO: PageChangeBO) {
+        LogUtil.i("$pageChangeBO")
+        mChangePage = pageChangeBO
+        mCanHandle = null
+
+        presenter?.getTicketDetail(pageChangeBO.ticketId) {
+            mTicketDetailData = it
+            mBinding?.tvTitle?.text = it?.ticketName
+            it?.createBy?.let { itCreator ->
+                if (itCreator.isEmpty()) {
+                    return@let
+                }
+                mCanHandle = itCreator.toLong() == SPUtils.getLoginUser(requireContext())?.userId
+            }
+            mCanHandle = (mCanHandle == true) || it?.ticketUserVOList?.any {
+                it.userId != null && it.userId.toLong() == SPUtils.getLoginUser(requireContext())?.userId
+            } == true
+        }
+
+        presenter?.getStepDetail(pageChangeBO.ticketId!!) {
+            BusinessManager.sendLoadingEventMsg(null, false)
+            mBinding?.tvWorker?.text =
+                "${it?.get(2)?.userNum}/${it?.get(4)?.userNum}/${it?.get(7)?.userNum}"
+            mBinding?.tvLock?.text =
+                "${it?.get(2)?.lockNum}/${it?.get(4)?.lockNum}/${it?.get(7)?.lockNum}"
+            mStepList.forEach { step ->
+                step.stepDetail = it?.find { it.stepIndex == step.index }
+                step.title =
+                    it?.find { it.stepIndex == step.index }?.androidStepContent ?: step.title
+            }
+            mBinding?.rvStep?.adapter?.notifyDataSetChanged()
+            it?.filter { it.stepStatus == "1" }?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
+                mStep = it
+            }
+            if (mStep <= 5) {
+                mBinding?.cbAction?.visibility = View.VISIBLE
+                mBinding?.cbAction?.setText(getString(R.string.cancel_the_job))
+            } else if (mStep == 8) {
+                mBinding?.cbAction?.visibility = View.VISIBLE
+                mBinding?.cbAction?.setText(getString(R.string.finish_the_job))
+            } else {
+                mBinding?.cbAction?.visibility = View.GONE
+            }
+            presenter?.preOpenKeyCharge(requireContext(), mStep)
+            handleBottomTip()
+        }
+
+        presenter?.getMachineryDetail(
+            pageChangeBO.machineryId!!, {
+                mMachineryDetail = it
+                Glide.with(this).load(it?.machineryImg).into(mBinding?.ivMachinery!!)
+            }) {
+            mLotoData = it
+
+            if (!mLotoData.isNullOrEmpty()) {
+                mLotoData?.mapId?.let { itId ->
+                    presenter?.getMapInfo(itId) { itMapInfo ->
+                        ThreadUtils.runOnIO {
+                            presenter?.mapDataHandleForStations(
+                                requireContext(),
+                                itMapInfo,
+                                mMachineryDetail?.pointIdList ?: mutableListOf(),
+                                { mBinding?.mapview },
+                                stationLayer
+                            ) { mapBmp ->
+                                ThreadUtils.runOnMain {
+                                    mBinding?.mapview?.loadMap(mapBmp)
+                                }
+                            }
+                        }
+//                        // 如果没有图 URL,直接返回
+//                        val imageUrl = itMapInfo?.imageUrl ?: return@getMapInfo
+//
+//                        BitmapUtil.loadBitmapFromUrl(requireContext(), imageUrl) { mapBmp ->
+//                            if (mapBmp == null) {
+//                                LogUtil.e("Map pic is null")
+//                                return@loadBitmapFromUrl
+//                            }
+//
+//                            // 清空旧点
+//                            mStationList.clear()
+//
+//                            // 1 格 对应的像素
+//                            val cellPx = 50f
+//                            // 后端给的“逻辑”子图原始尺寸(像素)
+//                            val backendW = itMapInfo.width!!.toFloat()
+//                            val backendH = itMapInfo.height!!.toFloat()
+//                            // 实际下载回来的 Bitmap 尺寸(像素)
+//                            val actualW = mapBmp.width.toFloat()
+//                            val actualH = mapBmp.height.toFloat()
+//                            // 计算缩放比例
+//                            val ratioX = actualW / backendW
+//                            val ratioY = actualH / backendH
+//                            mapRatio = ratioX
+//                            // 子图在全局坐标系里的左上角偏移(像素)
+//                            val offsetX = itMapInfo.x!!.toFloat()
+//                            val offsetY = itMapInfo.y!!.toFloat()
+//                            // 图标请求尺寸:逻辑 45px * 缩放比
+//                            val iconReqPx = (45f * ratioX).toInt().coerceAtLeast(1)
+//
+//                            itMapInfo.pointList?.forEach { pt ->
+//                                // 1) 格数 → 全局像素
+//                                val globalX = pt.x!!.toFloat() * cellPx
+//                                val globalY = pt.y!!.toFloat() * cellPx
+//                                // 2) 全局像素 - 子图偏移 = 子图内像素
+//                                val localX = globalX - offsetX
+//                                val localY = globalY - offsetY
+//                                // 3) 再乘缩放比,得到真实 Bitmap 上的像素坐标
+//                                val finalX = localX * ratioX
+//                                val finalY = localY * ratioY
+//                                // 异步加载点位图标,固定请求尺寸
+//                                BitmapUtil.loadBitmapFromUrl(
+//                                    requireContext(),
+//                                    pt.pointIcon!!,
+//                                    reqWidth = iconReqPx,
+//                                    reqHeight = iconReqPx
+//                                ) { bmpIcon ->
+//                                    val icon = bmpIcon ?: BitmapUtil.getResizedBitmapFromMipmap(
+//                                        requireContext(),
+//                                        R.mipmap.ticket_type_placeholder,
+//                                        iconReqPx,
+//                                        iconReqPx
+//                                    )
+//
+//                                    mStationList.add(
+//                                        CustomStationLayer.IsolationPoint(
+//                                            PointF(finalX, finalY),
+//                                            pt.entityName!!,
+//                                            icon,
+//                                            pt.entityId!!.toLong(),
+//                                            pt.pointSerialNumber,
+//                                            mMachineryDetail?.pointIdList?.contains(pt.entityId) == true
+//                                        )
+//                                    )
+//
+//                                    // 全部点都加载完后,设置给 layer 并绘制
+//                                    if (mStationList.size == itMapInfo.pointList.size) {
+//                                        if (stationLayer?.inDraw == true) {
+//                                            return@loadBitmapFromUrl
+//                                        }
+//                                        mBinding?.mapview?.loadMap(mapBmp)
+//                                    }
+//                                }
+//                            }
+//                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private fun handleStep(step: Int) {
+        if (mStep == 0) return
+        when (step) {
+            3 -> {
+                if (presenter?.canModifyColocker(requireContext(), step) == false) {
+                    ToastUtils.tip(R.string.current_step_can_not_modify_colocker)
+                    return
+                }
+                changePage(
+                    PageChangeBO(
+                        1,
+                        mChangePage?.workstationId,
+                        mChangePage?.ticketId,
+                        mChangePage?.machineryId,
+                        mChangePage?.machineryName
+                    )
+                )
+            }
+
+            4, 5, 6, 7, 8 -> {
+                if (mStep != step - 1) {
+                    ToastUtils.tip(
+                        getString(
+                            R.string.please_done_operation,
+                            mStepList.find { it.index == mStep + 1 }?.title
+                        )
+                    )
+                    return
+                }
+                updateStep(step)
+            }
+        }
+    }
+
+    private fun updateStep(step: Int) {
+        val canContinue =
+            presenter?.checkCanContinue(requireContext(), step, mTicketDetailData) ?: ""
+        if (canContinue.isEmpty()) {
+            val str = when (step) {
+                4 -> getString(R.string.action_confirm_shut_down)
+                5 -> getString(R.string.action_confirm_lock)
+                6 -> getString(R.string.action_confirm_power_isolation)
+                7 -> getString(R.string.action_confirm_check_before_unlocking)
+                8 -> getString(R.string.action_confirm_restore)
+                else -> ""
+            }
+            if (step == 8 && presenter?.checkCrossJobUnlockData(
+                    requireContext(), mTicketDetailData
+                ) == true
+            ) {
+                mTipDialog.setTip(getString(R.string.all_point_have_other_job_not_finish))
+                mTipDialog.setType(TipDialog.TYPE_HINT)
+                mTipDialog.setConfirmListener {
+                    mTicketDetailData?.noUnlockTicketPointsVOSet?.let {
+                        presenter?.updateCoincideToUnLock(it) {
+                            if (it) {
+                                presenter?.updateStep(
+                                    mStepList.find { it.index == step }?.stepDetail?.stepId!!, "1"
+                                ) {
+                                    presenter?.checkMyTodoForHandleKey()
+                                    mChangePage?.let {
+                                        refreshPage(it)
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                mTipDialog.showCancelCountdown(10)
+            } else {
+                mTipDialog.setTip(str)
+                mTipDialog.setType(TipDialog.TYPE_ALL)
+                mTipDialog.setConfirmListener {
+                    BusinessManager.sendLoadingEventMsg(getString(R.string.is_processing_please_wait))
+                    when (step) {
+                        4 -> {
+                            presenter?.updateStep(mStepList[2].stepDetail?.stepId!!, "1") {
+                                presenter?.updateStep(mStepList[3].stepDetail?.stepId!!, "1") {
+                                    BusinessManager.sendLoadingEventMsg(null, false)
+                                    refreshPage(mChangePage!!)
+                                    if (presenter?.jumpJobProgressPageCheck(
+                                            requireContext(), step
+                                        ) == true
+                                    ) {
+                                        // 自动跳转
+                                        changePage(
+                                            PageChangeBO(
+                                                2,
+                                                mChangePage?.workstationId,
+                                                mChangePage?.ticketId,
+                                                mChangePage?.machineryId,
+                                                mChangePage?.machineryName
+                                            )
+                                        )
+                                    }
+                                }
+                            }
+                        }
+
+                        else -> {
+                            presenter?.updateStep(
+                                mStepList.find { it.index == step }?.stepDetail?.stepId!!, "1"
+                            ) {
+                                refreshPage(mChangePage!!)
+                                if (presenter?.jumpJobProgressPageCheck(
+                                        requireContext(), step
+                                    ) == true
+                                ) {
+                                    // 自动跳转
+                                    changePage(
+                                        PageChangeBO(
+                                            2,
+                                            mChangePage?.workstationId,
+                                            mChangePage?.ticketId,
+                                            mChangePage?.machineryId,
+                                            mChangePage?.machineryName
+                                        )
+                                    )
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            mTipDialog.setType(TipDialog.TYPE_HINT)
+            mTipDialog.setTip(canContinue)
+            mTipDialog.setConfirmListener {
+                presenter?.tipToJobProgressPageCheck(requireContext(), mStep) {
+                    changePage(
+                        PageChangeBO(
+                            2,
+                            mChangePage?.workstationId,
+                            mChangePage?.ticketId,
+                            mChangePage?.machineryId,
+                            mChangePage?.machineryName
+                        )
+                    )
+                }
+            }
+        }
+        mTipDialog.show()
+    }
+
+    private fun handleBottomTip() {
+        mBinding?.llTip?.visibility = if (mStep >= 2) View.VISIBLE else View.GONE
+        when (mStep) {
+            2 -> {
+                mBinding?.tvTip?.text = getString(R.string.waiting_for_allocating_worker)
+            }
+
+            3 -> {
+                mBinding?.tvTip?.text = getString(R.string.waiting_for_shutting_down)
+            }
+
+            4 -> {
+                mBinding?.tvTip?.text = getString(R.string.waiting_for_hanging_a_sign)
+            }
+
+            5 -> {
+                mBinding?.tvTip?.text = getString(R.string.waiting_for_power_isolation)
+            }
+
+            6 -> {
+                mBinding?.tvTip?.text = getString(R.string.waiting_for_checking_before_unlocking)
+            }
+
+            7 -> {
+                mBinding?.tvTip?.text =
+                    getString(R.string.waiting_for_restoring_switch_before_unlocking)
+            }
+
+            8 -> {
+                mBinding?.tvTip?.text = getString(R.string.waiting_for_finishing)
+            }
+
+            else -> {
+                mBinding?.tvTip?.text = ""
+            }
+        }
+    }
+
+    override fun onPause() {
+        super.onPause()
+//        mBinding?.mapview?.release()
+        mStep = 0
+    }
+
+    override fun initPresenter(): StepPresenter {
+        return StepPresenter()
+    }
+
+    data class StepBO(
+        val pic: Int,
+        var title: String,
+        val index: Int,
+        val indexStr: String,
+        var stepDetail: StepDetailRespVO? = null
+    )
+}

+ 38 - 2
app/src/main/java/com/grkj/iscs_mars/view/fragment/TechnologySopFragment.kt

@@ -4,6 +4,7 @@ import android.widget.ImageView
 import android.widget.LinearLayout
 import androidx.recyclerview.widget.RecyclerView
 import com.bumptech.glide.Glide
+import com.google.android.material.card.MaterialCardView
 import com.grkj.iscs_mars.BusinessManager
 import com.grkj.iscs_mars.R
 import com.grkj.iscs_mars.databinding.FragmentTechnologySopBinding
@@ -25,9 +26,19 @@ import com.zhy.adapter.recyclerview.base.ViewHolder
 class TechnologySopFragment(val changePage: (PageChangeBO) -> Unit) :
     BaseMvpFragment<ITechnologySopView, TechnologySopPresenter, FragmentTechnologySopBinding>() {
 
+    // SOP列表
     private val mMachineryList = mutableListOf<MachineryPageRespVO.Record>()
+
+    // SOP类型
+    private val mMachineryTypeList = mutableListOf<MachineryPageRespVO.Record.SysDictData>()
+
+    // 当前选中的SOP
     private var mMachineryIdx = -1
+
+    // 当前选中的SOP类型
     private var mSopTypeIdx = -1
+
+    // 当前选中的岗位
     private var mWorkStationId = -1L
 
     override val viewBinding: FragmentTechnologySopBinding
@@ -125,17 +136,42 @@ class TechnologySopFragment(val changePage: (PageChangeBO) -> Unit) :
         mBinding?.sopList?.adapter =
             object : CommonAdapter<MachineryPageRespVO.Record>(requireActivity(), R.layout.item_rv_sop_list, mMachineryList) {
                 override fun convert(holder: ViewHolder, t: MachineryPageRespVO.Record, position: Int) {
-                    val colorId = if (mMachineryIdx.toLong() == t.machineryId) R.color.dialog_card_login_bg else R.color.common_transparent
+                    val colorId = if (mMachineryIdx == position) R.color.dialog_card_login_bg else R.color.common_transparent
                     holder.getView<LinearLayout>(R.id.root).setBackgroundResource(colorId)
                     holder.setText(R.id.tv_positon, t.workstationName)
                     holder.setText(R.id.tv_sop_name, t.machineryName)
                     holder.setOnClickListener(R.id.root) {
-                        mMachineryIdx = (t.machineryId ?: 0).toInt()
+                        mMachineryIdx = position
                         // 将当前选中的机器图片加载出来
                         Glide.with(this@TechnologySopFragment).load(t.machineryImg).into(mBinding!!.ivMachinery!!)
+                        // 处理当前SOP支持的类型
+                        mMachineryTypeList.clear()
+                        mMachineryTypeList.addAll(t.sysDictDatas ?: emptyList())
+                        mBinding?.sopTypeList?.adapter?.notifyDataSetChanged()
+                        // 更新当前选中状态
+                        notifyDataSetChanged()
+                    }
+                }
+            }
+
+        // 处理工艺类型
+        mBinding?.sopTypeList?.adapter =
+            object : CommonAdapter<MachineryPageRespVO.Record.SysDictData>(requireActivity(), R.layout.item_rv_sop_type, mMachineryTypeList) {
+
+                override fun convert(holder: ViewHolder, t: MachineryPageRespVO.Record.SysDictData, position: Int) {
+                    val colorId = if (mSopTypeIdx == position) R.color.dialog_card_login_bg_no_alpha else R.color.common_bg_black_10
+                    holder.getView<MaterialCardView>(R.id.cv_sop_type).setCardBackgroundColor(context!!.getColor(colorId))
+                    // 设置工艺图标
+                    mSopTypeList.find { it.type.toString() == t.dictValue }?.icon?.let { icon ->
+                        holder.getView<ImageView>(R.id.iv_sop_type).setImageResource(icon)
+                    }
+                    holder.setText(R.id.sop_type_name, t.dictLabel)
+                    holder.setOnClickListener(R.id.cv_sop_type) {
+                        mSopTypeIdx = position
                         notifyDataSetChanged()
                     }
                 }
+
             }
     }
 

+ 57 - 210
app/src/main/java/com/grkj/iscs_mars/view/fragment/WorkerFragment.kt

@@ -1,7 +1,6 @@
 package com.grkj.iscs_mars.view.fragment
 
 import android.view.View
-import android.widget.ImageView
 import com.grkj.iscs_mars.R
 import com.grkj.iscs_mars.databinding.FragmentWorkerBinding
 import com.grkj.iscs_mars.model.Constants.USER_ROLE_COLOCKER
@@ -15,6 +14,7 @@ import com.grkj.iscs_mars.model.vo.user.UserListRespVO
 import com.grkj.iscs_mars.util.SPUtils
 import com.grkj.iscs_mars.util.ToastUtils
 import com.grkj.iscs_mars.view.base.BaseMvpFragment
+import com.grkj.iscs_mars.view.dialog.LockerSelectDialog
 import com.grkj.iscs_mars.view.iview.IWorkerView
 import com.grkj.iscs_mars.view.presenter.WorkerPresenter
 import com.zhy.adapter.recyclerview.CommonAdapter
@@ -28,8 +28,7 @@ class WorkerFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> U
     private val mLockerSelectedList = mutableListOf<TicketUserReqVO>()
     private val mCoLockerSelectedList = mutableListOf<TicketUserReqVO>()
     private val mColockerSelectedShowList = mutableListOf<TicketUserReqVO>()    // 仅展示用
-    private val mOriginalUserList =
-        mutableListOf<TicketDetailRespVO.JobTicketUserVO>()  // 修改前的人员选择列表
+    private val mOriginalUserList = mutableListOf<TicketDetailRespVO.JobTicketUserVO>()  // 修改前的人员选择列表
 
     private val mLockerList = mutableListOf<UserListRespVO.Row>()
     private val mColockerInsideList = mutableListOf<UserListRespVO.Row>()
@@ -40,230 +39,78 @@ class WorkerFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> U
     private var mStepDetailList: MutableList<StepDetailRespVO> = mutableListOf()
     private var isColockerChanged: Boolean = false
 
+    private lateinit var mLockerSelectDialog: LockerSelectDialog
+
     override val viewBinding: FragmentWorkerBinding
         get() = FragmentWorkerBinding.inflate(layoutInflater)
 
     override fun initView() {
+        mLockerSelectDialog = LockerSelectDialog(requireContext(), presenter)
         mBinding?.layoutLocker?.ivPhoto?.isSelected = true
-
-        mBinding?.cbCancel?.setOnClickListener { goBack() }
-        mBinding?.cbConfirm?.setOnClickListener {
-            if (!checkUpdate()) {
-                return@setOnClickListener
-            }
+        // 设置取消和确定按钮的点击事件
+        mBinding?.tvCancel?.setOnClickListener { goBack() }
+        mBinding?.tvConfirm?.setOnClickListener {
+            if (!checkUpdate()) return@setOnClickListener
             if (isColockerChanged) {
                 presenter?.checkColockerChangedStepJump(requireContext(), mStepDetailList, mStep) {
-                    presenter?.updateTicketUser(
-                        mPageChangeBO?.ticketId!!,
-                        (mLockerSelectedList + mCoLockerSelectedList).toMutableList()
-                    ) {
-                        //选择人员之后提前打开充电,加速连接
+                    presenter?.updateTicketUser(mPageChangeBO?.ticketId!!, (mLockerSelectedList + mCoLockerSelectedList).toMutableList()) {
+                        // 选择人员之后提前打开充电,加速连接
                         presenter?.preOpenKeyCharge()
-                        if (it) {
-                            goBack()
-                        }
+                        if (it) goBack()
                     }
                 }
             }
         }
 
-        mBinding?.rvColockerSelected?.adapter =
-            object : CommonAdapter<TicketUserReqVO>(
-                requireActivity(),
-                R.layout.item_rv_worker,
-                mColockerSelectedShowList
-            ) {
-                override fun convert(holder: ViewHolder, data: TicketUserReqVO, position: Int) {
-                    holder.getView<ImageView>(R.id.iv_photo).isSelected = true
-                    holder.setText(R.id.tv_name, data.userName)
-                    holder.setOnClickListener(R.id.root) {
-                        if (presenter?.colockerCanRemove(requireContext(), data, mStep) == true) {
-                            val minColockerSize =
-                                presenter?.getMinColockerSize(requireContext()) ?: 1
-                            if (mColockerSelectedShowList.size == minColockerSize) {
-                                ToastUtils.tip(
-                                    getString(
-                                        R.string.keep_at_least_colocker,
-                                        minColockerSize
-                                    )
-                                )
-                                return@setOnClickListener
-                            }
-                            // 共锁人取消
-                            mCoLockerSelectedList.removeIf { it.userId == data.userId }
-                            mColockerSelectedShowList.removeIf { it.userId == data.userId }
-                            mBinding?.rvColockerSelected?.adapter?.notifyDataSetChanged()
-                            mBinding?.rvColockerInside?.adapter?.notifyDataSetChanged()
-                            mBinding?.rvColockerOutside?.adapter?.notifyDataSetChanged()
-                            isColockerChanged = true
-                        } else {
-                            ToastUtils.tip(getString(R.string.can_not_remove_current_colocker))
-                        }
-                    }
+        mLockerSelectDialog.onConfirmClicked { isLocker, selects ->
+            mLockerSelectDialog.dismiss()
+            if (isLocker) {
+                if (selects.isEmpty()) {
+                    ToastUtils.tip("至少保留一位上锁人")
+                    return@onConfirmClicked
                 }
+                isColockerChanged = true
+                mLockerSelectedList.clear()
+                mLockerSelectedList.addAll(selects)
+                mBinding?.rvLockPersonal?.adapter?.notifyDataSetChanged()
+            } else {
+                isColockerChanged = true
+                mCoLockerSelectedList.clear()
+                mColockerSelectedShowList.clear()
+                mCoLockerSelectedList.addAll(selects)
+                mColockerSelectedShowList.addAll(selects)
+                mBinding?.rvTogetherPersonal?.adapter?.notifyDataSetChanged()
             }
-
-        mBinding?.tvLockerSelect?.setOnClickListener {
-            mBinding?.llLocker?.visibility = View.VISIBLE
-            mBinding?.llColockerInside?.visibility = View.GONE
-            mBinding?.llColockerOutside?.visibility = View.GONE
         }
 
-        mBinding?.tvColockerSelect?.setOnClickListener {
-            mBinding?.llLocker?.visibility = View.GONE
-            mBinding?.llColockerInside?.visibility = View.VISIBLE
-            mBinding?.llColockerOutside?.visibility = View.VISIBLE
+        // 选择上锁人
+        mBinding?.tvLockSelect?.setOnClickListener {
+            mLockerSelectDialog.setTitle(getString(R.string.presentation_hint_locker))
+            mLockerSelectDialog.setSelectList(ArrayList(mLockerSelectedList), mStep)
+            mLockerSelectDialog.setListData(mLockerList, null)
+            mLockerSelectDialog.show()
+        }
+        // 选择共锁人
+        mBinding?.tvTogetherSelect?.setOnClickListener {
+            mLockerSelectDialog.setTitle("请选择共锁人")
+            mLockerSelectDialog.setSelectList(ArrayList(mColockerSelectedShowList), mStep)
+            mLockerSelectDialog.setListData(mColockerInsideList, mColockerOutsideList)
+            mLockerSelectDialog.show()
         }
 
-        mBinding?.rvLockerList?.adapter =
-            object : CommonAdapter<UserListRespVO.Row>(
-                requireActivity(),
-                R.layout.item_rv_worker,
-                mLockerList
-            ) {
-                override fun convert(holder: ViewHolder, user: UserListRespVO.Row, position: Int) {
-                    holder.getView<ImageView>(R.id.iv_photo).isSelected =
-                        mLockerSelectedList.any { it.userId == user.userId && it.userRole == USER_ROLE_LOCKER }
-                    holder.setText(R.id.tv_name, user.nickName)
-                    holder.setOnClickListener(R.id.root) {
-                        // 上锁人选择
-                        if (mLockerSelectedList.any { it.userId == user.userId }) {
-                            mLockerSelectedList.removeIf { it.userId == user.userId }
-                            mBinding?.layoutLocker?.root?.visibility = View.INVISIBLE
-                        } else {
-                            mLockerSelectedList.removeIf { it.userRole == USER_ROLE_LOCKER }
-                            mLockerSelectedList.add(
-                                TicketUserReqVO(
-                                    user.userId!!,
-                                    user.nickName!!,
-                                    "0",
-                                    USER_ROLE_LOCKER,
-                                    ticketUserVOList.find { ticketUser -> ticketUser.userId == user.userId }?.jobStatus
-                                )
-                            )
-                            mBinding?.layoutLocker?.root?.visibility = View.VISIBLE
-                            mBinding?.layoutLocker?.tvName?.text = user.nickName
-                        }
-                        mBinding?.rvLockerList?.adapter?.notifyDataSetChanged()
-                    }
-                }
-            }
-
-        mBinding?.rvColockerInside?.adapter =
-            object : CommonAdapter<UserListRespVO.Row>(
-                requireActivity(),
-                R.layout.item_rv_worker,
-                mColockerInsideList
-            ) {
-                override fun convert(holder: ViewHolder, user: UserListRespVO.Row, position: Int) {
-                    holder.getView<ImageView>(R.id.iv_photo).isSelected =
-                        mCoLockerSelectedList.any { it.userId == user.userId && it.userRole == USER_ROLE_COLOCKER }
-                    holder.setText(R.id.tv_name, user.nickName)
-                    holder.setOnClickListener(R.id.root) {
-                        if (presenter?.colockerInsideCanAdd(
-                                requireContext(),
-                                user,
-                                mStep
-                            ) == true
-                        ) {
-                            val addUser = TicketUserReqVO(
-                                user.userId!!,
-                                user.nickName!!,
-                                "0",
-                                USER_ROLE_COLOCKER,
-                                ticketUserVOList.find { ticketUser -> ticketUser.userId == user.userId }?.jobStatus
-                            )
-                            // 内部共锁人选择
-                            if (mCoLockerSelectedList.any { it.userId == user.userId } &&
-                                presenter?.colockerCanRemove(
-                                    requireContext(),
-                                    addUser,
-                                    mStep
-                                ) == true
-                            ) {
-                                val minColockerSize =
-                                    presenter?.getMinColockerSize(requireContext()) ?: 1
-                                if (mColockerSelectedShowList.size == minColockerSize) {
-                                    ToastUtils.tip(
-                                        getString(
-                                            R.string.keep_at_least_colocker,
-                                            minColockerSize
-                                        )
-                                    )
-                                    return@setOnClickListener
-                                }
-                                mCoLockerSelectedList.removeIf { it.userId == user.userId }
-                                mColockerSelectedShowList.removeIf { it.userId == user.userId }
-                            } else {
-                                mCoLockerSelectedList.add(addUser)
-                                mColockerSelectedShowList.add(addUser)
-                            }
-                            mBinding?.rvColockerSelected?.adapter?.notifyDataSetChanged()
-                            mBinding?.rvColockerInside?.adapter?.notifyDataSetChanged()
-                            isColockerChanged = true
-                        } else {
-                            ToastUtils.tip(getString(R.string.current_step_not_allowed_to_add_colocker))
-                        }
-                    }
-                }
+        // 处理已选择上锁人的列表
+        mBinding?.rvLockPersonal?.adapter = object : CommonAdapter<TicketUserReqVO>(requireActivity(), R.layout.item_rv_worker, mLockerSelectedList) {
+            override fun convert(holder: ViewHolder, user: TicketUserReqVO, position: Int) {
+                val user = mLockerList.find { it.userId == user.userId }
+                holder.setText(R.id.tv_name, user?.nickName ?: "")
             }
+        }
 
-        mBinding?.rvColockerOutside?.adapter =
-            object : CommonAdapter<UserListRespVO.Row>(
-                requireActivity(),
-                R.layout.item_rv_worker,
-                mColockerOutsideList
-            ) {
-                override fun convert(holder: ViewHolder, user: UserListRespVO.Row, position: Int) {
-                    holder.getView<ImageView>(R.id.iv_photo).isSelected =
-                        mCoLockerSelectedList.any { it.userId == user.userId }
-                    holder.setText(R.id.tv_name, user.nickName)
-                    holder.setOnClickListener(R.id.root) {
-                        if (presenter?.colockerOutsideCanAdd(
-                                requireContext(),
-                                user,
-                                mStep
-                            ) == true
-                        ) {
-                            val addUser = TicketUserReqVO(
-                                user.userId!!,
-                                user.nickName!!,
-                                "1",
-                                USER_ROLE_COLOCKER,
-                                ticketUserVOList.find { ticketUser -> ticketUser.userId == user.userId }?.jobStatus
-                            )
-                            // 外部共锁人选择
-                            if (mCoLockerSelectedList.any { it.userId == user.userId } &&
-                                presenter?.colockerCanRemove(
-                                    requireContext(),
-                                    addUser,
-                                    mStep
-                                ) == true
-                            ) {
-                                val minColockerSize =
-                                    presenter?.getMinColockerSize(requireContext()) ?: 1
-                                if (mColockerSelectedShowList.size == minColockerSize) {
-                                    ToastUtils.tip(
-                                        getString(
-                                            R.string.keep_at_least_colocker,
-                                            minColockerSize
-                                        )
-                                    )
-                                    return@setOnClickListener
-                                }
-                                mCoLockerSelectedList.removeIf { it.userId == user.userId }
-                                mColockerSelectedShowList.removeIf { it.userId == user.userId }
-                            } else {
-                                mCoLockerSelectedList.add(addUser)
-                                mColockerSelectedShowList.add(addUser)
-                            }
-                            mBinding?.rvColockerSelected?.adapter?.notifyDataSetChanged()
-                            mBinding?.rvColockerOutside?.adapter?.notifyDataSetChanged()
-                            isColockerChanged = true
-                        } else {
-                            ToastUtils.tip(getString(R.string.current_step_not_allowed_to_add_colocker))
-                        }
-                    }
+        // 处理已选择的共锁人列表
+        mBinding?.rvTogetherPersonal?.adapter =
+            object : CommonAdapter<TicketUserReqVO>(requireActivity(), R.layout.item_rv_worker, mColockerSelectedShowList) {
+                override fun convert(holder: ViewHolder, data: TicketUserReqVO, position: Int) {
+                    holder.setText(R.id.tv_name, data.userName)
                 }
             }
 
@@ -271,7 +118,7 @@ class WorkerFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> U
             if (mBinding?.layoutLocker?.root?.visibility == View.VISIBLE) {
                 mBinding?.layoutLocker?.root?.visibility = View.INVISIBLE
                 mLockerSelectedList.removeIf { it.userRole == USER_ROLE_LOCKER }
-                mBinding?.rvLockerList?.adapter?.notifyDataSetChanged()
+                mBinding?.rvLockPersonal?.adapter?.notifyDataSetChanged()
             }
         }
     }
@@ -337,8 +184,8 @@ class WorkerFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> U
             }
             mColockerSelectedShowList.addAll(mCoLockerSelectedList.filter { it.userRole == USER_ROLE_COLOCKER }
                 .toMutableList())
-            mBinding?.rvColockerSelected?.adapter?.notifyDataSetChanged()
-            mBinding?.rvLockerList?.adapter?.notifyDataSetChanged()
+            mBinding?.rvTogetherPersonal?.adapter?.notifyDataSetChanged()
+            mBinding?.rvLockPersonal?.adapter?.notifyDataSetChanged()
             mBinding?.rvColockerInside?.adapter?.notifyDataSetChanged()
             mBinding?.rvColockerOutside?.adapter?.notifyDataSetChanged()
         }
@@ -366,7 +213,7 @@ class WorkerFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> U
                     mBinding?.layoutLocker?.tvName?.text = it.nickName
                 }
             }
-            mBinding?.rvLockerList?.adapter?.notifyDataSetChanged()
+            mBinding?.rvLockPersonal?.adapter?.notifyDataSetChanged()
         }
 
         presenter?.getUserList(mPageChangeBO?.workstationId, 4) {

+ 438 - 0
app/src/main/java/com/grkj/iscs_mars/view/fragment/WorkerFragmentLand.kt

@@ -0,0 +1,438 @@
+package com.grkj.iscs_mars.view.fragment
+
+import android.view.View
+import android.widget.ImageView
+import com.grkj.iscs_mars.R
+import com.grkj.iscs_mars.databinding.FragmentWorkerBinding
+import com.grkj.iscs_mars.model.Constants.USER_ROLE_COLOCKER
+import com.grkj.iscs_mars.model.Constants.USER_ROLE_LOCKER
+import com.grkj.iscs_mars.model.bo.PageChangeBO
+import com.grkj.iscs_mars.model.vo.ticket.StepDetailRespVO
+import com.grkj.iscs_mars.model.vo.ticket.TicketDetailRespVO
+import com.grkj.iscs_mars.model.vo.ticket.TicketDetailRespVO.JobTicketUserVO
+import com.grkj.iscs_mars.model.vo.ticket.TicketUserReqVO
+import com.grkj.iscs_mars.model.vo.user.UserListRespVO
+import com.grkj.iscs_mars.util.SPUtils
+import com.grkj.iscs_mars.util.ToastUtils
+import com.grkj.iscs_mars.view.base.BaseMvpFragment
+import com.grkj.iscs_mars.view.iview.IWorkerView
+import com.grkj.iscs_mars.view.presenter.WorkerPresenter
+import com.zhy.adapter.recyclerview.CommonAdapter
+import com.zhy.adapter.recyclerview.base.ViewHolder
+
+/**
+ * 分配人员页
+ */
+class WorkerFragmentLand(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Unit) :
+    BaseMvpFragment<IWorkerView, WorkerPresenter, FragmentWorkerBinding>() {
+    private val mLockerSelectedList = mutableListOf<TicketUserReqVO>()
+    private val mCoLockerSelectedList = mutableListOf<TicketUserReqVO>()
+    private val mColockerSelectedShowList = mutableListOf<TicketUserReqVO>()    // 仅展示用
+    private val mOriginalUserList =
+        mutableListOf<JobTicketUserVO>()  // 修改前的人员选择列表
+
+    private val mLockerList = mutableListOf<UserListRespVO.Row>()
+    private val mColockerInsideList = mutableListOf<UserListRespVO.Row>()
+    private val mColockerOutsideList = mutableListOf<UserListRespVO.Row>()
+    private val ticketUserVOList = mutableListOf<JobTicketUserVO>()
+    private var mPageChangeBO: PageChangeBO? = null
+    private var mStep: Int = 0
+    private var mStepDetailList: MutableList<StepDetailRespVO> = mutableListOf()
+    private var isColockerChanged: Boolean = false
+
+    override val viewBinding: FragmentWorkerBinding
+        get() = FragmentWorkerBinding.inflate(layoutInflater)
+
+    override fun initView() {
+        mBinding?.layoutLocker?.ivPhoto?.isSelected = true
+
+        mBinding?.cbCancel?.setOnClickListener { goBack() }
+        mBinding?.cbConfirm?.setOnClickListener {
+            if (!checkUpdate()) {
+                return@setOnClickListener
+            }
+            if (isColockerChanged) {
+                presenter?.checkColockerChangedStepJump(requireContext(), mStepDetailList, mStep) {
+                    presenter?.updateTicketUser(
+                        mPageChangeBO?.ticketId!!,
+                        (mLockerSelectedList + mCoLockerSelectedList).toMutableList()
+                    ) {
+                        //选择人员之后提前打开充电,加速连接
+                        presenter?.preOpenKeyCharge()
+                        if (it) {
+                            goBack()
+                        }
+                    }
+                }
+            }
+        }
+
+        mBinding?.rvColockerSelected?.adapter =
+            object : CommonAdapter<TicketUserReqVO>(
+                requireActivity(),
+                R.layout.item_rv_worker,
+                mColockerSelectedShowList
+            ) {
+                override fun convert(holder: ViewHolder, data: TicketUserReqVO, position: Int) {
+                    holder.getView<ImageView>(R.id.iv_photo).isSelected = true
+                    holder.setText(R.id.tv_name, data.userName)
+                    holder.setOnClickListener(R.id.root) {
+                        if (presenter?.colockerCanRemove(requireContext(), data, mStep) == true) {
+                            val minColockerSize =
+                                presenter?.getMinColockerSize(requireContext()) ?: 1
+                            if (mColockerSelectedShowList.size == minColockerSize) {
+                                ToastUtils.tip(
+                                    getString(
+                                        R.string.keep_at_least_colocker,
+                                        minColockerSize
+                                    )
+                                )
+                                return@setOnClickListener
+                            }
+                            // 共锁人取消
+                            mCoLockerSelectedList.removeIf { it.userId == data.userId }
+                            mColockerSelectedShowList.removeIf { it.userId == data.userId }
+                            mBinding?.rvColockerSelected?.adapter?.notifyDataSetChanged()
+                            mBinding?.rvColockerInside?.adapter?.notifyDataSetChanged()
+                            mBinding?.rvColockerOutside?.adapter?.notifyDataSetChanged()
+                            isColockerChanged = true
+                        } else {
+                            ToastUtils.tip(getString(R.string.can_not_remove_current_colocker))
+                        }
+                    }
+                }
+            }
+
+        mBinding?.tvLockerSelect?.setOnClickListener {
+            mBinding?.llLocker?.visibility = View.VISIBLE
+            mBinding?.llColockerInside?.visibility = View.GONE
+            mBinding?.llColockerOutside?.visibility = View.GONE
+        }
+
+        mBinding?.tvColockerSelect?.setOnClickListener {
+            mBinding?.llLocker?.visibility = View.GONE
+            mBinding?.llColockerInside?.visibility = View.VISIBLE
+            mBinding?.llColockerOutside?.visibility = View.VISIBLE
+        }
+
+        mBinding?.rvLockerList?.adapter =
+            object : CommonAdapter<UserListRespVO.Row>(
+                requireActivity(),
+                R.layout.item_rv_worker,
+                mLockerList
+            ) {
+                override fun convert(holder: ViewHolder, user: UserListRespVO.Row, position: Int) {
+                    holder.getView<ImageView>(R.id.iv_photo).isSelected =
+                        mLockerSelectedList.any { it.userId == user.userId && it.userRole == USER_ROLE_LOCKER }
+                    holder.setText(R.id.tv_name, user.nickName)
+                    holder.setOnClickListener(R.id.root) {
+                        // 上锁人选择
+                        if (mLockerSelectedList.any { it.userId == user.userId }) {
+                            mLockerSelectedList.removeIf { it.userId == user.userId }
+                            mBinding?.layoutLocker?.root?.visibility = View.INVISIBLE
+                        } else {
+                            mLockerSelectedList.removeIf { it.userRole == USER_ROLE_LOCKER }
+                            mLockerSelectedList.add(
+                                TicketUserReqVO(
+                                    user.userId!!,
+                                    user.nickName!!,
+                                    "0",
+                                    USER_ROLE_LOCKER,
+                                    ticketUserVOList.find { ticketUser -> ticketUser.userId == user.userId }?.jobStatus
+                                )
+                            )
+                            mBinding?.layoutLocker?.root?.visibility = View.VISIBLE
+                            mBinding?.layoutLocker?.tvName?.text = user.nickName
+                        }
+                        mBinding?.rvLockerList?.adapter?.notifyDataSetChanged()
+                    }
+                }
+            }
+
+        mBinding?.rvColockerInside?.adapter =
+            object : CommonAdapter<UserListRespVO.Row>(
+                requireActivity(),
+                R.layout.item_rv_worker,
+                mColockerInsideList
+            ) {
+                override fun convert(holder: ViewHolder, user: UserListRespVO.Row, position: Int) {
+                    holder.getView<ImageView>(R.id.iv_photo).isSelected =
+                        mCoLockerSelectedList.any { it.userId == user.userId && it.userRole == USER_ROLE_COLOCKER }
+                    holder.setText(R.id.tv_name, user.nickName)
+                    holder.setOnClickListener(R.id.root) {
+                        if (presenter?.colockerInsideCanAdd(
+                                requireContext(),
+                                user,
+                                mStep
+                            ) == true
+                        ) {
+                            val addUser = TicketUserReqVO(
+                                user.userId!!,
+                                user.nickName!!,
+                                "0",
+                                USER_ROLE_COLOCKER,
+                                ticketUserVOList.find { ticketUser -> ticketUser.userId == user.userId }?.jobStatus
+                            )
+                            // 内部共锁人选择
+                            if (mCoLockerSelectedList.any { it.userId == user.userId } &&
+                                presenter?.colockerCanRemove(
+                                    requireContext(),
+                                    addUser,
+                                    mStep
+                                ) == true
+                            ) {
+                                val minColockerSize =
+                                    presenter?.getMinColockerSize(requireContext()) ?: 1
+                                if (mColockerSelectedShowList.size == minColockerSize) {
+                                    ToastUtils.tip(
+                                        getString(
+                                            R.string.keep_at_least_colocker,
+                                            minColockerSize
+                                        )
+                                    )
+                                    return@setOnClickListener
+                                }
+                                mCoLockerSelectedList.removeIf { it.userId == user.userId }
+                                mColockerSelectedShowList.removeIf { it.userId == user.userId }
+                            } else {
+                                mCoLockerSelectedList.add(addUser)
+                                mColockerSelectedShowList.add(addUser)
+                            }
+                            mBinding?.rvColockerSelected?.adapter?.notifyDataSetChanged()
+                            mBinding?.rvColockerInside?.adapter?.notifyDataSetChanged()
+                            isColockerChanged = true
+                        } else {
+                            ToastUtils.tip(getString(R.string.current_step_not_allowed_to_add_colocker))
+                        }
+                    }
+                }
+            }
+
+        mBinding?.rvColockerOutside?.adapter =
+            object : CommonAdapter<UserListRespVO.Row>(
+                requireActivity(),
+                R.layout.item_rv_worker,
+                mColockerOutsideList
+            ) {
+                override fun convert(holder: ViewHolder, user: UserListRespVO.Row, position: Int) {
+                    holder.getView<ImageView>(R.id.iv_photo).isSelected =
+                        mCoLockerSelectedList.any { it.userId == user.userId }
+                    holder.setText(R.id.tv_name, user.nickName)
+                    holder.setOnClickListener(R.id.root) {
+                        if (presenter?.colockerOutsideCanAdd(
+                                requireContext(),
+                                user,
+                                mStep
+                            ) == true
+                        ) {
+                            val addUser = TicketUserReqVO(
+                                user.userId!!,
+                                user.nickName!!,
+                                "1",
+                                USER_ROLE_COLOCKER,
+                                ticketUserVOList.find { ticketUser -> ticketUser.userId == user.userId }?.jobStatus
+                            )
+                            // 外部共锁人选择
+                            if (mCoLockerSelectedList.any { it.userId == user.userId } &&
+                                presenter?.colockerCanRemove(
+                                    requireContext(),
+                                    addUser,
+                                    mStep
+                                ) == true
+                            ) {
+                                val minColockerSize =
+                                    presenter?.getMinColockerSize(requireContext()) ?: 1
+                                if (mColockerSelectedShowList.size == minColockerSize) {
+                                    ToastUtils.tip(
+                                        getString(
+                                            R.string.keep_at_least_colocker,
+                                            minColockerSize
+                                        )
+                                    )
+                                    return@setOnClickListener
+                                }
+                                mCoLockerSelectedList.removeIf { it.userId == user.userId }
+                                mColockerSelectedShowList.removeIf { it.userId == user.userId }
+                            } else {
+                                mCoLockerSelectedList.add(addUser)
+                                mColockerSelectedShowList.add(addUser)
+                            }
+                            mBinding?.rvColockerSelected?.adapter?.notifyDataSetChanged()
+                            mBinding?.rvColockerOutside?.adapter?.notifyDataSetChanged()
+                            isColockerChanged = true
+                        } else {
+                            ToastUtils.tip(getString(R.string.current_step_not_allowed_to_add_colocker))
+                        }
+                    }
+                }
+            }
+
+        mBinding?.layoutLocker?.root?.setOnClickListener {
+            if (mBinding?.layoutLocker?.root?.visibility == View.VISIBLE) {
+                mBinding?.layoutLocker?.root?.visibility = View.INVISIBLE
+                mLockerSelectedList.removeIf { it.userRole == USER_ROLE_LOCKER }
+                mBinding?.rvLockerList?.adapter?.notifyDataSetChanged()
+            }
+        }
+    }
+
+    override fun refreshPage(pageChangeBO: PageChangeBO) {
+        mStep = 0
+        mOriginalUserList.clear()
+        mLockerSelectedList.clear()
+        mCoLockerSelectedList.clear()
+        mColockerSelectedShowList.clear()
+        mLockerList.clear()
+        mColockerInsideList.clear()
+        mColockerOutsideList.clear()
+
+        mBinding?.llLocker?.visibility = View.VISIBLE
+        mBinding?.llColockerInside?.visibility = View.GONE
+        mBinding?.llColockerOutside?.visibility = View.GONE
+
+        mPageChangeBO = pageChangeBO
+        mBinding?.layoutLocker?.root?.visibility = View.INVISIBLE
+
+        presenter?.getTicketDetail(pageChangeBO.ticketId) {
+            ticketUserVOList.clear()
+            ticketUserVOList.addAll(it?.ticketUserVOList ?: mutableListOf())
+            mBinding?.tvTitle?.text = it?.ticketName
+
+            if (it?.ticketUserVOList.isNullOrEmpty()) {
+                return@getTicketDetail
+            }
+            it?.ticketUserVOList?.let { it1 -> mOriginalUserList.addAll(it1) }
+            it?.ticketUserVOList?.forEach { user ->
+                if (user.userRole == USER_ROLE_LOCKER) {
+                    mBinding?.layoutLocker?.root?.visibility = View.VISIBLE
+                    mBinding?.layoutLocker?.tvName?.text = user.userName
+                }
+                mLockerSelectedList.add(
+                    TicketUserReqVO(
+                        user.userId!!,
+                        user.userName!!,
+                        user.userType!!,
+                        user.userRole!!,
+                        user.jobStatus
+                    )
+                )
+            }
+            // 上锁人默认选择自己
+            if (mLockerSelectedList.none { it.userRole == USER_ROLE_LOCKER }) {
+                val user =
+                    it?.ticketUserVOList?.find { it.userId == SPUtils.getLoginUser(requireContext())?.userId }
+                user?.let {
+                    mLockerSelectedList.add(
+                        TicketUserReqVO(
+                            it.userId!!,
+                            it.userName!!,
+                            it.userType!!,
+                            USER_ROLE_LOCKER,
+                            user.jobStatus
+                        )
+                    )
+                    mBinding?.layoutLocker?.root?.visibility = View.VISIBLE
+                    mBinding?.layoutLocker?.tvName?.text = it.userName
+                }
+            }
+            mColockerSelectedShowList.addAll(mCoLockerSelectedList.filter { it.userRole == USER_ROLE_COLOCKER }
+                .toMutableList())
+            mBinding?.rvColockerSelected?.adapter?.notifyDataSetChanged()
+            mBinding?.rvLockerList?.adapter?.notifyDataSetChanged()
+            mBinding?.rvColockerInside?.adapter?.notifyDataSetChanged()
+            mBinding?.rvColockerOutside?.adapter?.notifyDataSetChanged()
+        }
+
+        presenter?.getUserList(mPageChangeBO?.workstationId, 3, 9) {
+            mLockerList.clear()
+            if (!it?.rows.isNullOrEmpty()) {
+                mLockerList.addAll(it?.rows!!)
+            }
+            // 上锁人默认选择自己
+            if (mLockerSelectedList.none { it.userRole == USER_ROLE_LOCKER }) {
+                val user =
+                    it?.rows?.find { it.userId == SPUtils.getLoginUser(requireContext())?.userId }
+                user?.let {
+                    mLockerSelectedList.add(
+                        TicketUserReqVO(
+                            it.userId!!,
+                            it.nickName!!,
+                            "0",
+                            USER_ROLE_LOCKER,
+                            ticketUserVOList.find { ticketUser -> ticketUser.userId == it.userId }?.jobStatus
+                        )
+                    )
+                    mBinding?.layoutLocker?.root?.visibility = View.VISIBLE
+                    mBinding?.layoutLocker?.tvName?.text = it.nickName
+                }
+            }
+            mBinding?.rvLockerList?.adapter?.notifyDataSetChanged()
+        }
+
+        presenter?.getUserList(mPageChangeBO?.workstationId, 4) {
+            mColockerInsideList.clear()
+            mColockerOutsideList.clear()
+            if (!it?.rows.isNullOrEmpty()) {
+                it?.rows?.forEach { user ->
+                    if (user.unitId == 9L) {
+                        mColockerInsideList.add(user)
+                    } else {
+                        mColockerOutsideList.add(user)
+                    }
+                }
+            }
+            mBinding?.rvColockerInside?.adapter?.notifyDataSetChanged()
+            mBinding?.rvColockerOutside?.adapter?.notifyDataSetChanged()
+        }
+
+        presenter?.getStepDetail(pageChangeBO.ticketId!!) {
+            mStepDetailList.clear()
+            mStepDetailList.addAll(it ?: mutableListOf())
+            mBinding?.tvWorker?.text =
+                "${it?.get(2)?.userNum}/${it?.get(4)?.userNum}/${it?.get(7)?.userNum}"
+            mBinding?.tvLock?.text =
+                "${it?.get(2)?.lockNum}/${it?.get(4)?.lockNum}/${it?.get(7)?.lockNum}"
+
+            it?.filter { it.stepStatus == "1" }?.maxByOrNull { it.stepIndex!! }?.stepIndex?.let {
+                mStep = it
+            }
+        }
+    }
+
+    /**
+     * step4做完就不能改上锁人,step6做之前可改共锁人
+     */
+    private fun checkUpdate(): Boolean {
+        if (mStep == 0) {
+            return false
+        }
+        //选择人员的时候一定要添加共锁人
+        if (mStep == 2) {
+            val minColockerSize =
+                presenter?.getMinColockerSize(requireContext()) ?: 1
+            val hasColocker =
+                mCoLockerSelectedList.count { it.userRole == USER_ROLE_COLOCKER } >= minColockerSize
+            if (!hasColocker) {
+                ToastUtils.tip(getString(R.string.please_add_at_least_colockers, minColockerSize))
+                return false
+            }
+        }
+        if (mStep >= 4) {
+            val originLocker = mOriginalUserList.find { it.userRole == USER_ROLE_LOCKER }
+            val selectedLocker = mLockerSelectedList.find { it.userRole == USER_ROLE_LOCKER }
+            if (originLocker != null && selectedLocker != null && originLocker.userId != selectedLocker.userId) {
+                ToastUtils.tip(R.string.can_not_change_locker)
+                return false
+            }
+            if (presenter?.canChangeColocker(requireContext(), mStep) == false) {
+                ToastUtils.tip(R.string.can_not_change_colocker)
+                return false
+            }
+        }
+        return true
+    }
+
+    override fun initPresenter(): WorkerPresenter {
+        return WorkerPresenter()
+    }
+}

+ 25 - 57
app/src/main/java/com/grkj/iscs_mars/view/fragment/WorkshopFragment.kt

@@ -14,10 +14,9 @@ import com.grkj.iscs_mars.util.SPUtils
 import com.grkj.iscs_mars.util.ToastUtils
 import com.grkj.iscs_mars.util.log.LogUtil
 import com.grkj.iscs_mars.view.base.BaseMvpFragment
-import com.grkj.iscs_mars.view.dialog.TicketListDialog
 import com.grkj.iscs_mars.view.iview.IWorkshopView
 import com.grkj.iscs_mars.view.presenter.WorkshopPresenter
-import com.grkj.iscs_mars.view.widget.CustomMarkLayer
+import com.grkj.iscs_mars.view.widget.CustomMarkLayerSample
 import com.onlylemi.mapview.library.MapViewListener
 import com.zhy.adapter.recyclerview.CommonAdapter
 import com.zhy.adapter.recyclerview.base.ViewHolder
@@ -34,7 +33,7 @@ class WorkshopFragment(val changePage: (PageChangeBO) -> Unit) :
 
     // 当前工作任务列表
     private val jobList: MutableList<WorkstationTicketListRespVO> = mutableListOf()
-    private var markLayer: CustomMarkLayer? = null
+    private var markLayer: CustomMarkLayerSample? = null
     private val mPointList = mutableListOf<CustomPoint>()
     private var mMapPicWidth = 1
 
@@ -68,9 +67,13 @@ class WorkshopFragment(val changePage: (PageChangeBO) -> Unit) :
                 // 处理岗位
                 if (splName.size == 7) holder.setText(R.id.tv_positon, "${splName[0]}-${splName[1]}")
                 // 处理显示的图标
-                holder.setImageResource(R.id.iv_type, Constants.getTicketTypeRoundIcon(t.ticketType ?: ""))
+                holder.setImageBitmap(R.id.iv_type, t.bitmap)
                 // 显示票据名称
                 holder.setText(R.id.tv_job_name, t.ticketName)
+                // 当前作业的点击事件
+                holder.setOnClickListener(R.id.job_root) {
+                    changePage(PageChangeBO(2, t.workstationId, t.ticketId, t.machineryId, t.ticketName))
+                }
             }
         }
 
@@ -111,51 +114,39 @@ class WorkshopFragment(val changePage: (PageChangeBO) -> Unit) :
                         mPointList.forEach { itPoint ->
                             itPoint.ticketList = it.filter { it.workstationId == itPoint.workstationId }.toMutableList()
                             itPoint.ticketList.take(4).forEachIndexed { index, itTicket ->
-                                if (itPoint.ticketList.size > 3 && index == 3) {
-                                    val itBitmap = BitmapUtil.loadBitmapSmall(
-                                        requireContext(),
-                                        SPUtils.getAttributeValue(requireContext(), Constants.getTicketKey(5)),
-                                        60,
-                                        60,
-                                        R.mipmap.ticket_type_placeholder
-                                    )
-                                    itTicket.bitmap = itBitmap ?: BitmapUtil.getResizedBitmapFromMipmap(
+                                if (itTicket.ticketType == null) {
+                                    itTicket.bitmap = BitmapUtil.getResizedBitmapFromMipmap(
                                         requireContext(),
                                         R.mipmap.ticket_type_placeholder,
                                         60,
                                         60
                                     )
                                 } else {
-                                    if (itTicket.ticketType == null) {
-                                        itTicket.bitmap = BitmapUtil.getResizedBitmapFromMipmap(
+                                    val itBitmap = BitmapUtil.loadBitmapSmall(
+                                        requireContext(),
+                                        SPUtils.getAttributeValue(requireContext(), Constants.getTicketKey(itTicket.ticketType.toInt())),
+                                        60,
+                                        60, R.mipmap.ticket_type_placeholder
+                                    )
+                                    itTicket.bitmap =
+                                        itBitmap ?: BitmapUtil.getResizedBitmapFromMipmap(
                                             requireContext(),
                                             R.mipmap.ticket_type_placeholder,
                                             60,
                                             60
                                         )
-                                    } else {
-                                        val itBitmap = BitmapUtil.loadBitmapSmall(
-                                            requireContext(),
-                                            SPUtils.getAttributeValue(requireContext(), Constants.getTicketKey(itTicket.ticketType.toInt())),
-                                            60,
-                                            60, R.mipmap.ticket_type_placeholder
-                                        )
-                                        itTicket.bitmap =
-                                            itBitmap ?: BitmapUtil.getResizedBitmapFromMipmap(
-                                                requireContext(),
-                                                R.mipmap.ticket_type_placeholder,
-                                                60,
-                                                60
-                                            )
-                                    }
                                 }
                             }
                         }
                         mBinding?.rvStatistics?.adapter?.notifyDataSetChanged()
+                        mBinding?.jobsList?.adapter?.notifyDataSetChanged()
 
                         Executor.repeatOnMain({
                             val isAllBitmapLoaded = mPointList.all { it.ticketList.take(4).all { it.bitmap != null } }
-                            if (isAllBitmapLoaded) mBinding?.mapview?.refreshWorld()
+                            if (isAllBitmapLoaded) {
+                                mBinding?.mapview?.currentZoom = 0.51f
+                                mBinding?.mapview?.refreshWorld()
+                            }
                             return@repeatOnMain !isAllBitmapLoaded
                         }, 100, true)
                     }
@@ -168,41 +159,18 @@ class WorkshopFragment(val changePage: (PageChangeBO) -> Unit) :
         mBinding?.mapview?.isScaleAndRotateTogether = false
         mBinding?.mapview?.setMapViewListener(object : MapViewListener {
             override fun onMapLoadSuccess() {
+                mBinding?.mapview?.currentZoom = 0.51f
                 mBinding?.mapview?.post {
                     // 要加null判断,否则loadMap的时候会调用onMapLoadSuccess导致多次创建layer
                     if (markLayer != null) {
                         mBinding?.mapview?.currentRotateDegrees = 0f
                         return@post
                     }
-                    markLayer = CustomMarkLayer(mBinding?.mapview, mPointList)
-                    markLayer?.setMarkIsClickListener(object : CustomMarkLayer.MarkIsClickListener {
+                    markLayer = CustomMarkLayerSample(mBinding?.mapview, mPointList)
+                    markLayer?.setMarkIsClickListener(object : CustomMarkLayerSample.MarkIsClickListener {
                         override fun markIsClick(index: Int, btnIndex: Int, isClickIcon: Boolean) {
                             if (btnIndex == -1) {
                                 changePage(PageChangeBO(1, mPointList[index].workstationId, machineryName = mPointList[index].name))
-                            } else {
-                                if (isClickIcon && (mPointList[index].ticketList.size <= 3 || (mPointList[index].ticketList.size > 3 && btnIndex < 2))) {
-                                    changePage(
-                                        PageChangeBO(
-                                            2,
-                                            mPointList[index].workstationId,
-                                            mPointList[index].ticketList[btnIndex].ticketId,
-                                            mPointList[index].ticketList[btnIndex].machineryId,
-                                            mPointList[index].name
-                                        )
-                                    )
-                                    return
-                                }
-                                TicketListDialog(requireContext()) { selectIdx ->
-                                    changePage(
-                                        PageChangeBO(
-                                            2,
-                                            mPointList[index].workstationId,
-                                            mPointList[index].ticketList[selectIdx].ticketId,
-                                            mPointList[index].ticketList[selectIdx].machineryId,
-                                            mPointList[index].name
-                                        )
-                                    )
-                                }.setDataAndShow(mPointList[index].name, mPointList[index].ticketList)
                             }
                         }
                     })

+ 25 - 11
app/src/main/java/com/grkj/iscs_mars/view/presenter/TechnologySopPresenter.kt

@@ -37,17 +37,31 @@ class TechnologySopPresenter : BasePresenter<ITechnologySopView>() {
             ToastUtils.tip(R.string.please_select_sop_type)
             return
         }
-        BusinessManager.sendLoadingEventMsg(mContext?.getString(R.string.ticket_is_starting))
-        NetApi.getSopPage(
-            0,
-            100,
-            list[machineryIdx].machineryId!!,
-            list[machineryIdx].sysDictDatas?.get(sopTypeIdx)?.dictValue!!.toInt()
-        ) {
-            it ?: return@getSopPage
-            NetApi.createTicket(it.records[0].sopId) { ticketId ->
-                Executor.runOnMain {
-                    callBack(ticketId)
+        // 校验当前工艺是否已经有任务,如果有,不让创建任务
+        ThreadUtils.runOnIO {
+            val machineryId = list[machineryIdx].machineryId
+            val ticketType = list[machineryIdx].sysDictDatas?.get(sopTypeIdx)?.dictValue ?: ""
+            NetApi.getWorkstationTicketList(0, 100) {
+                val find = it?.find { t -> t.machineryId == machineryId && t.ticketType == ticketType }
+                ThreadUtils.runOnMain {
+                    if (find == null) {
+                        BusinessManager.sendLoadingEventMsg(mContext?.getString(R.string.ticket_is_starting))
+                        NetApi.getSopPage(
+                            0,
+                            100,
+                            list[machineryIdx].machineryId!!,
+                            list[machineryIdx].sysDictDatas?.get(sopTypeIdx)?.dictValue!!.toInt()
+                        ) {
+                            it ?: return@getSopPage
+                            NetApi.createTicket(it.records[0].sopId) { ticketId ->
+                                Executor.runOnMain {
+                                    callBack(ticketId)
+                                }
+                            }
+                        }
+                    } else {
+                        ToastUtils.tip("当前SOP已有工作在执行")
+                    }
                 }
             }
         }

+ 12 - 18
app/src/main/java/com/grkj/iscs_mars/view/presenter/WorkerPresenter.kt

@@ -2,12 +2,8 @@ package com.grkj.iscs_mars.view.presenter
 
 import android.content.Context
 import com.grkj.iscs_mars.R
-import com.grkj.iscs_mars.modbus.DockBean
-import com.grkj.iscs_mars.modbus.ModBusController
-import com.grkj.iscs_mars.modbus.ModBusController.dockList
+import com.grkj.iscs_mars.enums.HardwareMode
 import com.grkj.iscs_mars.model.Constants.USER_ROLE_LOCKER
-import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_KEY
-import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_PORTABLE
 import com.grkj.iscs_mars.model.vo.ticket.StepDetailRespVO
 import com.grkj.iscs_mars.model.vo.ticket.TicketDetailRespVO
 import com.grkj.iscs_mars.model.vo.ticket.TicketUserReqVO
@@ -30,8 +26,8 @@ class WorkerPresenter : BasePresenter<IWorkerView>() {
             ToastUtils.tip(mContext!!.resources.getString(R.string.ticket_id_is_null))
             return
         }
-        NetApi.getTicketDetail(ticketId) {it,_->
-            if (it==null){
+        NetApi.getTicketDetail(ticketId) { it, _ ->
+            if (it == null) {
                 return@getTicketDetail
             }
             Executor.runOnMain {
@@ -137,18 +133,16 @@ class WorkerPresenter : BasePresenter<IWorkerView>() {
      */
     fun preOpenKeyCharge() {
         ThreadUtils.runOnIO {
-            val keyDockList =
-                dockList.filter { it.type == DOCK_TYPE_KEY || it.type == DOCK_TYPE_PORTABLE }
-            keyDockList.forEach { dock ->
-                dock.deviceList.filter { it.isExist }.filterIsInstance<DockBean.KeyBean>()
-                    .forEach { key ->
-                        ModBusController.controlKeyCharge(false, key.isLeft, dock.addr) {
-                            ThreadUtils.runOnIO {
-                                delay(3000)
-                                ModBusController.controlKeyCharge(true, key.isLeft, dock.addr)
-                            }
-                        }
+            val opt = HardwareMode.getCurrentHardwareMode()
+            opt.getKeyDockData().forEach { dock ->
+                val canUseKeys = dock.keyData.filter { key -> key.isExist }
+                canUseKeys.forEach {
+                    opt.controlKeyCharge(false, it.idx, dock.addr)
+                    ThreadUtils.runOnIO {
+                        delay(3000)
+                        opt.controlKeyCharge(true, it.idx, dock.addr)
                     }
+                }
             }
         }
     }

+ 236 - 0
app/src/main/java/com/grkj/iscs_mars/view/widget/CustomMarkLayerSample.kt

@@ -0,0 +1,236 @@
+package com.grkj.iscs_mars.view.widget
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Matrix
+import android.graphics.Paint
+import android.graphics.RectF
+import android.view.MotionEvent
+import com.grkj.iscs_mars.util.IconCache
+import com.grkj.iscs_mars.view.fragment.WorkshopFragment.CustomPoint
+import com.onlylemi.mapview.library.MapView
+import com.onlylemi.mapview.library.layer.MapBaseLayer
+
+/**
+ * 首页地图区域图层
+ */
+class CustomMarkLayerSample @JvmOverloads constructor(
+    mapView: MapView?,
+    private var pointList: List<CustomPoint> = mutableListOf()
+) : MapBaseLayer(mapView) {
+    private var listener: MarkIsClickListener? = null
+    private var textSize = 36f
+    private var horizontalPadding = 30f
+    private var isClickMark: Boolean = false
+    private var num: Int
+    private lateinit var paint: Paint
+    private var btnIndex: Int
+    private var currentZoom = 0f
+    private var currentDegree = 0f
+    private var mBitmapSize = 48    // 默认图标大小
+    private var isClickIcon: Boolean = false
+    private var isFirst: Boolean = true
+
+    private val iconCache = IconCache(12 * 1024 * 1024) // 12MB 够用
+
+    init {
+        num = -1
+        btnIndex = -1
+        initLayer()
+    }
+
+    private fun initLayer() {
+        paint = Paint()
+        paint.isAntiAlias = true
+        paint.style = Paint.Style.FILL_AND_STROKE
+        paint.isFilterBitmap = true
+    }
+
+    override fun onTouch(event: MotionEvent) {
+        if (pointList.isEmpty() || event.action != MotionEvent.ACTION_UP) return
+
+        val sx = event.x
+        val sy = event.y
+
+        // 初始化点击状态
+        isClickMark = false
+        isClickIcon = false
+        num = -1
+        btnIndex = -1
+
+        // 文字绘制时的度量要一致
+        paint.textSize = textSize
+
+        // 遍历所有点(屏幕坐标命中)
+        for (i in pointList.indices) {
+            val point = pointList[i]
+
+            // 1) 地图点 -> 屏幕点(与 onDraw 完全一致)
+            val goal = mapView.mapXYToScreenXY(point.pos.x, point.pos.y)
+
+            // ===== 命中 1:label 圆角矩形(与 onDraw 同公式)=====
+            val name = point.name
+            val width = paint.measureText(name)
+            val fm = paint.fontMetrics
+            val height = fm.descent - fm.ascent
+
+            val labelLeft = goal[0] - width / 2f - horizontalPadding * 2f
+            val labelTop = goal[1] - height / 2f - horizontalPadding / 2f
+            val labelRight = goal[0] + width / 2f + horizontalPadding * 2f
+            val labelBottom = goal[1] + height / 2f + horizontalPadding / 2f
+
+            if (sx > labelLeft && sx < labelRight && sy > labelTop && sy < labelBottom) {
+                num = i
+                btnIndex = -1
+                isClickMark = true
+                isClickIcon = false
+                break
+            }
+
+            // ===== 命中 2:上方最多 3 个 icon(与 onDraw 同公式)=====
+            val list = point.ticketList.take(3)
+            if (list.isEmpty()) continue
+
+            // icon 顶点的屏幕 Y(与 onDraw 保持)
+            val iconTopY = goal[1] - height / 2f - horizontalPadding / 2f - 10f - mBitmapSize
+
+            for (j in list.indices) {
+                // 与 onDraw 的水平排布保持一致
+                val ticketX = when {
+                    list.size % 2 == 0 -> { // 偶数
+                        if (j + 1 <= list.size / 2) {
+                            goal[0] - mBitmapSize * (list.size / 2 - j)
+                        } else {
+                            goal[0] + mBitmapSize * (j - list.size / 2)
+                        }
+                    }
+
+                    else -> { // 奇数
+                        if (j + 1 <= list.size / 2) {
+                            goal[0] - mBitmapSize * (list.size / 2 - j + 0.5f)
+                        } else {
+                            goal[0] + mBitmapSize * (j - list.size / 2 - 0.5f)
+                        }
+                    }
+                }
+
+                // icon 的屏幕矩形(顶点与 onDraw 对齐)
+                val iconLeft = ticketX
+                val iconTop = iconTopY
+                val iconRight = ticketX + mBitmapSize
+                val iconBottom = iconTopY + mBitmapSize
+
+                // 命中 2.1:点击到图标本体(用圆形或矩形都行,这里圆形更贴合视觉)
+                val iconCx = (iconLeft + iconRight) / 2f
+                val iconCy = (iconTop + iconBottom) / 2f
+                val dx = sx - iconCx
+                val dy = sy - iconCy
+                val r = mBitmapSize / 2f
+                val hitIcon = (dx * dx + dy * dy) <= (r * r)
+
+                if (hitIcon) {
+                    num = i
+                    btnIndex = j
+                    isClickMark = true
+                    isClickIcon = true
+                    break
+                }
+
+                val badgeSize = mBitmapSize * 0.9f
+                val gap = horizontalPadding
+
+                val iconCenterX = iconLeft + mBitmapSize / 2f
+
+                val badgeBottom = iconTop - gap
+                val badgeTop = badgeBottom - badgeSize
+                val badgeLeft = iconCenterX - badgeSize / 2f
+                val badgeRight = iconCenterX + badgeSize / 2f
+
+                val hitBadge =
+                    sx > badgeLeft && sx < badgeRight && sy > badgeTop && sy < badgeBottom
+                if (hitBadge) {
+                    num = i
+                    btnIndex = j
+                    isClickMark = true
+                    isClickIcon = false
+                    break
+                }
+            }
+
+            if (isClickMark) break
+        }
+
+        if (listener != null && isClickMark) {
+            listener!!.markIsClick(num, btnIndex, isClickIcon)
+            mapView.refreshWorld()
+        }
+    }
+
+    override fun draw(
+        canvas: Canvas,
+        currentMatrix: Matrix,
+        currentZoom: Float,
+        currentRotateDegrees: Float
+    ) {
+        this.currentZoom = currentZoom
+        currentDegree = 360 - currentRotateDegrees
+        if (isVisible) {
+            canvas.save()
+            if (pointList.isNotEmpty()) {
+                val viewW = canvas.width.toFloat()
+                val viewH = canvas.height.toFloat()
+                val margin = mBitmapSize * 3f
+                val viewport = RectF(-margin, -margin, viewW + margin, viewH + margin)
+
+                pointList.forEach { point ->
+                    val mark = point.pos
+                    val goal = floatArrayOf(mark.x, mark.y)
+                    currentMatrix.mapPoints(goal)
+                    if (!viewport.contains(goal[0], goal[1])) return@forEach  // ← 屏外跳过
+
+                    // 文字背景
+                    paint.textSize = textSize
+                    val width = paint.measureText(point.name)
+                    val height = paint.fontMetrics.descent - paint.fontMetrics.ascent
+                    paint.color = Color.parseColor("#70b26f")
+                    paint.style = Paint.Style.FILL
+                    paint.strokeWidth = 1.0f
+                    val left = goal[0] - width / 2 - horizontalPadding * 2
+                    val top = goal[1] - height / 2 - horizontalPadding / 2
+                    val right = goal[0] + width / 2 + horizontalPadding * 2
+                    val bottom = goal[1] + height / 2 + horizontalPadding / 2
+                    // 圆角矩形
+                    canvas.drawRoundRect(left, top, right, bottom, 10f, 10f, paint)
+
+                    val cx = right - horizontalPadding / 2
+                    val cy = top + (bottom - top) / 2
+                    paint.color = Color.parseColor("#FFFFFF")
+                    canvas.drawCircle(cx - horizontalPadding, cy, 26f, paint)
+                    paint.color = Color.parseColor("#218BE6")
+                    canvas.drawCircle(cx - horizontalPadding, cy, 22f, paint)
+                    // 设置颜色,准备绘制文字
+                    paint.color = Color.parseColor("#FFFFFF")
+                    // 绘制个数
+                    val numW = paint.measureText("${point.ticketList.size}")
+                    canvas.drawText("${point.ticketList.size}", cx - (numW / 2) - horizontalPadding, goal[1] + height / 2 - paint.fontMetrics.descent, paint)
+                    // 绘制岗位
+                    canvas.drawText(point.name, (goal[0] - width / 2) - horizontalPadding, goal[1] + height / 2 - paint.fontMetrics.descent, paint)
+                }
+            }
+
+            canvas.restore()
+        }
+        if (isFirst) {
+            isFirst = false
+            mapView.postInvalidateDelayed(80)
+        }
+    }
+
+    fun setMarkIsClickListener(listener: MarkIsClickListener?) {
+        this.listener = listener
+    }
+
+    interface MarkIsClickListener {
+        fun markIsClick(index: Int, btnIndex: Int, isClickIcon: Boolean)
+    }
+}

+ 56 - 0
app/src/main/res/layout-land/dialog_tip.xml

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
+    app:cardCornerRadius="@dimen/common_radius">
+
+    <RelativeLayout
+        android:layout_width="@dimen/dialog_tip_width"
+        android:layout_height="@dimen/dialog_tip_height">
+
+        <TextView
+            android:id="@+id/tv_title"
+            style="@style/CommonTextView"
+            android:layout_width="match_parent"
+            android:background="@color/main_color"
+            android:gravity="left"
+            android:paddingVertical="5dp"
+            android:paddingLeft="10dp"
+            android:text="@string/action_confirm" />
+
+        <TextView
+            android:id="@+id/tv_tip"
+            style="@style/CommonTextView"
+            android:layout_centerInParent="true"
+            android:textColor="@color/black"
+            android:textStyle="bold" />
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentBottom="true"
+            android:layout_centerHorizontal="true"
+            android:layout_marginBottom="@dimen/common_spacing"
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/btn_confirm"
+                style="@style/CommonBtnBlue"
+                android:layout_width="80dp"
+                android:layout_height="25dp"
+                android:backgroundTint="#E600AE00"
+                android:text="@string/confirm" />
+
+            <TextView
+                android:id="@+id/btn_cancel"
+                style="@style/CommonBtnBlue"
+                android:layout_width="wrap_content"
+                android:minWidth="80dp"
+                android:layout_height="25dp"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:backgroundTint="#99FF0000"
+                android:text="@string/cancel" />
+        </LinearLayout>
+    </RelativeLayout>
+</androidx.cardview.widget.CardView>

+ 212 - 0
app/src/main/res/layout-land/fragment_job_progress.xml

@@ -0,0 +1,212 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".view.fragment.JobProgressFragment">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/rl_action"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true">
+
+        <LinearLayout
+            android:id="@+id/ll_tip"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:visibility="gone"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toTopOf="parent">
+
+            <ImageView
+                android:layout_width="@dimen/common_icon_size"
+                android:layout_height="@dimen/common_icon_size"
+                android:background="@mipmap/tip" />
+
+            <TextView
+                android:id="@+id/tv_tip"
+                style="@style/CommonTextView"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:text="@string/allocating_worker_tip" />
+        </LinearLayout>
+
+        <com.grkj.iscs_mars.view.widget.CommonBtn
+            android:id="@+id/cb_back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            app:btn_bg="@drawable/common_btn_blue_bg"
+            app:btn_icon="@mipmap/go_back"
+            app:btn_name="@string/back"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toRightOf="parent" />
+
+        <com.grkj.iscs_mars.view.widget.CommonBtn
+            android:id="@+id/cb_action"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="@dimen/common_spacing"
+            android:visibility="gone"
+            app:btn_bg="@drawable/common_btn_red_bg"
+            app:btn_icon="@mipmap/ticket_lock"
+            app:btn_name="@string/go_locking"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toLeftOf="@id/cb_back" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_above="@id/rl_action"
+        android:layout_marginBottom="@dimen/common_spacing"
+        android:background="@drawable/item_rv_technology_sop_bg_normal"
+        android:padding="@dimen/common_spacing">
+
+        <TextView
+            android:id="@+id/tv_title"
+            style="@style/CommonTextView" />
+
+        <LinearLayout
+            android:id="@+id/ll_detail"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_alignParentRight="true"
+            android:gravity="center_vertical"
+            android:orientation="horizontal">
+
+            <ImageView
+                android:id="@+id/iv_worker"
+                android:layout_width="@dimen/common_icon_size_small"
+                android:layout_height="@dimen/common_icon_size_small"
+                android:src="@mipmap/ticket_worker" />
+
+            <TextView
+                android:id="@+id/tv_worker"
+                style="@style/CommonTextView"
+                android:layout_marginLeft="@dimen/common_spacing_small" />
+
+            <ImageView
+                android:id="@+id/iv_lock"
+                android:layout_width="@dimen/common_icon_size_small"
+                android:layout_height="@dimen/common_icon_size_small"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:src="@mipmap/ticket_lock" />
+
+            <TextView
+                android:id="@+id/tv_lock"
+                style="@style/CommonTextView"
+                android:layout_marginLeft="@dimen/common_spacing_small" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_below="@id/tv_title"
+            android:layout_marginTop="@dimen/common_spacing_small"
+            android:orientation="horizontal">
+
+            <LinearLayout
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_marginRight="@dimen/common_spacing"
+                android:layout_weight="1"
+                android:background="@drawable/item_rv_technology_sop_bg_normal"
+                android:clipToOutline="true"
+                android:orientation="vertical">
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:background="#7b88af"
+                    android:orientation="horizontal">
+
+                    <TextView
+                        style="@style/CommonTextView"
+                        android:layout_width="0dp"
+                        android:layout_weight="1"
+                        android:paddingVertical="@dimen/common_spacing_small"
+                        android:text="@string/isolation_point" />
+
+                    <TextView
+                        style="@style/CommonTextView"
+                        android:layout_width="0dp"
+                        android:layout_weight="1"
+                        android:paddingVertical="@dimen/common_spacing_small"
+                        android:text="@string/effect" />
+
+                    <TextView
+                        style="@style/CommonTextView"
+                        android:layout_width="0dp"
+                        android:layout_weight="1"
+                        android:paddingVertical="@dimen/common_spacing_small"
+                        android:text="@string/switch_status" />
+
+                    <TextView
+                        style="@style/CommonTextView"
+                        android:layout_width="0dp"
+                        android:layout_weight="1"
+                        android:paddingVertical="@dimen/common_spacing_small"
+                        android:text="@string/lock_status" />
+                </LinearLayout>
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/rv_point"
+                    style="@style/CommonRecyclerView" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:layout_width="0dp"
+                android:layout_height="match_parent"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:layout_weight="1"
+                android:background="@drawable/item_rv_technology_sop_bg_normal"
+                android:clipToOutline="true"
+                android:orientation="vertical">
+
+                <LinearLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:background="#7b88af"
+                    android:orientation="horizontal">
+
+                    <TextView
+                        style="@style/CommonTextView"
+                        android:layout_width="0dp"
+                        android:layout_weight="1"
+                        android:paddingVertical="@dimen/common_spacing_small"
+                        android:text="@string/colocker" />
+
+                    <TextView
+                        style="@style/CommonTextView"
+                        android:layout_width="0dp"
+                        android:layout_weight="1"
+                        android:paddingVertical="@dimen/common_spacing_small"
+                        android:text="@string/ready_to_colock" />
+
+                    <TextView
+                        style="@style/CommonTextView"
+                        android:layout_width="0dp"
+                        android:layout_weight="1"
+                        android:paddingVertical="@dimen/common_spacing_small"
+                        android:text="@string/colocked" />
+
+                    <TextView
+                        style="@style/CommonTextView"
+                        android:layout_width="0dp"
+                        android:layout_weight="1"
+                        android:paddingVertical="@dimen/common_spacing_small"
+                        android:text="@string/unlocked" />
+                </LinearLayout>
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/rv_colocker"
+                    style="@style/CommonRecyclerView" />
+            </LinearLayout>
+        </LinearLayout>
+    </RelativeLayout>
+</RelativeLayout>

+ 183 - 0
app/src/main/res/layout-land/fragment_step.xml

@@ -0,0 +1,183 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".view.fragment.StepFragment">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/rl_action"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true">
+
+        <LinearLayout
+            android:id="@+id/ll_tip"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:orientation="horizontal"
+            android:gravity="center_vertical"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toTopOf="parent"
+            android:visibility="gone">
+
+            <ImageView
+                android:layout_width="@dimen/common_icon_size"
+                android:layout_height="@dimen/common_icon_size"
+                android:background="@mipmap/tip" />
+
+            <TextView
+                android:id="@+id/tv_tip"
+                style="@style/CommonTextView"
+                android:layout_marginLeft="@dimen/common_spacing" />
+        </LinearLayout>
+
+        <com.grkj.iscs_mars.view.widget.CommonBtn
+            android:id="@+id/cb_back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            app:btn_bg="@drawable/common_btn_blue_bg"
+            app:btn_icon="@mipmap/go_back"
+            app:btn_name="@string/back"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toRightOf="parent" />
+
+        <com.grkj.iscs_mars.view.widget.CommonBtn
+            android:id="@+id/cb_action"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="@dimen/common_spacing"
+            android:visibility="invisible"
+            app:btn_bg="@drawable/common_btn_red_bg"
+            app:btn_icon="@mipmap/stop"
+            app:btn_name="@string/cancel_the_job"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toLeftOf="@id/cb_back" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_above="@id/rl_action"
+        android:layout_marginBottom="@dimen/common_spacing"
+        android:background="@drawable/item_rv_technology_sop_bg_normal"
+        android:padding="5dp">
+
+        <TextView
+            android:id="@+id/tv_title"
+            style="@style/CommonTextView"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <LinearLayout
+            android:id="@+id/ll_detail"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            app:layout_constraintBottom_toBottomOf="@id/tv_title"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="@id/tv_title">
+
+            <ImageView
+                android:id="@+id/iv_worker"
+                android:layout_width="@dimen/common_icon_size_small"
+                android:layout_height="@dimen/common_icon_size_small"
+                android:src="@mipmap/ticket_worker" />
+
+            <TextView
+                android:id="@+id/tv_worker"
+                style="@style/CommonTextView"
+                android:layout_marginLeft="@dimen/common_spacing_small" />
+
+            <ImageView
+                android:id="@+id/iv_lock"
+                android:layout_width="@dimen/common_icon_size_small"
+                android:layout_height="@dimen/common_icon_size_small"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:src="@mipmap/ticket_lock" />
+
+            <TextView
+                android:id="@+id/tv_lock"
+                style="@style/CommonTextView"
+                android:layout_marginLeft="@dimen/common_spacing_small" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/ll_container"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginTop="@dimen/common_spacing_small"
+            android:background="@drawable/item_rv_technology_sop_bg_normal"
+            android:orientation="vertical"
+            android:padding="2dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintHorizontal_weight="300"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toLeftOf="@id/rv_step"
+            app:layout_constraintTop_toBottomOf="@id/tv_title">
+
+            <!-- 工艺图 -->
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:gravity="center_horizontal"
+                android:orientation="vertical">
+
+                <TextView
+                    style="@style/CommonTextView"
+                    android:background="@drawable/common_btn_blue_bg"
+                    android:paddingHorizontal="@dimen/common_spacing_small"
+                    android:paddingVertical="@dimen/common_spacing_smallest"
+                    android:text="@string/machinery_pic" />
+
+                <ImageView
+                    android:id="@+id/iv_machinery"
+                    android:layout_width="80dp"
+                    android:layout_height="80dp"
+                    android:layout_marginTop="@dimen/common_spacing" />
+            </LinearLayout>
+
+            <!-- 锁定站 -->
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:gravity="center_horizontal"
+                android:orientation="vertical">
+
+                <TextView
+                    style="@style/CommonTextView"
+                    android:background="@drawable/common_btn_blue_bg"
+                    android:paddingHorizontal="@dimen/common_spacing_small"
+                    android:paddingVertical="@dimen/common_spacing_smallest"
+                    android:text="@string/lock_station" />
+
+                <com.onlylemi.mapview.library.MapView
+                    android:id="@+id/mapview"
+                    android:layout_width="match_parent"
+                    android:layout_height="match_parent"
+                    android:layout_above="@id/rv_statistics"
+                    android:layout_marginTop="@dimen/common_spacing_small"/>
+            </LinearLayout>
+        </LinearLayout>
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/rv_step"
+            style="@style/CommonRecyclerView"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginLeft="@dimen/common_spacing_small"
+            app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+            app:layout_constraintBottom_toBottomOf="@id/ll_container"
+            app:layout_constraintHorizontal_weight="1150"
+            app:layout_constraintLeft_toRightOf="@id/ll_container"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="@id/ll_container"
+            app:spanCount="4" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</RelativeLayout>

+ 297 - 0
app/src/main/res/layout-land/fragment_worker.xml

@@ -0,0 +1,297 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    tools:context=".view.fragment.WorkerFragment">
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:id="@+id/rl_action"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true">
+
+        <LinearLayout
+            android:id="@+id/ll_tip"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerVertical="true"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toTopOf="parent">
+
+            <ImageView
+                android:layout_width="@dimen/common_icon_size"
+                android:layout_height="@dimen/common_icon_size"
+                android:background="@mipmap/tip" />
+
+            <TextView
+                style="@style/CommonTextView"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:text="@string/allocating_worker_tip" />
+        </LinearLayout>
+
+        <com.grkj.iscs_mars.view.widget.CommonBtn
+            android:id="@+id/cb_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            app:btn_bg="@drawable/common_btn_red_bg"
+            app:btn_icon="@mipmap/cancel"
+            app:btn_name="@string/cancel"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toRightOf="parent" />
+
+        <com.grkj.iscs_mars.view.widget.CommonBtn
+            android:id="@+id/cb_confirm"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginRight="@dimen/common_spacing"
+            android:layout_toLeftOf="@id/cb_cancel"
+            app:btn_bg="@drawable/common_btn_blue_bg"
+            app:btn_icon="@mipmap/confirm"
+            app:btn_name="@string/confirm"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintRight_toLeftOf="@id/cb_cancel" />
+    </androidx.constraintlayout.widget.ConstraintLayout>
+
+    <androidx.constraintlayout.widget.ConstraintLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_above="@id/rl_action"
+        android:layout_marginBottom="@dimen/common_spacing"
+        android:background="@drawable/item_rv_technology_sop_bg_normal"
+        android:orientation="horizontal"
+        android:padding="@dimen/common_spacing">
+
+        <TextView
+            android:id="@+id/tv_title"
+            style="@style/CommonTextView"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintTop_toTopOf="parent" />
+
+        <LinearLayout
+            android:id="@+id/ll_detail"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:gravity="center_vertical"
+            android:orientation="horizontal"
+            app:layout_constraintBottom_toBottomOf="@id/tv_title"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="@id/tv_title">
+
+            <ImageView
+                android:id="@+id/iv_worker"
+                android:layout_width="@dimen/common_icon_size_small"
+                android:layout_height="@dimen/common_icon_size_small"
+                android:src="@mipmap/ticket_worker" />
+
+            <TextView
+                android:id="@+id/tv_worker"
+                style="@style/CommonTextView"
+                android:layout_marginLeft="@dimen/common_spacing_small" />
+
+            <ImageView
+                android:id="@+id/iv_lock"
+                android:layout_width="@dimen/common_icon_size_small"
+                android:layout_height="@dimen/common_icon_size_small"
+                android:layout_marginLeft="@dimen/common_spacing"
+                android:src="@mipmap/ticket_lock" />
+
+            <TextView
+                android:id="@+id/tv_lock"
+                style="@style/CommonTextView"
+                android:layout_marginLeft="@dimen/common_spacing_small" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/ll_selected"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_marginTop="@dimen/common_spacing_small"
+            android:layout_marginRight="@dimen/common_spacing"
+            android:background="@drawable/item_rv_technology_sop_bg_normal"
+            android:gravity="center_horizontal"
+            android:orientation="vertical"
+            android:padding="5dp"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintHorizontal_weight="380"
+            app:layout_constraintLeft_toLeftOf="parent"
+            app:layout_constraintRight_toLeftOf="@id/ll_list"
+            app:layout_constraintTop_toBottomOf="@id/tv_title">
+
+            <!--     上锁人       -->
+            <com.google.android.material.card.MaterialCardView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginBottom="@dimen/common_spacing"
+                app:cardBackgroundColor="@color/common_bg_white_10"
+                app:cardCornerRadius="@dimen/common_radius"
+                app:cardElevation="0dp"
+                app:strokeColor="@color/common_transparent">
+
+                <androidx.constraintlayout.widget.ConstraintLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:padding="2dp">
+
+                    <TextView
+                        android:id="@+id/tv_locker"
+                        style="@style/CommonTextView"
+                        android:paddingHorizontal="5dp"
+                        android:paddingVertical="3dp"
+                        android:text="@string/locker"
+                        android:textSize="@dimen/common_text_size_small"
+                        app:layout_constraintBottom_toBottomOf="parent"
+                        app:layout_constraintLeft_toLeftOf="parent"
+                        app:layout_constraintRight_toLeftOf="@id/tv_locker_select"
+                        app:layout_constraintTop_toTopOf="parent" />
+
+                    <TextView
+                        android:id="@+id/tv_locker_select"
+                        style="@style/CommonTextView"
+                        android:background="@drawable/select_btn_bg"
+                        android:paddingHorizontal="@dimen/common_spacing"
+                        android:paddingVertical="3dp"
+                        android:text="@string/select"
+                        android:textSize="@dimen/common_text_size_small"
+                        app:layout_constraintBottom_toBottomOf="parent"
+                        app:layout_constraintLeft_toRightOf="@id/tv_locker"
+                        app:layout_constraintRight_toRightOf="parent"
+                        app:layout_constraintTop_toTopOf="parent" />
+                </androidx.constraintlayout.widget.ConstraintLayout>
+            </com.google.android.material.card.MaterialCardView>
+
+            <include
+                android:id="@+id/layout_locker"
+                layout="@layout/item_rv_worker" />
+
+            <!--     共锁人       -->
+            <com.google.android.material.card.MaterialCardView
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_marginVertical="@dimen/common_spacing"
+                app:cardBackgroundColor="@color/common_bg_white_10"
+                app:cardCornerRadius="@dimen/common_radius"
+                app:cardElevation="0dp"
+                app:strokeColor="@color/common_transparent">
+
+                <androidx.constraintlayout.widget.ConstraintLayout
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:orientation="horizontal"
+                    android:padding="2dp">
+
+                    <TextView
+                        android:id="@+id/tv_colocker"
+                        style="@style/CommonTextView"
+                        android:paddingHorizontal="5dp"
+                        android:paddingVertical="3dp"
+                        android:text="@string/colocker"
+                        android:textSize="@dimen/common_text_size_small"
+                        app:layout_constraintBottom_toBottomOf="parent"
+                        app:layout_constraintLeft_toLeftOf="parent"
+                        app:layout_constraintRight_toLeftOf="@id/tv_colocker_select"
+                        app:layout_constraintTop_toTopOf="parent" />
+
+                    <TextView
+                        android:id="@+id/tv_colocker_select"
+                        style="@style/CommonTextView"
+                        android:background="@drawable/select_btn_bg"
+                        android:paddingHorizontal="@dimen/common_spacing"
+                        android:paddingVertical="3dp"
+                        android:text="@string/select"
+                        android:textSize="@dimen/common_text_size_small"
+                        app:layout_constraintBottom_toBottomOf="parent"
+                        app:layout_constraintLeft_toRightOf="@id/tv_colocker"
+                        app:layout_constraintRight_toRightOf="parent"
+                        app:layout_constraintTop_toTopOf="parent" />
+                </androidx.constraintlayout.widget.ConstraintLayout>
+            </com.google.android.material.card.MaterialCardView>
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_colocker_selected"
+                style="@style/CommonRecyclerView"
+                app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+                app:spanCount="3" />
+        </LinearLayout>
+
+        <LinearLayout
+            android:id="@+id/ll_list"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:background="@drawable/item_rv_technology_sop_bg_normal"
+            android:orientation="vertical"
+            android:padding="@dimen/common_spacing"
+            app:layout_constraintBottom_toBottomOf="parent"
+            app:layout_constraintHorizontal_weight="1150"
+            app:layout_constraintLeft_toRightOf="@id/ll_selected"
+            app:layout_constraintRight_toRightOf="parent"
+            app:layout_constraintTop_toTopOf="@id/ll_selected">
+
+            <LinearLayout
+                android:id="@+id/ll_locker"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:orientation="vertical">
+
+                <TextView
+                    style="@style/CommonTextView"
+                    android:layout_marginBottom="@dimen/common_spacing_small"
+                    android:text="@string/select_locker" />
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/rv_locker_list"
+                    style="@style/CommonRecyclerView"
+                    android:layout_height="wrap_content"
+                    app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+                    app:spanCount="10" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:id="@+id/ll_colocker_inside"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+                <TextView
+                    style="@style/CommonTextView"
+                    android:layout_marginBottom="@dimen/common_spacing_small"
+                    android:text="@string/select_coloker_mars" />
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/rv_colocker_inside"
+                    style="@style/CommonRecyclerView"
+                    android:layout_height="wrap_content"
+                    app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+                    app:spanCount="10" />
+            </LinearLayout>
+
+            <LinearLayout
+                android:id="@+id/ll_colocker_outside"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:orientation="vertical"
+                android:visibility="gone">
+
+                <TextView
+                    style="@style/CommonTextView"
+                    android:layout_marginVertical="@dimen/common_spacing_small"
+                    android:text="@string/select_coloker_outside" />
+
+                <androidx.recyclerview.widget.RecyclerView
+                    android:id="@+id/rv_colocker_outside"
+                    style="@style/CommonRecyclerView"
+                    android:layout_height="wrap_content"
+                    app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+                    app:spanCount="10" />
+            </LinearLayout>
+        </LinearLayout>
+    </androidx.constraintlayout.widget.ConstraintLayout>
+</RelativeLayout>

+ 22 - 0
app/src/main/res/layout-land/item_rv_worker.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/root"
+    android:layout_width="30dp"
+    android:layout_height="31dp"
+    android:layout_margin="2dp"
+    android:background="@drawable/item_rv_technology_sop_bg_normal"
+    android:gravity="center"
+    android:orientation="vertical">
+
+    <ImageView
+        android:id="@+id/iv_photo"
+        android:layout_width="@dimen/common_icon_size_small"
+        android:layout_height="@dimen/common_icon_size_small"
+        android:background="@drawable/item_rv_worker_bg_selector" />
+
+    <TextView
+        android:id="@+id/tv_name"
+        style="@style/CommonTextView"
+        android:layout_marginTop="3dp"
+        android:textSize="6dp"/>
+</LinearLayout>

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

@@ -33,9 +33,11 @@
     <TextView
         android:id="@+id/tv_common_progress"
         android:layout_width="wrap_content"
+        android:layout_marginTop="5dp"
         android:layout_height="wrap_content"
         android:textColor="@android:color/white"
         android:textSize="20sp"
+        android:gravity="center"
         android:visibility="gone"
         tools:text="副标题"
         tools:visibility="visible" />

+ 100 - 0
app/src/main/res/layout/dialog_locker_select.xml

@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical"
+    app:cardBackgroundColor="#0943B1"
+    app:strokeWidth="0dp">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_margin="20dp"
+        android:gravity="center"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/tv_title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="20dp"
+            android:textColor="@color/white"
+            android:textSize="20sp"
+            tools:text="标题" />
+
+
+        <TextView
+            android:id="@+id/tv_inner"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start"
+            android:layout_marginBottom="10dp"
+            android:text="内部"
+            android:textColor="@color/white"
+            android:textSize="16sp" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/list_1"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:overScrollMode="never"
+            android:scrollbars="none"
+            app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+            app:spanCount="5" />
+
+        <TextView
+            android:id="@+id/tv_out"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start"
+            android:layout_marginTop="20dp"
+            android:layout_marginBottom="10dp"
+            android:text="外部"
+            android:textColor="@color/white"
+            android:textSize="16sp" />
+
+        <androidx.recyclerview.widget.RecyclerView
+            android:id="@+id/list_2"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:overScrollMode="never"
+            android:scrollbars="none"
+            app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+            app:spanCount="5" />
+
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginTop="20dp"
+            android:orientation="horizontal">
+
+            <TextView
+                android:id="@+id/tv_confirm"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="@drawable/common_btn_blue_bg"
+                android:paddingHorizontal="20dp"
+                android:paddingVertical="10dp"
+                android:text="@string/confirm"
+                android:textColor="@color/white"
+                android:textSize="20sp" />
+
+            <TextView
+                android:id="@+id/tv_cancel"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:background="@drawable/common_btn_red_bg"
+                android:paddingHorizontal="20dp"
+                android:paddingVertical="10dp"
+                android:text="@string/cancel"
+                android:textColor="@color/white"
+                android:textSize="20sp" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+</com.google.android.material.card.MaterialCardView>

+ 29 - 19
app/src/main/res/layout/dialog_tip.xml

@@ -3,27 +3,31 @@
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
-    app:cardCornerRadius="@dimen/common_radius">
+    app:cardCornerRadius="20dp">
 
     <RelativeLayout
-        android:layout_width="@dimen/dialog_tip_width"
-        android:layout_height="@dimen/dialog_tip_height">
+        android:layout_width="350dp"
+        android:layout_height="200dp">
 
         <TextView
             android:id="@+id/tv_title"
-            style="@style/CommonTextView"
             android:layout_width="match_parent"
+            android:layout_height="wrap_content"
             android:background="@color/main_color"
-            android:gravity="left"
-            android:paddingVertical="5dp"
-            android:paddingLeft="10dp"
-            android:text="@string/action_confirm" />
+            android:paddingVertical="10dp"
+            android:paddingLeft="15dp"
+            android:text="@string/action_confirm"
+            android:textColor="@color/white"
+            android:textSize="20sp" />
 
         <TextView
             android:id="@+id/tv_tip"
-            style="@style/CommonTextView"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:layout_centerInParent="true"
             android:textColor="@color/black"
+            android:layout_marginHorizontal="20dp"
+            android:textSize="18sp"
             android:textStyle="bold" />
 
         <LinearLayout
@@ -36,21 +40,27 @@
 
             <TextView
                 android:id="@+id/btn_confirm"
-                style="@style/CommonBtnBlue"
-                android:layout_width="80dp"
-                android:layout_height="25dp"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="@drawable/common_btn_blue_bg"
                 android:backgroundTint="#E600AE00"
-                android:text="@string/confirm" />
+                android:paddingHorizontal="20dp"
+                android:paddingVertical="10dp"
+                android:text="@string/confirm"
+                android:textColor="@color/white"
+                android:textSize="20sp" />
 
             <TextView
                 android:id="@+id/btn_cancel"
-                style="@style/CommonBtnBlue"
                 android:layout_width="wrap_content"
-                android:minWidth="80dp"
-                android:layout_height="25dp"
-                android:layout_marginLeft="@dimen/common_spacing"
-                android:backgroundTint="#99FF0000"
-                android:text="@string/cancel" />
+                android:layout_height="wrap_content"
+                android:layout_marginLeft="20dp"
+                android:background="@drawable/common_btn_red_bg"
+                android:paddingHorizontal="20dp"
+                android:paddingVertical="10dp"
+                android:text="@string/cancel"
+                android:textColor="@color/white"
+                android:textSize="20sp" />
         </LinearLayout>
     </RelativeLayout>
 </androidx.cardview.widget.CardView>

+ 334 - 2
app/src/main/res/layout/fragment_job_progress.xml

@@ -4,13 +4,343 @@
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:paddingHorizontal="20dp"
     tools:context=".view.fragment.JobProgressFragment">
 
+    <!--  顶部标题  -->
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/job_header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="20dp"
+        app:cardBackgroundColor="#11000000"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="15dp">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="工作进度"
+                android:textColor="@color/white"
+                android:textSize="20sp" />
+
+        </RelativeLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/job_tab"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/job_header"
+        android:layout_marginBottom="10dp"
+        app:cardBackgroundColor="#11000000"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+
+            <LinearLayout
+                android:id="@+id/ll_lock_info"
+                android:layout_width="0dp"
+                android:layout_height="50dp"
+                android:layout_weight="1"
+                android:background="@color/dialog_card_login_bg"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="20dp">
+
+                <ImageView
+                    android:layout_width="20dp"
+                    android:layout_height="20dp"
+                    android:layout_marginRight="10dp"
+                    android:src="@mipmap/step5"
+                    android:tint="@color/white" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="上锁信息"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+            </LinearLayout>
+
+            <LinearLayout
+                android:id="@+id/ll_together_info"
+                android:layout_width="0dp"
+                android:layout_height="50dp"
+                android:layout_weight="1"
+                android:gravity="center_vertical"
+                android:orientation="horizontal"
+                android:paddingHorizontal="20dp">
+
+                <ImageView
+                    android:layout_width="20dp"
+                    android:layout_height="20dp"
+                    android:layout_marginRight="10dp"
+                    android:src="@mipmap/ticket_worker"
+                    android:tint="@color/white" />
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:text="共锁信息"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+            </LinearLayout>
+
+        </LinearLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/cv_lock_info"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/job_tab"
+        android:layout_marginBottom="80dp"
+        app:cardBackgroundColor="#11000000"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="40dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:id="@+id/tv_position"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:gravity="center"
+                    android:text="隔离点"
+                    android:textStyle="bold"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+                <View
+                    android:layout_width="2dp"
+                    android:layout_height="match_parent"
+                    android:background="#23FFFFFF" />
+
+                <TextView
+                    android:id="@+id/tv_fun"
+                    android:layout_width="0dp"
+                    android:textStyle="bold"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:gravity="center"
+                    android:text="作用"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+                <View
+                    android:layout_width="2dp"
+                    android:layout_height="match_parent"
+                    android:background="#23FFFFFF" />
+
+                <TextView
+                    android:id="@+id/tv_switch_status"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:gravity="center"
+                    android:textStyle="bold"
+                    android:text="开关状态"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+                <View
+                    android:layout_width="2dp"
+                    android:layout_height="match_parent"
+                    android:background="#23FFFFFF" />
+
+                <TextView
+                    android:id="@+id/tv_status"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="2"
+                    android:gravity="center"
+                    android:textStyle="bold"
+                    android:text="上锁状态"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1dp"
+                android:background="#23FFFFFF" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_lock_position_list"
+                style="@style/CommonRecyclerView"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
+        </LinearLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/cv_together_info"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_below="@id/job_tab"
+        android:layout_marginBottom="80dp"
+        android:visibility="gone"
+        app:cardBackgroundColor="#11000000"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="40dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:id="@+id/tv_together_personal"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="2"
+                    android:gravity="center"
+                    android:text="共锁人"
+                    android:textStyle="bold"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+                <View
+                    android:layout_width="2dp"
+                    android:layout_height="match_parent"
+                    android:background="#23FFFFFF" />
+
+                <TextView
+                    android:id="@+id/tv_wait"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:textStyle="bold"
+                    android:gravity="center"
+                    android:text="待共锁"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+                <View
+                    android:layout_width="2dp"
+                    android:layout_height="match_parent"
+                    android:background="#23FFFFFF" />
+
+                <TextView
+                    android:id="@+id/tv_locked"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:gravity="center"
+                    android:textStyle="bold"
+                    android:text="已共锁"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+                <View
+                    android:layout_width="2dp"
+                    android:layout_height="match_parent"
+                    android:background="#23FFFFFF" />
+
+                <TextView
+                    android:id="@+id/tv_unlocked"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:gravity="center"
+                    android:text="已解锁"
+                    android:textStyle="bold"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1dp"
+                android:background="#23FFFFFF" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_together_list"
+                style="@style/CommonRecyclerView"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
+        </LinearLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+
+    <LinearLayout
+        android:id="@+id/fun_btn"
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:layout_alignParentBottom="true"
+        android:gravity="center"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/tv_confirm"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/common_btn_red_bg"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="10dp"
+            android:text="@string/go_locking"
+            android:textColor="@color/white"
+            android:textSize="20sp" />
+
+        <TextView
+            android:id="@+id/tv_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="20dp"
+            android:background="@drawable/common_btn_blue_bg"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="10dp"
+            android:text="@string/back"
+            android:textColor="@color/white"
+            android:textSize="20sp" />
+
+    </LinearLayout>
+
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/rl_action"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true">
+        android:layout_alignParentBottom="true"
+        android:visibility="gone">
 
         <LinearLayout
             android:id="@+id/ll_tip"
@@ -65,7 +395,8 @@
         android:layout_above="@id/rl_action"
         android:layout_marginBottom="@dimen/common_spacing"
         android:background="@drawable/item_rv_technology_sop_bg_normal"
-        android:padding="@dimen/common_spacing">
+        android:padding="@dimen/common_spacing"
+        android:visibility="gone">
 
         <TextView
             android:id="@+id/tv_title"
@@ -209,4 +540,5 @@
             </LinearLayout>
         </LinearLayout>
     </RelativeLayout>
+
 </RelativeLayout>

+ 268 - 8
app/src/main/res/layout/fragment_step.xml

@@ -1,28 +1,287 @@
 <?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingHorizontal="20dp"
     tools:context=".view.fragment.StepFragment">
 
+    <!--  顶部标题  -->
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/step_header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="10dp"
+        app:cardBackgroundColor="#11000000"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="15dp">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="作业执行步骤"
+                android:textColor="@color/white"
+                android:textSize="20sp" />
+
+        </RelativeLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+    <!--  当前作业名称  -->
+    <TextView
+        android:id="@+id/tv_ticket_name"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="10dp"
+        android:layout_marginBottom="10dp"
+        android:textColor="@color/white"
+        android:textSize="18sp" />
+
+    <com.google.android.material.card.MaterialCardView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="20dp"
+        app:cardBackgroundColor="#11000000"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="10dp">
+
+            <LinearLayout
+                android:id="@+id/ll_lock"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center_vertical"
+                android:orientation="horizontal">
+
+                <ImageView
+                    android:layout_width="20dp"
+                    android:layout_height="20dp"
+                    android:layout_marginEnd="10dp"
+                    android:src="@mipmap/step5" />
+
+                <TextView
+                    android:id="@+id/tv_lock_personal"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/white"
+                    android:textSize="18sp"
+                    tools:text="5/0/0 (带上锁/以上锁/已解锁)" />
+
+            </LinearLayout>
+
+            <LinearLayout
+                android:id="@+id/ll_together"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/ll_lock"
+                android:layout_marginTop="8dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal">
+
+                <ImageView
+                    android:layout_width="20dp"
+                    android:layout_height="20dp"
+                    android:layout_marginEnd="10dp"
+                    android:src="@mipmap/ticket_worker"
+                    android:tint="@color/white" />
+
+                <TextView
+                    android:id="@+id/tv_together_personal"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:textColor="@color/white"
+                    android:textSize="18sp"
+                    tools:text="0/0/0 (待共锁/已共锁/已解除共锁)" />
+
+            </LinearLayout>
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentEnd="true"
+                android:layout_centerVertical="true"
+                android:background="@drawable/common_btn_blue_bg"
+                android:paddingHorizontal="20dp"
+                android:paddingVertical="10dp"
+                android:text="详情"
+                android:textColor="@color/white"
+                android:textSize="20sp" />
+
+        </RelativeLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+    <com.google.android.material.card.MaterialCardView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        app:cardBackgroundColor="#11000000"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="50dp"
+                android:gravity="center_vertical"
+                android:orientation="horizontal">
+
+                <TextView
+                    android:id="@+id/tv_step"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="1"
+                    android:gravity="center"
+                    android:text="步骤"
+                    android:textColor="@color/white"
+                    android:textSize="18sp"
+                    android:textStyle="bold" />
+
+                <View
+                    android:layout_width="2dp"
+                    android:layout_height="match_parent"
+                    android:background="#23FFFFFF" />
+
+                <TextView
+                    android:id="@+id/tv_icon"
+                    android:layout_width="60dp"
+                    android:layout_height="wrap_content"
+                    android:gravity="center"
+                    android:text="图标"
+                    android:textColor="@color/white"
+                    android:textSize="18sp"
+                    android:textStyle="bold" />
+
+                <View
+                    android:layout_width="2dp"
+                    android:layout_height="match_parent"
+                    android:background="#23FFFFFF" />
+
+                <TextView
+                    android:id="@+id/tv_step_name"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="4"
+                    android:gravity="center"
+                    android:text="步骤名称"
+                    android:textColor="@color/white"
+                    android:textSize="18sp"
+                    android:textStyle="bold" />
+
+                <View
+                    android:layout_width="2dp"
+                    android:layout_height="match_parent"
+                    android:background="#23FFFFFF" />
+
+                <TextView
+                    android:id="@+id/tv_status"
+                    android:layout_width="0dp"
+                    android:layout_height="wrap_content"
+                    android:layout_weight="2"
+                    android:gravity="center"
+                    android:text="状态"
+                    android:textColor="@color/white"
+                    android:textSize="18sp"
+                    android:textStyle="bold" />
+
+            </LinearLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="1dp"
+                android:background="#23FFFFFF" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/step_list"
+                style="@style/CommonRecyclerView"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+
+        </LinearLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <!--  底部功能按键  -->
+    <LinearLayout
+        android:id="@+id/ll_fun"
+        android:layout_width="wrap_content"
+        android:layout_height="80dp"
+        android:layout_below="@id/sop_info"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        android:layout_gravity="center_horizontal"
+        android:gravity="center_vertical"
+        android:orientation="horizontal">
+
+
+        <TextView
+            android:id="@+id/tv_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/common_btn_red_bg"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="10dp"
+            android:text="@string/cancel_the_job"
+            android:textColor="@color/white"
+            android:textSize="20sp" />
+
+        <TextView
+            android:id="@+id/tv_back"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="20dp"
+            android:background="@drawable/common_btn_bg"
+            android:gravity="center"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="10dp"
+            android:text="@string/back"
+            android:textColor="@color/white"
+            android:textSize="20sp" />
+
+    </LinearLayout>
+
+
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/rl_action"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true">
+        android:layout_alignParentBottom="true"
+        android:visibility="gone">
 
         <LinearLayout
             android:id="@+id/ll_tip"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_centerVertical="true"
-            android:orientation="horizontal"
             android:gravity="center_vertical"
+            android:orientation="horizontal"
+            android:visibility="gone"
             app:layout_constraintBottom_toBottomOf="parent"
             app:layout_constraintLeft_toLeftOf="parent"
-            app:layout_constraintTop_toTopOf="parent"
-            android:visibility="gone">
+            app:layout_constraintTop_toTopOf="parent">
 
             <ImageView
                 android:layout_width="@dimen/common_icon_size"
@@ -64,7 +323,8 @@
         android:layout_above="@id/rl_action"
         android:layout_marginBottom="@dimen/common_spacing"
         android:background="@drawable/item_rv_technology_sop_bg_normal"
-        android:padding="5dp">
+        android:padding="5dp"
+        android:visibility="gone">
 
         <TextView
             android:id="@+id/tv_title"
@@ -162,7 +422,7 @@
                     android:layout_width="match_parent"
                     android:layout_height="match_parent"
                     android:layout_above="@id/rv_statistics"
-                    android:layout_marginTop="@dimen/common_spacing_small"/>
+                    android:layout_marginTop="@dimen/common_spacing_small" />
             </LinearLayout>
         </LinearLayout>
 
@@ -180,4 +440,4 @@
             app:layout_constraintTop_toTopOf="@id/ll_container"
             app:spanCount="4" />
     </androidx.constraintlayout.widget.ConstraintLayout>
-</RelativeLayout>
+</LinearLayout>

+ 22 - 16
app/src/main/res/layout/fragment_technology_sop.xml

@@ -14,7 +14,7 @@
         android:id="@+id/sop_header"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_marginBottom="10dp"
+        android:layout_marginBottom="20dp"
         app:cardBackgroundColor="#11000000"
         app:strokeColor="#23FFFFFF"
         app:strokeWidth="2dp">
@@ -32,7 +32,7 @@
                 android:layout_centerVertical="true"
                 android:text="选择工艺SOP"
                 android:textColor="@color/white"
-                android:textSize="18sp" />
+                android:textSize="20sp" />
 
         </RelativeLayout>
 
@@ -47,12 +47,12 @@
         android:layout_marginBottom="5dp"
         android:text="请选择工艺/设备"
         android:textColor="@color/white"
-        android:textSize="15sp" />
+        android:textSize="18sp" />
 
     <com.google.android.material.card.MaterialCardView
         android:layout_width="match_parent"
         android:layout_height="0dp"
-        android:layout_marginBottom="10dp"
+        android:layout_marginBottom="20dp"
         android:layout_weight="1"
         app:cardBackgroundColor="#11000000"
         app:strokeColor="#23FFFFFF"
@@ -77,7 +77,8 @@
                     android:gravity="center"
                     android:text="岗位"
                     android:textColor="@color/white"
-                    android:textSize="16sp" />
+                    android:textSize="18sp"
+                    android:textStyle="bold" />
 
                 <View
                     android:layout_width="2dp"
@@ -92,7 +93,8 @@
                     android:gravity="center"
                     android:text="⼯艺/设备名称"
                     android:textColor="@color/white"
-                    android:textSize="16sp" />
+                    android:textSize="18sp"
+                    android:textStyle="bold" />
 
             </LinearLayout>
 
@@ -119,7 +121,7 @@
         android:layout_marginBottom="5dp"
         android:text="请选择SOP"
         android:textColor="@color/white"
-        android:textSize="15sp" />
+        android:textSize="18sp" />
 
     <com.google.android.material.card.MaterialCardView
         android:id="@+id/sop_info"
@@ -148,6 +150,7 @@
 
 
             <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/sop_type_list"
                 style="@style/CommonRecyclerView"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
@@ -163,22 +166,24 @@
     <LinearLayout
         android:id="@+id/ll_fun"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
+        android:layout_height="80dp"
         android:layout_below="@id/sop_info"
         android:layout_alignParentBottom="true"
         android:layout_centerHorizontal="true"
         android:layout_marginTop="10dp"
         android:layout_marginBottom="10dp"
+        android:gravity="center_vertical"
         android:orientation="horizontal">
 
         <LinearLayout
             android:id="@+id/tv_start_sop"
             android:layout_width="wrap_content"
-            android:layout_height="45dp"
-            android:background="@drawable/common_btn_bg"
+            android:layout_height="wrap_content"
+            android:background="@drawable/common_btn_green_bg"
             android:gravity="center"
             android:orientation="horizontal"
-            android:paddingHorizontal="10dp">
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="10dp">
 
             <ImageView
                 android:layout_width="28dp"
@@ -192,21 +197,22 @@
                 android:layout_marginLeft="10dp"
                 android:text="@string/start_the_job"
                 android:textColor="@color/white"
-                android:textSize="18sp" />
+                android:textSize="20sp" />
 
         </LinearLayout>
 
         <TextView
             android:id="@+id/tv_back"
             android:layout_width="wrap_content"
-            android:layout_height="45dp"
-            android:layout_marginLeft="10dp"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="20dp"
             android:background="@drawable/common_btn_bg"
             android:gravity="center"
-            android:minWidth="130dp"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="10dp"
             android:text="@string/back"
             android:textColor="@color/white"
-            android:textSize="18sp" />
+            android:textSize="20sp" />
 
     </LinearLayout>
 

+ 184 - 4
app/src/main/res/layout/fragment_worker.xml

@@ -1,16 +1,194 @@
 <?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:paddingHorizontal="20dp"
     tools:context=".view.fragment.WorkerFragment">
 
+    <!--  顶部标题  -->
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/step_header"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginBottom="10dp"
+        app:cardBackgroundColor="#11000000"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <RelativeLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="15dp">
+
+            <TextView
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_centerVertical="true"
+                android:text="确认人员"
+                android:textColor="@color/white"
+                android:textSize="18sp" />
+
+        </RelativeLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+    <com.google.android.material.card.MaterialCardView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        app:cardBackgroundColor="#11000000"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:orientation="vertical">
+
+            <RelativeLayout
+                android:layout_width="match_parent"
+                android:layout_height="60dp"
+                android:paddingHorizontal="20dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
+                    android:text="@string/presentation_person_lock"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+                <TextView
+                    android:id="@+id/tv_lock_select"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentEnd="true"
+                    android:layout_centerVertical="true"
+                    android:background="@drawable/common_btn_blue_bg"
+                    android:paddingHorizontal="20dp"
+                    android:paddingVertical="5dp"
+                    android:text="@string/select"
+                    android:textColor="@color/white"
+                    android:textSize="16sp" />
+
+            </RelativeLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="2dp"
+                android:background="#23FFFFFF" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_lock_personal"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginHorizontal="20dp"
+                android:layout_marginVertical="10dp"
+                android:layout_weight="1"
+                android:overScrollMode="never"
+                android:scrollbars="none"
+                app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+                app:spanCount="5" />
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="2dp"
+                android:background="#23FFFFFF" />
+
+            <RelativeLayout
+                android:layout_width="match_parent"
+                android:layout_height="60dp"
+                android:paddingHorizontal="20dp">
+
+                <TextView
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_centerVertical="true"
+                    android:text="@string/colocker"
+                    android:textColor="@color/white"
+                    android:textSize="18sp" />
+
+                <TextView
+                    android:id="@+id/tv_together_select"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_alignParentEnd="true"
+                    android:layout_centerVertical="true"
+                    android:background="@drawable/common_btn_blue_bg"
+                    android:paddingHorizontal="20dp"
+                    android:paddingVertical="5dp"
+                    android:text="@string/select"
+                    android:textColor="@color/white"
+                    android:textSize="16sp" />
+
+            </RelativeLayout>
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="2dp"
+                android:background="#23FFFFFF" />
+
+            <androidx.recyclerview.widget.RecyclerView
+                android:id="@+id/rv_together_personal"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_gravity="center_horizontal"
+                android:layout_marginHorizontal="20dp"
+                android:layout_marginVertical="10dp"
+                android:layout_weight="1"
+                android:overScrollMode="never"
+                android:scrollbars="none"
+                app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
+                app:spanCount="5" />
+
+        </LinearLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:gravity="center"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/tv_confirm"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/common_btn_blue_bg"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="5dp"
+            android:text="@string/confirm"
+            android:textColor="@color/white"
+            android:textSize="20sp" />
+
+        <TextView
+            android:id="@+id/tv_cancel"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginLeft="20dp"
+            android:background="@drawable/common_btn_red_bg"
+            android:paddingHorizontal="20dp"
+            android:paddingVertical="5dp"
+            android:text="@string/cancel"
+            android:textColor="@color/white"
+            android:textSize="20sp" />
+
+    </LinearLayout>
+
+
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/rl_action"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_alignParentBottom="true">
+        android:layout_alignParentBottom="true"
+        android:visibility="gone">
 
         <LinearLayout
             android:id="@+id/ll_tip"
@@ -64,7 +242,8 @@
         android:layout_marginBottom="@dimen/common_spacing"
         android:background="@drawable/item_rv_technology_sop_bg_normal"
         android:orientation="horizontal"
-        android:padding="@dimen/common_spacing">
+        android:padding="@dimen/common_spacing"
+        android:visibility="gone">
 
         <TextView
             android:id="@+id/tv_title"
@@ -294,4 +473,5 @@
             </LinearLayout>
         </LinearLayout>
     </androidx.constraintlayout.widget.ConstraintLayout>
-</RelativeLayout>
+
+</LinearLayout>

+ 14 - 12
app/src/main/res/layout/fragment_workshop.xml

@@ -30,7 +30,7 @@
                 android:layout_centerVertical="true"
                 android:text="@string/ticket_processing"
                 android:textColor="@color/white"
-                android:textSize="18sp" />
+                android:textSize="20sp" />
 
             <TextView
                 android:layout_width="wrap_content"
@@ -39,10 +39,10 @@
                 android:layout_centerVertical="true"
                 android:background="@drawable/common_btn_bg"
                 android:paddingHorizontal="20dp"
-                android:paddingVertical="5dp"
+                android:paddingVertical="10dp"
                 android:text="创建"
                 android:textColor="@color/white"
-                android:textSize="16sp" />
+                android:textSize="20sp" />
 
         </RelativeLayout>
 
@@ -53,7 +53,7 @@
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_below="@id/job_header"
-        android:layout_marginBottom="10dp"
+        android:layout_marginBottom="20dp"
         app:cardCornerRadius="@dimen/common_radius"
         app:strokeWidth="0dp">
 
@@ -64,13 +64,12 @@
 
     </com.google.android.material.card.MaterialCardView>
 
-
     <com.google.android.material.card.MaterialCardView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_above="@id/rv_statistics"
         android:layout_below="@id/map_root"
-        android:layout_marginBottom="10dp"
+        android:layout_marginBottom="20dp"
         app:cardBackgroundColor="#11000000"
         app:strokeColor="#23FFFFFF"
         app:strokeWidth="2dp">
@@ -82,7 +81,7 @@
 
             <LinearLayout
                 android:layout_width="match_parent"
-                android:layout_height="40dp"
+                android:layout_height="50dp"
                 android:gravity="center_vertical"
                 android:orientation="horizontal">
 
@@ -94,7 +93,8 @@
                     android:gravity="center"
                     android:text="岗位"
                     android:textColor="@color/white"
-                    android:textSize="16sp" />
+                    android:textSize="18sp"
+                    android:textStyle="bold" />
 
                 <View
                     android:layout_width="2dp"
@@ -108,7 +108,8 @@
                     android:gravity="center"
                     android:text="类型"
                     android:textColor="@color/white"
-                    android:textSize="16sp" />
+                    android:textSize="18sp"
+                    android:textStyle="bold" />
 
                 <View
                     android:layout_width="2dp"
@@ -123,14 +124,15 @@
                     android:gravity="center"
                     android:text="作业名称"
                     android:textColor="@color/white"
-                    android:textSize="16sp" />
+                    android:textSize="18sp"
+                    android:textStyle="bold" />
 
             </LinearLayout>
 
             <View
                 android:layout_width="match_parent"
-                android:background="#23FFFFFF"
-                android:layout_height="1dp" />
+                android:layout_height="1dp"
+                android:background="#23FFFFFF" />
 
             <androidx.recyclerview.widget.RecyclerView
                 android:id="@+id/jobs_list"

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

@@ -6,6 +6,7 @@
     android:orientation="vertical">
 
     <LinearLayout
+        android:id="@+id/job_root"
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_weight="1"
@@ -19,7 +20,7 @@
             android:layout_weight="1"
             android:gravity="center"
             android:textColor="@color/white"
-            android:textSize="16sp"
+            android:textSize="18sp"
             tools:text="岗位" />
 
         <View
@@ -48,7 +49,7 @@
             android:gravity="center"
             android:maxLines="1"
             android:textColor="@color/white"
-            android:textSize="16sp"
+            android:textSize="18sp"
             tools:text="工艺名称" />
     </LinearLayout>
 

+ 76 - 0
app/src/main/res/layout/item_rv_point_list.xml

@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="60dp"
+    android:orientation="vertical">
+
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+
+        <TextView
+            android:id="@+id/tv_position"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textColor="@color/white"
+            android:textSize="18sp"
+            tools:text="隔离点" />
+
+        <View
+            android:layout_width="2dp"
+            android:layout_height="match_parent"
+            android:background="#23FFFFFF" />
+
+        <TextView
+            android:id="@+id/tv_func"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textColor="@color/white"
+            android:textSize="18sp"
+            tools:text="作用" />
+
+        <View
+            android:layout_width="2dp"
+            android:layout_height="match_parent"
+            android:background="#23FFFFFF" />
+
+        <TextView
+            android:id="@+id/tv_switch_status"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textColor="@color/white"
+            android:textSize="18sp"
+            tools:text="开关状态" />
+
+        <View
+            android:layout_width="2dp"
+            android:layout_height="match_parent"
+            android:background="#23FFFFFF" />
+
+        <TextView
+            android:id="@+id/tv_lock_status"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="2"
+            android:gravity="center"
+            android:textColor="@color/white"
+            android:textSize="18sp"
+            tools:text="上锁状态" />
+
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="2dp"
+        android:background="#23FFFFFF" />
+
+</LinearLayout>

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

@@ -20,7 +20,7 @@
             android:layout_weight="1"
             android:gravity="center"
             android:textColor="@color/white"
-            android:textSize="16sp"
+            android:textSize="18sp"
             tools:text="岗位" />
 
         <View
@@ -37,7 +37,7 @@
             android:gravity="center"
             android:maxLines="1"
             android:textColor="@color/white"
-            android:textSize="16sp"
+            android:textSize="18sp"
             tools:text="工艺名称" />
     </LinearLayout>
 

+ 44 - 0
app/src/main/res/layout/item_rv_sop_type.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="60dp">
+
+    <com.google.android.material.card.MaterialCardView
+        android:id="@+id/cv_sop_type"
+        android:layout_width="150dp"
+        android:layout_height="50dp"
+        android:layout_centerInParent="true"
+        app:cardBackgroundColor="#11000000"
+        app:cardCornerRadius="5dp"
+        app:strokeColor="#23FFFFFF"
+        app:strokeWidth="2dp">
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:gravity="center_vertical"
+            android:orientation="horizontal">
+
+            <ImageView
+                android:id="@+id/iv_sop_type"
+                android:layout_width="32dp"
+                android:layout_height="32dp"
+                android:layout_marginLeft="20dp" />
+
+            <TextView
+                android:id="@+id/sop_type_name"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_centerInParent="true"
+                android:gravity="center"
+                android:textColor="@color/white"
+                android:textSize="18sp"
+                tools:text="操作类型" />
+
+        </LinearLayout>
+
+    </com.google.android.material.card.MaterialCardView>
+
+</RelativeLayout>

+ 92 - 0
app/src/main/res/layout/item_rv_step_list.xml

@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:id="@+id/root"
+    android:layout_width="match_parent"
+    android:layout_height="60dp"
+    android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1"
+        android:gravity="center_vertical"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/tv_step"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="1"
+            android:gravity="center"
+            android:textColor="@color/white"
+            android:textSize="18sp"
+            tools:text="岗位" />
+
+        <View
+            android:layout_width="2dp"
+            android:layout_height="match_parent"
+            android:background="#23FFFFFF" />
+
+        <ImageView
+            android:id="@+id/iv_icon"
+            android:layout_width="60dp"
+            android:layout_height="60dp"
+            android:padding="15dp" />
+
+        <View
+            android:layout_width="2dp"
+            android:layout_height="match_parent"
+            android:background="#23FFFFFF" />
+
+        <TextView
+            android:id="@+id/tv_step_name"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_weight="4"
+            android:ellipsize="end"
+            android:gravity="center"
+            android:maxLines="1"
+            android:textColor="@color/white"
+            android:textSize="18sp"
+            tools:text="工艺名称" />
+
+        <View
+            android:layout_width="2dp"
+            android:layout_height="match_parent"
+            android:background="#23FFFFFF" />
+
+        <RelativeLayout
+            android:id="@+id/tv_status"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="2"
+            android:gravity="center">
+
+            <TextView
+                android:id="@+id/tv_setting"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:background="@drawable/common_btn_blue_bg"
+                android:paddingHorizontal="10dp"
+                android:paddingVertical="5dp"
+                android:visibility="gone"
+                android:text="去设置"
+                android:textColor="@color/white"
+                android:textSize="18sp" />
+
+            <ImageView
+                android:id="@+id/iv_status"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content" />
+
+        </RelativeLayout>
+
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="2dp"
+        android:background="#23FFFFFF" />
+
+</LinearLayout>

+ 12 - 10
app/src/main/res/layout/item_rv_worker.xml

@@ -1,22 +1,24 @@
 <?xml version="1.0" encoding="utf-8"?>
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/root"
-    android:layout_width="30dp"
-    android:layout_height="31dp"
-    android:layout_margin="2dp"
-    android:background="@drawable/item_rv_technology_sop_bg_normal"
+    android:layout_width="match_parent"
+    android:layout_height="80dp"
+    android:layout_margin="5dp"
     android:gravity="center"
     android:orientation="vertical">
 
     <ImageView
         android:id="@+id/iv_photo"
-        android:layout_width="@dimen/common_icon_size_small"
-        android:layout_height="@dimen/common_icon_size_small"
-        android:background="@drawable/item_rv_worker_bg_selector" />
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+        android:src="@mipmap/worker_selected"
+        android:tint="@color/white" />
 
     <TextView
         android:id="@+id/tv_name"
-        style="@style/CommonTextView"
-        android:layout_marginTop="3dp"
-        android:textSize="6dp"/>
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="6dp"
+        android:textColor="@color/white"
+        android:textSize="16sp" />
 </LinearLayout>

+ 108 - 0
app/src/main/res/layout/item_rv_worker_status_list.xml

@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="60dp"
+    android:orientation="vertical">
+
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+
+        <LinearLayout
+            android:id="@+id/ll_personal"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="2"
+            android:gravity="center">
+
+            <ImageView
+                android:layout_width="24dp"
+                android:layout_height="24dp"
+                android:layout_marginRight="10dp"
+                android:src="@mipmap/worker_selected" />
+
+            <TextView
+                android:id="@+id/tv_personal"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:gravity="center"
+                android:textColor="@color/white"
+                android:textSize="18sp"
+                tools:text="共锁人" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="2dp"
+            android:layout_height="match_parent"
+            android:background="#23FFFFFF" />
+
+        <LinearLayout
+            android:id="@+id/ll_wait_lock"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center">
+
+            <ImageView
+                android:id="@+id/iv_wait_lock"
+                android:layout_width="32dp"
+                android:layout_height="32dp"
+                android:src="@mipmap/ok"
+                android:tint="@color/white" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="2dp"
+            android:layout_height="match_parent"
+            android:background="#23FFFFFF" />
+
+        <LinearLayout
+            android:id="@+id/tv_locked"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center">
+
+            <ImageView
+                android:id="@+id/iv_locked"
+                android:layout_width="32dp"
+                android:layout_height="32dp"
+                android:src="@mipmap/ok"
+                android:tint="@color/white" />
+
+        </LinearLayout>
+
+        <View
+            android:layout_width="2dp"
+            android:layout_height="match_parent"
+            android:background="#23FFFFFF" />
+
+        <LinearLayout
+            android:id="@+id/tv_unlocked"
+            android:layout_width="0dp"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            android:gravity="center">
+
+            <ImageView
+                android:id="@+id/iv_unlocked"
+                android:layout_width="32dp"
+                android:layout_height="32dp"
+                android:src="@mipmap/ok"
+                android:tint="@color/white" />
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <View
+        android:layout_width="match_parent"
+        android:layout_height="2dp"
+        android:background="#23FFFFFF" />
+
+</LinearLayout>

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

@@ -6,6 +6,7 @@
 
     <color name="main_color">#00AAFF</color>
     <color name="main_color_dark">#CC055EB3</color>
+    <color name="common_bg_black_10">#11000000</color>
     <color name="common_transparent">#00000000</color>
     <color name="common_bg_white_10">#1affffff</color>
     <color name="common_bg_white_20">#33ffffff</color>

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

@@ -96,4 +96,6 @@
     <dimen name="device_registration_common_icon_height">49dp</dimen>
     <dimen name="device_registration_common_text_size">12sp</dimen>
     <dimen name="map_title_text_size">30sp</dimen>
+
+    <dimen name="select_locker_list_max_height">100dp</dimen>
 </resources>

+ 2 - 1
app/src/main/res/values/styles.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<resources>
+<resources >
     <style name="CommonTextView">
         <item name="android:layout_width">wrap_content</item>
         <item name="android:layout_height">wrap_content</item>
@@ -59,4 +59,5 @@
         <item name="android:padding">@dimen/common_text_padding</item>
         <item name="android:background">@drawable/white_stroke_bg</item>
     </style>
+
 </resources>