18034727885
2026-06-22 a6481ef2ed0431bf6e222dff549a74862bcfb528
修复问题
4个文件已修改
278 ■■■■■ 已修改文件
app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailVM.kt 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessActivity.kt 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessVM.kt 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/res/layout/activity_accident_process.xml 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/xw/yunwei/ui/task/accident/detail/AccidentDetailVM.kt
@@ -226,7 +226,7 @@
            1 -> {
                startActivity(
                    AccidentProcessActivity::class.java,
                    bundleOf("taskId" to taskDetail.value?.id)
                    AccidentProcessActivity.getParams(taskDetail.value)
                )
            }
        }
app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessActivity.kt
@@ -2,7 +2,17 @@
import android.annotation.SuppressLint
import android.net.Uri
import android.os.Bundle
import android.view.Gravity
import android.view.ViewGroup
import android.view.WindowManager
import androidx.core.os.bundleOf
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.customview.customView
import com.afollestad.materialdialogs.customview.getCustomView
import com.blankj.utilcode.util.UriUtils
import com.luck.picture.lib.config.PictureMimeType
import com.luck.picture.lib.entity.LocalMedia
@@ -13,9 +23,16 @@
import com.xw.common.base.ImageEventListener
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.base.ShowImgListDialog
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.BR
import com.xw.yunwei.BaseBusinessActivity
import com.xw.yunwei.constants.Key
import com.xw.yunwei.databinding.ActivityAccidentProcessBinding
import com.xw.yunwei.databinding.DialogAccidentFilterBinding
import com.xw.yunwei.model.TaskAccidentModel
import com.xw.yunwei.ui.task.create.LeftCategoryAdapter
import com.xw.yunwei.ui.task.create.RightItemAdapter
import com.xw.yunwei.utils.DialogFactory
import com.xw.yunwei.utils.PictureSelectorFactory
/**
@@ -29,13 +46,34 @@
 *
 * 图片支持拍照和从图库选择两种方式,提交时先上传图片再调用接口。
 */
