feat: 国际事故签证新增/编辑页面及列表侧滑菜单

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-17 11:37:26 +08:00
parent 8ced5be7a9
commit 9b089d51b1
11 changed files with 1046 additions and 237 deletions

View File

@@ -8,10 +8,14 @@ import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpAccidentVisaBinding
import com.lukouguoji.gjj.viewModel.IntImpAccidentVisaViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.bean.IntImpAccidentVisaBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.impl.observe
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
import com.lukouguoji.module_base.ktx.addOnItemClickListener
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.router.ARouterConstants
/**
@@ -19,7 +23,8 @@ import com.lukouguoji.module_base.router.ARouterConstants
*/
@Route(path = ARouterConstants.ACTIVITY_URL_INT_IMP_ACCIDENT_VISA)
class IntImpAccidentVisaActivity :
BaseBindingActivity<ActivityIntImpAccidentVisaBinding, IntImpAccidentVisaViewModel>() {
BaseBindingActivity<ActivityIntImpAccidentVisaBinding, IntImpAccidentVisaViewModel>(),
IOnItemClickListener {
override fun layoutId() = R.layout.activity_int_imp_accident_visa
override fun viewModelClass() = IntImpAccidentVisaViewModel::class.java
@@ -34,6 +39,8 @@ class IntImpAccidentVisaActivity :
viewModel.pageModel.bindSmartRefreshLayout(binding.srl, binding.rv, viewModel, this)
binding.rv.addOnItemClickListener(this)
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).observe(this) {
viewModel.refresh()
}
@@ -48,4 +55,15 @@ class IntImpAccidentVisaActivity :
viewModel.searchClick()
}
}
override fun onItemClick(position: Int, type: Int) {
when (type) {
2000 -> {
// 侧滑菜单 - 修改
val bean = binding.rv.commonAdapter()?.getItem(position) as? IntImpAccidentVisaBean
?: return
IntImpAccidentVisaEditActivity.start(this, bean.id)
}
}
}
}

View File

@@ -0,0 +1,45 @@
package com.lukouguoji.gjj.activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.lukouguoji.gjj.R
import com.lukouguoji.gjj.databinding.ActivityIntImpAccidentVisaEditBinding
import com.lukouguoji.gjj.viewModel.IntImpAccidentVisaEditViewModel
import com.lukouguoji.module_base.base.BaseBindingActivity
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.ktx.addOnItemClickListener
/**
* 国际进港-事故签证新增/编辑
*/
class IntImpAccidentVisaEditActivity :
BaseBindingActivity<ActivityIntImpAccidentVisaEditBinding, IntImpAccidentVisaEditViewModel>() {
override fun layoutId() = R.layout.activity_int_imp_accident_visa_edit
override fun viewModelClass() = IntImpAccidentVisaEditViewModel::class.java
override fun initOnCreate(savedInstanceState: Bundle?) {
binding.viewModel = viewModel
viewModel.rv = binding.rv
binding.rv.addOnItemClickListener(viewModel)
viewModel.initOnCreate(intent)
viewModel.pageType.observe(this) {
val title = if (it == DetailsPageType.Add) "国际事故签证新增" else "国际事故签证修改"
setBackArrow(title)
}
}
companion object {
@JvmStatic
fun start(context: Context, id: Long = 0) {
context.startActivity(
Intent(context, IntImpAccidentVisaEditActivity::class.java)
.putExtra(Constant.Key.ID, id)
)
}
}
}

View File

@@ -21,5 +21,11 @@ class IntImpAccidentVisaViewHolder(view: View) :
bean.checked.set(!bean.checked.get())
binding.executePendingBindings()
}
// 侧滑菜单 - 修改按钮
binding.btnEdit.setOnClickListener {
binding.swipeMenu.quickClose()
clickListener?.onItemClick(position, 2000) // type=2000表示修改操作
}
}
}

View File

