puzhibing
2026-08-21 5fa94b3718b4a78a4fcea4c97652b0ef20b7de3a
app/src/main/java/com/xw/yunwei/ui/task/normal/NormalTaskDetailVM.kt
@@ -1,87 +1,150 @@
package com.xw.yunwei.ui.task.normal
import android.app.Application
import android.content.Context
import android.util.Log
import android.view.View
import androidx.core.os.bundleOf
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.map
import androidx.lifecycle.viewModelScope
import com.amap.api.location.AMapLocation
import com.blankj.utilcode.util.GsonUtils
import com.xw.common.base.BaseViewModel
import com.xw.common.base.FileSelectBean
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.utils.LogUtils
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.Constants
import com.xw.yunwei.Constants.user
import com.xw.yunwei.R
import com.xw.yunwei.model.SwitchTabMain
import com.xw.yunwei.model.SwitchTabTask
import com.xw.yunwei.model.TaskNormalChargeModel
import com.xw.yunwei.model.TaskNormalCheckModel
import com.xw.yunwei.model.TaskNormalCleanModel
import com.xw.yunwei.model.TaskNormalMaintainModel
import com.xw.yunwei.model.TaskNormalModel
import com.xw.yunwei.model.TaskNormalRepairModel
import com.xw.yunwei.model.VehicleLocationInfo
import com.xw.yunwei.net.CommonRepository
import com.xw.yunwei.net.TaskRepository
import com.xw.yunwei.net.WorkRepository
import com.xw.yunwei.net.CommonRepository
import com.xw.yunwei.ui.dialog.ApplyForReassignReasonDialog
import com.xw.yunwei.ui.work.car.detail.StandardDescriptionActivity
import com.xw.yunwei.ui.work.car.detail.operations.charge.ChargeCarActivity
import com.xw.yunwei.ui.work.car.detail.operations.check.CheckCarActivity
import com.xw.yunwei.ui.work.car.detail.operations.maintain.MaintainCarActivity
import com.xw.yunwei.ui.work.car.detail.operations.repair.RepairCarActivity
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import org.greenrobot.eventbus.EventBus
import org.koin.core.component.inject
import java.io.File
import kotlin.getValue
/**
 * 常规任务详情视图模型
 *
 * 负责任务详情的查询、子详情加载、图片适配器管理以及任务提交操作。
 * 根据任务类型(检测、充电、整备、洗车、维修、保养等)和状态(待处理/已处理)
 * 动态切换 UI 状态并处理对应的业务逻辑。
 */
