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.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 /** * 常规任务详情视图模型 * * 负责任务详情的查询、子详情加载、图片适配器管理以及任务提交操作。 * 根据任务类型(检测、充电、整备、洗车、维修、保养等)和状态(待处理/已处理) * 动态切换 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 = 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 /** 图片最大选择数量 */ val maxSize = 6 /** 仅查看模式的图片适配器列表 */ val adapters = mutableListOf() /** 仅查看模式的图片事件监听器列表 */ val imageEvents = mutableListOf>() /** 充电任务子详情 */ val chargeModel: MutableLiveData = MutableLiveData() /** 洗车任务子详情 */ val cleanModel: MutableLiveData = MutableLiveData() /** 检测任务子详情 */ val checkModel: MutableLiveData = MutableLiveData() /** 整备任务子详情 */ val maintainModel: MutableLiveData = MutableLiveData() /** 维修任务子详情 */ val repairModel: MutableLiveData = MutableLiveData() //是否已经循环检测车辆位置 var hadLoopRefreshCarLocation = false //车辆位置 val carLocation = MutableLiveData() /** 统一点击事件处理:查看标准说明、提交任务 */ 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 // 开始充电 "4" -> 3 // 车身标识及清洁说明 "6" -> 10 // 保养 "7" -> 8 // 保险 "8" -> 9 //年检 "9" -> 11 // 车辆运营资质 else -> null } type?.let { startActivity( StandardDescriptionActivity::class.java, bundleOf("type" to type) ) } } } R.id.submit -> submit() } } /** * 查询任务详情 * * 根据 [taskId] 拉取主详情,并根据任务状态进一步查询子详情。 */ fun queryDetail() { launchRequest { 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() } } } } } /** * 查询进行中(待处理)任务的子详情 * * 目前仅充电和维修任务有待处理子详情需要单独查询。 */ fun queryDoingTaskStatusByType() { taskDetail.value?.let { launchRequest { when (it.taskTypeId) { "2" -> { // 充电 taskRepository.chargingDetail("$taskId")?.let { chargeModel.postValue(it) } } "5" -> { // 维修 taskRepository.repairDetail("$taskId")?.let { repairModel.postValue(it) } } } } } } /** * 查询已完成任务的子详情 * * 根据任务类型分别查询检测、充电、整备、洗车、维修等子详情数据。 */ fun queryFinishTaskByType() { taskDetail.value?.let { launchRequest { when (it.taskTypeId) { "1" -> { // 检测 taskRepository.detectionDetail("$taskId")?.let { 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) } } } } } } /** * 根据任务类型执行对应的提交操作 * * 检测、充电、整备、维修等任务跳转对应页面; * 洗车任务直接提交; * 保养/年检/保险/资质到期调用统一保存接口。 */ private fun submit() { taskDetail.value?.let { when (it.taskTypeId) { "1" -> { // 车辆检测 startActivity( CheckCarActivity::class.java, 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" -> { // 完成保养 完成续保 完成年检 车辆运营资质到期 saveBy() } } } } /** * 提交洗车任务 * * 校验图片非空后上传图片,随后调用洗车完成接口。 */ private fun cleanCar() { if (adapterCanEdit.data.isEmpty()) { ToastUtilCommon.showError("请先上传车身清洁照片") return } val files = mutableListOf() files.addAll(adapterCanEdit.data) showDialog("上传中...") uploadFile(files) { dismissDialog() val map = mapOf( "operationsUserId" to user?.id, "vehicleId" to taskDetail.value?.vehicleId, "taskImage" to "${files.map { it.url }}", "taskId" to taskDetail.value?.id ) launchRequest(tips = "提交中...") { workRepository.cleanCar(map) ToastUtilCommon.showSuc("提交成功") queryDetail() } } } /** * 提交保养/保险/年检任务 * * 校验说明文字与图片非空后上传图片,随后调用统一保存接口。 */ private fun saveBy() { if (taskDescription.value.isNullOrEmpty()) { ToastUtilCommon.showError("请录入完成任务情况说明") return } if (adapterCanEdit.data.isEmpty()) { ToastUtilCommon.showError("请先上传完成任务情况图片") return } val files = mutableListOf() files.addAll(adapterCanEdit.data) showDialog("上传中...") uploadFile(files) { dismissDialog() val map = mapOf( "taskDescription" to taskDescription.value, "taskImage" to GsonUtils.toJson(files.map { it.url }), "id" to taskDetail.value?.id ) launchRequest(tips = "提交中...") { taskRepository.saveRoutineDetail(map) ToastUtilCommon.showSuc("提交成功") queryDetail() } } } /** * 递归上传文件 * * 遍历待上传文件列表,对未上传(url 为空)的文件逐个上传到服务器, * 全部上传完成后执行成功回调。 * * @param files 待上传的文件列表 * @param succ 全部上传成功后的回调 */ private fun uploadFile(files: List, succ: () -> Unit) { val result = files.find { it.url.isEmpty() } if (result == null) { succ() } else { launchRequest(showLoading = false, error = { _, errMsg -> ToastUtilCommon.showError(errMsg) dismissDialog() }) { val file = File(result.localPath) val fileRequestBody = file.asRequestBody("image/jpg".toMediaType()) val mBuilder = MultipartBody.Builder() mBuilder.addFormDataPart("file", file.name, fileRequestBody) mBuilder.setType(MultipartBody.FORM) val data = commonRepository.uploadFile(mBuilder.build()) result.url = GsonUtils.toJson(data) uploadFile(files, succ) } } } //显示改派弹窗 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) } } } } } } }