@@ -0,0 +1,271 @@
package com.lukouguoji.gjj.viewModel
import android.content.Intent
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import androidx.recyclerview.widget.RecyclerView
import com.lukouguoji.gjj.R
import com.lukouguoji.module_base.base.BaseViewModel
import com.lukouguoji.module_base.bean.FileBean
import com.lukouguoji.module_base.bean.GjAccidentVisaEditBean
import com.lukouguoji.module_base.common.Constant
import com.lukouguoji.module_base.common.ConstantEvent
import com.lukouguoji.module_base.common.DetailsPageType
import com.lukouguoji.module_base.http.net.NetApply
import com.lukouguoji.module_base.impl.FlowBus
import com.lukouguoji.module_base.impl.ImageSelectViewHolder
import com.lukouguoji.module_base.interfaces.IOnItemClickListener
import com.lukouguoji.module_base.ktx.commonAdapter
import com.lukouguoji.module_base.ktx.launchCollect
import com.lukouguoji.module_base.ktx.launchLoadingCollect
import com.lukouguoji.module_base.ktx.noNull
import com.lukouguoji.module_base.ktx.showToast
import com.lukouguoji.module_base.ktx.toRequestBody
import com.lukouguoji.module_base.ktx.verifyNullOrEmpty
import com.lukouguoji.module_base.util.MediaUtil
import com.lukouguoji.module_base.util.UploadUtil
import dev.utils.app.info.KeyValue
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.launch
class IntImpAccidentVisaEditViewModel : BaseViewModel(), IOnItemClickListener {
var id: Long = 0
val pageType = MutableLiveData(DetailsPageType.Add)
val dataBean = MutableLiveData(GjAccidentVisaEditBean())
// 图片列表
val itemLayoutId = R.layout.item_image_select
val itemViewHolder = ImageSelectViewHolder::class.java
var rv: RecyclerView? = null
// 下拉列表
val outerPackageList = MutableLiveData<List<KeyValue>>(emptyList())
val damageTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val contentTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val unusualTypeList = MutableLiveData<List<KeyValue>>(emptyList())
val photoList = MutableLiveData(
listOf(KeyValue("是", "是"), KeyValue("否", "否"))
)
// 航班级联查询
private var lastQueriedFlight = ""
///////////////////////////////////////////////////////////////////////////
// 初始化
///////////////////////////////////////////////////////////////////////////
fun initOnCreate(intent: Intent) {
id = intent.getLongExtra(Constant.Key.ID, 0)
pageType.value = if (id == 0L) DetailsPageType.Add else DetailsPageType.Modify
loadDropdownLists()
if (id != 0L) {
loadDetail()
}
rv?.post {
rv?.commonAdapter()?.addItem(FileBean())
}
}
private fun loadDropdownLists() {
launchCollect({ NetApply.api.getPackTypeList() }) {
onSuccess = { result ->
outerPackageList.value = result.data?.mapNotNull { bean ->
bean.name?.let { name -> KeyValue(name, name) }
} ?: emptyList()
}
}
launchCollect({ NetApply.api.getDamageTypeList() }) {
onSuccess = { result ->
damageTypeList.value = result.data?.mapNotNull { bean ->
bean.name?.let { name -> KeyValue(name, name) }
} ?: emptyList()
}
}
launchCollect({ NetApply.api.getContentTypeList() }) {
onSuccess = { result ->
contentTypeList.value = result.data?.mapNotNull { bean ->
bean.name?.let { name -> KeyValue(name, name) }
} ?: emptyList()
}
}
launchCollect({ NetApply.api.getUnusualTypeList() }) {
onSuccess = { result ->
unusualTypeList.value = result.data?.mapNotNull { bean ->
bean.name?.let { name -> KeyValue(name, name) }
} ?: emptyList()
}
}
}
private fun loadDetail() {
launchLoadingCollect({ NetApply.api.getGjAccidentVisaDetail(id) }) {
onSuccess = {
dataBean.value = it.data ?: GjAccidentVisaEditBean()
// 渲染图片
val bean = dataBean.value!!
val picList = bean.pic.split(",")
.filter { url -> url.isNotEmpty() }
.map { url -> FileBean(MediaUtil.fillUrl(url), url) }
val originalList = bean.originalPic.split(",")
.filter { url -> url.isNotEmpty() }
.map { url -> FileBean(MediaUtil.fillUrl(url)) }
for ((index, fileBean) in picList.withIndex()) {
if (index < originalList.size) {
picList[index].originalPic = originalList[index].path
}
}
rv?.commonAdapter()?.loadMore(picList)
}
}
}
///////////////////////////////////////////////////////////////////////////
// 航班级联查询
///////////////////////////////////////////////////////////////////////////
fun onFlightDateInputComplete() {
lastQueriedFlight = ""
queryFlightIfReady()
}
fun onFlightNoInputComplete() {
queryFlightIfReady()
}
private fun queryFlightIfReady() {
val bean = dataBean.value ?: return
val fdate = bean.fdate
val fno = bean.fno
if (fdate.isEmpty() || fno.isEmpty()) return
val key = "$fdate-$fno"
if (key == lastQueriedFlight) return
lastQueriedFlight = key
launchCollect({
NetApply.api.getGjFlightBean(
mapOf(
"fdate" to fdate,
"fno" to fno,
"ieFlag" to "I",
).toRequestBody()
)
}) {
onSuccess = {
if (it.verifySuccess() && it.data != null) {
val flight = it.data!!
val b = dataBean.value ?: GjAccidentVisaEditBean()
b.dep = flight.fdep.noNull()
b.dest = flight.fdest.noNull()
dataBean.value = b
} else {
val b = dataBean.value ?: GjAccidentVisaEditBean()
b.dep = ""
b.dest = ""
dataBean.value = b
showToast(it.msg.noNull("获取航班信息失败"))
}
}
onFailed = { _, _ ->
val b = dataBean.value ?: GjAccidentVisaEditBean()
b.dep = ""
b.dest = ""
dataBean.value = b
}
}
}
///////////////////////////////////////////////////////////////////////////
// 保存
///////////////////////////////////////////////////////////////////////////
fun onSaveClick() {
val bean = dataBean.value ?: return
if (bean.fdate.verifyNullOrEmpty("请输入航班日期")) return
if (bean.fno.verifyNullOrEmpty("请输入航班号")) return
if (bean.wbNo.verifyNullOrEmpty("请输入运单号")) return
(rv?.commonAdapter()?.items ?: emptyList())
.asFlow()
.map { it as FileBean }
.filter { it.path.isNotEmpty() && it.url.isEmpty() }
.onEach {
val data = UploadUtil.upload(it.path).data
it.url = data?.newName ?: ""
it.originalPic = data?.zipFileName ?: ""
}
.flowOn(Dispatchers.IO)
.onStart { showLoading() }
.catch {
showToast(it.message.noNull("上传图片失败"))
dismissLoading()
}
.onCompletion {
launchLoadingCollect({
val list = (rv?.commonAdapter()?.items as List<FileBean>)
.filter { it.path.isNotEmpty() }
bean.picNumber = list.size.toString()
bean.originalPic = list.joinToString(separator = ",") { MediaUtil.removeUrl(it.url) }
bean.pic = list.joinToString(separator = ",") { MediaUtil.removeUrl(it.originalPic) }
bean.idFlag = "1"
if (pageType.value == DetailsPageType.Add) {
NetApply.api.saveGjAccidentVisa(bean.toRequestBody())
} else {
NetApply.api.modifyGjAccidentVisa(bean.toRequestBody())
}
}) {
onSuccess = {
showToast(it.msg.noNull("${pageType.value!!.title}成功"))
viewModelScope.launch {
FlowBus.with<String>(ConstantEvent.EVENT_REFRESH).emit("refresh")
}
getTopActivity().finish()
}
}
}
.launchIn(viewModelScope)
}
fun onCancelClick() {
getTopActivity().finish()
}
///////////////////////////////////////////////////////////////////////////
// 图片操作
///////////////////////////////////////////////////////////////////////////
override fun onItemClick(position: Int, type: Int) {
val adapter = rv!!.commonAdapter()!!
val bean = adapter.getItem(position) as FileBean
when (type) {
R.id.rl -> {
bean.canDelete.set(!bean.canDelete.get())
}
R.id.iv_delete -> {
adapter.removeItem(position)
}
else -> {}
}
}
}

View File

@@ -123,6 +123,10 @@ class IntImpAccidentVisaViewModel : BasePageViewModel() {
ScanModel.startScan(getTopActivity(), Constant.RequestCode.WAYBILL)
}
fun addClick() {
com.lukouguoji.gjj.activity.IntImpAccidentVisaEditActivity.start(getTopActivity())
}
fun searchClick() {
refresh()
}