puzhibing
2026-08-21 5fa94b3718b4a78a4fcea4c97652b0ef20b7de3a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
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<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()
 
    //是否已经循环检测车辆位置
    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 // 开始充电
                        "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<FileSelectBean>()
        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<FileSelectBean>()
        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<FileSelectBean>, 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)
                        }
                    }
                }
            }
        }
    }
}