class NormalTaskDetailVM(application: Application) : BaseViewModel(application) {
    /** 任务数据仓库 */
    val taskRepository: TaskRepository by inject()
    /** 工作台数据仓库 */
    val workRepository: WorkRepository by inject()
    /** 通用数据仓库(如文件上传) */
    val commonRepository: CommonRepository by inject()
    /** 当前定位信息 */
    var location: AMapLocation? = null
    /** 当前任务 ID */
    var taskId = 0L
    val taskDetail: MutableLiveData<TaskNormalModel> = MutableLiveData()
    val title = taskDetail.map {
        if(it.status == 1) "待处理" else if(it.status == 2) "已处理" else ""
    }
    val levelId = taskDetail.map {
       when(it.taskUrgencyLevel){
           0 -> R.mipmap.ic_accident_one
           1 -> R.mipmap.ic_accident_two
           2 -> R.mipmap.ic_accident_three
           3 -> R.mipmap.ic_accident_four
           else -> R.mipmap.ic_accident_one
       }
    }
    val btnDoingAction = MutableLiveData("")
    val showDoingBtn = MutableLiveData(true) // 显示按钮
    val showDoingSlide = MutableLiveData(false) // 显示滑块
    val isRepair = MutableLiveData(false) // 是否已送修
    val taskDescription = MutableLiveData("") // 完成任务情况
    /*可编辑*/
    lateinit var adapterCanEdit: ImageSelectAdapter // 只有洗车和(保养/年检/保险)
    /** 任务主详情数据 */
    val taskDetail: MutableLiveData<TaskNormalModel> = MutableLiveData()
    /** 页面标题:根据任务状态映射为"待处理"或"已处理" */
    val title = taskDetail.map {
        if (it.status == 1) "待处理" else if (it.status == 2) "已处理" else ""
    }
    /** 紧急程度图标资源 ID */
    val levelId = taskDetail.map {
        when (it.taskUrgencyLevel) {
            0 -> R.mipmap.ic_accident_one
            1 -> R.mipmap.ic_accident_two
            2 -> R.mipmap.ic_accident_three
            3 -> R.mipmap.ic_accident_four
            else -> R.mipmap.ic_accident_one
        }
    }
    /** 待处理状态下操作按钮的文案 */
    val btnDoingAction = MutableLiveData("")
    /** 是否显示操作按钮 */
    val showDoingBtn = MutableLiveData(true)
    /** 是否显示滑动完成控件(用于充电任务结束充电) */
    val showDoingSlide = MutableLiveData(false)
    /** 维修任务是否已送修 */
    val isRepair = MutableLiveData(false)
    /** 完成任务情况说明(用于保养/年检/保险等) */
    val taskDescription = MutableLiveData("")
    /** 可编辑图片适配器,仅用于洗车和保养/年检/保险等需要上传图片的任务 */
    lateinit var adapterCanEdit: ImageSelectAdapter
    /** 可编辑图片的事件监听器 */
    lateinit var imageEventCanEdit: ImageEventListener<FileSelectBean>
    /** 图片最大选择数量 */
    val maxSize = 6
    /*仅查看*/
    /** 仅查看模式的图片适配器列表 */
    val adapters = mutableListOf<ImageSelectAdapter>()
    /** 仅查看模式的图片事件监听器列表 */
    val imageEvents = mutableListOf<ImageEventListener<FileSelectBean>>()
    val chargeModel: MutableLiveData<TaskNormalChargeModel> = MutableLiveData() // 充电
    val cleanModel: MutableLiveData<TaskNormalCleanModel> = MutableLiveData() // 洗车
    val checkModel: MutableLiveData<TaskNormalCheckModel> = MutableLiveData() // 检测
    val maintainModel: MutableLiveData<TaskNormalMaintainModel> = MutableLiveData() // 整备
    val repairModel: MutableLiveData<TaskNormalRepairModel> = MutableLiveData() // 维修
    /** 充电任务子详情 */
    val chargeModel: MutableLiveData<TaskNormalChargeModel> = MutableLiveData()
    /** 洗车任务子详情 */
    val cleanModel: MutableLiveData<TaskNormalCleanModel> = MutableLiveData()
    /** 检测任务子详情 */
    val checkModel: MutableLiveData<TaskNormalCheckModel> = MutableLiveData()
    /** 整备任务子详情 */
    val maintainModel: MutableLiveData<TaskNormalMaintainModel> = MutableLiveData()
    /** 维修任务子详情 */
    val repairModel: MutableLiveData<TaskNormalRepairModel> = MutableLiveData()
    //是否已经循环检测车辆位置
    var hadLoopRefreshCarLocation = false
    //车辆位置
    val carLocation = MutableLiveData<VehicleLocationInfo>()
    /** 统一点击事件处理:查看标准说明、提交任务 */
    val onClick = View.OnClickListener {
        when (it.id) {
            R.id.viewDetail, R.id.viewDetail1 -> {
                taskDetail.value?.let {
                    // 根据任务类型跳转到对应标准说明页面
                    val type = when (it.taskTypeId) {
                        "1" -> 7 // 车辆检测
                        "2" -> 6 // 开始充电
@@ -105,16 +168,30 @@
        }
    }
    /**
     * 查询任务详情
     *
     * 根据 [taskId] 拉取主详情,并根据任务状态进一步查询子详情。
     */
    fun queryDetail() {
        launchRequest {
            Log.e(TAG, "queryDetail: $taskId", )
            Log.e(TAG, "queryDetail: $taskId")
            taskRepository.vehicleRoutineDetail("$taskId")?.let {
                runOnMainThread {
                    // 当首次加载或任务状态发生变化时更新主详情
                    if (taskDetail.value == null || taskDetail.value!!.status != it.status) {
                        taskDetail.value = it
                    }
                    if (it.status == 1) { // 待处理
                        queryDoingTaskStatusByType()
                        carLocation.postValue(
                            VehicleLocationInfo(
                                it.vehicleLon?.toString(),
                                it.vehicleLat?.toString(),
                                it.vehicleLocation
                            )
                        )
                        loopRefreshCarLocation()
                    } else if (it.status == 2) { // 已处理
                        queryFinishTaskByType()
                    }
@@ -123,7 +200,11 @@
        }
    }
    /*查询进行中任务状态*/
    /**
     * 查询进行中(待处理)任务的子详情
     *
     * 目前仅充电和维修任务有待处理子详情需要单独查询。
     */
    fun queryDoingTaskStatusByType() {
        taskDetail.value?.let {
            launchRequest {
@@ -145,7 +226,11 @@
        }
    }
    /*查询已完成任务的具体子详情*/
    /**
     * 查询已完成任务的子详情
     *
     * 根据任务类型分别查询检测、充电、整备、洗车、维修等子详情数据。
     */
    fun queryFinishTaskByType() {
        taskDetail.value?.let {
            launchRequest {
@@ -155,21 +240,25 @@
                            checkModel.postValue(it)
                        }
                    }
                    "2" -> { // 充电
                        taskRepository.chargingDetail("$taskId")?.let {
                            chargeModel.postValue(it)
                        }
                    }
                    "3" -> { // 整备
                        taskRepository.preparationDetail("$taskId")?.let {
                            maintainModel.postValue(it)
                        }
                    }
                    "4" -> { // 洗车
                        taskRepository.cleanDetail("$taskId")?.let {
                            cleanModel.postValue(it)
                        }
                    }
                    "5" -> { // 维修
                        taskRepository.repairDetail("$taskId")?.let {
                            repairModel.postValue(it)
@@ -180,7 +269,14 @@
        }
    }
    private fun submit(){
    /**
     * 根据任务类型执行对应的提交操作
     *
     * 检测、充电、整备、维修等任务跳转对应页面;
     * 洗车任务直接提交;
     * 保养/年检/保险/资质到期调用统一保存接口。
     */
    private fun submit() {
        taskDetail.value?.let {
            when (it.taskTypeId) {
                "1" -> { // 车辆检测
@@ -189,34 +285,44 @@
                        bundleOf("carId" to (it.vehicleId ?: 0L), "taskId" to (it.id ?: 0L))
                    )
                }
                "2" -> { // 开始充电
                    startActivity(
                        ChargeCarActivity::class.java,
                        bundleOf("carId" to (it.vehicleId ?: 0L), "taskId" to (it.id ?: 0L))
                    )
                }
                "3" -> { // 开始整备
                    startActivity(
                        MaintainCarActivity::class.java,
                        bundleOf("carId" to (it.vehicleId ?: 0L), "taskId" to (it.id ?: 0L))
                    )
                }
                "4" -> { // 完成洗车任务
                    cleanCar()
                }
                "5" -> { // 去送修/取回
                    startActivity(
                        RepairCarActivity::class.java,
                        bundleOf("carId" to (it.vehicleId ?: 0L), "taskId" to (it.id ?: 0L))
                    )
                }
                "6","7","8","9" -> { // 完成保养 完成续保 完成年检 车辆运营资质到期
                "6", "7", "8", "9" -> { // 完成保养 完成续保 完成年检 车辆运营资质到期
                    saveBy()
                }
            }
        }
    }
    /**
     * 提交洗车任务
     *
     * 校验图片非空后上传图片,随后调用洗车完成接口。
     */
    private fun cleanCar() {
        if (adapterCanEdit.data.isEmpty()) {
            ToastUtilCommon.showError("请先上传车身清洁照片")
@@ -233,7 +339,7 @@
            val map = mapOf(
                "operationsUserId" to user?.id,
                "vehicleId" to taskDetail.value?.vehicleId,
                "taskImage" to GsonUtils.toJson(files.map { it.url }),
                "taskImage" to "${files.map { it.url }}",
                "taskId" to taskDetail.value?.id
            )
            launchRequest(tips = "提交中...") {
@@ -244,8 +350,12 @@
        }
    }
    /*完成保养/保险/年检*/
    private fun saveBy(){
    /**
     * 提交保养/保险/年检任务
     *
     * 校验说明文字与图片非空后上传图片,随后调用统一保存接口。
     */
    private fun saveBy() {
        if (taskDescription.value.isNullOrEmpty()) {
            ToastUtilCommon.showError("请录入完成任务情况说明")
            return
@@ -275,6 +385,15 @@
        }
    }
    /**
     * 递归上传文件
     *
     * 遍历待上传文件列表,对未上传(url 为空)的文件逐个上传到服务器,
     * 全部上传完成后执行成功回调。
     *
     * @param files 待上传的文件列表
     * @param succ 全部上传成功后的回调
     */
    private fun uploadFile(files: List<FileSelectBean>, succ: () -> Unit) {
        val result = files.find { it.url.isEmpty() }
        if (result == null) {
@@ -295,4 +414,73 @@
            }
        }
    }
    //显示改派弹窗
    fun showApplyForReassignDialog(context: Context) {
        if (taskDetail.value == null) {
            return
        }
        ApplyForReassignReasonDialog.show(
            context,
            Constants.reasons,
        ) { position, input, dialog ->
            showDialog(content = "改派中...")
            launchRequest(showLoading = false, error = { code, msg ->
                dismissDialog()
                ToastUtilCommon.showError(msg)
                LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
            }) {
                val comment = Constants.reasons[position]
                taskRepository.taskReassignment(comment, input, taskId.toString()).also {
                    dialog.dismiss()
                    checkApplyForReassignResult()
                }
            }
        }
    }
    //检测申请改派结果
    private fun checkApplyForReassignResult() {
        launchRequest(showLoading = false, error = { code, msg ->
            dismissDialog()
            ToastUtilCommon.showError(msg)
            LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
        }) {
            delay(3 * 1000)
            val isOk = taskRepository.checkApplyForReassignResult(taskId.toString())
            dismissDialog()
            isOk?.also {
                if (it) ToastUtilCommon.showSuc("改派成功") else ToastUtilCommon.showError("暂未找到运维人员")
                EventBus.getDefault().post(SwitchTabMain(1))
                if (!it) {
                    EventBus.getDefault().post(SwitchTabTask(4))
                }
            }
            delay(1000)
            finish()
        }
    }
    //循环刷新车辆位置
    private fun loopRefreshCarLocation() {
        if (hadLoopRefreshCarLocation) {
            return
        }
        hadLoopRefreshCarLocation = true
        viewModelScope.launch {
            while (true) {
                delay(60 * 1000)
                launchRequest(showLoading = false, error = { code, msg ->
                    LogUtils.e(TAG, "launchRequest: code = $code msg = $msg")
                }) {
                    taskDetail.value?.also { it ->
                        taskRepository.queryVehicleNewPoint(it.vehicleId?.toString())?.also {
                            carLocation.postValue(it)
                        }
                    }
                }
            }
        }
    }
}