class AccidentProcessActivity : BaseBusinessActivity<ActivityAccidentProcessBinding, AccidentProcessVM>(){
class AccidentProcessActivity :
    BaseBusinessActivity<ActivityAccidentProcessBinding, AccidentProcessVM>() {
    /** 事故类型筛选弹窗 */
    private var filterDialog: MaterialDialog? = null
    /** 左侧事故大类 Adapter */
    private lateinit var leftAdapter: LeftCategoryAdapter
    /** 右侧事故子类 Adapter */
    private lateinit var rightAdapter: RightItemAdapter
    companion object {
        //获取跳转该页面参数
        fun getParams(model: TaskAccidentModel?): Bundle {
            return bundleOf(
                Key.ID to model?.id,
                Key.DATA to model?.taskTypeId
            )
        }
    }
    override fun getBindingVariable() = BR.viewModel
    override fun init() {
        super.init()
        // 从Intent获取任务ID并保存到ViewModel
        viewModel.taskId = intent.getLongExtra("taskId", 0L)
        viewModel.taskId = intent.getLongExtra(Key.ID, 0L)
        viewModel.taskTypeId = intent.getStringExtra(Key.DATA)
        initAdapter()
        // 移除默认选中状态,由用户手动选择责任判定
        binding.stllZrpd.remove()
@@ -46,10 +84,20 @@
            resources.getColor(R.color.white),
            "shape_blue_5_bg_4"
        )
        viewModel.getTypeList{
            binding.tvAccidentFilter.text =
                if (viewModel.getSelectType().isEmpty()) "" else "选好了"
        }
    }
    override fun setListener() {
        super.setListener()
        // 点击事故类型筛选按钮,先拉取类型列表再弹窗
        binding.tvAccidentFilter.setOnClickListener {
            viewModel.getTypeList {
                showFilterDialog()
            }
        }
        // 责任判定标签点击监听:单选逻辑,先取消全部选中,再选中当前点击项
        binding.stllZrpd.setListener {
            for (index in binding.stllZrpd.selectIndexList) { // 先取消选中状态
@@ -67,7 +115,7 @@
     * 分别绑定到 rv1(交警判责照片)、rv2(现场情况照片)、rv3(处置情况照片),
     * 每组最多上传 [AccidentProcessVM.maxSizes] 张图片。
     */
    private fun initAdapter(){
    private fun initAdapter() {
        viewModel.adapters.clear()
        viewModel.imageEvents.clear()
        for (index in 0 until 3) {
@@ -138,7 +186,7 @@
     */
    // 拍照
    private fun takeAPhotograph() {
        PictureSelectorFactory.takeAPhotograph(this,resultCallbackListener)
        PictureSelectorFactory.takeAPhotograph(this, resultCallbackListener)
    }
    /**
@@ -154,17 +202,112 @@
                dataList.addAll(viewModel.adapters[viewModel.operateIndex].data)
                for (item in selectList) {
                    val path: String = item.availablePath
                    var imgPath = if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
                        UriUtils.uri2File(Uri.parse(path)).absolutePath
                    } else {
                        path
                    }
                    var imgPath =
                        if (PictureMimeType.isContent(path) && !item.isCut && !item.isCompressed) {
                            UriUtils.uri2File(Uri.parse(path)).absolutePath
                        } else {
                            path
                        }
                    dataList.add(FileSelectBean(localPath = imgPath, type = "img"))
                }
                viewModel.adapters[viewModel.operateIndex].setList(dataList)
            }
        }
        override fun onCancel() {}
    }
    /**
     * 显示事故类型筛选弹窗(底部 BottomSheet 样式)
     *
     * 左侧显示事故大类,右侧显示对应子类,支持多选。
     * 弹窗 dismiss 时更新筛选按钮文案。
     */
    private fun showFilterDialog() {
        if (filterDialog == null) {
            filterDialog = DialogFactory.produce(this).apply {
                customView(
                    com.xw.yunwei.R.layout.dialog_accident_filter,
                    noVerticalPadding = true,
                    horizontalPadding = false
                )
                cancelable(true)
                cornerRadius(12f)
                val bind: DialogAccidentFilterBinding? = DataBindingUtil.bind(getCustomView())
                bind?.let {
                    setupRecyclerViews(it)
                    // 取消按钮:清空所有选中状态并重置到第一项
                    it.cancel.setOnClickListener {
                        viewModel.categories.forEach {
                            it.items.forEach {
                                it.isSelected = false
                            }
                        }
                        leftAdapter.selectedPosition = 0
                        rightAdapter.updateData(viewModel.categories[0].items)
                        dismiss()
                    }
                    // 左侧按钮:仅重置选中状态,不关闭弹窗
                    it.btnLeft.setOnClickListener {
                        viewModel.categories.forEach {
                            it.items.forEach {
                                it.isSelected = false
                            }
                        }
                        leftAdapter.selectedPosition = 0
                        rightAdapter.updateData(viewModel.categories[0].items)
                    }
                    // 右侧按钮:确认选择并关闭弹窗
                    it.btnRight.setOnClickListener {
                        if (viewModel.getSelectType().isEmpty()) {
                            ToastUtilCommon.showWarn("还未选择事故类型")
                            return@setOnClickListener
                        }
                        dismiss()
                    }
                    // 确定按钮:确认选择并关闭弹窗
                    it.sure.setOnClickListener {
                        if (viewModel.getSelectType().isEmpty()) {
                            ToastUtilCommon.showWarn("还未选择事故类型")
                            return@setOnClickListener
                        }
                        dismiss()
                    }
                }
            }
            // 弹窗关闭时更新筛选按钮文案(已选则显示"选好了")
            filterDialog!!.setOnDismissListener {
                binding.tvAccidentFilter.text =
                    if (viewModel.getSelectType().isEmpty()) "" else "选好了"
            }
        }
        filterDialog?.show()
        // 关键:让软键盘把 BottomSheet 顶上去
        filterDialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
        filterDialog?.window?.setLayout(
            ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT
        )
        filterDialog?.window?.setGravity(Gravity.BOTTOM)
        filterDialog?.window?.setWindowAnimations(R.style.AnimUp)
    }
    /**
     * 初始化事故类型筛选弹窗中的左右 RecyclerView
     *
     * @param bind 弹窗视图绑定对象
     */
    private fun setupRecyclerViews(bind: DialogAccidentFilterBinding) {
        bind.leftRecyclerView.layoutManager = LinearLayoutManager(this)
        leftAdapter = LeftCategoryAdapter(viewModel.categories) { category, position ->
            rightAdapter.updateData(category.items)
        }
        bind.leftRecyclerView.adapter = leftAdapter
        bind.rightRecyclerView.layoutManager = LinearLayoutManager(this)
        rightAdapter = RightItemAdapter(viewModel.categories[0].items)
        bind.rightRecyclerView.adapter = rightAdapter
    }
}
app/src/main/java/com/xw/yunwei/ui/task/accident/handle/AccidentProcessVM.kt
@@ -11,16 +11,16 @@
import com.xw.common.base.ImageSelectAdapter
import com.xw.common.utils.ToastUtilCommon
import com.xw.yunwei.R
import com.xw.yunwei.model.Category
import com.xw.yunwei.model.Item
import com.xw.yunwei.net.CommonRepository
import com.xw.yunwei.net.TaskRepository
import com.xw.yunwei.ui.MainActivity
import kotlinx.coroutines.delay
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import org.koin.core.component.inject
import java.io.File
import kotlin.getValue
/**
@@ -40,35 +40,55 @@
    /** 当前任务ID */
    var taskId = 0L
    /**
     * 任务类型ID
     * 任务类别为2时:对应数据字典,多个逗号分割
     * 任务类别为1时:枚举值 1-9
     */
    var taskTypeId: String? = null
    /** 死亡人数 LiveData,默认 0 */
    val death = MutableLiveData("0")
    /** 重伤人数 LiveData,默认 0 */
    val badlyHurt = MutableLiveData("0")
    /** 轻伤人数 LiveData,默认 0 */
    val minorInjuries = MutableLiveData("0")
    /** 现场情况描述 LiveData */
    val siteDesc = MutableLiveData("")
    /** 处置情况描述 LiveData */
    val disposalDesc = MutableLiveData("")
    /** 现场情况当前字数 / 200 */
    val siteNums = siteDesc.map { "${it.length}/200" }
    /** 处置情况当前字数 / 200 */
    val disposalNums = disposalDesc.map { "${it.length}/200" }
    /** 责任判定选项列表 */
    val dataZrpd = listOf("我方主责", "我方无责", "双方同责")
    /** 当前选中的责任判定 */
    var selectZrpd = ""
    /** 三组图片选择适配器(对应交警判责、现场情况、处置情况) */
    val adapters = mutableListOf<ImageSelectAdapter>()
    /** 三组图片的事件监听器 */
    val imageEvents = mutableListOf<ImageEventListener<FileSelectBean>>()
    /** 每组图片最大可上传数量,默认均为 8 张 */
    val maxSizes = listOf(8, 8, 8)
    /** 当前正在操作的图片组下标(0/1/2),-1 表示未选择 */
    var operateIndex = -1
    /** 事故类型分类列表(大类 + 子类) */
    var categories = mutableListOf<Category>()
    /** 页面点击事件统一处理:增减人数按钮、提交按钮 */
    var onClick = View.OnClickListener {
@@ -130,6 +150,7 @@
                map["responsibleImage"] = "${adapters[0].data.map { it.url }}"
                map["situationImage"] = "${adapters[1].data.map { it.url }}"
                map["disposalImage"] = "${adapters[2].data.map { it.url }}"
                map["taskTypeId"] = getSelectType()
                taskRepository.handleVehicleAccident(map)
                ToastUtilCommon.showSuc("提交成功")
@@ -196,4 +217,51 @@
            value = (current + 1).toString()
        }
    }
    /**
     * 获取事故类型列表
     *
     * 若 [categories] 已存在则直接回调,否则通过网络请求拉取并转换数据结构。
     *
     * @param block 数据就绪后的回调(在主线程执行)
     */
    fun getTypeList(block: () -> Unit) {
        if (categories.isNotEmpty()) {
            block()
        } else {
            launchRequest {
                taskRepository.getTypeList()?.forEachIndexed { index, type ->
                    runOnMainThread {
                        categories.clear()
                        val items = mutableListOf<Item>()
                        type.child?.forEach {
                            items.add(Item(it.id ?: 0L, it.errorName ?: ""))
                        }
                        categories.add(Category(index, type.errorName ?: "", items))
                        val ids = taskTypeId?.split(", ") ?: emptyList()
                        categories.forEach { it ->
                            it.items.forEach {
                                it.isSelected = ids.contains(it.id.toString())
                            }
                        }
                        block()
                    }
                }
            }
        }
    }
    /**
     * 获取当前已选中的事故类型 ID 字符串
     *
     * 遍历所有分类的子项,过滤出 [Item.isSelected] 为 true 的项,
     * 将其 ID 以逗号分隔拼接成字符串返回。
     *
     * @return 已选中事故类型 ID 的逗号分隔字符串,未选择时返回空串
     */
    fun getSelectType(): String {
        val items = mutableListOf<Item>()
        categories.forEach { items.addAll(it.items) }
        return items.filter { it.isSelected }.map { it.id }.joinToString()
    }
}
app/src/main/res/layout/activity_accident_process.xml
@@ -276,6 +276,49 @@
                </LinearLayout>
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="@dimen/dp_58"
                    android:layout_marginTop="@dimen/dp_8"
                    android:layout_marginHorizontal="@dimen/dp_28"
                    android:gravity="center_vertical"
                    android:orientation="horizontal">
                    <androidx.appcompat.widget.AppCompatTextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="事故类型"
                        android:textColor="@color/gray_9"
                        android:textSize="@dimen/sp_16" />
                    <androidx.appcompat.widget.AppCompatTextView
                        android:id="@+id/tvAccidentFilter"
                        android:layout_width="0dp"
                        android:layout_height="wrap_content"
                        android:layout_marginStart="@dimen/dp_20"
                        android:layout_weight="1"
                        android:gravity="end"
                        android:hint="请选择"
                        android:paddingVertical="@dimen/dp_3"
                        android:textColor="@color/gray_9"
                        android:textColorHint="@color/gray_6"
                        android:textSize="@dimen/sp_14" />
                    <androidx.appcompat.widget.AppCompatImageView
                        android:layout_width="@dimen/dp_16"
                        android:layout_height="@dimen/dp_16"
                        android:layout_marginStart="@dimen/dp_4"
                        android:src="@mipmap/ic_task_item_arrow_right" />
                </LinearLayout>
                <View
                    android:layout_width="match_parent"
                    android:layout_height="1px"
                    android:layout_marginHorizontal="@dimen/dp_28"
                    android:background="@color/gray_4" />
                <androidx.appcompat.widget.AppCompatTextView
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"